From ddf971f9369f8d806fcb577822850f6eb0d37c40 Mon Sep 17 00:00:00 2001 From: raster Date: Thu, 30 Aug 2012 09:54:57 +0000 Subject: [PATCH 1/1] EFL 1.7 svn doobies git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/branches/ecore-1.7@75862 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33 --- .gitignore | 91 + AUTHORS | 54 + COPYING | 25 + ChangeLog | 890 + INSTALL | 236 + Makefile.am | 250 + NEWS | 286 + README | 98 + autogen.sh | 40 + configure.ac | 2259 +++ doc/Doxyfile.in | 221 + doc/Makefile.am | 33 + doc/e.css | 273 + doc/ecore.dox.in | 0 doc/examples.dox | 1692 ++ doc/foot.html | 19 + doc/head.html | 69 + doc/img/e.png | Bin 0 -> 30052 bytes doc/img/ecore-pos-map.eps | 5750 ++++++ doc/img/ecore-pos-map.png | Bin 0 -> 17267 bytes doc/img/ecore_con-client-server-example.eps | 566 + doc/img/ecore_con-client-server-example.png | Bin 0 -> 60234 bytes doc/img/ecore_con-client-server-example2.eps | 580 + doc/img/ecore_con-client-server-example2.png | Bin 0 -> 67464 bytes doc/img/ecore_con-client-server.eps | 513 + doc/img/ecore_con-client-server.png | Bin 0 -> 58250 bytes doc/img/ecore_thread.eps | 17292 +++++++++++++++++ doc/img/ecore_thread.png | Bin 0 -> 107067 bytes doc/img/ecore_thread_feedback.eps | 18387 +++++++++++++++++++ doc/img/ecore_thread_feedback.png | Bin 0 -> 116002 bytes doc/img/edoxy.css | 486 + doc/img/foot_bg.png | Bin 0 -> 173 bytes doc/img/head_bg.png | Bin 0 -> 214 bytes doc/img/header_menu_background.png | Bin 0 -> 192 bytes doc/img/header_menu_background_last.png | Bin 0 -> 637 bytes doc/img/header_menu_current_background.png | Bin 0 -> 1200 bytes doc/img/header_menu_unselected_background.png | Bin 0 -> 1596 bytes doc/img/logo.png | Bin 0 -> 3825 bytes doc/img/prog_flow.eps | 6036 ++++++ doc/img/prog_flow.png | Bin 0 -> 24099 bytes ecore-cocoa.pc.in | 11 + ecore-con.pc.in | 11 + ecore-config.pc.in | 11 + ecore-directfb.pc.in | 11 + ecore-evas.pc.in | 11 + ecore-fb.pc.in | 11 + ecore-file.pc.in | 11 + ecore-imf-evas.pc.in | 11 + ecore-imf.pc.in | 11 + ecore-input-evas.pc.in | 11 + ecore-input.pc.in | 11 + ecore-ipc.pc.in | 11 + ecore-psl1ght.pc.in | 12 + ecore-sdl.pc.in | 11 + ecore-wayland.pc.in | 12 + ecore-win32.pc.in | 12 + ecore-wince.pc.in | 12 + ecore-x.pc.in | 12 + ecore.pc.in | 12 + ecore.spec.in | 233 + ecore.supp | 46 + m4/ac_abstract_socket.m4 | 41 + m4/ac_attribute.m4 | 47 + m4/ac_path_generic.m4 | 137 + m4/check_x_extension.m4 | 40 + m4/ecore_check_module.m4 | 97 + m4/ecore_check_options.m4 | 331 + m4/efl_compiler.m4 | 56 + m4/efl_compiler_flag.m4 | 57 + m4/efl_coverage.m4 | 62 + m4/efl_doxygen.m4 | 97 + m4/efl_examples.m4 | 63 + m4/efl_gettimeofday.m4 | 48 + m4/efl_path_max.m4 | 36 + m4/efl_shm_open.m4 | 69 + m4/efl_tests.m4 | 43 + m4/efl_threads.m4 | 206 + po/ChangeLog | 0 po/LINGUAS | 2 + po/Makevars | 41 + po/POTFILES.in | 1 + po/cs.po | 174 + po/de.po | 175 + po/el.po | 205 + po/fr.po | 208 + po/it.po | 204 + po/nl.po | 175 + po/pt.po | 176 + po/sl.po | 175 + src/Makefile.am | 26 + src/bin/Makefile.am | 51 + src/bin/ecore_config.c | 324 + src/bin/ecore_test.c | 109 + src/examples/Makefile.am | 117 + src/examples/ecore_animator_example.c | 117 + src/examples/ecore_client_bench.c | 79 + src/examples/ecore_con_client_example.c | 92 + src/examples/ecore_con_client_simple_example.c | 126 + src/examples/ecore_con_lookup_example.c | 40 + src/examples/ecore_con_server_example.c | 81 + src/examples/ecore_con_server_http_example.c | 136 + src/examples/ecore_con_server_simple_example.c | 133 + src/examples/ecore_con_url_cookies_example.c | 123 + src/examples/ecore_con_url_download_example.c | 113 + src/examples/ecore_con_url_headers_example.c | 106 + src/examples/ecore_evas_basics_example.c | 89 + src/examples/ecore_evas_buffer_example_01.c | 121 + src/examples/ecore_evas_buffer_example_02.c | 126 + src/examples/ecore_evas_callbacks.c | 128 + src/examples/ecore_evas_ews_example.c | 269 + src/examples/ecore_evas_object_example.c | 53 + src/examples/ecore_evas_window_sizes_example.c | 204 + src/examples/ecore_event_example_01.c | 26 + src/examples/ecore_event_example_02.c | 89 + src/examples/ecore_exe_example.c | 100 + src/examples/ecore_exe_example_child.c | 56 + src/examples/ecore_fd_handler_example.c | 89 + src/examples/ecore_fd_handler_gnutls_example.c | 203 + src/examples/ecore_file_download_example.c | 86 + src/examples/ecore_idler_example.c | 115 + src/examples/ecore_imf_example.c | 571 + src/examples/ecore_job_example.c | 50 + src/examples/ecore_pipe_gstreamer_example.c | 190 + src/examples/ecore_pipe_simple_example.c | 67 + src/examples/ecore_poller_example.c | 49 + src/examples/ecore_server_bench.c | 63 + src/examples/ecore_thread_example.c | 395 + src/examples/ecore_time_functions_example.c | 34 + src/examples/ecore_timer_example.c | 187 + src/examples/red.png | Bin 0 -> 225 bytes src/lib/Makefile.am | 75 + src/lib/ecore/Ecore.h | 2619 +++ src/lib/ecore/Ecore_Getopt.h | 419 + src/lib/ecore/Makefile.am | 69 + src/lib/ecore/ecore.c | 854 + src/lib/ecore/ecore_alloc.c | 132 + src/lib/ecore/ecore_anim.c | 516 + src/lib/ecore/ecore_app.c | 96 + src/lib/ecore/ecore_events.c | 648 + src/lib/ecore/ecore_exe.c | 1913 ++ src/lib/ecore/ecore_exe_ps3.c | 20 + src/lib/ecore/ecore_exe_win32.c | 1055 ++ src/lib/ecore/ecore_exe_wince.c | 21 + src/lib/ecore/ecore_getopt.c | 1927 ++ src/lib/ecore/ecore_glib.c | 342 + src/lib/ecore/ecore_idle_enterer.c | 211 + src/lib/ecore/ecore_idle_exiter.c | 179 + src/lib/ecore/ecore_idler.c | 161 + src/lib/ecore/ecore_job.c | 125 + src/lib/ecore/ecore_main.c | 2093 +++ src/lib/ecore/ecore_pipe.c | 688 + src/lib/ecore/ecore_poll.c | 353 + src/lib/ecore/ecore_private.h | 380 + src/lib/ecore/ecore_signal.c | 594 + src/lib/ecore/ecore_thread.c | 1611 ++ src/lib/ecore/ecore_throttle.c | 101 + src/lib/ecore/ecore_time.c | 184 + src/lib/ecore/ecore_timer.c | 847 + src/lib/ecore_cocoa/Ecore_Cocoa.h | 147 + src/lib/ecore_cocoa/Ecore_Cocoa_Keys.h | 285 + src/lib/ecore_cocoa/Makefile.am | 29 + src/lib/ecore_cocoa/ecore_cocoa.m | 283 + src/lib/ecore_cocoa/ecore_cocoa_private.h | 11 + src/lib/ecore_cocoa/ecore_cocoa_window.m | 163 + src/lib/ecore_con/Ecore_Con.h | 1948 ++ src/lib/ecore_con/Makefile.am | 53 + src/lib/ecore_con/dns.c | 7878 ++++++++ src/lib/ecore_con/dns.h | 1074 ++ src/lib/ecore_con/ecore_con.c | 2586 +++ src/lib/ecore_con/ecore_con_alloc.c | 101 + src/lib/ecore_con/ecore_con_ares.c | 628 + src/lib/ecore_con/ecore_con_dns.c | 344 + src/lib/ecore_con/ecore_con_info.c | 449 + src/lib/ecore_con/ecore_con_local.c | 325 + src/lib/ecore_con/ecore_con_local_win32.c | 754 + src/lib/ecore_con/ecore_con_private.h | 399 + src/lib/ecore_con/ecore_con_socks.c | 940 + src/lib/ecore_con/ecore_con_ssl.c | 2112 +++ src/lib/ecore_con/ecore_con_url.c | 1635 ++ src/lib/ecore_config/Ecore_Config.h | 312 + src/lib/ecore_config/Makefile.am | 62 + src/lib/ecore_config/ecore_config.c | 1870 ++ src/lib/ecore_config/ecore_config_db.c | 296 + src/lib/ecore_config/ecore_config_extra.c | 803 + src/lib/ecore_config/ecore_config_ipc.h | 50 + src/lib/ecore_config/ecore_config_ipc_ecore.c | 384 + src/lib/ecore_config/ecore_config_ipc_main.c | 275 + src/lib/ecore_config/ecore_config_private.h | 70 + src/lib/ecore_config/ecore_config_storage.c | 176 + src/lib/ecore_config/ecore_config_util.c | 129 + src/lib/ecore_config/ecore_config_util.h | 14 + src/lib/ecore_directfb/Ecore_DirectFB.h | 181 + src/lib/ecore_directfb/Makefile.am | 31 + src/lib/ecore_directfb/ecore_directfb.c | 757 + src/lib/ecore_directfb/ecore_directfb_keys.h | 184 + src/lib/ecore_directfb/ecore_directfb_private.h | 52 + src/lib/ecore_evas/Ecore_Evas.h | 2270 +++ src/lib/ecore_evas/Makefile.am | 160 + src/lib/ecore_evas/ecore_evas.c | 2861 +++ src/lib/ecore_evas/ecore_evas_buffer.c | 829 + src/lib/ecore_evas/ecore_evas_cocoa.c | 584 + src/lib/ecore_evas/ecore_evas_directfb.c | 606 + src/lib/ecore_evas/ecore_evas_ews.c | 1469 ++ src/lib/ecore_evas/ecore_evas_extn.c | 2221 +++ src/lib/ecore_evas/ecore_evas_fb.c | 678 + src/lib/ecore_evas/ecore_evas_private.h | 487 + src/lib/ecore_evas/ecore_evas_psl1ght.c | 515 + src/lib/ecore_evas/ecore_evas_sdl.c | 657 + src/lib/ecore_evas/ecore_evas_util.c | 445 + src/lib/ecore_evas/ecore_evas_wayland_egl.c | 1141 ++ src/lib/ecore_evas/ecore_evas_wayland_shm.c | 1320 ++ src/lib/ecore_evas/ecore_evas_win32.c | 1589 ++ src/lib/ecore_evas/ecore_evas_wince.c | 1013 + src/lib/ecore_evas/ecore_evas_x.c | 4653 +++++ src/lib/ecore_fb/Ecore_Fb.h | 100 + src/lib/ecore_fb/Makefile.am | 34 + src/lib/ecore_fb/ecore_fb.c | 129 + src/lib/ecore_fb/ecore_fb_kbd.c | 326 + src/lib/ecore_fb/ecore_fb_keytable.h | 129 + src/lib/ecore_fb/ecore_fb_li.c | 721 + src/lib/ecore_fb/ecore_fb_private.h | 94 + src/lib/ecore_fb/ecore_fb_ps2.c | 223 + src/lib/ecore_fb/ecore_fb_ts.c | 362 + src/lib/ecore_fb/ecore_fb_vt.c | 322 + src/lib/ecore_file/Ecore_File.h | 190 + src/lib/ecore_file/Makefile.am | 41 + src/lib/ecore_file/ecore_file.c | 1109 ++ src/lib/ecore_file/ecore_file_download.c | 449 + src/lib/ecore_file/ecore_file_monitor.c | 180 + src/lib/ecore_file/ecore_file_monitor_inotify.c | 370 + src/lib/ecore_file/ecore_file_monitor_poll.c | 340 + src/lib/ecore_file/ecore_file_monitor_win32.c | 310 + src/lib/ecore_file/ecore_file_path.c | 184 + src/lib/ecore_file/ecore_file_private.h | 129 + src/lib/ecore_imf/Ecore_IMF.h | 572 + src/lib/ecore_imf/Makefile.am | 28 + src/lib/ecore_imf/ecore_imf.c | 73 + src/lib/ecore_imf/ecore_imf_context.c | 1896 ++ src/lib/ecore_imf/ecore_imf_module.c | 212 + src/lib/ecore_imf/ecore_imf_private.h | 84 + src/lib/ecore_imf_evas/Ecore_IMF_Evas.h | 50 + src/lib/ecore_imf_evas/Makefile.am | 22 + src/lib/ecore_imf_evas/ecore_imf_evas.c | 309 + src/lib/ecore_input/Ecore_Input.h | 234 + src/lib/ecore_input/Makefile.am | 26 + src/lib/ecore_input/ecore_input.c | 127 + src/lib/ecore_input/ecore_input_compose.c | 61 + src/lib/ecore_input/ecore_input_compose.h | 9895 ++++++++++ src/lib/ecore_input/ecore_input_private.h | 37 + src/lib/ecore_input_evas/Ecore_Input_Evas.h | 64 + src/lib/ecore_input_evas/Makefile.am | 29 + src/lib/ecore_input_evas/ecore_input_evas.c | 418 + .../ecore_input_evas/ecore_input_evas_private.h | 37 + src/lib/ecore_ipc/Ecore_Ipc.h | 328 + src/lib/ecore_ipc/Makefile.am | 34 + src/lib/ecore_ipc/ecore_ipc.c | 1603 ++ src/lib/ecore_ipc/ecore_ipc_private.h | 105 + src/lib/ecore_psl1ght/Ecore_Psl1ght.h | 121 + src/lib/ecore_psl1ght/Ecore_Psl1ght_Keys.h | 78 + src/lib/ecore_psl1ght/Makefile.am | 30 + src/lib/ecore_psl1ght/ecore_psl1ght.c | 859 + src/lib/ecore_psl1ght/ecore_psl1ght_private.h | 36 + src/lib/ecore_psl1ght/gemutil.c | 281 + src/lib/ecore_psl1ght/gemutil.h | 19 + src/lib/ecore_psl1ght/moveutil.c | 245 + src/lib/ecore_psl1ght/moveutil.h | 43 + src/lib/ecore_psl1ght/spursutil.c | 62 + src/lib/ecore_psl1ght/spursutil.h | 24 + src/lib/ecore_sdl/Ecore_Sdl.h | 114 + src/lib/ecore_sdl/Ecore_Sdl_Keys.h | 266 + src/lib/ecore_sdl/Makefile.am | 29 + src/lib/ecore_sdl/ecore_sdl.c | 335 + src/lib/ecore_sdl/ecore_sdl_private.h | 36 + src/lib/ecore_wayland/Ecore_Wayland.h | 389 + src/lib/ecore_wayland/Makefile.am | 33 + src/lib/ecore_wayland/ecore_wl.c | 498 + src/lib/ecore_wayland/ecore_wl_dnd.c | 485 + src/lib/ecore_wayland/ecore_wl_input.c | 1210 ++ src/lib/ecore_wayland/ecore_wl_output.c | 85 + src/lib/ecore_wayland/ecore_wl_private.h | 103 + src/lib/ecore_wayland/ecore_wl_window.c | 703 + src/lib/ecore_win32/Ecore_Win32.h | 526 + src/lib/ecore_win32/Makefile.am | 44 + src/lib/ecore_win32/ecore_win32.c | 841 + src/lib/ecore_win32/ecore_win32_cursor.c | 305 + src/lib/ecore_win32/ecore_win32_dnd.c | 221 + .../ecore_win32/ecore_win32_dnd_data_object.cpp | 209 + src/lib/ecore_win32/ecore_win32_dnd_data_object.h | 49 + .../ecore_win32/ecore_win32_dnd_drop_source.cpp | 92 + src/lib/ecore_win32/ecore_win32_dnd_drop_source.h | 36 + .../ecore_win32/ecore_win32_dnd_drop_target.cpp | 232 + src/lib/ecore_win32/ecore_win32_dnd_drop_target.h | 47 + .../ecore_win32/ecore_win32_dnd_enumformatetc.cpp | 157 + .../ecore_win32/ecore_win32_dnd_enumformatetc.h | 50 + src/lib/ecore_win32/ecore_win32_event.c | 1307 ++ src/lib/ecore_win32/ecore_win32_private.h | 170 + src/lib/ecore_win32/ecore_win32_window.c | 1418 ++ src/lib/ecore_wince/Ecore_WinCE.h | 314 + src/lib/ecore_wince/Makefile.am | 35 + src/lib/ecore_wince/ecore_wince.c | 400 + src/lib/ecore_wince/ecore_wince_event.c | 1123 ++ src/lib/ecore_wince/ecore_wince_private.h | 85 + src/lib/ecore_wince/ecore_wince_window.c | 827 + src/lib/ecore_x/Ecore_X.h | 2399 +++ src/lib/ecore_x/Ecore_X_Atoms.h | 290 + src/lib/ecore_x/Ecore_X_Cursor.h | 87 + src/lib/ecore_x/Makefile.am | 30 + src/lib/ecore_x/ecore_x_atoms_decl.h | 595 + src/lib/ecore_x/xcb/Makefile.am | 99 + src/lib/ecore_x/xcb/ecore_xcb.c | 1583 ++ src/lib/ecore_x/xcb/ecore_xcb_atoms.c | 153 + src/lib/ecore_x/xcb/ecore_xcb_composite.c | 290 + src/lib/ecore_x/xcb/ecore_xcb_cursor.c | 400 + src/lib/ecore_x/xcb/ecore_xcb_damage.c | 155 + src/lib/ecore_x/xcb/ecore_xcb_dnd.c | 688 + src/lib/ecore_x/xcb/ecore_xcb_dpms.c | 320 + src/lib/ecore_x/xcb/ecore_xcb_drawable.c | 123 + src/lib/ecore_x/xcb/ecore_xcb_e.c | 1552 ++ src/lib/ecore_x/xcb/ecore_xcb_error.c | 123 + src/lib/ecore_x/xcb/ecore_xcb_events.c | 2820 +++ src/lib/ecore_x/xcb/ecore_xcb_extensions.c | 148 + src/lib/ecore_x/xcb/ecore_xcb_gc.c | 173 + src/lib/ecore_x/xcb/ecore_xcb_gesture.c | 203 + src/lib/ecore_x/xcb/ecore_xcb_icccm.c | 1569 ++ src/lib/ecore_x/xcb/ecore_xcb_image.c | 740 + src/lib/ecore_x/xcb/ecore_xcb_input.c | 274 + src/lib/ecore_x/xcb/ecore_xcb_keymap.c | 491 + src/lib/ecore_x/xcb/ecore_xcb_mwm.c | 104 + src/lib/ecore_x/xcb/ecore_xcb_netwm.c | 1604 ++ src/lib/ecore_x/xcb/ecore_xcb_pixmap.c | 128 + src/lib/ecore_x/xcb/ecore_xcb_private.h | 442 + src/lib/ecore_x/xcb/ecore_xcb_randr.c | 3807 ++++ src/lib/ecore_x/xcb/ecore_xcb_region.c | 159 + src/lib/ecore_x/xcb/ecore_xcb_render.c | 225 + src/lib/ecore_x/xcb/ecore_xcb_screensaver.c | 371 + src/lib/ecore_x/xcb/ecore_xcb_selection.c | 1033 ++ src/lib/ecore_x/xcb/ecore_xcb_shape.c | 50 + src/lib/ecore_x/xcb/ecore_xcb_sync.c | 338 + src/lib/ecore_x/xcb/ecore_xcb_textlist.c | 509 + src/lib/ecore_x/xcb/ecore_xcb_vsync.c | 375 + src/lib/ecore_x/xcb/ecore_xcb_window.c | 2238 +++ src/lib/ecore_x/xcb/ecore_xcb_window_prop.c | 720 + src/lib/ecore_x/xcb/ecore_xcb_window_shadow.c | 410 + src/lib/ecore_x/xcb/ecore_xcb_window_shape.c | 790 + src/lib/ecore_x/xcb/ecore_xcb_xdefaults.c | 116 + src/lib/ecore_x/xcb/ecore_xcb_xfixes.c | 750 + src/lib/ecore_x/xcb/ecore_xcb_xinerama.c | 139 + src/lib/ecore_x/xcb/ecore_xcb_xtest.c | 215 + src/lib/ecore_x/xlib/Makefile.am | 94 + src/lib/ecore_x/xlib/ecore_x.c | 2208 +++ src/lib/ecore_x/xlib/ecore_x_atoms.c | 100 + src/lib/ecore_x/xlib/ecore_x_composite.c | 176 + src/lib/ecore_x/xlib/ecore_x_cursor.c | 246 + src/lib/ecore_x/xlib/ecore_x_damage.c | 71 + src/lib/ecore_x/xlib/ecore_x_dnd.c | 706 + src/lib/ecore_x/xlib/ecore_x_dpms.c | 247 + src/lib/ecore_x/xlib/ecore_x_drawable.c | 118 + src/lib/ecore_x/xlib/ecore_x_e.c | 1622 ++ src/lib/ecore_x/xlib/ecore_x_error.c | 126 + src/lib/ecore_x/xlib/ecore_x_events.c | 2527 +++ src/lib/ecore_x/xlib/ecore_x_fixes.c | 365 + src/lib/ecore_x/xlib/ecore_x_gc.c | 171 + src/lib/ecore_x/xlib/ecore_x_gesture.c | 137 + src/lib/ecore_x/xlib/ecore_x_icccm.c | 1214 ++ src/lib/ecore_x/xlib/ecore_x_image.c | 600 + src/lib/ecore_x/xlib/ecore_x_mwm.c | 106 + src/lib/ecore_x/xlib/ecore_x_netwm.c | 2083 +++ src/lib/ecore_x/xlib/ecore_x_pixmap.c | 121 + src/lib/ecore_x/xlib/ecore_x_private.h | 379 + src/lib/ecore_x/xlib/ecore_x_randr.c | 103 + src/lib/ecore_x/xlib/ecore_x_randr.h | 7 + src/lib/ecore_x/xlib/ecore_x_randr_11.c | 334 + src/lib/ecore_x/xlib/ecore_x_randr_12.c | 2405 +++ src/lib/ecore_x/xlib/ecore_x_randr_12_edid.c | 463 + src/lib/ecore_x/xlib/ecore_x_randr_13.c | 68 + src/lib/ecore_x/xlib/ecore_x_region.c | 158 + src/lib/ecore_x/xlib/ecore_x_screensaver.c | 204 + src/lib/ecore_x/xlib/ecore_x_selection.c | 1002 + src/lib/ecore_x/xlib/ecore_x_sync.c | 159 + src/lib/ecore_x/xlib/ecore_x_test.c | 167 + src/lib/ecore_x/xlib/ecore_x_vsync.c | 351 + src/lib/ecore_x/xlib/ecore_x_window.c | 1727 ++ src/lib/ecore_x/xlib/ecore_x_window_prop.c | 760 + src/lib/ecore_x/xlib/ecore_x_window_shape.c | 658 + src/lib/ecore_x/xlib/ecore_x_xi2.c | 283 + src/lib/ecore_x/xlib/ecore_x_xinerama.c | 91 + src/modules/Makefile.am | 3 + src/modules/immodules/Makefile.am | 15 + src/modules/immodules/ibus/Makefile.am | 36 + src/modules/immodules/ibus/ibus_imcontext.c | 820 + src/modules/immodules/ibus/ibus_imcontext.h | 36 + src/modules/immodules/ibus/ibus_module.c | 103 + src/modules/immodules/scim/Makefile.am | 36 + src/modules/immodules/scim/scim_imcontext.cpp | 2900 +++ src/modules/immodules/scim/scim_imcontext.h | 42 + src/modules/immodules/scim/scim_module.cpp | 104 + src/modules/immodules/xim/Makefile.am | 29 + src/modules/immodules/xim/ecore_imf_xim.c | 1555 ++ src/tests/Makefile.am | 37 + src/tests/ecore_suite.c | 103 + src/tests/ecore_suite.h | 11 + src/tests/ecore_test_ecore.c | 366 + src/tests/ecore_test_ecore_con.c | 258 + src/tests/ecore_test_ecore_x.c | 60 + src/util/Makefile.am | 17 + src/util/makekeys.c | 326 + src/util/mkks.sh | 10 + 407 files changed, 229870 insertions(+) create mode 100644 .gitignore create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100755 autogen.sh create mode 100644 configure.ac create mode 100644 doc/Doxyfile.in create mode 100644 doc/Makefile.am create mode 100644 doc/e.css create mode 100644 doc/ecore.dox.in create mode 100644 doc/examples.dox create mode 100644 doc/foot.html create mode 100644 doc/head.html create mode 100644 doc/img/e.png create mode 100644 doc/img/ecore-pos-map.eps create mode 100644 doc/img/ecore-pos-map.png create mode 100644 doc/img/ecore_con-client-server-example.eps create mode 100644 doc/img/ecore_con-client-server-example.png create mode 100644 doc/img/ecore_con-client-server-example2.eps create mode 100644 doc/img/ecore_con-client-server-example2.png create mode 100644 doc/img/ecore_con-client-server.eps create mode 100644 doc/img/ecore_con-client-server.png create mode 100644 doc/img/ecore_thread.eps create mode 100644 doc/img/ecore_thread.png create mode 100644 doc/img/ecore_thread_feedback.eps create mode 100644 doc/img/ecore_thread_feedback.png create mode 100644 doc/img/edoxy.css create mode 100644 doc/img/foot_bg.png create mode 100644 doc/img/head_bg.png create mode 100644 doc/img/header_menu_background.png create mode 100644 doc/img/header_menu_background_last.png create mode 100644 doc/img/header_menu_current_background.png create mode 100644 doc/img/header_menu_unselected_background.png create mode 100644 doc/img/logo.png create mode 100644 doc/img/prog_flow.eps create mode 100644 doc/img/prog_flow.png create mode 100644 ecore-cocoa.pc.in create mode 100644 ecore-con.pc.in create mode 100644 ecore-config.pc.in create mode 100644 ecore-directfb.pc.in create mode 100644 ecore-evas.pc.in create mode 100644 ecore-fb.pc.in create mode 100644 ecore-file.pc.in create mode 100644 ecore-imf-evas.pc.in create mode 100644 ecore-imf.pc.in create mode 100644 ecore-input-evas.pc.in create mode 100644 ecore-input.pc.in create mode 100644 ecore-ipc.pc.in create mode 100644 ecore-psl1ght.pc.in create mode 100644 ecore-sdl.pc.in create mode 100644 ecore-wayland.pc.in create mode 100644 ecore-win32.pc.in create mode 100644 ecore-wince.pc.in create mode 100644 ecore-x.pc.in create mode 100644 ecore.pc.in create mode 100644 ecore.spec.in create mode 100644 ecore.supp create mode 100644 m4/ac_abstract_socket.m4 create mode 100644 m4/ac_attribute.m4 create mode 100644 m4/ac_path_generic.m4 create mode 100644 m4/check_x_extension.m4 create mode 100644 m4/ecore_check_module.m4 create mode 100644 m4/ecore_check_options.m4 create mode 100644 m4/efl_compiler.m4 create mode 100644 m4/efl_compiler_flag.m4 create mode 100644 m4/efl_coverage.m4 create mode 100644 m4/efl_doxygen.m4 create mode 100644 m4/efl_examples.m4 create mode 100644 m4/efl_gettimeofday.m4 create mode 100644 m4/efl_path_max.m4 create mode 100644 m4/efl_shm_open.m4 create mode 100644 m4/efl_tests.m4 create mode 100644 m4/efl_threads.m4 create mode 100644 po/ChangeLog create mode 100644 po/LINGUAS create mode 100644 po/Makevars create mode 100644 po/POTFILES.in create mode 100644 po/cs.po create mode 100644 po/de.po create mode 100644 po/el.po create mode 100644 po/fr.po create mode 100644 po/it.po create mode 100644 po/nl.po create mode 100644 po/pt.po create mode 100644 po/sl.po create mode 100644 src/Makefile.am create mode 100644 src/bin/Makefile.am create mode 100644 src/bin/ecore_config.c create mode 100644 src/bin/ecore_test.c create mode 100644 src/examples/Makefile.am create mode 100644 src/examples/ecore_animator_example.c create mode 100644 src/examples/ecore_client_bench.c create mode 100644 src/examples/ecore_con_client_example.c create mode 100644 src/examples/ecore_con_client_simple_example.c create mode 100644 src/examples/ecore_con_lookup_example.c create mode 100644 src/examples/ecore_con_server_example.c create mode 100644 src/examples/ecore_con_server_http_example.c create mode 100644 src/examples/ecore_con_server_simple_example.c create mode 100644 src/examples/ecore_con_url_cookies_example.c create mode 100644 src/examples/ecore_con_url_download_example.c create mode 100644 src/examples/ecore_con_url_headers_example.c create mode 100644 src/examples/ecore_evas_basics_example.c create mode 100644 src/examples/ecore_evas_buffer_example_01.c create mode 100644 src/examples/ecore_evas_buffer_example_02.c create mode 100644 src/examples/ecore_evas_callbacks.c create mode 100644 src/examples/ecore_evas_ews_example.c create mode 100644 src/examples/ecore_evas_object_example.c create mode 100644 src/examples/ecore_evas_window_sizes_example.c create mode 100644 src/examples/ecore_event_example_01.c create mode 100644 src/examples/ecore_event_example_02.c create mode 100644 src/examples/ecore_exe_example.c create mode 100644 src/examples/ecore_exe_example_child.c create mode 100644 src/examples/ecore_fd_handler_example.c create mode 100644 src/examples/ecore_fd_handler_gnutls_example.c create mode 100644 src/examples/ecore_file_download_example.c create mode 100644 src/examples/ecore_idler_example.c create mode 100644 src/examples/ecore_imf_example.c create mode 100644 src/examples/ecore_job_example.c create mode 100644 src/examples/ecore_pipe_gstreamer_example.c create mode 100644 src/examples/ecore_pipe_simple_example.c create mode 100644 src/examples/ecore_poller_example.c create mode 100644 src/examples/ecore_server_bench.c create mode 100644 src/examples/ecore_thread_example.c create mode 100644 src/examples/ecore_time_functions_example.c create mode 100644 src/examples/ecore_timer_example.c create mode 100644 src/examples/red.png create mode 100644 src/lib/Makefile.am create mode 100644 src/lib/ecore/Ecore.h create mode 100644 src/lib/ecore/Ecore_Getopt.h create mode 100644 src/lib/ecore/Makefile.am create mode 100644 src/lib/ecore/ecore.c create mode 100644 src/lib/ecore/ecore_alloc.c create mode 100644 src/lib/ecore/ecore_anim.c create mode 100644 src/lib/ecore/ecore_app.c create mode 100644 src/lib/ecore/ecore_events.c create mode 100644 src/lib/ecore/ecore_exe.c create mode 100644 src/lib/ecore/ecore_exe_ps3.c create mode 100644 src/lib/ecore/ecore_exe_win32.c create mode 100644 src/lib/ecore/ecore_exe_wince.c create mode 100644 src/lib/ecore/ecore_getopt.c create mode 100644 src/lib/ecore/ecore_glib.c create mode 100644 src/lib/ecore/ecore_idle_enterer.c create mode 100644 src/lib/ecore/ecore_idle_exiter.c create mode 100644 src/lib/ecore/ecore_idler.c create mode 100644 src/lib/ecore/ecore_job.c create mode 100644 src/lib/ecore/ecore_main.c create mode 100644 src/lib/ecore/ecore_pipe.c create mode 100644 src/lib/ecore/ecore_poll.c create mode 100644 src/lib/ecore/ecore_private.h create mode 100644 src/lib/ecore/ecore_signal.c create mode 100644 src/lib/ecore/ecore_thread.c create mode 100644 src/lib/ecore/ecore_throttle.c create mode 100644 src/lib/ecore/ecore_time.c create mode 100644 src/lib/ecore/ecore_timer.c create mode 100644 src/lib/ecore_cocoa/Ecore_Cocoa.h create mode 100644 src/lib/ecore_cocoa/Ecore_Cocoa_Keys.h create mode 100644 src/lib/ecore_cocoa/Makefile.am create mode 100644 src/lib/ecore_cocoa/ecore_cocoa.m create mode 100644 src/lib/ecore_cocoa/ecore_cocoa_private.h create mode 100644 src/lib/ecore_cocoa/ecore_cocoa_window.m create mode 100644 src/lib/ecore_con/Ecore_Con.h create mode 100644 src/lib/ecore_con/Makefile.am create mode 100644 src/lib/ecore_con/dns.c create mode 100644 src/lib/ecore_con/dns.h create mode 100644 src/lib/ecore_con/ecore_con.c create mode 100644 src/lib/ecore_con/ecore_con_alloc.c create mode 100644 src/lib/ecore_con/ecore_con_ares.c create mode 100644 src/lib/ecore_con/ecore_con_dns.c create mode 100644 src/lib/ecore_con/ecore_con_info.c create mode 100644 src/lib/ecore_con/ecore_con_local.c create mode 100644 src/lib/ecore_con/ecore_con_local_win32.c create mode 100644 src/lib/ecore_con/ecore_con_private.h create mode 100644 src/lib/ecore_con/ecore_con_socks.c create mode 100644 src/lib/ecore_con/ecore_con_ssl.c create mode 100644 src/lib/ecore_con/ecore_con_url.c create mode 100644 src/lib/ecore_config/Ecore_Config.h create mode 100644 src/lib/ecore_config/Makefile.am create mode 100644 src/lib/ecore_config/ecore_config.c create mode 100644 src/lib/ecore_config/ecore_config_db.c create mode 100644 src/lib/ecore_config/ecore_config_extra.c create mode 100644 src/lib/ecore_config/ecore_config_ipc.h create mode 100644 src/lib/ecore_config/ecore_config_ipc_ecore.c create mode 100644 src/lib/ecore_config/ecore_config_ipc_main.c create mode 100644 src/lib/ecore_config/ecore_config_private.h create mode 100644 src/lib/ecore_config/ecore_config_storage.c create mode 100644 src/lib/ecore_config/ecore_config_util.c create mode 100644 src/lib/ecore_config/ecore_config_util.h create mode 100644 src/lib/ecore_directfb/Ecore_DirectFB.h create mode 100644 src/lib/ecore_directfb/Makefile.am create mode 100644 src/lib/ecore_directfb/ecore_directfb.c create mode 100644 src/lib/ecore_directfb/ecore_directfb_keys.h create mode 100644 src/lib/ecore_directfb/ecore_directfb_private.h create mode 100644 src/lib/ecore_evas/Ecore_Evas.h create mode 100644 src/lib/ecore_evas/Makefile.am create mode 100644 src/lib/ecore_evas/ecore_evas.c create mode 100644 src/lib/ecore_evas/ecore_evas_buffer.c create mode 100644 src/lib/ecore_evas/ecore_evas_cocoa.c create mode 100644 src/lib/ecore_evas/ecore_evas_directfb.c create mode 100644 src/lib/ecore_evas/ecore_evas_ews.c create mode 100644 src/lib/ecore_evas/ecore_evas_extn.c create mode 100644 src/lib/ecore_evas/ecore_evas_fb.c create mode 100644 src/lib/ecore_evas/ecore_evas_private.h create mode 100644 src/lib/ecore_evas/ecore_evas_psl1ght.c create mode 100644 src/lib/ecore_evas/ecore_evas_sdl.c create mode 100644 src/lib/ecore_evas/ecore_evas_util.c create mode 100644 src/lib/ecore_evas/ecore_evas_wayland_egl.c create mode 100644 src/lib/ecore_evas/ecore_evas_wayland_shm.c create mode 100644 src/lib/ecore_evas/ecore_evas_win32.c create mode 100644 src/lib/ecore_evas/ecore_evas_wince.c create mode 100644 src/lib/ecore_evas/ecore_evas_x.c create mode 100644 src/lib/ecore_fb/Ecore_Fb.h create mode 100644 src/lib/ecore_fb/Makefile.am create mode 100644 src/lib/ecore_fb/ecore_fb.c create mode 100644 src/lib/ecore_fb/ecore_fb_kbd.c create mode 100644 src/lib/ecore_fb/ecore_fb_keytable.h create mode 100644 src/lib/ecore_fb/ecore_fb_li.c create mode 100644 src/lib/ecore_fb/ecore_fb_private.h create mode 100644 src/lib/ecore_fb/ecore_fb_ps2.c create mode 100644 src/lib/ecore_fb/ecore_fb_ts.c create mode 100644 src/lib/ecore_fb/ecore_fb_vt.c create mode 100644 src/lib/ecore_file/Ecore_File.h create mode 100644 src/lib/ecore_file/Makefile.am create mode 100644 src/lib/ecore_file/ecore_file.c create mode 100644 src/lib/ecore_file/ecore_file_download.c create mode 100644 src/lib/ecore_file/ecore_file_monitor.c create mode 100644 src/lib/ecore_file/ecore_file_monitor_inotify.c create mode 100644 src/lib/ecore_file/ecore_file_monitor_poll.c create mode 100644 src/lib/ecore_file/ecore_file_monitor_win32.c create mode 100644 src/lib/ecore_file/ecore_file_path.c create mode 100644 src/lib/ecore_file/ecore_file_private.h create mode 100644 src/lib/ecore_imf/Ecore_IMF.h create mode 100644 src/lib/ecore_imf/Makefile.am create mode 100644 src/lib/ecore_imf/ecore_imf.c create mode 100644 src/lib/ecore_imf/ecore_imf_context.c create mode 100644 src/lib/ecore_imf/ecore_imf_module.c create mode 100644 src/lib/ecore_imf/ecore_imf_private.h create mode 100644 src/lib/ecore_imf_evas/Ecore_IMF_Evas.h create mode 100644 src/lib/ecore_imf_evas/Makefile.am create mode 100644 src/lib/ecore_imf_evas/ecore_imf_evas.c create mode 100644 src/lib/ecore_input/Ecore_Input.h create mode 100644 src/lib/ecore_input/Makefile.am create mode 100644 src/lib/ecore_input/ecore_input.c create mode 100644 src/lib/ecore_input/ecore_input_compose.c create mode 100644 src/lib/ecore_input/ecore_input_compose.h create mode 100644 src/lib/ecore_input/ecore_input_private.h create mode 100644 src/lib/ecore_input_evas/Ecore_Input_Evas.h create mode 100644 src/lib/ecore_input_evas/Makefile.am create mode 100644 src/lib/ecore_input_evas/ecore_input_evas.c create mode 100644 src/lib/ecore_input_evas/ecore_input_evas_private.h create mode 100644 src/lib/ecore_ipc/Ecore_Ipc.h create mode 100644 src/lib/ecore_ipc/Makefile.am create mode 100644 src/lib/ecore_ipc/ecore_ipc.c create mode 100644 src/lib/ecore_ipc/ecore_ipc_private.h create mode 100644 src/lib/ecore_psl1ght/Ecore_Psl1ght.h create mode 100644 src/lib/ecore_psl1ght/Ecore_Psl1ght_Keys.h create mode 100644 src/lib/ecore_psl1ght/Makefile.am create mode 100644 src/lib/ecore_psl1ght/ecore_psl1ght.c create mode 100644 src/lib/ecore_psl1ght/ecore_psl1ght_private.h create mode 100644 src/lib/ecore_psl1ght/gemutil.c create mode 100644 src/lib/ecore_psl1ght/gemutil.h create mode 100644 src/lib/ecore_psl1ght/moveutil.c create mode 100644 src/lib/ecore_psl1ght/moveutil.h create mode 100644 src/lib/ecore_psl1ght/spursutil.c create mode 100644 src/lib/ecore_psl1ght/spursutil.h create mode 100644 src/lib/ecore_sdl/Ecore_Sdl.h create mode 100644 src/lib/ecore_sdl/Ecore_Sdl_Keys.h create mode 100644 src/lib/ecore_sdl/Makefile.am create mode 100644 src/lib/ecore_sdl/ecore_sdl.c create mode 100644 src/lib/ecore_sdl/ecore_sdl_private.h create mode 100644 src/lib/ecore_wayland/Ecore_Wayland.h create mode 100644 src/lib/ecore_wayland/Makefile.am create mode 100644 src/lib/ecore_wayland/ecore_wl.c create mode 100644 src/lib/ecore_wayland/ecore_wl_dnd.c create mode 100644 src/lib/ecore_wayland/ecore_wl_input.c create mode 100644 src/lib/ecore_wayland/ecore_wl_output.c create mode 100644 src/lib/ecore_wayland/ecore_wl_private.h create mode 100644 src/lib/ecore_wayland/ecore_wl_window.c create mode 100644 src/lib/ecore_win32/Ecore_Win32.h create mode 100644 src/lib/ecore_win32/Makefile.am create mode 100644 src/lib/ecore_win32/ecore_win32.c create mode 100644 src/lib/ecore_win32/ecore_win32_cursor.c create mode 100755 src/lib/ecore_win32/ecore_win32_dnd.c create mode 100644 src/lib/ecore_win32/ecore_win32_dnd_data_object.cpp create mode 100644 src/lib/ecore_win32/ecore_win32_dnd_data_object.h create mode 100644 src/lib/ecore_win32/ecore_win32_dnd_drop_source.cpp create mode 100644 src/lib/ecore_win32/ecore_win32_dnd_drop_source.h create mode 100644 src/lib/ecore_win32/ecore_win32_dnd_drop_target.cpp create mode 100644 src/lib/ecore_win32/ecore_win32_dnd_drop_target.h create mode 100644 src/lib/ecore_win32/ecore_win32_dnd_enumformatetc.cpp create mode 100644 src/lib/ecore_win32/ecore_win32_dnd_enumformatetc.h create mode 100644 src/lib/ecore_win32/ecore_win32_event.c create mode 100644 src/lib/ecore_win32/ecore_win32_private.h create mode 100644 src/lib/ecore_win32/ecore_win32_window.c create mode 100644 src/lib/ecore_wince/Ecore_WinCE.h create mode 100644 src/lib/ecore_wince/Makefile.am create mode 100644 src/lib/ecore_wince/ecore_wince.c create mode 100644 src/lib/ecore_wince/ecore_wince_event.c create mode 100644 src/lib/ecore_wince/ecore_wince_private.h create mode 100644 src/lib/ecore_wince/ecore_wince_window.c create mode 100644 src/lib/ecore_x/Ecore_X.h create mode 100644 src/lib/ecore_x/Ecore_X_Atoms.h create mode 100644 src/lib/ecore_x/Ecore_X_Cursor.h create mode 100644 src/lib/ecore_x/Makefile.am create mode 100644 src/lib/ecore_x/ecore_x_atoms_decl.h create mode 100644 src/lib/ecore_x/xcb/Makefile.am create mode 100644 src/lib/ecore_x/xcb/ecore_xcb.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_atoms.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_composite.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_cursor.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_damage.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_dnd.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_dpms.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_drawable.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_e.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_error.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_events.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_extensions.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_gc.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_gesture.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_icccm.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_image.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_input.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_keymap.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_mwm.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_netwm.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_pixmap.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_private.h create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_randr.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_region.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_render.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_screensaver.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_selection.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_shape.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_sync.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_textlist.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_vsync.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_window.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_window_prop.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_window_shadow.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_window_shape.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_xdefaults.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_xfixes.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_xinerama.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_xtest.c create mode 100644 src/lib/ecore_x/xlib/Makefile.am create mode 100644 src/lib/ecore_x/xlib/ecore_x.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_atoms.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_composite.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_cursor.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_damage.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_dnd.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_dpms.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_drawable.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_e.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_error.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_events.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_fixes.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_gc.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_gesture.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_icccm.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_image.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_mwm.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_netwm.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_pixmap.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_private.h create mode 100644 src/lib/ecore_x/xlib/ecore_x_randr.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_randr.h create mode 100644 src/lib/ecore_x/xlib/ecore_x_randr_11.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_randr_12.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_randr_12_edid.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_randr_13.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_region.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_screensaver.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_selection.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_sync.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_test.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_vsync.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_window.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_window_prop.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_window_shape.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_xi2.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_xinerama.c create mode 100644 src/modules/Makefile.am create mode 100644 src/modules/immodules/Makefile.am create mode 100644 src/modules/immodules/ibus/Makefile.am create mode 100644 src/modules/immodules/ibus/ibus_imcontext.c create mode 100644 src/modules/immodules/ibus/ibus_imcontext.h create mode 100644 src/modules/immodules/ibus/ibus_module.c create mode 100644 src/modules/immodules/scim/Makefile.am create mode 100644 src/modules/immodules/scim/scim_imcontext.cpp create mode 100644 src/modules/immodules/scim/scim_imcontext.h create mode 100644 src/modules/immodules/scim/scim_module.cpp create mode 100644 src/modules/immodules/xim/Makefile.am create mode 100644 src/modules/immodules/xim/ecore_imf_xim.c create mode 100644 src/tests/Makefile.am create mode 100644 src/tests/ecore_suite.c create mode 100644 src/tests/ecore_suite.h create mode 100644 src/tests/ecore_test_ecore.c create mode 100644 src/tests/ecore_test_ecore_con.c create mode 100644 src/tests/ecore_test_ecore_x.c create mode 100644 src/util/Makefile.am create mode 100644 src/util/makekeys.c create mode 100755 src/util/mkks.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1454d80 --- /dev/null +++ b/.gitignore @@ -0,0 +1,91 @@ +*.o +*.lo +*.a +*.la +.deps +.libs +*~ +*.gmo +*.pc +/configure +/config.status +Makefile +Makefile.in +/ABOUT-NLS +/README +/aclocal.m4 +/autom4te.cache/ +/config.cache +/config.cache-env +/config.guess +/config.h +/config.h.in +/config.log +/config.rpath +/config.sub +/depcomp +/doc/ecore.dox +/ecore.spec +/install-sh +/libtool +/ltmain.sh +/m4/codeset.m4 +/m4/gettext.m4 +/m4/glibc21.m4 +/m4/iconv.m4 +/m4/intdiv0.m4 +/m4/intmax.m4 +/m4/inttypes-pri.m4 +/m4/inttypes.m4 +/m4/inttypes_h.m4 +/m4/isc-posix.m4 +/m4/lcmessage.m4 +/m4/lib-ld.m4 +/m4/lib-link.m4 +/m4/lib-prefix.m4 +/m4/libtool.m4 +/m4/longdouble.m4 +/m4/longlong.m4 +/m4/ltoptions.m4 +/m4/ltsugar.m4 +/m4/ltversion.m4 +/m4/lt~obsolete.m4 +/m4/nls.m4 +/m4/po.m4 +/m4/printf-posix.m4 +/m4/progtest.m4 +/m4/signed.m4 +/m4/size_max.m4 +/m4/stdint_h.m4 +/m4/uintmax_t.m4 +/m4/ulonglong.m4 +/m4/wchar_t.m4 +/m4/wint_t.m4 +/m4/xsize.m4 +/m4/glibc2.m4 +/m4/intl.m4 +/m4/intldir.m4 +/m4/intlmacosx.m4 +/m4/lock.m4 +/m4/visibility.m4 +/missing +/mkinstalldirs +/po/Makefile.in.in +/po/Makevars.template +/po/POTFILES +/po/Rules-quot +/po/boldquot.sed +/po/ecore.pot +/po/en@boldquot.header +/po/en@quot.header +/po/insert-header.sin +/po/quot.sed +/po/remove-potcdate.sed +/po/remove-potcdate.sin +/po/stamp-po +/stamp-h1 +/doc/Doxyfile +/src/bin/ecore_test +/src/lib/ecore_x/xcb/ecore_xcb_keysym_table.h +/src/util/makekeys +INSTALL diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..f531462 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,54 @@ +Myoungwoon Roy Kim(roy_kim) +The Rasterman +Tom Gilbert +Burra +Chris Ross +Term +Tilman Sauerbeck +Ibukun Olumuyiwa +Yuri +Nicholas Curran +Howell Tam +Nathan Ingersoll +Andrew Elcock +Kim Woelders +Sebastian Dransfeld +Simon Poole +Jorge Luis Zapata Muga +dan sinclair +Michael 'Mickey' Lauer +David 'onefang' Seikel +Hisham 'CodeWarrior' Mardam Bey +Brian 'rephorm' Mattern +Tim Horton +Arnaud de Turckheim 'quarium' +Matt Barclay +Peter Wehrfritz +Albin "Lutin" Tonnerre +Vincent Torri +Lars Munch +Andre Dieb +Mathieu Taillefumier +Rui Miguel Silva Seabra +Samsung Electronics +Samsung SAIT +Nicolas Aguirre +Brett Nash +Mike Blumenkrantz +Leif Middelschulte +Mike McCormack +Sangho Park +Jihoon Kim +PnB +Daniel Juyung Seo +Christopher 'devilhorns' Michael +ChunEon Park (Hermet) +xlopez@igalia.com +Rafael Antognolli +Kim Yunhan +Youness Alaoui +Bluezery +Doyoun Kang +Haifeng Deng +Jérémy Zurcher +Vikram Narayanan diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..fb8c49d --- /dev/null +++ b/COPYING @@ -0,0 +1,25 @@ +Copyright notice for Ecore: + +Copyright (C) 2000-2011 Carsten Haitzler and various contributors (see AUTHORS) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e80701c --- /dev/null +++ b/ChangeLog @@ -0,0 +1,890 @@ +2011-01-29 Carsten Haitzler (The Rasterman) + + 1.0.0 release + +2011-01-29 Mike McCormack + + * Convert fd list to inlist to save allocs + +2011-01-29 Rui Miguel Silva Seabra + + * make https not fail (that's curl's responsibility, really). + +2011-01-31 Carsten Haitzler (The Rasterman) + + * Fix ecore-evas CAN send "render done" messages even if not + waiting for sync counter when using gl engine. new semi-sync + mode to account for that. + +2011-02-01 Mike McCormack + + * Remove SIGRT from ecore's signals since it's unused and broken + +2011-02-09 Mathieu Taillefumier + + * Add xrandr backlight support to ecore_x + +2011-02-10 Mike Blumenkrantz + + * Added some more possibly useless safety checks to ecore_con_ares + + * Implement event-driven error message api for all non-curl ecore_con + +ECORE_CON_EVENT_CLIENT_ERROR, ECORE_CON_EVENT_SERVER_ERROR events + +Ecore_Con_Event_Server_Error, Ecore_Con_Event_Client_Error types + + * Unify event handler code + * Always increment server event count for client events + +2011-02-11 Mike Blumenkrantz + + * Added ecore_con_client_port_get + +2011-02-16 Sangho Park + + * Added ecore_file_download_full API. + +2011-02-20 Vincent Torri + + * Ecore_Win32: improve resize of windows and fix key up event for + the 'space' key. + * Ecore_WinCE: do not erase a window background + +2011-02-21 Jihoon Kim + + * Add get calls in ecore_imf for ecore_imf_context_canvas_get() and + ecore_imf_context_window_get(). + +2011-02-21 Raoul Hecky + + * Remove 300 second timeout so large downloads work in ecore_con. + +2011-02-22 Carsten Haitzler (The Rasterman) + + * Fix ecore-file inotify fd would be duplicated in children + on fork. Have it detecti this on next monitor add and re-init the + inotify fd and fd handler. + +2011-02-24 Vincent Torri + + * Ecore_File: fix compilation when ecore_con and curl are not + available + +2011-02-27 Jihoon Kim + + * Add ecore_imf_context_preedit_string_with_attributes_get API. + +2011-03-01 Raoul Hecky + + * Add ecore_con_url_ssl_verify_peer_set API. + +2011-03-01 Guillaume Friloux + + * Fix detection of complete file write in ecore_file inotify. + +2011-03-16 Cedric Bail + + * Add ecore_thread_reschedule. + +2011-03-19 Mike Blumenkrantz + + * Fix crash in ecore_con_ssl related to attempted connections on a dead socket + +2011-03-23 Carsten Haitzler (The Rasterman) + + * Fix ecore-evas interceptor didn't handle override-redirect + windows correctly, expecting a feed-back event from x, which it didn't + get. + +2011-03-23 Elixirious + + * Fix ecore_con_url_ftp_upload upload the file until the end. + +2011-03-29 PnB + + * Add ecore_con_url_ssl_ca_set to manually set a certificate authority. + +2011-03-30 Carsten Haitzler (The Rasterman) + + * Ecore_X gains some more x sync counter controls and Ecore_Evas + now uses the netwm sync protocol to get wm's to only configure + as fast as it can keep drawing. + +2011-04-01 Leif Middelschulte + + * Add ecore_x_randr_edid_* data extraction and validation functions + for EDID structures. + +2011-04-01 Cedric Bail + + * Add ecore_con_url_pipeline_set and ecore_con_url_pipeline_get for + HTTP 1.1 pipelining support. + +2011-04-05 Cedric Bail + + * Remove Ecore_Evas Cocoa backend that use depreacted Evas Quartz + backend. + +2011-04-11 Hannes Janetzek + + * Fix removal of windows from ignore_list with ecore_x_window_ignore_set + +2011-04-13 Doyun Kang + + * Ecore_X + Ecore_Evas: Add more support for shape input setting + +2011-04-15 Carsten Haitzler (The Rasterman) + + * Fix bug in Ecore_Evas setting modifiers for + sub-buffer-canvas. They never got set. Now they do. + +2011-04-19 Mike Blumenkrantz + + * Add ecore_exe_data_set + +2011-04-20 Carsten Haitzler (The Rasterman) + + * Added ecore animator timeline, where animator runs for a + specified time (in seconds) and then stops, but it also passes + the position in the timeline (as a 0.0 to 1.0 value) to the + callback which it can then use the new pos map call to map to + some ease in/out, bounce, spring or whatever position. + +2011-04-28 Eduardo Felipe Castegnaro + + * Add a monotonic clock implementation for Mac OS X to fix warning. + Mac OS X does not provide an implementation of clock_gettime() + even though it's POSIX, but it does provide a fast high-resolution + monotonic clock through mach specific APIs that are perfectly suited + for usage in ecore_timer. + +2011-04-20 Jihoon Kim + + * Ecore_IMF: Added support for auto-capitalization and prediction + control API's + +2011-05-03 Carsten Haitzler (The Rasterman) + + * Fixed null pointer dereference in selection notification + handling in Ecore_X. + +2011-05-12 Carsten Haitzler (The Rasterman) + + * Add a custom Ecore Animator source and tick ability to be able + to plug in external animator tick sources like vblank interrupts + and so on. + +2011-05-14 Cedric Bail + + * Sync GNUTLS threads activation with Eina. + +2011-05-14 Vincent Torri + + * Make ecore_con work on Windows (only the local connections + need a port) + * Make ecore_ipc compile on Windows + +2011-05-17 Cedric Bail + + * Add ecore_timer_dump. + +2011-05-19 Carsten Haitzler (The Rasterman) + + * Fix Ecore_X shadow tree search handling to respect shape and + shape input of windows. + +2011-05-20 Daniel Juyung Seo (SeoZ) + + * Ecore ecore_main.c: Fixed ecore_main_loop + (_ecore_main_loop_iterate_internal). This fixes fd handler pending + issue when ecore_idler callback adds ecore_job/event. + * Ecore ecore_main.c: Refactoring _ecore_main_loop_iterate_internal(). + +2011-05-27 Gustavo Sverzut Barbieri (k-s) + + * Ecore_X: introduce ecore_x_screen_size_get() + * Ecore_Evas: be safer when returning Ecore_Evas* from + ecore_evas_ecore_evas_get() + * Ecore_Evas: introduce ecore_evas_screen_geometry_get() + +2011-05-30 Cedric Bail + + * Add ecore_pipe_freeze/thaw to suspend and restart watching the pipe + inside the main loop. + +2011-06-09 Cedric Bail + + * Add ecore_pipe_wait (should only called from outside of the main loop). + +2011-06-15 Mike Blumenkrantz + + * Add ecore_con_ssl_client/server_upgrade to begin asynchronously upgrading an + existing connection to SSL/TLS, emitting ECORE_CON_CLIENT/SERVER_UPGRADE event + upon completion. + +2011-06-16 Cedric Bail + + * Fix ecore_x_selection_convert not taking selection length into account. + +2011-06-17 Mike Blumenkrantz + + * ecore_con_server_timeout_get/set now applies to client-type servers + +2011-06-20 Ulrich Eckhardt + + * Removed support for evas xrender engine from ecore-evas as + it is not a deprecated engine in evas and no longer needs support. + +2011-06-20 Jihoon Kim + + * Ecore_IMF: Added ecore_imf_context_input_panel_enabled_set/get API + +2011-06-25 Mike Blumenkrantz + + * Fix security hole in openssl certificate verification + * Fix gnutls server-client certificate verification + * New function: ecore_con_ssl_server_verify_basic for only verifying + certificates against a server's Common Name (CN) or its + Subject Alternative Name (if available) + +2011-06-28 Carsten Haitzler (The Rasterman) + + * Add ecore_throttle mechanism to voluntarily do powersaving to + avoid wakeups and excess animation etc. when in the background + or another "powersave" state. + +2011-07-01 Carsten Haitzler (The Rasterman) + + * Fix epoll delete fd handling in child process - #796 + +2011-07-07 Jihoon Kim + + * Ecore_IMF: Added ecore_imf_context_cursor_location_set API + +2011-07-22 Mike Blumenkrantz + + * Added ecore_con_url_url_get + +2011-07-26 Carsten Haitzler (The Rasterman) + + * Fix timer precision handling for grouping timer ticks so + they actually do tick off together + +2011-07-28 Cedric Bail + + * Add ecore_main_loop_thread_safe_call_async. + +2011-07-26 Carsten Haitzler (The Rasterman) + + * Make ecore-evas give more errors on stderr when engines are + not found. + +2011-08-16 Cedric Bail + + * Add ecore_main_loop_thread_safe_call_sync. + +2011-08-17 Cedric Bail + + * Add ecore_thread_main_loop_begin and ecore_thread_main_loop_end. + Usefull to protect EFL call from another thread. + +2011-09-12 Mike Blumenkrantz + + * Add ecore_con_server_fd_get, ecore_con_client_fd_get for manipulating + server file descriptors. + +2011-09-13 Mike Blumenkrantz + + * Add ECORE_CON_EVENT_CLIENT_WRITE, ECORE_CON_EVENT_SERVER_WRITE for + obtaining progress of socket writes + +2011-09-18 Carsten Haitzler (The Rasterman) + + * Fix bug in Ecore_X generic event handling for extended event + sizes when freeing (and allocating) the data. + +2011-09-29 Youness Alaoui (KaKaRoTo) + + * Port ecore-con to work on systems without IPv6 support + * Use inet_ntop instead of getnameinfo for ecore_con_client_get_ip + * Added ecore-con unit test + +2011-10-28 Jiyoun Park + + * Fix bug in Ecore_X using geometry value instead of + recently requested geometry value + +2011-10-28 Rafael Antognolli + + * Make the framebuffer engine input use ecore_input_evas instead + of feeding evas input events directly. + +2011-11-02 Nicolas Aguirre + + * Add support ecore_cocoa_evas engine. + * Fix ecore_cocoa code to correctly handle cocoa window. + +2011-11-02 Bluezery + + * Fix return error handling in ecore_file_download when + ecore_con_url_get() fails. + +2011-11-20 Vincent Torri + + * Ecore_Win32, Ecore_WinCE: fix Shift, Control and Alt keys + detection + * Ecore_Win32: fix "mouse-down inside and mouse-up outside" issue + +2011-11-2 Carsten Haitzler (The Rasterman) + + * Fix bug ecore-evas for fb, buffer, sdl back-ends to ensure + mouse is in on init (as events wont always give this) and focus + is set on show if appropriate if no focus in/out events come + from the back-end later + * Fix setting override state to only hide if it should be + visible at that point in x back end support + +2011-11-24 Rafael Antognolli + + * Add ecore_fb_input_device_window_set(). + +2011-11-27 Vincent Torri + + * Fix and improve key management on Windows XP + +2011-11-29 Vincent Torri + + * Discard left Ctrl when AltGr is pressed (Windows XP) + * Fix the string value for the Delete key (Windows XP) + * Fix the key release values for non keystroke keys (Windows XP) + +2011-11-29 Mike McCormack + + * Allow quitting before entering the glib version of the main loop + +2011-12-02 Carsten Haitzler (The Rasterman) + + 1.1.0 release + +2011-12-02 Mike Blumenkrantz + + * Use mempools for allocations + +2011-12-02 Term + + * added ecore_x_randr_output_backlight_available() + +2011-12-03 Vincent Torri + + * Fix the modifiers value (Windows XP) + +2011-12-04 Mike Blumenkrantz + + * added ecore_timer_reset() + +2011-12-05 Mike Blumenkrantz + + * added ecore_con_socks api + +2011-12-07 Mike Blumenkrantz + + * Allow SSL certificates to be loaded for STARTTLS + * Added functions to set/get the hostname used for SSL certificate verification + * ecore_con_ssl_server_cafile_add() now accepts directories + +2011-12-10 Mike Blumenkrantz + + * Fix case where SSL certificates would not be used + * Added ECORE_CON_REMOTE_CORK for applying TCP_CORK to sends + +2011-12-12 Carsten Haitzler (The Rasterman) + + * Fix bug where an animator that just keeps adding another + animator keeps the animator handler in an infinite loop. Do + the same as timers and mark them as "just added" to skip in + this run of animators + +2011-12-13 Doyun Kang + + * Add ability to get resource id of last x error in ecore_x. + +2011-12-16 Carsten Haitzler (The Rasterman) + + * Clean up some ecore-evas-buffer code + * Add Ecore-evas extn (external) plug and socket canvas wrappers + allowing for any ecore-evas to contain an image object that is + a "socket" for other processes to plug into with "plugs" and + thus provide image content via a canvas remotely (from another + process) as well as the socket process passing in events to the + plug process to it can see key, mouse, multi etc. events. + + +2011-12-16 Mike Blumenkrantz + + * Fix possible 0 byte allocation in ecore-x + +2011-12-20 Carsten Haitzler (The Rasterman) + + * Fix probable leak for g_static_mutex's on some architectures + +2011-12-20 Jihoon Kim + + * Add XIM attribute support to Ecore_IMF + +2011-12-21 Tae-Hwan Kim (Bluezery) + + * Add proxy set and timeout set functions in ecore_con. + +2011-12-26 Tae-Hwan Kim (Bluezery) + + * Add proxy username/password set functions in ecore_con. + +2011-12-26 Christopher Michael (devilhorns) + + * Add Ecore_Wayland (backend to support Wayland). + * Add Shm and Egl engines for ecore_evas to draw in Wayland. + +2011-12-27 Carsten Haitzler (The Rasterman) + + * Fix mouse down grab counts going bad by missing events. + +2011-12-29 Carsten Haitzler (The Rasterman) + + * Fix massive post data problem in ecore-con that would cause + post data to be corrupted (as it was never copied into the + ecore con url struct) or could cause crashes if the memory + pointed to became invalid. + +2012-01-04 Carsten Haitzler (The Rasterman) + + * Add HEX, TERMINAL and PASSWORD layouts to ecore-imf + +2011-01-05 Jiyoun Park (Jypark) + + * Fix Ecore-evas extn (external) for multi client model. + "Socket" creates canvas and other process can show that canvas + using "Plug" image object. Before only one to one communication + is possible, but now many "plug"s can show socket's canvas. + +2011-12-26 Christopher Michael (devilhorns) + + * Add Ecore_X function to return the keycode from a given keyname. + +2012-02-06 Jihoon Kim (jihoon) + + * Set ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL as default layout in ecore_imf_context_add. + * Add Ecore_IMF function to set or get the input panel-specific data. + +2012-02-07 Jihoon Kim (jihoon) + + * Support ecore_imf_context_input_panel_show/hide in XIM and SCIM module. + +2012-02-08 Carsten Haitzler (The Rasterman) + + * Add ecore_con_url_http_version_set() to set url request version + +2012-02-09 Jihoon Kim (jihoon) + + * Provide compose, string in key down/up event in case of scim-input-pad. + +2012-02-10 Christopher Michael (devilhorns) + + * Add Ecore_Evas function to allow setting a mouse pointer from efl/elm wayland clients. + +2012-02-15 Jihoon Kim (jihoon) + + * Add ecore_imf APIs to set return key type, disable return key. + +2012-02-16 Leif Middelschulte (T_UNIX) + + * Add ecore_x_randr_mode_add to add a mode to a display + * Add ecore_x_randr_mode_del to remove a mode from the display + * Add ecore_x_randr_output_mode_add to add a mode to an output + * Add ecore_x_randr_output_mode_del to remove a mode from an output + +2012-02-10 Jérémy Zurcher + + * Improve callbacks in ecore_evas to use typedefs for readability. + +2012-02-20 Cedric Bail + + * Rewrite internal of Ecore_Thread to use Eina_Lock and ecore_main_loop_thread_safe_call_async. + +2012-02-23 Cedric Bail + + * Move to Evas buffer engine for Ecore_Evas SDL software backend. + +2012-02-23 Leif Middelschulte (T_UNIX) + + * Add ecore_x_randr_window_crtcs_get to get the crtcs that display a + window. + * Deprecate ecore_x_randr_current_output_get. Use + ecore_x_randr_window_crtcs_get instead. + +2012-02-24 Doyun Kang + + * Add indicator controls to ecore_x + +2012-02-26 Carsten Haitzler (The Rasterman) + + * Fix ecore_file_download to not limit downloads to 30sec. + +2012-02-28 Carsten Haitzler (The Rasterman) + + * Add ecore_x_netwm_icons_set() + * Add ecore_evas_window_group_set() ecore_evas_window_group_get() + ecore_evas_aspect_set() ecore_evas_aspect_get() + ecore_evas_urgent_set() ecore_evas_urgent_get() + ecore_evas_modal_set() ecore_evas_modal_get() + ecore_evas_demand_attention_set() + ecore_evas_demand_attention_get() + ecore_evas_focus_skip_set() ecore_evas_focus_skip_get() + ecore_evas_callback_state_change_set() + +2012-02-28 Christopher Michael (devilhorns) + + * Refactor Ecore_Wayland code to improve running EFL + applications as Wayland Clients. + * Refactor Ecore_Evas Wayland code to match changes in + Ecore_Wayland + +2012-02-29 Jihoon Kim (jihoon) + + * Add ecore_imf_context_input_panel_caps_lock_mode_set/get to set the caps lock mode on the input panel + +2012-03-07 ChunEon Park (Hermet) + + * Add ecore_x_illume_clipboard_state_set() + ecore_x_illume_clipboard_state_get() + ecore_x_illume_clipboard_geometry_set() + ecore_x_illume_clipboard_geometry_get() + +2012-03-07 Carsten Haitzler (The Rasterman) + + * Add atoms and api for rotation and indicator transparency in + ecore_x/ecore_evas + +2012-03-07 Mike Blumenkrantz (discomfitor/zmike) + + * Add ecore_con_url_status_code_get() to check return code at any time + +2012-03-09 Carsten Haitzler (The Rasterman) + + * Fix ecore_thread_feedback_run to work as the documentation and logic tell us. + +2012-03-10 Cedric Bail + + * Fix double free at end of execution of Ecore_Thread with feedback. + +2012-03-13 Leif Middelschulte (T_UNIX) + + * Fix ecore_x_randr_modes_info_get to not cut off the trailing '\0' + anymore + +2012-03-20 Vincent Torri + + * Rename ecore_win32_window_focus_set() to ecore_win32_window_focus() + to match ecore_x API. + * Add ecore_wince_window_focus(), ecore_wince_window_focus_get() + and ecore_win32_window_focus_get(). + +2012-03-26 Shinwoo Kim + + * Do not autorepeat Ctrl, Shift, Alt and Win keys on Windows + +2012-03-26 Christopher Michael (devilhorns) + + Ecore_Wayland: + * Add ecore_wl_dpi_get + * Implement functions for input grab/ungrab + * Implement setting surface input & opaque regions + * Implement popup windows + * Implement ecore_wl_window_transparent_set function + * Implement function to allow setting Ecore_Wl_Window type. + +2012-03-26 Jihoon Kim (jihoon) + + * scim-immodule: fix bug candidate window covers the preedit string when preedit string appears in 2 line. + +2012-03-29 Carsten Haitzler (The Rasterman) + + * Fix range of issues with ecore_fb and even ecore_evas where + it didn't work right on the fb. (timestamps wrong, focus + handling etc.). This makes it work fully again. + +2012-04-13 Gustavo Sverzut Barbieri (k-s) + + * remove EAPI from _ecore_event_signal_user_new(). It should never + be exported outside of libecore.so + * stop leaking every system signal event. + +2012-04-16 Shinwoo Kim + + * Check control charater and convert into printing character on Windows + +2012-04-20 Vincent Torri + + * Add override_set() support in ecore_evas_win32. + +2012-04-26 Carsten Haitzler (The Rasterman) + + 1.2.0 release + +2012-05-08 Cedric Bail + + * Don't over allocate Ecore_Pipe during ecore_init/ecore_shutdown. + +2012-05-10 Cedric Bail + + * Reduce rounding error in ecore_animator_pos_map. + +2012-05-10 Jiyoun Park + + * Send mouse move event before mouse down event in ecore_extn + +2012-05-13 Carsten Haitzler (The Rasterman) + + * Fix ecore-x randr issues with memory access when building + output arrays which are memory segv bugs waiting to crash. + +2012-05-17 Vincent Torri + + * Add transparent support in ecore_evas on Windows (GDI engine only) + +2012-05-22 Cedric Bail + + * Reduce race condition on Ecore_Thread shutdown. + +2012-05-22 Carsten Haitzler (The Rasterman) + + * Add ecore_x_mouse_in_send() and ecore_x_mouse_out_send() + * Add ecore_x illume access control/action atoms+api's + +2012-05-24 Doyoun Kang + + * Add Ecore_X_Error_Code enumeration in ecore_x + +2012-05-24 Carsten Haitzler (The Rasterman) + + * Fix ecore-thread scheduling issue where re-scheduled threads + will hold a loop busy and not allow feedback workers to run, + so now have fairer scheduling. + * Allow 16 * cpu num for worker threads (default still cpu num) + +2012-05-25 Carsten Haitzler (The Rasterman) + + * Fix ecore mainloop issue if you begin the mainloop, keep a + timer around, quit mainloop, then start it again expecting the timer + to keep ticking off. also happens to be an issue with + iterating the mainloop. + +2012-05-25 Rob Bradford + + * Make ecore_{software_x11, software_x11_8, software_x11_16, wayland, + directfb}_window_get return 0 if the Ecore_Evas was not created with + the appropriate constructor. + +2012-05-29 Rob Bradford + + * Initial cursor support for Wayland: + * Add api to the ecore_wl_input_ namespace to allow setting the buffer + to use for the pointer and for loading a named cursor from a cursor + theme. Under the Wayland protocol the cursor is associated with the + input device. + * Add helper functions to ecore_wl_window to set the cursor based on + the active pointer input device for the window. + * Load the cursor theme when the SHM interface is ready and provide an + API call to provide a wl_cursor for a given name. + * Add API to restore to the default cursor and then use that when the + pointer enters the surface to ensure compliance with the Wayland + protocol. + +2012-05-30 Cedric Bail + + * Force cancel of all running Ecore_Thread on shutdown. + * Make Ecore_Thread work reliabily when main loop isn't running. + +2012-05-30 Mariusz Grzegorczyk + + * Small fix to ecore-evas buffer engine on resize to make the + right kind of buffer cavas (ARGB32 vs RGB32). + +2012-05-30 Leif Middelschulte (T_UNIX) + + * Add ECORE_X_RANDR_OUTPUT_POLICY_ASK + +2012-06-04 Mike Blumenkrantz + + * ECORE_{CON,IPC}_NO_PROXY now available for disabling proxying on certain connections + * Added new resolver method: dns.c -- This is used by default now when ipv6 is enabled + and c-ares support is disabled. + +2012-06-06 Rob Bradford + + * Ecore_Wayland: Enhance the keyboard input handling + * Associate the keymap with the input device rather than the display + since you could could have different keymaps associated with different + devices. + * Increase the size of character arrays used for the string + representations of the keyname, keysym and for the string + representing the key. + * Re-enable the code that converts the keysym to a printable definition + - this is required where the keysym is not the same as the printable + definition + +2012-06-06 Rob Bradford + + * Ecore_Wayland: Update to protocol change - axis events are now fixed point numbers + +2012-06-11 Rob Bradford + + * Ecore_Wayland: Add missing null pointer checks on input device + deletion (ticket #1031). Not all devices are keyboards. + +2012-06-11 Jihoon Kim (jihoon) + + * ibus-immodule: Add immodule for supporting ibus. + +2012-06-12 Mike Blumenkrantz + + * Fixed bug in ecore-file monitoring with inotify where watching a file + that was deleted broke the world. + +2012-06-15 Rob Bradford + + * Ecore_Wayland: Port to latest Wayland protocol. The cursor for a + pointer is now a surface rather than a buffer. + +2012-06-15 Rob Bradford + + * Ecore_Wayland: Drop unused timestamp from configure event. Rationale: + - timestamp isn't used by the handler for this event + - configure event we receive from the compositor doesn't have a timestamp + - ecore_wl_window_maximized_set and ecore_wl_window_fullscreen_set had + an implicit requirement that the window had keyboard focus to retrieve + a timestamp that wasn't used. This removes that requirement and fixes + ticket #1030. + +2012-06-22 Vincent Torri + + * ecore_exe: fix compilation on fedora 18. + +2012-06-23 Carsten Haitzler (The Rasterman) + + * Fix small problem with xim module and if xim input context is + destroyed. causes crashes next focus. track ic and set to NULL. + +2012-06-27 Sebastian Dransfeld + + * Fix xim module to pass of Windows key as Mod4, not Mod5 + * Add support for AltGr key in X + +2012-06-28 Carsten Haitzler (The Rasterman) + + * Add compose sequence handling to ecore_input to be able to + query a sequence of keysyms for a final compose string (utf8) + that you free if you get it. + +2012-07-02 Mike Blumenkrantz + + * Fix crash which occurred in ecore-con when dns resolution failed + immediately due to lack of connectivity + +2012-07-03 Cedric Bail + + * Fix unitialized use of Ecore_X_Atom. + +2012-07-03 Christopher Michael + + * Merge Tizen EFL changes to upsteam. + * Add ecore_evas functions to get/set profiles + * Fix GL buffer. some GL drivers are doing buffer copy in a separate thread. + we need to check whether GL driver sends SYNC_DRAW_DONE msg afger copying + that are required in order to exactly render. - added by gl77.lee + * Add Ecore_X atoms for Illume Rotate Window + * Add event callbacks for Ecore_Imf Input Panel + * Add functions to retrieve input panel geometry & state from Ecore_Imf. + +2012-07-05 Carsten Haitzler (The Rasterman) + + * Add ecore_evas_screen_dpi_get() + * Fix ecore_evas_screen_geometry_get(0 for x11 to return zone + pos/size as it should. + * Fix ecore-fb to use key repeat like x so apps dont break in fb + * Fix ecore-fb string lookup table to include ctrl+keys + * Fix ecore-fb to trap sigint (ctrl+c) so it doesnt exit your fb app + * Fix ecore-fb mouse to swap button 2 and 3 ro work right. + +2012-07-13 Jiyoun Park + + * Fix bug in Ecore_extn to call pre/post render function + +2012-07-16 Carsten Haitzler (The Rasterman) + + * Fix ecore-x selection handling to fall back to getting + selection directly if getting targets fails. This fixes e17 to + elm cnp. + +2012-08-01 Mike Blumenkrantz + + * Add ecore_main_fd_handler_file_add() for integrating file descriptors + from regular files into the main loop + +2012-08-01 Rob Bradford + + * Support setting fullscreen on Ecore_Evas's under the Wayland engine + before they are visible. The fullscreening will then be applied when + they become visible. + +2012-08-01 Rob Bradford + + * Use libxkbcommon function to map keysym to unicode characters in the + Wayland backend. Removing the need to have our own function to do this + and increasing the range of supported keysms. Fixes #1105. + +2012-08-03 Rob Bradford + + * In the Wayland backend handle the case that events can be received + for surfaces that have been since destroyed - the client side + marshaller changes the pointer to NULL to when the object is destroyed + on the client side. Fixes #1258. + +2012-08-09 Cedric Bail + + * Correctly shutdown Ecore_Thread. + * Add a way to reset Ecore_Thread internal pipe after a fork via ecore_fork_reset. + +2012-08-13 Carsten Haitzler (The Rasterman) + + * Fix ecore fork reset function to allow for callbacks to be + attached so ecore-evas can reset evas async fd on fork. + +2012-08-13 Vincent Torri + + * Fix segmentation fault when fd_set pointers are NULL on Windows + +2012-08-18 Carsten Haitzler (The Rasterman) + + * Add xkb change events patch from trac. + +2012-08-27 Carsten Haitzler (The Rasterman) + + * Add ecore_x custom blanker screensaver enable/disable - cant + do e17 properly without so add in even in freeze. + +2012-08-27 Vincent Torri + + * Fix segmentation fault in ecore_thread on Windows as PHS + was returning a wrong value. + +2012-08-29 Cedric Bail + + * Always call evas_render_update_free to prevent leak in Ecore_Evas X backend. + +2012-08-29 Mike Blumenkrantz + + * Fix leak in ecore_ipc servers + +2012-08-29 Christopher Michael + + * Add Copy-N-Paste support for Ecore_Wayland. + diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..23e5f25 --- /dev/null +++ b/INSTALL @@ -0,0 +1,236 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free +Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + +By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). Here is a another example: + + /bin/bash ./configure CONFIG_SHELL=/bin/bash + +Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent +configuration-related scripts to be executed by `/bin/bash'. + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..9f16aeb --- /dev/null +++ b/Makefile.am @@ -0,0 +1,250 @@ +## Process this file with automake to produce Makefile.in + +ACLOCAL_AMFLAGS = -I m4 + +SUBDIRS = doc src + +if HAVE_PO + +SUBDIRS += po + +endif + +MAINTAINERCLEANFILES = \ +ABOUT-NLS \ +Makefile.in \ +aclocal.m4 \ +config.guess \ +config.h.in \ +config.h.in~ \ +config.rpath \ +config.sub \ +configure \ +depcomp \ +install-sh \ +ltmain.sh \ +missing \ +mkinstalldirs \ +$(PACKAGE_TARNAME)-$(PACKAGE_VERSION).tar.gz \ +$(PACKAGE_TARNAME)-$(PACKAGE_VERSION).tar.bz2 \ +$(PACKAGE_TARNAME)-$(PACKAGE_VERSION)-doc.tar.bz2 \ +m4/libtool.m4 \ +m4/lt~obsolete.m4 \ +m4/ltoptions.m4 \ +m4/ltsugar.m4 \ +m4/ltversion.m4 \ +m4/codeset.m4 \ +m4/gettext.m4* \ +m4/glibc2*.m4 \ +m4/iconv.m4 \ +m4/intdiv0.m4 \ +m4/intldir.m4 \ +m4/intl.m4 \ +m4/intlmacosx.m4 \ +m4/intmax.m4* \ +m4/inttypes_h.m4 \ +m4/inttypes.m4 \ +m4/inttypes-pri.m4 \ +m4/isc-posix.m4 \ +m4/lcmessage.m4 \ +m4/lib-ld.m4* \ +m4/lib-link.m4 \ +m4/lib-prefix.m4* \ +m4/lock.m4 \ +m4/longdouble.m4* \ +m4/longlong.m4* \ +m4/nls.m4 \ +m4/po.m4* \ +m4/printf-posix.m4* \ +m4/progtest.m4 \ +m4/signed.m4 \ +m4/size_max.m4* \ +m4/stdint_h.m4 \ +m4/uintmax_t.m4 \ +m4/ulonglong.m4* \ +m4/visibility.m4 \ +m4/wchar_t.m4 \ +m4/wint_t.m4* \ +m4/xsize.m4* + +if HAVE_PO + +MAINTAINERCLEANFILES += \ +po/boldquot.sed \ +po/en@boldquot.header \ +po/en@quot.header \ +po/insert-header.sin \ +po/Makefile.in.in* \ +po/Makevars.template \ +po/quot.sed \ +po/remove-potcdate.sin \ +po/Rules-quot* + +endif + +bin_SCRIPTS = + +EXTRA_DIST = \ +AUTHORS \ +COPYING \ +autogen.sh \ +ecore.supp \ +ecore.pc.in \ +ecore-con.pc.in \ +ecore-config.pc.in \ +ecore-directfb.pc.in\ +ecore-evas.pc.in \ +ecore-fb.pc.in \ +ecore-file.pc.in \ +ecore-imf.pc.in \ +ecore-imf-evas.pc.in \ +ecore-ipc.pc.in \ +ecore-x.pc.in \ +ecore-win32.pc.in \ +ecore-sdl.pc.in \ +ecore-cocoa.pc.in \ +ecore-psl1ght.pc.in \ +ecore-input.pc.in \ +ecore-wince.pc.in \ +ecore-wayland.pc.in \ +ecore.spec.in \ +ecore.spec \ +m4/ac_abstract_socket.m4 \ +m4/ac_attribute.m4 \ +m4/check_x_extension.m4 \ +m4/ecore_check_module.m4 \ +m4/ecore_check_options.m4 \ +m4/efl_doxygen.m4 \ +m4/efl_path_max.m4 \ +m4/efl_shm_open.m4 \ +m4/efl_coverage.m4 \ +m4/efl_tests.m4 \ +m4/efl_threads.m4 + + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = ecore.pc + +if BUILD_ECORE_CON +pkgconfig_DATA += ecore-con.pc +endif + +if BUILD_ECORE_CONFIG +pkgconfig_DATA += ecore-config.pc +endif + +if BUILD_ECORE_DIRECTFB +pkgconfig_DATA += ecore-directfb.pc +endif + +if BUILD_ECORE_EVAS +pkgconfig_DATA += ecore-evas.pc +endif + +if BUILD_ECORE_FB +pkgconfig_DATA += ecore-fb.pc +endif + +if BUILD_ECORE_FILE +pkgconfig_DATA += ecore-file.pc +endif + +if BUILD_ECORE_IMF +pkgconfig_DATA += ecore-imf.pc +endif + +if BUILD_ECORE_IMF_EVAS +pkgconfig_DATA += ecore-imf-evas.pc +endif + +if BUILD_ECORE_INPUT +pkgconfig_DATA += ecore-input.pc +endif + +if BUILD_ECORE_INPUT_EVAS +pkgconfig_DATA += ecore-input-evas.pc +endif + +if BUILD_ECORE_IPC +pkgconfig_DATA += ecore-ipc.pc +endif + +if BUILD_ECORE_X +pkgconfig_DATA += ecore-x.pc +endif + +if BUILD_ECORE_WIN32 +pkgconfig_DATA += ecore-win32.pc +endif + +if BUILD_ECORE_WINCE +pkgconfig_DATA += ecore-wince.pc +endif + +if BUILD_ECORE_SDL +pkgconfig_DATA += ecore-sdl.pc +endif + +if BUILD_ECORE_COCOA +pkgconfig_DATA += ecore-cocoa.pc +endif + +if BUILD_ECORE_PSL1GHT +pkgconfig_DATA += ecore-psl1ght.pc +endif + +if BUILD_ECORE_WAYLAND +pkgconfig_DATA += ecore-wayland.pc +endif + +.PHONY: doc coverage + +# Documentation + +doc: + @echo "entering doc/" + make -C doc doc + +# Unit tests + +if EFL_ENABLE_TESTS + +check-local: + @./src/tests/ecore_suite + +else + +check-local: + @echo "reconfigure with --enable-tests" + +endif + +# Coverage report + +if EFL_ENABLE_COVERAGE +lcov-reset: + @rm -rf $(top_builddir)/coverage + @find $(top_builddir) -name "*.gcda" -delete + @lcov --zerocounters --directory $(top_builddir) + +lcov-report: + @mkdir $(top_builddir)/coverage + lcov --capture --compat-libtool --output-file $(top_builddir)/coverage/coverage.info --directory $(top_builddir) + lcov --remove $(top_builddir)/coverage/coverage.info '*.h' --output-file $(top_builddir)/coverage/coverage.cleaned.info + genhtml -t "$(PACKAGE_STRING)" -o $(top_builddir)/coverage/html $(top_builddir)/coverage/coverage.cleaned.info + @echo "Coverage Report at $(top_builddir)/coverage/html" + +coverage: + @$(MAKE) lcov-reset + @$(MAKE) check + @$(MAKE) lcov-report +else +lcov-reset: + @echo "reconfigure with --enable-coverage" + +lcov-report: + @echo "reconfigure with --enable-coverage" + +coverage: + @echo "reconfigure with --enable-tests --enable-coverage" +endif diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..e208cd3 --- /dev/null +++ b/NEWS @@ -0,0 +1,286 @@ +Ecore 1.7.0 + +Changes since Ecore 1.2.0: +-------------------------- + +Additions: + * ecore: + - Add ecore_main_fd_handler_file_add() + - Add ecore_fork_reset() + * ecore_evas: + - Add transparency support on Windows (GDI engine only) + - Add API functions to get/set an Ecore_Evas's profile. + * ecore_x: + - Add Ecore_X_Error_Code enumeration + - ECORE_X_RANDR_OUTPUT_POLICY_ASK + - Add API functions to get/set an Ecore_X window's profile + * ecore_con: + - ECORE_{CON,IPC}_NO_PROXY now available for disabling proxying on certain connections + - New dns.c resolver backend for faster dns lookups + * immodule: + - Add immodule for supporing ibus + +Fixes: + * ecore + - Prevent running out of fd when cycling ecore_init/ecore_shutdown. + - Reduce rounding error in ecore_animator_pos_map. + - Send mouse move event before mouse down event in ecore_extn + - Reduce race condition on shutdown of Ecore_Thread. + - Force cancel of all running Ecore_Thread on shutdown. + - Make Ecore_Thread work reliably when called without a running main loop. + - Correctly shutdown Ecore_Thread. + - Fix usage of FD_SET and al. when fd_set pointers are NULL (Windows) + - Fix ecore_thread seg fault on Windows where PHS() was returning a wrong value + - Always call evas_render_update_free to prevent leak in Ecore_Evas X bakcend. + + * ecore_x + - Fix unitialized Ecore_X_Atom use. + + +Ecore 1.2.0 + +Changes since Ecore 1.1.0: +-------------------------- + +Additions: + * ecore + - ecore_timer_reset() + * ecore_con + - ecore_con_socks api + - ecore_con_ssl_server_verify_name_set/get + - ecore_con_ssl_server_cafile_add() now accepts directories + - ECORE_CON_REMOTE_CORK + - ecore_con_url_proxy_set() + - ecore_con_url_timeout_set() + - ecore_con_url_proxy_username_set() + - ecore_con_url_proxy_password_set() + - ecore_con_url_http_version_set() + - ecore_con_url_status_code_get() + * ecore_x: + - ecore_x_randr_output_backlight_available() + - ecore_x_randr_window_crtcs_get() + - Add ability to get resource id of last x error + - get keycode from keyname + - ecore_x_randr_mode_add() + - ecore_x_randr_mode_del() + - ecore_x_randr_output_mode_add() + - ecore_x_randr_output_mode_del() + - Add indicator controls + - ecore_x_netwm_icons_set() + - ecore_x_illume_clipboard_state_set() + - ecore_x_illume_clipboard_state_get() + - ecore_x_illume_clipboard_geometry_set() + - ecore_x_illume_clipboard_geometry_get() + - Add indicator rotation and transparency controls + * ecore_evas: + - Add Shm and Egl engines for ecore_evas to draw in Wayland. + - Add Socket and Plug to draw other process area. + - Ability to set pointer for wayland support + - Add override_set support on Windows XP + - ecore_evas_window_group_set() + - ecore_evas_window_group_get() + - ecore_evas_aspect_set() + - ecore_evas_aspect_get() + - ecore_evas_urgent_set() + - ecore_evas_urgent_get() + - ecore_evas_modal_set() + - ecore_evas_modal_get() + - ecore_evas_demand_attention_set() + - ecore_evas_demand_attention_get() + - ecore_evas_focus_skip_set() + - ecore_evas_focus_skip_get() + - ecore_evas_callback_state_change_set() + * ecore_wayland + - Add Ecore_Wayland (backend to support Wayland). + * ecore_imf + - ecore_imf_context_event_callback_add() + - ecore_imf_context_event_callback_del() + - ecore_imf_context_event_callback_call() + - ecore_imf_context_input_panel_imdata_set() + - ecore_imf_context_input_panel_imdata_get() + - ecore_imf_context_input_panel_return_key_type_set() + - ecore_imf_context_input_panel_return_key_type_get() + - ecore_imf_context_input_panel_return_key_disabled_set() + - ecore_imf_context_input_panel_return_key_disabled_get() + - ecore_imf_context_input_panel_caps_lock_mode_set() + - ecore_imf_context_input_panel_caps_lock_mode_get() + - add XIM attribute support + - add HEX, TERMINAL and PASSWORD layouts + - panel-specific data set/get + - panel show/hide + - set return key type or disable return on panel + * ecore_win32: + - ecore_win32_focus() + - ecore_win32_focus_get() + - ecore_win32_window_focus() + - ecore_win32_window_focus_get() + * ecore_wince: + - ecore_wince_focus() + - ecore_wince_focus_get() + - ecore_wince_window_focus() + - ecore_wince_window_focus_get() + * ecore_wayland: + - Add wayland support to ecore + +Fixes: + * ecore: + - animator adding another animator that adds another animator ... loop. + - possible leak related to g_static_mutex's on some architectures. + - stop leaking signal events + * ecore_thread: + - ecore_thread_feedback_run now handle try_no_queue the way it logically should. + - prevent double free that could cause crash when an Ecore_Thread stop. + * ecore_x: + - ecore_x_randr_modes_info_get does not cut off the trailing '\0' anymore. + - possible 0 byte allocation. + * ecore_win32/wince: + - do not autorepeat Ctrl, Shift, Alt and Win keys. + - Check control charater and convert into printing character + * ecore_con: + - fix case where SSL certificates not being used. + - post data corruption due to it not being copied to the con struct. + * ecore_evas: + - mouse down count handling when grabs happen. + - ecore_evas_fb support works again now with keyboard input + * ecore_file: + - do not limit downloads to 30sec with ecore_file_download(). + * ecore_fb: + - bring ecore_fb back to a working state + +Improvements: + * ecore: + - most allocations moved to mempools + - ecore_thread rewrite to use eina_lock and other ecore infra + * ecore_con: + - certificates can now be added for STARTTTLS + * ecore_win32: + - fix modifiers value on Windows XP + * ecore_thread: + - use eina_lock + - use Ecore thread safe async call + * ecore_evas: + - use Evas buffer backend for SDL software engine + - clean up ecore-evas-buffer code somewhat + +Deprecations: + * ecore_x: + - ecore_x_randr_crtc_current_get() + +Removal: + * ecore_win32: + - ecore_win32_focus_set() + +Ecore 1.1.0 + +Changes since Ecore 1.0.0: +-------------------------- + +Additions: + + * ecore: + - ecore_thread_reschedule() + - ecore_exe_data_set() + - ecore_animator_timeline_add() + - ecore_timer_dump() + - custom ecore animator tick mode and support + - ecore_pipe_freeze/thaw() + - ecore_pipe_wait() + - ecore_throttle() + - ecore_main_loop_thread_safe_call_async() + - ecore_main_loop_thread_safe_call_sync() + - ecore_thread_main_loop_begin() + - ecore_thread_main_loop_end() + + * ecore_con: + - ECORE_CON_EVENT_CLIENT_ERROR, ECORE_CON_EVENT_SERVER_ERROR events + - Ecore_Con_Event_Server_Error, Ecore_Con_Event_Client_Error types + - ecore_con_client_port_get() + - ecore_con_url_ssl_verify_peer_set() + - ecore_con_url_ssl_ca_set() + - ecore_con_url_pipeline_set() + - ecore_con_url_pipeline_get() + - ecore_con_ssl_client/server_upgrade() + - ECORE_CON_CLIENT/SERVER_UPGRADE events + - ecore_con_server_timeout_get/set() + - ecore_con_ssl_server_verify_basic() + - ecore_con_url_url_get() + - ecore_con_server_fd_get() + - ecore_con_client_fd_get() + - ECORE_CON_EVENT_CLIENT_WRITE, ECORE_CON_EVENT_SERVER_WRITE events + + * ecore_evas: + - ecore_evas_screen_geometry_get() + - ecore_cocoa_evas support + + * ecore_file: + - ecore_file_download_full() + + * ecore_imf: + - ecore_imf_context_canvas_get() + - ecore_imf_context_window_get() + - ecore_imf_context_preedit_string_with_attributes_get() + - added controls for auto-capitalization and prediction controls + - ecore_imf_context_input_panel_enabled_set/get() + - ecore_imf_context_cursor_location_set() + + * ecore_x: + - ecore_x_randr_edid_*() + - ecore_x_randr_screen_backlight_*() + - more ecore_x_sync api controls to support ecore_evas + - shape input setting support added + - ecore_x_screen_size_get() + +Fixes: + + * https failing via curl + * removed SIGRT handling as it was broken anyway and unused + * space key handling in ecore_wince/ecore_win32 support + * wince background erasing + * 300 second timeout to handle slow or large downloads in ecore_con + * ecore_file inotify fd's to not be inherited by forked children + * ecore_file compilation if ecore_con and curl disabled + * crash in ecore_con_ssl when attempting connections on dead socket + * ecore-evas interceptor not handling override-redirect + * ecore_con_url_ftp_upload to complete uploads always + * window removal from ignore_list in ecore_x + * bug in ecore_evas when setting modifiers for sub buffer canvases + * NULL pointer dereference in ecore_x selection notification code + * sync GNUTLS thread activation with eina changes + * ecore_ipc compilation on Windows + * fix Shift, Control, Alt and AltGr keys detection on Windows XP + * "mouse-down inside and mouse-up outside" issue on Windows + * ecore_x shadow tree search fixed to respect shape input of windows + * fd handlers fixed when idler callbacks add jobs or events + * ecore_x_selection_convert takes length into account + * security issue in openssl certificate verification + * gnutls server client certificate verification + * epoll delete of fd handling in forked child + * grouping of timers that go off very close to each other go off together + * generic event buffer handling in ecore_x fixed + * use current size not requested size when getting geom in ecore-evas + * ecore_cocoa now handles windows correctly + * ecore_file_download error handling when ecore_con_url_get fails + * focus and mouse-in initial state on some ecore-evas back-ends + +Improvements: + + * reduced memory needed for list of fd's in ecore by using inlist + * ecore_evas now is able to send render-done even if not syncing to comp + * more safety checks in ecore_con are support + * ecore timer monotonic clock now supported on OSX + * make ecore_con work on Windows + * improve resize/move on Windows + * improve keyboard management on Windows XP + * refactored _ecore_main_loop_iterate_internal + * better safety with ecore_evas_ecore_evas_get + * ecore-evas produces more errors on stderr when errors happen now + * ecore-con works on IPv6 now + * inet_ntop instead of getnameinfo for ecore_con_client_get_ip + * ecore-con unit tests added + * ecore-evas fb uses ecore_input_evas now instead of going direct + * fix ecore-evas x changing of override support if window not shown yet + +Removals: + + * xrender evas engine support removed from ecore_evas (api still there) + diff --git a/README b/README new file mode 100644 index 0000000..e0712b4 --- /dev/null +++ b/README @@ -0,0 +1,98 @@ +Ecore 1.7.0 + +****************************************************************************** + + FOR ANY ISSUES PLEASE EMAIL: + enlightenment-devel@lists.sourceforge.net + +****************************************************************************** + +Requirements: +------------- + +Must: + libc + eina (1.1.0 or better) + (For windows you also need: evil) + +Recommended: + libX11 + libXext + libXcursor + libXprint + libXinerama + libXrandr + libXss + libXrender + libXcomposite + libXfixes + libXdamage + libXdpms + libXtest + GNUTLS or OpenSSL + CURL + evas (1.1.0 or better) + +Optional: + XCB (fully working) + SDL + DirectFB + glib + tslib + +Ecore is a clean and tiny event loop library with many modules to do +lots of convenient things for a programmer, to save time and effort. + +It's small and lean, designed to work on embedded systems all the way +to large and powerful multi-cpu workstations. It serialises all system +signals, events etc. into a single event queue, that is easily +processed without needing to worry about concurrency. A properly +written, event-driven program using this kind of programming doesn't +need threads, nor has to worry about concurrency. It turns a program +into a state machine, and makes it very robust and easy to follow. + +Ecore gives you other handy primitives, such as timers to tick over +for you and call specified functions at particular times so the +programmer can use this to do things, like animate, or time out on +connections or tasks that take too long etc. + +Idle handlers are provided too, as well as calls on entering an idle +state (often a very good time to update the state of the program). All +events that enter the system are passed to specific callback functions +that the program sets up to handle those events. Handling them is +simple and other Ecore modules produce more events on the queue, +coming from other sources such as file descriptors etc. + +Ecore also help you work in a multi threaded environment and setup a +thread pool that help you use the EFL on multi-cpu system. It help split +the part that can't be called outside of the ecore main loop from the +computation heavy function that could run on another CPU. Be aware that +Evas and most of Ecore API is not thread safe and should only be called +in the main loop. Eina and Eet could be used, if done carefully, in any +heavy function on another cpu. + +Ecore also lets you have functions called when file descriptors become +active for reading or writing, allowing for streamlined, non-blocking +IO. + +------------------------------------------------------------------------------ +COMPILING AND INSTALLING: + + ./configure + make +(as root unless you are installing in your users directories): + make install + +------------------------------------------------------------------------------ +NOTE: + +You can experience main loop lock (and more likely see UI lock) if libcurl +doesn't use an asynchronous dns resolver. Since Curl 7.21.0, you can use the +native dns resolver asynchronously by turning --enable-threaded-resolver +on during configure time. For older version, C-Ares is the way to solve that +issue (see: http://c-ares.haxx.se/ ). + +Also the wayland support (ecore_wayland) is considered experimental as +wayland itself is still unstable and liable to change core protocol. +If you use this api, it is possible it will break in future, until this +notice is removed. diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..81e1956 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +rm -rf autom4te.cache +rm -f aclocal.m4 ltmain.sh + +touch ABOUT-NLS + +echo "Running autopoint..." ; autopoint -f || : +echo "Running aclocal..." ; aclocal $ACLOCAL_FLAGS -I m4 || exit 1 +echo "Running autoheader..." ; autoheader || exit 1 +echo "Running autoconf..." ; autoconf || exit 1 +echo "Running libtoolize..." ; (libtoolize --copy --automake || glibtoolize --automake) || exit 1 +echo "Running automake..." ; automake --add-missing --copy --gnu || exit 1 + +W=0 + +rm -f config.cache-env.tmp +echo "OLD_PARM=\"$@\"" >> config.cache-env.tmp +echo "OLD_CFLAGS=\"$CFLAGS\"" >> config.cache-env.tmp +echo "OLD_PATH=\"$PATH\"" >> config.cache-env.tmp +echo "OLD_PKG_CONFIG_PATH=\"$PKG_CONFIG_PATH\"" >> config.cache-env.tmp +echo "OLD_LDFLAGS=\"$LDFLAGS\"" >> config.cache-env.tmp +echo "OLD_CXXFLAGS=\"$CXXFLAGS\"" >> config.cache-env.tmp + +cmp config.cache-env.tmp config.cache-env >> /dev/null +if [ $? -ne 0 ]; then + W=1; +fi + +if [ $W -ne 0 ]; then + echo "Cleaning configure cache..."; + rm -f config.cache config.cache-env + mv config.cache-env.tmp config.cache-env +else + rm -f config.cache-env.tmp +fi + +if [ -z "$NOCONFIGURE" ]; then + ./configure -C "$@" +fi diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..7907b3c --- /dev/null +++ b/configure.ac @@ -0,0 +1,2259 @@ +##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## +##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## +m4_define([v_maj], [1]) +m4_define([v_min], [7]) +m4_define([v_mic], [0]) +m4_define([v_rev], m4_esyscmd([(svnversion "${SVN_REPO_PATH:-.}" | grep -v '\(export\|Unversioned directory\)' || echo 0) | awk -F : '{printf("%s\n", $1);}' | tr -d ' :MSP\n' | sed 's/Unversioneddirectory/0/' | tr -d '\n'])) +m4_if(v_rev, [0], [m4_define([v_rev], m4_esyscmd([git log 2> /dev/null | (grep -m1 git-svn-id || echo 0) | sed -e 's/.*@\([0-9]*\).*/\1/' | tr -d '\n']))]) +##-- When released, remove the dnl on the below line +m4_undefine([v_rev]) +##-- When doing snapshots - change soname. remove dnl on below line +dnl m4_define([relname], [ver-pre-svn-07]) +dnl m4_define([v_rel], [-release relname]) +##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## +m4_ifdef([v_rev], [m4_define([v_ver], [v_maj.v_min.v_mic.v_rev])], [m4_define([v_ver], [v_maj.v_min.v_mic])]) +m4_define([lt_cur], m4_eval(v_maj + v_min)) +m4_define([lt_rev], v_mic) +m4_define([lt_age], v_min) +##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## +##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## + +AC_INIT([ecore], [v_ver], [enlightenment-devel@lists.sourceforge.net]) +AC_PREREQ([2.52]) +AC_CONFIG_SRCDIR([configure.ac]) +AC_CONFIG_MACRO_DIR([m4]) + +AC_CONFIG_HEADERS([config.h]) +AH_TOP([ +#ifndef EFL_CONFIG_H__ +#define EFL_CONFIG_H__ +]) +AH_BOTTOM([ +#endif /* EFL_CONFIG_H__ */ +]) + +AM_INIT_AUTOMAKE([1.6 dist-bzip2]) +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +AC_GNU_SOURCE + +AC_LIBTOOL_WIN32_DLL +define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl +AC_PROG_LIBTOOL + +##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## +##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## +m4_ifdef([v_rev], , [m4_define([v_rev], [0])]) +m4_ifdef([v_rel], , [m4_define([v_rel], [])]) +AC_DEFINE_UNQUOTED(VERS_MAJ, [v_maj], [Major version]) +AC_DEFINE_UNQUOTED(VERS_MIN, [v_min], [Minor version]) +AC_DEFINE_UNQUOTED(VERS_MIC, [v_mic], [Micro version]) +AC_DEFINE_UNQUOTED(VERS_REV, [v_rev], [Revison]) +version_info="lt_cur:lt_rev:lt_age" +release_info="v_rel" +AC_SUBST(version_info) +AC_SUBST(release_info) +##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## +##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## +VMAJ=v_maj +AC_SUBST(VMAJ) + +AM_GNU_GETTEXT_VERSION(0.17) + +m4_ifdef([AM_GNU_GETTEXT], [ +AM_GNU_GETTEXT([external]) +po_makefile_in=po/Makefile.in +have_po="yes" +],[ +have_po="no" +]) +AC_SUBST(LTLIBINTL) + +if test "x${POSUB}" = "x" ; then + have_po="no" +fi + +AM_CONDITIONAL([HAVE_PO], [test "x${have_po}" = "xyes"]) + +with_max_log_level="" +AC_ARG_WITH(internal-maximum-log-level, + [AC_HELP_STRING([--with-internal-maximum-log-level=NUMBER], + [limit ecore internal log level to the given number, any call to EINA_LOG() with values greater than this will be compiled out, ignoring runtime settings, but saving function calls.])], + [ + if test "x${withval}" != "xno"; then + if echo "${withval}" | grep -E '^[[0-9]]+$' >/dev/null 2>/dev/null; then + AC_MSG_NOTICE([ignoring any EINA_LOG() with level greater than ${withval}]) + AC_DEFINE_UNQUOTED(EINA_LOG_LEVEL_MAXIMUM, ${withval}, [if set, logging is limited to this amount.]) + with_max_log_level="${withval}" + else + AC_MSG_ERROR([--with-internal-maximum-log-level takes a decimal number, got "${withval}" instead.]) + fi + fi + ], [:]) + + +### Default options with respect to host + +AC_CANONICAL_BUILD +AC_CANONICAL_HOST + +# dependencies and options +want_curl="no" +want_local_sockets="yes" +want_abstract_sockets="no" +want_gnutls="no" +want_openssl="no" +want_cares="no" +want_cipher="no" +want_signature="no" +want_poll="yes" +want_inotify="no" +want_notify_win32="no" +want_tslib="no" +want_glib="no" + +# core modules +want_ecore_con="yes" +want_ecore_ipc="yes" +want_ecore_file="yes" +#want_ecore_config="no" +want_ecore_imf="no" +want_ecore_input="yes" + +# graphic system modules +want_evas_simple_x11="no" +want_ecore_x_xcb="no" +want_ecore_x="no" +want_ecore_win32="no" +want_ecore_cocoa="no" +want_ecore_sdl="no" +want_ecore_psl1ght="no" +want_ecore_fb="no" +want_ecore_directfb="no" +want_ecore_wince="no" +want_ecore_wayland="no" + +# ecore_x options (both xlib and xcb) +want_ecore_x_composite="yes" +want_ecore_x_damage="yes" +want_ecore_x_dpms="yes" +want_ecore_x_randr="yes" +want_ecore_x_render="yes" +want_ecore_x_screensaver="yes" +want_ecore_x_shape="yes" +want_ecore_x_gesture="no" +want_ecore_x_sync="yes" +want_ecore_x_xfixes="yes" +want_ecore_x_xinerama="yes" +want_ecore_x_xprint="yes" +want_ecore_x_xtest="yes" +want_ecore_x_cursor="yes" +want_ecore_x_input="yes" +want_ecore_x_dri="yes" + +# ecore_evas modules +want_ecore_evas="yes" +want_ecore_evas_software_buffer="yes" +want_ecore_evas_software_x11="no" +want_ecore_evas_opengl_x11="no" +want_ecore_evas_software_16_x11="no" +want_ecore_evas_software_8_x11="no" +want_ecore_evas_software_xcb="no" +want_ecore_evas_software_gdi="no" +want_ecore_evas_software_ddraw="no" +want_ecore_evas_direct3d="no" +want_ecore_evas_opengl_glew="no" +want_ecore_evas_software_16_ddraw="no" +want_ecore_evas_software_sdl="no" +want_ecore_evas_gl_sdl="no" +want_ecore_evas_gl_cocoa="no" +want_ecore_evas_psl1ght="no" +want_ecore_evas_directfb="no" +want_ecore_evas_fb="no" +want_ecore_evas_software_16_wince="no" +want_ecore_evas_ews="yes" +want_ecore_evas_extn="yes" +want_ecore_evas_wayland_shm="no" +want_ecore_evas_wayland_egl="no" + +# ecore_imf modules +want_ecore_imf_xim="no" +want_ecore_imf_scim="no" +want_ecore_imf_ibus="no" + +case "$host_os" in + mingw32ce*) + want_ecore_con="no" + want_ecore_ipc="no" + want_ecore_wince="yes" + want_ecore_evas_software_16_wince="yes" + want_ecore_evas_extn="no" + ;; + mingw*) + want_notify_win32="yes" + want_curl="yes" + want_glib="auto" + want_gnutls="auto" + want_openssl="auto" + want_ecore_imf="yes" + want_ecore_win32="yes" + want_ecore_evas_software_gdi="yes" + want_ecore_evas_software_ddraw="yes" + want_ecore_evas_direct3d="yes" + want_ecore_evas_opengl_glew="yes" + want_ecore_evas_software_16_ddraw="auto" + want_ecore_evas_software_sdl="yes" + want_ecore_evas_gl_sdl="yes" + ;; + darwin*) + want_curl="yes" + want_glib="auto" + want_gnutls="auto" + want_openssl="auto" + want_ecore_imf="yes" + want_ecore_cocoa="yes" + want_ecore_evas_software_sdl="yes" + want_ecore_evas_gl_sdl="yes" + want_ecore_evas_gl_cocoa="yes" + ;; + *) + want_curl="yes" + want_glib="auto" + want_abstract_sockets="yes" + want_gnutls="auto" + want_openssl="auto" + want_cipher="yes" + want_signature="yes" + want_inotify="yes" + want_tslib="yes" + want_ecore_fb="yes" + want_ecore_imf="yes" + want_ecore_x="yes" + want_ecore_wayland="yes" + want_ecore_evas_software_x11="yes" + want_ecore_evas_opengl_x11="yes" + want_ecore_evas_software_16_x11="yes" + want_ecore_evas_software_8_x11="yes" + want_ecore_evas_software_xcb="no" + want_ecore_evas_software_sdl="yes" + want_ecore_evas_gl_sdl="yes" + want_ecore_evas_gl_cocoa="no" + want_ecore_evas_directfb="yes" + want_ecore_evas_fb="yes" + want_ecore_evas_wayland_shm="yes" + want_ecore_evas_wayland_egl="yes" + want_ecore_imf_xim="yes" + want_ecore_imf_scim="yes" + want_ecore_imf_ibus="yes" + ;; +esac + +case "$host_vendor" in + ps3*) + want_local_sockets="no" + ;; +esac +requirements_ecore="" +requirements_ecore_con="" +#requirements_ecore_config="" +requirements_ecore_directfb="" +requirements_ecore_evas="" +requirements_ecore_fb="" +requirements_ecore_file="" +requirements_ecore_imf="" +requirements_ecore_imf_evas="" +requirements_ecore_input="" +requirements_ecore_input_evas="" +requirements_ecore_ipc="" +requirements_ecore_cocoa="" +requirements_ecore_sdl="" +requirements_ecore_psl1ght="" +requirements_ecore_x="" +requirements_ecore_win32="" +requirements_ecore_wince="" +requirements_ecore_imf_xim="" +requirements_ecore_imf_scim="" +requirements_ecore_imf_ibus="" +requirements_ecore_wayland="" + +### Additional options to configure + +want_glib_integration_always=no +AC_ARG_ENABLE(glib-integration-always, + AC_HELP_STRING([--enable-glib-integration-always], [enable glib integration when ecore_init() is called always]), + [want_glib_integration_always=$enableval]) + +if test "x${want_glib_integration_always}" = "xyes" ; then + AC_DEFINE([GLIB_INTEGRATION_ALWAYS], [1], [Always integrate glib if support compiled]) + want_glib=yes +fi + +want_g_main_loop=no +AC_ARG_ENABLE(g-main-loop, + AC_HELP_STRING([--enable-g-main-loop], [ecore_main_loop based on g_main_loop]), + [want_g_main_loop=$enableval]) + +if test "x${want_g_main_loop}" = "xyes" ; then + AC_DEFINE([USE_G_MAIN_LOOP], [1], [Use g_main_loop in ecore]) + want_glib=yes +fi + +if test "x${want_glib_integration_always}" = "xyes" -a "x${want_g_main_loop}" = "xyes"; then + AC_MSG_ERROR([--enable-glib-integration-always and --enable-glib-main-loop are mutually exclusive]) +fi + +# local sockets (ecore_con.c) +AC_ARG_ENABLE([local-sockets], + [AC_HELP_STRING([--disable-local-sockets], [disable local sockets.])], + [ + if test "x${enableval}" = "xyes" ; then + want_ecore_con_local_sockets="yes" + else + want_ecore_con_local_sockets="no" + fi + ], + [want_ecore_con_local_sockets=${want_local_sockets}]) + +if test "x${want_ecore_con_local_sockets}" = "xyes" ; then + AC_DEFINE([HAVE_LOCAL_SOCKETS], [1], [Have local sockets support]) +fi + +# abstract sockets (ecore_con.c) +AC_ARG_ENABLE([abstract-sockets], + [AC_HELP_STRING([--disable-abstract-sockets], [disable abstract sockets.])], + [ + if test "x${enableval}" = "xyes" ; then + want_ecore_con_abstract_sockets="yes" + else + want_ecore_con_abstract_sockets="no" + fi + ], + [want_ecore_con_abstract_sockets=${want_abstract_sockets}]) + +if test "x${want_ecore_con_abstract_sockets}" = "xyes" ; then + AC_DEFINE([HAVE_ABSTRACT_SOCKETS], [1], [Have abstract sockets namespace]) +fi + +# Simple X11 build/link + +AC_ARG_ENABLE(simple-x11, + AC_HELP_STRING([--enable-simple-x11], [enable simple x11 linking]), + [want_evas_simple_x11=$enableval]) + +# XIM +AC_ARG_ENABLE([xim], + [AC_HELP_STRING([--disable-xim], [disable X Input Method.])], + [ + if test "x${enableval}" = "xyes" ; then + want_xim="yes" + else + want_xim="no" + fi + ], + [want_xim="yes"]) + +if test "x${want_xim}" = "xyes" ; then + AC_DEFINE([ENABLE_XIM], [1], [Enable X Input Method]) +fi + +### Checks for programs + +m4_ifdef([AC_PROG_OBJC], + [ + AC_PROG_OBJC + _AM_DEPENDENCIES(OBJC) + ], + [ + AC_CHECK_TOOL([OBJC], [gcc]) + AC_SUBST([OBJC]) + AC_SUBST([OBJCFLAGS]) + ]) +m4_ifndef([am__fastdepOBJC], [ + AM_CONDITIONAL([am__fastdepOBJC], [false]) +]) + +AC_PROG_CXX +AC_PROG_CC_C99 +if test "x${ac_cv_prog_cc_c99}" = "xno" ; then + AC_MSG_ERROR([ecore requires a c99-capable compiler]) +fi + +have_gnu_objc=${ac_cv_objc_compiler_gnu} + +# doxygen program for documentation building + +EFL_CHECK_DOXYGEN([build_doc="yes"], [build_doc="no"]) + +m4_ifdef([v_mic], + [ + EFL_COMPILER_FLAG([-Wall]) + EFL_COMPILER_FLAG([-W]) + ]) + +# The first call to PKG_CHECK_MODULES is done conditionally, +# so we should include this here: +PKG_PROG_PKG_CONFIG + +# Check whether pkg-config supports Requires.private +if $PKG_CONFIG --atleast-pkgconfig-version 0.22; then + pkgconfig_requires_private="Requires.private" +else + pkgconfig_requires_private="Requires" +fi +AC_SUBST(pkgconfig_requires_private) + +### Checks for some build time option +have_backtrace="no" +AC_CHECK_FUNCS([backtrace], [have_backtrace="yes"], []) + +want_ecore_timer_dump="no" + +AC_ARG_ENABLE([ecore-timer-dump], + [AC_HELP_STRING([--disable-ecore-timer-dump], [disable tracking of timer allocation. @<:@default=enable@:>@])], + [want_ecore_timer_dump=$enableval], []) + +if test "x$want_ecore_timer_dump" = "xyes" -a "x$have_backtrace" = "xyes"; then + AC_DEFINE(WANT_ECORE_TIMER_DUMP, [1], [Want Ecore_Timer dump infrastructure]) +fi + +### Checks for libraries + +# Evil library for compilation on Windows + +case "$host_os" in + mingw*) + PKG_CHECK_MODULES([EVIL], [evil >= 1.6.99]) + AC_DEFINE(HAVE_EVIL, 1, [Set to 1 if Evil library is installed]) + requirements_ecore="evil ${requirements_ecore}" + requirements_ecore_evas="evil ${requirements_ecore_evas}" + requirements_ecore_file="evil ${requirements_ecore_file}" + requirements_ecore_imf="evil ${requirements_ecore_imf}" + requirements_ecore_imf_evas="evil ${requirements_ecore_imf_evas}" + EFL_ECORE_BUILD="-DEFL_ECORE_BUILD" + EFL_ECORE_CON_BUILD="-DEFL_ECORE_CON_BUILD" + EFL_ECORE_EVAS_BUILD="-DEFL_ECORE_EVAS_BUILD" + EFL_ECORE_FILE_BUILD="-DEFL_ECORE_FILE_BUILD" + EFL_ECORE_IMF_BUILD="-DEFL_ECORE_IMF_BUILD" + EFL_ECORE_IMF_EVAS_BUILD="-DEFL_ECORE_IMF_EVAS_BUILD" + EFL_ECORE_INPUT_BUILD="-DEFL_ECORE_INPUT_BUILD" + EFL_ECORE_INPUT_EVAS_BUILD="-DEFL_ECORE_INPUT_EVAS_BUILD" + EFL_ECORE_IPC_BUILD="-DEFL_ECORE_IPC_BUILD" + ;; +esac + +have_win32="" +have_wince="" +case "$host_os" in + mingw32ce* | cegcc*) + EFL_ECORE_WINCE_BUILD="-DEFL_ECORE_WINCE_BUILD" + requirements_ecore_wince="evil ${requirements_ecore_wince}" + have_wince="yes" + ;; + mingw*) + EFL_ECORE_WIN32_BUILD="-DEFL_ECORE_WIN32_BUILD" + EFL_ECORE_SDL_BUILD="-DEFL_ECORE_SDL_BUILD" + requirements_ecore_win32="evil ${requirements_ecore_win32}" + requirements_ecore_sdl="evil ${requirements_ecore_sdl}" + have_win32="yes" + ;; +esac + +have_ps3="" +case "$host_vendor" in + ps3*) + have_ps3="yes" + PKG_CHECK_MODULES([ESCAPE], [escape]) + CFLAGS="$CFLAGS $ESCAPE_CFLAGS" + AC_DEFINE(HAVE_ESCAPE, 1, [Set to 1 if Escape library is installed]) + EFL_ECORE_PSL1GHT_BUILD="-DEFL_ECORE_PSL1GHT_BUILD" + requirements_ecore="escape ${requirements_ecore}" + requirements_ecore_evas="escape ${requirements_ecore_evas}" + requirements_ecore_file="escape ${requirements_ecore_file}" + requirements_ecore_imf="escape ${requirements_ecore_imf}" + requirements_ecore_imf_evas="escape ${requirements_ecore_imf_evas}" + requirements_ecore_sdl="escape ${requirements_ecore_sdl}" + want_ecore_psl1ght="yes" + want_ecore_evas_psl1ght="yes" + ;; +esac + + +### Checks for portability layer + +PKG_CHECK_MODULES([EXOTIC], + [exotic], + [enable_exotic="yes"], + [enable_exotic="no"]) + +if test "x${enable_exotic}" = "xyes"; then + requirements_ecore="exotic ${requirements_ecore}" + + AC_DEFINE([HAVE_EXOTIC], [1], [Define to 1 if you have Exotic.]) +fi +AM_CONDITIONAL([ECORE_HAVE_EXOTIC], [test "x${enable_exotic}" = "xyes"]) + +AC_SUBST(EFL_ECORE_BUILD) +AC_SUBST(EFL_ECORE_CON_BUILD) +AC_SUBST(EFL_ECORE_EVAS_BUILD) +AC_SUBST(EFL_ECORE_FILE_BUILD) +AC_SUBST(EFL_ECORE_IMF_BUILD) +AC_SUBST(EFL_ECORE_IMF_EVAS_BUILD) +AC_SUBST(EFL_ECORE_INPUT_BUILD) +AC_SUBST(EFL_ECORE_INPUT_EVAS_BUILD) +AC_SUBST(EFL_ECORE_IPC_BUILD) +AC_SUBST(EFL_ECORE_WINCE_BUILD) +AC_SUBST(EFL_ECORE_WIN32_BUILD) +AC_SUBST(EFL_ECORE_SDL_BUILD) +AC_SUBST(EFL_ECORE_PSL1GHT_BUILD) + +AM_CONDITIONAL(ECORE_HAVE_WINCE, test "x${have_wince}" = "xyes") +AM_CONDITIONAL(ECORE_HAVE_WIN32, test "x${have_win32}" = "xyes") +AM_CONDITIONAL(ECORE_HAVE_PS3, test "x${have_ps3}" = "xyes") + +WIN32_LIBS="" +case "$host_os" in + mingw32ce* | cegcc*) + WIN32_LIBS="-lws2" + dlopen_libs="-ldl" + ;; + mingw*) + WIN32_LIBS="-lws2_32" + dlopen_libs="-ldl" + ;; + *) + AC_CHECK_LIB([c], [dlopen], + [], + [AC_CHECK_LIB([dl], [dlopen], + [dlopen_libs=-ldl]) + ]) + AC_CHECK_LIB([c], [clock_gettime], + [AC_DEFINE(HAVE_CLOCK_GETTIME, [1], [Have clock_gettime()])], + [AC_CHECK_LIB([rt], [clock_gettime], + [ + rt_libs=-lrt + AC_DEFINE(HAVE_CLOCK_GETTIME, [1], [Have clock_gettime()]) + ]) + ]) + ;; +esac +AC_SUBST(WIN32_LIBS) +AC_SUBST(dlopen_libs) +AC_SUBST(rt_libs) + +# Eina library + +PKG_CHECK_MODULES(EINA, [eina >= 1.6.99]) +#FIXME check all the requirements when the eina move will be finished +requirements_ecore="eina >= 1.6.99 ${requirements_ecore}" +requirements_ecore_con="ecore >= 1.6.99 eina >= 1.6.99 ${requirements_ecore_con}" +#requirements_ecore_config="ecore >= 1.6.99 eina >= 1.6.99 ${requirements_ecore_config}" +requirements_ecore_directfb="ecore >= 1.6.99 eina >= 1.6.99 ${requirements_ecore_directfb}" +requirements_ecore_evas="ecore >= 1.6.99 eina >= 1.6.99 ${requirements_ecore_evas}" +requirements_ecore_fb="ecore >= 1.6.99 eina >= 1.6.99 ${requirements_ecore_fb}" +requirements_ecore_file="ecore >= 1.6.99 eina >= 1.6.99 ${requirements_ecore_file}" +requirements_ecore_imf="ecore >= 1.6.99 eina >= 1.6.99 ${requirements_ecore_imf}" +requirements_ecore_imf_evas="ecore >= 1.6.99 eina >= 1.6.99 ${requirements_ecore_imf_evas}" +requirements_ecore_input="ecore >= 1.6.99 eina >= 1.6.99 ${requirements_ecore_input}" +requirements_ecore_input_evas="ecore >= 1.6.99 eina >= 1.6.99 ${requirements_ecore_input_evas}" +requirements_ecore_ipc="ecore >= 1.6.99 eina >= 1.6.99 ${requirements_ecore_ipc}" +requirements_ecore_cocoa="ecore >= 1.6.99 eina >= 1.6.99 ${requirements_ecore_cocoa}" +requirements_ecore_sdl="ecore >= 1.6.99 eina >= 1.6.99 ${requirements_ecore_sdl}" +requirements_ecore_psl1ght="ecore >= 1.6.99 eina >= 1.6.99 ${requirements_ecore_sdl}" +requirements_ecore_win32="ecore >= 1.6.99 eina >= 1.6.99 ${requirements_ecore_win32}" +requirements_ecore_wince="ecore >= 1.6.99 eina >= 1.6.99 ${requirements_ecore_wince}" +requirements_ecore_x="ecore >= 1.6.99 eina >= 1.6.99 ${requirements_ecore_x}" + + +# glib support (main loop integration) +AC_ARG_ENABLE([glib], + [AC_HELP_STRING([--disable-glib], [disable glib support. @<:@default=detect@:>@])], + [want_glib=$enableval], []) + +if test "x$want_glib" != "xno"; then + PKG_CHECK_MODULES([GLIB], [glib-2.0], [have_glib="yes"], [have_glib="no"]) +else + have_glib="no" +fi +if test "x$want_glib" = "xyes" -a "x$have_glib" = "xno"; then + AC_MSG_ERROR([GLib support requested, but no GLib found by pkg-config.]) +elif test "x$have_glib" = "xyes"; then + AC_DEFINE(HAVE_GLIB, [1], [Have GLib]) + requirements_ecore="glib-2.0 ${requirements_ecore}" +fi + + +# SDL library (ecore_sdl) + +have_sdl="no" +PKG_CHECK_MODULES([SDL], [sdl >= 1.2.0], [have_sdl="yes"], [have_sdl="no"]) +if test "x${have_sdl}" != "xyes" ; then + SDL_CONFIG="sdl-config" + AC_ARG_WITH([sdl-config], + [AC_HELP_STRING([--with-sdl-config=PATH], [use sdl-config specified])], + [ + SDL_CONFIG=$withval + AC_MSG_NOTICE([using ${SDL_CONFIG} for sdl-config]) + ]) + + AC_PATH_PROG([SDL_CONFIG], ["sdl-config"], [""], [$PATH]) + + if test -n "$SDL_CONFIG" ; then + SDL_CFLAGS=`$SDL_CONFIG --cflags` + SDL_LIBS=`$SDL_CONFIG --libs` + AC_SUBST(SDL_CFLAGS) + AC_SUBST(SDL_LIBS) + have_sdl="yes" + fi +fi + +if test "x${have_sdl}" = "xyes" ; then + PKG_CHECK_EXISTS([sdl >= 1.3.0], + [AC_DEFINE(BUILD_ECORE_EVAS_SDL_130, 1, [Support for SVN SDL])]) +fi + + +# DirectFB library (ecore_directfb) + +PKG_CHECK_MODULES([DIRECTFB], + [directfb >= 0.9.16], + [have_directfb="yes"], + [have_directfb="no"]) + + +# Eet library (ecore_config) + +#PKG_CHECK_MODULES([EET], +# [eet >= 1.6.99], +# [have_eet="yes"], +# [have_eet="no"]) + + +# Xlib and XCB (ecore_x) + +AC_CHECK_DECL([MAXHOSTNAMELEN], [FOUND_MAXHOSTNAMELEN=yes]) + +if test "x${FOUND_MAXHOSTNAMELEN}" != "xyes" ; then + AC_MSG_CHECKING([for header that defines MAXHOSTNAMELEN]) + FOUND_MAXHOSTNAMELEN="not found" + + AC_COMPILE_IFELSE( + [ + AC_LANG_PROGRAM( + [[ +#include + ]], + [[ +int h = MAXHOSTNAMELEN; + ]]) + ], + [ + FOUND_MAXHOSTNAMELEN="sys/param.h" + AC_DEFINE([NEED_SYS_PARAM_H], [1], [Define to 1 if you need to define MAXHOSTNAMELEN]) + ]) + + AC_COMPILE_IFELSE( + [ + AC_LANG_PROGRAM( + [[ +#include + ]], + [[ +int h = MAXHOSTNAMELEN; + ]]) + ], + [ + FOUND_MAXHOSTNAMELEN="netdb.h" + AC_DEFINE([NEED_NETDB_H], [1], [Define to 1 if you need to define MAXHOSTNAMELEN]) + ]) + + AC_MSG_RESULT([$FOUND_MAXHOSTNAMELEN]) +fi + +have_x="no" +have_ecore_x="no" +have_ecore_x_xlib="no" +have_ecore_x_xcb="no" + +x_dir=""; +x_includes=""; +x_cflags=""; +x_libs=""; + +ecore_x_libs_private="" + +AC_ARG_ENABLE(ecore-x-composite, + [AC_HELP_STRING([--disable-ecore-x-composite], + [disable the ecore_x support for Xcomposite extension. + @<:@default=detect@:>@])], + [want_ecore_x_composite=$enableval]) + +AC_ARG_ENABLE(ecore-x-damage, + [AC_HELP_STRING([--disable-ecore-x-damage], + [disable the ecore_x support for Xdamage extension. + @<:@default=detect@:>@])], + [want_ecore_x_damage=$enableval]) + +AC_ARG_ENABLE(ecore-x-dpms, + [AC_HELP_STRING([--disable-ecore-x-dpms], + [disable the ecore_x support for Xdpms extension. + @<:@default=detect@:>@])], + [want_ecore_x_dpms=$enableval]) + +AC_ARG_ENABLE(ecore-x-randr, + [AC_HELP_STRING([--disable-ecore-x-randr], + [disable the ecore_x support for Xrandr extension. + @<:@default=detect@:>@])], + [want_ecore_x_randr=$enableval]) + +AC_ARG_ENABLE(ecore-x-render, + [AC_HELP_STRING([--disable-ecore-x-render], + [disable the ecore_x support for Xrender extension. + @<:@default=detect@:>@])], + [want_ecore_x_render=$enableval]) + +AC_ARG_ENABLE(ecore-x-screensaver, + [AC_HELP_STRING([--disable-ecore-x-screensaver], + [disable the ecore_x support for Xscreensaver extension. + @<:@default=detect@:>@])], + [want_ecore_x_screensaver=$enableval]) + +AC_ARG_ENABLE(ecore-x-shape, + [AC_HELP_STRING([--disable-ecore-x-shape], + [disable the ecore_x support for Xshape extension. + @<:@default=detect@:>@])], + [want_ecore_x_shape=$enableval]) + +AC_ARG_ENABLE(ecore-x-gesture, + [AC_HELP_STRING([--enable-ecore-x-gesture], + [enable the ecore_x support for Xgesture extension. + @<:@default=detect@:>@])], + [want_ecore_x_gesture=$enableval]) + +AC_ARG_ENABLE(ecore-x-sync, + [AC_HELP_STRING([--disable-ecore-x-sync], + [disable the ecore_x support for Xsync extension. + @<:@default=detect@:>@])], + [want_ecore_x_sync=$enableval]) + +AC_ARG_ENABLE(ecore-x-xfixes, + [AC_HELP_STRING([--disable-ecore-x-xfixes], + [disable the ecore_x support for Xfixes extension. + @<:@default=detect@:>@])], + [want_ecore_x_xfixes=$enableval]) + +AC_ARG_ENABLE(ecore-x-xinerama, + [AC_HELP_STRING([--disable-ecore-x-xinerama], + [disable the ecore_x support for Xinerama extension. + @<:@default=detect@:>@])], + [want_ecore_x_xinerama=$enableval]) + +AC_ARG_ENABLE(ecore-x-xprint, + [AC_HELP_STRING([--disable-ecore-x-xprint], + [disable the ecore_x support for Xprint extension. + @<:@default=detect@:>@])], + [want_ecore_x_xprint=$enableval]) + +AC_ARG_ENABLE(ecore-x-xtest, + [AC_HELP_STRING([--disable-ecore-x-xtest], + [disable the ecore_x support for Xtest extension. + @<:@default=detect@:>@])], + [want_ecore_x_xtest=$enableval]) + +AC_ARG_ENABLE(ecore-x-cursor, + [AC_HELP_STRING([--disable-ecore-x-cursor], + [disable the ecore_x support for Xcursor extension. + @<:@default=detect@:>@])], + [want_ecore_x_cursor=$enableval]) + +AC_ARG_ENABLE(ecore-x-input, + [AC_HELP_STRING([--disable-ecore-x-input], + [disable the ecore_x support for Xinput/Xinput2 extension. + @<:@default=detect@:>@])], + [want_ecore_x_input=$enableval]) + +AC_ARG_ENABLE(ecore-x-dri, + [AC_HELP_STRING([--disable-ecore-x-dri], + [disable the ecore_x support for DRI extension. + @<:@default=detect@:>@])], + [want_ecore_x_dri=$enableval]) + +AC_ARG_ENABLE(ecore-x-xcb, + [AC_HELP_STRING([--enable-ecore-x-xcb], + [enable the ecore_x module with XCB backend. @<:@default=disabled@:>@])], + [want_ecore_x_xcb=$enableval]) + +AC_MSG_CHECKING(whether ecore_x with XCB backend is to be built) +AC_MSG_RESULT($want_ecore_x_xcb) + +if test "x$want_ecore_x_xcb" = "xyes" ; then + + AC_MSG_CHECKING([keysym definitions]) + KEYSYMDEFDIR=`$PKG_CONFIG --variable=includedir xproto`/X11 + FILES="keysymdef.h XF86keysym.h Sunkeysym.h DECkeysym.h HPkeysym.h" + for i in $FILES; do + if test -f "$KEYSYMDEFDIR/$i"; then + KEYSYMDEFS="$KEYSYMDEFS $KEYSYMDEFDIR/$i" + elif test "x$i" = "xkeysymdef.h"; then + AC_MSG_ERROR([Cannot find keysymdef.h]) + fi + done + AC_MSG_RESULT([$KEYSYMDEFS]) + AC_SUBST(KEYSYMDEFS) + + have_iconv="no" + AC_ARG_WITH([iconv-link], + AC_HELP_STRING([--with-iconv-link=ICONV_LINK], [explicitly specify an iconv link option]), + [ + LIBS="$withval $LIBS" + have_iconv="yes" + ]) + + AC_MSG_CHECKING(for explicit iconv link options) + if test "x${iconv_libs}" = "x" ; then + AC_MSG_RESULT([no explicit iconv link option]) + else + AC_MSG_RESULT([$iconv_libs]) + fi + + if test "x${have_iconv}" = "xno" ; then + AC_CHECK_HEADERS([iconv.h], [have_iconv="yes"]) + + if test "x${have_iconv}" = "xyes" ; then + AC_MSG_CHECKING([whether iconv() is in libc]) + + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ + #include + #include + ]], + [[ + iconv_t ic; + size_t count = iconv(ic, NULL, NULL, NULL, NULL); + ]])], + [have_iconv="yes"], + [have_iconv="no"]) + + AC_MSG_RESULT([${have_iconv}]) + fi + + if test "x${have_iconv}" = "xno" ; then + AC_MSG_CHECKING([whether iconv() is in libiconv.a]) + + LIBS_save="${LIBS}" + LIBS="-liconv $LIBS" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ + #include + #include + ]], + [[ + iconv_t ic; + size_t count; + count = iconv(ic, NULL, NULL, NULL, NULL); + ]])], + [have_iconv="yes"], + [ + have_iconv="no" + LIBS=${LIBS_save} + ]) + + AC_MSG_RESULT([${have_iconv}]) + fi + + if test "x${have_iconv}" = "xno" ; then + AC_MSG_CHECKING([whether iconv() is in libiconv_plug.a]) + + LIBS_save="${LIBS}" + LIBS="-liconv_plug $LIBS" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ + #include + #include + ]], + [[ + iconv_t ic; + size_t count = iconv(ic, NULL, NULL, NULL, NULL); + ]])], + [have_iconv="yes"], + [ + have_iconv="no" + LIBS=${LIBS_save} + ]) + + AC_MSG_RESULT([${have_iconv}]) + fi + + if test "x${have_iconv}" = "xyes" ; then + AC_DEFINE([HAVE_ICONV], [1], [Set to 1 if iconv library is installed]) + fi + fi + + PKG_CHECK_MODULES(ECORE_XCB, x11-xcb xcb xcb-shm xcb-event xcb-icccm >= 0.3.8 xcb-util >= 0.3.8 xcb-image xcb-keysyms >= 0.3.8, + [ have_ecore_x_xcb="yes" + requirements_ecore_x="x11-xcb xcb xcb-shm xcb-event xcb-icccm xcb-util xcb-image xcb-keysyms ${requirements_ecore_x}" + ], + [ + PKG_CHECK_MODULES(ECORE_XCB, x11-xcb xcb xcb-event xcb-shm xcb-icccm xcb-image xcb-keysyms, + [ have_ecore_x_xcb="yes" + AC_DEFINE(OLD_XCB_VERSION, 1, [xcb version]) + requirements_ecore_x="x11-xcb xcb xcb-event xcb-shm xcb-icccm xcb-image xcb-keysyms ${requirements_ecore_x}" ], + [ have_ecore_x_xcb="no" ]) + ], + [have_ecore_x_xcb="no" ]) + + if test "x$have_ecore_x_xcb" = "xyes" ; then + + PKG_CHECK_MODULES([PIXMAN], + [pixman-1], + [ + have_pixman="yes" + AC_DEFINE(HAVE_PIXMAN, 1, [have pixman for rendering]) + requirements_ecore_x="pixman-1 ${requirements_ecore_x}" + ], + [ + if test "x${want_pixman}" = "xyes" -a "x${use_strict}" = "xyes" ; then + AC_MSG_ERROR([Pixman not found (strict dependencies checking)]) + fi + ]) + + if test "x$want_ecore_x_composite" != "xno"; then + PKG_CHECK_MODULES(XCB_COMPOSITE, xcb-composite, + [ have_ecore_x_xcb_composite="yes" + requirements_ecore_x="xcb-composite ${requirements_ecore_x}" + AC_DEFINE(ECORE_XCB_COMPOSITE, 1, [Build support for XCB composite]) ], + [ have_ecore_x_xcb_composite="no" ]) + else + have_ecore_x_xcb_composite="no" + AC_MSG_NOTICE("composite extension explicitly disabled") + fi + + if test "x$want_ecore_x_damage" != "xno"; then + PKG_CHECK_MODULES(XCB_DAMAGE, xcb-damage, + [ have_ecore_x_xcb_damage="yes" + requirements_ecore_x="xcb-damage ${requirements_ecore_x}" + AC_DEFINE(ECORE_XCB_DAMAGE, 1, [Build support for XCB damage]) ], + [ have_ecore_x_xcb_damage="no" ]) + else + have_ecore_x_xcb_damage="no" + AC_MSG_NOTICE("damage extension explicitly disabled") + fi + + if test "x$want_ecore_x_dpms" != "xno"; then + PKG_CHECK_MODULES(XCB_DPMS, xcb-dpms, + [ have_ecore_x_xcb_dpms="yes" + requirements_ecore_x="xcb-dpms ${requirements_ecore_x}" + AC_DEFINE(ECORE_XCB_DPMS, 1, [Build support for XCB dpms]) ], + [ have_ecore_x_xcb_dpms="no" ]) + else + have_ecore_x_xcb_dpms="no" + AC_MSG_NOTICE("dpms extension explicitly disabled") + fi + + if test "x$want_ecore_x_randr" != "xno"; then + PKG_CHECK_MODULES(XCB_RANDR, xcb-randr, + [ have_ecore_x_xcb_randr="yes" + requirements_ecore_x="xcb-randr ${requirements_ecore_x}" + AC_DEFINE(ECORE_XCB_RANDR, 1, [Build support for XCB randr]) ], + [ have_ecore_x_xcb_randr="no" ]) + else + have_ecore_x_xcb_randr="no" + AC_MSG_NOTICE("randr extension explicitly disabled") + fi + + if test "x$want_ecore_x_render" != "xno"; then + PKG_CHECK_MODULES(XCB_RENDER, xcb-render xcb-renderutil, + [ have_ecore_x_xcb_render="yes" + requirements_ecore_x="xcb-render xcb-renderutil ${requirements_ecore_x}" + AC_DEFINE(ECORE_XCB_RENDER, 1, [Build support for XCB render]) ], + [ have_ecore_x_xcb_render="no" ]) + else + have_ecore_x_xcb_render="no" + AC_MSG_NOTICE("render extension explicitly disabled") + fi + + if test "x$want_ecore_x_screensaver" != "xno"; then + PKG_CHECK_MODULES(XCB_SCREENSAVER, xcb-screensaver, + [ have_ecore_x_xcb_screensaver="yes" + requirements_ecore_x="xcb-screensaver ${requirements_ecore_x}" + AC_DEFINE(ECORE_XCB_SCREENSAVER, 1, [Build support for XCB screensaver]) ], + [ have_ecore_x_xcb_screensaver="no" ]) + else + have_ecore_x_xcb_screensaver="no" + AC_MSG_NOTICE("screensaver extension explicitly disabled") + fi + + if test "x$want_ecore_x_shape" != "xno"; then + PKG_CHECK_MODULES(XCB_SHAPE, xcb-shape, + [ have_ecore_x_xcb_shape="yes" + requirements_ecore_x="xcb-shape ${requirements_ecore_x}" + AC_DEFINE(ECORE_XCB_SHAPE, 1, [Build support for XCB shape]) ], + [ have_ecore_x_xcb_shape="no" ]) + else + have_ecore_x_xcb_shape="no" + AC_MSG_NOTICE("shape extension explicitly disabled") + fi + + if test "x$want_ecore_x_gesture" != "xno"; then + PKG_CHECK_MODULES(XCB_XGESTURE, xcb-gesture, + [ have_ecore_x_xcb_gesture="yes" + requirements_ecore_x="xcb-gesture ${requirements_ecore_x}" + AC_DEFINE(ECORE_XCB_XGESTURE, 1, [Build support for XCB gesture]) ], + [ have_ecore_x_xcb_gesture="no" ]) + else + have_ecore_x_xcb_gesture="no" + AC_MSG_NOTICE("gesture extension explicitly disabled") + fi + + if test "x$want_ecore_x_sync" != "xno"; then + PKG_CHECK_MODULES(XCB_SYNC, xcb-sync, + [ have_ecore_x_xcb_sync="yes" + requirements_ecore_x="xcb-sync ${requirements_ecore_x}" + AC_DEFINE(ECORE_XCB_SYNC, 1, [Build support for XCB sync]) ], + [ have_ecore_x_xcb_sync="no" ]) + else + have_ecore_x_xcb_sync="no" + AC_MSG_NOTICE("sync extension explicitly disabled") + fi + + if test "x$want_ecore_x_xfixes" != "xno"; then + PKG_CHECK_MODULES(XCB_XFIXES, xcb-xfixes, + [ have_ecore_x_xcb_xfixes="yes" + requirements_ecore_x="xcb-xfixes ${requirements_ecore_x}" + AC_DEFINE(ECORE_XCB_XFIXES, 1, [Build support for XCB xfixes]) ], + [ have_ecore_x_xcb_xfixes="no" ]) + else + have_ecore_x_xcb_xfixes="no" + AC_MSG_NOTICE("xfixes extension explicitly disabled") + fi + + if test "x$want_ecore_x_xinerama" != "xno"; then + PKG_CHECK_MODULES(XCB_XINERAMA, xcb-xinerama, + [ have_ecore_x_xcb_xinerama="yes" + requirements_ecore_x="xcb-xinerama ${requirements_ecore_x}" + AC_DEFINE(ECORE_XCB_XINERAMA, 1, [Build support for XCB xinerama]) ], + [ have_ecore_x_xcb_xinerama="no" ]) + else + have_ecore_x_xcb_xinerama="no" + AC_MSG_NOTICE("xinerama extension explicitly disabled") + fi + + if test "x$want_ecore_x_xprint" != "xno"; then + PKG_CHECK_MODULES(XCB_XPRINT, xcb-xprint, + [ have_ecore_x_xcb_xprint="yes" + requirements_ecore_x="xcb-xprint ${requirements_ecore_x}" + AC_DEFINE(ECORE_XCB_XPRINT, 1, [Build support for XCB xprint]) ], + [ have_ecore_x_xcb_xprint="no" ]) + else + have_ecore_x_xcb_xprint="no" + AC_MSG_NOTICE("xprint extension explicitly disabled") + fi + + if test "x$want_ecore_x_xtest" != "xno"; then + PKG_CHECK_MODULES(XCB_XTEST, xcb-xtest, + [ have_ecore_x_xcb_xtest="yes" + requirements_ecore_x="xcb-xtest ${requirements_ecore_x}" + AC_DEFINE(ECORE_XCB_XTEST, 1, [Build support for XCB xtest]) ], + [ have_ecore_x_xcb_xtest="no" ]) + else + have_ecore_x_xcb_xtest="no" + AC_MSG_NOTICE("xtest extension explicitly disabled") + fi + +# input extension disabled currently in xcb as xcb-input has some issues + want_ecore_x_input="no" + if test "x$want_ecore_x_input" != "xno"; then + PKG_CHECK_MODULES(XCB_XINPUT, xcb-xinput, + [ have_ecore_x_xcb_xinput="yes" + requirements_ecore_x="xcb-xinput ${requirements_ecore_x}" + AC_DEFINE(ECORE_XCB_XINPUT, 1, [Build support for XCB xinput]) ], + [ have_ecore_x_xcb_xinput="no" ]) + else + have_ecore_x_xcb_xinput="no" + AC_MSG_NOTICE("xinput extension explicitly disabled") + fi + + if test "x$want_ecore_x_cursor" != "xno"; then + PKG_CHECK_MODULES(XCB_CURSOR, xcb-render xcb-renderutil, + [ have_ecore_x_xcb_cursor="yes" + requirements_ecore_x="xcb-render xcb-renderutil ${requirements_ecore_x}" + AC_DEFINE(ECORE_XCB_CURSOR, 1, [Build support for XCB cursor]) ], + [ have_ecore_x_xcb_cursor="no" ]) + else + have_ecore_x_xcb_cursor="no" + AC_MSG_NOTICE("cursor extension explicitly disabled") + fi + +# if test "x$want_ecore_x_dri" != "xno"; then +# PKG_CHECK_MODULES(XCB_DRI, xcb-dri2, +# [ have_ecore_x_xcb_dri="yes" +# requirements_ecore_x="xcb-dri2 ${requirements_ecore_x}" +# AC_DEFINE(ECORE_XCB_DRI, 1, [Build support for XCB dri/dri2]) ], +# [ have_ecore_x_xcb_dri="no" ]) +# else +# have_ecore_x_xcb_dri="no" +# AC_MSG_NOTICE("dri extension explicitly disabled") +# fi + + AC_DEFINE(HAVE_ECORE_X_XCB, 1, [Defined to 1 if XCB is enabled.]) + + x_cflags=$ECORE_XCB_CFLAGS + x_libs=$ECORE_XCB_LIBS + have_x="yes" + + have_ecore_x_xcb_define="-DHAVE_ECORE_X_XCB" + AC_SUBST(have_ecore_x_xcb_define) + fi +fi + +if ! test "x$have_ecore_x_xcb" = "xyes" ; then + AC_PATH_XTRA + AC_CHECK_HEADER(X11/X.h, + [ + if test "x$want_evas_simple_x11" = "xyes"; then + x_libs="${x_libs} -lX11 -lXext" + else + x_dir=${x_dir:-/usr/X11R6} + x_cflags=${x_cflags:--I${x_includes:-$x_dir/include}} + x_libs="${x_libs:--L${x_libraries:-$x_dir/lib}} -lX11 -lXext" + fi + have_ecore_x_xlib="yes" + ] + ) + + if test "x$have_ecore_x_xlib" = "xyes"; then + Xcursor_libs="" + Xcursor_cflags="" + use_Xcursor="no" + PCFLAGS=$CFLAGS + CFLAGS="$x_cflags $x_includes" + + if test "x$want_ecore_x_cursor" = "xyes"; then + AC_CHECK_HEADER(X11/Xcursor/Xcursor.h, + [ + AC_CHECK_LIB(Xcursor, XcursorImageLoadCursor, + [ + AC_DEFINE(ECORE_XCURSOR, 1, [Build support for Xcursor]) + Xcursor_cflags="" + Xcursor_libs="-lXcursor" + use_Xcursor="yes" + ], [ + Xcursor_cflags="" + Xcursor_libs="" + use_Xcursor="no" + ], [ + $x_libs -lXrender + ] + ) + ], [ + Xcursor_cflags="" + Xcursor_libs="" + use_Xcursor="no" + ], [ + #include + ] + ) + CFLAGS=$PCFLAGS + else + Xcursor_cflags="" + Xcursor_libs="" + use_Xcursor="no" + AC_MSG_NOTICE("Xcursor explicitly disabled") + fi + + AC_SUBST(Xcursor_cflags) + AC_SUBST(Xcursor_libs) + + ECORE_CHECK_X_EXTENSION([Xkb], [XKB.h], [X11], [XkbSetDetectableAutoRepeat], [$want_ecore_x_xkb]) + ECORE_CHECK_X_EXTENSION([Xcomposite], [Xcomposite.h], [Xcomposite], [XCompositeQueryExtension], [$want_ecore_x_composite]) + ECORE_CHECK_X_EXTENSION([Xdamage], [Xdamage.h], [Xdamage], [XDamageSubtract], [$want_ecore_x_damage]) + ECORE_CHECK_X_EXTENSION([Xdpms], [dpms.h], [Xdpms], [DPMSQueryExtension], [$want_ecore_x_dpms]) + if test "x$use_xdpms" = "xno" ; then + ECORE_CHECK_X_EXTENSION([Xdpms], [dpms.h], [Xext], [DPMSQueryExtension], [$want_ecore_x_dpms]) + fi + ECORE_CHECK_X_EXTENSION([Xfixes], [Xfixes.h], [Xfixes], [XFixesExpandRegion], [$want_ecore_x_xfixes]) + ECORE_CHECK_X_EXTENSION([Xinerama], [Xinerama.h], [Xinerama], [XineramaQueryScreens], [$want_ecore_x_xinerama]) + ECORE_CHECK_X_EXTENSION([Xprint], [Print.h], [Xp], [XpQueryScreens], [$want_ecore_x_xprint]) + ECORE_CHECK_X_EXTENSION([Xrandr], [Xrandr.h], [Xrandr], [XRRGetScreenResourcesCurrent], [$want_ecore_x_randr]) + ECORE_CHECK_X_EXTENSION([Xgesture], [gesture.h], [Xgesture], [XGestureQueryExtension], [$want_ecore_x_gesture]) + ECORE_CHECK_X_EXTENSION([Xrender], [Xrender.h], [Xrender], [XRenderFindVisualFormat], [$want_ecore_x_render]) + ECORE_CHECK_X_EXTENSION([Xtest], [XTest.h], [Xtst], [XTestFakeKeyEvent], [$want_ecore_x_xtest]) + ECORE_CHECK_X_EXTENSION([Xss], [scrnsaver.h], [Xss], [XScreenSaverSelectInput], [$want_ecore_x_screensaver]) + ECORE_CHECK_X_EXTENSION([Xi2], [XInput2.h], [Xi], [XIQueryDevice], [$want_ecore_x_input]) + + ecore_x_libs_private="${Xcursor_libs} ${XKB_LIBS} ${XCOMPOSITE_LIBS} ${XGESTURE_LIBS} ${XDAMAGE_LIBS} ${XDPMS_LIBS} ${XFIXES_LIBS} ${XINERAMA_LIBS} ${XPRINT_LIBS} ${XRANDR_LIBS} ${XRENDER_LIBS} ${XTEST_LIBS} ${XSS_LIBS} ${XI2_LIBS}" + + AC_DEFINE(HAVE_ECORE_X_XLIB, 1, [Defined to 1 if Xlib is enabled.]) + have_x="yes" + + have_ecore_x_xlib="yes" + fi +fi + +AC_SUBST(x_cflags) +AC_SUBST(x_includes) +AC_SUBST(x_libs) +AC_SUBST(ecore_x_libs_private) + +AM_CONDITIONAL(BUILD_ECORE_X_XLIB, test $have_ecore_x_xlib = yes) +AM_CONDITIONAL(BUILD_ECORE_X_XCB, test $have_ecore_x_xcb = yes) + + +# Evas library (ecore_config, ecore_input_evas, ecore_imf_evas and ecore_evas) + +PKG_CHECK_MODULES([EVAS], [evas >= 1.6.99], + [have_evas="yes"], + [have_evas="no"]) + + +### Checks for header files + +AC_CHECK_HEADERS([sys/select.h sys/prctl.h]) + +EFL_CHECK_PATH_MAX + +AC_HEADER_SYS_WAIT +AC_SYS_LARGEFILE + +have_addrinfo="no" +case "$host_os" in + mingw* | cegcc*) + AC_DEFINE(HAVE_DLFCN_H, 1, [Define to 1 if you have the header file.]) + AC_DEFINE(HAVE_SYS_MMAN_H, 1, [Define to 1 if you have the header file.]) + AC_DEFINE(HAVE_SYS_TIME_H, 1, [Define to 1 if you have the header file.]) + have_addrinfo="yes" + ;; + *) + AC_CHECK_HEADERS([dlfcn.h features.h langinfo.h locale.h sys/time.h sys/mman.h signal.h sys/resource.h]) + ;; +esac + +# ecore_con + +AC_CHECK_HEADERS([sys/socket.h]) +AC_CHECK_HEADERS([net/if.h], [], [], +[ +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +]) +AC_CHECK_HEADERS([sys/un.h], [], [], +[ +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +]) +AC_CHECK_HEADERS([arpa/inet.h arpa/nameser.h netinet/tcp.h netinet/in.h ws2tcpip.h netdb.h errno.h]) + +if test "x${ac_cv_header_netdb_h}" = "xyes" ; then + have_addrinfo="yes" +fi + +# Framebuffer (ecore_fb) +have_fb="no" +AC_CHECK_HEADER([linux/fb.h], + [AC_CHECK_HEADER([linux/input.h], [have_fb="yes"])]) + +# Cocoa header files (ecore_cocoa) + +if test "x${want_ecore_cocoa}" = "xyes" ; then + cocoa_ldflags="" + have_cocoa="no" + m4_ifdef([AC_PROG_OBJC], + [ + if test "x${have_gnu_objc}" = "xyes" ; then + AC_LANG_PUSH([Objective C]) + LIBS_save="$LIBS" + LIBS="$LIBS -framework Cocoa" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include + ]], + [[ +NSWindow *window; +window = [[NSWindow alloc] + initWithContentRect:NSMakeRect(0, 0, 1, 1) + styleMask:(NSTitledWindowMask) + backing:NSBackingStoreBuffered + defer:NO + screen:nil + ]; + ]])], + [ + have_cocoa="yes" + cocoa_ldflags="-framework Cocoa" + ], + [have_cocoa="no"]) + LIBS="$LIBS_save" + AC_MSG_CHECKING([whether Cocoa framework is supported]) + AC_MSG_RESULT([${have_cocoa}]) + AC_LANG_POP([Objective C]) + fi + ]) +fi +AC_SUBST(cocoa_ldflags) + +want_epoll=yes +AC_ARG_ENABLE(epoll, + AC_HELP_STRING([--enable-epoll], [enable or disable epoll support]), + [want_epoll=$enableval]) + +if test "x${want_epoll}" = "xyes" ; then + # check for epoll support + AC_CHECK_HEADERS([sys/epoll.h]) +fi + +# timerfd_create +AC_CHECK_HEADERS([sys/timerfd.h]) +AC_CHECK_FUNCS(timerfd_create) + +# thread support + +EFL_CHECK_THREADS( + [ + if test "x${_efl_have_posix_threads}" = "xyes" ; then + have_threads="POSIX" + else + if test "x${_efl_have_win32_threads}" = "xyes" ; then + have_threads="Win32" + else + have_threads="no" + fi + fi + ], + [have_threads="no"]) + +### enable thread safety if we have threads, unless specifically asked not to +if test "x${have_threads}" = "xno" +then + want_thread_safety="no" +else + want_thread_safety="no" # to be changed to yes when ready + AC_ARG_ENABLE(thread-safety, + AC_HELP_STRING([--enable-thread-safety], [enable or disable thread safety]), + [want_thread_safety=$enableval]) +fi + +if test "x${want_thread_safety}" = "xyes" +then + AC_DEFINE([HAVE_THREAD_SAFETY], [1], [Define to enable thread safety]) +fi + +### Checks for types +AC_CHECK_SIZEOF(int, 4) +AC_CHECK_SIZEOF(long, 4) + + +### Checks for structures + + +### Checks for compiler characteristics +AC_PROG_CC_STDC +AC_C_CONST +AC_C_BIGENDIAN +AC_HEADER_STDC +AC_C___ATTRIBUTE__ + +WIN32_CPPFLAGS="" +WIN32_CFLAGS="" +case "$host_os" in + mingw32ce*) + WIN32_CPPFLAGS="-D_WIN32_WCE=0x0420" + ;; + cegcc*) + WIN32_CPPFLAGS="-D_WIN32_WCE=0x0420" + WIN32_CFLAGS="-mwin32" + ;; + mingw*) + WIN32_CPPFLAGS="-D_WIN32_WINNT=0x0501" + ;; +esac +AC_SUBST(WIN32_CPPFLAGS) +AC_SUBST(WIN32_CFLAGS) + + +### Checks for linker characteristics + +# use --enable-auto-import on Windows + +lt_enable_auto_import="" +case "$host_os" in + mingw* | cegcc*) + lt_enable_auto_import="-Wl,--enable-auto-import" + ;; +esac +AC_SUBST(lt_enable_auto_import) + +### Checks for library functions +AC_ISC_POSIX +AC_FUNC_ALLOCA +AC_CHECK_FUNCS([gettimeofday strlcpy execvp]) + +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include + ]], + [[ +int i = isfinite(0); + ]])], + [ + AC_DEFINE(HAVE_ISFINITE, 1, [Define to 1 if you have `isfinite', as a function or macro.]) + have_isfinite="yes" + ], + [have_isfinite="no"]) + +AC_MSG_CHECKING([for isfinite]) +AC_MSG_RESULT([${have_isfinite}]) + +have_atfile_source=auto +AC_ARG_ENABLE([atfile-source], + [AC_HELP_STRING([--disable-atfile-source], + [disable use of atfile source functions as openat and mkdirat @<:@default=detect@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + have_atfile_source="yes" + else + have_atfile_source="no" + fi], + [have_atfile_source=auto]) + +if ! test "x${have_atfile_source}" = "xno" ; then + AC_CHECK_FUNCS(mkdirat, + [ + have_atfile_source="yes" + AC_DEFINE(HAVE_ATFILE_SOURCE, 1, [mkdirat exists]) + ], + [ + if test "x${have_atfile_source}" = "xyes" ; then + AC_MSG_ERROR([required atfile-source but no mkdirat()]) + fi + have_atfile_source="no" + ]) +fi + +# shm_open +EFL_CHECK_SHM_OPEN([have_shm_open="yes"], [have_shm_open="no"]) + +### Checks for optionnal feature +AC_CHECK_FUNC([mallinfo], + [ + have_mallinfo="yes" + AC_DEFINE(HAVE_MALLINFO, 1, [Gather memory statistic]) + ], + [have_mallinfo="no"]) + +### Ecore modules + +## Core modules + +# ecore_con +ECORE_CHECK_MODULE([con], [${want_ecore_con}], [Con], [${have_addrinfo}]) + +have_curl="no" +have_gnutls="no" +have_openssl="no" +have_cares="no" +want_ipv6="yes" +have_ipv6="no" + +AC_ARG_ENABLE([ipv6], + [AC_HELP_STRING([--disable-ipv6], + [disable ipv6 functionality @<:@default=detect@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + want_ipv6="yes" + else + want_ipv6="no" + fi], + [want_ipv6="auto"]) + +if test "x${have_ecore_con}" = "xyes" ; then + + # Verify IPV6 availability in headers + if test "x${want_ipv6}" != "xno" ; then + AC_CHECK_TYPES([struct ipv6_mreq], + [have_ipv6="yes"], + [have_ipv6="no"], + [[ +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_WS2TCPIP_H +# include +#endif + ]]) + fi + + if test "x${have_ipv6}" = "xyes" ; then + AC_DEFINE(HAVE_IPV6, 1, [Define if IPV6 is supported]) + fi + AM_CONDITIONAL([HAVE_IPV6], [test "x${have_ipv6}" = "xyes"]) + + ECORE_CHECK_CURL([${want_curl}], + [ + have_curl="yes" + requirements_ecore_con="libcurl ${requirements_ecore_con}" + ], + [have_curl="no"]) + + ECORE_CHECK_GNUTLS([${want_gnutls}], + [have_gnutls="yes"], + [have_gnutls="no"]) + + ECORE_CHECK_OPENSSL([${want_openssl}], + [have_openssl="yes"], + [have_openssl="no"]) + + if test "x${have_gnutls}" = "xyes" ; then + requirements_ecore_con="gnutls ${requirements_ecore_con}" + # no need to add it to req_ecore_ipc, since they + # depends on ecore_con anyway. + else + if test "x${have_openssl}" = "xyes" ; then + requirements_ecore_con="openssl ${requirements_ecore_con}" + # no need to add it to req_ecore_ipc, since they + # depends on ecore_con anyway. + fi + fi + + ECORE_CHECK_CARES([${want_cares}], + [ + have_cares="yes" + requirements_ecore_con="libcares ${requirements_ecore_con}" + ], + [have_cares="no"]) + +fi + +EFL_CHECK_COMPILER_FLAGS([ECORE_CON], [-Wno-override-init -Wno-initializer-overrides]) + +AM_CONDITIONAL([HAVE_CARES], [test "x${have_cares}" = "xyes"]) + +# ecore_ipc +ECORE_CHECK_MODULE([ipc], [${want_ecore_ipc}], [Ipc], [${have_ecore_con}], + [ + requirements_ecore_ipc="ecore-con >= 1.6.99 ${requirements_ecore_ipc}" + requirements_ecore_evas="ecore-ipc >= 1.6.99 ${requirements_ecore_evas}" + ]) + +# ecore_file +ECORE_CHECK_MODULE([file], [${want_ecore_file}], [File]) + +have_poll="no" +have_inotify="no" +have_notify_win32="no" +if test "x${have_ecore_file}" = "xyes" ; then + ECORE_CHECK_POLL([${want_poll}], [have_poll="yes"], [have_poll="no"]) + ECORE_CHECK_INOTIFY([${want_inotify}], [have_inotify="yes"], [have_inotify="no"]) + ECORE_CHECK_NOTIFY_WIN32([${want_notify_win32}], [have_notify_win32="yes"], [have_notify_win32="no"]) + + if test "x${have_ecore_con}" = "xyes" ; then + requirements_ecore_file="ecore-con >= 1.6.99 ${requirements_ecore_file}" + else + ECORE_CHECK_CURL([${want_curl}], + [ + have_curl="yes" + requirements_ecore_file="libcurl ${requirements_ecore_file}" + ], + [have_curl="no"]) + fi + +fi + +# ecore_config +#ecore_config_deps="no" +#if test "x${have_eet}" = "xyes" -a "x${have_evas}" -a "x${have_ecore_ipc}" ; then +# ecore_config_deps="yes" +#fi + +#ECORE_CHECK_MODULE([config], [${want_ecore_config}], [Config], [${ecore_config_deps}], +# [requirements_ecore_config="ecore-ipc >= 1.6.99 evas >= 1.6.99 eet >= 1.6.99 ${requirements_ecore_config}"]) + +AM_CONDITIONAL(BUILD_ECORE_CONFIG, false) + +# ecore_imf + +ECORE_CHECK_MODULE([imf], [${want_ecore_imf}], [Imf]) + +# ecore_imf_evas + +ecore_imf_evas_deps="no" +if test "x${have_ecore_imf}" = "xyes" -a "x${have_evas}" = "xyes" ; then + ecore_imf_evas_deps="yes" +fi + +ECORE_CHECK_MODULE([imf-evas], [${want_ecore_imf}], [Imf_Evas], [${ecore_imf_evas_deps}], + [requirements_ecore_imf_evas="ecore-imf >= 1.6.99 evas >= 1.6.99 ${requirements_ecore_imf_evas}"]) + +# ecore_input{_evas} +ECORE_CHECK_MODULE([input], [${want_ecore_input}], [Input]) +ECORE_CHECK_MODULE([input-evas], [${want_ecore_input}], [Input_Evas], [${have_evas}], + [requirements_ecore_input_evas="ecore-input >= 1.6.99 evas >= 1.6.99 ${requirements_ecore_input}"]) + +# ecore_imf_xim +AM_CONDITIONAL(BUILD_ECORE_IMF_XIM, false) +ecore_imf_xim_deps="no" +echo "have_ecore_x_xlib: ${have_ecore_x_xlib}" +if test "x${have_ecore_imf}" = "xyes" \ + -a "x${have_ecore_x_xlib}" = "xyes" \ + -a "x${have_ecore_input}" = "xyes" ; then + ecore_imf_xim_deps="yes" + AC_DEFINE(BUILD_ECORE_IMF_XIM, 1, [Ecore Imf XIM Support]) +fi + +ECORE_CHECK_MODULE([imf-xim], [${want_ecore_imf}], [Imf_XIM], [${ecore_imf_xim_deps}], + [requirements_ecore_imf_xim="ecore-imf >= 1.6.99 ecore-x >= 1.6.99 ecore-input >= 1.6.99 ${requirements_ecore_imf_xim}"]) + +# ecore_imf_scim +PKG_CHECK_MODULES([SCIM], [scim], [have_scim="yes"], [have_scim="no"]) + +AM_CONDITIONAL(BUILD_ECORE_IMF_SCIM, false) +ecore_imf_scim_deps="no" +echo "have_ecore_x_xlib: ${have_ecore_x_xlib}" +if test "x${have_ecore_imf}" = "xyes" \ + -a "x${have_scim}" = "xyes" \ + -a "x${have_ecore_input}" = "xyes" ; then + ecore_imf_scim_deps="yes" + AC_DEFINE(BUILD_ECORE_IMF_SCIM, 1, [Ecore Imf SCIM Support]) +fi + +ECORE_CHECK_MODULE([imf-scim], [${want_ecore_imf}], [Imf_SCIM], [${ecore_imf_scim_deps}], + [requirements_ecore_imf_scim="ecore-imf >= 1.6.99 ecore-x >= 1.6.99 ecore-input >= 1.6.99 ${requirements_ecore_imf_scim}"]) + +# ecore_imf_ibus +PKG_CHECK_MODULES([IBUS], [ibus-1.0 >= 1.4], [have_ibus="yes"], [have_ibus="no"]) + +AM_CONDITIONAL(BUILD_ECORE_IMF_IBUS, false) +ecore_imf_ibus_deps="no" +echo "have_ecore_x_xlib: ${have_ecore_x_xlib}" +if test "x${have_ecore_imf}" = "xyes" \ + -a "x${have_glib}" = "xyes" \ + -a "x${have_ibus}" = "xyes" \ + -a "x${have_ecore_input}" = "xyes" ; then + ecore_imf_ibus_deps="yes" + AC_DEFINE(BUILD_ECORE_IMF_IBUS, 1, [Ecore Imf IBUS Support]) +fi + +ECORE_CHECK_MODULE([imf-ibus], [${want_ecore_imf}], [Imf_IBUS], [${ecore_imf_ibus_deps}], + [requirements_ecore_imf_ibus="ecore-imf >= 1.6.99 ecore-x >= 1.6.99 ecore-input >= 1.6.99 ${requirements_ecore_imf_ibus}"]) + +## Graphic systems + +# ecore_x{cb} + +ecore_x_deps="no" +if test "x${have_x}" = "xyes" -a \ + "x${have_ecore_input}" = "xyes" ; then + ecore_x_deps="yes" +fi + +ECORE_CHECK_MODULE([x], [${want_ecore_x}], [X], [${ecore_x_deps}], + [ + ecore_x_libs="$ecore_x_libs $x_libs" + requirements_ecore_x="ecore-input >= 1.6.99 ${requirements_ecore_x}" + ]) + +# ecore_win32 + +ECORE_CHECK_MODULE([win32], [${want_ecore_win32}], [Win32], [${have_ecore_input}], + [ + ecore_win32_libs="-lole32 -lgdi32" + requirements_ecore_win32="ecore-input >= 1.6.99 ${requirements_ecore_win32}" + ]) +AC_SUBST(ecore_win32_libs) + +# ecore_cocoa + +ecore_cocoa_deps="no" +if test "x${have_ecore_input}" = "xyes" -a "x${have_cocoa}" = "xyes" ; then + ecore_cocoa_deps="yes" +fi + +ECORE_CHECK_MODULE([cocoa], [${want_ecore_cocoa}], [Cocoa], [${ecore_cocoa_deps}], + [requirements_ecore_cocoa="ecore-input >= 1.6.99 ${requirements_ecore_cocoa}"]) + +# ecore_sdl + +ecore_sdl_deps="no" +if test "x${have_sdl}" = "xyes" -a "x${have_ecore_input}" = "xyes" ; then + ecore_sdl_deps="yes" +fi + +ECORE_CHECK_MODULE([sdl], [${want_ecore_sdl}], [Sdl], [${ecore_sdl_deps}], + [requirements_ecore_sdl="ecore-input >= 1.6.99 ${requirements_ecore_sdl}"]) + +ECORE_CHECK_MODULE([psl1ght], [${want_ecore_psl1ght}], [psl1ght], [${ecore_psl1ght_deps}], + [requirements_ecore_psl1ght="ecore-input >= 1.6.99 ${requirements_ecore_psl1ght}"]) + +# ecore_fb +ECORE_CHECK_MODULE([fb], [${want_ecore_fb}], [FB], [$have_fb]) + +if test "x${have_ecore_fb}" = "xyes" ; then + ECORE_CHECK_TSLIB([${want_tslib}], + [ + have_tslib="yes" + requirements_ecore_fb="${_tslib_requirement} ${requirements_ecore_fb}" + ], + [have_tslib="no"]) +fi + +# ecore_directfb + +ECORE_CHECK_MODULE([directfb], [${want_ecore_directfb}], [DirectFB], [${have_directfb}], + [requirements_ecore_directfb="directfb ${requirements_ecore_directfb}"]) + +# ecore_wince + +ECORE_CHECK_MODULE([wince], [${want_ecore_wince}], [WinCE], [${have_ecore_input}], + [requirements_ecore_win32="ecore-input >= 1.6.99 ${requirements_ecore_win32}"]) + +## Ecore Evas + +# ecore_evas + +ecore_evas_deps="no" +if test "x${have_evas}" = "xyes" && test "x${have_ecore_input}" = "xyes" && test "x${have_ecore_input_evas}" = "xyes" ; then + ecore_evas_deps="yes" +fi + +ECORE_CHECK_MODULE([evas], [${want_ecore_evas}], [Evas], [${ecore_evas_deps}], + [requirements_ecore_evas="ecore-input >= 1.6.99 ecore-input-evas >= 1.6.99 evas >= 1.6.99 ${requirements_ecore_evas}"]) + +# ecore_evas_buffer + +ECORE_EVAS_CHECK_MODULE([software-buffer], + [${want_ecore_evas_software_buffer}], + [Software Buffer], + [yes]) + +# ecore_evas_x11 + +# ecore_evas_software_x11 + +ECORE_EVAS_CHECK_MODULE([software-x11], + [${want_ecore_evas_software_x11}], + [Software X11], + [${have_ecore_x}]) + +have_ecore_evas_software_xlib="no" +have_ecore_evas_software_xcb="no" +if test "x$have_ecore_evas_software_x11" = "xyes" ; then + have_ecore_evas_software_xlib=`${PKG_CONFIG} --variable=Xlib evas-software-x11` + if test "x${have_ecore_evas_software_xlib}" = "xstatic"; then + have_ecore_evas_software_xlib="yes" + fi + if test "x${have_ecore_evas_software_xlib}" = "xyes" -a "x${have_ecore_x_xlib}" = "xyes" ; then + AC_DEFINE(BUILD_ECORE_EVAS_SOFTWARE_XLIB, 1, [Evas Software Xlib Engine Support]) + fi + have_ecore_evas_software_xcb=`${PKG_CONFIG} --variable=XCB evas-software-x11` + if test "x$have_ecore_evas_software_xcb" = "xstatic"; then + have_ecore_evas_software_xcb="yes" + fi + if test "x$have_ecore_evas_software_xcb" = "xyes" -a "x${have_ecore_x_xcb}" = "xyes" ; then + AC_DEFINE(BUILD_ECORE_EVAS_SOFTWARE_XCB, 1, [Evas Software XCB Engine Support]) + fi +fi + +# ecore_evas_opengl_x11 + +ECORE_EVAS_CHECK_MODULE([opengl-x11], + [${want_ecore_evas_opengl_x11}], + [OpenGL Xlib], + [${have_ecore_x}]) + +have_ecore_evas_opengl_xlib="no" +have_ecore_evas_opengl_xcb="no" +if test "x${have_ecore_evas_opengl_x11}" = "xyes" -o "x${have_ecore_evas_opengl_x11}" = "xstatic" ; then + have_ecore_evas_opengl_xlib=`${PKG_CONFIG} --variable=Xlib evas-opengl-x11` + if test "x${have_ecore_evas_opengl_xlib}" = "xyes" ; then + AC_DEFINE(BUILD_ECORE_EVAS_OPENGL_XLIB, 1, [OpenGL Xlib rendering backend]) + fi + +# opengl does not work with xcb (yet) + have_ecore_evas_opengl_xcb=`${PKG_CONFIG} --variable=XCB evas-opengl-x11` + if test "x${have_ecore_evas_opengl_xcb}" = "xstatic"; then + have_ecore_evas_opengl_xcb="yes" + fi + if test "x${have_ecore_evas_opengl_xcb}" = "xyes" -a "x${have_ecore_x_xcb}" = "xyes" ; then + PKG_CHECK_MODULES(XCB_X11, x11-xcb, + [ have_ecore_x_opengl_xcb="yes" + requirements_ecore_x="x11-xcb ${requirements_ecore_x}" + AC_DEFINE(BUILD_ECORE_X_OPENGL_XCB, 1, [Build support for XCB-based OpenGL]) + AC_DEFINE(BUILD_ECORE_EVAS_OPENGL_XCB, 1, [OpenGL XCB rendering backend]) + ], + [ have_ecore_x_opengl_xcb="no" ]) + else + have_ecore_x_opengl_xcb="no" + AC_MSG_NOTICE("XCB-based OpenGL explicitly disabled") + fi +fi + +# ecore_evas_software_x11 16 bits + +ECORE_EVAS_CHECK_MODULE([software-16-x11], + [${want_ecore_evas_software_16_x11}], + [Software Xlib 16 bits], + [${have_ecore_x_xlib}]) + +ECORE_EVAS_CHECK_MODULE([software-8-x11], + [$want_ecore_evas_software_8_x11], + [Software 8bit X11], + $have_ecore_x_xcb) + + +if test "x$have_ecore_evas_software_x11" = "xyes" -o \ + "x$have_ecore_evas_opengl_x11" = "xyes" -o \ + "x$have_ecore_evas_software_8_x11" = "xyes" -o \ + "x$have_ecore_evas_software_16_x11" = "xyes" -o \ + "x$have_ecore_evas_software_xcb" = "xyes"; then + AC_DEFINE(BUILD_ECORE_EVAS_X11, 1, [Support for X Window Engines in Ecore_Evas]) + requirements_ecore_evas="ecore-x >= 1.6.99 ${requirements_ecore_evas}" +fi + +# ecore_evas_win32 + +ECORE_EVAS_CHECK_MODULE([software-gdi], + [${want_ecore_evas_software_gdi}], + [Software GDI], + [${have_ecore_win32}]) + +ECORE_EVAS_CHECK_MODULE([software-ddraw], + [${want_ecore_evas_software_ddraw}], + [Software DirectDraw], + [${have_ecore_win32}]) + +ECORE_EVAS_CHECK_MODULE([direct3d], + [${want_ecore_evas_direct3d}], + [Direct3d], + [${have_ecore_win32}]) + +ECORE_EVAS_CHECK_MODULE([opengl-glew], + [${want_ecore_evas_opengl_glew}], + [Glew OpenGL], + [${have_ecore_win32}]) + +ECORE_EVAS_CHECK_MODULE([software-16-ddraw], + [${want_ecore_evas_software_16_ddraw}], + [16 bpp Software DirectDraw], + [${have_ecore_win32}]) + +if test "x${have_ecore_evas_software_gdi}" = "xyes" -o \ + "x${have_ecore_evas_software_ddraw}" = "xyes" -o \ + "x${have_ecore_evas_direct3d}" = "xyes" -o \ + "x${have_ecore_evas_opengl_glew}" = "xyes" -o \ + "x${have_ecore_evas_software_16_ddraw}" = "xyes" ; then + AC_DEFINE(BUILD_ECORE_EVAS_WIN32, 1, [Support for Win32 Engine in Ecore_Evas]) + requirements_ecore_evas="ecore-win32 >= 1.6.99 ${requirements_ecore_evas}" +fi + +# ecore_evas_software_sdl + +have_ecore_evas_software_sdl="no" +if test "x${have_ecore_sdl}" = "xyes"; then + requirements_ecore_evas="ecore-sdl >= 1.6.99 ${requirements_ecore_evas}" + have_ecore_evas_software_sdl="yes" + AC_DEFINE(BUILD_ECORE_EVAS_SOFTWARE_SDL, 1, [Support for Software SDL Engine in Ecore_Evas]) + requirements_ecore_evas="ecore-sdl >= 1.6.99 ${requirements_ecore_evas}" +fi + +# ecore_evas_gl_sdl + +ECORE_EVAS_CHECK_MODULE([opengl-sdl], + [${want_ecore_evas_gl_sdl}], + [OpenGL SDL], + [${have_ecore_sdl}], + [requirements_ecore_evas="ecore-sdl >= 1.6.99 ${requirements_ecore_evas}"]) + +# ecore_evas_cocoa + +ECORE_EVAS_CHECK_MODULE([opengl-cocoa], + [${want_ecore_evas_gl_cocoa}], + [OpenGL Cocoa], + [${have_ecore_cocoa}], + [requirements_ecore_evas="ecore-cocoa >= 1.6.99 ${requirements_ecore_evas}"]) + +# ecore_evas_directfb + +ECORE_EVAS_CHECK_MODULE([directfb], + [${want_ecore_evas_directfb}], + [DirectFB], + [${have_ecore_directfb}], + [requirements_ecore_evas="ecore-directfb >= 1.6.99 ${requirements_ecore_evas}"]) + +# ecore_evas_fb + +ECORE_EVAS_CHECK_MODULE([fb], + [${want_ecore_evas_fb}], + [Linux Framebuffer], + [${have_ecore_fb}], + [requirements_ecore_evas="ecore-fb >= 1.6.99 ${requirements_ecore_evas}"]) + +# ecore_evas_wince + +ECORE_EVAS_CHECK_MODULE([software-16-wince], + [${want_ecore_evas_software_16_wince}], + [16 bpp Software Windows CE], + [${have_ecore_wince}], + [requirements_ecore_evas="ecore-wince >= 1.6.99 ${requirements_ecore_evas}"]) + +# ecore_evas_ews + +ECORE_EVAS_CHECK_MODULE_FULL([ews], [software-buffer], + [${want_ecore_evas_ews}], + [Ecore Evas Single Process Windowing System], + [yes], []) + +# ecore_evas_extn + +have_extn="yes" +if test "x${have_ecore_ipc}" = "xno" || \ + test "x${have_ecore_evas_software_buffer}" = "xno" || \ + test "x${have_shm_open}" = "xno" ; then + have_extn="no" +fi + +dnl THIS IS SPECIAL - dont use normal ECORE_EVAS_CHECK_MODULE +have_ecore_evas_extn="no" +if test "x${want_ecore_evas_extn}" = "xyes" && \ + test "x${have_extn}" = "xyes" && \ + test "x${have_ecore_evas}" = "xyes"; then + AC_DEFINE([BUILD_ECORE_EVAS_EXTN], [1], [Support for Extn Engine in Ecore_Evas]) + have_ecore_evas_extn="yes" +fi + +# ecore_evas_psl1ght + +ECORE_EVAS_CHECK_MODULE([psl1ght], + [${want_ecore_evas_psl1ght}], + [PSL1GHT], + [${have_ecore_psl1ght}], + [requirements_ecore_evas="ecore-psl1ght >= 1.6.99 ${requirements_ecore_evas}"]) + +### WAYLAND + +ecore_wayland_deps="no" +have_wayland="no" +if test "x${want_ecore_wayland}" = "xyes" ; then + PKG_CHECK_MODULES([WAYLAND], [wayland-client wayland-cursor xkbcommon], [have_wayland="yes"], [have_wayland="no"]) +fi +if test "x${have_ecore_input}" = "xyes" -a "x${have_wayland}" = "xyes" ; then + ecore_wayland_deps="yes" +fi + +ECORE_CHECK_MODULE([wayland], [${want_ecore_wayland}], [Wayland], [${ecore_wayland_deps}]) +if test "x${have_ecore_wayland}" = "xyes" ; then + requirements_ecore_wayland="ecore-input >= 1.6.99 wayland-client wayland-cursor xkbcommon ${requirements_ecore_wayland}" +fi + +ECORE_EVAS_CHECK_MODULE_FULL([wayland-shm], [wayland-shm], + [${want_ecore_evas_wayland_shm}], + [Wayland Shm], + [${have_ecore_wayland}], + [requirements_ecore_evas="${requirements_ecore_wayland} ${requirements_ecore_evas}"]) + +ECORE_EVAS_CHECK_MODULE_FULL([wayland-egl], [wayland-egl egl >= 7.10], + [${want_ecore_evas_wayland_egl}], + [Wayland Egl], + [${have_ecore_wayland}], + [ + PKG_CHECK_MODULES([WAYLAND_EGL], [wayland-egl], [have_wayland_egl="yes"], [have_wayland_egl="no"]) + if test "x${have_wayland_egl}" = "xyes" ; then + requirements_ecore_evas="wayland-egl egl >= 7.10 ${requirements_ecore_wayland} ${requirements_ecore_evas}" + fi + ]) + +### Unit tests and coverage + +EFL_CHECK_TESTS([enable_tests="yes"], [enable_tests="no"]) + +EFL_CHECK_COVERAGE([${enable_tests}], [enable_coverage="yes"], [enable_coverage="no"]) +CFLAGS="${CFLAGS} ${EFL_COVERAGE_CFLAGS}" +ECORE_LIBS="${ECORE_LIBS} ${EFL_COVERAGE_LIBS}" +if test "x$enable_coverage" = "xyes" ; then + CFLAGS="${CFLAGS} ${EFL_DEBUG_CFLAGS}" +fi + +### install and build examples + +EFL_CHECK_BUILD_EXAMPLES([enable_build_examples="yes"], [enable_build_examples="no"]) +EFL_CHECK_INSTALL_EXAMPLES([enable_install_examples="yes"], [enable_install_examples="no"]) + +### requirements + +AC_SUBST(requirements_ecore) +AC_SUBST(requirements_ecore_con) +#AC_SUBST(requirements_ecore_config) +AC_SUBST(requirements_ecore_directfb) +AC_SUBST(requirements_ecore_evas) +AC_SUBST(requirements_ecore_fb) +AC_SUBST(requirements_ecore_file) +AC_SUBST(requirements_ecore_imf) +AC_SUBST(requirements_ecore_imf_evas) +AC_SUBST(requirements_ecore_input) +AC_SUBST(requirements_ecore_input_evas) +AC_SUBST(requirements_ecore_ipc) +AC_SUBST(requirements_ecore_cocoa) +AC_SUBST(requirements_ecore_sdl) +AC_SUBST(requirements_ecore_psl1ght) +AC_SUBST(requirements_ecore_x) +AC_SUBST(requirements_ecore_win32) +AC_SUBST(requirements_ecore_wince) +AC_SUBST(requirements_ecore_imf_xim) +AC_SUBST(requirements_ecore_imf_scim) +AC_SUBST(requirements_ecore_imf_ibus) +AC_SUBST(requirements_ecore_wayland) + +AC_CONFIG_FILES([ +Makefile +ecore-con.pc +ecore-config.pc +ecore-directfb.pc +ecore-evas.pc +ecore-fb.pc +ecore-file.pc +ecore-imf.pc +ecore-imf-evas.pc +ecore-ipc.pc +ecore-x.pc +ecore-input.pc +ecore-input-evas.pc +ecore-win32.pc +ecore-sdl.pc +ecore-cocoa.pc +ecore-psl1ght.pc +ecore-wince.pc +ecore-wayland.pc +ecore.pc +doc/ecore.dox +doc/Makefile +doc/Doxyfile +src/Makefile +src/util/Makefile +src/bin/Makefile +src/lib/Makefile +src/lib/ecore/Makefile +src/lib/ecore_con/Makefile +src/lib/ecore_config/Makefile +src/lib/ecore_directfb/Makefile +src/lib/ecore_evas/Makefile +src/lib/ecore_fb/Makefile +src/lib/ecore_file/Makefile +src/lib/ecore_cocoa/Makefile +src/lib/ecore_sdl/Makefile +src/lib/ecore_psl1ght/Makefile +src/lib/ecore_imf/Makefile +src/lib/ecore_imf_evas/Makefile +src/lib/ecore_input/Makefile +src/lib/ecore_input_evas/Makefile +src/lib/ecore_ipc/Makefile +src/lib/ecore_win32/Makefile +src/lib/ecore_wince/Makefile +src/lib/ecore_x/Makefile +src/lib/ecore_x/xlib/Makefile +src/lib/ecore_x/xcb/Makefile +src/lib/ecore_wayland/Makefile +src/examples/Makefile +src/tests/Makefile +src/modules/Makefile +src/modules/immodules/Makefile +src/modules/immodules/xim/Makefile +src/modules/immodules/scim/Makefile +src/modules/immodules/ibus/Makefile +ecore.spec +$po_makefile_in +]) + +AC_OUTPUT + +echo +echo "$PACKAGE $VERSION" +echo +echo "Optional Modules:" +echo +echo " Core:" +echo +echo " Ecore........................: always" +echo " Thread support.............: $have_threads" +echo " Thread safety..............: $want_thread_safety" +echo " GLib support...............: $have_glib" +echo " Always integrate GLib......: $want_glib_integration_always" +echo " Use g_main_loop............: $want_g_main_loop" +echo " Gathering memory statistic.: $have_mallinfo" +echo " Gathering timer allocation.: $want_ecore_timer_dump" +echo " Ecore_Con....................: $have_ecore_con" +if test "x$have_ecore_con" = "xyes" ; then + echo $ECHO_N " OpenSSL....................: $have_openssl $ECHO_C" +if test "x$have_gnutls" = "xyes" ; then + echo " (disabled)" +else + echo +fi + echo " IPv6.......................: $have_ipv6" + echo " GnuTLS.....................: $have_gnutls" + echo " CURL.......................: $have_curl" + echo " Local Sockets..............: $want_ecore_con_local_sockets" +if test "x$want_ecore_con_local_sockets" = "xyes" ; then + echo " Abstract Sockets.........: $want_ecore_con_abstract_sockets" +fi +if test "x$have_cares" = "xyes" ; then + echo " Resolver...................: c-ares" +elif test "x$have_ipv6" = "xyes" ; then + echo " Resolver...................: dns.c" +else + echo " Resolver...................: fork" +fi +fi +echo " Ecore_Ipc....................: $have_ecore_ipc" +if test "x$have_ecore_ipc" = "xyes" ; then + echo $ECHO_N " OpenSSL....................: $have_openssl $ECHO_C" +if test "x$have_gnutls" = "xyes" ; then + echo " (disabled)" +else + echo +fi + echo " GnuTLS.....................: $have_gnutls" +fi +echo " Ecore_File...................: $have_ecore_file" +if test "x$have_ecore_file" = "xyes" ; then + echo " Inotify....................: $have_inotify" + echo " Windows notification.......: $have_notify_win32" + echo " Poll.......................: $have_poll" + echo " CURL.......................: $have_curl" +fi +#echo " Ecore_Config.................: $have_ecore_config (deprecated)" +echo " Ecore_IMF....................: $have_ecore_imf" +echo " XIM........................: $have_ecore_imf_xim" +echo " SCIM.......................: $have_ecore_imf_scim" +echo " IBUS.......................: $have_ecore_imf_ibus" +echo " Ecore_IMF_Evas...............: $have_ecore_imf_evas" +echo " Ecore_Input..................: $have_ecore_input" +echo " Ecore_Input_Evas.............: $have_ecore_input_evas" + +echo +echo " Graphic systems:" +echo + +if test "x$have_ecore_x" = "xyes" ; then + if test "x$have_ecore_x_xcb" = "xyes" ; then + echo " Ecore_X (XCB backend)........: $have_ecore_x_xcb" + echo " Xprint.....................: $have_ecore_x_xcb_xprint" + echo " Xinerama...................: $have_ecore_x_xcb_xinerama" + echo " Xrandr.....................: $have_ecore_x_xcb_randr" + echo " Xscreensaver...............: $have_ecore_x_xcb_screensaver" + echo " Xshape.....................: $have_ecore_x_xcb_shape" + echo " Xgesture...................: $have_ecore_x_xcb_gesture" + echo " Xsync......................: $have_ecore_x_xcb_sync" + echo " Xrender....................: $have_ecore_x_xcb_render" + echo " Xcomposite.................: $have_ecore_x_xcb_composite" + echo " Xfixes.....................: $have_ecore_x_xcb_xfixes" + echo " Xdamage....................: $have_ecore_x_xcb_damage" + echo " Xdpms......................: $have_ecore_x_xcb_dpms" + echo " Xtest......................: $have_ecore_x_xcb_xtest" + else + echo " Ecore_X (Xlib backend).......: $have_ecore_x" + echo " Xcursor....................: $use_Xcursor" + echo " Xkb........................: $use_xkb" + echo " Xprint.....................: $use_xprint" + echo " Xinerama...................: $use_xinerama" + echo " Xrandr.....................: $use_xrandr" + echo " Xgesture...................: $use_xgesture" + echo " Xscreensaver...............: $use_xss" + echo " Xrender....................: $use_xrender" + echo " Xcomposite.................: $use_xcomposite" + echo " Xfixes.....................: $use_xfixes" + echo " Xdamage....................: $use_xdamage" + echo " Xdpms......................: $use_xdpms" + echo " Xtest......................: $use_xtest" + echo " XIM........................: $want_xim" + echo " Xi2........................: $use_xi2" + fi +else + echo " Ecore_X......................: $have_ecore_x" +fi +echo " Ecore_Win32..................: $have_ecore_win32" +echo " Ecore_Cocoa..................: $have_ecore_cocoa" +echo " Ecore_SDL....................: $have_ecore_sdl" +echo " Ecore_FB.....................: $have_ecore_fb" +if test "x${have_ecore_fb}" = "xyes" ; then + echo " Touchscreen................: $have_tslib" +fi +echo " Ecore_DirectFB...............: $have_ecore_directfb" +echo " Ecore_WinCE..................: $have_ecore_wince" +echo " Ecore_PSL1GHT................: $have_ecore_psl1ght" +echo " Ecore_Wayland................: $have_ecore_wayland" + +echo +echo " Ecore Evas:" +echo + +echo " Ecore_Evas...................: $have_ecore_evas" +if test "x${have_ecore_evas}" = "xyes" ; then + echo " Software Memory Buffer.....: $have_ecore_evas_software_buffer" + if test "x${have_ecore_evas_software_x11}" = "xyes" ; then + echo " Software X11...............: $have_ecore_evas_software_x11 (Xlib=${have_ecore_evas_software_xlib}) (XCB=${have_ecore_evas_software_xcb})" + else + echo " Software X11...............: $have_ecore_evas_software_x11" + fi + if test "x${have_ecore_evas_opengl_x11}" = "xyes" ; then + echo " OpenGL X11.................: $have_ecore_evas_opengl_x11 (Xlib=${have_ecore_evas_opengl_xlib}) (XCB=${have_ecore_evas_opengl_xcb})" + else + echo " OpenGL X11.................: $have_ecore_evas_opengl_x11" + fi + echo " Software GDI...............: $have_ecore_evas_software_gdi" + echo " Software DirectDraw........: $have_ecore_evas_software_ddraw" + echo " Direct3D...................: $have_ecore_evas_direct3d" + echo " OpenGL Glew................: $have_ecore_evas_opengl_glew" + echo " Software SDL...............: $have_ecore_evas_software_sdl" + echo " OpenGL SDL.................: $have_ecore_evas_opengl_sdl" + echo " OpenGL Cocoa...............: $have_ecore_evas_opengl_cocoa" + echo " DirectFB...................: $have_ecore_evas_directfb" + echo " PSL1GHT....................: $have_ecore_evas_psl1ght" + echo " Software Framebuffer.......: $have_ecore_evas_fb" + echo " Software 8bit grayscale XCB: $have_ecore_evas_software_8_x11" + echo " Software 16bit X11.........: $have_ecore_evas_software_16_x11" + echo " Software 16bit DirectDraw..: $have_ecore_evas_software_16_ddraw" + echo " Software 16bit WinCE.......: $have_ecore_evas_software_16_wince" + echo " Sing.Proc. Windowing System: $have_ecore_evas_ews" + echo " Wayland Shm................: $have_ecore_evas_wayland_shm" + echo " Wayland Egl................: $have_ecore_evas_wayland_egl" + echo " Extn (Plug/socket Extn)....: $have_ecore_evas_extn" +fi +echo +echo " Tests................: ${enable_tests}" +echo " Coverage.............: ${enable_coverage}" +echo " Maximum log level....: ${with_max_log_level}" +echo "Documentation..........: ${build_doc}" +echo "Examples...............: ${enable_build_examples}" +echo "Examples installed.....: ${enable_install_examples}" +echo +echo "Compilation............: make (or gmake)" +echo " CPPFLAGS.............: $CPPFLAGS" +echo " CFLAGS...............: $CFLAGS" +echo " CXXFLAGS.............: $CXXFLAGS" +echo " LDFLAGS..............: $LDFLAGS" +echo +echo "Installation...........: make install (as root if needed, with 'su' or 'sudo')" +echo " prefix...............: $prefix" +echo diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in new file mode 100644 index 0000000..43e73c1 --- /dev/null +++ b/doc/Doxyfile.in @@ -0,0 +1,221 @@ +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = Ecore +PROJECT_NUMBER = +OUTPUT_DIRECTORY = . +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 2 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +EXTENSION_MAPPING = +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +TYPEDEF_HIDES_STRUCT = NO +SYMBOL_CACHE_SIZE = 0 +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = NO +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = YES +HIDE_UNDOC_CLASSES = YES +HIDE_FRIEND_COMPOUNDS = YES +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = NO +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = NO +SHOW_DIRECTORIES = NO +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +INPUT = @builddir@/ecore.dox \ + @top_srcdir@/src/lib \ + @srcdir@/examples.dox +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = +RECURSIVE = YES +EXCLUDE = @top_srcdir@/src/lib/ecore_config/* @top_srcdir@/src/lib/ecore_x/xcb/*.c +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = ecore_config* Ecore_Config* +EXCLUDE_SYMBOLS = Ecore_Config* +EXAMPLE_PATH = @top_srcdir@/src/examples/ +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = YES +IMAGE_PATH = @srcdir@/img +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = NO +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 2 +IGNORE_PREFIX = ecore_ _ecore_ Ecore_ _Ecore_ ECORE_ _ECORE_ +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = @srcdir@/head.html +HTML_FOOTER = @srcdir@/foot.html +HTML_STYLESHEET = @srcdir@/e.css +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_TIMESTAMP = YES +HTML_ALIGN_MEMBERS = YES +HTML_DYNAMIC_SECTIONS = NO +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = YES +ENUM_VALUES_PER_LINE = 1 +GENERATE_TREEVIEW = NO +USE_INLINE_TREES = NO +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +FORMULA_FONTSIZE = 10 +FORMULA_TRANSPARENT = YES +SEARCHENGINE = NO +SERVER_BASED_SEARCH = NO +GENERATE_LATEX = YES +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_SOURCE_CODE = NO +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +GENERATE_MAN = YES +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = YES +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +GENERATE_AUTOGEN_DEF = NO +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +SEARCH_INCLUDES = NO +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = __UNUSED__= +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +CLASS_DIAGRAMS = NO +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +DOT_NUM_THREADS = 0 +DOT_FONTNAME = FreeSans.ttf +DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = NO +COLLABORATION_GRAPH = NO +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = NO +INCLUDED_BY_GRAPH = NO +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = NO +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..8bffa14 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,33 @@ +MAINTAINERCLEANFILES = Makefile.in ecore.dox + +.PHONY: doc + +PACKAGE_DOCNAME = $(PACKAGE_TARNAME)-$(PACKAGE_VERSION)-doc + +if EFL_BUILD_DOC + +doc-clean: + rm -rf html/ latex/ man/ xml/ $(top_builddir)/$(PACKAGE_DOCNAME).tar* + +doc: all doc-clean + $(efl_doxygen) + cp $(srcdir)/img/* html/ + cp $(srcdir)/img/* latex/ + rm -rf $(PACKAGE_DOCNAME).tar* + mkdir -p $(PACKAGE_DOCNAME)/doc + cp -R html/ latex/ man/ $(PACKAGE_DOCNAME)/doc + tar cf $(PACKAGE_DOCNAME).tar $(PACKAGE_DOCNAME)/ + bzip2 -9 $(PACKAGE_DOCNAME).tar + rm -rf $(PACKAGE_DOCNAME)/ + mv $(PACKAGE_DOCNAME).tar.bz2 $(top_builddir) + +clean-local: doc-clean + +else + +doc: + @echo "Documentation not built. Run ./configure --help" + +endif + +EXTRA_DIST = Doxyfile.in $(wildcard img/*.*) e.css head.html foot.html ecore.dox.in examples.dox diff --git a/doc/e.css b/doc/e.css new file mode 100644 index 0000000..2dd6b44 --- /dev/null +++ b/doc/e.css @@ -0,0 +1,273 @@ +/* + Author: + Andres Blanc + DaveMDS Andreoli + + Supported Browsers: + ie7, opera9, konqueror4 and firefox3 + + Please use a different file for ie6, ie5, etc. hacks. +*/ + + +/* Necessary to place the footer at the bottom of the page */ +html, body { + height: 100%; + margin: 0px; + padding: 0px; +} + +#container { + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -53px; +} + +#footer, #push { + height: 53px; +} + + +* html #container { + height: 100%; +} + +/* Prevent floating elements overflowing containers */ +.clear { + clear: both; + width: 0px; + height: 0px; +} + +/* Flexible & centered layout from 750 to 960 pixels */ +.layout { + max-width: 960px; + min-width: 760px; + margin-left: auto; + margin-right: auto; +} + +body { + /*font-family: Lucida Grande, Helvetica, sans-serif;*/ + font-family: "Bitstream Vera","Vera","Trebuchet MS",Trebuchet,Tahoma,sans-serif +} + +/* Prevent design overflowing the viewport in small resolutions */ +#container { + padding-right: 17px; + padding-left: 17px; + background-image: url(head_bg.png); + background-repeat: repeat-x; +} + +/****************************/ +/* Top main menu */ +/****************************/ +#header_logo { + background-image : url(logo.png); + width : 61px; +} + +#header_logo a { + position : absolute; + border : 0px; + background-color : transparent; + top : 0px; + width : 60px; + height : 60px; +} + +#header_menu { + background-image : url(header_menu_background.png); + font : normal 10pt verdana,'Bitstream Vera Sans',helvetica,arial,sans-serif; + text-align : right; +} + +#header_last { + background-image : url(header_menu_background_last.png); + width : 15px; +} + +td.nav_passive { + background : url(header_menu_unselected_background.png) 0 0 no-repeat; + height : 63px; + font-family : "Bitstream Vera","Vera","Trebuchet MS",Trebuchet,Tahoma,sans-serif; + font-size : 11px; + padding : 20px 10px 20px 10px; + vertical-align : middle; +} + +td.nav_active { + background : url(header_menu_current_background.png) 0 0 no-repeat; + height : 63px; + color : #646464; + font-family : "Bitstream Vera","Vera","Trebuchet MS",Trebuchet,Tahoma,sans-serif; + font-size : 11px; + font-weight : bold; + padding : 20px 10px 20px 10px; + vertical-align : middle; +} + +#header_menu a { + display : block; + text-decoration : none; + cursor : pointer; + color : #cdcdcd; +} + + + +#header { + width: 100%; + height: 102px; +} + +#header h1 { + width: 63px; + height: 63px; + position: absolute; + margin: 0px; +} + +#header h1 span { + display: none; +} + +#header h2 { + display: none; +} + +/* .menu-container is used to set properties common to .menu and .submenu */ +#header .menu-container { +} + +#header .menu-container ul { + list-style-type: none; + list-style-position: inside; + margin: 0; +} + +#header .menu-container li { + display: block; + float: right; +} + +#header .menu { + height: 63px; + display: block; + background-image: url(menu_bg.png); + background-repeat: repeat-x; +} + +#header .menu ul { + height: 100%; + display: block; + background-image: url(menu_bg_last.png); + background-repeat: no-repeat; + background-position: top right; + padding-right: 17px; +} + +#header .menu li { + height: 100%; + text-align: center; + background-image: url(menu_bg_unsel.png); + background-repeat: no-repeat; +} + +#header .menu a { + height: 100%; + display: block; + color: #cdcdcd; + text-decoration: none; + font-size: 10pt; + line-height: 59px; + text-align: center; + padding: 0px 15px 0px 15px; +} + +#header .menu li:hover { + background-image: url(menu_bg_hover.png); + background-repeat: no-repeat; +} + +#header .menu li:hover a { + color: #FFFFFF; +} + +#header .menu li.current { + background-image: url(menu_bg_current.png); + background-repeat: no-repeat; +} + +#header .menu li.current a { + color: #646464; +} + + +/* Hide all the submenus but the current */ +#header .submenu ul { + display: none; +} + +#header .submenu .current { + display: block; +} + +#header .submenu { + font: bold 10px verdana,'Bitstream Vera Sans',helvetica,arial,sans-serif; + margin-top: 10px; +} + +#header .submenu a { + color: #888888; + text-decoration: none; + font-size: 0.9em; + line-height: 15px; + padding:0px 5px 0px 5px; +} + +#header .submenu a:hover { + color: #444444; +} + +#header .submenu li { + border-left: 1px solid #DDDDDD; +} + +#header .submenu li:last-child { + border-left: 0; +} + +#header .doxytitle { + position: absolute; + font-size: 1.8em; + font-weight: bold; + color: #444444; + line-height: 35px; +} + +#header small { + font-size: 0.4em; +} + +#footer { + background-image: url(foot_bg.png); + width: 100%; +} + +#footer table { + width: 100%; + text-align: center; + white-space: nowrap; + padding: 5px 30px 5px 30px; + font-size: 0.8em; + font-family: "Bitstream Vera","Vera","Trebuchet MS",Trebuchet,Tahoma,sans-serif; + color: #888888; +} + +#footer td.copyright { + width: 100%; +} + diff --git a/doc/ecore.dox.in b/doc/ecore.dox.in new file mode 100644 index 0000000..e69de29 diff --git a/doc/examples.dox b/doc/examples.dox new file mode 100644 index 0000000..cc7ec9d --- /dev/null +++ b/doc/examples.dox @@ -0,0 +1,1692 @@ +/** + * @page Examples Examples + * + * Here is a page with some Ecore examples explained: + * + * @li @ref ecore_time_functions_example_c + * @li @ref ecore_timer_example_c + * @li @ref ecore_idler_example_c + * @li @ref ecore_job_example_c + * @li @ref ecore_event_example_01_c + * @li @ref ecore_event_example_02_c + * @li @ref ecore_fd_handler_example_c + * @li @ref ecore_poller_example_c + * @li @ref ecore_con_lookup_example_c + * @li @ref ecore_con_url_download_example_c + * @li @ref ecore_con_server_simple_example_c + * @li @ref ecore_con_client_simple_example_c + * @li @ref ecore_evas_callbacks_example_c + * @li @ref ecore_evas_object_example_c + * @li @ref ecore_evas_basics_example_c + * @li @ref Ecore_Evas_Window_Sizes_Example_c + * @li @ref Ecore_Evas_Buffer_Example_01_c + * @li @ref Ecore_Evas_Buffer_Example_02_c + * @li @ref Ecore_exe_simple_example_c + * @li @ref ecore_imf_example_c + */ + +/** + * @page ecore_time_functions_example_c ecore_time - Differences between time functions + * + * This example shows the difference between calling ecore_time_get(), + * ecore_loop_time_get() and ecore_time_unix_get(). + * + * It initializes ecore, then sets a timer with a callback that, when called, + * will retrieve the system time using these 3 different functions. After + * displaying the time, it sleeps for 1 second, then call display the time + * again using the 3 functions. + * + * Since everything occurs inside the same main loop iteration, the internal + * ecore time variable will not be updated, and calling ecore_loop_time_get() + * before and after the sleep() call will return the same result. + * + * The two other functions will return a difference of 1 second, as expected. + * But ecore_time_unix_get() returns the number of seconds since 00:00:00 1st + * January 1970, while ecore_time_get() will return the time since a + * unspecified point, but that never goes back in time, even when the timezone + * of the machine changes. + * + * @note The usage of ecore_loop_time_get() should be preferred against the + * two other functions, for most time calculations, since it won't produce a + * system call to get the current time. Use ecore_time_unix_get() when you need + * to know the current time and date, and ecore_time_get() when you need a + * monotonic and more precise time than ecore_loop_time_get(). + * + * @include ecore_time_functions_example.c + */ + +/** + * @page ecore_timer_example_c ecore timers - Scheduled events + * @dontinclude ecore_timer_example.c + * + * This example shows how to setup timer callbacks. It starts a timer that will + * tick (expire) every 1 second, and then setup other timers that will expire + * only once, but each of them will affect the first timer still executing with + * a different API, to demonstrate its usage. To see the full code for this + * example, click @ref ecore_timer_example.c "here". + * + * To demonstrate this, let's define some constants that will determine at which + * time each timer will expire: + * + * @until INTERVAL1 + * + * These constants should tell by themselves what will be the behavior of the + * program, but I'll explain it anyway. The first timer is set to tick every 1 + * second, but all the other timers until the 6th one will be started + * concurrently at the beginning of the program. Each of them will expire at the + * specified time in these constants: + * + * @li The timer2, after 3 seconds of the program being executed, will add a delay + * of 3 seconds to timer1; + * @li The timer3 will pause timer1 at 8.2 seconds; + * @li timer4 will resume timer1 at 11.0 seconds; + * @li timer5 will will change the interval of timer1 to 2 seconds; + * @li timer6 will stop timer1 and start timer7 and timer8, with 1.1 and 1.2 + * seconds of interval, respectively; it also sets the precision to 0.2 seconds; + * @li timer7 and timer8 will just print their expiration time. + * + * @until ecore_time_get + * @until } + * + * As almost all the other examples, we create a context structure to pass to + * our callbacks, so they can have access to the other timers. We also store the + * time of the program start in @c _initial_time, and use the function + * @c _get_current_time to retrieve the current time relative to that time. This + * will help demonstrate what is going on. + * + * Now, the behavior and relationship between the timers that was described + * above is dictated by the following timer callbacks: + * + * @until _timer6_cb + * @until } + * + * It's possible to see the same behavior as other Ecore callbacks here, + * returning @ref ECORE_CALLBACK_RENEW when the timer needs to continue ticking, + * and @ref ECORE_CALLBACK_CANCEL when it needs to stop its execution. Also + * notice that later on our program we are checking for the timers pointers in + * the context to see if they are still executing before deleting them, so we + * need to set these timer pointers to @c NULL when we are returning @ref + * ECORE_CALLBACK_CANCEL. Otherwise the pointer would still be not @c NULL, but + * pointing to something that is invalid, since the timer would have already + * expired without renewing. + * + * Now the main code, which will start the timers: + * + * @until ecore_shutdown + * @until } + * + * This code is very simple. Just after starting the library, it will save the + * current time to @c _initial_time, start all timers from 1 to 6, and begin the + * main loop. Everything should be running right now, displaying the time which + * each timer is expiring, and what it is doing to affect the other timers. + * + * After returning from the main loop, every timer is checked to see if it's + * still alive and, in that case, deleted, before finalizing the library. This + * is not really necessary, since ecore_shutdown() will already delete them for + * you, but it's good practice if you have other things going on after this + * point that could restart the main loop. + * + */ + +/** + * @page ecore_idler_example_c ecore idle state - Idlers, enterers and exiters + * + * This example demonstrates how to manage the idle state of the main loop. Once + * a program knows that the main loop is going to enter in idle state, it could + * start doing some processing until getting out of this state. + * + * To exemplify this, we also add events and a timer to this program, so we can + * see the idle exiter callback being called before processing the event and/or + * timer, the event/timer callback being called (processed), then the idle + * enterer being called before entering in idle state again. Once in idle, the + * main loop keeps calling the idler callback continuously until a new event or + * timer is received. + * + * First, we declare a struct that will be used as context to be passed to + * every callback. It's not useful everywhere, since this example is very + * simple and doesn't do anything other than printing messages, but using this + * context will make it a little bit more real. Our context will be used to + * delete the timer, idler, idle enterer and exiter, and the event handler, and + * also to count how many times the idler was called. + * + * Then we start declaring callbacks for the idle enterer, idle exiter and the + * idler itself. Idle enterer and exiter callbacks just print a message saying + * that they were called, while the idler, in addition to printing a message + * too, also sends an event every 10 times that it is called, incrementing the + * context count variable. This event will be used to make the main loop exit + * the idle state and call the event callback. + * + * These callbacks return @ref ECORE_CALLBACK_RENEW, since we want them to keep + * being called every time the main loop changes to/from idle state. Otherwise, + * if we didn't want them to be called again, they should return @ref + * ECORE_CALLBACK_CANCEL. + * + * The next function declared is the event callback @c _event_handler_cb. It + * will check if the idler was called more than 100 times already @c + * (ctxt->count > 100), and will delete the idler, idle enterer and exiter, the + * timer (if it still exists), and request that the main loop stop running. Then + * it returns @ref ECORE_CALLBACK_DONE to indicate that the event shouldn't be + * handled by any other callback. + * + * Finally, we add a callback to the timer, that will just print a message when + * it is called, and this will happen only once (@ref ECORE_CALLBACK_CANCEL is + * being returned). This timer callback is just here to show that the main loop + * gets out of idle state when processing timers too. + * + * The @b main function is simple, just creates a new type of event that we will + * use to demonstrate the event handling together with the idle state, adds the + * callbacks that we declared so far, fill the context struct, and starts + * running the main loop. + * + * @note We use timer and event callbacks to demonstrate the idle state + * changing, but it also happens for file descriptor handlers, pipe handlers, + * etc. + * + * @include ecore_idler_example.c + */ + +/** + * @page ecore_job_example_c ecore_job - Queuing tasks + * + * This example shows how an @ref Ecore_Job can be added, how it can be + * deleted, and that they always execute in the added order. + * + * First, 2 callback functions are declared, one that prints strings passed to + * it in the @c data pointer, and another one that quits the main loop. In the + * @c main function, 3 jobs are added using the first callback, and another one + * is added using the second one. + * + * Then the second added job is deleted just to demonstrate the usage of + * ecore_job_del(), and the main loop is finally started. Run this example to + * see that @c job1, @c job3 and @c job_quit are ran, in this order. + * + * @include ecore_job_example.c + */ + +/** + * @page ecore_event_example_01_c Handling events example + * This example shows the simplest possible way to register a handler for an + * ecore event, this way we can focus on the important aspects. The example will + * start the main loop and quit it when it receives the ECORE_EVENT_SIGNAL_EXIT + * event. This event is triggered by a SIGTERM(pressing ctrl+c). + * + * So let's start with the function we want called when we receive the event, + * instead of just stopping the main loop we'll also print a message, that's + * just so it's clear that it got called: + * @dontinclude ecore_event_example_01.c + * @skip static + * @until } + * @note We return ECORE_CALLBACK_DONE because we don't want any other handlers + * for this event to be called, the program is quitting after all. + * + * We then have our main function and the obligatory initialization of ecore: + * @until ecore_init + * + * We then get to the one line of our example that makes everything work, the + * registering of the callback: + * @until handler_add + * @note The @c NULL there is because there is no need to pass data to the + * callback. + * + * And the all that is left to do is start the main loop: + * @until } + * + * Full source code for this example: @ref ecore_event_example_01.c. + */ + +/** + * @page ecore_event_example_02_c ecore events and handlers - Setup and use + * This example shows how to create a new type of event, setup some event + * handlers to it, fire the event and have the callbacks called. After + * finishing, we delete the event handlers so no memory will leak. + * + * See the full source code for this example @ref ecore_event_example_02.c + * "here". + * + * Let's start the example from the beginning: + * + * @dontinclude ecore_event_example_02.c + * @until _event_type + * + * First thing is to declare a struct that will be passed as context to the + * event handlers. In this structure we will store the event handler pointers, + * and two strings that will be used by the first event handler. We also will + * use a global integer to store the event type used for our event. It is + * initialized with 0 in the beginning because the event wasn't created yet. + * Later, in the main function we will use ecore_event_type_new() to associate + * another value to it. Now the event handler callbacks: + * + * @until } + * + * This is the first event handler callback. It prints the event data received + * by the event, and the data passed to this handler when it was added. Notice + * that this callback already knows that the event data is an integer pointer, + * and that the handler data is a string. It knows about the first one because + * this is based on the type of event that is going to be handled, and the + * second because it was passed to the ecore_event_handler_add() function when + * registering the event handler. + * + * Another interesting point about this callback is that it returns @ref + * ECORE_CALLBACK_DONE (0) if the event data is even, swallowing the event and + * don't allowing any other callback to be called after this one for this event. + * Otherwise it returns @ref ECORE_CALLBACK_PASS_ON, allowing the event to be + * handled by other event handlers registered for this event. This makes the + * second event handler be called just for "odd" events. + * + * @until ECORE_CALLBACK_DONE + * @until } + * + * The second event handler will check if the event data is equal to 5, and if + * that's the case, it will change the event handler data of the first event + * handler to another string. Then it checks if the event data is higher than + * 10, and if so, it will request the main loop to quit. + * + * An interesting point of this example is that although the second event + * handler requests the main loop to finish after the 11th event being received, + * it will process all the events that were already fired, and call their + * respective event handlers, before the main loop stops. If we didn't want + * these event handlers to be called after the 11th event, we would need to + * unregister them with ecore_event_handler_del() at this point. + * + * Now some basic initialization of the context, and the Ecore library itself: + * + * @until type_new + * + * This last line is interesting. It creates a new type of event and returns a + * unique ID for this event inside Ecore. This ID can be used anywhere else in + * your program to reference this specific type of event, and to add callbacks + * to it. + * + * It's common if you are implementing a library that declares new types of + * events to export their respective types as extern in the header files. This + * way, when the library is initialized and the new type is created, it will be + * available through the header file to an application using it add some + * callbacks to it. Since our example is self-contained, we are just putting it + * as a global variable. + * + * Now we add some callbacks: + * + * @until ctxt); + * + * This is very simple. Just need to call ecore_event_handler_add() with the + * respective event type, the callback function to be called, and a data pointer + * that will be passed to the callback when it is called by the event. + * + * Then we start firing events: + * + * @until } + * + * This @c for will fire 16 events of this type. Notice that the events will be + * fired consecutively, but any callback will be called yet. They are just + * called by the main loop, and since it wasn't even started, nothing happens + * yet. For each event fired, we allocate an integer that will hold the number + * of the event (we are arbitrarily creating these numbers just for + * demonstration purposes). It's up to the event creator to decide which type of + * information it wants to give to the event handler, and the event handler must + * know what is the event info structure for that type of event. + * + * Since we are not allocating any complex structure, just a simple integer, we + * don't need to pass any special free function to ecore_event_add(), and it + * will use a simple @c free on our data. That's the default behavior. + * + * Now finishing our example: + * + * @until } + * + * We just start the main loop and watch things happen, waiting to shutdown + * Ecore when the main loop exits and return. + */ + +/** + * @page ecore_fd_handler_example_c ecore fd handlers - Monitoring file descriptors + * @dontinclude ecore_fd_handler_example.c + * + * This is a very simple example where we will start monitoring the stdin of the + * program and, whenever there's something to be read, we call our callback that + * will read it. + * + * Check the full code for this example @ref ecore_fd_handler_example.c "here". + * + * This seems to be stupid, since a similar result could be achieved by the + * following code: + * + * @code + * while (nbytes = read(STDIN_FILENO, buf, sizeof(buf))) + * { + * buf[nbytes - 1] = '\0'; + * printf("Read %zd bytes from input: \"%s\"\n", nbytes - 1, buf); + * } + * @endcode + * + * However, the above code is blocking, and won't allow you to do anything else + * other than reading the input. Of course there are other methods to do a + * non-blocking reading, like setting the file descriptor to non-blocking and + * keep looping always checking if there's something to be read, and do other + * things otherwise. Or use a @c select call to watch for more than one file + * descriptor at the same time. + * + * The advantage of using an @ref Ecore_Fd_Handler is that you can monitor a + * file descriptor, while still iterating on the Ecore main loop. It will allow + * you to have timers working and expiring, events still being processed when + * received, idlers doing its work when there's nothing happening, and whenever + * there's something to be read from the file descriptor, your callback will be + * called. And it's everything monitored in the same main loop, no threads are + * needed, thus reducing the complexity of the program and any overhead caused + * by the use of threads. + * + * Now let's start our program. First we just declare a context structure that + * will be passed to our callback, with pointers to our handler and to a timer + * that will be used later: + * + * @until }; + * + * Then we will declare a prepare_callback that is called before any fd_handler + * set in the program, and before the main loop select function is called. Just + * use one if you really know that you need it. We are just putting it here to + * exemplify its usage: + * + * @until } + * + * Now, our fd handler. In its arguments, the @c data pointer will have any data + * passed to it when it was registered, and the @c handler pointer will contain + * the fd handler returned by the ecore_main_fd_handler_add() call. It can be + * used, for example, to retrieve which file descriptor triggered this callback, + * since it could be added to more than one file descriptor, or to check what + * type of activity there's in the file descriptor. + * + * The code is very simple: we first check if the type of activity was an error. + * It probably won't happen with the default input, but could be the case of a + * network socket detecting a disconnection. Next, we get the file descriptor + * from this handler (as said before, the callback could be added to more than + * one file descriptor), and read it since we know that it shouldn't block, + * because our fd handler told us that there's some activity on it. If the + * result of the read was 0 bytes, we know that it's an end of file (EOF), so we + * can finish reading the input. Otherwise we just print the content read from + * it: + * + * @until } + * + * Also notice that this callback returns @ref ECORE_CALLBACK_RENEW to keep + * being called, as almost all other Ecore callbacks, otherwise if it returns + * @ref ECORE_CALLBACK_CANCEL then the file handler would be deleted. + * + * Just to demonstrate that our program isn't blocking in the input read but + * still can process other Ecore events, we are going to setup an @ref + * Ecore_Timer. This is its callback: + * + * @until } + * + * Now in the main code we are going to initialize the library, and setup + * callbacks for the file descriptor, the prepare callback, and the timer: + * + * @until timer_add + * + * Notice that the use of ecore_main_fd_handler_add() specifies what kind of + * activity we are monitoring. In this case, we want to monitor for read (since + * it's the standard input) and for errors. This is done by the flags @ref + * ECORE_FD_READ and @ref ECORE_FD_ERROR. For the three callbacks we are also + * giving a pointer to our context structure, which has pointers to the handlers + * added. + * + * Then we can start the main loop and see everything happening: + * + * @until } + * + * In the end we are just deleting the fd handler and the timer to demonstrate + * the API usage, since Ecore would already do it for us on its shutdown. + */ + +/** + * @page ecore_poller_example_c ecore poller - Repetitive polling tasks + * @dontinclude ecore_poller_example.c + * + * This example show how to setup, and explains how an @ref Ecore_Poller is + * called. You can @ref ecore_poller_example.c "see the full source code here". + * + * In this example we store the initial time of the program just to use as + * comparison to the time when the poller callbacks are called. It will be + * stored in @c _initial_time : + * + * @until initial_time + * + * Then next step is to define the poller callback. This callback assumes that a + * @c data pointer is passed to it on creation, and is a string just used to + * identify the poller. The callback prints this string and the time since the + * program started, and returns @ref ECORE_CALLBACK_RENEW to keep being called. + * + * @until } + * + * Now in the main function we initialize Ecore, and save the initial time of + * the program, so we can compare it later with the time that the pollers are + * being called: + * + * @until initial_time + * + * Then we change the poll interval to 0.3 seconds (the default is 0.125 + * seconds) just to show the API usage. + * + * Finally, we create two pollers, one that will be called every 4 ticks, and + * another one that will be called every 8 ticks. This means the the first + * poller interval will be around 1.2 seconds, and the second one will be + * around 2.4 seconds. But the most important point is: since the second poller + * interval is a multiple of the first one, they will be always synchronized. + * Ecore calls pollers that are in the "same tick" together. It doesn't go back + * to the main loop and check if there's another poller to execute at this + * time, but instead it calls all the pollers registered to this "tick" at the + * same time. See the description of ecore_poller_add() for more details. This + * is easy to see in the time printed by both of them. + * + * If instead of two synchronized pollers, we were using two different timers, + * one with interval of 1.2 seconds and another one with an interval of 2.4 + * seconds, there would be no guarantee that they would be totally in sync. Some + * delay in the execution of another task, or even in the task called in the + * callback, could make them get out of sync, forcing Ecore's main loop to wake + * up more than necessary. + * + * Well, this is the code that create these two pollers and set the poll + * interval, then starts the main loop: + * + * @until ecore_main_loop_begin + * + * If you hit CTRL-C during the execution of the program, the main loop will + * quit, since there are some signal handlers already set by default to do this. + * So after the main loop begin call, we change the second poller's interval to + * 16 ticks, so it will happen each 4.8 seconds (or each 4 times that the first + * poller is called). + * + * This means: the program is started, the first poller is called each 4 ticks + * and the second is called each 8 ticks. After CTRL-C is used, the second + * poller will be called each 16 ticks. + * + * @until } + * + * The rest of the program is just deleting the pollers and shutting down the + * library. + */ + +/** + * @page ecore_con_lookup_example_c Ecore_Con - DNS lookup + * + * This is a very simple example that shows how to make a simple DNS lookup + * using ecore_con_lookup(). + * + * It's possible to see in the beginning of the main function that we are using + * the arguments passed via command line. This is the address that we are going + * to make the DNS lookup on. + * + * The next step is to initialize the libraries, and just call + * ecore_con_lookup(). This function will get the string that contains the + * address to be resolved as first parameter, then a callback that will be + * called when the resolve stage is done, and finally a data pointer that will + * be passed to the callback. + * + * This function is asynchronous, and the callback will be called only on + * success. If there was an error during the resolve stage, there's no way to + * know about that. It's only possible to know about errors when setting up the + * lookup, by looking at the return code of the ecore_con_lookup() function. + * + * The callback @c _lookup_done_cb passed as argument to ecore_con_lookup() just + * prints the resolved canonical name, IP, address of the sockaddr structure, + * and the length of the socket address (in bytes). + * + * Finally, we start the main loop, and after that we finalize the libraries and + * exit. + * + * This is the code for this simple example: + * + * @include ecore_con_lookup_example.c + */ + +/** + * @page ecore_con_url_download_example_c Ecore_Con_Url - downloading a file + * + * This is a simple example that shows how to download a file using @ref + * Ecore_Con_Url. The full source code for this example can be found at @ref + * ecore_con_url_download_example.c. + * + * First we are setting some callbacks for events that will be sent when data + * arrives in our connection (the data is the content of the file being + * downloaded), and when the download is completed. The @c _url_progress_cb and + * @c _url_complete_cb are these callbacks: + * + * @dontinclude ecore_con_url_download_example.c + * @skip struct + * @until main_loop_quit + * @until } + * + * Notice that we also declared a struct that will hold how many bytes were + * downloaded through this object. It will be set in the @c main function using + * ecore_con_url_data_set(). + * + * In the next step, on the @c main function, we open a file where we are going + * to save the content being downloaded: + * + * @until open( + * @until } + * + * With the file successfully open, let's create our @ref Ecore_Con_Url object. + * For this, we initialize the libraries and create the object: + * + * @until } + * + * Then we allocate and set the data struct to the connection object, and set a + * file descriptor from our previously open file to it. We also add the event + * handlers (callbacks) to the events that will be emitted on data being + * received and download complete: + * + * @until complete_cb + * + * Finally we start our request, and run the main loop: + * + * @until return 0 + * @until } + * + * The rest of this code was just freeing resources, with some labels to be used + * for error handling. + */ + +/** + * @page ecore_con_url_cookies_example_c Ecore_Con_Url - Managing cookies + * + * This example shows how to use an @ref Ecore_Con_Url and enable it to + * receive/send cookies. These cookies can be set by the server, saved to a + * file, loaded later from this file and sent again to the server. The complete + * example can be found at @ref ecore_con_url_cookies_example.c + * "ecore_con_url_cookies_example.c" + * + * First we are setting some callbacks for events that will be sent when data + * arrives in our connection (the data is the content of the file being + * downloaded), and when the download is completed. The @c _url_data_cb and + * @c _url_complete_cb are these callbacks: + * + * @dontinclude ecore_con_url_download_example.c + * @skip Eina_Bool + * @until main_loop_quit + * @until } + * + * In the @c main function we parse some parameter from the command line. These + * parameters are the url that we are connecting to, and cookie use policy. + * + * After that we initialize the libraries and create a handler to our request + * using the given url: + * + * @until goto end + * @until } + * + * We also set the event handlers for this request and add a header to it, that + * will inform our custom user agent: + * + * @until User-Agent + * + * Now we start playing with cookies. First, let's call + * ecore_con_url_cookies_init() to inform that we want cookies enabled. We also + * set a file from which we are loading previously set (old) cookies, in case + * that we don't want to clear old cookies or old session cookies. + * + * After that we set the file where we are going to save all valid cookies in + * the @ref Ecore_Con_Url object. This includes previously loaded cookies (that + * weren't cleared) and new cookies set by the response header "Set-Cookie" that + * comes with the response to our request: + * + * @until jar_file_set + * + * And finally, before performing the request, we check the command passed as + * argument in the command line and use it to choose between clearing old + * cookies, clearing just old session cookies, or ignoring old session cookies. + * + * After that we just finish our code as expected: + * + * @until return + * @until } + * + * Notice that in this code, if we want to clear old cookies, we also don't load + * them from the file. This is a bit confusing and the API isn't clear, but + * ecore_con_url_cookies_file_add() will load cookies from the specified files + * just when the operation is really performed (i.e. ecore_con_url_get() is + * called). So if ecore_con_url_cookies_clear() is called before + * ecore_con_url_get(), the old cookies may not have been loaded yet, so they + * are not cleared. To avoid having old cookies loaded, don't add any cookie + * file with ecore_con_url_cookies_file_add(). + * + * The function ecore_con_url_cookies_clear() is just useful to clear cookies + * that are already loaded/valid in the @ref Ecore_Con_Url object (from a + * previous request, for example). + */ + +/** + * @page ecore_con_url_headers_example_c Ecore_Con_Url - customizing a request + * + * This is a simple example that shows how to make a custom request using @ref + * Ecore_Con_Url. The full source code for this example can be found at @ref + * ecore_con_url_headers_example.c. + * + * The first part of the example is setting the callbacks to be called when an + * #ECORE_CON_EVENT_URL_DATA or #ECORE_CON_EVENT_URL_COMPLETE event is received. + * These are the callbacks that are going to be used with this: + * + * @dontinclude ecore_con_url_headers_example.c + * @skip static + * @until main_loop_quit + * @until } + * + * The @c main code is as simple as the @ref Ecore_Con_Url example. It contains + * some checks for the arguments to see if a GET or POST request is required: + * + * @until GET + * @until } + * + * Then we start our required libraries and configure a global option to use + * pipelined requests: + * + * @until pipeline_set + * + * Now we create our request object, but using ecore_con_url_custom_new() to use + * a POST or GET method depending on the command line arguments. And we also add + * the event handlers for our callbacks: + * + * @until complete_cb + * + * In order to demonstrate our API, some options are set to this request before + * actually performing it: + * + * @until url_time + * + * Depending on what kind of request was asked (GET or POST), we use one of the + * specific functions to perform it: + * + * @until url_post + * + * After that, we just check for errors, start the main loop, free resources and + * finally exit: + * + * @until return + * @until } + */ + +/** + * @page ecore_con_server_simple_example_c Ecore_Con - Creating a server + * + * In this example we are going to create a server that listens for connections + * from clients through a TCP port. You can get the full source code at @ref + * ecore_con_server_simple_example.c. + * + * We begin our example in the main function, to demonstrate how to setup + * things, and then go to the callbacks that are needed for it to run properly. + * + * In the @c main function, after initializing the libraries, we use + * ecore_con_server_add() to startup the server. Look at the reference + * documentation of this function: it supports many types of server, and we are + * going to use #ECORE_CON_REMOTE_TCP (a TCP based server). Other arguments to + * this function are the address where we are listening on, the port, and a data + * pointer that will associate that data with the server: + * + * @dontinclude ecore_con_server_simple_example.c + * @skip main(void) + * @until exit + * + * Notice that we are listening only on 127.0.0.1, which is the internal + * loopback interface. If the server needs to listening on all of its ips, use + * 0.0.0.0 instead. + * + * We also need to set event handlers to be called when we receive any data from + * the clients, when a new client connects to our server, or when a client + * disconnects. These callbacks are: + * + * @until CLIENT_DATA + * + * More details about what these callbacks do will be given later. + * + * Now, before running the main loop, we also want to set some limits to our + * server. To avoid it to be overloaded with too many connections to handle, we + * are going to set a maximum of 3 clients connected at the same time. This + * number is used just to demonstrate the API. A good number to be used here + * would need to be determined by tests done on the server, to check the load + * supported by it. + * + * Any other client trying to connect to this server, after the limit is + * reached, will wait until one of the connected clients disconnect and the + * server accepts the new connection. + * + * Another important thing to do is setting a timeout, to avoid that a client + * hold a connection for too long without doing anything. This timeout will + * disconnect the idle client, allowing that other clients that may be waiting + * to connect finally can do it. + * + * Then we just start the main loop: + * + * @until main_loop_begin + * + * After exiting the main loop, we print the list of connected clients, and also + * free the data associated with each respective client. This data was + * previously associated using ecore_con_client_data_set(): + * + * @until } + * + * Then before exiting we show the total uptime of the server: + * + * @until uptime + * + * Now let's go back to the used callbacks. + * + * The first callback, @c _add, is registered to the event + * #ECORE_CON_EVENT_CLIENT_ADD, which will be called whenever a client connects + * to the server. + * + * This callback will associate a data structure to this client, that will be + * used to count how many bytes were received from it. It also prints some info + * about the client, and send a welcome string to it. ecore_con_client_flush() + * is used to ensure that the string is sent immediately, instead of being + * buffered. + * + * A timeout for idle specific for this client is also set, to demonstrate that + * it is independent of the general timeout of the server. + * + * Before exiting, the callback will display a list of all clients still + * connected to this server. The code for this callback follows: + * + * @dontinclude ecore_con_server_simple_example.c + * @skip Eina_Bool + * @until CALLBACK_RENEW + * @until } + * + * The second callback is @c _del. It is associated with + * #ECORE_CON_EVENT_CLIENT_DEL, and is called whenever a client disconnects from + * this server. + * + * It will just print some information about the client, free the associated + * data structure, and call ecore_con_client_del() on it before exiting the + * callback. Here's its code: + * + * @until CALLBACK_RENEW + * @until } + * + * The last callback will print any data received by this server from its + * clients. It also increments the "bytes received" counter, sdata, in the + * data structure associated with this client. The callback code follows: + * + * @until CALLBACK_RENEW + * @until } + * + * The important parts of this example were described above. If you need to see + * the full source code for it, there's a link to the code in the beginning of + * this page. + * + * This example will start a server and start accepting connections from clients, as + * demonstrated in the following diagram: + * @htmlonly + * + * Full size + * @endhtmlonly + * + * @image rtf ecore_con-client-server-example.png + * @image latex ecore_con-client-server-example.eps width=\textwidth + * + * @note This example contains a serious security flaw: it doesn't check for the + * size of data being received, thus allowing to the string to be exploited in + * some way. However, it is left like this to make the code simpler and just + * demonstrate the API usage. + */ + +/** + * @page ecore_con_client_simple_example_c Ecore_Con - Creating a client + * + * Following the same idea as the @ref ecore_con_server_simple_example_c , this + * example will demonstrate how to create a client that connects to a specified + * server through a TCP port. You can see the full source code at @ref + * ecore_con_client_simple_example.c. + * + * Starting from the @c main function, after reading the command line argument + * list and initializing the libraries, we try to connect to the server: + * + * @dontinclude ecore_con_client_simple_example.c + * @skip main( + * @until exit(2) + * @until } + * + * After doing this, everything else in @c main is setting up callbacks for the + * client events, starting the main loop and shutting down the libraries after + * it. + * + * Now let's go to the callbacks. These callbacks are very similar to the server + * callbacks (our implementation for this example is very simple). On the + * @c _add callback, we just set a data structure to the server, print some + * information about the server, and send a welcome message to it: + * + * @dontinclude ecore_con_client_simple_example.c + * @skip Eina_Bool + * @until CALLBACK_RENEW + * @until } + * + * The @c _del callback is as simple as the previous one. We free the data + * associated with the server, print the uptime of this client, and quit the + * main loop (since there's nothing to do once we disconnect): + * + * @until CALLBACK_RENEW + * @until } + * + * The @c _data callback is also similar to the server data callback. it will + * print any received data, and increase the data counter in the structure + * associated with this server: + * + * @skip Eina_Bool + * @until CALLBACK_RENEW + * @until } + * + * You can see the server counterpart functions of the ones used in this example + * in the @ref ecore_con_server_simple_example_c. + * + * This example will connect to the server and start comunicating with it, as + * demonstrated in the following diagram: + * @htmlonly + * + * Full size + * @endhtmlonly + * + * @image rtf ecore_con-client-server-example2.png + * @image latex ecore_con-client-server-example2.eps width=\textwidth + * + * @note This example contains a serious security flaw: it doesn't check for the + * size of data being received, thus allowing to the string to be exploited in + * some way. However, it is left like this to make the code simpler and just + * demonstrate the API usage. + */ + +/** + * @example ecore_idler_example.c + * This example shows when @ref Ecore_Idler, @ref Ecore_Idle_Enterer and @ref + * Ecore_Idle_Exiter are called. See + * @ref ecore_idler_example_c "the explanation here". + */ + +/** + * @example ecore_job_example.c + * This example shows how to use an @ref Ecore_Job. See + * @ref ecore_job_example_c "the explanation here". + */ + +/** + * @example ecore_time_functions_example.c + * Shows the difference between the three time functions. See @ref + * ecore_time_functions_example_c "the example explained". + */ + +/** + * @example ecore_timer_example.c + * This example show how to use timers to have timed events inside ecore. + * See @ref ecore_timer_example_c "the example explained". + */ + +/** + * @example ecore_exe_example_child.c + * This is a child process used to receive messages and send it back + * to its father. + * Check the @ref Ecore_exe_simple_example_c "Full tutorial" + */ + +/** + * @example ecore_exe_example.c + * This is a process that will send messages to a child and it will stop + * when it receives "quit". + * Check the @ref Ecore_exe_simple_example_c "Full tutorial" + */ + +/** + * @example ecore_fd_handler_example.c + * This example shows how to setup and use an fd_handler. See + * @ref ecore_fd_handler_example_c "the explanation here". + */ + +/** + * @example ecore_poller_example.c + * This example shows how to setup and use a poller. See + * @ref ecore_poller_example_c "the explanation here". + */ + +/** + * @example ecore_event_example_01.c + * This example shows how to create an event handler. Explanation: @ref + * ecore_event_example_01_c + */ + +/** + * @example ecore_event_example_02.c + * This example shows how to setup, change, and delete event handlers. See + * @ref ecore_event_example_02_c "the explanation here". + */ + +/** + * @example ecore_fd_handler_gnutls_example.c + * Shows how to use fd handlers. + */ + +/** + * @example ecore_con_lookup_example.c + * Shows how to make a simple DNS lookup. See the complete example description + * at @ref ecore_con_lookup_example_c + */ + +/** + * @example ecore_con_url_download_example.c + * Shows how to download a file using an @ref Ecore_Con_Url object. See the + * complete example description at @ref ecore_con_url_download_example_c + */ + +/** + * @example ecore_con_url_cookies_example.c + * Shows how to manage cookies on a @ref Ecore_Con_Url object. See the complete + * example description at @ref ecore_con_url_cookies_example_c. + */ + +/** + * @example ecore_con_server_simple_example.c + * Shows how to setup a simple server that accepts client connections and sends + * a "hello" string to them. See the complete example description at @ref + * ecore_con_server_simple_example_c + */ + +/** + * @example ecore_con_client_simple_example.c + * Shows how to setup a simple client that connects to a server and sends a + * "hello" string to it. See the complete example description at @ref + * ecore_con_client_simple_example_c + */ + +/** + * @example ecore_con_url_headers_example.c + * Shows how to make GET or POST requests using an @ref Ecore_Con_Url object, + * and make use of most of its API. See the complete example description at + * @ref ecore_con_url_headers_example_c + */ + +/** + * @page tutorial_ecore_pipe_gstreamer_example + * + * Here is an example that uses the pipe wrapper with a Gstreamer + * pipeline. For each decoded frame in the Gstreamer thread, a handle + * is called in the ecore thread. + * + * @include ecore_pipe_gstreamer_example.c + * @example ecore_pipe_gstreamer_example.c + */ + +/** + * @page tutorial_ecore_pipe_simple_example + * @dontinclude ecore_pipe_simple_example.c + * + * This example shows some simple usage of ecore_pipe. We are going to create a + * pipe, fork our process, and then the child is going to communicate to the + * parent the result of its processing through the pipe. + * + * As always we start with our includes, nothing special: + * @skip #include + * @until Ecore.h + * + * The first thing we are going to define in our example is the function we are + * going to run on the child process, which, as mentioned, will do some + * processing and then will write the result to the pipe: + * @until } + * @until } + * @note The sleep was added so the parent process would think the child process + * was doing something interesting... + * + * Next up is our function for handling data arriving in the pipe. It copies the + * data to another buffer, adds a terminating NULL and prints it. Also if it + * receives a certain string it stops the main loop(effectively ending the + * program): + * @until } + * @until } + * + * And now on to our main function, we start by declaring some variables and + * initializing ecore: + * @until ecore_init + * + * And since we are talking about pipes let's create one: + * @until pipe_add + * + * Now we are going to fork: + * @until fork + * @note duh... + * + * The child process is going to do the our fancy processing: + * @until } + * @note It's very important to call ecore_pipe_read_close() here so that the + * child process won't read what it is writing to the pipe itself. + * + * And the parent is going to run ecore's main loop waiting for some data: + * @until } + * @note Calling ecore_pipe_write_close() here isn't important but since we + * aren't going to write in the pipe it is good practice. + * + * And finally when done processing(the child) or done receiving(the parent) we + * delete the pipe and shutdown ecore: + * @until } + * + * @example ecore_pipe_simple_example.c + */ + +/** + * @page tutorial_ecore_animator Ecore animator example + * @dontinclude ecore_animator_example.c + * + * For this example we are going to animate a rectangle growing, moving and + * changing color, and then move it back to it's initial state with a + * different animation. We are also going to have a second rectangle moving + * along the bottom of the screen. To do this we are going to use ecore_evas, + * but since that is not the focus here we won't going into detail about it. + * + * @skip #include + * @until evas_object_show + * @until evas_object_show + * All of this is just setup, not what we're interested in right now. + * + * Now we are going to set the frametime for our animation to one fiftieth of + * a second, this will make our program consume more resources but should make + * our animation extra smooth: + * @until frametime + * + * And now we get right to the business of creating our ecore_animator: + * @until timeline + * @note We are telling our animation to last 10 second and to call + * _advance_frame with rect as data. + * + * So far we setup the first and second animations, the third one however is a + * bit different, this time we won't use a timeline animation, that's because we + * don't want our animation to stop: + * @until animator_add + * + * Next we set a few timers to execute _start_second_anim, _freeze_third_anim + * and _thaw_thir_anim in 10, 5 and 10 seconds respectively: + * @until thaw + * + * And now we tell ecore to begin the main loop and free some resources once + * it leaves the main loop: + * @until } + * + * Here we have the callback function for our first animation, which first + * takes @p pos(where in the timeline we are), maps it to a SPRING curve that + * which will wobble 15 times and will decay by a factor of 1.2: + * @until pos_map + * + * Now that we have the frame we can adjust the rectangle to its appropriate + * state: + * @until } + * + * And now the callback that will run 10 seconds after the program starts(5 + * seconds after the first animation finishes) and starts our second + * animation: + * @until } + * @note For this animation we made the frametime much larger which means our + * animation might get "jerky". + * + * The callback for our second animation, our savvy reader no doubt noted that + * it's very similar to the callback for the first animation. What we change for + * this one is the type of animation to BOUNCE and the number of times it will + * bounce to 50: + * @until } + * + * And for our last animation callback something simpler, we just move our + * rectangle right by one pixel until it reaches the end of the screen and then + * start at the beginning again: + * @until } + * + * Our next two functions respectively freezes and thaw our third animation, so + * that it won't happen for the 5 seconds after the first animation ends and the + * second animation begins: + * @until } + * @until } + * + * @example ecore_animator_example.c + */ + +/** + * @page ecore_thread_example_c Ecore_Thread - API overview + * + * Working with threads is hard. Ecore helps to do so a bit easier, but as + * the example in @ref ecore_thread_example.c "ecore_thread_example.c" shows, + * there's a lot to consider even when doing the most simple things. + * + * We'll be going through this thorough example now, showing how the differents + * aspects of @ref Ecore_Thread are used, but users are encourage to avoid + * threads unless it's really the only option, as they always add more + * complexity than the program usually requires. + * + * Ecore Threads come in two flavors, short jobs and feedback jobs. Short jobs + * just run the given function and are more commonly used for small tasks + * where the main loop does not need to know how the work is going in between. + * The short job in our example is so short we had to artificially enlarge it + * with @c sleep(). Other than that, it also uses threads local data to keep + * the data we are working with persistent across different jobs ran by the + * same system thread. This data will be freed when the no more jobs are + * pending and the thread is terminated. If the data doesn't exist in the + * thread's storage, we create it and save it there for future jobs to find + * it. If creation fails, we cancel ourselves, so the main loop knows that + * we didn't just exit normally, meaning the job could not be done. The main + * part of the function checks in each iteration if it was canceled by the + * main loop, and if it was, it stops processing and clears the data from the + * storage (we assume @c cancel means no one else will need this, but this is + * really application dependent). + * @dontinclude ecore_thread_example.c + * @skip static void + * @until sleep(1) + * @until } + * @until } + * + * Feedback jobs, on the other hand, run tasks that will inform back to the + * main loop its progress, send partial data as is processed, just ping saying + * it's still alive and processing, or anything that needs the thread to talk + * back to the main loop. + * @skip static void + * @until the_end + * @until } + * + * Finally, one more feedback job, but this one will be running outside of + * Ecore's pool, so we can use the pool for real work and keep this very + * light function unchecked. All it does is check if some condition is met + * and send a message to the main loop telling it it's time to close. + * @skip static void + * @until } + * @until } + * @until } + * + * Every now and then the program prints its status, counting threads running + * and pending jobs. + * @skip static void + * @until } + * + * In our main loop, we'll be receiving messages from our feedback jobs using + * the same callback for both of them. + * @skip static void + * @until char *str + * + * The light job running out of the pool will let us know when we can exit our + * program. + * @until } + * + * Next comes the handling of data sent from the actual worker threads, always + * remembering that the data belongs to us now, and not the thread, so it's + * our responsibility to free it. + * @until } + * @until } + * + * Last, the condition to exit is given by how many messages we want to handle, + * so we need to count them and inform the condition checking thread that the + * value changed. + * @until } + * + * When a thread finishes its job or gets canceled, the main loop is notified + * through the callbacks set when creating the task. In this case, we just + * print what happen and keep track of one of them used to exemplify canceling. + * Here we are pretending one of our short jobs has a timeout, so if it doesn't + * finish before a timer is triggered, it will be canceled. + * @skip static void + * @until _cancel_timer_cb + * @until } + * + * The main function does some setup that includes reading parameters from + * the command line to change its behaviour and test different results. + * These are: + * @li -t \ maximum number of threads to run at the same time. + * @li -p \ adds @c some_path to the list used by the feedback jobs. + * This parameter can be used multiple times. + * @li -m \ the number of messages to process before the program is + * signalled to exit. + * + * Skipping some bits, we init Ecore and our application data. + * @skip ecore_init + * @until appdata.max_msgs + * + * If any paths for the feedback jobs were given, we use them, otherwise we + * fallback to some defaults. Always initializing the proper mutexes used by the + * threaded job. + * @skip path_list + * @until EINA_LIST_FREE + * @until } + * @until } + * + * Initialize the mutex needed for the condition checking thread + * @skip appdata.mutex + * @until appdata.condition + * + * And start our tasks. + * @until appdata.thread_3 + * @until EINA_FALSE + * + * To finalize, set a timer to cancel one of the tasks if it doesn't end + * before the timeout, one more timer for status report and get into the main + * loop. Once we are out, destroy our mutexes and finish the program. + * @until _status_timer_cb + * @until } + * + * @example ecore_thread_example.c + */ + +/** + * @page ecore_evas_callbacks_example_c Ecore Evas Callbacks + * @dontinclude ecore_evas_callbacks.c + * + * Our example is remarkably simple, all it does is create an Ecore_Evas and + * register a callback for a bunch of events. What's interesting here is + * knowing when each of these callbacks will be called, however since that + * depends on the underlying windowing system there are no guarantees that all + * of the callbacks will be called for your windowing system. To know which + * callbacks will be called for your windowing system run the example and + * redirect the output to a file, and take a look at it. + * + * @note Make sure you minimize, resize, give and remove focus to see more + * callbacks called. + * + * The example is constituted of two main parts, first is the implementation of + * callbacks that will be called for each event(all our callbacks do is print + * their own name) and the second is the main function where we register the + * event callbacks and run the main loop: + * @include ecore_evas_callbacks.c + * @example ecore_evas_callbacks.c + */ + +/** + * @page Ecore_Evas_Window_Sizes_Example_c Ecore_Evas window size hints + * + * On this example, we show you how to deal with @c Ecore_Evas window + * size hints, which are implemented per Evas engine. + * + * We start by defining an initial size for our window and, after + * creating it, adding a background white rectangle and a text object + * to it, to be used to display the current window's sizes, at any + * given time: + * @dontinclude ecore_evas_window_sizes_example.c + * @skip define WIDTH + * @until define + * @until define + * @dontinclude ecore_evas_window_sizes_example.c + * @skip evas_init + * @until show(bg) + * @dontinclude ecore_evas_window_sizes_example.c + * @skip text = + * @until main_loop_begin + * @dontinclude ecore_evas_window_sizes_example.c + * @skip to inform + * @until } + * + * The program has a command line interface, responding to the + * following keys: + * @dontinclude ecore_evas_window_sizes_example.c + * @skip commands + * @until ; + * + * Use the @c 'm' key to impose a minimum size of half the initial + * ones on our window. Test it by trying to resize it to smaller sizes + * than that: + * @dontinclude ecore_evas_window_sizes_example.c + * @skip keyname, "m" + * @until } + * @until } + * @until } + * + * The @c 'x' key will, in turn, set a maximum size on our window -- + * to two times our initial size. Test it by trying to resize the + * window to bigger sizes than that: + * @dontinclude ecore_evas_window_sizes_example.c + * @skip keyname, "x" + * @until } + * @until } + * @until } + * + * Window base sizes will override any minimum sizes set, so try it + * with the @c 'b' key. It will set a base size of two times the + * initial one: + * @dontinclude ecore_evas_window_sizes_example.c + * @skip keyname, "b" + * @until } + * @until } + * @until } + * + * Finally, there's a key to impose a "step size" on our window, of 40 + * pixels. With than on (@c 's' key), you'll see the window will + * always be bound to @b multiples of that size, for dimensions on + * both axis: + * @skip keyname, "s" + * @until } + * @until } + * @until } + * + * The full example follows. + * + * @include ecore_evas_window_sizes_example.c + * @example ecore_evas_window_sizes_example.c + */ + +/** + * @page ecore_evas_object_example_c Ecore Evas Object example + * @dontinclude ecore_evas_object_example.c + * + * This example creates an Ecore_Evas(a window) and associates a background and + * a custom cursor for it. + * + * We'll start looking at the association, which is quite simple. We choose to + * associate using ECORE_EVAS_OBJECT_ASSOCIATE_BASE to have it be resized with + * the window, since for a background that is what's most useful: + * @skipline ecore_evas_object_associate + * @note If we didn't associate the background we'd need to listen to resize of + * Ecore_Evas and manually resize the background or have artifacts on our + * window. + * + * We then check that the association worked: + * @until printf + * + * Next we are going to set a custom cursor, for our cursor we are going to use + * a small green rectangle. Our cursor is going to be on layer 0(any lower and + * it would be below the background and thus invisible) and clicks will be + * computed as happening on pixel 1, 1 of the image: + * @until cursor_set + * + * We then check every one of those parameters: + * @until printf + * + * Here you have the full-source of the code: + * @include ecore_evas_object_example.c + * @example ecore_evas_object_example.c + */ + +/** + * @page ecore_evas_basics_example_c Ecore Evas basics example + * @dontinclude ecore_evas_basics_example.c + * + * This example will illustrates the usage of some basic Ecore_Evas functions. + * This example will list the available evas engines, check which one we used to + * create our window and set some data on our Ecore_Evas. It also allows you to + * hide/show all windows in this process(we only have one, but if there were + * more they would be hidden), to hide the windows type 'h' and hit return, to + * show them, type 's' and hit return. + * + * The very first thing we'll do is initialize ecore_evas: + * @skipline evas_init + * @until return 1 + * + * Once inited we query which engines are available: + * @until ecore_evas_engines_free + * + * We then create an Ecore_Evas(window) with the first available engine, on + * position 0,0 with size 200,200 and no especial flags, set it's title and show + * it: + * @until evas_show + * + * We now add some important data to our Ecore_Evas: + * @until data_set + * + * And since our data is dynamically allocated we'll need to free it when the + * Ecore_Evas dies: + * @until delete_request + * @dontinclude ecore_evas_basics_example.c + * @skip static void + * @until } + * @skip printf("Using + * + * We now print which Evas engine is being used for our example: + * @until printf + * + * We are going to add a background to our window but before we can do that + * we'll need to get the canvas(Evas) on which to draw it: + * @until canvas + * + * We then do a sanity check, verifying if the Ecore_Evas of the Evas is the + * Ecore_Evas from which we got the Evas: + * @until printf + * + * Now we can actually add the background: + * @until ecore_evas_object_associate + * + * To hide and show the windows of this process when the user presses 'h' and + * 's' respectively we need to know when the user types something, so we + * register a callback for when we can read something from @c stdin: + * @until ) + * + * The callback that actually does the hiding and showing is pretty simple, it + * does a @c scanf(which we know won't block since there is something to read on + * @c stdin) and if the character is an 'h' we iterate over all windows calling + * @c ecore_evas_hide on them, if the character is an 's' we call @c + * ecore_evas_show instead: + * @dontinclude ecore_evas_basics_example.c + * @skip static Eina_Bool + * @until } + * @skip ecore_main_loop_begin + * + * Once all is done we run our main loop, and when that is done(application is + * exiting) we free our Ecore_Evas and shutdown the ecore_evas subsystem: + * @until shutdown + * + * Here you have the full-source of the code: + * @include ecore_evas_basics_example.c + * @example ecore_evas_basics_example.c + */ + +/** + * @page Ecore_Evas_Buffer_Example_01_c Ecore_Evas buffer example + * + * Between the Evas examples, there is one in which one creates a + * canvas bound to the Evas @b buffer engine and uses its pixel + * contents to create an PPM image on disk. There, one does that by + * creating the canvas "by hand", with @c evas_new(), @c + * evas_engine_info_set(), etc. + * + * On this example, we accomplish the very same task, but by using the + * @c Ecore_Evas helper wrapper functions on a buffer engine + * canvas. If you compare both codes, you'll see how much code one is + * saved from by using the @c Ecore_Evas wrapper functions. + * + * The code is simple as it can be. After instantianting our canvas + * window, with ecore_evas_buffer_new(), we grab its canvas pointer + * and create the desired objects scene on it, which in this case is + * formed by 3 rectangles over the top left corner of a white + * background: + * @dontinclude ecore_evas_buffer_example_01.c + * @skip main(void) + * @until show(r3) + * + * Since it's a buffer canvas and we're using it to only save its + * contents on a file, we even needn't ecore_evas_show() it. We make + * it render itself, forcefully, without the aid of Ecore's main loop, + * with ecore_evas_manual_render(): + * @dontinclude ecore_evas_buffer_example_01.c + * @skip manual_render + * @until manual_render + * + * And we're ready to save the window's shiny rendered contents as a + * simple PPM image. We do so by grabbing the pixels of the @c + * Ecore_Evas' internal canvas, with ecore_evas_buffer_pixels_get(): + * @dontinclude ecore_evas_buffer_example_01.c + * @skip _scene_save + * @until } + * @dontinclude ecore_evas_buffer_example_01.c + * @skip support function + * @until } + * @until } + * @until } + * + * Check that destination file for the result. The full example + * follows. + * + * @include ecore_evas_buffer_example_01.c + * @example ecore_evas_buffer_example_01.c + */ + +/** + * @page Ecore_Evas_Buffer_Example_02_c Ecore_Evas (image) buffer example + * + * In this example, we'll demonstrate the use of + * ecore_evas_object_image_new(). The idea is to have the same scene + * created for @ref Ecore_Evas_Buffer_Example_01_c as the contents of + * an image object. + * + * The canvas receiving this image object will have a white + * background, a red border image to delimit this image's boundaries + * and the image itself. After we create the special image, we set + * its "fill" property, place and resize it as we want. We have also + * to resize its underlying @c Ecore_Evas too, to the same dimensions: + * @dontinclude ecore_evas_buffer_example_02.c + * @skip object_image_new + * @until resize(sub_ee + * + * Now, we re-create the scene we cited, using the sub-canvas of our + * image to parent the objects in question. Because image objects are + * created with the alpha channel enabled, by default, we'll be seeing + * our white rectangle beneath the scene: + * @dontinclude ecore_evas_buffer_example_02.c + * @skip rectangle_add(sub_canvas + * @until loop_begin + * + * And that's all. The contents of our image could be updated as one + * wished, and they would always be mirrored in the image's area. + * + * Check that destination file for the result. The full example + * follows. + * + * @include ecore_evas_buffer_example_02.c + * @example ecore_evas_buffer_example_02.c + */ + +/** + * @page Ecore_exe_simple_example_c Ecore_exe + * Creating a processes and IPC (Inter process communication) + * + * In this example we will show how to create a new process and communicate + * with it in a portable way using the Ecore_exe module. + * + * In this example we will have two process and both will communicate with each + * other using messages. A father process will start a child process and it will + * keep sending messages to the child until it receives a message to quit. + * To see the full source use the links: + * @li @ref ecore_exe_example.c "Father" + * @li @ref ecore_exe_example_child.c "Child" + * + * Let's start the tutorial. The implementation of the child it's pretty simple. + * We just read strings from stdin and write a message in the stdout. But you + * should be asking yourself right know. "If I'm receiving data from an other + * process why I'm reading and writing in stdin/stdout?". That's because, when + * you spawn a process using the Ecore_Exe module it will create a pipe between + * the father and the child process and the stdin/stdout of the child process + * will be redirected to the pipe. So when the child wants to receive or send + * data to the father, just use the stdin/stdout. + * However the steps to send data from the father to the child is quite + * different, but we will get there. + * + * The child will register a fd handler to monitor the stdin. + * So we start registering the ecore FD handler: + * @dontinclude ecore_exe_example_child.c + * @skip ecore_main_fd_handler_add + * @until ; + * + * If you don't remenber the parameters of @ref ecore_main_fd_handler_add, + * please check its documentation. + * + * Now that we have our handler registered we will start the ecore's main loop: + * @skipline ecore_main_loop_begin + * + * Now let's take a look in the callback function. Its a simple function + * that will read from stdin 3 times and at the third time will say + * to the father: "quit". + * @dontinclude ecore_exe_example_child.c + * @skip static Eina_Bool + * @until } + * @until } + * @until } + * @until } + * + * You may notice that we are sending the messages to stdout, and our father + * will receive it. Also our string must have a "\n" because the string will + * be buffered in the pipe until it finds EOF or a "newline" in our case we + * won't have a EOF unless we close the pipe, so we use the "\n" char. + * + * One more thing, we use fflush(stdout) because probably our message won't + * fill our entire buffer and the father would never receive the message. So we + * use this function to flush the buffer and the father can receive as fast as + * possible. + * + * Now that we have our child ready, let's start our work in the father's source + * code. + * + * We start creating the child process like this: + * @dontinclude ecore_exe_example.c + * @skip childHandle = ecore_exe_pipe_run + * @until ; + * + * With the command above we are creating our child process, the first + * parameter is the command to be executed, the second are the pipe flags and + * in our case we will write and read in the pipe so we must say what we are + * doing in the pipe. You may notice the flag ECORE_EXE_PIPE_READ_LINE_BUFFERED, + * this means that reads are buffered until I find a newline. And the third + * parameter is data that we would like to send to the process in its creating. + * This case we are sending nothing, so just use NULL. + * + * Then we check if the process was created: + * @skip if + * @until } + * + * After this we get the PID of the child process and just print it in the screen. + * The PID stands for Process identification. This is just an internal + * identifier of your process: + * + * @skip childPid + * @until fprintf + * @until fprintf + * + * The way that Ecore_exe works is: when we want to read data sent from + * our child we must use an ecore event. + * So let's start register our event listener: + * @skipline ecore_event_handler_add + * + * Now to send messages to our child we will use a timer, so every 1 second we + * will send a message to the child. + * @skipline ecore_timer_add + * + * After all this we start the main loop. Now let's pass to the callback + * functions. + * + * Now we will see how we actually send the data and receive it. + * Let's start with _sendMessage: + * @dontinclude ecore_exe_example.c + * @skip _sendMessage(void *data) + * @until } + * + * We use ecore_exe_send to send data to the child process, it's pretty simple. + * To know what the parameters stands for, check the docs. + * + * @note The function @b ecore_exe_send will never block your program, also + * there is no partial send of the data. This means either the function will + * send all the data or it will fail. + * + * Now let's take a look in our event callback and see how we retrieve the + * messages. + * @dontinclude ecore_exe_example.c + * @skip static Eina_Bool + * @until } + * @until } + * + * It's just like an normal event, we get a reference to Ecore_Exe_Event_Data, + * extract the data and then show it in the screen. + * + * And that's it, after all it's not complicated to create a process and + * communicate with it. + * + */ + +/** + * @page ecore_imf_example_c ecore_imf - How to handle preedit and commit string from Input Method Framework + * + * This example demonstrates how to connect input method framework and handle preedit and commit string from input method framework. + * + * To input Chinese, Japanese, Korean and other complex languages, the editor should be connected with input method framework. + * + * How to initialize and shutdown ecore imf module + * @li ecore_imf_init() should be called to initialize and load immodule. + * @li ecore_imf_shutdown() is used for shutdowning and unloading immodule. + * + * How to create input context and register pre-edit and commit event handler + * + * Each entry should have each input context to connect with input service framework. + * Key event is processed by input method engine. + * The result is notified to application through ECORE_IMF_CALLBACK_PREEDIT_CHANGED and ECORE_IMF_CALLBACK_COMMIT event. + * + * The full example follows. + * + * @include ecore_imf_example.c + */ diff --git a/doc/foot.html b/doc/foot.html new file mode 100644 index 0000000..a915831 --- /dev/null +++ b/doc/foot.html @@ -0,0 +1,19 @@ + +
+ + + + + + + + + + + diff --git a/doc/head.html b/doc/head.html new file mode 100644 index 0000000..2c61795 --- /dev/null +++ b/doc/head.html @@ -0,0 +1,69 @@ + + + $title + + + + + + + + + + + + + + +
+ + + +
+
diff --git a/doc/img/e.png b/doc/img/e.png new file mode 100644 index 0000000000000000000000000000000000000000..d42aeb420098578b19a3eab3d6d1e6e73e3277bc GIT binary patch literal 30052 zcmXtA1z1&0x88Ik9RgAUhmiV^M(OTu=@JkSNr59J-Q6kOARS7BNF&|dDWSj}|L3_V zDkz-Ud(T?ytua(pSq2C5DJBF#IC8R*>frYz@IHW!3PA`y{;&)10m6HA8F8rcC*>aa z0M$%EMiP4b_amphC?0$U!%0@}Jp^G9{(DD&(lW@vC(&Hxl%&vpVLd?;K!}OKo`WD7 zNKR5r(_{Y7$NeLb)~`o*tFMfv@iC~Mo{PdoLogU}Wn~J2=`cfx_Gm)Z>0wf$wsaxr z{zS}}@{?n1n#}4_1%bwiF@Zelyy^DYxA!&fap{9U7(d+zkN$aBzWume*IM_V`?1LN z;`^T>#ITib2|J84OWjP$8M7)KZxNgz&CLX#Plo0{wuX~05Q=>t@2`&_VMdj#MM^jt zL=6c}H1#>~=~U<^iZ2`Dh+f_Qxi;{9xZSDm{`>?h+xKp-6PJ>o20|C~IL(2&;(1Dw z4rsButpEHz5{9Qi-w~!FqN7iow}yx>ZZCGI5sHy=`n*rtukqnI;03V?KC?m6l$~A+ zUmcRf0#I+?t#tU1LEDomuiN{bDRq;2LkXFnobB_i;S-@uWz8yMDv0-$*QE_TRAt&7 ze6`r-dEt&dU6=MWQu_LKC;Oe}&8g}8nq089=$rfNl`4c)tC6%1NjsjwJD&WR%527M z{FfDt%kug)W#U8Wgzs)==WXXokSW$V`QS3c_g? zr|Ea2qDhRR$EqJ`0bQWhyhd9nBXauCjekwVnK8Y24(5u(!8&g5!u!jyabvwVJpb-;FFq+g9;s{^GrSkEY+8T4 zwbx8cU44R%nmU`mXi|@rot=FZEck zmcqUsi6=R);HIt;oAwwq*zg?fG6kM(xg||0ZWdfoJopSZPM9@z`_E~p1qn}BSQwc+ ztP46t97FFiN$vZ-YfT0<^t_gkka(k=gJM_fxS)Y!luV8zyqoKKFr%bO6Gr*TnGkXK zZu99&+~6|?_~9WcFCs+C$S9prY&VfgMCt{Ddu@*5LQ$=@rvlKO^G2T~6oP#ERLSe* zRD?E~YM1k(MA772s;YL>Uuz}~LxdbuI2Gg-=XOqxA;K3UE#Pln1N}s5Qh3^|WL1d? zS9FPv%_xM*5mu2`pTN<^u)A>1RT0FZ?OopBLKJ&75}`p{7B;-xZ-WY$f{@4D&Z#9{ z4f_-iN<8Iu{Yvyyxc6*IF(o%fL+RBAD5Y`Pi#6r%sHTODAas}Z^6dDER%WHY+H&prC*i;#q3>P*&%4wcjvZrn4guRW{S^eXS1(x3{(V>r@&0 zI4-w&Cd-+Zqf-Z)lD!kd)Ag4*+?y;q$rf^tBK9njE%nSo8@=!V1!#xmpR?up${Va9 zStj}!6>b-u+xYv50=X|79XE6q`%@*+nk--kpmcNo1eM!}x_StXT=b%2|H07fK}XlVY{}+MZzTDq|y3QR7bE`?L@HQ?~2r?>Yp+x?Xzxy*VSzP-dF{ z>hPAD*FJ?qk4mb`oRr;gx6R{>4wO(7l~C#9Y4?*s@9X0&n+|4l#IN>q1n4v-U2ue7 zpm+!f2tFcgPDFaTf@Q%s_$gm~mDt${s9F_W8BxSC;}I)k>~lCo-`@b&NQMKD^3lye`$2nk*6T ztX$teV>!jr_qp+Ue_6g$%nx0T!F;4SOr7NmN-*IzPsCv ztzsel+99fd`g6!eJ|#f4uLNOrveHOM;b5jBa-#2tBn+eEP3MCbB(lhpfYBALs0|~J z4SSaNDFg8v2Q3fJB@FHec_Hj7r5s_Mot^ndN2`eVBTNq}?iX@u;Ikh+F?k_o^2y(l z>a0$?LSF?P^@jNjIjT!srsYItGsFbi7%UR)nKU_fsnBGP?`DqryCauU^<-@mH7wsi zb_2#ip&6@EgJ$P$ALWhuh0Vw<M19zU-wyWp{Z^h)MsaVn@7tPck>IL|Z3mpXie4i=l=GeR8@b~3xsP%5|O5E8Tu zwSlf2@4C^46C1b-c`!YHz8M=8KDLR7gfw?PB)6_Ub~0DD;|gYol-}~`lKTq7d&gc?a7#V4tWWCwlExz!AMwM9 zEi-p_chfmK|GKzCQDCAlfZ=#591W%hDl|Zv+dqJwtF8dH zx_UqVw#qUj(^QYdpN7bOxviODE>1Vg`?wk2;qzx%Q9&U-Q$A7}2@EMq(45lcn0$h9 zsqQF-Ydg$#ki|sh<>ebU`lBBi86sTpF80RrWrAmEgH5Z!r0;{cA>Eyk^y|%`MAn!v zeHRTmKgQ?Jk?|>Ub|;HQiEGS-N4r;6{EoLr(qA)n@@aW$%IdaPI@Mr5=aMmE zWx&{R1BR&*vY3aY6Rg_vV!M$n*mNsLa~XGgbJMj2bfFK>w3)eiRR~p?Q7bQKKiJ6c zJoRs`F>!E46y)Xe7Rr%mA|u2lQY^I~t^EA_=;Y+WajG)CIz|A7@FdC3kOnIdkUwWK zBv3s(JOmLi7k!aLV`YzGkt7LabV;qF%u9wuPcJT7<&gJPQy&91FX>S8XkaZ|G&Cj@ zrp)q`;u5;5FnFINd~stR9np*T==GM z(eh#4l^c`06*9qr-zJcB;nI+cVu>SHA&&9BTc#{2DOrhlCere`d##!xvai&tuGwVr zi;^$yXC%qNJ>=7_g#~X>W8-B#?m}Vsl|@dT1zn7{XH%?6`@pX7pl9OYSvQ7rB;qME zxq}k-5-;Kzp4uDHV;uTXMm(=Qv3Xt?t;h!I3Yk3ixT=8~>!)L3XgJiVpO8lt-$oGK z9UaLjGK44ZcuHIjAN%DM@vq1*X}(ZXNeMxVB6J=J9Xmsxq`HI+b@agn*ad16%NOhV6ogqKbi<>{lcnK ziJpL3whv&cRIKcioS~6)zW3jZ7svDSy>qjF*%0q^O2w zKR=7J23oi{#LW0RAU3IP3rg$?FQ zM-oU`vIfoKii^I4rogcKBVM8XdC#>4Re03=boHB9UWo%}_yPb2{mu(JDYa;D&P8o0JIfaO}J*U|ljmC#Pa&E3ob{3( zfR27uJd3aInK#9(e~m{%;#TMP_^<>O@BB!8f14luDhx6Kz$I!YhE^hO`)B4`8jU@Z z=jn*utpMt$*w|-ee>|5XgQjEYWgY}Q&!0=Yb?H%I@CmF3jW%F||3}(OR!X=JfKRMf zUOw-#cFw?JgHDCB6)c(wj$wA-O1gu6);2c&bLtHv{s5hVp(X3WPg$EeI5Hw~fA#Cl zC{L>5dSCJtc%$Sp>%mk}8HEXioC!zM%S6?;x$aGDsO3xh?5(YhUxagX6f2k8YL`@o zqvTv)UEvH24kAEpx7+D{<5c*s!FZmJv$>LFo|cot&iigWT5F%^zU;XZVc3uROqk3a z>?Nk|V4Od0pe~jMafg{@2s8t6J(bgVn5XS|lXu4eW|esal+ZeqYXDP}lMH)bE}k*6 zLZ@o^LQYPOln)H^V=%S3)zar!l+t)?mqAO6oQQImt)@*tj|fUQ)GF1WgzihV%Hja% z*idrcJ*et*6f=y8fNrS${+|5=)320;)+_s!&kcC9%bP%fubi%R`xOa&`E_sxcHAvN zvCtyR^4-;ejyOfr+h3J4ZmlB3qQ04eA3kRJJ=}WB%d$`ZoT@bP?guoM5r3JSAMnK$ z+s*5Xi}XkE4PN9VI+i0B@tkx%`nL3%eewX)DWhiLXb(E4r>74{=dpE(eps>R4S0AV z@@}z-%L&|&U+6zAL_AJc>F3Q^1O#r8YR~lqG_cTe!ld&(Ra_+iGWm>4wXgi!CnP-l zkHRJFJwK&X_PTrPlJRBwt9Q$7dvkeGSmtJC>vL06Q)s59ri4_uGUN9h9UU^yUi)US z(FrQNtGl~CdCVQLVtp#5uRl-VFYyylcgvQ55F)dQ70{S323jM2RT>>wH|U$z&6(8A z;gOSj2J&i-XR4=%hT+B!CWv1M4mea* zXqPo&_wF#a=4S32%0Qh-@Bch6^`(3Mi&}vX*I!eaQ8n(rr7%@in#z~agLA=6!LVmQ z3emh7{?H+-)2rU@9`a0l3cp|s&X3OO$%rG$;=J!IR-(b1KEels?Z!?mh%K_K?w`_; zXe7ceZNvRVwW%~vql(eHE2I`-qlA<{pnhZ9^CBtQ&GD?DNKVdiU_fZ z#s_fSvTC+b+(9}{!a;FEWcQHu73K>?G;yROm-B>p9xLQAWpRnswKdbiuS=Fx>vRM3 zWAY4R2iPXaA67ihI}r8HEg16aV=2xd?7S6qU0rnO>)6;>4YBGDKd1^Jg5ttBEf(=3 zn$*PO`YGnJ-)beAu@b@9&9bh$k8u);iSi79McOhIzKqQ>F4L~?qFa9LcBrdnz9FHx zJnkg$MyBm0(=aRTam!XHbaar__6iH7<;EoUa0d8$|Nsz1HM(m z&&NvZz#Lbcs5u^;XEwuCLt5pJdMm2v+5r9CJUV)T^eS6S9V5{)C$&ub%+^rDt;&Ps(O%MF{k(`Qp!35%Lv zTDop3xV+(mD(q&;1!D0Am;+&aj2gP>u0x{e9-)~LWFebKU0~KUM67Bc!>a*n{EI8< zaZu5SY}T+ZzKF6hINbYRmf;Cv&OMNSxW(EO2Xo#c*_d#WNou6??Ug4dkkkg+h0AMD zamBx+p{cxG59iocI}XNy(Df^{(Q$E?`TQO}9-vWwjNy5|tw;}l1#kvw?$t9>0gAyB zlXIcCAJR01^E0xA1k!mlk&I6QV@9ENV-CDwO@|>%XFffmJe0R0p0-p&M>K(=3*tPU z>qA(K9zWy&?YWr3+h&m#w!z4ohf$Y4pCHHb+N_naMqp1=imk7X@e{eMS~I~C(vYv6?L?og z(KUSwE*0~_GebpZF;-s{j;<#vI%H5da>$;Jh=r1}-4Y35G?}SC3uh6RPpFX>6i>H7 zVIY)g{`!t+vnOgI9UY<9nT=NtjdH54EpFt-R)}FBgh_c{P=)y#C3LODPYZu}Ii#XllykDjZ77bgI~; z|1|wF_EvgSF$j8;Q~2)y6^{j)2Yl&-;iGsxiwl87m9?~VaOwcASE@G;bh!i6MtSn! zC4`0v_@FjjPE$+_-Uxss;)9Turi_$w`QXsd-5D4d%3q)_dCEA3xEF#1tI|lCuK43V zcY8$@65`^5>Z6lzeEQQV0Q&w!BJy0EAd}=fk=UY8i+J_)_VxL;0$h0p!!6_BniX=@T=>0dh9>U zS!#bkPC)+gt1)VI!)kFqSxzI+MINHut8rNPN;EzT1ObkJZNLXY2P4p!RlB^2em`l% z>b;Ay^3Nd9`Qrg>e7KlzcuNj++-m)b2>puS#>PfGeEi(VkPsV6e0==3oMifYS9fGd zmI7jUr<;TE0RRM1Vu+FnxLEv9;ApRZgMF4RBpv~>hXJ?Z{pDv&NJ_6%5|}!kfB2VxgE}mVPIgay!JeojKM#Zq&wt#J5$~O zzEL|_@F)2~e;Ra8Kot(kwactdmfPPRFE*R!_Sk+R%Si!DrqO3BQO61e6?NwE&q-%& zdO9nrcap7@TG=!@I=ZNnQ}qSd&O03scL#I8FKFdpg8xk6+E5Dbjnk;mZ|HdS>Xma) zP>>Ywk^71dUxIxgTf)~CWJN|`UHEPEMGF0}`j5lfN&@JtRaO-SjSt3n$c#)(*8M;^SSgHfU-$U|=7QN9 z&#lCKfbATbtVgpt84QTTFm&ypG$5e`eYKt3=I(bc)~oyC1TK%^HK20y1qILFM?VuW z(*T-1yHQI518<)*Wh-F5J}Ozlq1;a+3*q#nMd$U~%1?D&qS%3qbhGxEdRed0amlzP z)bIY_jRCMJE}r%~i-TT}4yf>7EGQQ+rD|O^ze?SjJc@?c0>0?lT*dmgd0D1p(Tyv< ze-K`p_ySL3O}k7>F{-QMdfEHkbg`PbJkTqfp$*(RFdZ_pL^IHYfwq$;hglVIZoj1LikByCu=*N$L*#f?e zHh#`Ba~wgW(jLg?9sy#`E4eWWENDboP6<1F=aa}TRHhZJx`7h2sffp ze_}r~Xms=edoCXPt(8u>t}{$Ppc!0fFq^3k-Ea90bfDXB{M%8y);}|vWt{C^%;9_d zYgwI6lshN53qWfR2ZRSjokh`F>XQ_bJfGE%lsQ{l+mohzB>-b7+`yI`hV41Q04Vkh?FB*X6D*QNN=Ng2%qA;L1PQ+Er$lj-I~8W;~B3&-JU8 z1^L9K{4a35_{v4^Q-u&8hB-QW)a*Q2q2-m8mG?sl%yOV8UL*@M^j6mj8*FZJKsG?5 zSqGh6DBSp!#mU|@=yv(o-8V3V3a|>@dK)zw%Vc*^+8m>nW^IJA{VT7P-$x6tpKDt; zZ}o%m#FK=WfCK&Kyxv0$dbZC96`X~zt^i(U(8%8L=eV`Htxfp9FeH>R(CpS=!?nKh zdD4oCKSqF~kyp_ZE5^m0&X|$~T8DzNqT-ZnbC$i+86F$uRn|KQAO@*U1Y~g>dPxzD+6ufB~iOnpk<#9x*iHL}R zP#6cJ%D73*&VD=t(hJ|WEk1kN#yubZ^Z@5VaiD)9wjg3i>#YkGQQIV9hgvrHYx)k3&*TnQ< z{hxyyUvJKU`|jPlo7-E<9DX7-qD`BH6k<_RK>R$^JW0vP1>WS3*FO|-DR^a?raVB) zQqKEW>2vlE0UJ%*!lU#;LKJ2$3j3)}VtAG6U(HbAIqC$Gk<$6ehBD{p=O(=A?=%dE z=T%`X()#Fqp-&a>!H`>izVZP8#%w0U%38Q(-CS5(ja0NfFjdRT*@D$yTtFFofPi9# zzJd98czOnH@9eC^6#L|;*G|N!n#@V$k5ARl*-zY4sxWV51g;tk%PdB&%b-ENrqBHexX{R@+-wB?HDe#g@HSc z9AOhzWRnxsPU~-59GbSkfBjj+?LB&YY#|)pdyZ!*$rpZ}_zeDOqbWHnaKKZ3w(X#PJeg6n?Fg5&;9RuI2INb>%lW7Lp@*eJ<3sRsLs+tjOsrt*ao^YrCCtZtpHEYwZJN z1SmRwI0Ftx;Rf(&wA8pGbu2v=stGLL#9Hc$ukb)tNFER5%eR<@KjF=ihc&YOdG)c| zvP^9-I29dP(Q{=QPEIE)7ngJOeTKv}+#XqEtHd76ie!XEG^bnkQ6Ky8fBxDmtLpHISieE}ZA&Q;R$T_ba1p?^#KX>%X?*WG z9uMd0CPP0Kejd*El8}v;!jhY#BLO}xMqM{Z!U}9k23L;z5r{mX zh4)V2vHNXd#z)cp=L1?xwk+pXhkW5Y+NyU`+t-CIV!WvU*~{;Kci8CYvr0*CFqj0y zl}o)nJSc-$r3WODPZtJU-NCkK;7(VTz>q7Bz_;L*)v zR5nF>8pg_)d{fX81w3^XOn1$WC0LJB2WLqTlHa_TMo7_|ygpNs>6Sula%5GEO0LP>_%ibB}qR0!NebD$Vt34D}7-cS%((i0oIk|TziAvk2N2KS9_T*XHHIQcC$}9Eo zKxjZU;0MZ;14;PSGO*eSxw*NO)#jm+>{1%F+f#_FLYrb1I4-Zi;t#z*5QIg@?a)U2 zVL`s>nQl@Lm;@HQ>F;4@GMlb$&@dQX9~BuV!xO$r-Z?TYB7Ygc_(=I748ON3W{X@} zl`rFCl~_ITOWBxAQ6AJax=4BjuXtn$W2W>ivhO^barUodX8(!|`dzJtEn+e_eC{Tm zWtNnbv}e>0-iJkfBK*V3-Y7vNmMo-~5R1B;X-{vIb%~7*X|g1iR&=k;it!hc9nl|? zlOt-5pX=+G-CM3T30J*i!X_y2*tY{I};&SsR9rE!uy3Y-1cG`Szl=R;*?c(VlFQ1*oiMu^vt~EpD|{i{!JS`1h7ysmpHCL5Cy%Kr z*j=UZU6c$Xnc(>my5%Lx3Q88&Kh9mFRmFOlAx-J%oK0;ekLDX1 zw9BqIVAh^297lf|k;;lCs03ZdSWJ{+&**u1-2x@=HRyKRfV*%6QbX&if?8s+`!*wK zFA2feBDAcolAO8+wbuH#(Rn7X;s=0)Rr#|lib#@5ib~7O%*@{dF$nWQn&qR-=u4O& z;21yNuY!U{F&iosXFitvQ>db@9`^y1jL6`-3Q43g)EuKGCsU15>c`)^f4HxVr1PE6 zth0S)P#KVZDm-rje4Y%{)-$_oSys|%Utiy&2x)q-wNV)YegP%nUj*m(<{;q+cnPJr zLVY^jzrCbygoEUjW7HU{VVxt~wiCcLbMNi%r;dZ6?;$w%{Q9pA7@w}=2>39&vguM* z7_5s4crkP+#dHfRfTt>_j97tQT~Y5)lL-_F9}hq}GPxJk-LM4&{4{Z^qo`k_LW;7o z=vdcM>}1d(z?P{2Xitt~pmG~dt2%PVcnn}SJ!)Z=gU9sy<AYu zWBALg26^6|_vX(ZG`R)T9AN9^`-zHnCB!qS__9lk%9kSteCvYXRqqV9rh0Z~YY36x zo|n7$z(iWmG8>C=p=amgyDkUKOAr_*zlqwJ^_6dLZ>#6*S3Nt9KU4e8CZfs?C%w=K zD@iYdiUF953h4Pa^YoQ#uTq%HtYn`NYu zY=h!VAoMgq%IHhu3;97%Ali+Tgd`8R@vR2+Hu$m#5eI;bM}Ge<&QFOuYtIXaixpvs z_%{&2a6iDr!U{iEGN{mIGi*Ao1w_}=!@~xc@lM?q+|Fjl2RS)84+K;xZa}19($LVD z?wQorjzY>Y)6;GMeZ9W<{m!#ebR%;X2!;#a-yP5ItLnI8u>%U(Ac496Q+TC$e-tes z4u9e;^=|I&%)rd8xIUb_AceLU-gS!T7Ro2WfY0YDc!Yw2LJD@RigCxs+tGtxRZOow z-l%e>Dn?B11%gbHe?R~}6_t??BO~L`% zz7Pgibs-Z$hW{zfm`kdqnvh9(akk~d+ZDhqjb-HC)XJ-|k|H<&I@b;|7haQQHIm@^ zghIXWvEZJ6Z)&v4`(hFkgJ>m!Gk_6#oqc_>vH}3by9(VJvrC{DWvh~qeD*hs_5=U+ zV)XT68}=&Zcyk%##5Roie*1@~EwCZ`UEaUHo+(z_pc2Ddb>i>35N0D8HXpDSS_gMG zCM6|hw*erVR$^jZE#lt#L{^=wsyCglUW4dXPjz**ST-=a@a?vNQl0~xLaAK0XzJGw zzJR>e0mmx#i3ytgFF|v)mOdh)6pSbE9nWXrb?0zRSo@t1LEyl#x2K0~i~nbMV9#y7 zMVPa6p?b+b;Yn?7ES+qe-n5z8&3SUG4FAxRiDbFlOkk#g&v|aqf zU<{4y zxsuG=e{KE8NbdWo{V0vvy{_IpPZWz~ncs88{C8DiQ0Gjk*6Uk02coY1YcYX}xA1f-T@Jd1NdqKXre7y2Hqz;K=g0Dl2Ci`oDQ z{|h4+Q1*LtLn|?K?|?a2wIm=4zStPD)e9e z0sN#N#2+7!Et{MW@q%$EX1)T6d0}szLm`>nAt5X40huAwKHLQ4Yy;f{GaYY0Gv-ya zLytua4`4;p-uU&#@BRn)WyznYiv*^T@D%PlUvJxrgDSz+&G{Dy$*okcegERVR4A{i zs`3T3`R32;WJ=C%d+x^pUbc!Zl z5+EZ0H@i4;{Sre;oBqj@CyrqJ{E3f?`}^uj+gXHsfZtAh7!$=nlTHuLZ-1;l_e_F-57up6Aq0 zBflhNXH!$+_Gf~xQWgX{2u_k^GZ5=4^}v3osK@jGiOCTr#gu9dMFrL61lBE)MN5Ia zDqEhXQxyh$maAQ#sLHk9szKTy(qWgX_{IO9gro)>Y2kn9*3HA?rT_?8U=$sK;KVVI zfwFR3xAA%tRHX=Nl#4Dhz!O?=b>N8FhynBq)P2K+&8H8*c3!czu;9^_$IkDh%J9Ik%@6B^p%Ek~JCX+}zyT z&imgBDw20ozzFL?!6Gr__x{bM5zEleiEYnopbv=Y&wq>E0mrVWRpzk>sqo09|7xYhO?lfw4DKs38Iz+>I1WVon6?{*{U|wE07e$6a z^&&TT4@~yakdP2^?Cxq}IZ>eg)_s=vjC({w@Blu$&(U`JeGuS*Uwo;GW`RM(+|ELx zbGLOokSnkogj+zJd7K5Go}QM12*`0ZkYr(`_>Bukwm{XVSJ%*}Q$6&yORlyy?n{F0 zv@n;t^2El*Hh|W2PTcRjyoEpl@c==!4@|_3-s`r@2?Zq3f7{6!meN@g2udXdg{Y~i zpAgJ-?Sat;M*6Y5Ko+7j2H0IsJ;4rsOXRfxTi4U(2`HzOeQyuVgNSa2C!k8D=L8Qx zSv~}+;%}kN`>3uiQAXh2QZpDa4jUop{~R$u5^V*+yjE~dVQk2h&}YQ1;nggd_;3Ab zQW)wOBV{bocpdgvKxpIl+S-~DXy@wjrev9e7I%L@#?c+@>S!b&KKlH)Xv-Pn8#hqp zbJ-ji(XaUGt4H=Pp8@!_8n^{$#g;lO{cof$^;~VuUP4R2i)vhIeqW@aN0tcM(scCe zhbHCkMmB<75oBEJiC}QO7#tnF76iK`LwU>NG9`s9FgSP}xI4on?1oL~3{)-($Y0#| zCM->Whc#8pZwW?Sjm2Qxso}4DJI~0JYT-!%JR%C=cM(lR#EM|DUeGAaO0- z4oaZ^_u*W(@LO$OF+99y&p`k3GXb(~m4+7=zR5FSV#NXjVkMD5UAJO}3y6yk2n=;k zwa|4L=+*%&IrDXNJmzs99<||ls0Tr$Ib_u!qMQ^E1v7CF6Z@@SJHaMR5%K2Dv{2-Vq|(84EIyg3SXc%fATKX) z!mLfXX!3F+`ZaDc0#U2W){sVMXedDB=AotEFR#P0@*II1X4vVQc?7;FowA>*)9=w2 zGm;#ne6E2?PcIOKrQ!8XULF&O@w@k613r@?*LpqlL*t(%HmIkkN8Lid3mha3g{+<4 zLwmC+!Bzkr;{P>B)g+cLY=> zD{1g zIzR}3I_;8)#VMIC(69MPH2TJ$?UR^y7Ac>~YN7#)T1{?J%a% z3(lvJpxN}da!0v2a)qOGp&%n8{{=^R3Lyr>QF~tMd}s@T!{JaiNb&KpjJlMSYlJa? z)FC(o~h|#$876wIphQ=r-#lVoU#iXk`O>+pszgL zFROAK92{hJuBsOoxHk~AY1Y6Hl|KqQ0i#VHXNY|t*`yUH^|Xa&U?PGOGG!JYhlhID z5{;{<5HV8ETc3iSXMBZsAy8bUO}A8$DK0MO#Hs=Ey&f-DgV^NI*^_Etc8 zm|m58ea5jyH%j)CQY03zqm3*UOBOl0K~{Z^{Jmf%jE!ya#kfnDcm@*u9vqa?I9_i5 zQyOA<%(3{Bm?ySln?Rb>(K)m4XY!iGfr{QLkblqggu zmYWC5>dbXbgiw3QpErZOiv~tzW?o+2wk=QESK^o6T2sP|?k`@vzya$L1Emw)Bd4US z{LtOsFEay~ai_+_#^NIdJq6LTHwwX~AEhuv=;@JwKMWb(nt$~1iOtOPG04LuNmSzv z{fzAg-~&1Ecuhf`{_ZOs#ZD1I+@;{?#VH5_g1DAE$sgc59j&wH=Hx(N9W;gY5CjlV zX#{;n&ZbL`m#3%J$ml4?G=AB17?{)O{;Dtpl8PC;=c2A4d$rv8@z$ju73b-XNgE!A z2iwCuKW{IunNO^BhHBZB#_grENxf!gs&RD|Mp4LO=&FmJtrL3k6U`!3|WkU(-@IYz4a9 z5u!n#$8G-p!@L|&3YJcA0Rf@d+y6GFz7va3;>si`b`n3yTecdKSVe$?EFUpK($rjJ zvR+sr991W&e&4B3$~2o8CNBeI2W}SCq=YFE*5pQR2^)=1>3xt6YHlqwsG&{BrB$60 zD6W_l8?jzck?32^hSfAAlicc6NrR5EH7yttDdN^&bLr*dD!>`t$0q2Fj#K>+u}2Rw zmS8~Bvun`LaeZpu$(>{>4JIEV)C$vKZen#~Eh^$rYAwJhDTKU{b#Tiy5>eQ)b~G&i zG6^P&t&S%BGH6CO!oVDU2ErJ?z_90FcxXdBBOTeUTa`b)z{z@rQUlxn7%_4C%=rCv z1Tc$mFn!PD1&BPdb{^d(b9kPX36n9(CKYOl4=WNSF?>s$KKfAyg`1MaBdfB(2e^~g z7#QyQSjL}z?mlZ*5AgK#9JArcR6WCcS%NLiG&`D%_bBdfDWT?e=gN@QPy*!fR%TI@ zgbl9$hVY$ft;o+mv2tj!Ep9FVKhTlIaBt_bSoF6P!@~2hx(}1hQmhOkw;+bV!HGSI z-?hhmtQ5dnWr}B^-Z;!KN-A`WM5FczqsxS|%Z6trkkz@4SS9u)Nuh-F6oHK3-PE^4 zQ-|)!G46nG5OA#g5gX|?7a-qY*7pPsuEYs8BuXEjFgE~htyX2+e&q2rZ)V~;ba;Y| z-Yf+Y4rHaa3)$FoaWspywqI-m=hyxO+#F= zZ+kJfdfD`C>SI$CK3w+!Xq^}y9X(oX0UsRaF2jEDpSr)jI*NdmpIwHd5yKq!Y%@-; zmKR#$)eJacI#>rF=iDP+R{p z-Ey$OK~8-=I%`i5bTRMj?DX?%I;U-s>%?q~sGw}Hm(UR3mP*L4;e`CDD6)IOKv z`Atpy2yjmGz6c_sWaCpYXR9+*C@sdfk=~lMDemysKNe13t3IS<)MeDK30;EOJi0ei zkq!=SV4bgjl`Kouie2&pIr>0wmi7zKa__Z>c0}1#@;FH#9iY<<0Q5z53r^pmfV4J& z189<%#>U1KB^9vDJz-WpBnr82I^i?r&Q7z#4o&MJHDoHpf};JRPB>rPTr) zTI(N+d_hM?CwOpmSN(5eEOq*I+Hl5-074oBg4W|my~oI|1DKhj*-tPq$bs-0KLkA2t-RUdoBZ`(9gbueZYnF zt3n6jO+PXpdAh*mN~u~}^k|*W7`!v0nV%KS^DRZvIr>is;qo0Z?WL4%;pAT2ATJ$e zr3Pnr|d08Rq$pdllpgA+H4GD()+c@IZozpaxV@v5~6zaNL1={QsYdXx(8AOmz7 zRFqwy~8IW zR`3Z6`bal`9f(l;?*w#mR|Ys#jLwp{4>L^6?6I5+*i8-ot`(MBi;y6h;I_0@$~f&0 zfpfTCRc+_;uS(>#T>l||pL4$#O{HaHy~(BcUj9O+JXaBwa}?&glF^RnR{SasJxgRRm7dfNzbUS$;Qo*B%7G^+#`jT5(`TqroKnBIw^DX)b%x>kVX~b5g^g z*Y@0A?D(o~Q5&U-AVPEtGH=~LAqZqpNJ7rz_lpWPx$^?T8xaY~3_kKV$;kBF@@+SH zKW#JfBX$#msWOHC?#lo!ssnPLI=UE|{9UpOh_O9di&Oo77U0vk4KgGQl!1_l2p*sp z`Qm@Wv=vmgwNn(B?94H_(*elL8RV3FJohFFrS=LzIBwUl!A=V&fz79oPT|lV)Zi#U zfbJ55Eu?Jnf2{b6-_|nw2!z@N%^W#lcmE?IuVX8CV83q&wJ1wjv`YUWUCFv>0XG~EsRR8b3k3claW&DawZJ#{ce-?t{_g z(p?tf4HAmdAUX5|^qRM@qvhuf7>rsbe~BleC$&i^3Ln2r7IFe~|3uX=JyB+lPQuLK z&F~Kv)kEg{+#i0Fmi%0Uia9s!ts_Dw!p0hWga}chxzC zNApaGVFBaQ{wT-hpBLnJgX%&EDj0G(7mNH5TOya!tmPe>CU5no@HHj(;k4)or2}zZ zem`WATOiUh>HXX%{{$bQBW<_H2B}=?ykpv;6O(*ykk)(8^(T2?-oqfI0K&rd@5-d)XxNdu1k5ME~z(9-7swX{8x(GZ2;#iX%Kh$N94`zP;sF)+``>A4z& zR9l7?KZJ4w1t12(@N@!L`Q;oj!iQNtLt1H9YRbqiq&%vQX&@ab2gKYkcJd^Q9Tk2TxY%doMtW`slsy;yhLf`i$xqT6TiJrR|C;8krqGg!N+Dt? zHp)CdezXf&YA9&xEC#=AobR@R6<{PMJ~2 zWm7gA=%#IGx9e3dqX~8rA7>mJub=WenLJ5gpB_vYCt-DX3%Z9!dwaV8OlazX+DvOk z%!U26QmFY}7)RPAaEj6ZvoxM6hC)=+uGiK zwLe?4aR;=(KZ7(V2G1-&YFy$aKsaMSm+u2X)iKA?Eoo(_6kJ4Le_tQ_v|Yna?xEx+ zZmN8jInc@PT&k}h-{C7Hp@242-V02NJ{QXVK^n4y;GjfN+$2j5-~*y|p7l{=*RYkT zi?Yx8pKTg{_~#K4c4jtlnfFaOPXqG*$iMA--2NZr2 zShvSLN(WT6rJ#e^f`Ei1N*WrPkBIQAhupWA&5&Oo=c$NpE-j6qjctXXG#_T)4AY~i zoJADa|E@9Z@9ljED4;L&eCGtYT%LuC1>x^V;0pIaQB4(SdE zK6dzNBZdJ0IyNjE`F<->;T-Tp(It~!=eVSr)m5tt_*#dEW!JJCr_lf7{4lWgGk8Qqbf-X_>lNvK%*{=*IOSDL zL+uwrss4tB+cRWkWi`?6OwRIKraj{pms5*nC|U0ET9Ug4RR!;&x?{~|H{g=#GNgUH zlSXV_z5xU18Niw)%BqQEH$?C{W@rB)56kqpftc><>N1(Cw5_)6j%MM_8E)G~}1 z9vmF>238_HEhUBE|3g&3`t}AO`Fmth(L5fx$V{|LY*8VSy6?x2AAxFG=qiCGAK!G*6?0)q4O(VX3n z#KAdmp;UW$dd~0t`-f@}mzJgnZNRqLOJ*yZCvt0u)nH*k-!UwXChK&Xb)Qa-kFPp{T~H5m-sRHf=AR$X!)&^|mHO1pUME*dhT#qcf;SG; z!OX^10wDHfX+c5399+KwK2ghUOD6Bi_)Db60TX{>;ma0~{s13gojAzwiu#G4paRZlkcbWcriB(BL#bN9Bk zwP8|(vw*FDYp)4-tcL(|Qy_kTOebWxE4{GeuXU?<)QPylEy;x9?DBc1im&pqRJa+j(w0%gabDddbq!Dw>&qe3D#uZ{9o3h z&;llczJ(5xK~7%Yy%EIj7k|MIp01Fy`$mK&_wOhmvYlY{*oFsU9_V@3QP$oMydJF2 zp`1g}vMqu(u{Z<9k0y;tmiJc<54dZ87HG8=fLf#vsLqgtgfRjb7=3@OH5@?#RU~lC zzuqLt4tC{YWP(TLA9{ISf#g%{K1)4z;YhNbAoT}`Dmm*^O%cAZ7f!)uUs;NKXeX;M z!MWnS(qFCko<;T_H?a&j=SB(XBx+vj>FGJ}@|INT7mdys@oR(2QxLd%9L8qg2_|^JOD_(f;#hsmmcDvP7VfTpOZkrCCxjym&*^9}$O1U2K`{w( z=`2(nXAs(ySz%AXfb3NXf3t`_3{edt6_oIfz z_*YX0D4l9Qy1O;QzYGI&gih-iv@Cy0O|&34ak;fcbR?v={kt~u=TGXNYYkz=Z`Ow7 zw>LL8Pk;n?ks!o~?@Zb^qzx>kH>7-B8G(XuXyeDPUpLkA%fYI4Fa<@~9*6)9(x*i# zph&s^2zdYAz+MoDU!Hw~MVI7bJGjP#k(n)z*;V?MT zbnb&h$KKHJcg^hVY=V3GSXdWxI&3iO!EE_WC~~Wle}??EEc&bmuYiHsR|mDasMl$Q z5nfA=z^VX%t&QduKf+A`VM>GQk%(BJF8S_`L3V{8R z547S{a1zHPEopA>6ShGkW#w_SMLPw4_iw=ay#&r(>n>DP;P6P+HBs1ZxijRFJ)Go) zzt%`dND$J}(vCDQlvGt4PeC2CAq|dmKTyA#!+Dd7$5ZMH@I@PlEv654ch}nZ2-)H~ ztSEZ+8uoynXsfdS<3ak*$y^QF#TergsPZ0Hf?Ftj!{zM|XrL&6H@+Q1x)YxY+$e1S zy9R4(2g%d2PZ&*s4O6Tm?GoOJ0#ln|Gr$6;8DAegHm-szKs z|Bj`KWoi%n&DgozZ+|$Q$s2u)x&-x5i=D6;Xyxo)yjbagjcqptM{Wohyw)GzDCR(b@8LZR^&`Zv zueWloCz-D$jMzwC3_n&c3ihG?tS%ozBf7G(k}_IsboTSjn9cjd?(FOg54!hrYU*t0 z6>LI5bFa==Jtup6`$hOW-th?u)!*vtr`$kFaJjs^Opfkk{TVu)&5#rSwzhhblauelSC`U$^5njpGY|CIo0!BBj!`S_E3hr;MBH{v zF#UdqZ-4so<;$u#d`K}=h9cKmLrozeA*Sm?i!yioR-OH=8)WjZ_;!Wb_#Od!r>~z} zpPfDb2Rx#Uj<6Qh{7X|v<^9RIbjkX_w|JlKL%ugWYFFP>rx57e$Khgffh1dkxUFAz zDF`G*L~zqr+zUreAyKLEFyq@?T46jLEs379U!`^g7NZaqiWw{Pq7 zva(tn?mxrRz$U2LeIDZ1%p$3tEQkjf(UN+qNa+Q!&vDy52q@6?f7FUO`|8yzGx*J& zz(Fe&q=^|7E0FD~!c>Get&)R5u{gCE-)nLB_wU~+bQZ|~zZktP$96jL_m7!m!Sne` z$e+L|swPYOT!v6bvZk9DMB~p7TrBbWOgt~2XegV>Lux>u#lgj8;N5$-T4LEzgcY6$ zc!)B6ZxXH7)5LNaqR4R{p)!y%Ha46fc*nUqtZtG#17Pv0!@m0MBmEaBRG2B$$q$N( ziazv#mha{#HeJR5Og@`}h!E=7ZgZ)EBl+tS@8xe|IhEq1;`j=4ajhpqo8bL%&}!bC z_}%8#*5xL&UC*9Bjn~#rQ&U&}z`@IVW#R38SqEf)G5CoWX+oRD@z6X&hTW_yl!d2=MFwOcRyF z(s=w#sfwss2tvZJF;c9mYPagve~ym29J@B1{ZY5EwLQbF5|}jMvuZkO+`iysWnC5? zlwvjRT-X(~1Cd^QON*>{*P9pPCNks^H?*%CdZ!=5i0H0qX}MfTCO?RPEDf~iYMsAu zuV3G2<%CYs$Dn0IPdN4(=z(ez}sE@p! z`3K9^Pq+6wW6)w_Hni&c=@w7bJ(_IVbU{E@`K+q(LCS3uu4)M2j}VVTCTAW+v;JaKJFam_2VaKqge z7Z*R0Q&N_E2oLAVWk-pplMy0{8xQr}8mHR^B=&xMn4FqY6zYTInPGH%sU%oCxPUsx z~uOD9UXlF65Fr6LWVQC zJm#nVh+lE<&NH<~RhXm|<>aU+@9OWrET8bCY~$mf^N%nuW9Q(QQ_qmP=z%UjLpO7t zd+wE#wnospl`j5&|0zB|OC94p;CpY`TUpiQ6&7-_^I;>%rTO@Fs?|aN;tob3Qb#M%FNts;UrLY&7=+=7kmbvd~_rE{X8y;>rg9v4_|#-+`5Yv2}=t{JDO>^i8(W zm>A4PMY`){6Ly;~U%q^n4q*Ha=v|1O=;{iK(hy~Y@y3};9HNt77EsE{^kJc)PwzxV z<1%*@UP$ur5J3v+CTIpP`$3C6iII4-l_(dlnvw)}(YWrc0u10s7eM=5ZMTQs6dc$y z8`^hEcdf3hY~1N)%h)h~s;l3qrdqRK&WXkmtRZMYFD)U#RS_1pjgb*898y>zZAdMK zSv?gZXx>0U1pFJ03TsSZW#z#SU>atQ&t|T^m3;bS{RnAQfzez+CT|T%Z_6OUy-GDr zTs85_mFtExMo9_J6*N=N&{8yj93Rl;rUE z@h@H=AIgX?S#CB4x-m%O~yda9Ra=~Bfu|m z($dmOVb}O+xJfbZ1Y!yZ5lF0Ey%wVd`S}fc`k5oR#S*0e(lh~%U-CnqX$i|)i2{V~ zGl?)vu_ot5nwdsI$B-!c%Ce7ux8Z9xfQHvDFIdMNKT!w~Ws;f|4fXc)NL_-y@#e>o z%K+>cw?j9HN{~7>mOyF(+@2qC_;SCXY$$<|?J6cU)zEWiRu*;=KXMs`P!Ce1yli(w+)E$4o^_sad;(fJ0B z0K`LCS=k2~A*aVR&IyB7?XYbPs_iBOn)35sL^ZSc<4}@g6tExXd)Xd%G?q3roDa~_ z((XY5Kr2Svz)E3ZLBY6)h{$;OpcnP|-;7^^eP2MF+zFNUbO7cJ4b+8PCv_>w>f08r ze2s$SXw0|$siJ_g(Suel*U<69?vA?fF6J0Wn6@KBLr-LDlFd9lB|u=xW&C!tazr@g z<-1uf!X6^3uo8`8qV?^Xh4 `kPGGuU|L4CGI8lY!k$3V<(&mZ=vuiQ_1>{KXa9cXfFTd%-}Uu3 z=-eu?G_^6^Cr_T_E>CT&t{w|WNlh0FT3K=!#q57+KLSvztG}P;b**8@T?%EkSc8~A z`O-&ghD?7UUgx&d=aP~Pmh~eF?Hc@ny#REmoHu+F!TA|mXsiv^F~s_vuK^fAC+akh zC6sQrjnXWVvAaiBOMnOq4<8&J-d{&&qq!fu8pmq!NFuzPoOXSHPnVwyRE2PcJ1`c{ zL*q|LlCCb}9*!4)Z4(|Io}ik@HS$_mG7Jc*+n^A{f%fp520x|-Pr|w#46xM* zs({9C%oc<&rR{>^wyvnCNUh_kdJsOh7IVO;m7oF-B(%IzRaGrZbXCOoF!TaCJs%yN zkzRa(xUTv&0O!Xi%3oaV!bbfMMIc*usdu@JqHU4TtGu#xaL5Pi0mb3b(N$x9ekVrI zG6!_5ATbjy7+a_0ES0RBsn9Rdc5yjuhs#PUlj-x_h{B83kF;WdFH;VlSUNK7RT*N9 z!&_t1)0g)kpS5Lm%YBGWuHx64dDHQHcoFQ25(xHkiBx#ZKI1;;zkCczSO#&wk467Y(R6D5`Sa%uoSQy?UOTKGc!aCv z_hOSc)%xD-KYEB9aMR$+7zlyXSGh)G2T+BI5(H6`N@aWq4-FlJII;DI$hc$UoI!>= zcd`phOLqfN!)*mwcrENG%%9MJ~90wVXMj+`)c|?pTO*7FLUi2o075K zXAN#nl)jB*@@s(XJG>7Ktxd^WJN}B9$CE?iBf4QU)O251xYbU$#DZ#B-T$5e^$l@S zoL_(bc>OftlaRZ^>=$^Po=*2MFK_yh<}hpeO0FKsTeg2K2<0MH_Uk4X1A9tC{ste&9B8yq7P6QBv|E z55Dz*8FJ!@s6R66+{aG%HbSL#IoUR^qOx+tj@J&BFP^OwJq#6Z@L7SQbEfg*F#rT;m&!@*A^BCv8%UzwL#&aRd(j| z4g>qGa6QNP1(BxXJPkU+Ha`23vBLN+h8F>`c21thFJ4)@|ELk9vd6OH?yb|;*FQuY zN99=qyng=R{lZojJ12}ae1w?Ed5Zlgyy}nTT2%O1lLYN=%$|;JSDs69_zC_b;ojr+ z6Z%g-I9MoflB!f=>vns{orVt>Fp9i)^uo$_%)KyR#IU9z9GKwMVPi z{M{+FK0kj26LE&syMG69I}rO!pE#s#Fzlre7{il+uk(>KeK%- zrnC7oElhatNj`JglCjF23-p#rN(>w!9^sSk61Fk_6in-LGPDpmqQL4}w2Ri3PQwzY zMwB(-Z6_dV&eml>Zbu6OP8MGz`3d9>}I@X9-4;;yFjx?B3}?v2uE>W2Mjm;Ou{D}B=Zx~FP>KE%38+RPm|9T1Crrb zYp96P)rs^9`l#(>ePDLI(}^P3^jl{cH|-r!d1#npdzWnHMYb?vUyXgov~&LHL~2$@ z=4o?{OZ-0Km<^C}yiTKY=(u71rYK$@&7_nDBV0O9r_ddikH^$C9K@4M#vUfrQo#)7&J2QKJ^gJXPh)k=F4}+#d)`i`ZNF5GT)me`cqVVyD3EjR z-{_lNALQ~#3_L6uQN-YEqTmY3IuV4spQl26(5|;Ydsupa#fG8zgC@f z)DVQoigGbisSM2Eq$4Okx%<-duXp}$KnyK3h#=C-G`L`g!o)pZwvmB+BG}@(eX#Z6+zD^Zw8yc#;Cb2Q-WaU5Bwd#Q09`zK$%uC zZamkS5O{BWdfHeFkZ9e6-Zwp)F4ZKguC;p4zjDVc_L}PidhyDxCg5M*skb9Hr&}1Y zbH(0?;&X6!56GPSh=s3;6MHs0h|mul2y0F9f?E^^6ogT7UVTV#a6if7mlA42=crvQ z_lWCS^<;5@3bH#hjJTKgu!tOmBA;Lj7wFE*j2uyMcHAiqE5|TMrDLt(1GF(0*qj)+ zTSw32XQ_$%v{Y9Uw8~tuqAYwmSP2ow_k1ZWVta1mS7P|9UuE;x-7JuGUPYc0HK#gm ze>WG%f}*zqop-nq&yzHNzJX`h^`aVl%%!-ru|}wW-$t`%o1_eFPpH0MLwGZGY4e2I zItZ@}k0+?buE6@GC<)=cKr6r*D zyp?3aqLVz^d>b!VyIMu#$<5KuSUlCC)YwJ7Qu3FYHLlPvs7-7hLjD(}^z-Ve6u2ck zhD)>fSOW3Q7>%-J$~WM5xj#Q75&dqkbLD_2QErw)^${qUy?BtRYr|Q$?@1>^>wEiQ z=DVB-pEqyb#H!^RXzJ^GIDi5_r){p_A{oK0$7IL;py^mrbI0den|*F7zyFWxv-ud+ zyCm%7-GpS?%_apF5s!-IUy~*&^NK!4p0gTe8H=H9jgE5t^E4 zfI6#6eeh660TvnunHf!;D|_87;=IR(up%wu+6!BrEy~i ziX0>GwCBE(vN&2J60wjm2}or&jgn3z+554_u;)9#;yw%{-;XhFuZQek=WZ>hw9 zJN`2;arar8NeA>1YY5?>M`ZyR6X2UYhDf>`FuI>t0y2)U$Y8o6_wWATJSg}QZD{F- zCVLCG$gxd`y@NNTdLbRfhHfT@~05t0&m!OC;_uwXDVhGrh)2hI*IPr$ZH;Yc?46y)XQr{U)_ z7cx%OU9y?(T6jVN^VtoVnR5*k+mqRo0Qq91?pdCmb&Bu>1-7Q*yd~2~R zZ$ulZLNH!hVvn+8CkT#deCBhb3LXSsu6_B4jZtb!imlh-#0v+<`af^*TTjW6qwMjC z85vDHY-}sJ(pM(~ne6yLa|VytT%g~BK#Us`t$Rl9Aa%3(CN6)l)G(OOBLSFU0BHeC zQ5Vpf$DuPNT_6rSho;kuabrk>{kHX==g38Kb8|8taA4X)b^Py-{QwOWl?gn*do+?B z+Liqco`C!^val@80`Fn(=hMd*y;H)daZmIs!w3pMWgk6l?fqGRU2m0)g+tyR+EykG z^Yk8O;Mg6@-{xQbyBz@lkkc>K`!A>Q&j@qNb+4^ne$q9iqYNyWpPw&rKq>bHQ(HJ?Ph(9Mmi7+qVZNCPJa{ z6QOzUq-vSQXNmz1c3a@PbU8mh>n6yLDo8x9Br}W!f5H~L>cQJ-vFk<=^y6oZFm$xp zR94q4Wth@lB!T_JjH`Bae^Wps-wV##<1ZycQ>& zzn5(-#=*n0H37@>3Br>H`HoKJ^VeF3YZ?qjW;uiJVC5fz8~YD8v#lY8_-Fy1tza?> zq~z6~o}CF{tQTI}!3Zvo5RD3d9HC+f{&nee5vO@fDD3I?r`;ANK7al!+3Na8?Wz9p zc?#lNxR2kDB|b%Z-}^`ju0$+7|BLq+G7tmU4}|E2K|nwN2W!k)*MQIE9yz`M71LYY zdweuKo=m|8UEn0W{J!>Diq$GwHXt1ThV~f3?L&3}M*7MJOgB=Q%81EFdndWK_?cqr z4n_^=w>CE$uRsgJM;%!M|Ihlh_80w5j%QPLRh<4ZDCOclL?VU>dGOxSrOu}$@@9L4 z1D`b6w~zT0^V z3~1icRsu<10f~VHnFr>;ZveBn5ne`yQAH5l%0na~J(U?YpLL$<8Jh-dVLDRzKD2pp zN3Ww1F%E>ZEgI!D2gS@9IAyJ@FW#DnV4WA&Z#ko_!^#cD4rxDBT1asHhM5_!Z>1n+ z#}EQo{ew4g4Yf%!lQ9{vn?tDnBxv+mw#E#P!i4Y^02z8|myN`sJ5xw)bO@oVSQ<3J zx0&wT5isHz6Q}8%FxQU268P`41wPr!DwD(!Lu|x9({XoC)OhNfh*9<%+LVaoGDd$Vw zZszpk(h!hmc%xfY1?Xzh(5v^lQVTH!>Xd@vU;4y_wucjUk{;)NJXx^$+H80 zyG3l#K2?t2?jJqoz)xH9tk!vn78YzRPeS+_IATnJt5fg6a^0O?KuQqK5`B8d_x8{Z zf)UO?7Z$F|ACI{((E7D{$NnJk)Y!s_GWZewljlBX&kYs4_!qA{JWkmF!EnMT2u4VR z%{`}KmVG9sd2v%+qICUJetM5n{U0WAC*UplQu?+)BULsZKrA)B4bdo};wfL5lyp`L z7=)9CaLpUp;;iP$3Pjmz+=?$otG`w5-<~=C9*K#G$q&TqLx4qa4c_jwTq}j7yVktC zJYhVM#bB*nseJr-WeNn~@;d+;NP}L3o^(|2)1sd~Ypsp#%zp%LDy96H_sVVX3bhdi zICvWKuB@QD@CFCE76eUUIMN4Wj$2{)B;2oCM*fsOpCg_@GuRTPEz9g!8e}hoQwHu4 zmN!8GNX{;J>rgX?Q_}HV)cDC0*W`s7`?+M4I5}?C<>M%sXv{DSl9Z$*Q8QpfUjgo% z1P%T%O&eb+4551l`ufY|+{!;N&8ctz+UfeWcoTV!}Zo!!s|-;TzhyDzY6d3`AkwU`@H{D17-CL!KuMoeNojC244C`qkBm zm2%FDwy3Q{OS0ee&A>da+CR}C3jz_@9Oz45K})!J#K}7)cSBGT%EBA5KhI0X48HH3 z^F$B{=}wxUZU+-TDkW>i#+Lb1in(@ufJ}S2-Xi&<;rI&f;#5h-pY!K z1`hW}x2V(}b!nccQU>qwPiZgnSf-SaNpo{@KCrc2N4K6A#JEDcc*%6Q__Ex=wrUN? zS#tjq8C9}ba$kzro%ampA7ohZ^))UYW5104C>wn&qDYGBv)mi-l$yDKn@A$~F$6)Q zF({S0_mr!khuQCpA5l*xtV81~$+=8WFQYR_Mj@*FRrWuvjTy>zq;W?rH{B=1B`!k; z;6F@E3$Ne2IVchcU{M;37SC7;rG1PwHfextCjUZ3QsyT}b4@5z;+{YNjkXM9qk=Oy z*E`{FDpB>DHYmCkpiaC}Bfh9(?}XYF|MBO_VL>dZ-mp__IG zc6R22r~5h`L740IIRyCy>}D(QbVl7I(%Yzv>fXibabHV__2+O3b!=YR4#uAk_atf1 z!HbgcBMT3f(%PCVKzJwTZNqa%VSRn-xJHPb>C&)qd1~>h9G7TY8B3ROAlCY(3m7V`)Cg8F{nAxPk^c7=gLOvdsLnXTQ~$YpXX zzL{FPJ!AQrxnqKX<6lKU1`K*uyLNg*`IOVJ6KjJMD{=_;2QOv!nSk$$6Xd z;#kz-)f{t){MJsk$tB6{TkO^qvHm%F-SUFEnGsy#<~t+As3osV|Jyd$x*gXvnKW)y zwpug)Rpi7NW6?WRx}b>r>m0p&nPf8JT6jF|MqZTgc-$m`oZHO3;Mo!l#>uvCbBCjn zyBo?b5K|OCCiXdtg1p>wk)+tieEd-b*J+#CzvwzL4Ik9lpok3b$_o`BUI-;%tRdOE z*}|Njm(}u7(GEgQe9+yjoE&2Kevw3Egj0i(*x178a?_9e%WV#gV){=Ck{r4!9P#h) z5%}y@-%!3$A)5@oNdbzhClLwq$KR3zk9I3Uf=;EGgZv0&c84d&2l0C_wF6%mn-cl@ zlw`<&IjF@+hx|dU{3 zJ?m|medZd-l+TeQ;dl$#a>d1S*(C6_7$<3G#^s!sj+e=Zjgl-0UV(~Gl2?-}eqiGN EKVH2_NB{r; literal 0 HcmV?d00001 diff --git a/doc/img/ecore-pos-map.eps b/doc/img/ecore-pos-map.eps new file mode 100644 index 0000000..bdc98db --- /dev/null +++ b/doc/img/ecore-pos-map.eps @@ -0,0 +1,5750 @@ +%!PS-Adobe-3.1 EPSF-3.0 +%ADO_DSC_Encoding: MacOS Roman +%%Title: diagramas_01-18.eps +%%Creator: Adobe Illustrator(R) 14.0 +%%For: Marina Proni +%%CreationDate: 7/7/11 +%%BoundingBox: 0 0 622 652 +%%HiResBoundingBox: 0 0 621.7319 651.9883 +%%CropBox: 0 0 621.7319 651.9883 +%%LanguageLevel: 2 +%%DocumentData: Clean7Bit +%ADOBeginClientInjection: DocumentHeader "AI11EPS" +%%AI8_CreatorVersion: 14.0.0 %AI9_PrintingDataBegin %ADO_BuildNumber: Adobe Illustrator(R) 14.0.0 x367 R agm 4.4890 ct 5.1541 %ADO_ContainsXMP: MainFirst +%ADOEndClientInjection: DocumentHeader "AI11EPS" +%%Pages: 1 +%%DocumentNeededResources: +%%DocumentSuppliedResources: procset Adobe_AGM_Image 1.0 0 +%%+ procset Adobe_CoolType_Utility_T42 1.0 0 +%%+ procset Adobe_CoolType_Utility_MAKEOCF 1.23 0 +%%+ procset Adobe_CoolType_Core 2.31 0 +%%+ procset Adobe_AGM_Core 2.0 0 +%%+ procset Adobe_AGM_Utils 1.0 0 +%%DocumentFonts: +%%DocumentNeededFonts: +%%DocumentNeededFeatures: +%%DocumentSuppliedFeatures: +%%DocumentProcessColors: Cyan Magenta Yellow Black +%%DocumentCustomColors: +%%CMYKCustomColor: +%%RGBCustomColor: +%%EndComments + + + + + + +%%BeginDefaults +%%ViewingOrientation: 1 0 0 1 +%%EndDefaults +%%BeginProlog +%%BeginResource: procset Adobe_AGM_Utils 1.0 0 +%%Version: 1.0 0 +%%Copyright: Copyright(C)2000-2006 Adobe Systems, Inc. All Rights Reserved. +systemdict/setpacking known +{currentpacking true setpacking}if +userdict/Adobe_AGM_Utils 75 dict dup begin put +/bdf +{bind def}bind def +/nd{null def}bdf +/xdf +{exch def}bdf +/ldf +{load def}bdf +/ddf +{put}bdf +/xddf +{3 -1 roll put}bdf +/xpt +{exch put}bdf +/ndf +{ + exch dup where{ + pop pop pop + }{ + xdf + }ifelse +}def +/cdndf +{ + exch dup currentdict exch known{ + pop pop + }{ + exch def + }ifelse +}def +/gx +{get exec}bdf +/ps_level + /languagelevel where{ + pop systemdict/languagelevel gx + }{ + 1 + }ifelse +def +/level2 + ps_level 2 ge +def +/level3 + ps_level 3 ge +def +/ps_version + {version cvr}stopped{-1}if +def +/set_gvm +{currentglobal exch setglobal}bdf +/reset_gvm +{setglobal}bdf +/makereadonlyarray +{ + /packedarray where{pop packedarray + }{ + array astore readonly}ifelse +}bdf +/map_reserved_ink_name +{ + dup type/stringtype eq{ + dup/Red eq{ + pop(_Red_) + }{ + dup/Green eq{ + pop(_Green_) + }{ + dup/Blue eq{ + pop(_Blue_) + }{ + dup()cvn eq{ + pop(Process) + }if + }ifelse + }ifelse + }ifelse + }if +}bdf +/AGMUTIL_GSTATE 22 dict def +/get_gstate +{ + AGMUTIL_GSTATE begin + /AGMUTIL_GSTATE_clr_spc currentcolorspace def + /AGMUTIL_GSTATE_clr_indx 0 def + /AGMUTIL_GSTATE_clr_comps 12 array def + mark currentcolor counttomark + {AGMUTIL_GSTATE_clr_comps AGMUTIL_GSTATE_clr_indx 3 -1 roll put + /AGMUTIL_GSTATE_clr_indx AGMUTIL_GSTATE_clr_indx 1 add def}repeat pop + /AGMUTIL_GSTATE_fnt rootfont def + /AGMUTIL_GSTATE_lw currentlinewidth def + /AGMUTIL_GSTATE_lc currentlinecap def + /AGMUTIL_GSTATE_lj currentlinejoin def + /AGMUTIL_GSTATE_ml currentmiterlimit def + currentdash/AGMUTIL_GSTATE_do xdf/AGMUTIL_GSTATE_da xdf + /AGMUTIL_GSTATE_sa currentstrokeadjust def + /AGMUTIL_GSTATE_clr_rnd currentcolorrendering def + /AGMUTIL_GSTATE_op currentoverprint def + /AGMUTIL_GSTATE_bg currentblackgeneration cvlit def + /AGMUTIL_GSTATE_ucr currentundercolorremoval cvlit def + currentcolortransfer cvlit/AGMUTIL_GSTATE_gy_xfer xdf cvlit/AGMUTIL_GSTATE_b_xfer xdf + cvlit/AGMUTIL_GSTATE_g_xfer xdf cvlit/AGMUTIL_GSTATE_r_xfer xdf + /AGMUTIL_GSTATE_ht currenthalftone def + /AGMUTIL_GSTATE_flt currentflat def + end +}def +/set_gstate +{ + AGMUTIL_GSTATE begin + AGMUTIL_GSTATE_clr_spc setcolorspace + AGMUTIL_GSTATE_clr_indx{AGMUTIL_GSTATE_clr_comps AGMUTIL_GSTATE_clr_indx 1 sub get + /AGMUTIL_GSTATE_clr_indx AGMUTIL_GSTATE_clr_indx 1 sub def}repeat setcolor + AGMUTIL_GSTATE_fnt setfont + AGMUTIL_GSTATE_lw setlinewidth + AGMUTIL_GSTATE_lc setlinecap + AGMUTIL_GSTATE_lj setlinejoin + AGMUTIL_GSTATE_ml setmiterlimit + AGMUTIL_GSTATE_da AGMUTIL_GSTATE_do setdash + AGMUTIL_GSTATE_sa setstrokeadjust + AGMUTIL_GSTATE_clr_rnd setcolorrendering + AGMUTIL_GSTATE_op setoverprint + AGMUTIL_GSTATE_bg cvx setblackgeneration + AGMUTIL_GSTATE_ucr cvx setundercolorremoval + AGMUTIL_GSTATE_r_xfer cvx AGMUTIL_GSTATE_g_xfer cvx AGMUTIL_GSTATE_b_xfer cvx + AGMUTIL_GSTATE_gy_xfer cvx setcolortransfer + AGMUTIL_GSTATE_ht/HalftoneType get dup 9 eq exch 100 eq or + { + currenthalftone/HalftoneType get AGMUTIL_GSTATE_ht/HalftoneType get ne + { + mark AGMUTIL_GSTATE_ht{sethalftone}stopped cleartomark + }if + }{ + AGMUTIL_GSTATE_ht sethalftone + }ifelse + AGMUTIL_GSTATE_flt setflat + end +}def +/get_gstate_and_matrix +{ + AGMUTIL_GSTATE begin + /AGMUTIL_GSTATE_ctm matrix currentmatrix def + end + get_gstate +}def +/set_gstate_and_matrix +{ + set_gstate + AGMUTIL_GSTATE begin + AGMUTIL_GSTATE_ctm setmatrix + end +}def +/AGMUTIL_str256 256 string def +/AGMUTIL_src256 256 string def +/AGMUTIL_dst64 64 string def +/AGMUTIL_srcLen nd +/AGMUTIL_ndx nd +/AGMUTIL_cpd nd +/capture_cpd{ + //Adobe_AGM_Utils/AGMUTIL_cpd currentpagedevice ddf +}def +/thold_halftone +{ + level3 + {sethalftone currenthalftone} + { + dup/HalftoneType get 3 eq + { + sethalftone currenthalftone + }{ + begin + Width Height mul{ + Thresholds read{pop}if + }repeat + end + currenthalftone + }ifelse + }ifelse +}def +/rdcmntline +{ + currentfile AGMUTIL_str256 readline pop + (%)anchorsearch{pop}if +}bdf +/filter_cmyk +{ + dup type/filetype ne{ + exch()/SubFileDecode filter + }{ + exch pop + } + ifelse + [ + exch + { + AGMUTIL_src256 readstring pop + dup length/AGMUTIL_srcLen exch def + /AGMUTIL_ndx 0 def + AGMCORE_plate_ndx 4 AGMUTIL_srcLen 1 sub{ + 1 index exch get + AGMUTIL_dst64 AGMUTIL_ndx 3 -1 roll put + /AGMUTIL_ndx AGMUTIL_ndx 1 add def + }for + pop + AGMUTIL_dst64 0 AGMUTIL_ndx getinterval + } + bind + /exec cvx + ]cvx +}bdf +/filter_indexed_devn +{ + cvi Names length mul names_index add Lookup exch get +}bdf +/filter_devn +{ + 4 dict begin + /srcStr xdf + /dstStr xdf + dup type/filetype ne{ + 0()/SubFileDecode filter + }if + [ + exch + [ + /devicen_colorspace_dict/AGMCORE_gget cvx/begin cvx + currentdict/srcStr get/readstring cvx/pop cvx + /dup cvx/length cvx 0/gt cvx[ + Adobe_AGM_Utils/AGMUTIL_ndx 0/ddf cvx + names_index Names length currentdict/srcStr get length 1 sub{ + 1/index cvx/exch cvx/get cvx + currentdict/dstStr get/AGMUTIL_ndx/load cvx 3 -1/roll cvx/put cvx + Adobe_AGM_Utils/AGMUTIL_ndx/AGMUTIL_ndx/load cvx 1/add cvx/ddf cvx + }for + currentdict/dstStr get 0/AGMUTIL_ndx/load cvx/getinterval cvx + ]cvx/if cvx + /end cvx + ]cvx + bind + /exec cvx + ]cvx + end +}bdf +/AGMUTIL_imagefile nd +/read_image_file +{ + AGMUTIL_imagefile 0 setfileposition + 10 dict begin + /imageDict xdf + /imbufLen Width BitsPerComponent mul 7 add 8 idiv def + /imbufIdx 0 def + /origDataSource imageDict/DataSource get def + /origMultipleDataSources imageDict/MultipleDataSources get def + /origDecode imageDict/Decode get def + /dstDataStr imageDict/Width get colorSpaceElemCnt mul string def + imageDict/MultipleDataSources known{MultipleDataSources}{false}ifelse + { + /imbufCnt imageDict/DataSource get length def + /imbufs imbufCnt array def + 0 1 imbufCnt 1 sub{ + /imbufIdx xdf + imbufs imbufIdx imbufLen string put + imageDict/DataSource get imbufIdx[AGMUTIL_imagefile imbufs imbufIdx get/readstring cvx/pop cvx]cvx put + }for + DeviceN_PS2{ + imageDict begin + /DataSource[DataSource/devn_sep_datasource cvx]cvx def + /MultipleDataSources false def + /Decode[0 1]def + end + }if + }{ + /imbuf imbufLen string def + Indexed_DeviceN level3 not and DeviceN_NoneName or{ + /srcDataStrs[imageDict begin + currentdict/MultipleDataSources known{MultipleDataSources{DataSource length}{1}ifelse}{1}ifelse + { + Width Decode length 2 div mul cvi string + }repeat + end]def + imageDict begin + /DataSource[AGMUTIL_imagefile Decode BitsPerComponent false 1/filter_indexed_devn load dstDataStr srcDataStrs devn_alt_datasource/exec cvx]cvx def + /Decode[0 1]def + end + }{ + imageDict/DataSource[1 string dup 0 AGMUTIL_imagefile Decode length 2 idiv string/readstring cvx/pop cvx names_index/get cvx/put cvx]cvx put + imageDict/Decode[0 1]put + }ifelse + }ifelse + imageDict exch + load exec + imageDict/DataSource origDataSource put + imageDict/MultipleDataSources origMultipleDataSources put + imageDict/Decode origDecode put + end +}bdf +/write_image_file +{ + begin + {(AGMUTIL_imagefile)(w+)file}stopped{ + false + }{ + Adobe_AGM_Utils/AGMUTIL_imagefile xddf + 2 dict begin + /imbufLen Width BitsPerComponent mul 7 add 8 idiv def + MultipleDataSources{DataSource 0 get}{DataSource}ifelse type/filetype eq{ + /imbuf imbufLen string def + }if + 1 1 Height MultipleDataSources not{Decode length 2 idiv mul}if{ + pop + MultipleDataSources{ + 0 1 DataSource length 1 sub{ + DataSource type dup + /arraytype eq{ + pop DataSource exch gx + }{ + /filetype eq{ + DataSource exch get imbuf readstring pop + }{ + DataSource exch get + }ifelse + }ifelse + AGMUTIL_imagefile exch writestring + }for + }{ + DataSource type dup + /arraytype eq{ + pop DataSource exec + }{ + /filetype eq{ + DataSource imbuf readstring pop + }{ + DataSource + }ifelse + }ifelse + AGMUTIL_imagefile exch writestring + }ifelse + }for + end + true + }ifelse + end +}bdf +/close_image_file +{ + AGMUTIL_imagefile closefile(AGMUTIL_imagefile)deletefile +}def +statusdict/product known userdict/AGMP_current_show known not and{ + /pstr statusdict/product get def + pstr(HP LaserJet 2200)eq + pstr(HP LaserJet 4000 Series)eq or + pstr(HP LaserJet 4050 Series )eq or + pstr(HP LaserJet 8000 Series)eq or + pstr(HP LaserJet 8100 Series)eq or + pstr(HP LaserJet 8150 Series)eq or + pstr(HP LaserJet 5000 Series)eq or + pstr(HP LaserJet 5100 Series)eq or + pstr(HP Color LaserJet 4500)eq or + pstr(HP Color LaserJet 4600)eq or + pstr(HP LaserJet 5Si)eq or + pstr(HP LaserJet 1200 Series)eq or + pstr(HP LaserJet 1300 Series)eq or + pstr(HP LaserJet 4100 Series)eq or + { + userdict/AGMP_current_show/show load put + userdict/show{ + currentcolorspace 0 get + /Pattern eq + {false charpath f} + {AGMP_current_show}ifelse + }put + }if + currentdict/pstr undef +}if +/consumeimagedata +{ + begin + AGMIMG_init_common + currentdict/MultipleDataSources known not + {/MultipleDataSources false def}if + MultipleDataSources + { + DataSource 0 get type + dup/filetype eq + { + 1 dict begin + /flushbuffer Width cvi string def + 1 1 Height cvi + { + pop + 0 1 DataSource length 1 sub + { + DataSource exch get + flushbuffer readstring pop pop + }for + }for + end + }if + dup/arraytype eq exch/packedarraytype eq or DataSource 0 get xcheck and + { + Width Height mul cvi + { + 0 1 DataSource length 1 sub + {dup DataSource exch gx length exch 0 ne{pop}if}for + dup 0 eq + {pop exit}if + sub dup 0 le + {exit}if + }loop + pop + }if + } + { + /DataSource load type + dup/filetype eq + { + 1 dict begin + /flushbuffer Width Decode length 2 idiv mul cvi string def + 1 1 Height{pop DataSource flushbuffer readstring pop pop}for + end + }if + dup/arraytype eq exch/packedarraytype eq or/DataSource load xcheck and + { + Height Width BitsPerComponent mul 8 BitsPerComponent sub add 8 idiv Decode length 2 idiv mul mul + { + DataSource length dup 0 eq + {pop exit}if + sub dup 0 le + {exit}if + }loop + pop + }if + }ifelse + end +}bdf +/addprocs +{ + 2{/exec load}repeat + 3 1 roll + [5 1 roll]bind cvx +}def +/modify_halftone_xfer +{ + currenthalftone dup length dict copy begin + currentdict 2 index known{ + 1 index load dup length dict copy begin + currentdict/TransferFunction known{ + /TransferFunction load + }{ + currenttransfer + }ifelse + addprocs/TransferFunction xdf + currentdict end def + currentdict end sethalftone + }{ + currentdict/TransferFunction known{ + /TransferFunction load + }{ + currenttransfer + }ifelse + addprocs/TransferFunction xdf + currentdict end sethalftone + pop + }ifelse +}def +/clonearray +{ + dup xcheck exch + dup length array exch + Adobe_AGM_Core/AGMCORE_tmp -1 ddf + { + Adobe_AGM_Core/AGMCORE_tmp 2 copy get 1 add ddf + dup type/dicttype eq + { + Adobe_AGM_Core/AGMCORE_tmp get + exch + clonedict + Adobe_AGM_Core/AGMCORE_tmp 4 -1 roll ddf + }if + dup type/arraytype eq + { + Adobe_AGM_Core/AGMCORE_tmp get exch + clonearray + Adobe_AGM_Core/AGMCORE_tmp 4 -1 roll ddf + }if + exch dup + Adobe_AGM_Core/AGMCORE_tmp get 4 -1 roll put + }forall + exch{cvx}if +}bdf +/clonedict +{ + dup length dict + begin + { + dup type/dicttype eq + {clonedict}if + dup type/arraytype eq + {clonearray}if + def + }forall + currentdict + end +}bdf +/DeviceN_PS2 +{ + /currentcolorspace AGMCORE_gget 0 get/DeviceN eq level3 not and +}bdf +/Indexed_DeviceN +{ + /indexed_colorspace_dict AGMCORE_gget dup null ne{ + dup/CSDBase known{ + /CSDBase get/CSD get_res/Names known + }{ + pop false + }ifelse + }{ + pop false + }ifelse +}bdf +/DeviceN_NoneName +{ + /Names where{ + pop + false Names + { + (None)eq or + }forall + }{ + false + }ifelse +}bdf +/DeviceN_PS2_inRip_seps +{ + /AGMCORE_in_rip_sep where + { + pop dup type dup/arraytype eq exch/packedarraytype eq or + { + dup 0 get/DeviceN eq level3 not and AGMCORE_in_rip_sep and + { + /currentcolorspace exch AGMCORE_gput + false + }{ + true + }ifelse + }{ + true + }ifelse + }{ + true + }ifelse +}bdf +/base_colorspace_type +{ + dup type/arraytype eq{0 get}if +}bdf +/currentdistillerparams where{pop currentdistillerparams/CoreDistVersion get 5000 lt}{true}ifelse +{ + /pdfmark_5{cleartomark}bind def +}{ + /pdfmark_5{pdfmark}bind def +}ifelse +/ReadBypdfmark_5 +{ + currentfile exch 0 exch/SubFileDecode filter + /currentdistillerparams where + {pop currentdistillerparams/CoreDistVersion get 5000 lt}{true}ifelse + {flushfile cleartomark} + {/PUT pdfmark}ifelse +}bdf +/ReadBypdfmark_5_string +{ + 2 dict begin + /makerString exch def string/tmpString exch def + { + currentfile tmpString readline not{pop exit}if + makerString anchorsearch + { + pop pop cleartomark exit + }{ + 3 copy/PUT pdfmark_5 pop 2 copy(\n)/PUT pdfmark_5 + }ifelse + }loop + end +}bdf +/xpdfm +{ + { + dup 0 get/Label eq + { + aload length[exch 1 add 1 roll/PAGELABEL + }{ + aload pop + [{ThisPage}<<5 -2 roll>>/PUT + }ifelse + pdfmark_5 + }forall +}bdf +/lmt{ + dup 2 index le{exch}if pop dup 2 index ge{exch}if pop +}bdf +/int{ + dup 2 index sub 3 index 5 index sub div 6 -2 roll sub mul exch pop add exch pop +}bdf +/ds{ + Adobe_AGM_Utils begin +}bdf +/dt{ + currentdict Adobe_AGM_Utils eq{ + end + }if +}bdf +systemdict/setpacking known +{setpacking}if +%%EndResource +%%BeginResource: procset Adobe_AGM_Core 2.0 0 +%%Version: 2.0 0 +%%Copyright: Copyright(C)1997-2007 Adobe Systems, Inc. All Rights Reserved. +systemdict/setpacking known +{ + currentpacking + true setpacking +}if +userdict/Adobe_AGM_Core 209 dict dup begin put +/Adobe_AGM_Core_Id/Adobe_AGM_Core_2.0_0 def +/AGMCORE_str256 256 string def +/AGMCORE_save nd +/AGMCORE_graphicsave nd +/AGMCORE_c 0 def +/AGMCORE_m 0 def +/AGMCORE_y 0 def +/AGMCORE_k 0 def +/AGMCORE_cmykbuf 4 array def +/AGMCORE_screen[currentscreen]cvx def +/AGMCORE_tmp 0 def +/AGMCORE_&setgray nd +/AGMCORE_&setcolor nd +/AGMCORE_&setcolorspace nd +/AGMCORE_&setcmykcolor nd +/AGMCORE_cyan_plate nd +/AGMCORE_magenta_plate nd +/AGMCORE_yellow_plate nd +/AGMCORE_black_plate nd +/AGMCORE_plate_ndx nd +/AGMCORE_get_ink_data nd +/AGMCORE_is_cmyk_sep nd +/AGMCORE_host_sep nd +/AGMCORE_avoid_L2_sep_space nd +/AGMCORE_distilling nd +/AGMCORE_composite_job nd +/AGMCORE_producing_seps nd +/AGMCORE_ps_level -1 def +/AGMCORE_ps_version -1 def +/AGMCORE_environ_ok nd +/AGMCORE_CSD_cache 0 dict def +/AGMCORE_currentoverprint false def +/AGMCORE_deltaX nd +/AGMCORE_deltaY nd +/AGMCORE_name nd +/AGMCORE_sep_special nd +/AGMCORE_err_strings 4 dict def +/AGMCORE_cur_err nd +/AGMCORE_current_spot_alias false def +/AGMCORE_inverting false def +/AGMCORE_feature_dictCount nd +/AGMCORE_feature_opCount nd +/AGMCORE_feature_ctm nd +/AGMCORE_ConvertToProcess false def +/AGMCORE_Default_CTM matrix def +/AGMCORE_Default_PageSize nd +/AGMCORE_Default_flatness nd +/AGMCORE_currentbg nd +/AGMCORE_currentucr nd +/AGMCORE_pattern_paint_type 0 def +/knockout_unitsq nd +currentglobal true setglobal +[/CSA/Gradient/Procedure] +{ + /Generic/Category findresource dup length dict copy/Category defineresource pop +}forall +setglobal +/AGMCORE_key_known +{ + where{ + /Adobe_AGM_Core_Id known + }{ + false + }ifelse +}ndf +/flushinput +{ + save + 2 dict begin + /CompareBuffer 3 -1 roll def + /readbuffer 256 string def + mark + { + currentfile readbuffer{readline}stopped + {cleartomark mark} + { + not + {pop exit} + if + CompareBuffer eq + {exit} + if + }ifelse + }loop + cleartomark + end + restore +}bdf +/getspotfunction +{ + AGMCORE_screen exch pop exch pop + dup type/dicttype eq{ + dup/HalftoneType get 1 eq{ + /SpotFunction get + }{ + dup/HalftoneType get 2 eq{ + /GraySpotFunction get + }{ + pop + { + abs exch abs 2 copy add 1 gt{ + 1 sub dup mul exch 1 sub dup mul add 1 sub + }{ + dup mul exch dup mul add 1 exch sub + }ifelse + }bind + }ifelse + }ifelse + }if +}def +/np +{newpath}bdf +/clp_npth +{clip np}def +/eoclp_npth +{eoclip np}def +/npth_clp +{np clip}def +/graphic_setup +{ + /AGMCORE_graphicsave save store + concat + 0 setgray + 0 setlinecap + 0 setlinejoin + 1 setlinewidth + []0 setdash + 10 setmiterlimit + np + false setoverprint + false setstrokeadjust + //Adobe_AGM_Core/spot_alias gx + /Adobe_AGM_Image where{ + pop + Adobe_AGM_Image/spot_alias 2 copy known{ + gx + }{ + pop pop + }ifelse + }if + /sep_colorspace_dict null AGMCORE_gput + 100 dict begin + /dictstackcount countdictstack def + /showpage{}def + mark +}def +/graphic_cleanup +{ + cleartomark + dictstackcount 1 countdictstack 1 sub{end}for + end + AGMCORE_graphicsave restore +}def +/compose_error_msg +{ + grestoreall initgraphics + /Helvetica findfont 10 scalefont setfont + /AGMCORE_deltaY 100 def + /AGMCORE_deltaX 310 def + clippath pathbbox np pop pop 36 add exch 36 add exch moveto + 0 AGMCORE_deltaY rlineto AGMCORE_deltaX 0 rlineto + 0 AGMCORE_deltaY neg rlineto AGMCORE_deltaX neg 0 rlineto closepath + 0 AGMCORE_&setgray + gsave 1 AGMCORE_&setgray fill grestore + 1 setlinewidth gsave stroke grestore + currentpoint AGMCORE_deltaY 15 sub add exch 8 add exch moveto + /AGMCORE_deltaY 12 def + /AGMCORE_tmp 0 def + AGMCORE_err_strings exch get + { + dup 32 eq + { + pop + AGMCORE_str256 0 AGMCORE_tmp getinterval + stringwidth pop currentpoint pop add AGMCORE_deltaX 28 add gt + { + currentpoint AGMCORE_deltaY sub exch pop + clippath pathbbox pop pop pop 44 add exch moveto + }if + AGMCORE_str256 0 AGMCORE_tmp getinterval show( )show + 0 1 AGMCORE_str256 length 1 sub + { + AGMCORE_str256 exch 0 put + }for + /AGMCORE_tmp 0 def + }{ + AGMCORE_str256 exch AGMCORE_tmp xpt + /AGMCORE_tmp AGMCORE_tmp 1 add def + }ifelse + }forall +}bdf +/AGMCORE_CMYKDeviceNColorspaces[ + [/Separation/None/DeviceCMYK{0 0 0}] + [/Separation(Black)/DeviceCMYK{0 0 0 4 -1 roll}bind] + [/Separation(Yellow)/DeviceCMYK{0 0 3 -1 roll 0}bind] + [/DeviceN[(Yellow)(Black)]/DeviceCMYK{0 0 4 2 roll}bind] + [/Separation(Magenta)/DeviceCMYK{0 exch 0 0}bind] + [/DeviceN[(Magenta)(Black)]/DeviceCMYK{0 3 1 roll 0 exch}bind] + [/DeviceN[(Magenta)(Yellow)]/DeviceCMYK{0 3 1 roll 0}bind] + [/DeviceN[(Magenta)(Yellow)(Black)]/DeviceCMYK{0 4 1 roll}bind] + [/Separation(Cyan)/DeviceCMYK{0 0 0}] + [/DeviceN[(Cyan)(Black)]/DeviceCMYK{0 0 3 -1 roll}bind] + [/DeviceN[(Cyan)(Yellow)]/DeviceCMYK{0 exch 0}bind] + [/DeviceN[(Cyan)(Yellow)(Black)]/DeviceCMYK{0 3 1 roll}bind] + [/DeviceN[(Cyan)(Magenta)]/DeviceCMYK{0 0}] + [/DeviceN[(Cyan)(Magenta)(Black)]/DeviceCMYK{0 exch}bind] + [/DeviceN[(Cyan)(Magenta)(Yellow)]/DeviceCMYK{0}] + [/DeviceCMYK] +]def +/ds{ + Adobe_AGM_Core begin + /currentdistillerparams where + { + pop currentdistillerparams/CoreDistVersion get 5000 lt + {<>setdistillerparams}if + }if + /AGMCORE_ps_version xdf + /AGMCORE_ps_level xdf + errordict/AGM_handleerror known not{ + errordict/AGM_handleerror errordict/handleerror get put + errordict/handleerror{ + Adobe_AGM_Core begin + $error/newerror get AGMCORE_cur_err null ne and{ + $error/newerror false put + AGMCORE_cur_err compose_error_msg + }if + $error/newerror true put + end + errordict/AGM_handleerror get exec + }bind put + }if + /AGMCORE_environ_ok + ps_level AGMCORE_ps_level ge + ps_version AGMCORE_ps_version ge and + AGMCORE_ps_level -1 eq or + def + AGMCORE_environ_ok not + {/AGMCORE_cur_err/AGMCORE_bad_environ def}if + /AGMCORE_&setgray systemdict/setgray get def + level2{ + /AGMCORE_&setcolor systemdict/setcolor get def + /AGMCORE_&setcolorspace systemdict/setcolorspace get def + }if + /AGMCORE_currentbg currentblackgeneration def + /AGMCORE_currentucr currentundercolorremoval def + /AGMCORE_Default_flatness currentflat def + /AGMCORE_distilling + /product where{ + pop systemdict/setdistillerparams known product(Adobe PostScript Parser)ne and + }{ + false + }ifelse + def + /AGMCORE_GSTATE AGMCORE_key_known not{ + /AGMCORE_GSTATE 21 dict def + /AGMCORE_tmpmatrix matrix def + /AGMCORE_gstack 32 array def + /AGMCORE_gstackptr 0 def + /AGMCORE_gstacksaveptr 0 def + /AGMCORE_gstackframekeys 14 def + /AGMCORE_&gsave/gsave ldf + /AGMCORE_&grestore/grestore ldf + /AGMCORE_&grestoreall/grestoreall ldf + /AGMCORE_&save/save ldf + /AGMCORE_&setoverprint/setoverprint ldf + /AGMCORE_gdictcopy{ + begin + {def}forall + end + }def + /AGMCORE_gput{ + AGMCORE_gstack AGMCORE_gstackptr get + 3 1 roll + put + }def + /AGMCORE_gget{ + AGMCORE_gstack AGMCORE_gstackptr get + exch + get + }def + /gsave{ + AGMCORE_&gsave + AGMCORE_gstack AGMCORE_gstackptr get + AGMCORE_gstackptr 1 add + dup 32 ge{limitcheck}if + /AGMCORE_gstackptr exch store + AGMCORE_gstack AGMCORE_gstackptr get + AGMCORE_gdictcopy + }def + /grestore{ + AGMCORE_&grestore + AGMCORE_gstackptr 1 sub + dup AGMCORE_gstacksaveptr lt{1 add}if + dup AGMCORE_gstack exch get dup/AGMCORE_currentoverprint known + {/AGMCORE_currentoverprint get setoverprint}{pop}ifelse + /AGMCORE_gstackptr exch store + }def + /grestoreall{ + AGMCORE_&grestoreall + /AGMCORE_gstackptr AGMCORE_gstacksaveptr store + }def + /save{ + AGMCORE_&save + AGMCORE_gstack AGMCORE_gstackptr get + AGMCORE_gstackptr 1 add + dup 32 ge{limitcheck}if + /AGMCORE_gstackptr exch store + /AGMCORE_gstacksaveptr AGMCORE_gstackptr store + AGMCORE_gstack AGMCORE_gstackptr get + AGMCORE_gdictcopy + }def + /setoverprint{ + dup/AGMCORE_currentoverprint exch AGMCORE_gput AGMCORE_&setoverprint + }def + 0 1 AGMCORE_gstack length 1 sub{ + AGMCORE_gstack exch AGMCORE_gstackframekeys dict put + }for + }if + level3/AGMCORE_&sysshfill AGMCORE_key_known not and + { + /AGMCORE_&sysshfill systemdict/shfill get def + /AGMCORE_&sysmakepattern systemdict/makepattern get def + /AGMCORE_&usrmakepattern/makepattern load def + }if + /currentcmykcolor[0 0 0 0]AGMCORE_gput + /currentstrokeadjust false AGMCORE_gput + /currentcolorspace[/DeviceGray]AGMCORE_gput + /sep_tint 0 AGMCORE_gput + /devicen_tints[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]AGMCORE_gput + /sep_colorspace_dict null AGMCORE_gput + /devicen_colorspace_dict null AGMCORE_gput + /indexed_colorspace_dict null AGMCORE_gput + /currentcolor_intent()AGMCORE_gput + /customcolor_tint 1 AGMCORE_gput + /absolute_colorimetric_crd null AGMCORE_gput + /relative_colorimetric_crd null AGMCORE_gput + /saturation_crd null AGMCORE_gput + /perceptual_crd null AGMCORE_gput + currentcolortransfer cvlit/AGMCore_gray_xfer xdf cvlit/AGMCore_b_xfer xdf + cvlit/AGMCore_g_xfer xdf cvlit/AGMCore_r_xfer xdf + << + /MaxPatternItem currentsystemparams/MaxPatternCache get + >> + setuserparams + end +}def +/ps +{ + /setcmykcolor where{ + pop + Adobe_AGM_Core/AGMCORE_&setcmykcolor/setcmykcolor load put + }if + Adobe_AGM_Core begin + /setcmykcolor + { + 4 copy AGMCORE_cmykbuf astore/currentcmykcolor exch AGMCORE_gput + 1 sub 4 1 roll + 3{ + 3 index add neg dup 0 lt{ + pop 0 + }if + 3 1 roll + }repeat + setrgbcolor pop + }ndf + /currentcmykcolor + { + /currentcmykcolor AGMCORE_gget aload pop + }ndf + /setoverprint + {pop}ndf + /currentoverprint + {false}ndf + /AGMCORE_cyan_plate 1 0 0 0 test_cmyk_color_plate def + /AGMCORE_magenta_plate 0 1 0 0 test_cmyk_color_plate def + /AGMCORE_yellow_plate 0 0 1 0 test_cmyk_color_plate def + /AGMCORE_black_plate 0 0 0 1 test_cmyk_color_plate def + /AGMCORE_plate_ndx + AGMCORE_cyan_plate{ + 0 + }{ + AGMCORE_magenta_plate{ + 1 + }{ + AGMCORE_yellow_plate{ + 2 + }{ + AGMCORE_black_plate{ + 3 + }{ + 4 + }ifelse + }ifelse + }ifelse + }ifelse + def + /AGMCORE_have_reported_unsupported_color_space false def + /AGMCORE_report_unsupported_color_space + { + AGMCORE_have_reported_unsupported_color_space false eq + { + (Warning: Job contains content that cannot be separated with on-host methods. This content appears on the black plate, and knocks out all other plates.)== + Adobe_AGM_Core/AGMCORE_have_reported_unsupported_color_space true ddf + }if + }def + /AGMCORE_composite_job + AGMCORE_cyan_plate AGMCORE_magenta_plate and AGMCORE_yellow_plate and AGMCORE_black_plate and def + /AGMCORE_in_rip_sep + /AGMCORE_in_rip_sep where{ + pop AGMCORE_in_rip_sep + }{ + AGMCORE_distilling + { + false + }{ + userdict/Adobe_AGM_OnHost_Seps known{ + false + }{ + level2{ + currentpagedevice/Separations 2 copy known{ + get + }{ + pop pop false + }ifelse + }{ + false + }ifelse + }ifelse + }ifelse + }ifelse + def + /AGMCORE_producing_seps AGMCORE_composite_job not AGMCORE_in_rip_sep or def + /AGMCORE_host_sep AGMCORE_producing_seps AGMCORE_in_rip_sep not and def + /AGM_preserve_spots + /AGM_preserve_spots where{ + pop AGM_preserve_spots + }{ + AGMCORE_distilling AGMCORE_producing_seps or + }ifelse + def + /AGM_is_distiller_preserving_spotimages + { + currentdistillerparams/PreserveOverprintSettings known + { + currentdistillerparams/PreserveOverprintSettings get + { + currentdistillerparams/ColorConversionStrategy known + { + currentdistillerparams/ColorConversionStrategy get + /sRGB ne + }{ + true + }ifelse + }{ + false + }ifelse + }{ + false + }ifelse + }def + /convert_spot_to_process where{pop}{ + /convert_spot_to_process + { + //Adobe_AGM_Core begin + dup map_alias{ + /Name get exch pop + }if + dup dup(None)eq exch(All)eq or + { + pop false + }{ + AGMCORE_host_sep + { + gsave + 1 0 0 0 setcmykcolor currentgray 1 exch sub + 0 1 0 0 setcmykcolor currentgray 1 exch sub + 0 0 1 0 setcmykcolor currentgray 1 exch sub + 0 0 0 1 setcmykcolor currentgray 1 exch sub + add add add 0 eq + { + pop false + }{ + false setoverprint + current_spot_alias false set_spot_alias + 1 1 1 1 6 -1 roll findcmykcustomcolor 1 setcustomcolor + set_spot_alias + currentgray 1 ne + }ifelse + grestore + }{ + AGMCORE_distilling + { + pop AGM_is_distiller_preserving_spotimages not + }{ + //Adobe_AGM_Core/AGMCORE_name xddf + false + //Adobe_AGM_Core/AGMCORE_pattern_paint_type get 0 eq + AGMUTIL_cpd/OverrideSeparations known and + { + AGMUTIL_cpd/OverrideSeparations get + { + /HqnSpots/ProcSet resourcestatus + { + pop pop pop true + }if + }if + }if + { + AGMCORE_name/HqnSpots/ProcSet findresource/TestSpot gx not + }{ + gsave + [/Separation AGMCORE_name/DeviceGray{}]AGMCORE_&setcolorspace + false + AGMUTIL_cpd/SeparationColorNames 2 copy known + { + get + {AGMCORE_name eq or}forall + not + }{ + pop pop pop true + }ifelse + grestore + }ifelse + }ifelse + }ifelse + }ifelse + end + }def + }ifelse + /convert_to_process where{pop}{ + /convert_to_process + { + dup length 0 eq + { + pop false + }{ + AGMCORE_host_sep + { + dup true exch + { + dup(Cyan)eq exch + dup(Magenta)eq 3 -1 roll or exch + dup(Yellow)eq 3 -1 roll or exch + dup(Black)eq 3 -1 roll or + {pop} + {convert_spot_to_process and}ifelse + } + forall + { + true exch + { + dup(Cyan)eq exch + dup(Magenta)eq 3 -1 roll or exch + dup(Yellow)eq 3 -1 roll or exch + (Black)eq or and + }forall + not + }{pop false}ifelse + }{ + false exch + { + /PhotoshopDuotoneList where{pop false}{true}ifelse + { + dup(Cyan)eq exch + dup(Magenta)eq 3 -1 roll or exch + dup(Yellow)eq 3 -1 roll or exch + dup(Black)eq 3 -1 roll or + {pop} + {convert_spot_to_process or}ifelse + } + { + convert_spot_to_process or + } + ifelse + } + forall + }ifelse + }ifelse + }def + }ifelse + /AGMCORE_avoid_L2_sep_space + version cvr 2012 lt + level2 and + AGMCORE_producing_seps not and + def + /AGMCORE_is_cmyk_sep + AGMCORE_cyan_plate AGMCORE_magenta_plate or AGMCORE_yellow_plate or AGMCORE_black_plate or + def + /AGM_avoid_0_cmyk where{ + pop AGM_avoid_0_cmyk + }{ + AGM_preserve_spots + userdict/Adobe_AGM_OnHost_Seps known + userdict/Adobe_AGM_InRip_Seps known or + not and + }ifelse + { + /setcmykcolor[ + { + 4 copy add add add 0 eq currentoverprint and{ + pop 0.0005 + }if + }/exec cvx + /AGMCORE_&setcmykcolor load dup type/operatortype ne{ + /exec cvx + }if + ]cvx def + }if + /AGMCORE_IsSeparationAProcessColor + { + dup(Cyan)eq exch dup(Magenta)eq exch dup(Yellow)eq exch(Black)eq or or or + }def + AGMCORE_host_sep{ + /setcolortransfer + { + AGMCORE_cyan_plate{ + pop pop pop + }{ + AGMCORE_magenta_plate{ + 4 3 roll pop pop pop + }{ + AGMCORE_yellow_plate{ + 4 2 roll pop pop pop + }{ + 4 1 roll pop pop pop + }ifelse + }ifelse + }ifelse + settransfer + } + def + /AGMCORE_get_ink_data + AGMCORE_cyan_plate{ + {pop pop pop} + }{ + AGMCORE_magenta_plate{ + {4 3 roll pop pop pop} + }{ + AGMCORE_yellow_plate{ + {4 2 roll pop pop pop} + }{ + {4 1 roll pop pop pop} + }ifelse + }ifelse + }ifelse + def + /AGMCORE_RemoveProcessColorNames + { + 1 dict begin + /filtername + { + dup/Cyan eq 1 index(Cyan)eq or + {pop(_cyan_)}if + dup/Magenta eq 1 index(Magenta)eq or + {pop(_magenta_)}if + dup/Yellow eq 1 index(Yellow)eq or + {pop(_yellow_)}if + dup/Black eq 1 index(Black)eq or + {pop(_black_)}if + }def + dup type/arraytype eq + {[exch{filtername}forall]} + {filtername}ifelse + end + }def + level3{ + /AGMCORE_IsCurrentColor + { + dup AGMCORE_IsSeparationAProcessColor + { + AGMCORE_plate_ndx 0 eq + {dup(Cyan)eq exch/Cyan eq or}if + AGMCORE_plate_ndx 1 eq + {dup(Magenta)eq exch/Magenta eq or}if + AGMCORE_plate_ndx 2 eq + {dup(Yellow)eq exch/Yellow eq or}if + AGMCORE_plate_ndx 3 eq + {dup(Black)eq exch/Black eq or}if + AGMCORE_plate_ndx 4 eq + {pop false}if + }{ + gsave + false setoverprint + current_spot_alias false set_spot_alias + 1 1 1 1 6 -1 roll findcmykcustomcolor 1 setcustomcolor + set_spot_alias + currentgray 1 ne + grestore + }ifelse + }def + /AGMCORE_filter_functiondatasource + { + 5 dict begin + /data_in xdf + data_in type/stringtype eq + { + /ncomp xdf + /comp xdf + /string_out data_in length ncomp idiv string def + 0 ncomp data_in length 1 sub + { + string_out exch dup ncomp idiv exch data_in exch ncomp getinterval comp get 255 exch sub put + }for + string_out + }{ + string/string_in xdf + /string_out 1 string def + /component xdf + [ + data_in string_in/readstring cvx + [component/get cvx 255/exch cvx/sub cvx string_out/exch cvx 0/exch cvx/put cvx string_out]cvx + [/pop cvx()]cvx/ifelse cvx + ]cvx/ReusableStreamDecode filter + }ifelse + end + }def + /AGMCORE_separateShadingFunction + { + 2 dict begin + /paint? xdf + /channel xdf + dup type/dicttype eq + { + begin + FunctionType 0 eq + { + /DataSource channel Range length 2 idiv DataSource AGMCORE_filter_functiondatasource def + currentdict/Decode known + {/Decode Decode channel 2 mul 2 getinterval def}if + paint? not + {/Decode[1 1]def}if + }if + FunctionType 2 eq + { + paint? + { + /C0[C0 channel get 1 exch sub]def + /C1[C1 channel get 1 exch sub]def + }{ + /C0[1]def + /C1[1]def + }ifelse + }if + FunctionType 3 eq + { + /Functions[Functions{channel paint? AGMCORE_separateShadingFunction}forall]def + }if + currentdict/Range known + {/Range[0 1]def}if + currentdict + end}{ + channel get 0 paint? AGMCORE_separateShadingFunction + }ifelse + end + }def + /AGMCORE_separateShading + { + 3 -1 roll begin + currentdict/Function known + { + currentdict/Background known + {[1 index{Background 3 index get 1 exch sub}{1}ifelse]/Background xdf}if + Function 3 1 roll AGMCORE_separateShadingFunction/Function xdf + /ColorSpace[/DeviceGray]def + }{ + ColorSpace dup type/arraytype eq{0 get}if/DeviceCMYK eq + { + /ColorSpace[/DeviceN[/_cyan_/_magenta_/_yellow_/_black_]/DeviceCMYK{}]def + }{ + ColorSpace dup 1 get AGMCORE_RemoveProcessColorNames 1 exch put + }ifelse + ColorSpace 0 get/Separation eq + { + { + [1/exch cvx/sub cvx]cvx + }{ + [/pop cvx 1]cvx + }ifelse + ColorSpace 3 3 -1 roll put + pop + }{ + { + [exch ColorSpace 1 get length 1 sub exch sub/index cvx 1/exch cvx/sub cvx ColorSpace 1 get length 1 add 1/roll cvx ColorSpace 1 get length{/pop cvx}repeat]cvx + }{ + pop[ColorSpace 1 get length{/pop cvx}repeat cvx 1]cvx + }ifelse + ColorSpace 3 3 -1 roll bind put + }ifelse + ColorSpace 2/DeviceGray put + }ifelse + end + }def + /AGMCORE_separateShadingDict + { + dup/ColorSpace get + dup type/arraytype ne + {[exch]}if + dup 0 get/DeviceCMYK eq + { + exch begin + currentdict + AGMCORE_cyan_plate + {0 true}if + AGMCORE_magenta_plate + {1 true}if + AGMCORE_yellow_plate + {2 true}if + AGMCORE_black_plate + {3 true}if + AGMCORE_plate_ndx 4 eq + {0 false}if + dup not currentoverprint and + {/AGMCORE_ignoreshade true def}if + AGMCORE_separateShading + currentdict + end exch + }if + dup 0 get/Separation eq + { + exch begin + ColorSpace 1 get dup/None ne exch/All ne and + { + ColorSpace 1 get AGMCORE_IsCurrentColor AGMCORE_plate_ndx 4 lt and ColorSpace 1 get AGMCORE_IsSeparationAProcessColor not and + { + ColorSpace 2 get dup type/arraytype eq{0 get}if/DeviceCMYK eq + { + /ColorSpace + [ + /Separation + ColorSpace 1 get + /DeviceGray + [ + ColorSpace 3 get/exec cvx + 4 AGMCORE_plate_ndx sub -1/roll cvx + 4 1/roll cvx + 3[/pop cvx]cvx/repeat cvx + 1/exch cvx/sub cvx + ]cvx + ]def + }{ + AGMCORE_report_unsupported_color_space + AGMCORE_black_plate not + { + currentdict 0 false AGMCORE_separateShading + }if + }ifelse + }{ + currentdict ColorSpace 1 get AGMCORE_IsCurrentColor + 0 exch + dup not currentoverprint and + {/AGMCORE_ignoreshade true def}if + AGMCORE_separateShading + }ifelse + }if + currentdict + end exch + }if + dup 0 get/DeviceN eq + { + exch begin + ColorSpace 1 get convert_to_process + { + ColorSpace 2 get dup type/arraytype eq{0 get}if/DeviceCMYK eq + { + /ColorSpace + [ + /DeviceN + ColorSpace 1 get + /DeviceGray + [ + ColorSpace 3 get/exec cvx + 4 AGMCORE_plate_ndx sub -1/roll cvx + 4 1/roll cvx + 3[/pop cvx]cvx/repeat cvx + 1/exch cvx/sub cvx + ]cvx + ]def + }{ + AGMCORE_report_unsupported_color_space + AGMCORE_black_plate not + { + currentdict 0 false AGMCORE_separateShading + /ColorSpace[/DeviceGray]def + }if + }ifelse + }{ + currentdict + false -1 ColorSpace 1 get + { + AGMCORE_IsCurrentColor + { + 1 add + exch pop true exch exit + }if + 1 add + }forall + exch + dup not currentoverprint and + {/AGMCORE_ignoreshade true def}if + AGMCORE_separateShading + }ifelse + currentdict + end exch + }if + dup 0 get dup/DeviceCMYK eq exch dup/Separation eq exch/DeviceN eq or or not + { + exch begin + ColorSpace dup type/arraytype eq + {0 get}if + /DeviceGray ne + { + AGMCORE_report_unsupported_color_space + AGMCORE_black_plate not + { + ColorSpace 0 get/CIEBasedA eq + { + /ColorSpace[/Separation/_ciebaseda_/DeviceGray{}]def + }if + ColorSpace 0 get dup/CIEBasedABC eq exch dup/CIEBasedDEF eq exch/DeviceRGB eq or or + { + /ColorSpace[/DeviceN[/_red_/_green_/_blue_]/DeviceRGB{}]def + }if + ColorSpace 0 get/CIEBasedDEFG eq + { + /ColorSpace[/DeviceN[/_cyan_/_magenta_/_yellow_/_black_]/DeviceCMYK{}]def + }if + currentdict 0 false AGMCORE_separateShading + }if + }if + currentdict + end exch + }if + pop + dup/AGMCORE_ignoreshade known + { + begin + /ColorSpace[/Separation(None)/DeviceGray{}]def + currentdict end + }if + }def + /shfill + { + AGMCORE_separateShadingDict + dup/AGMCORE_ignoreshade known + {pop} + {AGMCORE_&sysshfill}ifelse + }def + /makepattern + { + exch + dup/PatternType get 2 eq + { + clonedict + begin + /Shading Shading AGMCORE_separateShadingDict def + Shading/AGMCORE_ignoreshade known + currentdict end exch + {pop<>}if + exch AGMCORE_&sysmakepattern + }{ + exch AGMCORE_&usrmakepattern + }ifelse + }def + }if + }if + AGMCORE_in_rip_sep{ + /setcustomcolor + { + exch aload pop + dup 7 1 roll inRip_spot_has_ink not { + 4{4 index mul 4 1 roll} + repeat + /DeviceCMYK setcolorspace + 6 -2 roll pop pop + }{ + //Adobe_AGM_Core begin + /AGMCORE_k xdf/AGMCORE_y xdf/AGMCORE_m xdf/AGMCORE_c xdf + end + [/Separation 4 -1 roll/DeviceCMYK + {dup AGMCORE_c mul exch dup AGMCORE_m mul exch dup AGMCORE_y mul exch AGMCORE_k mul} + ] + setcolorspace + }ifelse + setcolor + }ndf + /setseparationgray + { + [/Separation(All)/DeviceGray{}]setcolorspace_opt + 1 exch sub setcolor + }ndf + }{ + /setseparationgray + { + AGMCORE_&setgray + }ndf + }ifelse + /findcmykcustomcolor + { + 5 makereadonlyarray + }ndf + /setcustomcolor + { + exch aload pop pop + 4{4 index mul 4 1 roll}repeat + setcmykcolor pop + }ndf + /has_color + /colorimage where{ + AGMCORE_producing_seps{ + pop true + }{ + systemdict eq + }ifelse + }{ + false + }ifelse + def + /map_index + { + 1 index mul exch getinterval{255 div}forall + }bdf + /map_indexed_devn + { + Lookup Names length 3 -1 roll cvi map_index + }bdf + /n_color_components + { + base_colorspace_type + dup/DeviceGray eq{ + pop 1 + }{ + /DeviceCMYK eq{ + 4 + }{ + 3 + }ifelse + }ifelse + }bdf + level2{ + /mo/moveto ldf + /li/lineto ldf + /cv/curveto ldf + /knockout_unitsq + { + 1 setgray + 0 0 1 1 rectfill + }def + level2/setcolorspace AGMCORE_key_known not and{ + /AGMCORE_&&&setcolorspace/setcolorspace ldf + /AGMCORE_ReplaceMappedColor + { + dup type dup/arraytype eq exch/packedarraytype eq or + { + /AGMCORE_SpotAliasAry2 where{ + begin + dup 0 get dup/Separation eq + { + pop + dup length array copy + dup dup 1 get + current_spot_alias + { + dup map_alias + { + false set_spot_alias + dup 1 exch setsepcolorspace + true set_spot_alias + begin + /sep_colorspace_dict currentdict AGMCORE_gput + pop pop pop + [ + /Separation Name + CSA map_csa + MappedCSA + /sep_colorspace_proc load + ] + dup Name + end + }if + }if + map_reserved_ink_name 1 xpt + }{ + /DeviceN eq + { + dup length array copy + dup dup 1 get[ + exch{ + current_spot_alias{ + dup map_alias{ + /Name get exch pop + }if + }if + map_reserved_ink_name + }forall + ]1 xpt + }if + }ifelse + end + }if + }if + }def + /setcolorspace + { + dup type dup/arraytype eq exch/packedarraytype eq or + { + dup 0 get/Indexed eq + { + AGMCORE_distilling + { + /PhotoshopDuotoneList where + { + pop false + }{ + true + }ifelse + }{ + true + }ifelse + { + aload pop 3 -1 roll + AGMCORE_ReplaceMappedColor + 3 1 roll 4 array astore + }if + }{ + AGMCORE_ReplaceMappedColor + }ifelse + }if + DeviceN_PS2_inRip_seps{AGMCORE_&&&setcolorspace}if + }def + }if + }{ + /adj + { + currentstrokeadjust{ + transform + 0.25 sub round 0.25 add exch + 0.25 sub round 0.25 add exch + itransform + }if + }def + /mo{ + adj moveto + }def + /li{ + adj lineto + }def + /cv{ + 6 2 roll adj + 6 2 roll adj + 6 2 roll adj curveto + }def + /knockout_unitsq + { + 1 setgray + 8 8 1[8 0 0 8 0 0]{}image + }def + /currentstrokeadjust{ + /currentstrokeadjust AGMCORE_gget + }def + /setstrokeadjust{ + /currentstrokeadjust exch AGMCORE_gput + }def + /setcolorspace + { + /currentcolorspace exch AGMCORE_gput + }def + /currentcolorspace + { + /currentcolorspace AGMCORE_gget + }def + /setcolor_devicecolor + { + base_colorspace_type + dup/DeviceGray eq{ + pop setgray + }{ + /DeviceCMYK eq{ + setcmykcolor + }{ + setrgbcolor + }ifelse + }ifelse + }def + /setcolor + { + currentcolorspace 0 get + dup/DeviceGray ne{ + dup/DeviceCMYK ne{ + dup/DeviceRGB ne{ + dup/Separation eq{ + pop + currentcolorspace 3 gx + currentcolorspace 2 get + }{ + dup/Indexed eq{ + pop + currentcolorspace 3 get dup type/stringtype eq{ + currentcolorspace 1 get n_color_components + 3 -1 roll map_index + }{ + exec + }ifelse + currentcolorspace 1 get + }{ + /AGMCORE_cur_err/AGMCORE_invalid_color_space def + AGMCORE_invalid_color_space + }ifelse + }ifelse + }if + }if + }if + setcolor_devicecolor + }def + }ifelse + /sop/setoverprint ldf + /lw/setlinewidth ldf + /lc/setlinecap ldf + /lj/setlinejoin ldf + /ml/setmiterlimit ldf + /dsh/setdash ldf + /sadj/setstrokeadjust ldf + /gry/setgray ldf + /rgb/setrgbcolor ldf + /cmyk[ + /currentcolorspace[/DeviceCMYK]/AGMCORE_gput cvx + /setcmykcolor load dup type/operatortype ne{/exec cvx}if + ]cvx bdf + level3 AGMCORE_host_sep not and{ + /nzopmsc{ + 6 dict begin + /kk exch def + /yy exch def + /mm exch def + /cc exch def + /sum 0 def + cc 0 ne{/sum sum 2#1000 or def cc}if + mm 0 ne{/sum sum 2#0100 or def mm}if + yy 0 ne{/sum sum 2#0010 or def yy}if + kk 0 ne{/sum sum 2#0001 or def kk}if + AGMCORE_CMYKDeviceNColorspaces sum get setcolorspace + sum 0 eq{0}if + end + setcolor + }bdf + }{ + /nzopmsc/cmyk ldf + }ifelse + /sep/setsepcolor ldf + /devn/setdevicencolor ldf + /idx/setindexedcolor ldf + /colr/setcolor ldf + /csacrd/set_csa_crd ldf + /sepcs/setsepcolorspace ldf + /devncs/setdevicencolorspace ldf + /idxcs/setindexedcolorspace ldf + /cp/closepath ldf + /clp/clp_npth ldf + /eclp/eoclp_npth ldf + /f/fill ldf + /ef/eofill ldf + /@/stroke ldf + /nclp/npth_clp ldf + /gset/graphic_setup ldf + /gcln/graphic_cleanup ldf + /ct/concat ldf + /cf/currentfile ldf + /fl/filter ldf + /rs/readstring ldf + /AGMCORE_def_ht currenthalftone def + /clonedict Adobe_AGM_Utils begin/clonedict load end def + /clonearray Adobe_AGM_Utils begin/clonearray load end def + currentdict{ + dup xcheck 1 index type dup/arraytype eq exch/packedarraytype eq or and{ + bind + }if + def + }forall + /getrampcolor + { + /indx exch def + 0 1 NumComp 1 sub + { + dup + Samples exch get + dup type/stringtype eq{indx get}if + exch + Scaling exch get aload pop + 3 1 roll + mul add + }for + ColorSpaceFamily/Separation eq + {sep} + { + ColorSpaceFamily/DeviceN eq + {devn}{setcolor}ifelse + }ifelse + }bdf + /sssetbackground{ + aload pop + ColorSpaceFamily/Separation eq + {sep} + { + ColorSpaceFamily/DeviceN eq + {devn}{setcolor}ifelse + }ifelse + }bdf + /RadialShade + { + 40 dict begin + /ColorSpaceFamily xdf + /background xdf + /ext1 xdf + /ext0 xdf + /BBox xdf + /r2 xdf + /c2y xdf + /c2x xdf + /r1 xdf + /c1y xdf + /c1x xdf + /rampdict xdf + /setinkoverprint where{pop/setinkoverprint{pop}def}if + gsave + BBox length 0 gt + { + np + BBox 0 get BBox 1 get moveto + BBox 2 get BBox 0 get sub 0 rlineto + 0 BBox 3 get BBox 1 get sub rlineto + BBox 2 get BBox 0 get sub neg 0 rlineto + closepath + clip + np + }if + c1x c2x eq + { + c1y c2y lt{/theta 90 def}{/theta 270 def}ifelse + }{ + /slope c2y c1y sub c2x c1x sub div def + /theta slope 1 atan def + c2x c1x lt c2y c1y ge and{/theta theta 180 sub def}if + c2x c1x lt c2y c1y lt and{/theta theta 180 add def}if + }ifelse + gsave + clippath + c1x c1y translate + theta rotate + -90 rotate + {pathbbox}stopped + {0 0 0 0}if + /yMax xdf + /xMax xdf + /yMin xdf + /xMin xdf + grestore + xMax xMin eq yMax yMin eq or + { + grestore + end + }{ + /max{2 copy gt{pop}{exch pop}ifelse}bdf + /min{2 copy lt{pop}{exch pop}ifelse}bdf + rampdict begin + 40 dict begin + background length 0 gt{background sssetbackground gsave clippath fill grestore}if + gsave + c1x c1y translate + theta rotate + -90 rotate + /c2y c1x c2x sub dup mul c1y c2y sub dup mul add sqrt def + /c1y 0 def + /c1x 0 def + /c2x 0 def + ext0 + { + 0 getrampcolor + c2y r2 add r1 sub 0.0001 lt + { + c1x c1y r1 360 0 arcn + pathbbox + /aymax exch def + /axmax exch def + /aymin exch def + /axmin exch def + /bxMin xMin axmin min def + /byMin yMin aymin min def + /bxMax xMax axmax max def + /byMax yMax aymax max def + bxMin byMin moveto + bxMax byMin lineto + bxMax byMax lineto + bxMin byMax lineto + bxMin byMin lineto + eofill + }{ + c2y r1 add r2 le + { + c1x c1y r1 0 360 arc + fill + } + { + c2x c2y r2 0 360 arc fill + r1 r2 eq + { + /p1x r1 neg def + /p1y c1y def + /p2x r1 def + /p2y c1y def + p1x p1y moveto p2x p2y lineto p2x yMin lineto p1x yMin lineto + fill + }{ + /AA r2 r1 sub c2y div def + AA -1 eq + {/theta 89.99 def} + {/theta AA 1 AA dup mul sub sqrt div 1 atan def} + ifelse + /SS1 90 theta add dup sin exch cos div def + /p1x r1 SS1 SS1 mul SS1 SS1 mul 1 add div sqrt mul neg def + /p1y p1x SS1 div neg def + /SS2 90 theta sub dup sin exch cos div def + /p2x r1 SS2 SS2 mul SS2 SS2 mul 1 add div sqrt mul def + /p2y p2x SS2 div neg def + r1 r2 gt + { + /L1maxX p1x yMin p1y sub SS1 div add def + /L2maxX p2x yMin p2y sub SS2 div add def + }{ + /L1maxX 0 def + /L2maxX 0 def + }ifelse + p1x p1y moveto p2x p2y lineto L2maxX L2maxX p2x sub SS2 mul p2y add lineto + L1maxX L1maxX p1x sub SS1 mul p1y add lineto + fill + }ifelse + }ifelse + }ifelse + }if + c1x c2x sub dup mul + c1y c2y sub dup mul + add 0.5 exp + 0 dtransform + dup mul exch dup mul add 0.5 exp 72 div + 0 72 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt + 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt + 1 index 1 index lt{exch}if pop + /hires xdf + hires mul + /numpix xdf + /numsteps NumSamples def + /rampIndxInc 1 def + /subsampling false def + numpix 0 ne + { + NumSamples numpix div 0.5 gt + { + /numsteps numpix 2 div round cvi dup 1 le{pop 2}if def + /rampIndxInc NumSamples 1 sub numsteps div def + /subsampling true def + }if + }if + /xInc c2x c1x sub numsteps div def + /yInc c2y c1y sub numsteps div def + /rInc r2 r1 sub numsteps div def + /cx c1x def + /cy c1y def + /radius r1 def + np + xInc 0 eq yInc 0 eq rInc 0 eq and and + { + 0 getrampcolor + cx cy radius 0 360 arc + stroke + NumSamples 1 sub getrampcolor + cx cy radius 72 hires div add 0 360 arc + 0 setlinewidth + stroke + }{ + 0 + numsteps + { + dup + subsampling{round cvi}if + getrampcolor + cx cy radius 0 360 arc + /cx cx xInc add def + /cy cy yInc add def + /radius radius rInc add def + cx cy radius 360 0 arcn + eofill + rampIndxInc add + }repeat + pop + }ifelse + ext1 + { + c2y r2 add r1 lt + { + c2x c2y r2 0 360 arc + fill + }{ + c2y r1 add r2 sub 0.0001 le + { + c2x c2y r2 360 0 arcn + pathbbox + /aymax exch def + /axmax exch def + /aymin exch def + /axmin exch def + /bxMin xMin axmin min def + /byMin yMin aymin min def + /bxMax xMax axmax max def + /byMax yMax aymax max def + bxMin byMin moveto + bxMax byMin lineto + bxMax byMax lineto + bxMin byMax lineto + bxMin byMin lineto + eofill + }{ + c2x c2y r2 0 360 arc fill + r1 r2 eq + { + /p1x r2 neg def + /p1y c2y def + /p2x r2 def + /p2y c2y def + p1x p1y moveto p2x p2y lineto p2x yMax lineto p1x yMax lineto + fill + }{ + /AA r2 r1 sub c2y div def + AA -1 eq + {/theta 89.99 def} + {/theta AA 1 AA dup mul sub sqrt div 1 atan def} + ifelse + /SS1 90 theta add dup sin exch cos div def + /p1x r2 SS1 SS1 mul SS1 SS1 mul 1 add div sqrt mul neg def + /p1y c2y p1x SS1 div sub def + /SS2 90 theta sub dup sin exch cos div def + /p2x r2 SS2 SS2 mul SS2 SS2 mul 1 add div sqrt mul def + /p2y c2y p2x SS2 div sub def + r1 r2 lt + { + /L1maxX p1x yMax p1y sub SS1 div add def + /L2maxX p2x yMax p2y sub SS2 div add def + }{ + /L1maxX 0 def + /L2maxX 0 def + }ifelse + p1x p1y moveto p2x p2y lineto L2maxX L2maxX p2x sub SS2 mul p2y add lineto + L1maxX L1maxX p1x sub SS1 mul p1y add lineto + fill + }ifelse + }ifelse + }ifelse + }if + grestore + grestore + end + end + end + }ifelse + }bdf + /GenStrips + { + 40 dict begin + /ColorSpaceFamily xdf + /background xdf + /ext1 xdf + /ext0 xdf + /BBox xdf + /y2 xdf + /x2 xdf + /y1 xdf + /x1 xdf + /rampdict xdf + /setinkoverprint where{pop/setinkoverprint{pop}def}if + gsave + BBox length 0 gt + { + np + BBox 0 get BBox 1 get moveto + BBox 2 get BBox 0 get sub 0 rlineto + 0 BBox 3 get BBox 1 get sub rlineto + BBox 2 get BBox 0 get sub neg 0 rlineto + closepath + clip + np + }if + x1 x2 eq + { + y1 y2 lt{/theta 90 def}{/theta 270 def}ifelse + }{ + /slope y2 y1 sub x2 x1 sub div def + /theta slope 1 atan def + x2 x1 lt y2 y1 ge and{/theta theta 180 sub def}if + x2 x1 lt y2 y1 lt and{/theta theta 180 add def}if + } + ifelse + gsave + clippath + x1 y1 translate + theta rotate + {pathbbox}stopped + {0 0 0 0}if + /yMax exch def + /xMax exch def + /yMin exch def + /xMin exch def + grestore + xMax xMin eq yMax yMin eq or + { + grestore + end + }{ + rampdict begin + 20 dict begin + background length 0 gt{background sssetbackground gsave clippath fill grestore}if + gsave + x1 y1 translate + theta rotate + /xStart 0 def + /xEnd x2 x1 sub dup mul y2 y1 sub dup mul add 0.5 exp def + /ySpan yMax yMin sub def + /numsteps NumSamples def + /rampIndxInc 1 def + /subsampling false def + xStart 0 transform + xEnd 0 transform + 3 -1 roll + sub dup mul + 3 1 roll + sub dup mul + add 0.5 exp 72 div + 0 72 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt + 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt + 1 index 1 index lt{exch}if pop + mul + /numpix xdf + numpix 0 ne + { + NumSamples numpix div 0.5 gt + { + /numsteps numpix 2 div round cvi dup 1 le{pop 2}if def + /rampIndxInc NumSamples 1 sub numsteps div def + /subsampling true def + }if + }if + ext0 + { + 0 getrampcolor + xMin xStart lt + { + xMin yMin xMin neg ySpan rectfill + }if + }if + /xInc xEnd xStart sub numsteps div def + /x xStart def + 0 + numsteps + { + dup + subsampling{round cvi}if + getrampcolor + x yMin xInc ySpan rectfill + /x x xInc add def + rampIndxInc add + }repeat + pop + ext1{ + xMax xEnd gt + { + xEnd yMin xMax xEnd sub ySpan rectfill + }if + }if + grestore + grestore + end + end + end + }ifelse + }bdf +}def +/pt +{ + end +}def +/dt{ +}def +/pgsv{ + //Adobe_AGM_Core/AGMCORE_save save put +}def +/pgrs{ + //Adobe_AGM_Core/AGMCORE_save get restore +}def +systemdict/findcolorrendering known{ + /findcolorrendering systemdict/findcolorrendering get def +}if +systemdict/setcolorrendering known{ + /setcolorrendering systemdict/setcolorrendering get def +}if +/test_cmyk_color_plate +{ + gsave + setcmykcolor currentgray 1 ne + grestore +}def +/inRip_spot_has_ink +{ + dup//Adobe_AGM_Core/AGMCORE_name xddf + convert_spot_to_process not +}def +/map255_to_range +{ + 1 index sub + 3 -1 roll 255 div mul add +}def +/set_csa_crd +{ + /sep_colorspace_dict null AGMCORE_gput + begin + CSA get_csa_by_name setcolorspace_opt + set_crd + end +} +def +/map_csa +{ + currentdict/MappedCSA known{MappedCSA null ne}{false}ifelse + {pop}{get_csa_by_name/MappedCSA xdf}ifelse +}def +/setsepcolor +{ + /sep_colorspace_dict AGMCORE_gget begin + dup/sep_tint exch AGMCORE_gput + TintProc + end +}def +/setdevicencolor +{ + /devicen_colorspace_dict AGMCORE_gget begin + Names length copy + Names length 1 sub -1 0 + { + /devicen_tints AGMCORE_gget 3 1 roll xpt + }for + TintProc + end +}def +/sep_colorspace_proc +{ + /AGMCORE_tmp exch store + /sep_colorspace_dict AGMCORE_gget begin + currentdict/Components known{ + Components aload pop + TintMethod/Lab eq{ + 2{AGMCORE_tmp mul NComponents 1 roll}repeat + LMax sub AGMCORE_tmp mul LMax add NComponents 1 roll + }{ + TintMethod/Subtractive eq{ + NComponents{ + AGMCORE_tmp mul NComponents 1 roll + }repeat + }{ + NComponents{ + 1 sub AGMCORE_tmp mul 1 add NComponents 1 roll + }repeat + }ifelse + }ifelse + }{ + ColorLookup AGMCORE_tmp ColorLookup length 1 sub mul round cvi get + aload pop + }ifelse + end +}def +/sep_colorspace_gray_proc +{ + /AGMCORE_tmp exch store + /sep_colorspace_dict AGMCORE_gget begin + GrayLookup AGMCORE_tmp GrayLookup length 1 sub mul round cvi get + end +}def +/sep_proc_name +{ + dup 0 get + dup/DeviceRGB eq exch/DeviceCMYK eq or level2 not and has_color not and{ + pop[/DeviceGray] + /sep_colorspace_gray_proc + }{ + /sep_colorspace_proc + }ifelse +}def +/setsepcolorspace +{ + current_spot_alias{ + dup begin + Name map_alias{ + exch pop + }if + end + }if + dup/sep_colorspace_dict exch AGMCORE_gput + begin + CSA map_csa + /AGMCORE_sep_special Name dup()eq exch(All)eq or store + AGMCORE_avoid_L2_sep_space{ + [/Indexed MappedCSA sep_proc_name 255 exch + {255 div}/exec cvx 3 -1 roll[4 1 roll load/exec cvx]cvx + ]setcolorspace_opt + /TintProc{ + 255 mul round cvi setcolor + }bdf + }{ + MappedCSA 0 get/DeviceCMYK eq + currentdict/Components known and + AGMCORE_sep_special not and{ + /TintProc[ + Components aload pop Name findcmykcustomcolor + /exch cvx/setcustomcolor cvx + ]cvx bdf + }{ + AGMCORE_host_sep Name(All)eq and{ + /TintProc{ + 1 exch sub setseparationgray + }bdf + }{ + AGMCORE_in_rip_sep MappedCSA 0 get/DeviceCMYK eq and + AGMCORE_host_sep or + Name()eq and{ + /TintProc[ + MappedCSA sep_proc_name exch 0 get/DeviceCMYK eq{ + cvx/setcmykcolor cvx + }{ + cvx/setgray cvx + }ifelse + ]cvx bdf + }{ + AGMCORE_producing_seps MappedCSA 0 get dup/DeviceCMYK eq exch/DeviceGray eq or and AGMCORE_sep_special not and{ + /TintProc[ + /dup cvx + MappedCSA sep_proc_name cvx exch + 0 get/DeviceGray eq{ + 1/exch cvx/sub cvx 0 0 0 4 -1/roll cvx + }if + /Name cvx/findcmykcustomcolor cvx/exch cvx + AGMCORE_host_sep{ + AGMCORE_is_cmyk_sep + /Name cvx + /AGMCORE_IsSeparationAProcessColor load/exec cvx + /not cvx/and cvx + }{ + Name inRip_spot_has_ink not + }ifelse + [ + /pop cvx 1 + ]cvx/if cvx + /setcustomcolor cvx + ]cvx bdf + }{ + /TintProc{setcolor}bdf + [/Separation Name MappedCSA sep_proc_name load]setcolorspace_opt + }ifelse + }ifelse + }ifelse + }ifelse + }ifelse + set_crd + setsepcolor + end +}def +/additive_blend +{ + 3 dict begin + /numarrays xdf + /numcolors xdf + 0 1 numcolors 1 sub + { + /c1 xdf + 1 + 0 1 numarrays 1 sub + { + 1 exch add/index cvx + c1/get cvx/mul cvx + }for + numarrays 1 add 1/roll cvx + }for + numarrays[/pop cvx]cvx/repeat cvx + end +}def +/subtractive_blend +{ + 3 dict begin + /numarrays xdf + /numcolors xdf + 0 1 numcolors 1 sub + { + /c1 xdf + 1 1 + 0 1 numarrays 1 sub + { + 1 3 3 -1 roll add/index cvx + c1/get cvx/sub cvx/mul cvx + }for + /sub cvx + numarrays 1 add 1/roll cvx + }for + numarrays[/pop cvx]cvx/repeat cvx + end +}def +/exec_tint_transform +{ + /TintProc[ + /TintTransform cvx/setcolor cvx + ]cvx bdf + MappedCSA setcolorspace_opt +}bdf +/devn_makecustomcolor +{ + 2 dict begin + /names_index xdf + /Names xdf + 1 1 1 1 Names names_index get findcmykcustomcolor + /devicen_tints AGMCORE_gget names_index get setcustomcolor + Names length{pop}repeat + end +}bdf +/setdevicencolorspace +{ + dup/AliasedColorants known{false}{true}ifelse + current_spot_alias and{ + 7 dict begin + /names_index 0 def + dup/names_len exch/Names get length def + /new_names names_len array def + /new_LookupTables names_len array def + /alias_cnt 0 def + dup/Names get + { + dup map_alias{ + exch pop + dup/ColorLookup known{ + dup begin + new_LookupTables names_index ColorLookup put + end + }{ + dup/Components known{ + dup begin + new_LookupTables names_index Components put + end + }{ + dup begin + new_LookupTables names_index[null null null null]put + end + }ifelse + }ifelse + new_names names_index 3 -1 roll/Name get put + /alias_cnt alias_cnt 1 add def + }{ + /name xdf + new_names names_index name put + dup/LookupTables known{ + dup begin + new_LookupTables names_index LookupTables names_index get put + end + }{ + dup begin + new_LookupTables names_index[null null null null]put + end + }ifelse + }ifelse + /names_index names_index 1 add def + }forall + alias_cnt 0 gt{ + /AliasedColorants true def + /lut_entry_len new_LookupTables 0 get dup length 256 ge{0 get length}{length}ifelse def + 0 1 names_len 1 sub{ + /names_index xdf + new_LookupTables names_index get dup length 256 ge{0 get length}{length}ifelse lut_entry_len ne{ + /AliasedColorants false def + exit + }{ + new_LookupTables names_index get 0 get null eq{ + dup/Names get names_index get/name xdf + name(Cyan)eq name(Magenta)eq name(Yellow)eq name(Black)eq + or or or not{ + /AliasedColorants false def + exit + }if + }if + }ifelse + }for + lut_entry_len 1 eq{ + /AliasedColorants false def + }if + AliasedColorants{ + dup begin + /Names new_names def + /LookupTables new_LookupTables def + /AliasedColorants true def + /NComponents lut_entry_len def + /TintMethod NComponents 4 eq{/Subtractive}{/Additive}ifelse def + /MappedCSA TintMethod/Additive eq{/DeviceRGB}{/DeviceCMYK}ifelse def + currentdict/TTTablesIdx known not{ + /TTTablesIdx -1 def + }if + end + }if + }if + end + }if + dup/devicen_colorspace_dict exch AGMCORE_gput + begin + currentdict/AliasedColorants known{ + AliasedColorants + }{ + false + }ifelse + dup not{ + CSA map_csa + }if + /TintTransform load type/nulltype eq or{ + /TintTransform[ + 0 1 Names length 1 sub + { + /TTTablesIdx TTTablesIdx 1 add def + dup LookupTables exch get dup 0 get null eq + { + 1 index + Names exch get + dup(Cyan)eq + { + pop exch + LookupTables length exch sub + /index cvx + 0 0 0 + } + { + dup(Magenta)eq + { + pop exch + LookupTables length exch sub + /index cvx + 0/exch cvx 0 0 + }{ + (Yellow)eq + { + exch + LookupTables length exch sub + /index cvx + 0 0 3 -1/roll cvx 0 + }{ + exch + LookupTables length exch sub + /index cvx + 0 0 0 4 -1/roll cvx + }ifelse + }ifelse + }ifelse + 5 -1/roll cvx/astore cvx + }{ + dup length 1 sub + LookupTables length 4 -1 roll sub 1 add + /index cvx/mul cvx/round cvx/cvi cvx/get cvx + }ifelse + Names length TTTablesIdx add 1 add 1/roll cvx + }for + Names length[/pop cvx]cvx/repeat cvx + NComponents Names length + TintMethod/Subtractive eq + { + subtractive_blend + }{ + additive_blend + }ifelse + ]cvx bdf + }if + AGMCORE_host_sep{ + Names convert_to_process{ + exec_tint_transform + } + { + currentdict/AliasedColorants known{ + AliasedColorants not + }{ + false + }ifelse + 5 dict begin + /AvoidAliasedColorants xdf + /painted? false def + /names_index 0 def + /names_len Names length def + AvoidAliasedColorants{ + /currentspotalias current_spot_alias def + false set_spot_alias + }if + Names{ + AGMCORE_is_cmyk_sep{ + dup(Cyan)eq AGMCORE_cyan_plate and exch + dup(Magenta)eq AGMCORE_magenta_plate and exch + dup(Yellow)eq AGMCORE_yellow_plate and exch + (Black)eq AGMCORE_black_plate and or or or{ + /devicen_colorspace_dict AGMCORE_gget/TintProc[ + Names names_index/devn_makecustomcolor cvx + ]cvx ddf + /painted? true def + }if + painted?{exit}if + }{ + 0 0 0 0 5 -1 roll findcmykcustomcolor 1 setcustomcolor currentgray 0 eq{ + /devicen_colorspace_dict AGMCORE_gget/TintProc[ + Names names_index/devn_makecustomcolor cvx + ]cvx ddf + /painted? true def + exit + }if + }ifelse + /names_index names_index 1 add def + }forall + AvoidAliasedColorants{ + currentspotalias set_spot_alias + }if + painted?{ + /devicen_colorspace_dict AGMCORE_gget/names_index names_index put + }{ + /devicen_colorspace_dict AGMCORE_gget/TintProc[ + names_len[/pop cvx]cvx/repeat cvx 1/setseparationgray cvx + 0 0 0 0/setcmykcolor cvx + ]cvx ddf + }ifelse + end + }ifelse + } + { + AGMCORE_in_rip_sep{ + Names convert_to_process not + }{ + level3 + }ifelse + { + [/DeviceN Names MappedCSA/TintTransform load]setcolorspace_opt + /TintProc level3 not AGMCORE_in_rip_sep and{ + [ + Names/length cvx[/pop cvx]cvx/repeat cvx + ]cvx bdf + }{ + {setcolor}bdf + }ifelse + }{ + exec_tint_transform + }ifelse + }ifelse + set_crd + /AliasedColorants false def + end +}def +/setindexedcolorspace +{ + dup/indexed_colorspace_dict exch AGMCORE_gput + begin + currentdict/CSDBase known{ + CSDBase/CSD get_res begin + currentdict/Names known{ + currentdict devncs + }{ + 1 currentdict sepcs + }ifelse + AGMCORE_host_sep{ + 4 dict begin + /compCnt/Names where{pop Names length}{1}ifelse def + /NewLookup HiVal 1 add string def + 0 1 HiVal{ + /tableIndex xdf + Lookup dup type/stringtype eq{ + compCnt tableIndex map_index + }{ + exec + }ifelse + /Names where{ + pop setdevicencolor + }{ + setsepcolor + }ifelse + currentgray + tableIndex exch + 255 mul cvi + NewLookup 3 1 roll put + }for + [/Indexed currentcolorspace HiVal NewLookup]setcolorspace_opt + end + }{ + level3 + { + currentdict/Names known{ + [/Indexed[/DeviceN Names MappedCSA/TintTransform load]HiVal Lookup]setcolorspace_opt + }{ + [/Indexed[/Separation Name MappedCSA sep_proc_name load]HiVal Lookup]setcolorspace_opt + }ifelse + }{ + [/Indexed MappedCSA HiVal + [ + currentdict/Names known{ + Lookup dup type/stringtype eq + {/exch cvx CSDBase/CSD get_res/Names get length dup/mul cvx exch/getinterval cvx{255 div}/forall cvx} + {/exec cvx}ifelse + /TintTransform load/exec cvx + }{ + Lookup dup type/stringtype eq + {/exch cvx/get cvx 255/div cvx} + {/exec cvx}ifelse + CSDBase/CSD get_res/MappedCSA get sep_proc_name exch pop/load cvx/exec cvx + }ifelse + ]cvx + ]setcolorspace_opt + }ifelse + }ifelse + end + set_crd + } + { + CSA map_csa + AGMCORE_host_sep level2 not and{ + 0 0 0 0 setcmykcolor + }{ + [/Indexed MappedCSA + level2 not has_color not and{ + dup 0 get dup/DeviceRGB eq exch/DeviceCMYK eq or{ + pop[/DeviceGray] + }if + HiVal GrayLookup + }{ + HiVal + currentdict/RangeArray known{ + { + /indexed_colorspace_dict AGMCORE_gget begin + Lookup exch + dup HiVal gt{ + pop HiVal + }if + NComponents mul NComponents getinterval{}forall + NComponents 1 sub -1 0{ + RangeArray exch 2 mul 2 getinterval aload pop map255_to_range + NComponents 1 roll + }for + end + }bind + }{ + Lookup + }ifelse + }ifelse + ]setcolorspace_opt + set_crd + }ifelse + }ifelse + end +}def +/setindexedcolor +{ + AGMCORE_host_sep{ + /indexed_colorspace_dict AGMCORE_gget + begin + currentdict/CSDBase known{ + CSDBase/CSD get_res begin + currentdict/Names known{ + map_indexed_devn + devn + } + { + Lookup 1 3 -1 roll map_index + sep + }ifelse + end + }{ + Lookup MappedCSA/DeviceCMYK eq{4}{1}ifelse 3 -1 roll + map_index + MappedCSA/DeviceCMYK eq{setcmykcolor}{setgray}ifelse + }ifelse + end + }{ + level3 not AGMCORE_in_rip_sep and/indexed_colorspace_dict AGMCORE_gget/CSDBase known and{ + /indexed_colorspace_dict AGMCORE_gget/CSDBase get/CSD get_res begin + map_indexed_devn + devn + end + } + { + setcolor + }ifelse + }ifelse +}def +/ignoreimagedata +{ + currentoverprint not{ + gsave + dup clonedict begin + 1 setgray + /Decode[0 1]def + /DataSourcedef + /MultipleDataSources false def + /BitsPerComponent 8 def + currentdict end + systemdict/image gx + grestore + }if + consumeimagedata +}def +/add_res +{ + dup/CSD eq{ + pop + //Adobe_AGM_Core begin + /AGMCORE_CSD_cache load 3 1 roll put + end + }{ + defineresource pop + }ifelse +}def +/del_res +{ + { + aload pop exch + dup/CSD eq{ + pop + {//Adobe_AGM_Core/AGMCORE_CSD_cache get exch undef}forall + }{ + exch + {1 index undefineresource}forall + pop + }ifelse + }forall +}def +/get_res +{ + dup/CSD eq{ + pop + dup type dup/nametype eq exch/stringtype eq or{ + AGMCORE_CSD_cache exch get + }if + }{ + findresource + }ifelse +}def +/get_csa_by_name +{ + dup type dup/nametype eq exch/stringtype eq or{ + /CSA get_res + }if +}def +/paintproc_buf_init +{ + /count get 0 0 put +}def +/paintproc_buf_next +{ + dup/count get dup 0 get + dup 3 1 roll + 1 add 0 xpt + get +}def +/cachepaintproc_compress +{ + 5 dict begin + currentfile exch 0 exch/SubFileDecode filter/ReadFilter exch def + /ppdict 20 dict def + /string_size 16000 def + /readbuffer string_size string def + currentglobal true setglobal + ppdict 1 array dup 0 1 put/count xpt + setglobal + /LZWFilter + { + exch + dup length 0 eq{ + pop + }{ + ppdict dup length 1 sub 3 -1 roll put + }ifelse + {string_size}{0}ifelse string + }/LZWEncode filter def + { + ReadFilter readbuffer readstring + exch LZWFilter exch writestring + not{exit}if + }loop + LZWFilter closefile + ppdict + end +}def +/cachepaintproc +{ + 2 dict begin + currentfile exch 0 exch/SubFileDecode filter/ReadFilter exch def + /ppdict 20 dict def + currentglobal true setglobal + ppdict 1 array dup 0 1 put/count xpt + setglobal + { + ReadFilter 16000 string readstring exch + ppdict dup length 1 sub 3 -1 roll put + not{exit}if + }loop + ppdict dup dup length 1 sub()put + end +}def +/make_pattern +{ + exch clonedict exch + dup matrix currentmatrix matrix concatmatrix 0 0 3 2 roll itransform + exch 3 index/XStep get 1 index exch 2 copy div cvi mul sub sub + exch 3 index/YStep get 1 index exch 2 copy div cvi mul sub sub + matrix translate exch matrix concatmatrix + 1 index begin + BBox 0 get XStep div cvi XStep mul/xshift exch neg def + BBox 1 get YStep div cvi YStep mul/yshift exch neg def + BBox 0 get xshift add + BBox 1 get yshift add + BBox 2 get xshift add + BBox 3 get yshift add + 4 array astore + /BBox exch def + [xshift yshift/translate load null/exec load]dup + 3/PaintProc load put cvx/PaintProc exch def + end + gsave 0 setgray + makepattern + grestore +}def +/set_pattern +{ + dup/PatternType get 1 eq{ + dup/PaintType get 1 eq{ + currentoverprint sop[/DeviceGray]setcolorspace 0 setgray + }if + }if + setpattern +}def +/setcolorspace_opt +{ + dup currentcolorspace eq{pop}{setcolorspace}ifelse +}def +/updatecolorrendering +{ + currentcolorrendering/RenderingIntent known{ + currentcolorrendering/RenderingIntent get + } + { + Intent/AbsoluteColorimetric eq + { + /absolute_colorimetric_crd AGMCORE_gget dup null eq + } + { + Intent/RelativeColorimetric eq + { + /relative_colorimetric_crd AGMCORE_gget dup null eq + } + { + Intent/Saturation eq + { + /saturation_crd AGMCORE_gget dup null eq + } + { + /perceptual_crd AGMCORE_gget dup null eq + }ifelse + }ifelse + }ifelse + { + pop null + } + { + /RenderingIntent known{null}{Intent}ifelse + }ifelse + }ifelse + Intent ne{ + Intent/ColorRendering{findresource}stopped + { + pop pop systemdict/findcolorrendering known + { + Intent findcolorrendering + { + /ColorRendering findresource true exch + } + { + /ColorRendering findresource + product(Xerox Phaser 5400)ne + exch + }ifelse + dup Intent/AbsoluteColorimetric eq + { + /absolute_colorimetric_crd exch AGMCORE_gput + } + { + Intent/RelativeColorimetric eq + { + /relative_colorimetric_crd exch AGMCORE_gput + } + { + Intent/Saturation eq + { + /saturation_crd exch AGMCORE_gput + } + { + Intent/Perceptual eq + { + /perceptual_crd exch AGMCORE_gput + } + { + pop + }ifelse + }ifelse + }ifelse + }ifelse + 1 index{exch}{pop}ifelse + } + {false}ifelse + } + {true}ifelse + { + dup begin + currentdict/TransformPQR known{ + currentdict/TransformPQR get aload pop + 3{{}eq 3 1 roll}repeat or or + } + {true}ifelse + currentdict/MatrixPQR known{ + currentdict/MatrixPQR get aload pop + 1.0 eq 9 1 roll 0.0 eq 9 1 roll 0.0 eq 9 1 roll + 0.0 eq 9 1 roll 1.0 eq 9 1 roll 0.0 eq 9 1 roll + 0.0 eq 9 1 roll 0.0 eq 9 1 roll 1.0 eq + and and and and and and and and + } + {true}ifelse + end + or + { + clonedict begin + /TransformPQR[ + {4 -1 roll 3 get dup 3 1 roll sub 5 -1 roll 3 get 3 -1 roll sub div + 3 -1 roll 3 get 3 -1 roll 3 get dup 4 1 roll sub mul add}bind + {4 -1 roll 4 get dup 3 1 roll sub 5 -1 roll 4 get 3 -1 roll sub div + 3 -1 roll 4 get 3 -1 roll 4 get dup 4 1 roll sub mul add}bind + {4 -1 roll 5 get dup 3 1 roll sub 5 -1 roll 5 get 3 -1 roll sub div + 3 -1 roll 5 get 3 -1 roll 5 get dup 4 1 roll sub mul add}bind + ]def + /MatrixPQR[0.8951 -0.7502 0.0389 0.2664 1.7135 -0.0685 -0.1614 0.0367 1.0296]def + /RangePQR[-0.3227950745 2.3229645538 -1.5003771057 3.5003465881 -0.1369979095 2.136967392]def + currentdict end + }if + setcolorrendering_opt + }if + }if +}def +/set_crd +{ + AGMCORE_host_sep not level2 and{ + currentdict/ColorRendering known{ + ColorRendering/ColorRendering{findresource}stopped not{setcolorrendering_opt}if + }{ + currentdict/Intent known{ + updatecolorrendering + }if + }ifelse + currentcolorspace dup type/arraytype eq + {0 get}if + /DeviceRGB eq + { + currentdict/UCR known + {/UCR}{/AGMCORE_currentucr}ifelse + load setundercolorremoval + currentdict/BG known + {/BG}{/AGMCORE_currentbg}ifelse + load setblackgeneration + }if + }if +}def +/set_ucrbg +{ + dup null eq{pop/AGMCORE_currentbg load}{/Procedure get_res}ifelse setblackgeneration + dup null eq{pop/AGMCORE_currentucr load}{/Procedure get_res}ifelse setundercolorremoval +}def +/setcolorrendering_opt +{ + dup currentcolorrendering eq{ + pop + }{ + product(HP Color LaserJet 2605)anchorsearch{ + pop pop pop + }{ + pop + clonedict + begin + /Intent Intent def + currentdict + end + setcolorrendering + }ifelse + }ifelse +}def +/cpaint_gcomp +{ + convert_to_process//Adobe_AGM_Core/AGMCORE_ConvertToProcess xddf + //Adobe_AGM_Core/AGMCORE_ConvertToProcess get not + { + (%end_cpaint_gcomp)flushinput + }if +}def +/cpaint_gsep +{ + //Adobe_AGM_Core/AGMCORE_ConvertToProcess get + { + (%end_cpaint_gsep)flushinput + }if +}def +/cpaint_gend +{np}def +/T1_path +{ + currentfile token pop currentfile token pop mo + { + currentfile token pop dup type/stringtype eq + {pop exit}if + 0 exch rlineto + currentfile token pop dup type/stringtype eq + {pop exit}if + 0 rlineto + }loop +}def +/T1_gsave + level3 + {/clipsave} + {/gsave}ifelse + load def +/T1_grestore + level3 + {/cliprestore} + {/grestore}ifelse + load def +/set_spot_alias_ary +{ + dup inherit_aliases + //Adobe_AGM_Core/AGMCORE_SpotAliasAry xddf +}def +/set_spot_normalization_ary +{ + dup inherit_aliases + dup length + /AGMCORE_SpotAliasAry where{pop AGMCORE_SpotAliasAry length add}if + array + //Adobe_AGM_Core/AGMCORE_SpotAliasAry2 xddf + /AGMCORE_SpotAliasAry where{ + pop + AGMCORE_SpotAliasAry2 0 AGMCORE_SpotAliasAry putinterval + AGMCORE_SpotAliasAry length + }{0}ifelse + AGMCORE_SpotAliasAry2 3 1 roll exch putinterval + true set_spot_alias +}def +/inherit_aliases +{ + {dup/Name get map_alias{/CSD put}{pop}ifelse}forall +}def +/set_spot_alias +{ + /AGMCORE_SpotAliasAry2 where{ + /AGMCORE_current_spot_alias 3 -1 roll put + }{ + pop + }ifelse +}def +/current_spot_alias +{ + /AGMCORE_SpotAliasAry2 where{ + /AGMCORE_current_spot_alias get + }{ + false + }ifelse +}def +/map_alias +{ + /AGMCORE_SpotAliasAry2 where{ + begin + /AGMCORE_name xdf + false + AGMCORE_SpotAliasAry2{ + dup/Name get AGMCORE_name eq{ + /CSD get/CSD get_res + exch pop true + exit + }{ + pop + }ifelse + }forall + end + }{ + pop false + }ifelse +}bdf +/spot_alias +{ + true set_spot_alias + /AGMCORE_&setcustomcolor AGMCORE_key_known not{ + //Adobe_AGM_Core/AGMCORE_&setcustomcolor/setcustomcolor load put + }if + /customcolor_tint 1 AGMCORE_gput + //Adobe_AGM_Core begin + /setcustomcolor + { + //Adobe_AGM_Core begin + dup/customcolor_tint exch AGMCORE_gput + 1 index aload pop pop 1 eq exch 1 eq and exch 1 eq and exch 1 eq and not + current_spot_alias and{1 index 4 get map_alias}{false}ifelse + { + false set_spot_alias + /sep_colorspace_dict AGMCORE_gget null ne + {/sep_colorspace_dict AGMCORE_gget/ForeignContent known not}{false}ifelse + 3 1 roll 2 index{ + exch pop/sep_tint AGMCORE_gget exch + }if + mark 3 1 roll + setsepcolorspace + counttomark 0 ne{ + setsepcolor + }if + pop + not{/sep_tint 1.0 AGMCORE_gput/sep_colorspace_dict AGMCORE_gget/ForeignContent true put}if + pop + true set_spot_alias + }{ + AGMCORE_&setcustomcolor + }ifelse + end + }bdf + end +}def +/begin_feature +{ + Adobe_AGM_Core/AGMCORE_feature_dictCount countdictstack put + count Adobe_AGM_Core/AGMCORE_feature_opCount 3 -1 roll put + {Adobe_AGM_Core/AGMCORE_feature_ctm matrix currentmatrix put}if +}def +/end_feature +{ + 2 dict begin + /spd/setpagedevice load def + /setpagedevice{get_gstate spd set_gstate}def + stopped{$error/newerror false put}if + end + count Adobe_AGM_Core/AGMCORE_feature_opCount get sub dup 0 gt{{pop}repeat}{pop}ifelse + countdictstack Adobe_AGM_Core/AGMCORE_feature_dictCount get sub dup 0 gt{{end}repeat}{pop}ifelse + {Adobe_AGM_Core/AGMCORE_feature_ctm get setmatrix}if +}def +/set_negative +{ + //Adobe_AGM_Core begin + /AGMCORE_inverting exch def + level2{ + currentpagedevice/NegativePrint known AGMCORE_distilling not and{ + currentpagedevice/NegativePrint get//Adobe_AGM_Core/AGMCORE_inverting get ne{ + true begin_feature true{ + <>setpagedevice + }end_feature + }if + /AGMCORE_inverting false def + }if + }if + AGMCORE_inverting{ + [{1 exch sub}/exec load dup currenttransfer exch]cvx bind settransfer + AGMCORE_distilling{ + erasepage + }{ + gsave np clippath 1/setseparationgray where{pop setseparationgray}{setgray}ifelse + /AGMIRS_&fill where{pop AGMIRS_&fill}{fill}ifelse grestore + }ifelse + }if + end +}def +/lw_save_restore_override{ + /md where{ + pop + md begin + initializepage + /initializepage{}def + /pmSVsetup{}def + /endp{}def + /pse{}def + /psb{}def + /orig_showpage where + {pop} + {/orig_showpage/showpage load def} + ifelse + /showpage{orig_showpage gR}def + end + }if +}def +/pscript_showpage_override{ + /NTPSOct95 where + { + begin + showpage + save + /showpage/restore load def + /restore{exch pop}def + end + }if +}def +/driver_media_override +{ + /md where{ + pop + md/initializepage known{ + md/initializepage{}put + }if + md/rC known{ + md/rC{4{pop}repeat}put + }if + }if + /mysetup where{ + /mysetup[1 0 0 1 0 0]put + }if + Adobe_AGM_Core/AGMCORE_Default_CTM matrix currentmatrix put + level2 + {Adobe_AGM_Core/AGMCORE_Default_PageSize currentpagedevice/PageSize get put}if +}def +/capture_mysetup +{ + /Pscript_Win_Data where{ + pop + Pscript_Win_Data/mysetup known{ + Adobe_AGM_Core/save_mysetup Pscript_Win_Data/mysetup get put + }if + }if +}def +/restore_mysetup +{ + /Pscript_Win_Data where{ + pop + Pscript_Win_Data/mysetup known{ + Adobe_AGM_Core/save_mysetup known{ + Pscript_Win_Data/mysetup Adobe_AGM_Core/save_mysetup get put + Adobe_AGM_Core/save_mysetup undef + }if + }if + }if +}def +/driver_check_media_override +{ + /PrepsDict where + {pop} + { + Adobe_AGM_Core/AGMCORE_Default_CTM get matrix currentmatrix ne + Adobe_AGM_Core/AGMCORE_Default_PageSize get type/arraytype eq + { + Adobe_AGM_Core/AGMCORE_Default_PageSize get 0 get currentpagedevice/PageSize get 0 get eq and + Adobe_AGM_Core/AGMCORE_Default_PageSize get 1 get currentpagedevice/PageSize get 1 get eq and + }if + { + Adobe_AGM_Core/AGMCORE_Default_CTM get setmatrix + }if + }ifelse +}def +AGMCORE_err_strings begin + /AGMCORE_bad_environ(Environment not satisfactory for this job. Ensure that the PPD is correct or that the PostScript level requested is supported by this printer. )def + /AGMCORE_color_space_onhost_seps(This job contains colors that will not separate with on-host methods. )def + /AGMCORE_invalid_color_space(This job contains an invalid color space. )def +end +/set_def_ht +{AGMCORE_def_ht sethalftone}def +/set_def_flat +{AGMCORE_Default_flatness setflat}def +end +systemdict/setpacking known +{setpacking}if +%%EndResource +%%BeginResource: procset Adobe_CoolType_Core 2.31 0 %%Copyright: Copyright 1997-2006 Adobe Systems Incorporated. All Rights Reserved. %%Version: 2.31 0 10 dict begin /Adobe_CoolType_Passthru currentdict def /Adobe_CoolType_Core_Defined userdict/Adobe_CoolType_Core known def Adobe_CoolType_Core_Defined {/Adobe_CoolType_Core userdict/Adobe_CoolType_Core get def} if userdict/Adobe_CoolType_Core 70 dict dup begin put /Adobe_CoolType_Version 2.31 def /Level2? systemdict/languagelevel known dup {pop systemdict/languagelevel get 2 ge} if def Level2? not { /currentglobal false def /setglobal/pop load def /gcheck{pop false}bind def /currentpacking false def /setpacking/pop load def /SharedFontDirectory 0 dict def } if currentpacking true setpacking currentglobal false setglobal userdict/Adobe_CoolType_Data 2 copy known not {2 copy 10 dict put} if get begin /@opStackCountByLevel 32 dict def /@opStackLevel 0 def /@dictStackCountByLevel 32 dict def /@dictStackLevel 0 def end setglobal currentglobal true setglobal userdict/Adobe_CoolType_GVMFonts known not {userdict/Adobe_CoolType_GVMFonts 10 dict put} if setglobal currentglobal false setglobal userdict/Adobe_CoolType_LVMFonts known not {userdict/Adobe_CoolType_LVMFonts 10 dict put} if setglobal /ct_VMDictPut { dup gcheck{Adobe_CoolType_GVMFonts}{Adobe_CoolType_LVMFonts}ifelse 3 1 roll put }bind def /ct_VMDictUndef { dup Adobe_CoolType_GVMFonts exch known {Adobe_CoolType_GVMFonts exch undef} { dup Adobe_CoolType_LVMFonts exch known {Adobe_CoolType_LVMFonts exch undef} {pop} ifelse }ifelse }bind def /ct_str1 1 string def /ct_xshow { /_ct_na exch def /_ct_i 0 def currentpoint /_ct_y exch def /_ct_x exch def { pop pop ct_str1 exch 0 exch put ct_str1 show {_ct_na _ct_i get}stopped {pop pop} { _ct_x _ct_y moveto 0 rmoveto } ifelse /_ct_i _ct_i 1 add def currentpoint /_ct_y exch def /_ct_x exch def } exch @cshow }bind def /ct_yshow { /_ct_na exch def /_ct_i 0 def currentpoint /_ct_y exch def /_ct_x exch def { pop pop ct_str1 exch 0 exch put ct_str1 show {_ct_na _ct_i get}stopped {pop pop} { _ct_x _ct_y moveto 0 exch rmoveto } ifelse /_ct_i _ct_i 1 add def currentpoint /_ct_y exch def /_ct_x exch def } exch @cshow }bind def /ct_xyshow { /_ct_na exch def /_ct_i 0 def currentpoint /_ct_y exch def /_ct_x exch def { pop pop ct_str1 exch 0 exch put ct_str1 show {_ct_na _ct_i get}stopped {pop pop} { {_ct_na _ct_i 1 add get}stopped {pop pop pop} { _ct_x _ct_y moveto rmoveto } ifelse } ifelse /_ct_i _ct_i 2 add def currentpoint /_ct_y exch def /_ct_x exch def } exch @cshow }bind def /xsh{{@xshow}stopped{Adobe_CoolType_Data begin ct_xshow end}if}bind def /ysh{{@yshow}stopped{Adobe_CoolType_Data begin ct_yshow end}if}bind def /xysh{{@xyshow}stopped{Adobe_CoolType_Data begin ct_xyshow end}if}bind def currentglobal true setglobal /ct_T3Defs { /BuildChar { 1 index/Encoding get exch get 1 index/BuildGlyph get exec }bind def /BuildGlyph { exch begin GlyphProcs exch get exec end }bind def }bind def setglobal /@_SaveStackLevels { Adobe_CoolType_Data begin /@vmState currentglobal def false setglobal @opStackCountByLevel @opStackLevel 2 copy known not { 2 copy 3 dict dup/args 7 index 5 add array put put get } { get dup/args get dup length 3 index lt { dup length 5 add array exch 1 index exch 0 exch putinterval 1 index exch/args exch put } {pop} ifelse } ifelse begin count 1 sub 1 index lt {pop count} if dup/argCount exch def dup 0 gt { args exch 0 exch getinterval astore pop } {pop} ifelse count /restCount exch def end /@opStackLevel @opStackLevel 1 add def countdictstack 1 sub @dictStackCountByLevel exch @dictStackLevel exch put /@dictStackLevel @dictStackLevel 1 add def @vmState setglobal end }bind def /@_RestoreStackLevels { Adobe_CoolType_Data begin /@opStackLevel @opStackLevel 1 sub def @opStackCountByLevel @opStackLevel get begin count restCount sub dup 0 gt {{pop}repeat} {pop} ifelse args 0 argCount getinterval{}forall end /@dictStackLevel @dictStackLevel 1 sub def @dictStackCountByLevel @dictStackLevel get end countdictstack exch sub dup 0 gt {{end}repeat} {pop} ifelse }bind def /@_PopStackLevels { Adobe_CoolType_Data begin /@opStackLevel @opStackLevel 1 sub def /@dictStackLevel @dictStackLevel 1 sub def end }bind def /@Raise { exch cvx exch errordict exch get exec stop }bind def /@ReRaise { cvx $error/errorname get errordict exch get exec stop }bind def /@Stopped { 0 @#Stopped }bind def /@#Stopped { @_SaveStackLevels stopped {@_RestoreStackLevels true} {@_PopStackLevels false} ifelse }bind def /@Arg { Adobe_CoolType_Data begin @opStackCountByLevel @opStackLevel 1 sub get begin args exch argCount 1 sub exch sub get end end }bind def currentglobal true setglobal /CTHasResourceForAllBug Level2? { 1 dict dup /@shouldNotDisappearDictValue true def Adobe_CoolType_Data exch/@shouldNotDisappearDict exch put begin count @_SaveStackLevels {(*){pop stop}128 string/Category resourceforall} stopped pop @_RestoreStackLevels currentdict Adobe_CoolType_Data/@shouldNotDisappearDict get dup 3 1 roll ne dup 3 1 roll { /@shouldNotDisappearDictValue known { { end currentdict 1 index eq {pop exit} if } loop } if } { pop end } ifelse } {false} ifelse def true setglobal /CTHasResourceStatusBug Level2? { mark {/steveamerige/Category resourcestatus} stopped {cleartomark true} {cleartomark currentglobal not} ifelse } {false} ifelse def setglobal /CTResourceStatus { mark 3 1 roll /Category findresource begin ({ResourceStatus}stopped)0()/SubFileDecode filter cvx exec {cleartomark false} {{3 2 roll pop true}{cleartomark false}ifelse} ifelse end }bind def /CTWorkAroundBugs { Level2? { /cid_PreLoad/ProcSet resourcestatus { pop pop currentglobal mark { (*) { dup/CMap CTHasResourceStatusBug {CTResourceStatus} {resourcestatus} ifelse { pop dup 0 eq exch 1 eq or { dup/CMap findresource gcheck setglobal /CMap undefineresource } { pop CTHasResourceForAllBug {exit} {stop} ifelse } ifelse } {pop} ifelse } 128 string/CMap resourceforall } stopped {cleartomark} stopped pop setglobal } if } if }bind def /ds { Adobe_CoolType_Core begin CTWorkAroundBugs /mo/moveto load def /nf/newencodedfont load def /msf{makefont setfont}bind def /uf{dup undefinefont ct_VMDictUndef}bind def /ur/undefineresource load def /chp/charpath load def /awsh/awidthshow load def /wsh/widthshow load def /ash/ashow load def /@xshow/xshow load def /@yshow/yshow load def /@xyshow/xyshow load def /@cshow/cshow load def /sh/show load def /rp/repeat load def /.n/.notdef def end currentglobal false setglobal userdict/Adobe_CoolType_Data 2 copy known not {2 copy 10 dict put} if get begin /AddWidths? false def /CC 0 def /charcode 2 string def /@opStackCountByLevel 32 dict def /@opStackLevel 0 def /@dictStackCountByLevel 32 dict def /@dictStackLevel 0 def /InVMFontsByCMap 10 dict def /InVMDeepCopiedFonts 10 dict def end setglobal }bind def /dt { currentdict Adobe_CoolType_Core eq {end} if }bind def /ps { Adobe_CoolType_Core begin Adobe_CoolType_GVMFonts begin Adobe_CoolType_LVMFonts begin SharedFontDirectory begin }bind def /pt { end end end end }bind def /unload { systemdict/languagelevel known { systemdict/languagelevel get 2 ge { userdict/Adobe_CoolType_Core 2 copy known {undef} {pop pop} ifelse } if } if }bind def /ndf { 1 index where {pop pop pop} {dup xcheck{bind}if def} ifelse }def /findfont systemdict begin userdict begin /globaldict where{/globaldict get begin}if dup where pop exch get /globaldict where{pop end}if end end Adobe_CoolType_Core_Defined {/systemfindfont exch def} { /findfont 1 index def /systemfindfont exch def } ifelse /undefinefont {pop}ndf /copyfont { currentglobal 3 1 roll 1 index gcheck setglobal dup null eq{0}{dup length}ifelse 2 index length add 1 add dict begin exch { 1 index/FID eq {pop pop} {def} ifelse } forall dup null eq {pop} {{def}forall} ifelse currentdict end exch setglobal }bind def /copyarray { currentglobal exch dup gcheck setglobal dup length array copy exch setglobal }bind def /newencodedfont { currentglobal { SharedFontDirectory 3 index known {SharedFontDirectory 3 index get/FontReferenced known} {false} ifelse } { FontDirectory 3 index known {FontDirectory 3 index get/FontReferenced known} { SharedFontDirectory 3 index known {SharedFontDirectory 3 index get/FontReferenced known} {false} ifelse } ifelse } ifelse dup { 3 index findfont/FontReferenced get 2 index dup type/nametype eq {findfont} if ne {pop false} if } if dup { 1 index dup type/nametype eq {findfont} if dup/CharStrings known { /CharStrings get length 4 index findfont/CharStrings get length ne { pop false } if } {pop} ifelse } if { pop 1 index findfont /Encoding get exch 0 1 255 {2 copy get 3 index 3 1 roll put} for pop pop pop } { currentglobal 4 1 roll dup type/nametype eq {findfont} if dup gcheck setglobal dup dup maxlength 2 add dict begin exch { 1 index/FID ne 2 index/Encoding ne and {def} {pop pop} ifelse } forall /FontReferenced exch def /Encoding exch dup length array copy def /FontName 1 index dup type/stringtype eq{cvn}if def dup currentdict end definefont ct_VMDictPut setglobal } ifelse }bind def /SetSubstituteStrategy { $SubstituteFont begin dup type/dicttype ne {0 dict} if currentdict/$Strategies known { exch $Strategies exch 2 copy known { get 2 copy maxlength exch maxlength add dict begin {def}forall {def}forall currentdict dup/$Init known {dup/$Init get exec} if end /$Strategy exch def } {pop pop pop} ifelse } {pop pop} ifelse end }bind def /scff { $SubstituteFont begin dup type/stringtype eq {dup length exch} {null} ifelse /$sname exch def /$slen exch def /$inVMIndex $sname null eq { 1 index $str cvs dup length $slen sub $slen getinterval cvn } {$sname} ifelse def end {findfont} @Stopped { dup length 8 add string exch 1 index 0(BadFont:)putinterval 1 index exch 8 exch dup length string cvs putinterval cvn {findfont} @Stopped {pop/Courier findfont} if } if $SubstituteFont begin /$sname null def /$slen 0 def /$inVMIndex null def end }bind def /isWidthsOnlyFont { dup/WidthsOnly known {pop pop true} { dup/FDepVector known {/FDepVector get{isWidthsOnlyFont dup{exit}if}forall} { dup/FDArray known {/FDArray get{isWidthsOnlyFont dup{exit}if}forall} {pop} ifelse } ifelse } ifelse }bind def /ct_StyleDicts 4 dict dup begin /Adobe-Japan1 4 dict dup begin Level2? { /Serif /HeiseiMin-W3-83pv-RKSJ-H/Font resourcestatus {pop pop/HeiseiMin-W3} { /CIDFont/Category resourcestatus { pop pop /HeiseiMin-W3/CIDFont resourcestatus {pop pop/HeiseiMin-W3} {/Ryumin-Light} ifelse } {/Ryumin-Light} ifelse } ifelse def /SansSerif /HeiseiKakuGo-W5-83pv-RKSJ-H/Font resourcestatus {pop pop/HeiseiKakuGo-W5} { /CIDFont/Category resourcestatus { pop pop /HeiseiKakuGo-W5/CIDFont resourcestatus {pop pop/HeiseiKakuGo-W5} {/GothicBBB-Medium} ifelse } {/GothicBBB-Medium} ifelse } ifelse def /HeiseiMaruGo-W4-83pv-RKSJ-H/Font resourcestatus {pop pop/HeiseiMaruGo-W4} { /CIDFont/Category resourcestatus { pop pop /HeiseiMaruGo-W4/CIDFont resourcestatus {pop pop/HeiseiMaruGo-W4} { /Jun101-Light-RKSJ-H/Font resourcestatus {pop pop/Jun101-Light} {SansSerif} ifelse } ifelse } { /Jun101-Light-RKSJ-H/Font resourcestatus {pop pop/Jun101-Light} {SansSerif} ifelse } ifelse } ifelse /RoundSansSerif exch def /Default Serif def } { /Serif/Ryumin-Light def /SansSerif/GothicBBB-Medium def { (fonts/Jun101-Light-83pv-RKSJ-H)status }stopped {pop}{ {pop pop pop pop/Jun101-Light} {SansSerif} ifelse /RoundSansSerif exch def }ifelse /Default Serif def } ifelse end def /Adobe-Korea1 4 dict dup begin /Serif/HYSMyeongJo-Medium def /SansSerif/HYGoThic-Medium def /RoundSansSerif SansSerif def /Default Serif def end def /Adobe-GB1 4 dict dup begin /Serif/STSong-Light def /SansSerif/STHeiti-Regular def /RoundSansSerif SansSerif def /Default Serif def end def /Adobe-CNS1 4 dict dup begin /Serif/MKai-Medium def /SansSerif/MHei-Medium def /RoundSansSerif SansSerif def /Default Serif def end def end def Level2?{currentglobal true setglobal}if /ct_BoldRomanWidthProc { stringwidth 1 index 0 ne{exch .03 add exch}if setcharwidth 0 0 }bind def /ct_Type0WidthProc { dup stringwidth 0 0 moveto 2 index true charpath pathbbox 0 -1 7 index 2 div .88 setcachedevice2 pop 0 0 }bind def /ct_Type0WMode1WidthProc { dup stringwidth pop 2 div neg -0.88 2 copy moveto 0 -1 5 -1 roll true charpath pathbbox setcachedevice }bind def /cHexEncoding [/c00/c01/c02/c03/c04/c05/c06/c07/c08/c09/c0A/c0B/c0C/c0D/c0E/c0F/c10/c11/c12 /c13/c14/c15/c16/c17/c18/c19/c1A/c1B/c1C/c1D/c1E/c1F/c20/c21/c22/c23/c24/c25 /c26/c27/c28/c29/c2A/c2B/c2C/c2D/c2E/c2F/c30/c31/c32/c33/c34/c35/c36/c37/c38 /c39/c3A/c3B/c3C/c3D/c3E/c3F/c40/c41/c42/c43/c44/c45/c46/c47/c48/c49/c4A/c4B /c4C/c4D/c4E/c4F/c50/c51/c52/c53/c54/c55/c56/c57/c58/c59/c5A/c5B/c5C/c5D/c5E /c5F/c60/c61/c62/c63/c64/c65/c66/c67/c68/c69/c6A/c6B/c6C/c6D/c6E/c6F/c70/c71 /c72/c73/c74/c75/c76/c77/c78/c79/c7A/c7B/c7C/c7D/c7E/c7F/c80/c81/c82/c83/c84 /c85/c86/c87/c88/c89/c8A/c8B/c8C/c8D/c8E/c8F/c90/c91/c92/c93/c94/c95/c96/c97 /c98/c99/c9A/c9B/c9C/c9D/c9E/c9F/cA0/cA1/cA2/cA3/cA4/cA5/cA6/cA7/cA8/cA9/cAA /cAB/cAC/cAD/cAE/cAF/cB0/cB1/cB2/cB3/cB4/cB5/cB6/cB7/cB8/cB9/cBA/cBB/cBC/cBD /cBE/cBF/cC0/cC1/cC2/cC3/cC4/cC5/cC6/cC7/cC8/cC9/cCA/cCB/cCC/cCD/cCE/cCF/cD0 /cD1/cD2/cD3/cD4/cD5/cD6/cD7/cD8/cD9/cDA/cDB/cDC/cDD/cDE/cDF/cE0/cE1/cE2/cE3 /cE4/cE5/cE6/cE7/cE8/cE9/cEA/cEB/cEC/cED/cEE/cEF/cF0/cF1/cF2/cF3/cF4/cF5/cF6 /cF7/cF8/cF9/cFA/cFB/cFC/cFD/cFE/cFF]def /ct_BoldBaseFont 11 dict begin /FontType 3 def /FontMatrix[1 0 0 1 0 0]def /FontBBox[0 0 1 1]def /Encoding cHexEncoding def /_setwidthProc/ct_BoldRomanWidthProc load def /_bcstr1 1 string def /BuildChar { exch begin _basefont setfont _bcstr1 dup 0 4 -1 roll put dup _setwidthProc 3 copy moveto show _basefonto setfont moveto show end }bind def currentdict end def systemdict/composefont known { /ct_DefineIdentity-H { /Identity-H/CMap resourcestatus { pop pop } { /CIDInit/ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo 3 dict dup begin /Registry(Adobe)def /Ordering(Identity)def /Supplement 0 def end def /CMapName/Identity-H def /CMapVersion 1.000 def /CMapType 1 def 1 begincodespacerange <0000> endcodespacerange 1 begincidrange <0000>0 endcidrange endcmap CMapName currentdict/CMap defineresource pop end end } ifelse } def /ct_BoldBaseCIDFont 11 dict begin /CIDFontType 1 def /CIDFontName/ct_BoldBaseCIDFont def /FontMatrix[1 0 0 1 0 0]def /FontBBox[0 0 1 1]def /_setwidthProc/ct_Type0WidthProc load def /_bcstr2 2 string def /BuildGlyph { exch begin _basefont setfont _bcstr2 1 2 index 256 mod put _bcstr2 0 3 -1 roll 256 idiv put _bcstr2 dup _setwidthProc 3 copy moveto show _basefonto setfont moveto show end }bind def currentdict end def }if Level2?{setglobal}if /ct_CopyFont{ { 1 index/FID ne 2 index/UniqueID ne and {def}{pop pop}ifelse }forall }bind def /ct_Type0CopyFont { exch dup length dict begin ct_CopyFont [ exch FDepVector { dup/FontType get 0 eq { 1 index ct_Type0CopyFont /_ctType0 exch definefont } { /_ctBaseFont exch 2 index exec } ifelse exch } forall pop ] /FDepVector exch def currentdict end }bind def /ct_MakeBoldFont { dup/ct_SyntheticBold known { dup length 3 add dict begin ct_CopyFont /ct_StrokeWidth .03 0 FontMatrix idtransform pop def /ct_SyntheticBold true def currentdict end definefont } { dup dup length 3 add dict begin ct_CopyFont /PaintType 2 def /StrokeWidth .03 0 FontMatrix idtransform pop def /dummybold currentdict end definefont dup/FontType get dup 9 ge exch 11 le and { ct_BoldBaseCIDFont dup length 3 add dict copy begin dup/CIDSystemInfo get/CIDSystemInfo exch def ct_DefineIdentity-H /_Type0Identity/Identity-H 3 -1 roll[exch]composefont /_basefont exch def /_Type0Identity/Identity-H 3 -1 roll[exch]composefont /_basefonto exch def currentdict end /CIDFont defineresource } { ct_BoldBaseFont dup length 3 add dict copy begin /_basefont exch def /_basefonto exch def currentdict end definefont } ifelse } ifelse }bind def /ct_MakeBold{ 1 index 1 index findfont currentglobal 5 1 roll dup gcheck setglobal dup /FontType get 0 eq { dup/WMode known{dup/WMode get 1 eq}{false}ifelse version length 4 ge and {version 0 4 getinterval cvi 2015 ge} {true} ifelse {/ct_Type0WidthProc} {/ct_Type0WMode1WidthProc} ifelse ct_BoldBaseFont/_setwidthProc 3 -1 roll load put {ct_MakeBoldFont}ct_Type0CopyFont definefont } { dup/_fauxfont known not 1 index/SubstMaster known not and { ct_BoldBaseFont/_setwidthProc /ct_BoldRomanWidthProc load put ct_MakeBoldFont } { 2 index 2 index eq {exch pop } { dup length dict begin ct_CopyFont currentdict end definefont } ifelse } ifelse } ifelse pop pop pop setglobal }bind def /?str1 256 string def /?set { $SubstituteFont begin /$substituteFound false def /$fontname 1 index def /$doSmartSub false def end dup findfont $SubstituteFont begin $substituteFound {false} { dup/FontName known { dup/FontName get $fontname eq 1 index/DistillerFauxFont known not and /currentdistillerparams where {pop false 2 index isWidthsOnlyFont not and} if } {false} ifelse } ifelse exch pop /$doSmartSub true def end { 5 1 roll pop pop pop pop findfont } { 1 index findfont dup/FontType get 3 eq { 6 1 roll pop pop pop pop pop false } {pop true} ifelse { $SubstituteFont begin pop pop /$styleArray 1 index def /$regOrdering 2 index def pop pop 0 1 $styleArray length 1 sub { $styleArray exch get ct_StyleDicts $regOrdering 2 copy known { get exch 2 copy known not {pop/Default} if get dup type/nametype eq { ?str1 cvs length dup 1 add exch ?str1 exch(-)putinterval exch dup length exch ?str1 exch 3 index exch putinterval add ?str1 exch 0 exch getinterval cvn } { pop pop/Unknown } ifelse } { pop pop pop pop/Unknown } ifelse } for end findfont }if } ifelse currentglobal false setglobal 3 1 roll null copyfont definefont pop setglobal }bind def setpacking userdict/$SubstituteFont 25 dict put 1 dict begin /SubstituteFont dup $error exch 2 copy known {get} {pop pop{pop/Courier}bind} ifelse def /currentdistillerparams where dup { pop pop currentdistillerparams/CannotEmbedFontPolicy 2 copy known {get/Error eq} {pop pop false} ifelse } if not { countdictstack array dictstack 0 get begin userdict begin $SubstituteFont begin /$str 128 string def /$fontpat 128 string def /$slen 0 def /$sname null def /$match false def /$fontname null def /$substituteFound false def /$inVMIndex null def /$doSmartSub true def /$depth 0 def /$fontname null def /$italicangle 26.5 def /$dstack null def /$Strategies 10 dict dup begin /$Type3Underprint { currentglobal exch false setglobal 11 dict begin /UseFont exch $WMode 0 ne { dup length dict copy dup/WMode $WMode put /UseFont exch definefont } if def /FontName $fontname dup type/stringtype eq{cvn}if def /FontType 3 def /FontMatrix[.001 0 0 .001 0 0]def /Encoding 256 array dup 0 1 255{/.notdef put dup}for pop def /FontBBox[0 0 0 0]def /CCInfo 7 dict dup begin /cc null def /x 0 def /y 0 def end def /BuildChar { exch begin CCInfo begin 1 string dup 0 3 index put exch pop /cc exch def UseFont 1000 scalefont setfont cc stringwidth/y exch def/x exch def x y setcharwidth $SubstituteFont/$Strategy get/$Underprint get exec 0 0 moveto cc show x y moveto end end }bind def currentdict end exch setglobal }bind def /$GetaTint 2 dict dup begin /$BuildFont { dup/WMode known {dup/WMode get} {0} ifelse /$WMode exch def $fontname exch dup/FontName known { dup/FontName get dup type/stringtype eq{cvn}if } {/unnamedfont} ifelse exch Adobe_CoolType_Data/InVMDeepCopiedFonts get 1 index/FontName get known { pop Adobe_CoolType_Data/InVMDeepCopiedFonts get 1 index get null copyfont } {$deepcopyfont} ifelse exch 1 index exch/FontBasedOn exch put dup/FontName $fontname dup type/stringtype eq{cvn}if put definefont Adobe_CoolType_Data/InVMDeepCopiedFonts get begin dup/FontBasedOn get 1 index def end }bind def /$Underprint { gsave x abs y abs gt {/y 1000 def} {/x -1000 def 500 120 translate} ifelse Level2? { [/Separation(All)/DeviceCMYK{0 0 0 1 pop}] setcolorspace } {0 setgray} ifelse 10 setlinewidth x .8 mul [7 3] { y mul 8 div 120 sub x 10 div exch moveto 0 y 4 div neg rlineto dup 0 rlineto 0 y 4 div rlineto closepath gsave Level2? {.2 setcolor} {.8 setgray} ifelse fill grestore stroke } forall pop grestore }bind def end def /$Oblique 1 dict dup begin /$BuildFont { currentglobal exch dup gcheck setglobal null copyfont begin /FontBasedOn currentdict/FontName known { FontName dup type/stringtype eq{cvn}if } {/unnamedfont} ifelse def /FontName $fontname dup type/stringtype eq{cvn}if def /currentdistillerparams where {pop} { /FontInfo currentdict/FontInfo known {FontInfo null copyfont} {2 dict} ifelse dup begin /ItalicAngle $italicangle def /FontMatrix FontMatrix [1 0 ItalicAngle dup sin exch cos div 1 0 0] matrix concatmatrix readonly end 4 2 roll def def } ifelse FontName currentdict end definefont exch setglobal }bind def end def /$None 1 dict dup begin /$BuildFont{}bind def end def end def /$Oblique SetSubstituteStrategy /$findfontByEnum { dup type/stringtype eq{cvn}if dup/$fontname exch def $sname null eq {$str cvs dup length $slen sub $slen getinterval} {pop $sname} ifelse $fontpat dup 0(fonts/*)putinterval exch 7 exch putinterval /$match false def $SubstituteFont/$dstack countdictstack array dictstack put mark { $fontpat 0 $slen 7 add getinterval {/$match exch def exit} $str filenameforall } stopped { cleardictstack currentdict true $SubstituteFont/$dstack get { exch { 1 index eq {pop false} {true} ifelse } {begin false} ifelse } forall pop } if cleartomark /$slen 0 def $match false ne {$match(fonts/)anchorsearch pop pop cvn} {/Courier} ifelse }bind def /$ROS 1 dict dup begin /Adobe 4 dict dup begin /Japan1 [/Ryumin-Light/HeiseiMin-W3 /GothicBBB-Medium/HeiseiKakuGo-W5 /HeiseiMaruGo-W4/Jun101-Light]def /Korea1 [/HYSMyeongJo-Medium/HYGoThic-Medium]def /GB1 [/STSong-Light/STHeiti-Regular]def /CNS1 [/MKai-Medium/MHei-Medium]def end def end def /$cmapname null def /$deepcopyfont { dup/FontType get 0 eq { 1 dict dup/FontName/copied put copyfont begin /FDepVector FDepVector copyarray 0 1 2 index length 1 sub { 2 copy get $deepcopyfont dup/FontName/copied put /copied exch definefont 3 copy put pop pop } for def currentdict end } {$Strategies/$Type3Underprint get exec} ifelse }bind def /$buildfontname { dup/CIDFont findresource/CIDSystemInfo get begin Registry length Ordering length Supplement 8 string cvs 3 copy length 2 add add add string dup 5 1 roll dup 0 Registry putinterval dup 4 index(-)putinterval dup 4 index 1 add Ordering putinterval 4 2 roll add 1 add 2 copy(-)putinterval end 1 add 2 copy 0 exch getinterval $cmapname $fontpat cvs exch anchorsearch {pop pop 3 2 roll putinterval cvn/$cmapname exch def} {pop pop pop pop pop} ifelse length $str 1 index(-)putinterval 1 add $str 1 index $cmapname $fontpat cvs putinterval $cmapname length add $str exch 0 exch getinterval cvn }bind def /$findfontByROS { /$fontname exch def $ROS Registry 2 copy known { get Ordering 2 copy known {get} {pop pop[]} ifelse } {pop pop[]} ifelse false exch { dup/CIDFont resourcestatus { pop pop save 1 index/CIDFont findresource dup/WidthsOnly known {dup/WidthsOnly get} {false} ifelse exch pop exch restore {pop} {exch pop true exit} ifelse } {pop} ifelse } forall {$str cvs $buildfontname} { false(*) { save exch dup/CIDFont findresource dup/WidthsOnly known {dup/WidthsOnly get not} {true} ifelse exch/CIDSystemInfo get dup/Registry get Registry eq exch/Ordering get Ordering eq and and {exch restore exch pop true exit} {pop restore} ifelse } $str/CIDFont resourceforall {$buildfontname} {$fontname $findfontByEnum} ifelse } ifelse }bind def end end currentdict/$error known currentdict/languagelevel known and dup {pop $error/SubstituteFont known} if dup {$error} {Adobe_CoolType_Core} ifelse begin { /SubstituteFont /CMap/Category resourcestatus { pop pop { $SubstituteFont begin /$substituteFound true def dup length $slen gt $sname null ne or $slen 0 gt and { $sname null eq {dup $str cvs dup length $slen sub $slen getinterval cvn} {$sname} ifelse Adobe_CoolType_Data/InVMFontsByCMap get 1 index 2 copy known { get false exch { pop currentglobal { GlobalFontDirectory 1 index known {exch pop true exit} {pop} ifelse } { FontDirectory 1 index known {exch pop true exit} { GlobalFontDirectory 1 index known {exch pop true exit} {pop} ifelse } ifelse } ifelse } forall } {pop pop false} ifelse { exch pop exch pop } { dup/CMap resourcestatus { pop pop dup/$cmapname exch def /CMap findresource/CIDSystemInfo get{def}forall $findfontByROS } { 128 string cvs dup(-)search { 3 1 roll search { 3 1 roll pop {dup cvi} stopped {pop pop pop pop pop $findfontByEnum} { 4 2 roll pop pop exch length exch 2 index length 2 index sub exch 1 sub -1 0 { $str cvs dup length 4 index 0 4 index 4 3 roll add getinterval exch 1 index exch 3 index exch putinterval dup/CMap resourcestatus { pop pop 4 1 roll pop pop pop dup/$cmapname exch def /CMap findresource/CIDSystemInfo get{def}forall $findfontByROS true exit } {pop} ifelse } for dup type/booleantype eq {pop} {pop pop pop $findfontByEnum} ifelse } ifelse } {pop pop pop $findfontByEnum} ifelse } {pop pop $findfontByEnum} ifelse } ifelse } ifelse } {//SubstituteFont exec} ifelse /$slen 0 def end } } { { $SubstituteFont begin /$substituteFound true def dup length $slen gt $sname null ne or $slen 0 gt and {$findfontByEnum} {//SubstituteFont exec} ifelse end } } ifelse bind readonly def Adobe_CoolType_Core/scfindfont/systemfindfont load put } { /scfindfont { $SubstituteFont begin dup systemfindfont dup/FontName known {dup/FontName get dup 3 index ne} {/noname true} ifelse dup { /$origfontnamefound 2 index def /$origfontname 4 index def/$substituteFound true def } if exch pop { $slen 0 gt $sname null ne 3 index length $slen gt or and { pop dup $findfontByEnum findfont dup maxlength 1 add dict begin {1 index/FID eq{pop pop}{def}ifelse} forall currentdict end definefont dup/FontName known{dup/FontName get}{null}ifelse $origfontnamefound ne { $origfontname $str cvs print ( substitution revised, using )print dup/FontName known {dup/FontName get}{(unspecified font)} ifelse $str cvs print(.\n)print } if } {exch pop} ifelse } {exch pop} ifelse end }bind def } ifelse end end Adobe_CoolType_Core_Defined not { Adobe_CoolType_Core/findfont { $SubstituteFont begin $depth 0 eq { /$fontname 1 index dup type/stringtype ne{$str cvs}if def /$substituteFound false def } if /$depth $depth 1 add def end scfindfont $SubstituteFont begin /$depth $depth 1 sub def $substituteFound $depth 0 eq and { $inVMIndex null ne {dup $inVMIndex $AddInVMFont} if $doSmartSub { currentdict/$Strategy known {$Strategy/$BuildFont get exec} if } if } if end }bind put } if } if end /$AddInVMFont { exch/FontName 2 copy known { get 1 dict dup begin exch 1 index gcheck def end exch Adobe_CoolType_Data/InVMFontsByCMap get exch $DictAdd } {pop pop pop} ifelse }bind def /$DictAdd { 2 copy known not {2 copy 4 index length dict put} if Level2? not { 2 copy get dup maxlength exch length 4 index length add lt 2 copy get dup length 4 index length add exch maxlength 1 index lt { 2 mul dict begin 2 copy get{forall}def 2 copy currentdict put end } {pop} ifelse } if get begin {def} forall end }bind def end end %%EndResource currentglobal true setglobal %%BeginResource: procset Adobe_CoolType_Utility_MAKEOCF 1.23 0 %%Copyright: Copyright 1987-2006 Adobe Systems Incorporated. %%Version: 1.23 0 systemdict/languagelevel known dup {currentglobal false setglobal} {false} ifelse exch userdict/Adobe_CoolType_Utility 2 copy known {2 copy get dup maxlength 27 add dict copy} {27 dict} ifelse put Adobe_CoolType_Utility begin /@eexecStartData def /@recognizeCIDFont null def /ct_Level2? exch def /ct_Clone? 1183615869 internaldict dup /CCRun known not exch/eCCRun known not ct_Level2? and or def ct_Level2? {globaldict begin currentglobal true setglobal} if /ct_AddStdCIDMap ct_Level2? {{ mark Adobe_CoolType_Utility/@recognizeCIDFont currentdict put { ((Hex)57 StartData 0615 1e27 2c39 1c60 d8a8 cc31 fe2b f6e0 7aa3 e541 e21c 60d8 a8c9 c3d0 6d9e 1c60 d8a8 c9c2 02d7 9a1c 60d8 a849 1c60 d8a8 cc36 74f4 1144 b13b 77)0()/SubFileDecode filter cvx exec } stopped { cleartomark Adobe_CoolType_Utility/@recognizeCIDFont get countdictstack dup array dictstack exch 1 sub -1 0 { 2 copy get 3 index eq {1 index length exch sub 1 sub{end}repeat exit} {pop} ifelse } for pop pop Adobe_CoolType_Utility/@eexecStartData get eexec } {cleartomark} ifelse }} {{ Adobe_CoolType_Utility/@eexecStartData get eexec }} ifelse bind def userdict/cid_extensions known dup{cid_extensions/cid_UpdateDB known and}if { cid_extensions begin /cid_GetCIDSystemInfo { 1 index type/stringtype eq {exch cvn exch} if cid_extensions begin dup load 2 index known { 2 copy cid_GetStatusInfo dup null ne { 1 index load 3 index get dup null eq {pop pop cid_UpdateDB} { exch 1 index/Created get eq {exch pop exch pop} {pop cid_UpdateDB} ifelse } ifelse } {pop cid_UpdateDB} ifelse } {cid_UpdateDB} ifelse end }bind def end } if ct_Level2? {end setglobal} if /ct_UseNativeCapability? systemdict/composefont known def /ct_MakeOCF 35 dict def /ct_Vars 25 dict def /ct_GlyphDirProcs 6 dict def /ct_BuildCharDict 15 dict dup begin /charcode 2 string def /dst_string 1500 string def /nullstring()def /usewidths? true def end def ct_Level2?{setglobal}{pop}ifelse ct_GlyphDirProcs begin /GetGlyphDirectory { systemdict/languagelevel known {pop/CIDFont findresource/GlyphDirectory get} { 1 index/CIDFont findresource/GlyphDirectory get dup type/dicttype eq { dup dup maxlength exch length sub 2 index lt { dup length 2 index add dict copy 2 index /CIDFont findresource/GlyphDirectory 2 index put } if } if exch pop exch pop } ifelse + }def /+ { systemdict/languagelevel known { currentglobal false setglobal 3 dict begin /vm exch def } {1 dict begin} ifelse /$ exch def systemdict/languagelevel known { vm setglobal /gvm currentglobal def $ gcheck setglobal } if ?{$ begin}if }def /?{$ type/dicttype eq}def /|{ userdict/Adobe_CoolType_Data known { Adobe_CoolType_Data/AddWidths? known { currentdict Adobe_CoolType_Data begin begin AddWidths? { Adobe_CoolType_Data/CC 3 index put ?{def}{$ 3 1 roll put}ifelse CC charcode exch 1 index 0 2 index 256 idiv put 1 index exch 1 exch 256 mod put stringwidth 2 array astore currentfont/Widths get exch CC exch put } {?{def}{$ 3 1 roll put}ifelse} ifelse end end } {?{def}{$ 3 1 roll put}ifelse} ifelse } {?{def}{$ 3 1 roll put}ifelse} ifelse }def /! { ?{end}if systemdict/languagelevel known {gvm setglobal} if end }def /:{string currentfile exch readstring pop}executeonly def end ct_MakeOCF begin /ct_cHexEncoding [/c00/c01/c02/c03/c04/c05/c06/c07/c08/c09/c0A/c0B/c0C/c0D/c0E/c0F/c10/c11/c12 /c13/c14/c15/c16/c17/c18/c19/c1A/c1B/c1C/c1D/c1E/c1F/c20/c21/c22/c23/c24/c25 /c26/c27/c28/c29/c2A/c2B/c2C/c2D/c2E/c2F/c30/c31/c32/c33/c34/c35/c36/c37/c38 /c39/c3A/c3B/c3C/c3D/c3E/c3F/c40/c41/c42/c43/c44/c45/c46/c47/c48/c49/c4A/c4B /c4C/c4D/c4E/c4F/c50/c51/c52/c53/c54/c55/c56/c57/c58/c59/c5A/c5B/c5C/c5D/c5E /c5F/c60/c61/c62/c63/c64/c65/c66/c67/c68/c69/c6A/c6B/c6C/c6D/c6E/c6F/c70/c71 /c72/c73/c74/c75/c76/c77/c78/c79/c7A/c7B/c7C/c7D/c7E/c7F/c80/c81/c82/c83/c84 /c85/c86/c87/c88/c89/c8A/c8B/c8C/c8D/c8E/c8F/c90/c91/c92/c93/c94/c95/c96/c97 /c98/c99/c9A/c9B/c9C/c9D/c9E/c9F/cA0/cA1/cA2/cA3/cA4/cA5/cA6/cA7/cA8/cA9/cAA /cAB/cAC/cAD/cAE/cAF/cB0/cB1/cB2/cB3/cB4/cB5/cB6/cB7/cB8/cB9/cBA/cBB/cBC/cBD /cBE/cBF/cC0/cC1/cC2/cC3/cC4/cC5/cC6/cC7/cC8/cC9/cCA/cCB/cCC/cCD/cCE/cCF/cD0 /cD1/cD2/cD3/cD4/cD5/cD6/cD7/cD8/cD9/cDA/cDB/cDC/cDD/cDE/cDF/cE0/cE1/cE2/cE3 /cE4/cE5/cE6/cE7/cE8/cE9/cEA/cEB/cEC/cED/cEE/cEF/cF0/cF1/cF2/cF3/cF4/cF5/cF6 /cF7/cF8/cF9/cFA/cFB/cFC/cFD/cFE/cFF]def /ct_CID_STR_SIZE 8000 def /ct_mkocfStr100 100 string def /ct_defaultFontMtx[.001 0 0 .001 0 0]def /ct_1000Mtx[1000 0 0 1000 0 0]def /ct_raise{exch cvx exch errordict exch get exec stop}bind def /ct_reraise {cvx $error/errorname get(Error: )print dup( )cvs print errordict exch get exec stop }bind def /ct_cvnsi { 1 index add 1 sub 1 exch 0 4 1 roll { 2 index exch get exch 8 bitshift add } for exch pop }bind def /ct_GetInterval { Adobe_CoolType_Utility/ct_BuildCharDict get begin /dst_index 0 def dup dst_string length gt {dup string/dst_string exch def} if 1 index ct_CID_STR_SIZE idiv /arrayIndex exch def 2 index arrayIndex get 2 index arrayIndex ct_CID_STR_SIZE mul sub { dup 3 index add 2 index length le { 2 index getinterval dst_string dst_index 2 index putinterval length dst_index add/dst_index exch def exit } { 1 index length 1 index sub dup 4 1 roll getinterval dst_string dst_index 2 index putinterval pop dup dst_index add/dst_index exch def sub /arrayIndex arrayIndex 1 add def 2 index dup length arrayIndex gt {arrayIndex get} { pop exit } ifelse 0 } ifelse } loop pop pop pop dst_string 0 dst_index getinterval end }bind def ct_Level2? { /ct_resourcestatus currentglobal mark true setglobal {/unknowninstancename/Category resourcestatus} stopped {cleartomark setglobal true} {cleartomark currentglobal not exch setglobal} ifelse { { mark 3 1 roll/Category findresource begin ct_Vars/vm currentglobal put ({ResourceStatus}stopped)0()/SubFileDecode filter cvx exec {cleartomark false} {{3 2 roll pop true}{cleartomark false}ifelse} ifelse ct_Vars/vm get setglobal end } } {{resourcestatus}} ifelse bind def /CIDFont/Category ct_resourcestatus {pop pop} { currentglobal true setglobal /Generic/Category findresource dup length dict copy dup/InstanceType/dicttype put /CIDFont exch/Category defineresource pop setglobal } ifelse ct_UseNativeCapability? { /CIDInit/ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo 3 dict dup begin /Registry(Adobe)def /Ordering(Identity)def /Supplement 0 def end def /CMapName/Identity-H def /CMapVersion 1.000 def /CMapType 1 def 1 begincodespacerange <0000> endcodespacerange 1 begincidrange <0000>0 endcidrange endcmap CMapName currentdict/CMap defineresource pop end end } if } { /ct_Category 2 dict begin /CIDFont 10 dict def /ProcSet 2 dict def currentdict end def /defineresource { ct_Category 1 index 2 copy known { get dup dup maxlength exch length eq { dup length 10 add dict copy ct_Category 2 index 2 index put } if 3 index 3 index put pop exch pop } {pop pop/defineresource/undefined ct_raise} ifelse }bind def /findresource { ct_Category 1 index 2 copy known { get 2 index 2 copy known {get 3 1 roll pop pop} {pop pop/findresource/undefinedresource ct_raise} ifelse } {pop pop/findresource/undefined ct_raise} ifelse }bind def /resourcestatus { ct_Category 1 index 2 copy known { get 2 index known exch pop exch pop { 0 -1 true } { false } ifelse } {pop pop/findresource/undefined ct_raise} ifelse }bind def /ct_resourcestatus/resourcestatus load def } ifelse /ct_CIDInit 2 dict begin /ct_cidfont_stream_init { { dup(Binary)eq { pop null currentfile ct_Level2? { {cid_BYTE_COUNT()/SubFileDecode filter} stopped {pop pop pop} if } if /readstring load exit } if dup(Hex)eq { pop currentfile ct_Level2? { {null exch/ASCIIHexDecode filter/readstring} stopped {pop exch pop(>)exch/readhexstring} if } {(>)exch/readhexstring} ifelse load exit } if /StartData/typecheck ct_raise } loop cid_BYTE_COUNT ct_CID_STR_SIZE le { 2 copy cid_BYTE_COUNT string exch exec pop 1 array dup 3 -1 roll 0 exch put } { cid_BYTE_COUNT ct_CID_STR_SIZE div ceiling cvi dup array exch 2 sub 0 exch 1 exch { 2 copy 5 index ct_CID_STR_SIZE string 6 index exec pop put pop } for 2 index cid_BYTE_COUNT ct_CID_STR_SIZE mod string 3 index exec pop 1 index exch 1 index length 1 sub exch put } ifelse cid_CIDFONT exch/GlyphData exch put 2 index null eq { pop pop pop } { pop/readstring load 1 string exch { 3 copy exec pop dup length 0 eq { pop pop pop pop pop true exit } if 4 index eq { pop pop pop pop false exit } if } loop pop } ifelse }bind def /StartData { mark { currentdict dup/FDArray get 0 get/FontMatrix get 0 get 0.001 eq { dup/CDevProc known not { /CDevProc 1183615869 internaldict/stdCDevProc 2 copy known {get} { pop pop {pop pop pop pop pop 0 -1000 7 index 2 div 880} } ifelse def } if } { /CDevProc { pop pop pop pop pop 0 1 cid_temp/cid_CIDFONT get /FDArray get 0 get /FontMatrix get 0 get div 7 index 2 div 1 index 0.88 mul }def } ifelse /cid_temp 15 dict def cid_temp begin /cid_CIDFONT exch def 3 copy pop dup/cid_BYTE_COUNT exch def 0 gt { ct_cidfont_stream_init FDArray { /Private get dup/SubrMapOffset known { begin /Subrs SubrCount array def Subrs SubrMapOffset SubrCount SDBytes ct_Level2? { currentdict dup/SubrMapOffset undef dup/SubrCount undef /SDBytes undef } if end /cid_SD_BYTES exch def /cid_SUBR_COUNT exch def /cid_SUBR_MAP_OFFSET exch def /cid_SUBRS exch def cid_SUBR_COUNT 0 gt { GlyphData cid_SUBR_MAP_OFFSET cid_SD_BYTES ct_GetInterval 0 cid_SD_BYTES ct_cvnsi 0 1 cid_SUBR_COUNT 1 sub { exch 1 index 1 add cid_SD_BYTES mul cid_SUBR_MAP_OFFSET add GlyphData exch cid_SD_BYTES ct_GetInterval 0 cid_SD_BYTES ct_cvnsi cid_SUBRS 4 2 roll GlyphData exch 4 index 1 index sub ct_GetInterval dup length string copy put } for pop } if } {pop} ifelse } forall } if cleartomark pop pop end CIDFontName currentdict/CIDFont defineresource pop end end } stopped {cleartomark/StartData ct_reraise} if }bind def currentdict end def /ct_saveCIDInit { /CIDInit/ProcSet ct_resourcestatus {true} {/CIDInitC/ProcSet ct_resourcestatus} ifelse { pop pop /CIDInit/ProcSet findresource ct_UseNativeCapability? {pop null} {/CIDInit ct_CIDInit/ProcSet defineresource pop} ifelse } {/CIDInit ct_CIDInit/ProcSet defineresource pop null} ifelse ct_Vars exch/ct_oldCIDInit exch put }bind def /ct_restoreCIDInit { ct_Vars/ct_oldCIDInit get dup null ne {/CIDInit exch/ProcSet defineresource pop} {pop} ifelse }bind def /ct_BuildCharSetUp { 1 index begin CIDFont begin Adobe_CoolType_Utility/ct_BuildCharDict get begin /ct_dfCharCode exch def /ct_dfDict exch def CIDFirstByte ct_dfCharCode add dup CIDCount ge {pop 0} if /cid exch def { GlyphDirectory cid 2 copy known {get} {pop pop nullstring} ifelse dup length FDBytes sub 0 gt { dup FDBytes 0 ne {0 FDBytes ct_cvnsi} {pop 0} ifelse /fdIndex exch def dup length FDBytes sub FDBytes exch getinterval /charstring exch def exit } { pop cid 0 eq {/charstring nullstring def exit} if /cid 0 def } ifelse } loop }def /ct_SetCacheDevice { 0 0 moveto dup stringwidth 3 -1 roll true charpath pathbbox 0 -1000 7 index 2 div 880 setcachedevice2 0 0 moveto }def /ct_CloneSetCacheProc { 1 eq { stringwidth pop -2 div -880 0 -1000 setcharwidth moveto } { usewidths? { currentfont/Widths get cid 2 copy known {get exch pop aload pop} {pop pop stringwidth} ifelse } {stringwidth} ifelse setcharwidth 0 0 moveto } ifelse }def /ct_Type3ShowCharString { ct_FDDict fdIndex 2 copy known {get} { currentglobal 3 1 roll 1 index gcheck setglobal ct_Type1FontTemplate dup maxlength dict copy begin FDArray fdIndex get dup/FontMatrix 2 copy known {get} {pop pop ct_defaultFontMtx} ifelse /FontMatrix exch dup length array copy def /Private get /Private exch def /Widths rootfont/Widths get def /CharStrings 1 dict dup/.notdef dup length string copy put def currentdict end /ct_Type1Font exch definefont dup 5 1 roll put setglobal } ifelse dup/CharStrings get 1 index/Encoding get ct_dfCharCode get charstring put rootfont/WMode 2 copy known {get} {pop pop 0} ifelse exch 1000 scalefont setfont ct_str1 0 ct_dfCharCode put ct_str1 exch ct_dfSetCacheProc ct_SyntheticBold { currentpoint ct_str1 show newpath moveto ct_str1 true charpath ct_StrokeWidth setlinewidth stroke } {ct_str1 show} ifelse }def /ct_Type4ShowCharString { ct_dfDict ct_dfCharCode charstring FDArray fdIndex get dup/FontMatrix get dup ct_defaultFontMtx ct_matrixeq not {ct_1000Mtx matrix concatmatrix concat} {pop} ifelse /Private get Adobe_CoolType_Utility/ct_Level2? get not { ct_dfDict/Private 3 -1 roll {put} 1183615869 internaldict/superexec get exec } if 1183615869 internaldict Adobe_CoolType_Utility/ct_Level2? get {1 index} {3 index/Private get mark 6 1 roll} ifelse dup/RunInt known {/RunInt get} {pop/CCRun} ifelse get exec Adobe_CoolType_Utility/ct_Level2? get not {cleartomark} if }bind def /ct_BuildCharIncremental { { Adobe_CoolType_Utility/ct_MakeOCF get begin ct_BuildCharSetUp ct_ShowCharString } stopped {stop} if end end end end }bind def /BaseFontNameStr(BF00)def /ct_Type1FontTemplate 14 dict begin /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0]def /FontBBox [-250 -250 1250 1250]def /Encoding ct_cHexEncoding def /PaintType 0 def currentdict end def /BaseFontTemplate 11 dict begin /FontMatrix [0.001 0 0 0.001 0 0]def /FontBBox [-250 -250 1250 1250]def /Encoding ct_cHexEncoding def /BuildChar/ct_BuildCharIncremental load def ct_Clone? { /FontType 3 def /ct_ShowCharString/ct_Type3ShowCharString load def /ct_dfSetCacheProc/ct_CloneSetCacheProc load def /ct_SyntheticBold false def /ct_StrokeWidth 1 def } { /FontType 4 def /Private 1 dict dup/lenIV 4 put def /CharStrings 1 dict dup/.notdefput def /PaintType 0 def /ct_ShowCharString/ct_Type4ShowCharString load def } ifelse /ct_str1 1 string def currentdict end def /BaseFontDictSize BaseFontTemplate length 5 add def /ct_matrixeq { true 0 1 5 { dup 4 index exch get exch 3 index exch get eq and dup not {exit} if } for exch pop exch pop }bind def /ct_makeocf { 15 dict begin exch/WMode exch def exch/FontName exch def /FontType 0 def /FMapType 2 def dup/FontMatrix known {dup/FontMatrix get/FontMatrix exch def} {/FontMatrix matrix def} ifelse /bfCount 1 index/CIDCount get 256 idiv 1 add dup 256 gt{pop 256}if def /Encoding 256 array 0 1 bfCount 1 sub{2 copy dup put pop}for bfCount 1 255{2 copy bfCount put pop}for def /FDepVector bfCount dup 256 lt{1 add}if array def BaseFontTemplate BaseFontDictSize dict copy begin /CIDFont exch def CIDFont/FontBBox known {CIDFont/FontBBox get/FontBBox exch def} if CIDFont/CDevProc known {CIDFont/CDevProc get/CDevProc exch def} if currentdict end BaseFontNameStr 3(0)putinterval 0 1 bfCount dup 256 eq{1 sub}if { FDepVector exch 2 index BaseFontDictSize dict copy begin dup/CIDFirstByte exch 256 mul def FontType 3 eq {/ct_FDDict 2 dict def} if currentdict end 1 index 16 BaseFontNameStr 2 2 getinterval cvrs pop BaseFontNameStr exch definefont put } for ct_Clone? {/Widths 1 index/CIDFont get/GlyphDirectory get length dict def} if FontName currentdict end definefont ct_Clone? { gsave dup 1000 scalefont setfont ct_BuildCharDict begin /usewidths? false def currentfont/Widths get begin exch/CIDFont get/GlyphDirectory get { pop dup charcode exch 1 index 0 2 index 256 idiv put 1 index exch 1 exch 256 mod put stringwidth 2 array astore def } forall end /usewidths? true def end grestore } {exch pop} ifelse }bind def currentglobal true setglobal /ct_ComposeFont { ct_UseNativeCapability? { 2 index/CMap ct_resourcestatus {pop pop exch pop} { /CIDInit/ProcSet findresource begin 12 dict begin begincmap /CMapName 3 index def /CMapVersion 1.000 def /CMapType 1 def exch/WMode exch def /CIDSystemInfo 3 dict dup begin /Registry(Adobe)def /Ordering CMapName ct_mkocfStr100 cvs (Adobe-)search { pop pop (-)search { dup length string copy exch pop exch pop } {pop(Identity)} ifelse } {pop (Identity)} ifelse def /Supplement 0 def end def 1 begincodespacerange <0000> endcodespacerange 1 begincidrange <0000>0 endcidrange endcmap CMapName currentdict/CMap defineresource pop end end } ifelse composefont } { 3 2 roll pop 0 get/CIDFont findresource ct_makeocf } ifelse }bind def setglobal /ct_MakeIdentity { ct_UseNativeCapability? { 1 index/CMap ct_resourcestatus {pop pop} { /CIDInit/ProcSet findresource begin 12 dict begin begincmap /CMapName 2 index def /CMapVersion 1.000 def /CMapType 1 def /CIDSystemInfo 3 dict dup begin /Registry(Adobe)def /Ordering CMapName ct_mkocfStr100 cvs (Adobe-)search { pop pop (-)search {dup length string copy exch pop exch pop} {pop(Identity)} ifelse } {pop(Identity)} ifelse def /Supplement 0 def end def 1 begincodespacerange <0000> endcodespacerange 1 begincidrange <0000>0 endcidrange endcmap CMapName currentdict/CMap defineresource pop end end } ifelse composefont } { exch pop 0 get/CIDFont findresource ct_makeocf } ifelse }bind def currentdict readonly pop end end %%EndResource setglobal %%BeginResource: procset Adobe_CoolType_Utility_T42 1.0 0 %%Copyright: Copyright 1987-2004 Adobe Systems Incorporated. %%Version: 1.0 0 userdict/ct_T42Dict 15 dict put ct_T42Dict begin /Is2015? { version cvi 2015 ge }bind def /AllocGlyphStorage { Is2015? { pop } { {string}forall }ifelse }bind def /Type42DictBegin { 25 dict begin /FontName exch def /CharStrings 256 dict begin /.notdef 0 def currentdict end def /Encoding exch def /PaintType 0 def /FontType 42 def /FontMatrix[1 0 0 1 0 0]def 4 array astore cvx/FontBBox exch def /sfnts }bind def /Type42DictEnd { currentdict dup/FontName get exch definefont end ct_T42Dict exch dup/FontName get exch put }bind def /RD{string currentfile exch readstring pop}executeonly def /PrepFor2015 { Is2015? { /GlyphDirectory 16 dict def sfnts 0 get dup 2 index (glyx) putinterval 2 index (locx) putinterval pop pop } { pop pop }ifelse }bind def /AddT42Char { Is2015? { /GlyphDirectory get begin def end pop pop } { /sfnts get 4 index get 3 index 2 index putinterval pop pop pop pop }ifelse }bind def /T0AddT42Mtx2 { /CIDFont findresource/Metrics2 get begin def end }bind def end %%EndResource currentglobal true setglobal %%BeginFile: MMFauxFont.prc %%Copyright: Copyright 1987-2001 Adobe Systems Incorporated. %%All Rights Reserved. userdict /ct_EuroDict 10 dict put ct_EuroDict begin /ct_CopyFont { { 1 index /FID ne {def} {pop pop} ifelse} forall } def /ct_GetGlyphOutline { gsave initmatrix newpath exch findfont dup length 1 add dict begin ct_CopyFont /Encoding Encoding dup length array copy dup 4 -1 roll 0 exch put def currentdict end /ct_EuroFont exch definefont 1000 scalefont setfont 0 0 moveto [ <00> stringwidth <00> false charpath pathbbox [ {/m cvx} {/l cvx} {/c cvx} {/cp cvx} pathforall grestore counttomark 8 add } def /ct_MakeGlyphProc { ] cvx /ct_PSBuildGlyph cvx ] cvx } def /ct_PSBuildGlyph { gsave 8 -1 roll pop 7 1 roll 6 -2 roll ct_FontMatrix transform 6 2 roll 4 -2 roll ct_FontMatrix transform 4 2 roll ct_FontMatrix transform currentdict /PaintType 2 copy known {get 2 eq}{pop pop false} ifelse dup 9 1 roll { currentdict /StrokeWidth 2 copy known { get 2 div 0 ct_FontMatrix dtransform pop 5 1 roll 4 -1 roll 4 index sub 4 1 roll 3 -1 roll 4 index sub 3 1 roll exch 4 index add exch 4 index add 5 -1 roll pop } { pop pop } ifelse } if setcachedevice ct_FontMatrix concat ct_PSPathOps begin exec end { currentdict /StrokeWidth 2 copy known { get } { pop pop 0 } ifelse setlinewidth stroke } { fill } ifelse grestore } def /ct_PSPathOps 4 dict dup begin /m {moveto} def /l {lineto} def /c {curveto} def /cp {closepath} def end def /ct_matrix1000 [1000 0 0 1000 0 0] def /ct_AddGlyphProc { 2 index findfont dup length 4 add dict begin ct_CopyFont /CharStrings CharStrings dup length 1 add dict copy begin 3 1 roll def currentdict end def /ct_FontMatrix ct_matrix1000 FontMatrix matrix concatmatrix def /ct_PSBuildGlyph /ct_PSBuildGlyph load def /ct_PSPathOps /ct_PSPathOps load def currentdict end definefont pop } def systemdict /languagelevel known { /ct_AddGlyphToPrinterFont { 2 copy ct_GetGlyphOutline 3 add -1 roll restore ct_MakeGlyphProc ct_AddGlyphProc } def } { /ct_AddGlyphToPrinterFont { pop pop restore Adobe_CTFauxDict /$$$FONTNAME get /Euro Adobe_CTFauxDict /$$$SUBSTITUTEBASE get ct_EuroDict exch get ct_AddGlyphProc } def } ifelse /AdobeSansMM { 556 0 24 -19 541 703 { 541 628 m 510 669 442 703 354 703 c 201 703 117 607 101 444 c 50 444 l 25 372 l 97 372 l 97 301 l 49 301 l 24 229 l 103 229 l 124 67 209 -19 350 -19 c 435 -19 501 25 509 32 c 509 131 l 492 105 417 60 343 60 c 267 60 204 127 197 229 c 406 229 l 430 301 l 191 301 l 191 372 l 455 372 l 479 444 l 194 444 l 201 531 245 624 348 624 c 433 624 484 583 509 534 c cp 556 0 m } ct_PSBuildGlyph } def /AdobeSerifMM { 500 0 10 -12 484 692 { 347 298 m 171 298 l 170 310 170 322 170 335 c 170 362 l 362 362 l 374 403 l 172 403 l 184 580 244 642 308 642 c 380 642 434 574 457 457 c 481 462 l 474 691 l 449 691 l 433 670 429 657 410 657 c 394 657 360 692 299 692 c 204 692 94 604 73 403 c 22 403 l 10 362 l 70 362 l 69 352 69 341 69 330 c 69 319 69 308 70 298 c 22 298 l 10 257 l 73 257 l 97 57 216 -12 295 -12 c 364 -12 427 25 484 123 c 458 142 l 425 101 384 37 316 37 c 256 37 189 84 173 257 c 335 257 l cp 500 0 m } ct_PSBuildGlyph } def end %%EndFile setglobal Adobe_CoolType_Core begin /$Oblique SetSubstituteStrategy end %%BeginResource: procset Adobe_AGM_Image 1.0 0 +%%Version: 1.0 0 +%%Copyright: Copyright(C)2000-2006 Adobe Systems, Inc. All Rights Reserved. +systemdict/setpacking known +{ + currentpacking + true setpacking +}if +userdict/Adobe_AGM_Image 71 dict dup begin put +/Adobe_AGM_Image_Id/Adobe_AGM_Image_1.0_0 def +/nd{ + null def +}bind def +/AGMIMG_&image nd +/AGMIMG_&colorimage nd +/AGMIMG_&imagemask nd +/AGMIMG_mbuf()def +/AGMIMG_ybuf()def +/AGMIMG_kbuf()def +/AGMIMG_c 0 def +/AGMIMG_m 0 def +/AGMIMG_y 0 def +/AGMIMG_k 0 def +/AGMIMG_tmp nd +/AGMIMG_imagestring0 nd +/AGMIMG_imagestring1 nd +/AGMIMG_imagestring2 nd +/AGMIMG_imagestring3 nd +/AGMIMG_imagestring4 nd +/AGMIMG_imagestring5 nd +/AGMIMG_cnt nd +/AGMIMG_fsave nd +/AGMIMG_colorAry nd +/AGMIMG_override nd +/AGMIMG_name nd +/AGMIMG_maskSource nd +/AGMIMG_flushfilters nd +/invert_image_samples nd +/knockout_image_samples nd +/img nd +/sepimg nd +/devnimg nd +/idximg nd +/ds +{ + Adobe_AGM_Core begin + Adobe_AGM_Image begin + /AGMIMG_&image systemdict/image get def + /AGMIMG_&imagemask systemdict/imagemask get def + /colorimage where{ + pop + /AGMIMG_&colorimage/colorimage ldf + }if + end + end +}def +/ps +{ + Adobe_AGM_Image begin + /AGMIMG_ccimage_exists{/customcolorimage where + { + pop + /Adobe_AGM_OnHost_Seps where + { + pop false + }{ + /Adobe_AGM_InRip_Seps where + { + pop false + }{ + true + }ifelse + }ifelse + }{ + false + }ifelse + }bdf + level2{ + /invert_image_samples + { + Adobe_AGM_Image/AGMIMG_tmp Decode length ddf + /Decode[Decode 1 get Decode 0 get]def + }def + /knockout_image_samples + { + Operator/imagemask ne{ + /Decode[1 1]def + }if + }def + }{ + /invert_image_samples + { + {1 exch sub}currenttransfer addprocs settransfer + }def + /knockout_image_samples + { + {pop 1}currenttransfer addprocs settransfer + }def + }ifelse + /img/imageormask ldf + /sepimg/sep_imageormask ldf + /devnimg/devn_imageormask ldf + /idximg/indexed_imageormask ldf + /_ctype 7 def + currentdict{ + dup xcheck 1 index type dup/arraytype eq exch/packedarraytype eq or and{ + bind + }if + def + }forall +}def +/pt +{ + end +}def +/dt +{ +}def +/AGMIMG_flushfilters +{ + dup type/arraytype ne + {1 array astore}if + dup 0 get currentfile ne + {dup 0 get flushfile}if + { + dup type/filetype eq + { + dup status 1 index currentfile ne and + {closefile} + {pop} + ifelse + }{pop}ifelse + }forall +}def +/AGMIMG_init_common +{ + currentdict/T known{/ImageType/T ldf currentdict/T undef}if + currentdict/W known{/Width/W ldf currentdict/W undef}if + currentdict/H known{/Height/H ldf currentdict/H undef}if + currentdict/M known{/ImageMatrix/M ldf currentdict/M undef}if + currentdict/BC known{/BitsPerComponent/BC ldf currentdict/BC undef}if + currentdict/D known{/Decode/D ldf currentdict/D undef}if + currentdict/DS known{/DataSource/DS ldf currentdict/DS undef}if + currentdict/O known{ + /Operator/O load 1 eq{ + /imagemask + }{ + /O load 2 eq{ + /image + }{ + /colorimage + }ifelse + }ifelse + def + currentdict/O undef + }if + currentdict/HSCI known{/HostSepColorImage/HSCI ldf currentdict/HSCI undef}if + currentdict/MD known{/MultipleDataSources/MD ldf currentdict/MD undef}if + currentdict/I known{/Interpolate/I ldf currentdict/I undef}if + currentdict/SI known{/SkipImageProc/SI ldf currentdict/SI undef}if + /DataSource load xcheck not{ + DataSource type/arraytype eq{ + DataSource 0 get type/filetype eq{ + /_Filters DataSource def + currentdict/MultipleDataSources known not{ + /DataSource DataSource dup length 1 sub get def + }if + }if + }if + currentdict/MultipleDataSources known not{ + /MultipleDataSources DataSource type/arraytype eq{ + DataSource length 1 gt + } + {false}ifelse def + }if + }if + /NComponents Decode length 2 div def + currentdict/SkipImageProc known not{/SkipImageProc{false}def}if +}bdf +/imageormask_sys +{ + begin + AGMIMG_init_common + save mark + level2{ + currentdict + Operator/imagemask eq{ + AGMIMG_&imagemask + }{ + use_mask{ + process_mask AGMIMG_&image + }{ + AGMIMG_&image + }ifelse + }ifelse + }{ + Width Height + Operator/imagemask eq{ + Decode 0 get 1 eq Decode 1 get 0 eq and + ImageMatrix/DataSource load + AGMIMG_&imagemask + }{ + BitsPerComponent ImageMatrix/DataSource load + AGMIMG_&image + }ifelse + }ifelse + currentdict/_Filters known{_Filters AGMIMG_flushfilters}if + cleartomark restore + end +}def +/overprint_plate +{ + currentoverprint{ + 0 get dup type/nametype eq{ + dup/DeviceGray eq{ + pop AGMCORE_black_plate not + }{ + /DeviceCMYK eq{ + AGMCORE_is_cmyk_sep not + }if + }ifelse + }{ + false exch + { + AGMOHS_sepink eq or + }forall + not + }ifelse + }{ + pop false + }ifelse +}def +/process_mask +{ + level3{ + dup begin + /ImageType 1 def + end + 4 dict begin + /DataDict exch def + /ImageType 3 def + /InterleaveType 3 def + /MaskDict 9 dict begin + /ImageType 1 def + /Width DataDict dup/MaskWidth known{/MaskWidth}{/Width}ifelse get def + /Height DataDict dup/MaskHeight known{/MaskHeight}{/Height}ifelse get def + /ImageMatrix[Width 0 0 Height neg 0 Height]def + /NComponents 1 def + /BitsPerComponent 1 def + /Decode DataDict dup/MaskD known{/MaskD}{[1 0]}ifelse get def + /DataSource Adobe_AGM_Core/AGMIMG_maskSource get def + currentdict end def + currentdict end + }if +}def +/use_mask +{ + dup/Mask known {dup/Mask get}{false}ifelse +}def +/imageormask +{ + begin + AGMIMG_init_common + SkipImageProc{ + currentdict consumeimagedata + } + { + save mark + level2 AGMCORE_host_sep not and{ + currentdict + Operator/imagemask eq DeviceN_PS2 not and{ + imagemask + }{ + AGMCORE_in_rip_sep currentoverprint and currentcolorspace 0 get/DeviceGray eq and{ + [/Separation/Black/DeviceGray{}]setcolorspace + /Decode[Decode 1 get Decode 0 get]def + }if + use_mask{ + process_mask image + }{ + DeviceN_NoneName DeviceN_PS2 Indexed_DeviceN level3 not and or or AGMCORE_in_rip_sep and + { + Names convert_to_process not{ + 2 dict begin + /imageDict xdf + /names_index 0 def + gsave + imageDict write_image_file{ + Names{ + dup(None)ne{ + [/Separation 3 -1 roll/DeviceGray{1 exch sub}]setcolorspace + Operator imageDict read_image_file + names_index 0 eq{true setoverprint}if + /names_index names_index 1 add def + }{ + pop + }ifelse + }forall + close_image_file + }if + grestore + end + }{ + Operator/imagemask eq{ + imagemask + }{ + image + }ifelse + }ifelse + }{ + Operator/imagemask eq{ + imagemask + }{ + image + }ifelse + }ifelse + }ifelse + }ifelse + }{ + Width Height + Operator/imagemask eq{ + Decode 0 get 1 eq Decode 1 get 0 eq and + ImageMatrix/DataSource load + /Adobe_AGM_OnHost_Seps where{ + pop imagemask + }{ + currentgray 1 ne{ + currentdict imageormask_sys + }{ + currentoverprint not{ + 1 AGMCORE_&setgray + currentdict imageormask_sys + }{ + currentdict ignoreimagedata + }ifelse + }ifelse + }ifelse + }{ + BitsPerComponent ImageMatrix + MultipleDataSources{ + 0 1 NComponents 1 sub{ + DataSource exch get + }for + }{ + /DataSource load + }ifelse + Operator/colorimage eq{ + AGMCORE_host_sep{ + MultipleDataSources level2 or NComponents 4 eq and{ + AGMCORE_is_cmyk_sep{ + MultipleDataSources{ + /DataSource DataSource 0 get xcheck + { + [ + DataSource 0 get/exec cvx + DataSource 1 get/exec cvx + DataSource 2 get/exec cvx + DataSource 3 get/exec cvx + /AGMCORE_get_ink_data cvx + ]cvx + }{ + DataSource aload pop AGMCORE_get_ink_data + }ifelse def + }{ + /DataSource + Width BitsPerComponent mul 7 add 8 idiv Height mul 4 mul + /DataSource load + filter_cmyk 0()/SubFileDecode filter def + }ifelse + /Decode[Decode 0 get Decode 1 get]def + /MultipleDataSources false def + /NComponents 1 def + /Operator/image def + invert_image_samples + 1 AGMCORE_&setgray + currentdict imageormask_sys + }{ + currentoverprint not Operator/imagemask eq and{ + 1 AGMCORE_&setgray + currentdict imageormask_sys + }{ + currentdict ignoreimagedata + }ifelse + }ifelse + }{ + MultipleDataSources NComponents AGMIMG_&colorimage + }ifelse + }{ + true NComponents colorimage + }ifelse + }{ + Operator/image eq{ + AGMCORE_host_sep{ + /DoImage true def + currentdict/HostSepColorImage known{HostSepColorImage not}{false}ifelse + { + AGMCORE_black_plate not Operator/imagemask ne and{ + /DoImage false def + currentdict ignoreimagedata + }if + }if + 1 AGMCORE_&setgray + DoImage + {currentdict imageormask_sys}if + }{ + use_mask{ + process_mask image + }{ + image + }ifelse + }ifelse + }{ + Operator/knockout eq{ + pop pop pop pop pop + currentcolorspace overprint_plate not{ + knockout_unitsq + }if + }if + }ifelse + }ifelse + }ifelse + }ifelse + cleartomark restore + }ifelse + currentdict/_Filters known{_Filters AGMIMG_flushfilters}if + end +}def +/sep_imageormask +{ + /sep_colorspace_dict AGMCORE_gget begin + CSA map_csa + begin + AGMIMG_init_common + SkipImageProc{ + currentdict consumeimagedata + }{ + save mark + AGMCORE_avoid_L2_sep_space{ + /Decode[Decode 0 get 255 mul Decode 1 get 255 mul]def + }if + AGMIMG_ccimage_exists + MappedCSA 0 get/DeviceCMYK eq and + currentdict/Components known and + Name()ne and + Name(All)ne and + Operator/image eq and + AGMCORE_producing_seps not and + level2 not and + { + Width Height BitsPerComponent ImageMatrix + [ + /DataSource load/exec cvx + { + 0 1 2 index length 1 sub{ + 1 index exch + 2 copy get 255 xor put + }for + }/exec cvx + ]cvx bind + MappedCSA 0 get/DeviceCMYK eq{ + Components aload pop + }{ + 0 0 0 Components aload pop 1 exch sub + }ifelse + Name findcmykcustomcolor + customcolorimage + }{ + AGMCORE_producing_seps not{ + level2{ + //Adobe_AGM_Core/AGMCORE_pattern_paint_type get 2 ne AGMCORE_avoid_L2_sep_space not and currentcolorspace 0 get/Separation ne and{ + [/Separation Name MappedCSA sep_proc_name exch dup 0 get 15 string cvs(/Device)anchorsearch{pop pop 0 get}{pop}ifelse exch load]setcolorspace_opt + /sep_tint AGMCORE_gget setcolor + }if + currentdict imageormask + }{ + currentdict + Operator/imagemask eq{ + imageormask + }{ + sep_imageormask_lev1 + }ifelse + }ifelse + }{ + AGMCORE_host_sep{ + Operator/knockout eq{ + currentdict/ImageMatrix get concat + knockout_unitsq + }{ + currentgray 1 ne{ + AGMCORE_is_cmyk_sep Name(All)ne and{ + level2{ + Name AGMCORE_IsSeparationAProcessColor + { + Operator/imagemask eq{ + //Adobe_AGM_Core/AGMCORE_pattern_paint_type get 2 ne{ + /sep_tint AGMCORE_gget 1 exch sub AGMCORE_&setcolor + }if + }{ + invert_image_samples + }ifelse + }{ + //Adobe_AGM_Core/AGMCORE_pattern_paint_type get 2 ne{ + [/Separation Name[/DeviceGray] + { + sep_colorspace_proc AGMCORE_get_ink_data + 1 exch sub + }bind + ]AGMCORE_&setcolorspace + /sep_tint AGMCORE_gget AGMCORE_&setcolor + }if + }ifelse + currentdict imageormask_sys + }{ + currentdict + Operator/imagemask eq{ + imageormask_sys + }{ + sep_image_lev1_sep + }ifelse + }ifelse + }{ + Operator/imagemask ne{ + invert_image_samples + }if + currentdict imageormask_sys + }ifelse + }{ + currentoverprint not Name(All)eq or Operator/imagemask eq and{ + currentdict imageormask_sys + }{ + currentoverprint not + { + gsave + knockout_unitsq + grestore + }if + currentdict consumeimagedata + }ifelse + }ifelse + }ifelse + }{ + //Adobe_AGM_Core/AGMCORE_pattern_paint_type get 2 ne{ + currentcolorspace 0 get/Separation ne{ + [/Separation Name MappedCSA sep_proc_name exch 0 get exch load]setcolorspace_opt + /sep_tint AGMCORE_gget setcolor + }if + }if + currentoverprint + MappedCSA 0 get/DeviceCMYK eq and + Name AGMCORE_IsSeparationAProcessColor not and + //Adobe_AGM_Core/AGMCORE_pattern_paint_type get 2 ne{Name inRip_spot_has_ink not and}{false}ifelse + Name(All)ne and{ + imageormask_l2_overprint + }{ + currentdict imageormask + }ifelse + }ifelse + }ifelse + }ifelse + cleartomark restore + }ifelse + currentdict/_Filters known{_Filters AGMIMG_flushfilters}if + end + end +}def +/colorSpaceElemCnt +{ + mark currentcolor counttomark dup 2 add 1 roll cleartomark +}bdf +/devn_sep_datasource +{ + 1 dict begin + /dataSource xdf + [ + 0 1 dataSource length 1 sub{ + dup currentdict/dataSource get/exch cvx/get cvx/exec cvx + /exch cvx names_index/ne cvx[/pop cvx]cvx/if cvx + }for + ]cvx bind + end +}bdf +/devn_alt_datasource +{ + 11 dict begin + /convProc xdf + /origcolorSpaceElemCnt xdf + /origMultipleDataSources xdf + /origBitsPerComponent xdf + /origDecode xdf + /origDataSource xdf + /dsCnt origMultipleDataSources{origDataSource length}{1}ifelse def + /DataSource origMultipleDataSources + { + [ + BitsPerComponent 8 idiv origDecode length 2 idiv mul string + 0 1 origDecode length 2 idiv 1 sub + { + dup 7 mul 1 add index exch dup BitsPerComponent 8 idiv mul exch + origDataSource exch get 0()/SubFileDecode filter + BitsPerComponent 8 idiv string/readstring cvx/pop cvx/putinterval cvx + }for + ]bind cvx + }{origDataSource}ifelse 0()/SubFileDecode filter def + [ + origcolorSpaceElemCnt string + 0 2 origDecode length 2 sub + { + dup origDecode exch get dup 3 -1 roll 1 add origDecode exch get exch sub 2 BitsPerComponent exp 1 sub div + 1 BitsPerComponent 8 idiv{DataSource/read cvx/not cvx{0}/if cvx/mul cvx}repeat/mul cvx/add cvx + }for + /convProc load/exec cvx + origcolorSpaceElemCnt 1 sub -1 0 + { + /dup cvx 2/add cvx/index cvx + 3 1/roll cvx/exch cvx 255/mul cvx/cvi cvx/put cvx + }for + ]bind cvx 0()/SubFileDecode filter + end +}bdf +/devn_imageormask +{ + /devicen_colorspace_dict AGMCORE_gget begin + CSA map_csa + 2 dict begin + dup + /srcDataStrs[3 -1 roll begin + AGMIMG_init_common + currentdict/MultipleDataSources known{MultipleDataSources{DataSource length}{1}ifelse}{1}ifelse + { + Width Decode length 2 div mul cvi + { + dup 65535 gt{1 add 2 div cvi}{exit}ifelse + }loop + string + }repeat + end]def + /dstDataStr srcDataStrs 0 get length string def + begin + AGMIMG_init_common + SkipImageProc{ + currentdict consumeimagedata + }{ + save mark + AGMCORE_producing_seps not{ + level3 not{ + Operator/imagemask ne{ + /DataSource[[ + DataSource Decode BitsPerComponent currentdict/MultipleDataSources known{MultipleDataSources}{false}ifelse + colorSpaceElemCnt/devicen_colorspace_dict AGMCORE_gget/TintTransform get + devn_alt_datasource 1/string cvx/readstring cvx/pop cvx]cvx colorSpaceElemCnt 1 sub{dup}repeat]def + /MultipleDataSources true def + /Decode colorSpaceElemCnt[exch{0 1}repeat]def + }if + }if + currentdict imageormask + }{ + AGMCORE_host_sep{ + Names convert_to_process{ + CSA get_csa_by_name 0 get/DeviceCMYK eq{ + /DataSource + Width BitsPerComponent mul 7 add 8 idiv Height mul 4 mul + DataSource Decode BitsPerComponent currentdict/MultipleDataSources known{MultipleDataSources}{false}ifelse + 4/devicen_colorspace_dict AGMCORE_gget/TintTransform get + devn_alt_datasource + filter_cmyk 0()/SubFileDecode filter def + /MultipleDataSources false def + /Decode[1 0]def + /DeviceGray setcolorspace + currentdict imageormask_sys + }{ + AGMCORE_report_unsupported_color_space + AGMCORE_black_plate{ + /DataSource + DataSource Decode BitsPerComponent currentdict/MultipleDataSources known{MultipleDataSources}{false}ifelse + CSA get_csa_by_name 0 get/DeviceRGB eq{3}{1}ifelse/devicen_colorspace_dict AGMCORE_gget/TintTransform get + devn_alt_datasource + /MultipleDataSources false def + /Decode colorSpaceElemCnt[exch{0 1}repeat]def + currentdict imageormask_sys + }{ + gsave + knockout_unitsq + grestore + currentdict consumeimagedata + }ifelse + }ifelse + } + { + /devicen_colorspace_dict AGMCORE_gget/names_index known{ + Operator/imagemask ne{ + MultipleDataSources{ + /DataSource[DataSource devn_sep_datasource/exec cvx]cvx def + /MultipleDataSources false def + }{ + /DataSource/DataSource load dstDataStr srcDataStrs 0 get filter_devn def + }ifelse + invert_image_samples + }if + currentdict imageormask_sys + }{ + currentoverprint not Operator/imagemask eq and{ + currentdict imageormask_sys + }{ + currentoverprint not + { + gsave + knockout_unitsq + grestore + }if + currentdict consumeimagedata + }ifelse + }ifelse + }ifelse + }{ + currentdict imageormask + }ifelse + }ifelse + cleartomark restore + }ifelse + currentdict/_Filters known{_Filters AGMIMG_flushfilters}if + end + end + end +}def +/imageormask_l2_overprint +{ + currentdict + currentcmykcolor add add add 0 eq{ + currentdict consumeimagedata + }{ + level3{ + currentcmykcolor + /AGMIMG_k xdf + /AGMIMG_y xdf + /AGMIMG_m xdf + /AGMIMG_c xdf + Operator/imagemask eq{ + [/DeviceN[ + AGMIMG_c 0 ne{/Cyan}if + AGMIMG_m 0 ne{/Magenta}if + AGMIMG_y 0 ne{/Yellow}if + AGMIMG_k 0 ne{/Black}if + ]/DeviceCMYK{}]setcolorspace + AGMIMG_c 0 ne{AGMIMG_c}if + AGMIMG_m 0 ne{AGMIMG_m}if + AGMIMG_y 0 ne{AGMIMG_y}if + AGMIMG_k 0 ne{AGMIMG_k}if + setcolor + }{ + /Decode[Decode 0 get 255 mul Decode 1 get 255 mul]def + [/Indexed + [ + /DeviceN[ + AGMIMG_c 0 ne{/Cyan}if + AGMIMG_m 0 ne{/Magenta}if + AGMIMG_y 0 ne{/Yellow}if + AGMIMG_k 0 ne{/Black}if + ] + /DeviceCMYK{ + AGMIMG_k 0 eq{0}if + AGMIMG_y 0 eq{0 exch}if + AGMIMG_m 0 eq{0 3 1 roll}if + AGMIMG_c 0 eq{0 4 1 roll}if + } + ] + 255 + { + 255 div + mark exch + dup dup dup + AGMIMG_k 0 ne{ + /sep_tint AGMCORE_gget mul MappedCSA sep_proc_name exch pop load exec 4 1 roll pop pop pop + counttomark 1 roll + }{ + pop + }ifelse + AGMIMG_y 0 ne{ + /sep_tint AGMCORE_gget mul MappedCSA sep_proc_name exch pop load exec 4 2 roll pop pop pop + counttomark 1 roll + }{ + pop + }ifelse + AGMIMG_m 0 ne{ + /sep_tint AGMCORE_gget mul MappedCSA sep_proc_name exch pop load exec 4 3 roll pop pop pop + counttomark 1 roll + }{ + pop + }ifelse + AGMIMG_c 0 ne{ + /sep_tint AGMCORE_gget mul MappedCSA sep_proc_name exch pop load exec pop pop pop + counttomark 1 roll + }{ + pop + }ifelse + counttomark 1 add -1 roll pop + } + ]setcolorspace + }ifelse + imageormask_sys + }{ + write_image_file{ + currentcmykcolor + 0 ne{ + [/Separation/Black/DeviceGray{}]setcolorspace + gsave + /Black + [{1 exch sub/sep_tint AGMCORE_gget mul}/exec cvx MappedCSA sep_proc_name cvx exch pop{4 1 roll pop pop pop 1 exch sub}/exec cvx] + cvx modify_halftone_xfer + Operator currentdict read_image_file + grestore + }if + 0 ne{ + [/Separation/Yellow/DeviceGray{}]setcolorspace + gsave + /Yellow + [{1 exch sub/sep_tint AGMCORE_gget mul}/exec cvx MappedCSA sep_proc_name cvx exch pop{4 2 roll pop pop pop 1 exch sub}/exec cvx] + cvx modify_halftone_xfer + Operator currentdict read_image_file + grestore + }if + 0 ne{ + [/Separation/Magenta/DeviceGray{}]setcolorspace + gsave + /Magenta + [{1 exch sub/sep_tint AGMCORE_gget mul}/exec cvx MappedCSA sep_proc_name cvx exch pop{4 3 roll pop pop pop 1 exch sub}/exec cvx] + cvx modify_halftone_xfer + Operator currentdict read_image_file + grestore + }if + 0 ne{ + [/Separation/Cyan/DeviceGray{}]setcolorspace + gsave + /Cyan + [{1 exch sub/sep_tint AGMCORE_gget mul}/exec cvx MappedCSA sep_proc_name cvx exch pop{pop pop pop 1 exch sub}/exec cvx] + cvx modify_halftone_xfer + Operator currentdict read_image_file + grestore + }if + close_image_file + }{ + imageormask + }ifelse + }ifelse + }ifelse +}def +/indexed_imageormask +{ + begin + AGMIMG_init_common + save mark + currentdict + AGMCORE_host_sep{ + Operator/knockout eq{ + /indexed_colorspace_dict AGMCORE_gget dup/CSA known{ + /CSA get get_csa_by_name + }{ + /Names get + }ifelse + overprint_plate not{ + knockout_unitsq + }if + }{ + Indexed_DeviceN{ + /devicen_colorspace_dict AGMCORE_gget dup/names_index known exch/Names get convert_to_process or{ + indexed_image_lev2_sep + }{ + currentoverprint not{ + knockout_unitsq + }if + currentdict consumeimagedata + }ifelse + }{ + AGMCORE_is_cmyk_sep{ + Operator/imagemask eq{ + imageormask_sys + }{ + level2{ + indexed_image_lev2_sep + }{ + indexed_image_lev1_sep + }ifelse + }ifelse + }{ + currentoverprint not{ + knockout_unitsq + }if + currentdict consumeimagedata + }ifelse + }ifelse + }ifelse + }{ + level2{ + Indexed_DeviceN{ + /indexed_colorspace_dict AGMCORE_gget begin + }{ + /indexed_colorspace_dict AGMCORE_gget dup null ne + { + begin + currentdict/CSDBase known{CSDBase/CSD get_res/MappedCSA get}{CSA}ifelse + get_csa_by_name 0 get/DeviceCMYK eq ps_level 3 ge and ps_version 3015.007 lt and + AGMCORE_in_rip_sep and{ + [/Indexed[/DeviceN[/Cyan/Magenta/Yellow/Black]/DeviceCMYK{}]HiVal Lookup] + setcolorspace + }if + end + } + {pop}ifelse + }ifelse + imageormask + Indexed_DeviceN{ + end + }if + }{ + Operator/imagemask eq{ + imageormask + }{ + indexed_imageormask_lev1 + }ifelse + }ifelse + }ifelse + cleartomark restore + currentdict/_Filters known{_Filters AGMIMG_flushfilters}if + end +}def +/indexed_image_lev2_sep +{ + /indexed_colorspace_dict AGMCORE_gget begin + begin + Indexed_DeviceN not{ + currentcolorspace + dup 1/DeviceGray put + dup 3 + currentcolorspace 2 get 1 add string + 0 1 2 3 AGMCORE_get_ink_data 4 currentcolorspace 3 get length 1 sub + { + dup 4 idiv exch currentcolorspace 3 get exch get 255 exch sub 2 index 3 1 roll put + }for + put setcolorspace + }if + currentdict + Operator/imagemask eq{ + AGMIMG_&imagemask + }{ + use_mask{ + process_mask AGMIMG_&image + }{ + AGMIMG_&image + }ifelse + }ifelse + end end +}def + /OPIimage + { + dup type/dicttype ne{ + 10 dict begin + /DataSource xdf + /ImageMatrix xdf + /BitsPerComponent xdf + /Height xdf + /Width xdf + /ImageType 1 def + /Decode[0 1 def] + currentdict + end + }if + dup begin + /NComponents 1 cdndf + /MultipleDataSources false cdndf + /SkipImageProc{false}cdndf + /Decode[ + 0 + currentcolorspace 0 get/Indexed eq{ + 2 BitsPerComponent exp 1 sub + }{ + 1 + }ifelse + ]cdndf + /Operator/image cdndf + end + /sep_colorspace_dict AGMCORE_gget null eq{ + imageormask + }{ + gsave + dup begin invert_image_samples end + sep_imageormask + grestore + }ifelse + }def +/cachemask_level2 +{ + 3 dict begin + /LZWEncode filter/WriteFilter xdf + /readBuffer 256 string def + /ReadFilter + currentfile + 0(%EndMask)/SubFileDecode filter + /ASCII85Decode filter + /RunLengthDecode filter + def + { + ReadFilter readBuffer readstring exch + WriteFilter exch writestring + not{exit}if + }loop + WriteFilter closefile + end +}def +/spot_alias +{ + /mapto_sep_imageormask + { + dup type/dicttype ne{ + 12 dict begin + /ImageType 1 def + /DataSource xdf + /ImageMatrix xdf + /BitsPerComponent xdf + /Height xdf + /Width xdf + /MultipleDataSources false def + }{ + begin + }ifelse + /Decode[/customcolor_tint AGMCORE_gget 0]def + /Operator/image def + /SkipImageProc{false}def + currentdict + end + sep_imageormask + }bdf + /customcolorimage + { + Adobe_AGM_Image/AGMIMG_colorAry xddf + /customcolor_tint AGMCORE_gget + << + /Name AGMIMG_colorAry 4 get + /CSA[/DeviceCMYK] + /TintMethod/Subtractive + /TintProc null + /MappedCSA null + /NComponents 4 + /Components[AGMIMG_colorAry aload pop pop] + >> + setsepcolorspace + mapto_sep_imageormask + }ndf + Adobe_AGM_Image/AGMIMG_&customcolorimage/customcolorimage load put + /customcolorimage + { + Adobe_AGM_Image/AGMIMG_override false put + current_spot_alias{dup 4 get map_alias}{false}ifelse + { + false set_spot_alias + /customcolor_tint AGMCORE_gget exch setsepcolorspace + pop + mapto_sep_imageormask + true set_spot_alias + }{ + //Adobe_AGM_Image/AGMIMG_&customcolorimage get exec + }ifelse + }bdf +}def +/snap_to_device +{ + 6 dict begin + matrix currentmatrix + dup 0 get 0 eq 1 index 3 get 0 eq and + 1 index 1 get 0 eq 2 index 2 get 0 eq and or exch pop + { + 1 1 dtransform 0 gt exch 0 gt/AGMIMG_xSign? exch def/AGMIMG_ySign? exch def + 0 0 transform + AGMIMG_ySign?{floor 0.1 sub}{ceiling 0.1 add}ifelse exch + AGMIMG_xSign?{floor 0.1 sub}{ceiling 0.1 add}ifelse exch + itransform/AGMIMG_llY exch def/AGMIMG_llX exch def + 1 1 transform + AGMIMG_ySign?{ceiling 0.1 add}{floor 0.1 sub}ifelse exch + AGMIMG_xSign?{ceiling 0.1 add}{floor 0.1 sub}ifelse exch + itransform/AGMIMG_urY exch def/AGMIMG_urX exch def + [AGMIMG_urX AGMIMG_llX sub 0 0 AGMIMG_urY AGMIMG_llY sub AGMIMG_llX AGMIMG_llY]concat + }{ + }ifelse + end +}def +level2 not{ + /colorbuf + { + 0 1 2 index length 1 sub{ + dup 2 index exch get + 255 exch sub + 2 index + 3 1 roll + put + }for + }def + /tint_image_to_color + { + begin + Width Height BitsPerComponent ImageMatrix + /DataSource load + end + Adobe_AGM_Image begin + /AGMIMG_mbuf 0 string def + /AGMIMG_ybuf 0 string def + /AGMIMG_kbuf 0 string def + { + colorbuf dup length AGMIMG_mbuf length ne + { + dup length dup dup + /AGMIMG_mbuf exch string def + /AGMIMG_ybuf exch string def + /AGMIMG_kbuf exch string def + }if + dup AGMIMG_mbuf copy AGMIMG_ybuf copy AGMIMG_kbuf copy pop + } + addprocs + {AGMIMG_mbuf}{AGMIMG_ybuf}{AGMIMG_kbuf}true 4 colorimage + end + }def + /sep_imageormask_lev1 + { + begin + MappedCSA 0 get dup/DeviceRGB eq exch/DeviceCMYK eq or has_color not and{ + { + 255 mul round cvi GrayLookup exch get + }currenttransfer addprocs settransfer + currentdict imageormask + }{ + /sep_colorspace_dict AGMCORE_gget/Components known{ + MappedCSA 0 get/DeviceCMYK eq{ + Components aload pop + }{ + 0 0 0 Components aload pop 1 exch sub + }ifelse + Adobe_AGM_Image/AGMIMG_k xddf + Adobe_AGM_Image/AGMIMG_y xddf + Adobe_AGM_Image/AGMIMG_m xddf + Adobe_AGM_Image/AGMIMG_c xddf + AGMIMG_y 0.0 eq AGMIMG_m 0.0 eq and AGMIMG_c 0.0 eq and{ + {AGMIMG_k mul 1 exch sub}currenttransfer addprocs settransfer + currentdict imageormask + }{ + currentcolortransfer + {AGMIMG_k mul 1 exch sub}exch addprocs 4 1 roll + {AGMIMG_y mul 1 exch sub}exch addprocs 4 1 roll + {AGMIMG_m mul 1 exch sub}exch addprocs 4 1 roll + {AGMIMG_c mul 1 exch sub}exch addprocs 4 1 roll + setcolortransfer + currentdict tint_image_to_color + }ifelse + }{ + MappedCSA 0 get/DeviceGray eq{ + {255 mul round cvi ColorLookup exch get 0 get}currenttransfer addprocs settransfer + currentdict imageormask + }{ + MappedCSA 0 get/DeviceCMYK eq{ + currentcolortransfer + {255 mul round cvi ColorLookup exch get 3 get 1 exch sub}exch addprocs 4 1 roll + {255 mul round cvi ColorLookup exch get 2 get 1 exch sub}exch addprocs 4 1 roll + {255 mul round cvi ColorLookup exch get 1 get 1 exch sub}exch addprocs 4 1 roll + {255 mul round cvi ColorLookup exch get 0 get 1 exch sub}exch addprocs 4 1 roll + setcolortransfer + currentdict tint_image_to_color + }{ + currentcolortransfer + {pop 1}exch addprocs 4 1 roll + {255 mul round cvi ColorLookup exch get 2 get}exch addprocs 4 1 roll + {255 mul round cvi ColorLookup exch get 1 get}exch addprocs 4 1 roll + {255 mul round cvi ColorLookup exch get 0 get}exch addprocs 4 1 roll + setcolortransfer + currentdict tint_image_to_color + }ifelse + }ifelse + }ifelse + }ifelse + end + }def + /sep_image_lev1_sep + { + begin + /sep_colorspace_dict AGMCORE_gget/Components known{ + Components aload pop + Adobe_AGM_Image/AGMIMG_k xddf + Adobe_AGM_Image/AGMIMG_y xddf + Adobe_AGM_Image/AGMIMG_m xddf + Adobe_AGM_Image/AGMIMG_c xddf + {AGMIMG_c mul 1 exch sub} + {AGMIMG_m mul 1 exch sub} + {AGMIMG_y mul 1 exch sub} + {AGMIMG_k mul 1 exch sub} + }{ + {255 mul round cvi ColorLookup exch get 0 get 1 exch sub} + {255 mul round cvi ColorLookup exch get 1 get 1 exch sub} + {255 mul round cvi ColorLookup exch get 2 get 1 exch sub} + {255 mul round cvi ColorLookup exch get 3 get 1 exch sub} + }ifelse + AGMCORE_get_ink_data currenttransfer addprocs settransfer + currentdict imageormask_sys + end + }def + /indexed_imageormask_lev1 + { + /indexed_colorspace_dict AGMCORE_gget begin + begin + currentdict + MappedCSA 0 get dup/DeviceRGB eq exch/DeviceCMYK eq or has_color not and{ + {HiVal mul round cvi GrayLookup exch get HiVal div}currenttransfer addprocs settransfer + imageormask + }{ + MappedCSA 0 get/DeviceGray eq{ + {HiVal mul round cvi Lookup exch get HiVal div}currenttransfer addprocs settransfer + imageormask + }{ + MappedCSA 0 get/DeviceCMYK eq{ + currentcolortransfer + {4 mul HiVal mul round cvi 3 add Lookup exch get HiVal div 1 exch sub}exch addprocs 4 1 roll + {4 mul HiVal mul round cvi 2 add Lookup exch get HiVal div 1 exch sub}exch addprocs 4 1 roll + {4 mul HiVal mul round cvi 1 add Lookup exch get HiVal div 1 exch sub}exch addprocs 4 1 roll + {4 mul HiVal mul round cvi Lookup exch get HiVal div 1 exch sub}exch addprocs 4 1 roll + setcolortransfer + tint_image_to_color + }{ + currentcolortransfer + {pop 1}exch addprocs 4 1 roll + {3 mul HiVal mul round cvi 2 add Lookup exch get HiVal div}exch addprocs 4 1 roll + {3 mul HiVal mul round cvi 1 add Lookup exch get HiVal div}exch addprocs 4 1 roll + {3 mul HiVal mul round cvi Lookup exch get HiVal div}exch addprocs 4 1 roll + setcolortransfer + tint_image_to_color + }ifelse + }ifelse + }ifelse + end end + }def + /indexed_image_lev1_sep + { + /indexed_colorspace_dict AGMCORE_gget begin + begin + {4 mul HiVal mul round cvi Lookup exch get HiVal div 1 exch sub} + {4 mul HiVal mul round cvi 1 add Lookup exch get HiVal div 1 exch sub} + {4 mul HiVal mul round cvi 2 add Lookup exch get HiVal div 1 exch sub} + {4 mul HiVal mul round cvi 3 add Lookup exch get HiVal div 1 exch sub} + AGMCORE_get_ink_data currenttransfer addprocs settransfer + currentdict imageormask_sys + end end + }def +}if +end +systemdict/setpacking known +{setpacking}if +%%EndResource +currentdict Adobe_AGM_Utils eq {end} if +%%EndProlog +%%BeginSetup +Adobe_AGM_Utils begin +2 2010 Adobe_AGM_Core/ds gx +Adobe_CoolType_Core/ds get exec Adobe_AGM_Image/ds gx +currentdict Adobe_AGM_Utils eq {end} if +%%EndSetup +%%Page: 18 1 +%%EndPageComments +%%BeginPageSetup +%ADOBeginClientInjection: PageSetup Start "AI11EPS" +%AI12_RMC_Transparency: Balance=75 RasterRes=300 GradRes=150 Text=0 Stroke=1 Clip=1 OP=0 +%ADOEndClientInjection: PageSetup Start "AI11EPS" +Adobe_AGM_Utils begin +Adobe_AGM_Core/ps gx +Adobe_AGM_Utils/capture_cpd gx +Adobe_CoolType_Core/ps get exec Adobe_AGM_Image/ps gx +%ADOBeginClientInjection: PageSetup End "AI11EPS" +/currentdistillerparams where {pop currentdistillerparams /CoreDistVersion get 5000 lt} {true} ifelse { userdict /AI11_PDFMark5 /cleartomark load put userdict /AI11_ReadMetadata_PDFMark5 {flushfile cleartomark } bind put} { userdict /AI11_PDFMark5 /pdfmark load put userdict /AI11_ReadMetadata_PDFMark5 {/PUT pdfmark} bind put } ifelse [/NamespacePush AI11_PDFMark5 [/_objdef {ai_metadata_stream_123} /type /stream /OBJ AI11_PDFMark5 [{ai_metadata_stream_123} currentfile 0 (% &&end XMP packet marker&&) /SubFileDecode filter AI11_ReadMetadata_PDFMark5 + + + + application/postscript + + + diagramas_01 + + + + + Adobe Illustrator CS4 + 2011-07-07T15:53:09-03:00 + 2011-07-07T15:53:09-03:00 + 2011-07-07T15:53:09-03:00 + + + + 256 + 156 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAnAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9Jy6VpkUKOLFpy1AVjIB G1eR5ugp9OAsoi+rVjYaPeQmUWTQ0d04SmjVQ8WPws37W2FiluqeXNN1S5NrFZW4NoVLSXaO6uJR yBiMcqNtxPLkN/oxVU0bQ7WzEem3lpAXpJJFLaq0UAjD0CFZJpJC45Dk3Qk9umKo+fTtIhngiNmW E7MvqqRxQqpf46uG3ANKA4qiBo+mxMkkcAV0ZSrVOxqPfFVC503To7c3H1JrmQ8SyRkczzYAt8bo tBXkd+mAllCNmrpbZ2Gk3Pqg2LQNE/psspFSeIbbg79m74WKXa15b0rULhLKKxgaWFRMZ7hXeIBm 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 + + + + + + proof:pdf + uuid:65E6390686CF11DBA6E2D887CEACB407 + xmp.did:01801174072068118DBB9C4385CA24A4 + xmp.iid:01801174072068118DBB9C4385CA24A4 + + + + converted + from application/pdf to <unknown> + + + saved + xmp.iid:D47F11740720681191099C3B601C4548 + 2008-04-17T14:19:21+05:30 + Adobe Illustrator CS4 + + + / + + + + + converted + from application/pdf to <unknown> + + + converted + from application/pdf to <unknown> + + + saved + xmp.iid:FD7F11740720681197C1BF14D1759E83 + 2008-05-16T17:01:20-07:00 + Adobe Illustrator CS4 + + + / + + + + + saved + xmp.iid:F77F117407206811BC18AC99CBA78E83 + 2008-05-19T18:10:15-07:00 + Adobe Illustrator CS4 + + + / + + + + + converted + from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator + + + saved + xmp.iid:FB7F117407206811B628E3BF27C8C41B + 2008-05-22T14:26:44-07:00 + Adobe Illustrator CS4 + + + / + + + + + converted + from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator + + + saved + xmp.iid:08C3BD25102DDD1181B594070CEB88D9 + 2008-05-28T16:51:46-07:00 + Adobe Illustrator CS4 + + + / + + + + + converted + from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator + + + saved + xmp.iid:F77F11740720681192B0DFFC927805D7 + 2008-05-30T21:26:38-07:00 + Adobe Illustrator CS4 + + + / + + + + + converted + from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator + + + saved + xmp.iid:F87F11740720681192B0DFFC927805D7 + 2008-05-30T21:27-07:00 + Adobe Illustrator CS4 + + + / + + + + + converted + from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator + + + saved + xmp.iid:F97F1174072068119098B097FDA39BEF + 2008-06-02T13:26:10-07:00 + Adobe Illustrator CS4 + + + / + + + + + saved + xmp.iid:F77F1174072068118DBB9A084B3843B2 + 2011-06-09T11:06:05-03:00 + Adobe Illustrator CS4 + / + + + saved + xmp.iid:F87F1174072068118DBB9A084B3843B2 + 2011-06-09T15:15:58-03:00 + Adobe Illustrator CS4 + / + + + saved + xmp.iid:7FF2245A3B2068118DBB9A084B3843B2 + 2011-06-09T17:21:50-03:00 + Adobe Illustrator CS4 + / + + + saved + xmp.iid:01801174072068118DBB9C4385CA24A4 + 2011-07-07T15:53:09-03:00 + Adobe Illustrator CS4 + / + + + + + uuid:190090dd-b95e-a142-9c53-7c955168a3d0 + xmp.did:7FF2245A3B2068118DBB9A084B3843B2 + uuid:65E6390686CF11DBA6E2D887CEACB407 + proof:pdf + + + + Web + + + 1 + False + False + + 549.002930 + 356.940430 + Pixels + + + + + Arial-BoldMT + Arial + Bold + Open Type + Version 5.01.2x + False + Arial Bold.ttf + + + ArialMT + Arial + Regular + Open Type + Version 5.01.2x + False + Arial.ttf + + + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + White + RGB + PROCESS + 255 + 255 + 255 + + + Black + RGB + PROCESS + 0 + 0 + 0 + + + RGB Red + RGB + PROCESS + 255 + 0 + 0 + + + RGB Yellow + RGB + PROCESS + 255 + 255 + 0 + + + RGB Green + RGB + PROCESS + 0 + 255 + 0 + + + RGB Cyan + RGB + PROCESS + 0 + 255 + 255 + + + RGB Blue + RGB + PROCESS + 0 + 0 + 255 + + + RGB Magenta + RGB + PROCESS + 255 + 0 + 255 + + + R=193 G=39 B=45 + RGB + PROCESS + 193 + 39 + 45 + + + R=237 G=28 B=36 + RGB + PROCESS + 237 + 28 + 36 + + + R=241 G=90 B=36 + RGB + PROCESS + 241 + 90 + 36 + + + R=247 G=147 B=30 + RGB + PROCESS + 247 + 147 + 30 + + + R=251 G=176 B=59 + RGB + PROCESS + 251 + 176 + 59 + + + R=252 G=238 B=33 + RGB + PROCESS + 252 + 238 + 33 + + + R=217 G=224 B=33 + RGB + PROCESS + 217 + 224 + 33 + + + R=140 G=198 B=63 + RGB + PROCESS + 140 + 198 + 63 + + + R=57 G=181 B=74 + RGB + PROCESS + 57 + 181 + 74 + + + R=0 G=146 B=69 + RGB + PROCESS + 0 + 146 + 69 + + + R=0 G=104 B=55 + RGB + PROCESS + 0 + 104 + 55 + + + R=34 G=181 B=115 + RGB + PROCESS + 34 + 181 + 115 + + + R=0 G=169 B=157 + RGB + PROCESS + 0 + 169 + 157 + + + R=41 G=171 B=226 + RGB + PROCESS + 41 + 171 + 226 + + + R=0 G=113 B=188 + RGB + PROCESS + 0 + 113 + 188 + + + R=46 G=49 B=146 + RGB + PROCESS + 46 + 49 + 146 + + + R=27 G=20 B=100 + RGB + PROCESS + 27 + 20 + 100 + + + R=102 G=45 B=145 + RGB + PROCESS + 102 + 45 + 145 + + + R=147 G=39 B=143 + RGB + PROCESS + 147 + 39 + 143 + + + R=158 G=0 B=93 + RGB + PROCESS + 158 + 0 + 93 + + + R=212 G=20 B=90 + RGB + PROCESS + 212 + 20 + 90 + + + R=237 G=30 B=121 + RGB + PROCESS + 237 + 30 + 121 + + + R=199 G=178 B=153 + RGB + PROCESS + 199 + 178 + 153 + + + R=153 G=134 B=117 + RGB + PROCESS + 153 + 134 + 117 + + + R=115 G=99 B=87 + RGB + PROCESS + 115 + 99 + 87 + + + R=83 G=71 B=65 + RGB + PROCESS + 83 + 71 + 65 + + + R=198 G=156 B=109 + RGB + PROCESS + 198 + 156 + 109 + + + R=166 G=124 B=82 + RGB + PROCESS + 166 + 124 + 82 + + + R=140 G=98 B=57 + RGB + PROCESS + 140 + 98 + 57 + + + R=117 G=76 B=36 + RGB + PROCESS + 117 + 76 + 36 + + + R=96 G=56 B=19 + RGB + PROCESS + 96 + 56 + 19 + + + R=66 G=33 B=11 + RGB + PROCESS + 66 + 33 + 11 + + + + + + Grays + 1 + + + + R=0 G=0 B=0 + RGB + PROCESS + 0 + 0 + 0 + + + R=26 G=26 B=26 + RGB + PROCESS + 26 + 26 + 26 + + + R=51 G=51 B=51 + RGB + PROCESS + 51 + 51 + 51 + + + R=77 G=77 B=77 + RGB + PROCESS + 77 + 77 + 77 + + + R=102 G=102 B=102 + RGB + PROCESS + 102 + 102 + 102 + + + R=128 G=128 B=128 + RGB + PROCESS + 128 + 128 + 128 + + + R=153 G=153 B=153 + RGB + PROCESS + 153 + 153 + 153 + + + R=179 G=179 B=179 + RGB + PROCESS + 179 + 179 + 179 + + + R=204 G=204 B=204 + RGB + PROCESS + 204 + 204 + 204 + + + R=230 G=230 B=230 + RGB + PROCESS + 230 + 230 + 230 + + + R=242 G=242 B=242 + RGB + PROCESS + 242 + 242 + 242 + + + + + + Web Color Group + 1 + + + + R=63 G=169 B=245 + RGB + PROCESS + 63 + 169 + 245 + + + R=122 G=201 B=67 + RGB + PROCESS + 122 + 201 + 67 + + + R=255 G=147 B=30 + RGB + PROCESS + 255 + 147 + 30 + + + R=255 G=29 B=37 + RGB + PROCESS + 255 + 29 + 37 + + + R=255 G=123 B=172 + RGB + PROCESS + 255 + 123 + 172 + + + R=189 G=204 B=212 + RGB + PROCESS + 189 + 204 + 212 + + + + + + + + + Adobe PDF library 9.00 + + + + + + + + + + + + + + + + + + + + + + + + + % &&end XMP packet marker&& [{ai_metadata_stream_123} <> /PUT AI11_PDFMark5 [/Document 1 dict begin /Metadata {ai_metadata_stream_123} def currentdict end /BDC AI11_PDFMark5 +%ADOEndClientInjection: PageSetup End "AI11EPS" +%%EndPageSetup +1 -1 scale 0 -651.988 translate +pgsv +[1 0 0 1 0 0 ]ct +gsave +np +gsave +0 0 mo +0 651.988 li +621.732 651.988 li +621.732 0 li +cp +clp +[1 0 0 1 0 0 ]ct +608.04 639.988 mo +10.7832 639.988 li +10.7832 41.3672 li +608.04 41.3672 li +608.04 639.988 li +cp +false sop +/0 +[/DeviceCMYK] /CSA add_res +3.0518e-05 3.0518e-05 3.0518e-05 3.0518e-05 cmyk +f +1 lw +0 lc +0 lj +4 ml +[] 0 dsh +true sadj +608.04 639.988 mo +10.7832 639.988 li +10.7832 41.3672 li +608.04 41.3672 li +608.04 639.988 li +cp +.193668 .150057 .155337 3.0518e-05 cmyk +@ +608.036 41.7031 mo +10.7832 41.7031 li +10.7832 12.5586 li +608.036 12.5586 li +608.036 41.7031 li +cp +f +608.036 41.7031 mo +10.7832 41.7031 li +10.7832 12.5586 li +608.036 12.5586 li +608.036 41.7031 li +cp +@ +.69482 .6318 .621515 .583612 cmyk +%ADOBeginSubsetFont: ArialMT Initial +%ADOt1write: (1.0.24) %%Copyright: Copyright 2011 Adobe System Incorporated. All rights reserved. 12 dict dup begin /FontType 1 def /FontName /ArialMT def /FontInfo 5 dict dup begin /ItalicAngle 0 def /FSType 8 def end def /PaintType 0 def /FontMatrix [0.001 0 0 0.001 0 0] def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 65 /A put dup 67 /C put dup 69 /E put dup 77 /M put dup 79 /O put dup 80 /P put dup 82 /R put dup 83 /S put dup 95 /underscore put def /FontBBox {-665 -325 2000 1006} def end systemdict begin dup /Private 7 dict dup begin /|- {def} def /| {put} def /BlueValues [0 0] def /password 5839 def /MinFeature {16 16} def /OtherSubrs[{}{}{}{systemdict/internaldict known not{pop 3}{1183615869 systemdict/internaldict get exec dup/startlock known{/startlock get exec}{dup /strtlck known{/strtlck get exec}{pop 3}ifelse}ifelse}ifelse}executeonly]def /Subrs 5 array dup 0 <1C60D8A8CC31FE2BF6E07AA3E541E2> | dup 1 <1C60D8A8C9C3D06D9E> | dup 2 <1C60D8A8C9C202D79A> | dup 3 <1C60D8A849> | dup 4 <1C60D8A8CC3674F41144B13B77> | def put dup /CharStrings 10 dict dup begin /.notdef <1C60D8A8C9B6E3FA5101D97F0BCF44F7161DEB1E2A84766DD477E7 C8A936AA182F5809A9> |- /A <1C60D8A8C9B64EDFED26B9E21A4F64848088903AC9891CF791BDBC4AB29A CC8B3E8D13924A7DDE35F09AC5F4A8229C87124C732743268600EF8D4582208B D16D82> |- /C <1C60D8A8C9B6079F6D1C46AC2732DFBDC9143C94793529C1940296210AAD 6EE09C39CFC4DAB7C5F3BA33C9E10838E0BC6FC9318A4E57F309EE20438B434C 69AE73A499211EBA75E22A57C1581D93869428818DC700A28C027571D7047CDF A8B017AACDE96DE4B2579EFD2C826A30F6EBDDC52701A22CDD669ADC60B66F32 261A1F55EDEF9802FD4511E0EF130772EDFD708A4113A1EDB1E717E0FA7D3148 51DE59> |- /E <1C60D8A8C9B64EDFFB83C6241DB110BEE5AB2FAD9D94B39ED5E81E7411B6 6E9361DDE78FC667AB91EF9824> |- /M <1C60D8A8C9B6B41CBB4B6664BFFC865F56E6FEAFA79E7B90883C1C68AFB3 79AC174B0F8DCC9294E2C26BD06BBA9FD3867F8768651EF4BA798B4F538FCE8F 80AF5A83421F8F> |- /O <1C60D8A8C9B6FF86E621E1FAD9CC02A23AF5AAF7451327A9277DAE8170AA C8E603A02E3EEFF561DDADE9FD6F6F16B77EE709DD797791A73F1C532C58482F 9C51E1EAE7EA6E4D820E6AA1026E7BE345B1C97C5D9EBBEF4840C4188F96B538 0E7625249BBAD172254404F6F1CB17CABA1F131B17AAAB56C5D3B94E3AC2C2E9 F0A0D079C435D0249DF6C47E18FCF00E7FFE3C519BB35DF797EF47286BDCA762 289BE1> |- /P <1C60D8A8C9B64EDFF4950CC53012D47AE97D5586315BA2F5162B63CEC117 C5379A1B3DB174CB2C739C68916A1E99A346AFF71DBF25658867D9AEF1BF3C47 CE1BA73978E8D0D40E52B85A56E08A1369D85E15B0A0C517291916FF6E61D0EF BF59B4862165C7DEA15B42BE3811C2CAA25C54> |- /R <1C60D8A8C9B6079F62E89B521DCDBE3DC5497B8DD99916239C0DFA5ED4F6 32B33575F4260343AF5DB7D477D12055F49C5E99C0AC176EAD42723223937F2B A15ECAD7751CB6A136B700EE485E38E7CDB87D9465C90BB8E29B04FDDA42609F BC3833B9FB5105619F4CC434003085F449D9FD5022725306B331FB97B31D2952 57B180DE1FD5465D256CCA19301DA97326882845130A5257BF61307ABA64C3F0 B222> |- /S <1C60D8A8C9B64EDFE3D078722A65C31955939D63AA5C8A4945719B5E558E 3B73A676CC12D1E18D93A8DC67C074D6E352D426981DE76F8EC4CFE5DAE051BE 47753A7C234C4B8D7D9F50292A61882B5500CC701F878FE626CDC6D4C322BB39 1537921D673F5AEE3EC19E36E7EFEC0F06A0EA4EAAB6BBA94DDCD11A6A564B13 B510F8C915848233B82F046D854DCD4F1639F149305DC73D3C68DF8AEB47A96A 30E55CF8BAD07FA2825BCE0D675F1CC2EBE61B07B772130E23119250F1EBF8FE 12A2098D9F09F3F21BDC41666CA4A0BB70D5F0A750B44BB93A5FBFDD2BF8DE45 0B277265536F77D5BD6F44FB72FF2E708C60107653AE44BFFB26AFF8> |- /underscore <1C60D8A8C9B7EF3224BB0E94C1F3EA8D5F87D58A9CCE> |- end put end dup /FontName get exch definefont pop end %ADOEndSubsetFont +/RQJJJK+ArialMT /ArialMT findfont ct_VMDictPut /RQJJJK+ArialMT*1 [65{/.notdef}rp /A /.notdef /C /.notdef /E 7{/.notdef}rp /M /.notdef /O /P /.notdef /R /S 11{/.notdef}rp /underscore 160{/.notdef}rp] RQJJJK+ArialMT nf RQJJJK+ArialMT*1 [16 0 0 -16 0 0 ]msf 237.976 34.6689 mo (ECORE_POS_MAP)sh .597284 .512352 .507713 .201328 cmyk +%ADOBeginSubsetFont: ArialMT AddGlyphs +%ADOt1write: (1.0.24) %%Copyright: Copyright 2011 Adobe System Incorporated. All rights reserved. systemdict begin RQJJJK+ArialMT dup /Private get dup rcheck {begin true}{pop false}ifelse exch /CharStrings get begin systemdict /gcheck known {currentglobal currentdict gcheck setglobal} if /e <1C60D8A8C9B7EF322472FA01213C7AD90A23B536C2309DD40D370E2449B0 D0FEF85A6BE8067F30686F143E75903EB6FA56935472EF47CE3F33433C2F0C8B 6FA51573AE54B2C516F6F024F8775AD6639544E339FC2A328548BCBFD58B0EEA 03B7DC3AB069F44477958BFBFAAC7196D411DF9BE0B78A86C4BC33EC5D7C3729 5284C077711C162623860AACA404F650F8D516970257> |- /i <1C60D8A8C9B88C087228DFC7C7ABCC71B868F57EDB285655227000619B17 1C8A80AB> |- /m <1C60D8A8C9B6B41CBB5F87BE20C872DF59FABCB36542419CBFA3D5519AD5 BA8076F32ECFD724B055F72CAC37BC47239ACC8B0FB48B8ACFF099B97085BD99 C333951D0338D27FF6AB9B3F3C69320476BA0CD4F9573B79AD358A91B0176AFB 9AEF169308783E9C6287F18E6E658AF5AA6C9688B500806DA169A1B21069D55C 54A2FF607A6A38976171B08665C3ACCAA84DFB970D01180645CE5CBC48DFE37B> |- /t <1C60D8A8C9B854D0F45CF665C7276F8075B54A4ECD6470F395A458CA2D06 5152075036EEECA213894C1EA0DACFBD370590F4B831924E5BDA5281442349CF AD2545E0750C3004A129C25B1EAA8DEF5DA8BF1998E80AE266F591E64CB5127F 5C42C88FB43C> |- systemdict /gcheck known {setglobal} if end {end} if end RQJJJK+ArialMT /Encoding get dup 101 /e put dup 105 /i put dup 109 /m put dup 116 /t put pop %ADOEndSubsetFont +/RQJJJK+ArialMT*1 [65{/.notdef}rp /A /.notdef /C /.notdef /E 7{/.notdef}rp /M /.notdef /O /P /.notdef /R /S 11{/.notdef}rp /underscore 5{/.notdef}rp /e 3{/.notdef}rp /i 3{/.notdef}rp /m 6{/.notdef}rp /t 139{/.notdef}rp] RQJJJK+ArialMT nf RQJJJK+ArialMT*1 [16 0 0 -16 0 0 ]msf 232.568 326.033 mo (time)sh %ADOBeginSubsetFont: ArialMT AddGlyphs +%ADOt1write: (1.0.24) %%Copyright: Copyright 2011 Adobe System Incorporated. All rights reserved. systemdict begin RQJJJK+ArialMT dup /Private get dup rcheck {begin true}{pop false}ifelse exch /CharStrings get begin systemdict /gcheck known {currentglobal currentdict gcheck setglobal} if /a <1C60D8A8C9B7EF32244AC11AA6BAAA29EE8C78E0E7206F4A2776A2D1EA7D C8D9A28C62ADE3B609CF5E2EE23C64D0B75055BD249ADFEC7B4224D040D883CA 6747571955349CF8AD17E94E6FE5D0259F4D55623D4DC5C3CB4AC64A7A87DBBA 48B7420D7990F3C261DB9838C5B90BF72B82C8238A1A58FE8E6137AAFE2405FD 710F7ADB95B4F576668A6DB104942C88ED8D01E4E58188F5E32A24B5B964D5CE C10C08F76C0F472E84A0FB6EB5E37AAEE233DE54C212B0A012D3E20F864B2D53 463E221F81B784B6F7BE81FBFCAE6785C2430454DD81C436E0A516BF8C8307B2 879FF86378629C5EA7E586D83C83550D2E732930F7FE3BAD07B86C81E024D177 B5D88A> |- /f <1C60D8A8C9B854D0F47057B2F13303E258FCAEE9E8BBA6E28AE872907C56 63BFD2A0F535ED0EB011F2C2A875E053FAF73E8AA16B1F99510A6812F90D61CF 3F1DA5EF558899A9AE12AAF6AF4568E0F6003B0A2FF6F33293> |- /r <1C60D8A8C9B81F2C3A9694980E415F1DEF5C498473095A24D1BE11285789 4FEA85DB28AD762FB8D2F4CAC5BF8B9C18D8A2DFCF155E0751AF58898A6619AD D420F549AB7C795751D32E8EE6> |- systemdict /gcheck known {setglobal} if end {end} if end RQJJJK+ArialMT /Encoding get dup 97 /a put dup 102 /f put dup 114 /r put pop %ADOEndSubsetFont +/RQJJJK+ArialMT*1 [65{/.notdef}rp /A /.notdef /C /.notdef /E 7{/.notdef}rp /M /.notdef /O /P /.notdef /R /S 11{/.notdef}rp /underscore /.notdef /a 3{/.notdef}rp /e /f 2{/.notdef}rp /i 3{/.notdef}rp /m 4{/.notdef}rp /r /.notdef /t 139{/.notdef}rp] RQJJJK+ArialMT nf RQJJJK+ArialMT*1 [0 -16 -16 0 0 0 ]msf 47.4312 142.669 mo (frame) [-4.44531 -5.32813 -8.89844 -13.3281 0 ]ysh .69482 .6318 .621515 .583612 cmyk +%ADOBeginSubsetFont: ArialMT AddGlyphs +%ADOt1write: (1.0.24) %%Copyright: Copyright 2011 Adobe System Incorporated. All rights reserved. systemdict begin RQJJJK+ArialMT dup /Private get dup rcheck {begin true}{pop false}ifelse exch /CharStrings get begin systemdict /gcheck known {currentglobal currentdict gcheck setglobal} if /l <1C60D8A8C9B88C08722AD20D19A90F9064193C8D82> |- /n <1C60D8A8C9B7EF322B3BE19FB964E04D2DB06D4930CA5D8F41D2EF3A285C 0BD536CD2C57668EB9E30311BF9A2872DFB44F2BF2A4683B5D66FA01BB1CCDAD E9C8A9EE2CB010715D3D6DFF0E843CF77C87A07D1DBD0482675E3CA1DAA2A520 3A8015DD09B7CE> |- systemdict /gcheck known {setglobal} if end {end} if end RQJJJK+ArialMT /Encoding get dup 108 /l put dup 110 /n put pop %ADOEndSubsetFont +/RQJJJK+ArialMT*1 [65{/.notdef}rp /A /.notdef /C /.notdef /E 7{/.notdef}rp /M /.notdef /O /P /.notdef /R /S 11{/.notdef}rp /underscore /.notdef /a 3{/.notdef}rp /e /f 2{/.notdef}rp /i 2{/.notdef}rp /l /m /n 3{/.notdef}rp /r /.notdef /t 139{/.notdef}rp] RQJJJK+ArialMT nf RQJJJK+ArialMT*1 [20.625 0 0 -20.625 0 0 ]msf 135.66 73.1016 mo (linear)sh 55.3784 99.7695 mo +52.4956 93.0059 li +49.6128 99.7695 li +55.3784 99.7695 li +cp +.75021 .679683 .670222 .90164 cmyk +f +.5 lw +52.4937 310.07 mo +52.4937 99.2422 li +@ +262.795 307.188 mo +269.559 310.072 li +262.795 312.955 li +262.795 307.188 li +cp +f +52.4937 310.074 mo +263.322 310.074 li +@ +269.559 93.0059 mo +52.4956 310.068 li +@ +.597284 .512352 .507713 .201328 cmyk +RQJJJK+ArialMT*1 [16 0 0 -16 0 0 ]msf 232.568 627.504 mo (time)sh RQJJJK+ArialMT*1 [0 -16 -16 0 0 0 ]msf 47.4312 444.14 mo (frame) [-4.44531 -5.32813 -8.89844 -13.3281 0 ]ysh .69482 .6318 .621515 .583612 cmyk +%ADOBeginSubsetFont: ArialMT AddGlyphs +%ADOt1write: (1.0.24) %%Copyright: Copyright 2011 Adobe System Incorporated. All rights reserved. systemdict begin RQJJJK+ArialMT dup /Private get dup rcheck {begin true}{pop false}ifelse exch /CharStrings get begin systemdict /gcheck known {currentglobal currentdict gcheck setglobal} if /c <1C60D8A8C9B7A73DB9D8FD6AA4FBAF8D65C36EA1D4AADBD389F972C0EDCE 9E7F36285FA93A80D3647871D2CE5AAAA6A6A370DC54E1595FB6AAB3E389C9F7 BBBB85F787D6C418B35B940450E5E243895ECFD2205F51B2D154CFFECF34148C 344C1EF806F9AAF539FB961E3EFAF6353381E833DF7C0542FFF27122A28D3654 8FE63FC8465B1B685766E782F0> |- systemdict /gcheck known {setglobal} if end {end} if end RQJJJK+ArialMT /Encoding get dup 99 /c put pop %ADOEndSubsetFont +/RQJJJK+ArialMT*1 [65{/.notdef}rp /A /.notdef /C /.notdef /E 7{/.notdef}rp /M /.notdef /O /P /.notdef /R /S 11{/.notdef}rp /underscore /.notdef /a /.notdef /c /.notdef /e /f 2{/.notdef}rp /i 2{/.notdef}rp /l /m /n 3{/.notdef}rp /r /.notdef /t 139{/.notdef}rp] RQJJJK+ArialMT nf RQJJJK+ArialMT*1 [20.625 0 0 -20.625 0 0 ]msf 113.303 374.572 mo (accelerate)sh 55.3784 401.24 mo +52.4956 394.477 li +49.6128 401.24 li +55.3784 401.24 li +cp +.75021 .679683 .670222 .90164 cmyk +f +52.4937 611.541 mo +52.4937 400.713 li +@ +262.795 608.658 mo +269.559 611.543 li +262.795 614.426 li +262.795 608.658 li +cp +f +52.4937 611.545 mo +263.322 611.545 li +@ +269.559 394.477 mo +218.307 611.539 52.4956 611.539 52.4956 611.539 cv +@ +561.039 93.0063 mo +561.039 93.0063 475.529 100.881 452.263 200.488 cv +428.997 300.096 343.487 310.069 343.487 310.069 cv +@ +.597284 .512352 .507713 .201328 cmyk +RQJJJK+ArialMT*1 [16 0 0 -16 0 0 ]msf 523.562 326.033 mo (time)sh RQJJJK+ArialMT*1 [0 -16 -16 0 0 0 ]msf 338.425 142.669 mo (frame) [-4.44531 -5.32813 -8.89844 -13.3281 0 ]ysh .69482 .6318 .621515 .583612 cmyk +%ADOBeginSubsetFont: ArialMT AddGlyphs +%ADOt1write: (1.0.24) %%Copyright: Copyright 2011 Adobe System Incorporated. All rights reserved. systemdict begin RQJJJK+ArialMT dup /Private get dup rcheck {begin true}{pop false}ifelse exch /CharStrings get begin systemdict /gcheck known {currentglobal currentdict gcheck setglobal} if /d <1C60D8A8C9B7EF322407C6655A1B3652DB8522EB511BE6B0855A72D96214 58876CAD1FA22A00635F436A34E23EAFC09C394044ECC1389CD99E4AF1C1F6DD 52305C78619784840FC37A805B0805EF290BC9E049CF068290816CB7E74DB612 941355BCE71CBDD11DD0F9CA29531036ED13EFB9CAB613E9F630FBBC9408EF13 CE4683D92968530F64760C3DF85C7C7EA06EBA8BF859> |- /o <1C60D8A8C9B7EF32334FFE7884F6C3B903D000D9FD76C2EAE8EDCCA90A98 7875625CA0393015EF6761BE1C3B6D9E9DA4BABE1DD313B783BCBF8F620C846C 7F6361946173FB7A4A6BF94EAA0CB4947DD1974AF371F3C211E584576DE9AD79 F9DA988E9E531810E3876F3029BB1D2ED366525F30E48DD7CE3C9B66C5CC099F 518C54BB58C51D6FB6D0C8> |- /s <1C60D8A8C9B7A73DA057E90C9BFBE0FE301E99CB771FA2F05368A6342B5F 80456D91458EA2F3CAD55CDF89BFF34EEB39D7DD325B057E2BF0E9B878C214E2 BD1BD70DCABE10E0DC8EBCF7B100B55EBE94FB0F17084E21EBD279B324AEABD9 6538911D053BE9D7ECBF43F934B1033C9E405BBE31E7EDB643609C8D779046E1 B250C3CF05E6FA4787649137D90F47F85972A6603BA900DD7CB710E02662DB32 87CB26D7B7AE794611498865FC85A28083D2F6C2DEC302D47619A4A577C5B843 5558FCFE71A1BB6783AFD5F58B6D2C03593B3F2297A66A7E6D13C1E321C57F41 72D53C8FCAF4D28F2B78D3A4BF03> |- /u <1C60D8A8C9B7EF32240889FE90FF09F794E92023A18223CCBE3629AB7F51 7D090BF7D55C0A5A8EADD9BE381137FE8504E8B2DB3D16839889E327241ACA8F 992A2BB9AD2BCE57ADB306CE2789439E67A64C32BE8669C197F5851EE3879399 0906DA8D7F8ACFF6D70790F06B02> |- systemdict /gcheck known {setglobal} if end {end} if end RQJJJK+ArialMT /Encoding get dup 100 /d put dup 111 /o put dup 115 /s put dup 117 /u put pop %ADOEndSubsetFont +/RQJJJK+ArialMT*1 [65{/.notdef}rp /A /.notdef /C /.notdef /E 7{/.notdef}rp /M /.notdef /O /P /.notdef /R /S 11{/.notdef}rp /underscore /.notdef /a /.notdef /c /d /e /f 2{/.notdef}rp /i 2{/.notdef}rp /l /m /n /o 2{/.notdef}rp /r /s /t /u 138{/.notdef}rp] RQJJJK+ArialMT nf RQJJJK+ArialMT*1 [20.625 0 0 -20.625 0 0 ]msf 406.014 73.1016 mo (sinusoidal)sh 346.372 99.7695 mo +343.489 93.0059 li +340.606 99.7695 li +346.372 99.7695 li +cp +.75021 .679683 .670222 .90164 cmyk +f +343.487 310.07 mo +343.487 99.2422 li +@ +553.789 307.188 mo +560.552 310.072 li +553.789 312.955 li +553.789 307.188 li +cp +f +343.487 310.074 mo +554.316 310.074 li +@ +343.488 611.539 mo +394.74 394.477 560.551 394.477 560.551 394.477 cv +@ +.597284 .512352 .507713 .201328 cmyk +RQJJJK+ArialMT*1 [16 0 0 -16 0 0 ]msf 523.562 627.504 mo (time)sh RQJJJK+ArialMT*1 [0 -16 -16 0 0 0 ]msf 338.425 444.14 mo (frame) [-4.44531 -5.32813 -8.89844 -13.3281 0 ]ysh .69482 .6318 .621515 .583612 cmyk +RQJJJK+ArialMT*1 [20.625 0 0 -20.625 0 0 ]msf 403.717 374.572 mo (decelerate)sh 346.372 401.24 mo +343.489 394.477 li +340.606 401.24 li +346.372 401.24 li +cp +.75021 .679683 .670222 .90164 cmyk +f +343.487 611.541 mo +343.487 400.713 li +@ +553.789 608.658 mo +560.552 611.543 li +553.789 614.426 li +553.789 608.658 li +cp +f +343.487 611.545 mo +554.316 611.545 li +@ +%ADOBeginClientInjection: EndPageContent "AI11EPS" +userdict /annotatepage 2 copy known {get exec}{pop pop} ifelse +%ADOEndClientInjection: EndPageContent "AI11EPS" +grestore +grestore +pgrs +%%PageTrailer +%ADOBeginClientInjection: PageTrailer Start "AI11EPS" +[/EMC AI11_PDFMark5 [/NamespacePop AI11_PDFMark5 +%ADOEndClientInjection: PageTrailer Start "AI11EPS" +[ +[/CSA [/0 ]] +] del_res +/RQJJJK+ArialMT*1 uf /RQJJJK+ArialMT uf /ArialMT uf Adobe_AGM_Image/pt gx +Adobe_CoolType_Core/pt get exec Adobe_AGM_Core/pt gx +currentdict Adobe_AGM_Utils eq {end} if +%%Trailer +Adobe_AGM_Image/dt get exec +Adobe_CoolType_Core/dt get exec Adobe_AGM_Core/dt get exec +%%EOF +%AI9_PrintingDataEnd userdict /AI9_read_buffer 256 string put userdict begin /ai9_skip_data { mark { currentfile AI9_read_buffer { readline } stopped { } { not { exit } if (%AI9_PrivateDataEnd) eq { exit } if } ifelse } loop cleartomark } def end userdict /ai9_skip_data get exec %AI9_PrivateDataBegin %!PS-Adobe-3.0 EPSF-3.0 %%Creator: Adobe Illustrator(R) 11.0 %%AI8_CreatorVersion: 14.0.0 %%For: (Marina Proni) () %%Title: (diagramas_01-18.eps) %%CreationDate: 7/7/11 3:53 PM %%Canvassize: 16383 %AI9_DataStream %Gb"-6CNCN %gn4Q9k'QmJc.Tke^3obA05(0K2p_K4Hfb+SrB"](Hh67ZjY))g^\GS=k9p..0:rnC>CQ2Cp$7qtDP)FNNSQ81\(<9>hHmsCF*I6D %CcWXMQG+ZNIfC2I!RgIM#63]^fus-9DgqkBh*1kX*W5acraP_iIfAL'h)f!GHn`@6/q<[Ms20'Ok@`iN<5od5mlIj;-i.810u=H< %$oO[UoT-c#rVjdjGAhBU]m+]"5CY#u]Qs2HmcMdoIes`6@b]erhS"A`oBqo7,33bc;p8nG4J-8"F9ElX!>G7!P/I*#CHO+g4Dug, %ZWP6=OOALl6H]MkGPY.mrqXP#?[`LFp[#lt]2rp#@/g,e`A?ZGm`i@^?MkmQAW;8?Y9b%5jkJ\,IsLqRp\-=[X=Af?,P^B$kI3+$ %RtBbujUJM>UaPe!\\[`PhL'hM%`InfbP0)mT:aB'r9@APn"/D6Gl-X*?u+[!qXs7Smp>r+dJ]ll$B0Y3$0NGi^t*`G`XElZ$%HjW %/AaXEHh9NI7PoohYtm(E^B%L4opZcT^UX;hLikhL`kkXEO)J>emm8eKZ^Lid5+Kses/,fPZ-_r`mr%TJp^k3Rr+3o)Np"1T#!RCD %It%4Y%L3,ingAbqUjJ3[lf!mlC)?pHrmeX8[t*f+m9-J+hnQ_to.=ok^=YSuEVfrhoC`54c2IAQQQYoR?G=(_ %38?WCs6fU?=79J.I"$G4CMbt7r8-;?i?gL:m/lA.%EQ\905pmXihj3DpMU?51IZacD[mSmr9CD2p"!Gt_<>6FRhr6P$YsfZk_G't %h"DJlIHB1sZF6s(PkWu*4Z@fHRgp8'XmP_Ln%ZVcF7C4U]Y2"'#5l2[qsO1&9C0XPgLhp[(Opc2o&]8NMq9n+O9;\9\:?O+DXO.s %kp:<5%F&n.pAEq'X4KRfV#9`M!p9FP>Fadk9S7c]r;P6YkI9>SljaiHIf&]um14i#?GCmfp?oouqqamDrpf^]ipQa`4D`a9hlkm! %s6^Y!]sthrTC6[S5(!;Bs.Km>!%qXYfCuamZ'3L@rT4%

;IT]XadZ6+UAb]6O]9fN[7L,^saJ-0+ms0\!RUYMQt*rU*tk(NTYB %s,5L]o=(nhc!Ka]0QnXVo%2j[(!=VrF!0`,p5]+r5mA)<;Z-j\UjmMH"/!@'o*Z6DA")rc?gO]ZhV@UV*o=YW7?l4o0tQUVKPn

jYTYqj%6k(`,c/thI(Jrqu,\qj6bic[H9%"Kec`T+/iW %i'IFfUi?i#8<4(e^rMMK?N"pUcP8/20O@%X`cIq7L&StS%+j+_L[2#,bNo-"m^g4j?Vf;H %\c=P7FhA49j5KiR3*[IV&,X94cjoYU3n-MWj?kuH6NG@"qUOQilK[qTJ$g5ug=:R.?.GurQ%AVu.KBM$Q\WbbbKJ*-jmKE[cBm!k %]e#NG10qoCE&m?ipP8^trc5d2n+LT_n#(TiQ[R_gI2kKd`ng=UYe/Upme49KY3kB-[&^gEbIb->])_fDVQm_HVX@iIY,G:O/aV-8 %3euO\W/K;"lt3,t@V;sXcs_;5al+pMc`ur*e:6NZnt6R:O;#\Cj@1;Q+A\(La;94nistVbrYpAZaKW=a>;m\m[`&1 %GPK,>CAeQFORVI4T)J@#NW=:X#`GkKk2\:agCR1K$'F*u3PUoA!ph[!=lC_?f+>?T4Eb/[X/."4[G5,8nk4[C0lJ#-s4u %8cj#BEtB$'l]fMc-`B-'.FJL^00d^Z5s&"q@ROX/;aXEbImh?'.TK'o0Oco*igH28)EOC'^!JTj36+S$,bW1mAoG`pr( %%(N)>"A1P8@R\fc8\O+>P*3L*7>n2>MUX4->l8M!OPXiMHVs[7riMuK;%%$b`!M3K:GRXI$I.r?WT>X.c)@.04emUHXMKp1K-O1h %e7Vn]F8i7R3q`tP_=\J6Z@0B)'KW?hX'i/UTF,ibKCB*=F:3EYLm#+McWAL'^!$5!YT-Qu.Xr %3_q?'ZW,4S.@m'ZU*WEI$5dN07LmFf*QBE.l3Rd.fU %h_6UD%:c1XVU/F#@a7JC,`pJa.+@_lUi7bbM!%J%*:5/h^AJ$%OMEEXFrGHZUgJsn.VGZSMi`A45lTf5gY7)Dl)Xl8Y,[O-.^:Km %Y7SB&A:#%Csb@3ln,)/QY_-?'.U1-#oe.[Xb-:@$8>M%#aWj./H(LCp4+=Y^kb#%P'VCZNmc;G%;h. %1*f=C44#9=B*"g/OrG%)5I:.R6^HpPs*"kp)Q`:WJ-)UO&u>h>(WE4bjS;J[)A_k21:^C^Sm]mQ/'!"HlKc;:AW-1g(24n8X,ENXfZ\W]aOPp*b@>CeD&_-YH4]R3`_:AhoHJ6&oQ=W?'(3,tQcJ/B.^$0S)V-+CKd)]]"1NLZSIA(AhlLqu[c;$-[u& %e4j=-nG5iX.+skr_Qa]./p&F!]!0kYLitW?aJj(<=RX>AhNNS?.8KTeJDO'GB1i)*2H\).7%E*KTWW6HB'IZ;3d""0`;q>#FY;#d %j6s6k7!:3:[M0fc":(@u"uIm8#RS;iBSMtJ*mH@aMa.H$.WuT-TO:2r#pEf@c,GS.%,$PT0a897CQb&8P+KA>NaP#ub9(h88J*NG %J8#$*0B>0T^eB&^,$e#:*u#SOrXVM_7i(s`ftIffm#5/mY9$)/T(tXo_#c&FW#7-l$DgE39&X.bLJnZq9SjHW.H:-IgSqT"o^W"[ %e6+ZPXMPi$EsfsB-Bq7S`&cS)g6%$.0&D.b]RbGmp@?;F,G0Nm]U9`GFRn)/'1Yi'4`iiShsB]d]/PPdf>ql=]D9m&5I+"-,Wk5i %dEIS,H^@O:V[Tp`PRiJ;^A,H=5oA\/A`RSH]Ae)K#LU'VB3E3Vng\\1s/[uXWbCm)i`D-"=&!9Gs2f72S9^IppSGAj#?_ZTI^Jmp %i].P=%sFDlD-"]FS7d2K4d15)H2(b-;\';r3QUbe@71ZT(41l[>3rJNTQ='7`*oVP %L6H:I,3XkW+gHlOIJ>]CJH';eic#nekZ5e[6S4@*0>@C-p;DI5r:r",0RWYXop.rgHOG49a>6IK,Y.pr+@-MJ(2LFi8o,_D9S7u; %LVX$04,I<<&j;QU0q%4"KTNfcmLAb;lS,HZ"#%Y2;\n-cl:@/>Y+en=37WSGP"StZG(YLLAls+6?A/ul9GS@5XTE6)MEZ"GlA?@] %]gT)JA1>eaHgH+/f_7YID[q84m(5d& %Rmk)=r4BI0fcic&dBULka,YhmNl8oFOg.>kCuFEoKu\RkbQZ,PBeE/XYqh<)Z.,&TJnF9mZ5?%I5a*\_Qj0^Z\YEbij(q7b+7$GN?joRW3kgH\cZWsdIl/;!^0OJX;ToLl%g7+,aLesF.)he%iC:)0R5Pp474bb%1&sIjn^V_%8/%[$C8>j8qi7UUGWhI3 %-.2*LSgQQld_M'"VMS%\h.NPJ+d7PV#-J8*^C4`Wc39^C1^aN8niXiQ\2:9BUc>#0PUPpnRq_eF_h$oR7L[=QO9$#=&`d(@R7HLV %[F'Ne-]UmIEEP'D*$MU7h-O12]riS!?-B?&%SC\BU'qa(R*>0Lh(IOL)TC06cc/'@D;j+h,\Ab@k1=5P>u]7K1[3L3l.eod:H=Yi1J:.kWO+bh&6u+ZJ'1p?]37&,_.e0YHQr6D5*Rm[&]%kmbWO\F-,d_0\`itgG78*0e!L>V85UUe=4$+Iqf[Y.Zr9/7CAOk?2=^l[Xs-Jph'%m %fa$?\DD(D9?;o&T'4Nrdjl8?q2JFi)e\E=^fqXN>f[I'"&+&X.KL]0#(:0cL*GPMIWA9)0G[-%pEb7/TPA$%8gp>kr?c>nJM>;*= %eH]#c$`No`WXGh!&?(A8.(20-BQ\@SeK,=ND>u,W!u)a_mYRYXPK6TB85!^9Lpa)!NAPh.7!n>iL[&rkG\!Z^oZ'9mlc@59nn<&[ %NoG(3L5CPkPF1YN`?@43M5Qk;\A?U\GeWEY]6(A28cTh+D4q4D7^u!B`Zd#?=[$rli7Xr""t^Xs<,dq8,+d`"U:%g3.@F"b/-ia# %"J&>s#5$$UdqPfYQ[4.:!=DlT#?/^BLcJ/&>'Hh-9rG!@<>A-KF"kjQZ=7g4]r=Gu#Us[?>UOmpQ7uHY"9#JAGOqueYF6cDWgZ-u %Ss8>0X=..dq>]Fahe0>L16n']D5_\1>SkFG(Mhf">h*?IO>O?JCQK\K7"&6,K1_WT(dDR20Vjmm&E-Z/a[V"hD %hHZ(EpXU]J",b9('An3lpH?(j[\.eu9,TfNO8d<"qX3*rIm8`Pe*NLiko?eu'_gZ5#r<^_d65X%T6Y?h(f/sH,+K>k6?Wp+\*?=[@78CgO@rQ.s?ZFR4o7>;?JYsfZ3kT#'?b-FCaSUPTkLEl\2 %m*kg%20G3A2bQ;=*s.NH^`]6:6"Gneh7\*H9`bA9'%!i_qnU05iS9%g_fAB`'/SRqj0V?Q!.r'3'.$FqVB3^1`H[F: %bVD3=F=8S(@iBngR$e&r``+XC#S;PY88!HO/n;d%RK?t2nZ.3q;NaOCk7P_IPBI"4S-K260d<2$L2rk'c^:S].3CR'W>7Oo/A7"p %2bn`]X78<'!4WH1YK''gdB`8fAh&I#F,K+\E2P-agNXO?>b*WCp837haU@@IO,M2N"63Y1*B&n1dH!@'*U`c'(Fb(]p %WD!\#2"FK4LFJN_-]^dY"nmC+#Lo-O'q.c*3[)qt8J6@Gir56=;-B43)U^FUCcb7M66&2qnaI]XbC0]ug]MNi#0V&>I43FXp?S'W %Q-N/:a#jjW05%K$Dca574tX5%r>,<.GC4B/pspZspuE-$nkQa,jm&43N+pW]djiS;JL:'>2;$D0i3Zj%P8lESA>#m57cC+n0(dDt+VOroP-?f0k%MFskO2i6*PT\i]15)tBiiL!VKDG$& %%"0cjP=s^#dE8\L"XdB?S>!5g`LNQ%'"2k%-I8nN'X*hKVi/F++-Rc0,6k%k]HHj6 %cnRgGQJWq-UkU+GY`@d]@sRBRSdN>)6m5_T:N^qF4a;Cg&;R=l21,m0(Pm55NXA3q)*C*AX[7"bQrG&+)*IGf?kat0>st3U$r0ul %&gK1'pR\SHp\9.d?!Gl %kghT"!@.u(>)C+!%AX*D=HPpPN?VF@[DI1="N#d?1^ENr0R3l_;N8Q*\6EpF:fP:pJ3rf*k*'@]U.j)o>CR@U9+Kr5SBTrVa7.Hh %*'Sf[mmB*ok"sdGn^+b)h;KA;]&O=hpgZCT6Tb7bc>_jcc=\3NOkn8Fm;1(#bI3EAjBL6-EK0.]5SIKreod`MZ3oU9\^r"?FQ0*. %:2+TdW3c+Ilpjot'ST%SGSGjk.(Ct[a/ZXh.?s3cT?hm\:@rr13OCG&^\4)YFM<%nh)hdaGP4fc^;%F28&qcm6$lT5l273F+11Wl %FFG(k&MAQFo?S;=3hM$ZRa7jQ%[M#1r6\Xli4.Vk^7;F9hO)UNq0Yf>IK%jM#X7S??S@M5/0r!F^V@=kI=Cn'JBhPoJWq,XP8Hp1 %7Lhjl4lA"7opj!@5+;L*D!O\qW9$Aq&@;1*4m55HddY'uLgXlKIO7t)M>1t"`5H1ALW#OqQpID$Kj4RoQ_a<;LL0eG:p5hjkP9$G;@"0M7+SWl&Kj9]eqp>QL\T?74oXek'ua\"(6&iE;#0Z %Qe"]ts0nSpmO.](WTq.Ec_eY4Tt]UqOk`hK([G+DVgr"\;)cLV3o(E1d#l%5M`$7nl)a>',fhud'G;C!H**5R[nVpi6[E3tGr*YS %k]-GPVNbNYmb0FOQ^MAIDg5o_\lTftUSsb2j&-NC5ZtRdCTI8@Qog$_A!)gE9:"4`;.k/V!U6l!_^[NmHZoBEb!9gE57O5`o]`&A %:TQOj0ICcb,XKWNnFc+ZPbO9T;qK7,48tqO*:/W:*;AZ0*1E-u:o?Mem.["4YJ.bts6BW""@-Gs)?lcn^oCR3MP2VFhPV5C%du*( %IOhA]0Y\f^/Q&uppX`dbLHf2^'_pKH(0"QKbb&H('rgKXMPuI:3a,bK"PCF`=f.t*1+c-7(AH=>51>.F,RpdASKE0D;d/a)qiP2l %qk5C5qm-u"CS])OnWPU"/+2?qE=4N#SKg-.>DQ^75U(sZJ,kZ_TQ5H^$-X5i7*q"M'TJu([bN9sMIoU0Ha %X%'M0i0Tu0[94Nb"q.Vp?bX7O!<8RePH<;llTaQiSW>GW3A''V[?>p]XaA9oHd&U=bcUcP-p6YC4m(=DrdU!>FcX(UO'+;hhcVds %U@9Qg:>'?b6"Bneald$G/L=@BThYRCrpJCRq/?]fno#,JF%#jOEj#\F\oHcg"G9Q2?Hqa-0&/Yg8KG$j.h*YUCbaZ %T;]+jnk+Prr#G_m/KjoDqALW'("0=r"_eSSDN_**AqaaRs&BX*6TV.3k\+$;']aWKstXUh@t/*K%>qm]dW!$*\j6,#jTCL]Ioi:6.-h`u+>VN;,+sr"pZ-N"J:oL`^-F %O"oY7B[C6sn50l@7H%)X^+MnQ%thieeB:[lj4Jblrlte_28\5gZ+)I(h\EE+-,SIHiK#be_b?!K9LD%je>kdEC9,(sC;8,khso'3 %*>H'J=-u[>g5hjO*QR5NH-Ita#"s];MksBtR93(7gck5sSVUPe]HfTf$[b1u+Hk)__+=a^ATF?rnl^;]$g5GGTRG$rZ!$C5jK]W8 %=tOq]Je(r+?&[m\KB\->m\OnJWjCO3o/q>U10m)MSG5.PbH!`&oNrYPgh;5S/iYgSfLH[,bl=FV?oY:j(.qstoJZKb/tEtM"KI-P %2107f#:p5J+l56:UR)8\DG#+Z\jKt;5KMbeZ/eWijK"7?BX-XcbsZeb`Su3ng##HP`F+%HMb`aspnFo%MSeHB-Lk_Q\'%&T %<\)%b$H)egE\N:R5]Q;1n;n^\RQu"H/dqPP(BnFO*)#G^pQYGq+'8CL/,i'IarUb1U8pl&mWtOQ8K-DV''VTCbLYl0Op#9@J?d$# %8FZJJhH\N4$+t)Mi'em+HFdNqTY"Tnfmtak\Kj'XP?GF?HWdTt>D]>t;V%dma"4Eq`5U[YA\):.6W^e#cUKHDqu5ku %oNqu7hdZ243+`tN5(#'Tgd=[dZ8d4c[.lmoE>;P[>g>'Og$Kc;B_3L?3.0Y%NX'Iaq!d[[_[!?Z?/EZ]0#7G4rO7F7_BD2H3Qi&s %G*mS4;@n/UJ.A[EV1s(o"YWU1o.#,kA\nEaSQ!?<.YiI/iM.e`MSc,:4Gn`I_O&gFC09f5I:3>A]_hN4^$9j6;la8mm%eQLDRS#\ %'oVqBc/j8a^-\ATVc;.JHTMb`];oAJa5c?SmdTl'ZB*8D9=lH2BW7s'(@b`!5jC/p=LkBt*\hNj$uV9=[7/as[l:t4!3U1]7U=3^ %mP%!5g\oZnhrV#Em.DF'1Z]:4Nn'`l\%AP9Qm,?a&)Sr0OHA\)#aUk3bqk\CH$(pB.YWI-&Y!KRj)%Z10RRHCN,QGl6>r7\F&TaD68lL %f6XC8uO")NFgsbZeKc+7fLT:1R7E4\pBnf+r[=gI$dE'$1^rFbL$!p8/>?a7`4l\nh/A)mCF?JpdpP %a7aO4W)f)h*H@7GGt^$=#Zr58U;4]@pR5!'Xp?$)T!Xd?P@48lXkC@T'Cfc8DG5tF@PNCLWFP8kVlr932-')d?"^%?7hQk67J4d$ %4r'@6;TV4I! %7GQ&$T,BhA7E9a1eHj'F4kFeS#ESL6(k;_@C(WkB!rI-CM;^efT7h&AO((MDL99qX>&*!`"=";2b,_9,.Ul(I$PE9C6ir"phlW!/k(W;Be6DYeSH^fZB.G %Y&9'a1]u98E>JPSr.sl*N?E5NWtQi,[A;r"Cpj,+/"S1X4ZnkQNqMtA&D^BfT*3nMWQu9>WDA%np@YXQ'[VI5NHP@Uh5MXQ$pLCL %NuUpM4WHP.p^kq1DW&DFUTWqb,HPj#eWZ %TVWsG*ZX>&\f4Jk^6tOh8Obh%Z3b^JPmlT*%'./i7i/Pb11Z5;hg59C?s02;4QC%&H$YIi/qi4PAHT8#c\ %q.;P"\,H7_=9f/u+64=k]`a60CHUD3&e0*ae3jDQ%')@+Ahn:52P3Gl`6q;`Xp3X^]!g@ufE_fW2ub8)"]FVGb>ZX0i'6PCIu06) %J+dN`^Lt`%BT$N4GkU('Ll9fU98Z8Fb&c[96dLM67ktkDDf;gAPdGXR2HmT9HFhu09_`L-<"\]p=mO$O`3n,pTk:j%H_3P4Ko %+rLUWY=3]G'\.ja#=Wqe=KeIJ-nKk0G]ae,fiu\3+6DA+b;I`h!BAe'8,D]Q %[/XJNiO8O7H3'4@CfmfM4uI)#PK(7<_KOu9p-s92>J9meeX*?3Ol_J`QA"2G^$1kI\;M>-'u?1R-d,0sT4*n;7;g3kUL]W]ipU\f %-B9Vi7YX@/aRXegAR`_)+_6]@ZH3%_QAH]rrC*u`Aa0l>BUXII.7d#G_U&sY#0B(6E@_cRGA<^6$TA%`fJiJ[F.4ttj2-h$t]FMq6ElT?!WgsEHfA"e.K %KPPgG;OC'9A]Z[acnelDAB4S53.EHm=4O(jtRgJVg33!-[tP&2B[Kc %XQqpt`MnN]*'Lh&"r3V+"5$Pop0ZL%R`S90hKeMV]=*=q_)utVoU9%S_>J2anQK13Egus"!kn>3%Mm-RQq"&6Hh1OG:pV-<`K6LS %aQqsbe-hjUTt@6A3A]mEcs[gcK?:55.A2d`bRD$?m+fhGi&"'l\[2u`#;kkE=rt7:M3c+1V:(gg]Y=,1C?kK=Y@&_R#^rBrjjLYf %hPD6q3KW>1/D`i,dZH[.[Y:pL=@c5dS7I0DFQ12TWslG?Z-s,W,=O#)DNc&cRZ*_oUOHI$o#RYGmZ8M41HK]p:MUV&amm7GXuN=F %4[LYoHu1KE^Z9?\`??R4/[%)AS;T>Y+hetBM0st0*/Q*a42'6U$5RFu$h;ol[eYAGblD@Q2!SM:F\5F:eI.3Jd!SPZ0.OpTSBYg@#3b`-H@pUt%TT`c"]b!:*JEl1e86-U@EMj%.[pgK=M>Ei\3? %?%c#OY?O4=Wp'$LY0KDCphJV<>ODX65Bt5>VZ)RoDAi#+L6b;qW4!M+GXEKQZ %U<>VCDJs(Dm1I'n3KisSUdj!clY60bP(,("rGcg2K=N`L?T?h:HUS%:0oGgKnQ*q8T.0W_N4O1Z!.<^6iXC!6F6NN)EJkL`o0CMd %G3s!\]:qrK7p5rh&n8S(GUM)Q?dmGl8@)B$Jp.pV4NMtKiJS`=s4WqE]OH?VAr@2W"hq\.qoFoD&)VVOjLD(:L'N_$L]4o3i/stH %SFiW6J'RlQ:K^pen"@KE/?QhSZLHuFZW-?:XXD*daK'GPh8Dj/\?$WnaOg6_D@PZDn&b$9jFq+D\;/d.mNqW!fX92`?+G3+^cku+ %rUC6_qm%37^O2K\Ydo4/i#2n4Uq>angg[mg[H1!.D@YSN)jH$%[r+=b0hV%FDB?0&'*KPDf4Pnb2+uB#O"6$LjUW5GX*q/Ij0-BA(]Vsdd'HT^%;&'"EpH!dnp!@i0JBrN0 %mq+AK*Bg%KOY1Fs/Qr3).2J_*kiU$N8HVT*`t/KhD10\d?-!P9a/sWTI.8VqUT[&Z;_-!n4@Z;dO;R-WM+gn#TVr@C"Q,N>/Wjo2mJ2q5+qN,3$Zk?L9LS %p_A@?DiT902HGS^L:4UtGa`Uuo4e_r@0mVF!@sPU\lFbtKB;Dujj?[KD-706'"-'sqr%9o#q7u=S6ZZq$qI$af+/R,s*.+Ya^9sh %ZGePo->?\-WVkY[GMT;77p.%;0)TP59aiWp/@1:&QpnGs27\[(\K)s3/5U(Ti^4,SG&(6uo>)^/Hq^9j-ej1,9=EN)14')aqIIbJ %@9!g4ENge1u79a0X-])B`Ho>\86"5XA7<9B^/BP7EV@p)DX\&'eM`c#EXk9PAqC3)J($@@ %\*XGh?@09&KV7els#=N-"'FYtOQC2N0.8BZo?cX0Gl8IQhgKeRT72RP"'-0#-n%jeNl#Nj:MhS>pQ*/_h5%Z'Od$!J,`!q>I\7!+T)Frc>YX-WP8XZ7@GqmP&*+[+S-1G66LFp#k-I;=33[Gs(GDan %INBQZ %kpIHn,X6jslsmcVY=E],K&jVC)b_Usm?RD>$\BJS@p8J[E^$dp0SNoYf!MAI<+,d([")fnf3-cU.9B1kNh<*)cG=`HjK79E_*%C+ %HqN_YL@BA?a!lbc&Wk%XbTam,r-gW0FU@3/fTolTT$I8'rLmL@K'bs8V%2_g?VD7d"cTP75_aZ'P2*e9?cV$eP[A %_@o',GE-qQ%fCDT%L"1P:'=T+a'el=qZ0DdP_P#&^k%[bq1jXk'UtbLUk.*sEoq7s#V*m_F6stG/g@gf)-iJ*nVcpbN:7;Y_`9]# %M9/:%?j'kRkL0^[:oE[u+ojWp_CQsB6Wfb,f&dqNLch%T+:Y_;"KQk)nB]_ujCJZQ0>7pf%^*`C3^$]D:RAtnD4!S?'-ZRAOknqr %/h,.%Gd\k4^no?JZ9t>K872qr_D(f1pr;JPPTYW%NkoL>NO/m&*'0qnkY9:F+LF%i.M10j,mf)1^&m6KgX:jD.>[H01@: %>%e(&+Hh%QEZ-Ebk.jboi.+]e'A+OT!,P2$-2WA/_CC8l'I#es)H9?Nph4ARA;$r5S@6oc#sM`s'%!t*H' %O5k`lLGCL@PI/Uq0NIV[3C_=,SBp5__\iM#$RN:$dbY7'kOUM;B)&,5BfIh:$ihuk`1UsGQB.:cSoMZ0BBa=TJT-(Q^m[7.9E:#A %U:/Nr#W6YWR2M;VHGMcoar:n+7K>cGZ4IsjXXk%a#&:%>GB*mBM6jFq9Ha]rKqQ@n"u#"*E)MGL6I*@`8&:Y7WX.ThQ02i))M0`t %!1,*NVkt/=nCe&uE+3n33V3+O6i!K872J7?SI$,K?m(hL9#*DU6]e$_&Zi*k3E&alC(lVg/JF"\T&V43#*p!D]R]uSg9CrqTCDt" %]?VYSOs4SM-kM,5JP?I:*K/k7W8tE:EZ[RE65;K^[l\e_/eTV%aZtT^ULPn&)&4 %/-9Y/GQpoa&-N^q]HEU(M.@ZX\adaOR,hrsi10*Y]UiUj"<`gf"JD8qA3_Y@8NrK9TU=*s9\N_0p&r62K\A9.MKcp[6"]^JNu`/0 %8"kN,9em9Dd"LA#@N\cD,q&iAKS"Ef>5H[V!0^LRcHsrioZ#1;:!-Q?;Lk#]0G\%A0&"8&!='`d;qVnMW&a1<3sV%F>$9>mCL\dp@+UU<&fFg+XN\]'8.cQ/9A?ak=1#VV[>Cu_THuRM %u51Qj0;[np6BOfIN&!I7Q:?^J&1M#/!!FV?Cq,Bs1!Y\k*f2TNS[jEes>$S[sl;bi<12;?Sl&dbBp(>Hmb1D&j%]oIQ*<._Y\f-jC\8"aW&]VU8.r1"N)!KUlf&\DUZb6m5=?/0;ID7H&+\/AD9"'9DYplUTFl!,icNFMh]-8(,)!B"k %[2=KJiY$EG0O:Vejqu"u(m8AQ")HC0ca[(->)InbLBcI-C)XlAB)uUHIaj_lZQZ85ogBDH!e;j+!EPSL"K\gUkt6[**eFB6H5Nt4 %@%E=n(oibW-@/JO*oM?Ee#IaACj`@]3L]kQXQo\5?I;5`)2f%:MjA+[RFN@k4#RhHail%2LKTT:Op)&UeqEn)ZFD,5l85)+D^%oQ@uY`+-r`VXVDnQc;+l4)-W[4%#(f+R %IRI#>pKocp:MH"CN]Z,s]r^[^7oKXBS+I7odVDRb^aSS9T(IAehtgXA,8o$liiuP\u=%'Qm-B7gps,d>21dO"i$= %@q)7E#"+Ks^s*YfRUqn"n0Co%GYjaEOIVW.;/%Fbij6jTi=.E4-JB)A5i@m/\%5P`ii?!*8Dta(oQ]f@3DKY*)(1Tc#dX7o.,:m2 %B#'\$l:CHP!17WC9p;#ZF)aBSPCNu?n\/*'fYe3%m':^RaTsBPd3.B"->>Q13N$p.?pQ)YNp=RBqb,.j,h.Q>2'N029G;JNk,EmI"4bqSQeE"_kRX2+ikX)XE1:`F[-O-SlBRK,4.;:'EBL7jRKVHm%%2(,4c!YGDX:KbUY %.1\[l2d'-`=$.4:(;!M>)@VS2L;YF!e.^3QBj*P4D`1+\aPofeXU\)TCroOnC.qCb(]hV[basj#]oabNZCZ>$ZV4.1E@T&h<\p\C %O2#Q/<5Bp+'Mi<`DMtIX=qklmF]Y90Dl7iljf&UidSSJnQmC23Z3rY?P,npu;W]gCP_9*BYF;t57"J(Rgu$.N]M$G5FI(Y6CAK,( %>B+:s5\R.JJAO.hr%5;LZ7ToKjoCp8)EpSk)ZigDg9:qf^g+1RjfKX.VO49@0VUIsrB(gr9uFeA$iq!li$Xp9#\.(1B]0tOdEBeU %MQ3b)>RnQGBhVaOX-c25QoInD5>J!,Id#>GqpcIE2U+iZ[8iUF7eoq[KA9/hf#)Y+h"H(+C1\OO)$BUjf8-!Bc?Ci+@07-0r>:[, %<1pI)gH&$2*P_Q>^FJnl1ketce=Np%`#S4hoV'.2140U`?pRN94uE3S8;+>4mp"KA"+ah6dEZ\fbHElg)ds'ZSa:+o9%VF9YX3k/n<'Yh1>= %/>W>s;BTU.dB;$o\EDigm(V(a,dB>UBqE+Y\VO$>GA)%&p7\3(A7eJrF/B9Tq:b-*)Rf^(LJpoXoJ\'S2^PK`cFK5b^;n %h*D7.<@uLQfSN!=-,MDk=Kd=YWC)lI#<.#&ZGS&`K(#/ %Ro,HX(u;D'_YQ+p7k4[unH>Z7.3jYWkui,gK!7hDPpX(%7F'sU5[.2%%NN"mY3b[C3r2pqkn?`.;0C(/5a5cE,,;ZJsd?0Gkg%"ZM($(IX<*/gPZB*`;teV1I8$'\GpKW6fdd*Y'0ZrT0E %cbPoJ)JIXm_l]oo;0i2mIoq;.#jQRumE3VeSs"O/'V^P>6r\u>W7!g$Ohc*E2*IslVZQ6d]'OkgYf`8&;+I4.p+>$`+`Peu`ei_Z %"O,"(E(=/YEYWXJHFb$;Y^[s<=Gt&06fon)BUAU[t;tq"&Q;h=SGK7-I:RA.k<9GCKV,!Pcj;q1s%aC@%)5bH#&\s/C$1/#`KYrfE'ReT,On>.G4Sj78kYOr0:ocoCT"uDluc?G"!2Af0#mRiXDs/O[ND[T^AP;o#O*?"=D==9:V#u^mlt9TSrSu&PCUL2(A[?aB:u62)]^-U!.p%q>JuU6>j_RBAuapQ%9iT>DPr` %Pnu>G)-DeH"EXqQW1.3DVm.(j5%G@kP`HQMj\6OSbbA%tCLIiF@%(hp`;n->8Vbp[prkf&bo@*[0W1T0:9a0;*p)KO5U%^_i'DR/ %WGTo'0EJQj)J>B23IT&Eq?1=3blq#n?)!f]O.P"m6s.g?=R/ibi6eX8'U7K,<=>_/kD`gul8bUHde@gepKMO`ZtD-Pe[0#?S)'aL %'aWC_T>J4`!mJ63ES:`:<6a-'*ha%Sd(9#VN^ZrB>qsL#?qlV4*8qMEZA2+`'h@"_P=0co;B.8?QTRm[#gbQr!ht,Y@Vk=bMMZpk %O]m32F#NQ2jb^.uq"`R4eKWnBFnqf"V3)JB)UoILUdtPoP)C_ZRlNP$h"qd;R%S2`4uQQ*LA'L:8DBIn"#SmT_&CZLR\,JQ3U1pd %1B;ta="H34gnP!f+M\'^c%BNf8b",+Ycp?Sj8nil9K\dd]'%c''[j/aTN3$dAQcZQU0TL:jR?INhhk %/f$_>5hf\N%2%Sn)/Y"70#fO"rt.%+@<7We>mhf]ZR(0DIM#F7CJ7Z4'`dMK/a"If#AONJl5(W-.1?jg6X\IZL9?5>@*UJdNB1B/ %:JA&o$6;miGtCR6Mu^kuf^A^^.LUen4_o0^,'m)J(M\gA[`tKp@@[+N^h132-HKTH(M0\MAcV5A1jM=pF>p-g8cSmEDY)=X0>B/s %eBJ4]@^h9LaB>1mCf!OT@F;D?Pa'HYh/\hRECMY:=XTp:WIT?X)4be;@,nU_DTb3i^iD=H\nf3<4665qN$gb' %E0ip!S/BmVP2ufX!p=A[oUO0Z5T!eo=uN(n"@-O$d\Jo,LS?/[MF9?'=R7<#C/hRUo[(UZ#L!IUj\AB.0!_>ZeKi*LJb,\88LSpg %&ZDSH1up*ffP"nPLfDJg8:4T0&SQV%oKY:nCqE$$"t&]RN#+Wf7p`H\Y9mL$%FlR%Z2c0\/dnlfCY2g?hbKB^k(Q>rR=kQ&odW5_ %G>Bi?"Q2=TFuu+n,)efda>7I8Z%VC&`R:l`))kI9k%"A6QlJViaY<"!3stHcP^Zu;A#2]+,U7f#&62mc?a*$q"3Fe.`I-J]:rARN!8MCl]E %CV">mq$S;sOUUS'%k_*J(!5!TWb\9gZ:8n"BjoPu)]D3M?nfPc>B=Q#3'QD:VQ6*aOVKDL92j\F(8G&cVUp(d]sn;3.X&p<40[.MgQuG&2^sUIk!1=lZ>4VaQOjX-`ssTk_>!nVKTH %'(q)EFHu24>(j/Q1gWkd'S9=D/TFQO%$/JY-3D$BbG?[%Rr.plpcEM*X)/?(m2FYUk=s.Q1/;A4rsA.U9%m*P!IdB4Y"^ec,'c8] %R6$5e&imIq]=dEd7a8iG%H0;pAO9A'TQCpN`QiEu\L8P6lh(SO5'N\t9+Ucr8"CjW2Fb]&R7fMFGp+68*qk_?eN=ei%0-'00m0E.Hl+RQnomT?*qRf$uXp$h%UBC81jNE%Y2Pj"\_)$EO7E; %ctGP=Vp'/e2KHO3VR"RmA@-BK!e=3K!WiVJ&Qn.f,P[MPQjc7t'nPNH;rUME.UJ8\1n.td3=19LbiYDQp6XjOou*IKJh`a:BmMi% %(oc$6-GY790j@dNOg4^BG[X60pCl%*H$'q]1eg#HmIX)u %6][`Uon9X*21jRo'9hi1XWatpap9K\*M#!no>a,#:QeJ`8Mg2>4=ZZrL3SX9V1$oBFDO4g0La:YA7/-Ci*-YC)$>c&5p\a&2P!9q %Kn*W:[fBBS%M(beJ^`8tW['dr_!K3a!\&Ao/4k%,h6bLO/4^9qa*s=_ZlQZt)^P9oSqiA/)kh!#(psThY1+JCMEOL]i%!,Sm$Ma- %Zm11463]T-eAn5SD8l*IZ5F8Ol(l]^Iq(^GK6\lFG\O(F&5:?S\tX"Zd`JYd/$NW4:X+c]`,e"MO&4M$&9ECu3VH1"aLc=ckgZ/L %5Z)BH"DT-oS+V#(F4/`-C$8@fbcbiA#<(G1d.qA2!=\BA(*5T)F&;WIMZsq8O;u,F\WO9AAIa+/K+JadO/40gZm1hA*0l:6B!&)+ %LO18@m$D1ZW.IYV0?#Kt?j@)O %-p_2rU'SSOb1+upX:ZYZI,JDN;[$fW(^'5V-od5J%T]>,P7!T3M3AtmW4N;.)q7t&Ki6\3/7oQnBli"O%q9`0eq1=V3qq`7D/7O5KY!/d,3L-6+U+ %,PL`oV$E_C*C[rQ+!>=D5oOmdIZ*s"HuO2/TZH2bJ1""QSVh=,9LVm8kQDP$>DcF3 %73d5Ufl]a0@.BhKDI7+LgQm@_UJ.5aU@g_gXB(9k6"1hLdWs:eiRO'ka#6[FZ%+VY2Un:JU7pQ@_Lnf%Yuu%[cf\<>NuDV<_*Z![-3>23=Ld8Ug?'fQAd-18AlfAADb>j>@/]F0&ineaqqIrqJ9(1?M8Z %leHTbTT&rRXK4r,'1)BLE%b8:m6'-(?fW'$(OmPIM/u3Jt4;JbYR8!@.Ljl'!ULjPit`\ZYOC0*pGl^>t=4;:7`&l7FqG/g)'dnK21JtK3] %Oe!>_3Uiu,m,,*s4;ZGn$=ln`oSmB5\[EB>(.b/?H0U[_s`&%IJ^@Wru2pE+)LS- %.rOqX_#Lp!^;cEF`%bano"!7B[D]m\7ZS2rl0'HLX#;$,RWk&DWo1`]!DCchjN-2[^m_cbI^^eaC-a0(?*('`$)jUHGpBJ/V9hJ5 %+E]C6^(-`d8%/..8>kT#8dYS+jMtGdLp1*@hn%b'@/gTKqVA;!Zm0IW__r*XHu=Lc)3;]Q.n39djn;o9Bts %)iS#t?`k)81)--0b;8R$8Sd1Y(XGoI6i"3Tel[0dCKHu4FVC)fWJHs_HI=s;G* %m@A9"2[g8KJg3N\WPMYqFL<2/@l%DR:_MYVR-YRn]Fb1t?bG>idA]^uVPr81TS_JOVAHmLS^^h<'pIKqF$O;SXCGGBV--NaNPk%3 %9L.2Z%$fOH$`&uVcX%0U5\7)0leD,N3NR!+0Q/IF_k]MJp%1T[ZlOu.&SG@`.BOGn^+fVJFl,[4X9J'cZPK&\6(IGSlJ2f;F:X^1 %$!/krAuUI#?)r?HBO3pu;u;7Z'kc.0TcP`[\C!D=iGAZn)Y^+Es:W39]54ch'g":E-]HRcI]FL7SP %7t:T)]1T/?gUl!uDE&c_`AO8?G6.635f!_!?`Ptj!,]pjash=n*p:3N8lSGZ^QH9pS;nCR9*b(V&.:DRSI6k>p:DXN`G %\3uA;h$RD'j-JtHZIM*Pm].kZW'K?dhuEFf-V_GH=?A2sO4Jja-XJF0,(Z7`jsX%K,;M$'=Fiskb2I@QD2#cWX;_n[\U3ED1`m'n5qc6 %$./D]g+/=JUd]2uncT4pRB+9;[_5lTl^@pRneN\4&C_92RY5l8E3RtS(&V(@XA(ILU0]+A5jfP&q2Ab4(/mt+=CLS^Tg5$Hi+0eB %*S,&K9o]8U14i9'CYSaJY\n])!cJZ85Ktrm;j%Op&!h$:#,\%Y8m:=o8\AA\b1Ii:dBsE3^L;i(",-efXFd]2b,AmO'l17J)Fo>Y %Q*Er`CYSaJY\n])12dbI%&^7:C^Te-moJA^3@rsHQ;m4VA1->O;'h`_b2*iPD;2WD1/;jl\5Gd32)mG7%u2]OfBlUZ<^P(%9a4c)2JKdp0n>4eQCTskH*!HCCmOGWID=a:fClB"B=g12'K[cX?0G8CKNYp-r:$eXN?e= %/#K#[]V7ZAb$LofdC+8NY\n])1:OM[2C:L(-G1C7-ZP?IA0P`eW#Csp+Gd8h_[/[9J,R6,=J<:=G_33aZ_!VQMr_!-T,Bk0!W; %]Jr*HYOZ(-S-QZXmn#%Cc.-Q^NDsJu3T)\[J@.Y?[VC`b#AVGm1@bco?CV7iL#oS"I#$O@!Wb'.:9A %TXtrg>ucF\(3J0KY0'">G>8XHC`R#'X0u+O+N,#G%V,X*WsT;V8"7P5WQbA=!p');XfcO0G)teafV%#JIYC]bc#L4''lLDCeoT^Q+'AfCYSaJY\n])+t&E=#N=_)PcN>n\I-=SKd=5t^mU+"0YJq"DOfM.Ljc$2 %/fgn'%9u?S\#k&3G)7a4c)2 %JKj;c]a)Ja%9="p;'8-cX&A9;qX,9Q%1c4q^QqbJK,gXcJNorR;Xb %Ja;nY.1i/W=/]E3mG0Y$)]kNlI3TrGSm'aSpWHuNn_dA1*0i$i3c\f']C^8#Pqa"][GAAWoTL,dEOhBcA[lS-(Jc]hFs'Xi#Ri9'k8-\PWG]G20R^Qsl<7A`3lY1o %s5Q5OJG!jDm(A[s'f^8[`@"nB;#48$*Y$XM[*:Tm'1d6W9:Jt!Rlb5!=?FlVE"4EFd["!*0)N,R5_+fd;sW02IQ=JK*dkX+LH"29 %5lrIf8t%_YenooJ==*YtZrui.Og5f2jBbPa)9TG-_R*fZ@I6=R5R0cp>%ku%%@o#?JC)W\HX_WjTQ[@\h/M:O:0d!EKS`Ldh6"KG %e\Y"^MXQY7i!.18`n:BX[;q)\\"31/ZpWPUW?2oJi7RMDkX^>3i9(@WTWtqBg@ei5X;_Y>b([`bT!bO*;iJ$iPcKG)g0ALdf.P.d %H#+LuN0X85XsFhrNbak"80:pA.^5CC%OL7H9>QejFTEsrPu-)@GKF9!FoGq>>G1;'_uui%HZpuZk2N73Y1.fgqi(r-EDQtX!L9uh %R``+9b)C1k[0)*a7A+%hqrs2OQ!Pt6Wrr])H)nlp[_5lcl%T;4JI3!g2bWBX;sb@ %F%W`jUQohC3!8%n\bs)?NN]J(B+%Vt8eVKE54YO^VNF_uPN%I8`R-hH1]&)fsk8G-j(`kYhX1=WY4G-TXYLX9JPg2,H*^#]s*28TifO6cZ`9XgiNO]m$*s*Xnt %B@X,mQG/uGF49rK\SX=9>dP,@O5k&(Fl:BA>L>/g*o7n'K".\$]q*Cm=gIs'CKn>!o+L?j30(K?/+3h %_n+gCakSeU&si/454.aoD8:>D?#aY1)u@:@9gJ)N9:GkDgX\9"Y]c[V3\SAJ%4)#+[]i\^`JTo@ne]/NH?gC\aQ:ebV\E`*g%bDlXC2"0"9CpsHS2FN0.-2A/ %kSE6VpIJ8tpK3"%/%fUmG;-+8j4];^X;r]'kTD;+p@:At@(4EB$3Y$i'l%%/iXR=TedW-bje"u3.6;9:O4&8,jrqm<-s5+NBq^E# %f6l(U20#pVDXg>_;-dXHg[mf]O0o(D!p-S:A&$Hl@h!_bW?Zq%b$1^M\*TZ+-oVPoQ$\6EJlk1F.&X+/'R'RJ]hq2XkRY90O'tJ.Vl"q %`NnlIMn-ajJQD'RK-OaPZc!c.@GFV/!0t/gX_Z\gjfiWIE%2Y50=S2B;3^U![fIEWIEUCu*La3;7W`!pir?\P@L;X2h#?6%(^C.7pR^dnM$%4(BSM2-(55$C%Fqme3*eC,\Y- %$3[;d]",-eFd)#_D/&@,-brMpT&>6;;DVFsT %)V,?.:?J431=A-:V&S3l^o9!R=ANolmNe&%PdC((-!Q%q5PTn(AkDSB\Ph5_.!_-.]Ks]iCjI%\3/Bh/\l; %)=q_JD0ecg[A25r#tE?CU^%\AW;Hs=Si1G4<>NL;JTL,Sm80g9]0s5lkoO+QTJ>(CC/.ZR[g_Sk"(-JBmM!dJI)lotrP)]>Q3:Zd %kKV+0#O_7`;R-2G?>1^ZY%KQ8=(Or(DphokAVnYHmng(qkYKbiE3Gn^Z+"kmHqb@]maY5MTrYKI5J=#:d`M,uHZ'nL:!ZUXX=iH@39gkFMC]7mCT!ta=4KrQWE*.nGkIsM %''U-6;ULE4IG:cg;L5DbkUWquE3GhlYkBOsNWNRM`DPsTp3o$')]kO7?lb2FM0>uE.^D$QYFUh1s$R7jC6b'Ko\S+e7@&V$Z"iOt %L^[o$qKa^7DeNkH'Z8TSXLPJ2C+PBCf=(FqiS=)*AEW4j7_1HE`i?:'BWmngd#shTo3!QE,eS5p2@!4,CA+H=>ICiLa4c*I)N07A %\g\,'YH[!lnC:V\Z*%s4QG^;r^o7go,s&?8M@mMlX*q3.8`Hf4%<8Au8R,$tlcHikFh2 %YrG?]gYO<5F4:.&*3$j%O6ZE48h:J-CSiAgqcU;0<`_lG;Q5'j('(CRin>0^4Dp"`"+;I2#OXHJ*7eG%`DPPDYrHK(gYOT=Fi/iq %*N?qFTY"lq_MYjug_VutdD3OQr%HjVg-Tb(YZrn:$?A2qk %ep8bF/1LFI.fu610?p5^X-T^Pg=EgB%Fu$U^&j3;f!Xo$l:Ek[mKs\aF"Vq@2[8J!m?<+rVi%)#k %@U7aF.u/8bJQ"RdZ1tA"oN\eVp0&ni>@L1p[UYJB/5 %]iGKs'Im`XHW?>eR?M&XJL*eW'jOtU6rp/6Y]c\C^uE.1/B&e"^&j3;f!Xo$l:J.f-2D>k]#PncY$aA2SEEIQf'hUc+3Y[76UUe2Ab! %n(Qe#LusgVuGgUh6'2`s'fbD8QFk%:"MH>"g+F[Cr,b$cf3d-'1mg9VK8Qb9ed8Ysh.lp*)9 %Z@Kqk<(7V#ej&Y2B:-E9FS_<:6Or4`mjG0MK#C-jdDDoe/APF:"Zp-fU/k705,;4"cpXaE#,c5u'g&GMZ$,&G8fLl*V(AiC9pGk_ %F[5E33H2I1**0,=i[Jis=$3mn %D=:QH]&gc[HZ44M9s2G#eQ4l_lD+ubU[IX8m>fPm+pZ.oop$ND?IXB`D%!Gnq`d/C#OKuB4Og7C_q?]+FPh;m=$3UfD=:Ip]'fTt %gp_gCUaKH:[/,Xb>FcHn".%sqVQEfs_4K1f2p'`J?PqVU[^H?be&A:rF[0#V`Ik9fMT9HHr?%Plh8YVl4_` %[/,Z8C7u?;9(X-;PJ>"'0%JZHNEWHE')^Dtf6%o26#!G8I;e#TZ'Ti*?DaX(f\H;,.@=j-)V %B_<*nd_oYH0M'U%e8pO^Op9_I[C3mhXG/S`XOttt %p_[-2>)+qo_9)]4fs2V+*+>0!9V0:7pGLp8/n_dq!*7?`\G-BG&=b[V^@'.u1M7XnKmMb`u(l87rn5rdCo^Z6Ziem!\.9 %=5En;oA<$]RF/D)m_:cd5s#*?I %IICpSGd(1>5t\%1=s=j)(nas@1_4-*1qZJ0fbW6RJefUFX<-S?YB[:;8b#>=k=R,;eR%da#1#U&Q6JK/JQ'*uA)A5I[9#ImbG68g %[GU)^oi//.-+Drcb$%oOl_5u:$^sg3WJA%?dCH[mb[;osHjG[0Ll_=%4lF8a1T(oi1c*FL>3H %flh60jjma>p>F&72q8=]?1!mh*'*/l!3MS8_ucb\io78R$A,',+ouf5YI(]'Vb+'TYSLX2_.]d4%RQ/h'U>A]JaLsFDRNj*[]Zdb %Ps'@Im1%@nM.0U\Yk6j/N?lGC6ufGa>+'<0`J6_3Sp:@O3:Stb? %,b1+)Xp%os0IOsd:cCTV\Ub-m\[-&P('H_@\a/!"dCm+t)mI$P0n?fd^tp;m'i][0V[bWUQ%D=GonYL8NPi3`rSpFl;O=mCSTT/,e,&-;-SFg+rC<-0]GmiD5YD#9@#t0rM(qdXu<='prjc=[Zho=t@*: %:>51%ZG7MP.Xotb')Y2NP?p=Y=-o`gf*X!UYI2qR5D-*k90_1^[Tci!F`e4d89]]XS#*[HAa.%=JdTf47\Ohm1p"q*WHqM/ZG8X< %TuKm^`Zj!TR7XS&YcGsqK52'a^/q;BdSHOdAa/A]>BYp>?*8(\'<,lro2ljkEWW@#<+*.De#Lr!?t#%,eB0>H#9c^B?u6iaX1e/@ %eg`.tVmYAR5Cosq90_+\[TceuF_(fL8qDUTA1+qN[5Q26jshi?hc=ik*.tK(:fGt\D&1cZ'W%gDD4I6>IKj(pQ@?9ED7?\!lfoNROU;=VVj\o3CU8uX3euiok9MQ_=VbPL$!@7G9WPUU!kBMne_Ou5>+h\sf6SopT=+5^5CQ\1V4VO= %gT@IJ]"7kofAWB$.4EYFBc4`-+#?*?d!/$JS$kc2#^ZYaQ7j[u_WHgjuq*0I'9,Ul_sH>p!a %!^P"ZmTOl>(7/h+A?F:3G;[L;;I*LnUmt77BI##R<9#8o0GRRO40=cLq?_7D>5H@L[_ljje(#I`dTjESR&*Eu#j$@^39Oo8U<5!r %^1m\I"RO3U:k0U)C6Y/# %S-e7t%0pDdC=Akq8Zh@32L6e)@E)V8+OB!0*J#0m5k+:Hga^!j,.O,\Sjn/gA=OJcE>QKY75l(d(4;LJ>ViF@+E\9q+R*8Y#LcaNb$/g*onephR")fn8*%:S%/@@GtYDYK%P)G6nf2!*[E4%%9mTr@5jW-F#-5S0h56GCulYi[1o;#&+0,VR3*"rPdMBl>GA"]P"T+#4'!OB0;s=h %Bre6(AAjgX*H/M59do#MOKu=[KSf1(M5(.WY(]MFt,bs=1c %TX+u-O-&_mjU@$bPR(p?$LBpo(=t+Od&pn;:(#0V.\#@3TqAVeH6ouU@2!.*RkM7V8cO?TE't6"7VgS$/;ZFIN]=DXZrms %A-9@TjBm<5qt/]_Y218WI/`bJ+m-7H2cg"O!;u8Gf2mGS'`YTQrV_-G+.iFMIb"JWh&eku?aQOlIJ^d.pY5:td`oC2f,kBeq=WYF %E;[cBpLj!U^jb_L_cM3"r:fo8E?%B34SHZhNeC?er0*_>i=H+8_m8l5(HcleD@/jPhsQ %qXNqMLECI'BQeN=M64qaddB?/EY\U8It.@Uk!a6q(LP(=(&YFap-3EWbl>A%k5TmaR=G24n%QO2puBJ?HK,@Xheug&[!D1!>^ud' %c;&9gYDZA\7ngoDRhrP+S=_g^sEXZlMB8io@qa+fOJ.5-Z&M.o8>V%)B-qq*Ht1_h_Xqb`9uuqRg;G:pS%Q.Nkk`2P:M702+SqF$UK>%@J&4)1d)EZu;%u@5:9Q=RDuT'05MiLgoT]$HM]%g:DRNf.#L37s %a0X5ZID-)EG)/M(Ng9D3q<#T:l.NPD-aV06B`/;+VTnEU8,)i=jQ8E$rcij6FuAhCN48_f"=YB_1dI %m*/JDbCn5m6<^!b=,iU#]^ %1YB;[&jp7EKK$=9cSpD$T&d09c.e%%d;L/!ABmb_Xf671e@3rSp\"!i41`/?34q75qsVc>V^2h&a5ZU]_GF86nE,DBgF'ld/ %T54&U:-S3?AQ %T8n@_\[ji6q"F(6lu\Pr]_]U*0C(9\h*_c[f'4'T`[/>Zs7Gj@jRhg0m-=9T-QdPgb)^lDET9+MV]!@. %[+e%g\%TFcL[1MUR/>/G6&m):ndkJ#r,&6/F0K:m0n6O<\%S0DH1"liI,U%(\5!_5e_8 %N'PnZjo)+os#Tsio.%n2\NRKkGHn+*(7MLGY@e-$f<6q%bm3`e7L^&H["Tdm_p.l9N'!!#?GU5u[@%AmS=Y2Dr-XRg\6DJ\p>n)J %2KOps&45$/$E-cPEqM4ASZ0bi?``TU_V`a];>Y&6K6W*L %TC-Y8`/M7qN!3SqK6T7`jd[j*[F]VX_]WR8II#,pDt3e0)-*f)5_p]tic,4/=j#Li5_qE7GC'E8G+.%ME$3)X\SjX7>65t65_tah %Qo>lgU#0`1`#SWd[Cg(+"!M:#I:pbH],:l/#CElpo63/*@`I34?E/>M5_uQ96L7Gea./&ERg?[TWU4-qY;q_MbJ$4>^-?2jJKD[1:0+_B80,pgWPqrOfG]OqdLHOJ\%I=KqBZBg:Z^)5V3+R+],@6TRLr\!/gibd&0sA:M533$[Gps %dsCSlLeeD(>0,/ZT!jYAokofYT$iD,4&fs?Fa^eDF)OVI=l,7bX'T\bchN7mq>B,_(Os.Yq<>L3cGb+_="dl@04!u@blN,Ia1oiT %dHd7h&g=kI]=bj6STlS`nPYDA2cH_CcT$l#0)2ZK^G9P"qssc%YPe8tq76FtX7D%Zh2g_^^NtD'iV`!/QPb'Sqfm:)qotY+lC,FR %2V;4`ENtAX/G1U'Tt\LDO&4eEj'(;MI>_s)>MdPCXW\gu]XM %o/t-9l`Pl0;;L!83qr?ekm0r7C %kJu%pa6`dZXB`'6Akc\'=?_GZEehia/KW*SA%?h8(Q[[1*gj=PMiPXgr(&k]99$^eYf&,bbc7U`Ps0Zhe(["$\G[(0]IgW"d2m6lJILCQ_I"Y#A=%2MgRW1eI+)Ko1#`l]j=6tZIW]`*ri>@SPH-dY/W606YqnP2 %"_3;BZP]/IA(+n'6I(cQg\t"Jqu$$Vm9OWXosc7V?Q>?Jk#IpWP[EPj3kD2lB'&gM*-IQW+D7km+Rop*:WH.,G6kYbcqf(Mq/X'?4Ln=DSe3m:*>+/@LIV %VV@m,]b0#<`B>^M%QN#Ue&ugViEOkfG0osR7PYi'@Y@l88P;\T_sd@QVW?&o%UW-)T3ft!4SE9.9hSsbbFQZ8LXY,;776q8R=DsQ,0cMOk%=k&c$%t)XeeD:+$P'5]*1U;3I^#ZY3.aR0g,_Af>P3o68GM5uXSA%6mcCRIDT41*FoHhbF;?f^nMTZK^Ng8E7%DkjE+[@CL1L)uJn;7k/EGXi,?LG %&/IpS(.k36G:`hOVS6.6[R>aQ/-/tr'GjEXG+?HZ$$_12/=(f>d"?43k!W<&>0r:D5p'u>:2`o\rciiT,K,t`g9_[EpC"1coI2"T %?@)$$CgWPapT7L^e\UCj,N#,@3rA %hBeWh(2Bb[S]W2B?uq&!gZo_noD01K^Y;aek)es@2qOBPD?71lKj<'&'Zu0L]P8m[3BVejKX+QDGn.I&r(8B`@PR]EkF:p)?PL01 %4gWhe(O_[G%W8KU,4Godp#\18LG9lHhdqRfMRD+2aZO`A-=4'FE-\*5`X2WK7c^%\NEpUa'gQ\kfJ7"@I+'WI5Oqu!Yd %02>:Bn^S\3Y!8MJT&9P>?ZQX/T5K.Iou8sKHhj>g=g+62m05k1SXK^+Z*aN.3"3`R.fBENE\0s\=Dbj0kM!.4d(LPDKGb7d(Da'\]T$:Nb %fQrkm^=mJ]Md:U3IYTH/K]R(HB:/j"boM18I^^W)2t\$b)\l8BRg!\:/LnTZhu*B3p!q_8WGD0b/JPg-P4OCLeLq\pj`Mi77:97$ %Q@9>$o$,rUM<0^"X?Q"HkXGJS%)+q2KC=bsm-cDcd;;(SH25+:bu;C#n(^^pD5HUnO1UkQ;qKd7lSDYY5@/sEb]XM50,&[W;4R2` %qsO'[PFM0u+"tt&Pdb"Eg$;SeKpTKme@1^0bs7Y5j^etOB"""tc"7(d.pH-/CU18%Z(`kSE,EWU49KB %NFa;WLe5@t$C/eE6Q=jm9=:&**m!G7l"Y8Lpf8&:]r1XtF[&mI`^Sl_1XJkMD)7mB>%[B*0,/LgJLF-Rhe(gH>@QnLdCmHjnC1E=GBhaE1M,uEq#YP<`(C+&Gg)gM3`cZhg#&SW', %n\?+7pCCmq^HK>W*>?;uSE9.[pG:*7Wss8bDmO-sQheC.>3:RZY?-29o@<)4G).W\!DGP1HYW#OimR92>^B7PdVkI'*PPR1!icrr %8c%&.PH.J$Ae[Vi*h7[m;#/Z\%NZlWD7'L;8+K>/i*nkEfi\h>K'MZ[Mk@CHn\C'j`8s-^>i'N1rh(&tIe!+"[JK;M=7>Iu,6797 %qS?EZb(SDh#@rrqbX10+Uk8s)>EEp\+@\I"(aL?bKBb?^H9Bri^O*809f-/-E5'+uK%5^.3L/Icqf%Wj_RBG/fqbli/5r;5$SZhG5SHNQJCHkGd.Ma"RLb?MT#M,/k3pIXU<`s!U!*kYGIk5j#:W*3X>=E8 %*&#JcSm(H7;qR:SOFA>;jRr)'[ %lVH$/Z31j.E;BQ.J:t6&KI97NEX2;aHid.?S*MfTk]24hIp>hbT]HCEosbF7?sO]?^0k7B.Hc"q8dcJ@QSTs>`OciSqf6P]NH4>! %XAV-IL9%dA-]PeDRPJ5]Ua1ZR_:$bNm>Xlj;TK')#QQsPKga!e$S^apl3N>4(])Xj'LE!X?$9["H8m:Aq!]ba"E<$!S>oC`=;,.I %:NS+K^)$i6ZkZK!^nC9ap0f5CCBqX!F$K]gP?_[p)7lJB+mIH[&"Q-r.>4VfD./sA;FSeD %J>FdZ-U\2'b/jp7U7o_jAYDf(i"uH[JAWb.GeEhBZV`=\E?nDXr"pH&%V.D.kqh8V+itJ!K65O&+jV4O1JBJ6c"r%QkD(H?&:Nc8 %1`I;8:)6:.Ng6PFA3:lcmDo-Ds"\DjnD.CBt4JHg?67Y)Ci#u.g!c9QM7+QsqX,CT,kBF0@9l\X8S7*k+sL_'.*lVSTd6AgA5V`,Gn=!fC$&a5(36)7c8 %&QW-dfcQKLas).c89bGXQ$,=B+WX2`d2*!UlBnIQ0H]Vf[SaRs>,1R-^H;AmS]((@r`GEF?iKF"'\W5-5MVdA5l.XCJBM-#?PT)h7I_onW:E/W`[G1@ %+LIt$m6cI`+ISL/r;EEu+)l;KB?Sm=6t:hr;/P:m")6R90a#`l\O5@Lmd"paHn@mr:2C*)Vj=SjbVRma[3f&5sXOt)p_9)Z2t@BLdV`P2qEY)&_cQlRJB$Q6.reZM=V[r %K#6LTq8pS7Kh&r$RDG4o)!],+qj3_eCSK4dS&hpG+dTQR4BXE@Bo+Tm3MaIgh$2Om4ABAT/8s'[#@J,SFPV2Y&`Dd4&dX,N)=9E) %o3E(_'64cEqS5(NhGl+<`h*Z4k(q?"G4B-q(&,hc!r^`o#PTKZipg#0`#FttanlY)E;PaA(\,)n?Fm,Od3;4tEi">.i<&-77qQ%0 %f?4D`+p^hBUd$(q&Rb73>eXMb,ZEA)/V0K.gnise)]=b23M)GXnibDmBq$kP'e*m.dD]k;.\sd,b9>7(h'#B23j?tQbGIgo8BO9q %Y?4Ob/pHrj1(%RjNqk\V'AO18#/11%5$%SN.MYp\mDrl0pSeR`X<->.&HKZQ!GLeHZJLZ"K(BP'&cq++,C4?dWBS0_W*MYjafsJ_tKLiSGBICM.eH%^*k"P %/tPQ_l,>hRjO?i#Su2pkf;:T[S.Wr,9G;n,^`m[]Oe.3Q17BZV#7IHM45Q>m).//$\VV+AY&PoukE.:Q4U?aF\2V4L4.io$e>)]tE %:V@$6EGlQ#.\?@.=iG%eifkCdIh_\#9sLJoTQ%tR%IOo:\$d/UiVk8\.92KDn#D3,,+dej*lZcXrC;^ROp[A4g!_3'V%]U/4)PeC %/"Ps0!^V`>A9`-F<8ojZqit"O\j7XA]bW=>Egt'G8bLG2LjH8F+9RF;Wq.@>&G%NT8'"Uu*=B<;c$$+(+fE2ZmPH_1BO]%gZ/`^2 %^Fb?/2l$4^=S]:r6[F@2<2-g1rtbT5Q3p,N(0g6Kj^flQ1$#>_X=RPp"hhL6$ku_hb"$4TVs-XDN,*AU\qWh5m$!_\W;nIp7R\]6 %RK86bP\]<9oY^hTLP9b'2#mY&EM(sW.,,$=em0liZ6+]Hm8`2%N;mTTU@#YXPT^Za:U96FR-'LAF=pMmn/;,i8$O#_VOk(9=]Q_TbN#:[S;jX]bT6u.X*oEYUcZUP3U]aX#of[;[Q'@=o;+c_,=MF8C2D<3gPd4mP&U!fZCg9UdoN:>Km!\0.eG %>-]e"cS13UN %ROGHaZs2<+W'bare6_0\9YO92mTR25hWJ'\fu=G"@.l_c %ct515.@sIhq8iQ5/Gn[.\Y;)U`'][.MGiA'FYTbbVkn*nHXjk].\;oW3/MO5=4N!m,*W/&PHQmSSJVQ[!CFeHYr#oW\ROP-"JDZ^ %UIf0-+JH;Sb!O"8Z71%h7=g<3#B&i/.3R`JX;,ehb*L;K=ZP5!Z=$^$"i_LUj65f%/;@-`W".I7=tURM]8l1NRc@C?fTkK#5r2KHbM`s@3Z6\XeA6OesFqBK7pKq+K;uIr!GRm %=_)i`HC"/HaINlW3HbEW4gI[*qH&fl24_/Cn^dd:-JuM?Aue6q>`K4\;hn0`EZ$R87RV3g7G"tEcRj_`GQ)A+GphIpdYa'!OA/2o5JK>ORrT+rJ*sCMF?Adf`5)qn>Ma![ucCik'2a$@IH5?:R:)5 %[\P*.OkFta5,`&4\T+Z8o\qm=9h!a[\`j,s?nX!)g1HXsn5t*u,pH4l.%k>YW7,;#U%"$U,_4r!-X'\l?/p*E)B^u?>Cp.BM8I@8Rb*'X#uLoYlq[t9+3A!6-LP# %)mQF\heY7R0#T5<,TF\<&Ouu0k+$*_`'K1^$3Dobl%s!58OQV$h-]soP2IV"jc7sSEfMU:NEi_r8'5OajIg(]jnrj5+H\P^F!P&= %SROkU@h.%UiuNhEFD>#qk,W!llOO%:lssdAhP];Q?K]"^^Y7EI;j%<*4/`;p!^HTh3Kis_ %-_\8/mPA,7EqB<[q$pl9O>]G\>lqZApLRdQ*2a)54-816e&MrE3-W^ng(neni)28EPVLk_rjR*dq!Qa@hqS]u&AS!8EKE:NTC8=; %lH/4ipNrN]4Sa61GDWU)s&iNRsKd:%;EWY.!YouYR3:k]Qaq09,i7*NB!!,DB`].BL %\&d.?eU[c(T,eGHJJ"-d0Y$Nig/c$76=:50/DLeaON6]I_t?\AQHjIBgo]RR2/6Psk$Y`BU&TikRYMbrMl/73*X&+S]Wr@3Ybek` %@HW0L#'9ph(>"<$=k%?0PJ]DRfjm)*3b(L6dbVFI!JBZL&@t:pffI!p_COpnlVL+R\=AT2,4Va:+Hmo`87e->JKUI"6)%A+#.RtO %;'t?)]#7Z3LAjc`G=DQB7;DcKX#?LLdga1?u8J\!bPIpYsn@FXQBN#X!j?8 %in2YKlD4NX#JW?]SmWmOsdY&WXHJ:R. %#-"m]rDl"k@Xq[HErcLrmeM*b!6./DNuTc_OBGZ_J.%d1OS"E)E6iL2%JM:+%ts-,.[Vn)6RuRmL[0l1IEX$9M?9Q-%8'AIlI@i1 %MapH^J2hZqdu"]gB3Z=)+nQY=#:Tj&S.0gB^bM9?h7:BT,k`GqDA,!mVDL;t!`$S8*2*IW41a[-(VZ`O[8Z\tGrXn#AFcCiTUUC.!60_[DFBY1qeQbJ`E#tgG*%(\p5M\W*;CtO*WKJC?ejC0bRpcdk`@$(+0AS,Z!Q(d:jkfLj[oN %a_A`DOn]DcqRCV*+l'C#cBB%X^I8O@a;5[\JFgqF:=hq=Tu<,M<)/>F?Mfb#K<%!<'b.H3je/n(r@QA5Ei`fDLL\:@&NGc+_D_=D %Ii+tZHh4L]aq:65YiDl7O3&!B,m`2WCIhlf=Dcu&(=JgT-hp!'#B?S>86^t^p7\n@:c(?BM8="#"?-Y:Oti=Z1DC)<#7i'q%!(L+&sW)VL;$8Q.[-Y^Qo5YdCS: %2A.;<5oSjR0UUppU#?jp/Hn9T!q(rMdLOcbXJ`a8euC&q.*'OTbenh!Uns$NF..8rZ5;Frc8Cu^ %m[T3B]9@XI#IqoJ:;o,q@cZb!&@'fUl%rI]-i=76$NUGaj3l*3.7c%he6TG'ckPj74s&U"?o#iU8-B-oJd\Q*Km(,Ws$S(eE'qDh %%%E5Z*mTs2Ir"PqTs&AG/t?pWL\ijoDL>"5sOF.c#[A;`\6X!fONd^]pmN`s:(K%;e-,"U8tMJ-JP:D?Y:@CTKWprWiEXH8uV%E^r/ %)"r)+e$e0aQO/m",e2(J+RB'_Pf!qQL]pj"<#($#K!kPOLgh'JH)I %'e=AQT<]:B42s#YA\@h(Si3A^3P,mS$6q5IP&km7%"^/"ADEo8>1;7=1<80g4fnp!(Q8Uc(QJM?P3Z6E#\.Tq,Z](%jV`$4p,e=, %]&jGEeKnoj9^2QJ.V'[&Q@O/Ug78X9BINhUPQ9r^?nS>8&'1g$nM6<+/p;&_R %PZ!`]?B#"T+E\ePH>"h9*.^\O[&eF9/.G,`Vsf:-(s1q'>E6p\e*W[2;Ct29lPZjWN"7Is:%=D5$AB'_SHZi;[5LA:MBe?IPD=mS %I>X2"f:e&^CRpCn.BOSch<&DQ7iCRnTNS++)V@X!d_IBXC&B,4Qo^F$'3(Y7r5nnG,9ncEKB+`bd=3HhMgY,E?>lC4.ne*Kt"rOJ]JE0gHZ*20ZpAhMqj$dlMR\4YN+V.oYSrN#SrSH`_D2&"BD/i*a>6[G#SIOaXHMQK %QM;gFg:k0$SqoHn,X]4?b)J/e]m>=@ %.@7CX9^?9X"B`>2')('j?)/'q:FU<=&eh5T^]O->9O(#',Z&c"LkJGO-A_#K6r+HWWgJk>d>(RD5XHq($Uf1U6D9m?5m05Eg*.gZ %TU#R12CnK9:1XsL8lQZ7.8N5:-4nWL7E`jKbb%ERj6AS?a*QQYU>ucWV#m1I'[;J.!7&Al.u4Oa+:A@EaooaHXcQq`":I:[jd1D@ %*AV;FLHR',\De85d6Q&+e8A)Ood7.]1(X\fi2crnTk4lNBn5a\+[IQEe^=_cFkXkO5Eas\`tgn>1&$_\IO%5RO"Gf+dE`eF4fs.N %r40"Z,fL>q-DB$%WI7`)8n-X!?i*A\`ueO_kXbLGj(][d8D2&65!!-_n`\[s@M=34mA&COqV"Gs)>W*rO,fU>5IgELUb"X6p5s1I %UMCt%P_[<15*?dG](SuqpNTC!,=tm\D!`IX301+g,e*J5[?#&gT:0`ikh8N>U&C),8'K#YpmNW+r*f4%oYm#',`30!YK""6Zf6po?>7&o18AX%C]ap/WGUjXbO"GU',_k,F'tffF %m7.r)4_!1(UC5p"Z#0!5K"#Wnn#HV1CBonPG^IAPh$4b/4aK$e*a8&6[dMNHDel"/7HcnIi2t5]d04H"miPR!p?5eCU(8o%/,/1g %"`NMR5.][SOGuaG]KHn6mNW+r*f4%oOTfZa`2`^eK""8=KLJ#+i9cYoFWXlXG,^_1<(^7B,qP;oQ:_H.DCh%cQ:_HVV1cH1,mp*-P+uJ0/O0VlYLNk$d@;['A8pO":f8KO%IQ\n#siN+o6a[rE_jNUpg:^]m*3X;q(B%4lRbu85F=ooWs89H$9o$#2]Od%F!@a93#ShfcY.[ir`ElQ+# %oT-r;+Mg7JTg**5Tachc0-]&R%D$N.A>LmZUBNF&fYLsL=bPsQ'em;M`H2@Xp3VTk-[o<6?]@aA %7"8-`l&]Mq2C:$?qiK^%R%Gle"BXM14)^4@%;cR(j!4Rold\6eM6>eD[X-X_QXsiO20,hr72]IogO96`UV\CrAf4YpQJ8i7\Ik%t %oE:+!oC:Ja0V@S>eS),:!U&>u5]nmq8``.ToQ)QA@$M@n:6pS@'M#21frqb_N9aep&l`bm@lO*J\X[/nhlXWT39?]4)kQFs)`T"J'rrrrd6%8$D %@.b.21/m)]POt9Bclg;teDe&=BMeS`]c:@q!EOm:2G:`(WRdZZ9S8T7Q)U*?;l,hpdNFGkG?#QWH`KRJWK!Qc+U4e8I>nsO-+!Yf %+k?^W6&G`RH4a^?PPU0BCokV>c+$2E[8@p;ZC.Y2=?#&\W!6u,Zn5N$6#\hZLG!.%FpQM4Wf>Ou(e#thGcRpa8Vnl$'8Qc:*5brA %BuW>T7,]O;^g$u:a*'#NWT:KI,oSqiW`ZFQ=6jj-g9Wukj@M2SkF7t`Rl@FKh0rElq3RUTo<+1eAr;) %Rc_]jd2G\Nc@Va'.Mc,4f`I@_:>+\Veq;75]!c:QTrOcR$G=sac#bO#n!_UUARi:9P$eDnQpm6k'!kG,FV-u<3gB;9$\@NW25=p: %%S(`F't?DU-N\eSR#aLS)"aq-gLC1UldoK7>jF:CQSiiQVHWm#fsJJ#lk*Rj*D7.(a] %IYZhj4flmn^',d*KLg6+-4L'ejUtadYiXj.bUsFpm'>Y>dUc/$=Hf0H-W]%)f>OC.^T;a[,noQ'p_;>*JY_@f)lf\;dORH8m*./6tMR;0][6Suuj]>uQcE %FmuKSUoj$QPs_%qj5JfWerB(.h1uH-1J4,dK#dp`FBPsl;-Pl@KjMNF;JKHBWRlg=?(iis6?MrG7LP"7n4b$\'TfCU#YuWWd&;J& %cXhk48UYl5;d;[RH(r7&1.p>c+NjR\cuL>pKpW*1KRO/[d-r2m^9:]D?;fd<3#4SZ?=P.LC>k]<.LV.CQl+Yr@2m %:0c4VRK--!'/YfE;IQ/K%32eVVN%Ahk\Cq=R@:@7A.mdkf:522RCldA$t'e5RebHZ-=%#;\+-`/(=pX3"Xf0";cS5t:4D>kZ1[X!ZNH %i;e9q7F/+nL7!S>[tV+oZTC@`]42Bi;po1%)\F#@4qo7Uk^e7WM7!U'.hX@b7TZaT+t&>ONf&^em9>,h=M-3iF!mW[iTakp<`@,g %R+h;plP?4Bhuke?)T`V3ZC+u;+]VT_cAGm?\jkG=[O*GCK6S"o*>a:%BG$PP9 %B(^IpBE'O<]lupI^rK#:gD8tX@#kEP6B6]Ig!1lR%"dl-EJuplYEs88[&'35m;#Ur9bE/Z=kTtk(7#WbQ %07-`A!Yb(S"\2_^9W1e0Y!u %m%A47?uAS7:.di(+hJtgaX2U>eG?GD>M#X>$ncuQL(8R_^tibk8DU_]3=T3FVVekBlT1$S#op)'.c*KG[l]j%>M)6rJo*Ws;YqnC %bIZeYh%!nV9L!7Uf(J5RK8WNqTu.X(E4=OZ<4=MtJ-Pd/LQdfJg,&`Y %[=63L-6%Hi+SBDO^]!s;X+q^(&W%(:O\Aije6o&`j:19O6ni0VW0*4"@u/j7kDh3nq_i5%B:-_ZX&R! %c!WP!-1?6hcqn3*fR]k34Y99Z1<(P!"f)-bU7t-h^7VbL;li@$C_*n;qc^a!)KlAR?+*<3)lIpQe=?lF-^rc?\gs&fE*EKPQqGR\8=fWG( %YijFU:io5I#:#57A7,9-?d;D!rbun)F8kXV%LYDR5G-`fT&!Z5D_KC3cb;P*\N%A#iHI6Dn,K#dT;^&ADUkDVnR%/_n`fc0"@i@U %:ER+iFQrhpqYFZ7q4"FKmk;t8p\FacfdCNGEHNBtSp,1i012-SO&@@=Ib*4UB&+OSN6A*%Tm7 %Pol,CGj6_3Ar9?hK+1oc2_$7$hY.!t?m"mQcMED"+N3fQJ %8`21oc%%X!]hV9aKV_]V;JASMkZ@P5EQP[sP[okt45_!1r*Jc`+NRm,Pr90J78UHNUQW,Q:q0^eKb,Xueo!Ou!Dc\GF4;l26*YM2 %+nX[tl@Rl_L0'^eNuFZ,E7J2>74b:'EQ78.cXiL1)?\^=#lk>#8hcV(%+[16btLarC,J+P-7Q`?`ac0rd(\Y0c=)qE9.ee[="([d %!Gt95G>eTVlF(f9\TEBC?e/T"b/iFhO;0b$Xs5SOWh8A-fW#0'Nn'G+)\.dD4]Y[u.h$+cV#kI]b,+gUWI?V0dBUGFXTCZ1RTm\0 %qVLF[_*B;ZI#mg'a?*!u/3fL:;D8WX-738C+!bS)'8+GU$/U-aLMDAXM?i'Hp]g7S.!E-"rN^lU)M#g9&"h_U.?kJMK@SrFUIRIp %n>KFj,j*r#])L"3=,p)sST20EpYAk#Gg-a6g]!M5!9_J%.$ZBdc!1K*Z/aMX=r8.QD9&d>G6sVbPU5*B"!8V?bdJ!]m`+?M3S_Yp %c?L/IH^=B:e_f]Y"tq4PrWesGbW9tiiXV2/pd0fAH3%#$LVqlAfGuZIG*iKt!cQ&roj9sT.Fe(U&8^JGLNCMOHs/bef"_,?PdrZ9H4ZQ'[S,lj_s4Hhq %8gD`.i5g\7(`?]>JDKSu#=sNil^Dc)GY0#9[EdfV\F93'dgh=@'$J#ubR %rFXG.?UV6-=M^ulEXrIn=C0*X3G3Tud"\p)KN!W\0e)(G--7inR1#!,*8A0*R>[O0oP17""u?i7?:Jaj>f(t?[SEXLog7u%bUU<> %JBYTcO*Es$Vb!pB6M/4P;Cb5f")b:W.H+]8SYjgF6n@-e#s>El!AL;(3bsttfqVr3&ua1VFHYr1nnN,9P5V+C?f3/`Ta)YM?piI" %]6B@$\I1HA!RWSbXE:P^&d#qAD=8*3-FZPjN_(%m:t0=rLc'L/mhCTJAWVL(Pa4>PQ-RLun?tgW'6+joq7nWNs"n-JQpDF8fU.F) %*YWT9c1?b-&_!0t:H1s8I=^A[U*d5pYUWU0BV7jO7OYp^98Vg6\4;B\hfStu-u-BBfQ1r\":U\E)o-n;>ZZ0_G29k(c7:)9TtW;? %CK;m:=!u[U`OBmZb%/*F(SsXY^a\PKMCW!))nQFtB<_Ye^LG!'VOgaAGYk5V-RheDUBc13q^70"g4+^V$=dB/#GSK"7\*;rX5hnPuY$*%M=.^$,7q#j$Kg%6k\UOX7k&+D`a%Xe'@JY1?_A8>&ZdIgK"fTfs3 %H@*=]CA%K'Q/3eZ]EZtd"cnZjGSFh&bfTU'Jf!%fF)./`B-2"-f@/`*=u=Jmdp--RMsG'^>Ye1hQSN0`AqO)g:^5g*#;u7#!(5HF %qO`d:#`9e\"#eCFdIja[$Lcb;jo"/(R6@[q8OH\)*`VM/-dCSdnM4bb<.8BM38pLIL/3FGS,VVmHH;b7%j'5."kdqZT0`BToV)DI %JN8(D'Dh];a%-u<'A08F"P&Xd:`$VqV^Dkt%W %(Z!jhH]6Rh%_AshDZ/]nAp,Qs?=i%TFFg'P.e&er++@I:JOLAWFFcjs=EK*_(YAao^qujB=?_V]o,7aM]UK2o*OM11].VZd8"B_V %#:[ >X^ %f#7cnmK65fl]j@%qLFMYl2r':n&cMK'CGirGK$cA.u"O["dI&>%3eIa:@s)pi'e`4?@CaM*uAKr;$IeI?r7+DARJ@>G!Hpa/bC'! %+C>W*%+"%s=CmgaKpR*6e8:A%'F+fs6qFRhWbAf[R&=E^!R!<[f1tc0;Gt/1c1,2hg]S_MA>H"1?UER.'CX%6fehc)6HY$+jXn\h %ciq!:`jb$/.UZ_]_p"eqAtTr"VVk!fg@#-U2.1\$cZC!iNtJOM%UJ_R2BF3"X?\MjKsEao`m]))l9P*QQAu"Q-JGOPV]U$jFN?OX %qf`9ikQA+iX/p)6P`iGi)'QV@g<3Gi:e8]JP;^`"#*Z! %nHP[RN*&*TFbm4p)Q\\N#-U9Clf^,f6/TJu#VJe2`&)Spg2fStYQg=PFc\NSemZ&/2L#BHXl$$G;#TrbH:#Yc>@8g:oMi#=p`*3bY53fh*! %J@Q4=kn"%@DrMa=38`r(32V34'1,,)kL0EpB3IAf_&&.CV7,fbriKBn(C!X^`AH6MD?7J5f678i`R\fn@s'Js;1l6$\*gg2G*bgO %8*foJZ(:F)eIj=3cHd6TG9a=DUI*l>N/3P-Zjm+,A6Xd-=*Ji#T64f*E-0t'T2p"!Q\ %a>Nk%9!EQ4*fr/,5P45m40Y#&HpKd=W#XlPCGsMhG$s+3g%u@b^V5n(A]%\IZIuW6nBuqmaW2g[9i.Z67!]Rm]%G2`c9$:s*Zp.X %oH(WR%rXk2.X1p%nEMkn&ln/5K*OMd`.2M$#2+,cOM8L?j+8ki:s@!g_P5M;/#QJ'PrSsW]O(QJ];!-hhlr1n4NDKq6h/D&0[%mU %n8#7>r;&&0p;_I)lh6IXQ$HQlWc/A>Di^qG=*`dKM@$)cM"5(V#HT,75R]hu@I.=XQbaJCg1]t;d\WV40XEZ3L8*,6p^N#_?7L%&?L8GPa[YC/I47UH1C'c6_9D+p8YapHA77pKKm1k_4>mu`d.rYC7tXUo:(iO-2Y,g:7YW:? %`#eQhdSbi8qS5$eacLaBc`+MP8eGHcVai3UYihR^@KmU(msB[epaL*b-%FpXg06]W&SQ[nq0h@La$"*S^=WAfL.gNo&`oligq %4Jr#'e(jBjn4jG%XID)\X\LR#UcKN@?/F68fOeD4.7fTnef29j1sVO4j/`PfKck\UJA26O>E5TkciNG]ei/69FB`[hWp+u6d$Oob %Vr6%Oc\ABBr]pK+\oo#&D\9ho]pEkHHpLiLZiu3,i&<>]o44U#fic^DdX\n#iW34qEc1ZB,9*/T2&!(S#8O+;iUkskNH)L8"iD/" %iNoQ?e/EDO@#KE(44\JHl %E]k+f(0H^ajRF1n"/Ec,"3N>t#eg`+,%5ARROP3aiqQnP)nH+@q][*tou`>4_0nh&Z`_aaCa`+'h%XX[rF/gZIC+Gbk1@TQ%n;:` %;NT*.!2&NB3sUpWb9D@"uTMS(Zne@03P>UPCp6-=Y"g/oQ^?/UE4:;+#DP$0*a1QV1KG=b,pW5o)5-;mFS3+djib[ %4o+:6c2$a+GQ*Y0pj8#;.)@gAkS5@l@?4ZMnA[4eM$+7&6Kg"a(BC2c)N1m\Kn0_1&cuf`8@/smLg7`e4G3P'U_LKI&$AO/T+I*V %#tkCg;V%M4WXg(*[,=0\"_4E2VT!n:p<,d'kk-^U7;N#.5IaPMY`)SGVVi;Oi\m&sl&?i-)nuijRj7dui'RcUl'DK>Uk$7hE.%X: %a#MnNUln0WJbr?NS.Ui)(n`06DDT_+PkI7Q10`>IP[cq%2gQTdIna;-hZAA!q;)SG`ed*-H6hooDotTct(L %C*;t8XrY=d>\rn`+@lXO9CDT''0N9$.MOI0M?l,TEZ$6,.h1TC;k'b89@kI*,*.$i\o"/AknKfK,XoRlD'MLX&.D5i"O!7#@mfCV %rB,=J1e6j\H.X$mV,=pAm/4RX%*I%qoj>I^$)+(mHW##Wa]83+9%.=AXAcK.jEkdUB %54qM-kQ"#$aJ[79+/?l4]YJH#elD2]lUnc!lCRW8\a8QaFH``/Ie#!NH:j5qJs3'&KR4OoM*KBg6hhFCk9I2kU)3=_#!KmG>+)J- %'saJ8P/[P^5oq+$PgYLRGYh%Ul:.Q)BF2u9%Lc63:L2A&b@'h(UHH=uB1/&.7L`S^+/or*s042dn"FXE3*HnL %RGLM\p6rpZZ3ofH1b.0LP_CJ+O&s-I=c_-&*)'<0INL\ko4c9n`#Y/b)!>E'P!\7"\/I$0VGU-;' %ONV%u3j9+\?aYWL/(U&E29E\AYP=V=:(&MBCc=S_%PQq043XFnEfT2GYS\Wk3oemGM\l5SV9`-,E+9sg53;&Xc*+&qIQY-em?kArl9uR4[ %9Lp#h3:n$g8ZIHcUC3/A(@#k6jf`H(:gmK^X*n-F2qN$Z"g*]/<"K_=nO^`Lt(Y.Mm.YV._aaFRR=X-c&]=LbCA@J %^A$qX?JkbDm.C/:I@2;=lC&T)$NUE"(,!I+,+%Nc*ZTV,qqpoFs8(^Nk*#_^aB2:3rUonthgPJ#r*>`;\$nS-S:0"d1"a2tfLEkT %1n-CCl@gZ[+8nZb`KRq\4LQFE`#o3l16f*4TR]OuatKMXJE2.Z_P?Un71d`N(g)F=,\BTF#%ZtUE;Z2u>KXBmi\D'>X,!8bE#>tb %G;H=Kp1kOHI'g0aZ^f>b;'`-hc@N;-<%LZQ1q99:XouFjQra2V==_-?^W_`(d%eCkOs6B#iLLPG"F=71PaqutNtt'6rau\9)X;hf %ff%H(,MGo3^.[*CCW7C7hoSiU$$p<%gdRDV0.A<;Ue%8EpY_b!@s*3g.0VSf#G"X$#Fh_jBeOCGmk@%WmNh%RO41#L-?Q8LHg2GK"H4OC8]ce@o==S %?t*C%WV0'@R^u6qf)MRZ!d8#<4N@g!0/D"f;L7YfO(Fr)+!'*=d/7rF!HXPDXfg3#8JF_um\6F`q$nf7M%65Q/U4I`:1LIJ0R!`" %#0n,B>lEO+/(g:G3Lne3"=Rn+`F$3bF^9F!.spc^BAn_'!r3^5?%RR*;jDogpPh]cF$eDmSo"S@C54Tai>nPi''j)$SE^:m94fkt %Cg%*2:>1\uG!HsPb_Q[].[;QDf051f7g+V+"XqB3Snd.`f$sFS=o=U-JVSU^a3RE#00E%*9H0q.;PTUni/K\9XrW>-]:;,LAUfe1 %8ZBKY:E+c)WW3-i<\%!AUhl9d[*A4mb1LJ3dKJild:-GVmOWQA\_[f'ZNYL=Ne@`D8a0KNV_r/8eKBGnmO(B^Zf %3(k%5,&jb\W'N#3JF*SfL4MHQKaB%4Lp3:F8K3`s"9b"#8QuF#^bk;`"7cSnK*DO'c]5ooCQPL5IKg2p8!qN/CKm.U3aLEh04u%) %b=F@oTO5]qnjrL/EJT]"apXL`?'GCK(Z\2M%>CPCUK8Nf16?=:4\=Z&KSK.?:l#=%o7sc_#1@_/coJH,oCk?LH>[&5[bq03g)#2KkHRPIPD'9Sp\NN+D;DX$7\uI%i>kQ'+rWD@)s*V %nST,07Fr^`>r%Fk3^pK%g)q,aMQgJE=dZuf9%'5hPa@0R%[,VT7rWceC6b\^>Gk0s,^au$">bid,el!,oOT,ZZTWL],Qq^+gjNHD43IpN)Od7CE6h7\$<cQH=ef!Q:7DJ^NFMJOE89Z1# %OW:'GPT>V+;dOP-'rHoX;[F>i[_PnDfq/aM4H](ZPGe&/qm?aJp&M0rAon[#:k1G29PFjpaV5M7b(PiSl#84+?#_Ef@S&;lI#rc: %p9;2[nsc[8;^@8mjJ&QJK&_lbrAGr;!/q&`!&82]'")akaODjDSP)GNOVSr`@&,.OPLS#I)FJ\a('.KJ5r;)GftkcB4HAhpWb9D/ %gh"=s?W=`^AA%9:!D?b0r+1Y++ZnKZ=,aUCW0pfnCSl^#t5d6'fnXl98X;JR,"/!27UYHFF1I# %ZSG=Q1B/@Y@+K->$"Q*Aaa>NPg2KIA9#8CXJ?;uiS:H5dcU*RI4p;SD %CD3I&)ZS`A7B*!GC:3)r!li$TWYfL\p4`k',IpF1ggqQQA5F`'"uqdS&/3))$DB\91;7Io9VG*f5_]L!*/#T7[+@CfO8Vs@&k]e\On %]]O"i$RQINf+*Hg"-J2s;T$UZ\<.Y.HnbNF)7U4kLj=^hRsdgF"YR(VSH7/k6m%#G*0RLno;1sCLc$PX_F2p-VEjkr90m]>!WaI) %&\'rZoZodQ1tYWiT(gD+ZdGD1;X7;i"2Z(!&.K&D&k.L;8^\`Xa;WR.F51tVOV"P:UF.+<2a_!XPn]GN=;^h\r7p2]jV;(5KV %KF/_K9/dDAl3lSC@/a=-g'/+/0c_QP6Wjd>#(_]@W+)TMaEH%u5$^*$Wa\fR)7#4[lntI!RSReVl9`%o+ouH8PUS^CHY/-FSB>3= %MVWJ7*Zc3'78b\+OsArAo12,)J3DmL.1l%-5^>+]p)V#g,_"$sBTp@UVc@8]`n;d9Fa.o1ni#cFeIS_`gK1aX'*%!jJ0cHYGV-`> %Ql^pr(*6[j'7S[:A.uE*W5(.=<;42M>JF'h5EdNeii*="U&&Efj7Mh)"^7iuY&A'%-%lgl%na]0$TKD';a]mr@.p&DU4nB,ZOdk/ %p*Z;!Afj9Knm`q9.$cj@PYeD<&FAGqQo-mT7ghEhBF:%7"(O@dp<)n>,&3!#@>LZH#7Jh)%Fu)rr.*mT%p!+3B*NZ4B3VM\edpTW %m&#lD!]VIc>,!s0%=kNV\hPg)_4[O+XF0@9-I\;N7Fj+o'3u0e&%K"?+J($tWtf\F7:H?ri.V.2d4'm\mR&\gBqeM:luo8S\?i&* %:;fEsfRd1-V(\0YmQ;-r5aDW80;eg7B%B,+Y#Xmq&TR3=au[IYV&DqD9$O)7"jCmR7L7G_4uuEg(aI2EZ7E\3SmR^ba@KNT1Y=3rtFqA*CNSA(>s#u&<3;U(;O@h-Y&:m+kR.[agEjHmJYW5O7Yq*N"DR"S]i)uV8rbCMcj,1h8ad3f2C]F"/n0Rj/(-:%)B%H8\$GYn(#2g->`&G$Y\K*Q6UY`7s5"h?\c %.ugG(SJ8/no>Y_gA`tk'JskjrM9^hh9#3f-7DG0_;1UI@q\c=BB"#+@56J7PD^5q+f'dKV4Tnk$!&MR5fa%B$F'kN$'"e>Pb.gPQW@4-EK*'h]bZ6ToP[QoY!erXGFdMR;J$P!Ba %*h4>/Pln6uJC@>9Y0`jB3s1$T&DTSE%mcp?8&,^u((rl_%##,O8'96S"P4t8'"@_BZ06H:^!RaCklNa^X?/+#N=I<(MBjlo=J-jG %Ke&MkAZetJcugF^1?kTV$^_eBk=uh93iQ6_,h'^c(O5@2(DEH8.u^EJ!W`_B36u'kJ]n-X[i54OOIqt>0mU#m;p6(k'hKZ\#<&+; %BX"3@L#([&AG]Zg$2@f#9!ZD%81P3Uc\9*>%`H8BU;L@iZGFA3dNp.uU"`ICSG@BN@AN.1XkG89mT*D:kG=4RkJ3?L%:tA^@QZcAVs#-;Z %=/)@[\0;LG&?Vq1X'R!.#TX4qAJ(WVs!b:1Yf"^g6m2u`Q7Sc$c6?F)Lq;IcR6Y:h/qN4ZhUl$FLmA1<-Vbf4lP#*Hli\O2l3TlT %!=;/?>lrEX#>^LJV"ja[q*h/q[#?ghM9,S3:'Qj&K,jfE_%DF*NUP!l#fQcB%lLlqO]$iaRHa]06O-f %QUMV?AJ)nh=[ZSub9E\9]h&tO!EZR_.+2_O,,/DA=[[7X(/]Iu/0`!:i:;e"Pu=cV-]NooFX<#\de$,ZLo..;FniG27c`0u&c$Q` %6ueRALuQ!&,$F8o7b$nBPGAe1l(*7u7:p;I%.nRS7)k1&0f:A_9-_UFdtmS+1a4/5e@%Dt-u36-oSZC"k\d2o9I$9EN-?P,Lu,I_ %K5!_'cV>^bM1%2.Ln`i*N&2`]Cc8($V0-K?r#59-V\-2#p.<_h6K0q4[l99p;IU*S^tb8GjD.YR=naMG&]OXrLsiqEmn4lD^:ZCa %BZ#dq1nlQm,Ecm:\!9FY^,1fTQ'@\N6uGR@>1/4m1nm'gdJPgF!`.7#4K%oFBgaFl^bX(tXrF_/&mU"Lc&orh<*--o( %RHubo#crtX-IGb(&s;kG75B_l\kJhHhf$dcdd&ZFqu\^211pZ*;^Tnrs0&%dUh`_bQ+))uB+i%#Y5A'HR7&"7^,qNljjRA#7!Hn& %aWu2k9VSaTP:3NU,gu9?M:@tf,0rhJO3T!XYFJ2F^GM-&L_7;C,T70N`AEak&5\EFs;&ie'71p2R_$rt(G&4Q3&cFhTM#Qu4\*J*jT',3:B?Anh %*5e&"aEg2UlPc5oc`B1JZ8>%Q&S6+<`XYPlmlA_%Djo7!g&ZI#ig(0qVC,aJ:6Ss>^&UTAi44#J]2c76=*FY)IQ`Peq]CjupA8b8 %H2cpiq9TtV'&njpbOU_+&fs[f_BF%-N %MBsQnKi<%M)giL_kZn^RLl_m>>K7B?UMJ'mks,e]P/rth`,A/p>$^RDqHZ(Xf+RUB7_>rhOF0Fc7`4q50`I^^"C]7H^*MoZNo#^H %+rgAYaJkL7#M!R.'$Kh_%.PhZ)0d\eQoZpt`WoOYC*lf&EiLQ8X7JJX^Pq3"?9Nt8m2g3J&1-;M&DDeF:GI99oSp7scVA@QIiPEA %B?i&T0(Ke9U1'$N0U0Pp#SnO45I$VU9Fq4E]MtO1OIn>Zb4.G@\`69ATSli'V59ZYkWQil^4-=6-)OtUbRl3fn&Q1I>_nod);Gph %1hjd`T\2i:$5K=b$Oq(+nPc-KS]JT?%rc:3-)^q:A-!5LdM"XKo`i:FeWK%\jlKhLCF0L^]b^rIoKFk:HjI`qae,`nh$_0uH[+W4 %:VZ\m1]IhB!6XtN/1;_4qX]t:I)-,!([KA6rpW@SN*WMHBDTL^SMYMpm]>X`?Z=_Clo+JEbjo[sJp=Z;poYY*,7bM_E>ZD%*LR91 %:bgHshI+3[4m$#P]io.0OWJ91*S2V/]?7r)Q=7H(@]r/iokFDX^b98Ei/#S %bObi^BU^9PJDeHNo<6eZ/Z0E*)JK;a4b;BOn@1S"BT9Yo%c2FHjmhtj@'\eq(jqp'+(NkH;@hPa8'9EJ)0D:@h&dA[EQOr/,CNA< %IOkVb3)3"5)1ugJ'Fu/:OH*H413AbBM5%C',nt[Fb)3UtCc&ll9M];JhAibVZi.a=\J&.Nb#G]?d<"!JjiM1b'&3VpIR>M(eMg/. %:$-P.QHgYU3S`+)Y-,a.];ACmOl$7rO;nU!J:N4;3FE5QSK>%k&g]S4!5X?!I5J$=8%MkL1]0F?kVs7ti\*Vecbq\&+F;oL8UT&+ %T=*:-CsmE<3(]fK.HD)JK)/*DJE77$QAB*8Ab/NPiN-,.ib1K`h#B&]6l=[QU749oln[P7lNL,r2JWDur*$=#'n2Jm.2/G^i-"b& %/;`5Th!FFsrU/h/VhmA_3Qr#,c'B5g\ZMSh(DIT="80=eGluKj:hX]SQjS]X'Tre1&_NP(cX>cfItP1RuD[)'u7qcRI6Q( %Qj,b-ir\m7:X#"U0s;MN*ke)a5R0iTtaH0cP\D.j*smk?TZQnL(!#"U_\WS^]EDC2nNXd!a@Vt78[9'#9XKLcoifPPND %)V.2dQ=8u+(^W_)4sh6]qSY&_4;A]`EO$E,,ff8m/Y3%*KcIGea]Vr3lfZCcA:R`XU,T"5&\gi2$3=SF,I,!r<5gV;WW^ut'IZRF %=s*fclf?#99aMi\/;P!33tnK!K5R"q\UTZCJM'neY;D2SE#ZD@Qm1Y?qal>&?I=r5)*?4=0LHJsjG$7ql6[V1@tP"UDK<[N?h\&\ %LcgK#M$c)Z$'?d+'T,Gd[pOkD$(MG7XOE98;^cn_A@mRM^+,GC\Gu2HM?jdl0[H,i+2]X(AG;,8@lkSFtPm!S=-19_iEie43@EQhSu7m3>t"*POp2Y'4(*!jJM@Dg?QE-.:_*\lm;bX(-ZJFd`" %j8ANkB-;3ljm;pZL`6@mjZ%7s5ts5\%V=if\U,S.dr@'KKh3.3!J%*#F%OF+)9.YXod0E8b42j'37g$>Qoo6*c72LWliV&]gpDFH'][\a+?TBi1"ZtBb;o:EGKXjhg:atafP%]Kooat`#m %pr&+`otW9U*&kE!RD'^Zn_!t4K//u6Hhm_%*1*02+K#RGDh9T8`q.Ds-lF:$_nUD2C`V&skVm9\nC"+Yd/l"KK^8qiS/O0IUTM;? %;(^&8RNtc0oPq!i83\0#5\D[f^Q@Cb&6eUh`c)\_IcBAf%.Z!%NUOXke1h4_25#dH:_">58p&Z/1H@RAY%a[XXaq.mb*"4LP(0[& %1@@[.d?:l\Q(n&oUOHht@*@e&SV7?`+q]J:6?L"RLuR8],;c4M.TF4AP##j'6?QFMr;mFm?V"H&op7gtO[P'uc!KQHLeHYX:,Zcb %l!+4.!eSUdeaS1qq`=YSX;bUf(AbMe^Geme+S*Hj?3E[@?1pON"27L;O)^e[Eph-(9#@$[PZ.^TZH>UJTWTH6Io(SMK&mmE#m$3L_Stu>&X9/Uc,;hhYb#eI+G&X4G2.^BWmP6`i"79h!_5!#=:(s,RY4KS(H?XEj.,so %Kh`R+)><:9YpNBc"oM,6_PXn!*'5sP[&gg02U59c)3j)*b`!L %b=HQq4EAZ`R:COoh3YX+?61S?g`JMi7LpCdi$DU18Cqbocj(ukSEV"JFE\gZfJkXeW16t&MMMlNknr0@\@Md*irFJM`@9GT$C3u^ %iOW9S.o1,T>Z9lei;,Qe:P?rTnS;$nD/^bDHpl<6i`k#((.=-rId;"(n46A]p'b>\,-g8hgZ/';qr[ %g/qds5[kug-Di3X%)'Xp^.3k;OIPTXd.^E\\bo`0EIfP"i!5V;@Gg@=.VN"4'(;mA?P]a[0\"q$_IO;RL]WpK7@U[V\#An10-MW %RRgkt:QHOhE9=)qXsg=ljrB9)qP.(V"H>'JmL8qmonH8r93UVI[)IHL8IKmVq*g9K-3(Qk*"gX+/1"tTVd4>Dp %b!S5H#5t&/[X(,FbY51>[Q=?XT= %l`e67IHls\;)h+,c]0e50eqj9"D^_39E:G>lPZEUWNr,uObXkg%$;2W8lC2j]B=.i6;8aYi/fb?!=V%0tHk+iuUC3>U+/P2C/9\]DV]8pYLhM %j3%DkHNW%*]f4\RdmNSW)H'.93h_c&AO@qT(tbn^EVk5hQOcihPNGX2dG7_L$dL3.l6: %>p(M;C_H)qa:!jkL]*W<.L<<_g=@X5J=>WSnstVdj;:7+8b0eLjDF".@1Jgm9KCa\);$Z1*W$HF7+q9"l:D-(RNU)>Z/n@,BC@*J %eK#V.-(UndmM*?_#!UYc*q#FT-liP>P'rZ.Wcsc1_$NTLWE]!F4Dl*,(1c4E67FsIn&0qd=W8PQ2Mk&/&^lj#O/dgNc_J#R4.[LM$REd$3T=41%FHKf-72E`@*g!IsE91_H+/ea\AL=4FBMHU@\RDSVETp]UD$-d!O0,L'3g%7+s %2*LWJa6b#YD+eD7#/MEo69.M^!c[6RLg1[b)]MntN``E$HHRp23\Pqq6Sa)h"X!dPoBid2>W@4B81FZ&;%h(W$=L %M?Wq%i@oRtkh$.H@[=(MY=rFmUoF5cFL5$M14NQi_0l.>%%\'>0+?o %M'"A8Ma9I5JnO3+GfHcc[u?G8hDU353a550X[6+V8'W\/j.6O=F/'k`>2iTcE/-#bp25,H*4sStNP;!M@J_mi_e]'.-q( %L#bn0OBfmBOt4(6E=jL]>_KVh:i[.g,o>$2;KD;&q7,Jmad-20^]*!dqPhcC?ZI067&G\^6X!)7`B2D4>j".J0"I57r'JNu`U"iU %^V8O,=,lT`[@aQJ*Y7iub#uY!FLN36-,a&&/.UTV^&Kf*lugOGC\m\sYaaonoST6![NN=&Nj]GjCO5,PL0cEC5l$o6Cr!LGXOdh% %aHJN/YJ1!o#+n\\!riTuLt`/7gWMEB,k;=hJ$qLkg:-"Ce)RlmKZjmidLE*kR=Sb^dlW(Hl`16'T,s-?9^1qP/IW9!66p*1G"2Mb %la*p)1E^XZU)cXRhMemN-FW['om?lZo.i?37WP`\dSgcnV55!9Mp %8FQ=]q,PfkE7?o=&/)]r^H=TmN>[k&;\B[1*pQ=J06l8,Ls-DZk(ii`+KF9/O^lK4_+F`JmFTMR`E!O^Y&MFFmW?1cCAl0[I/u'l %3Ksb4Jp$:*[pUb5\'ETs/N8S"f7Z/ZLC=D!>)qE[:4f8B3[KS^@eO%6s'BY@%t!*2Y<`8fohh::QQ;(%Iq>%d_Z:@5.?JiQigKFM %=HH"$[K&@=2Z[]cXn59hk#WnSo$MoDe5, %cHH3];T2>+mC48LoWHSaTW#tL'iuNW^ %j,\E^nW#B]1%`dfE.`^_lU:c3C*=Gds+Hi5;"G?8IR;:TW&aC.<$:\6nDY.-/gUEpp^I0jS"FBc'5`2mbtk],oo>::T3p6$T^h'Z %IpDc0$ib5*5;$3\45rK]n]*`jGfLoppufLo8^Y:6QU^T:#Ze^1'[lSK:DM$ol`4HmMom__C]SndUI4KmC2_:^%KgC%:G)S]*G\^Ymf>4 %FF9Y4IWPW(Y@Ep %?gH5`,[`9K$D,ZAiqOn2p&AG2rKFe6PTZMK^"SItgZ:B:%hT7fV$AZ:4a/9#`$q]QpoE?4E4qe?Ka&@Eqat7"fiNr?B"aUlNgoG@ %oO:djXdGa>n[E=SK.[kq)Pc\-[+`EU'OUVdf>$7?4\&->[EJLe@!g_R:Ds.6" %NW5]e3;aliXGtnJY"t+-N>DQc$_tPq\1i4l&_4q^h.R>FL7`o^5Y"e\M21)'`H\j.c^^'HI`(;ACaQQW/N(h:s+Y#HngGc?;$;3W %'7j'r.J>0_ljJBe&/KpE3`uDDmcA@m;S[d;]23&:s(7#TDcm_%T'!=:b[e>iVP:QZF;MY9N.ebbi*3VIlSZ@8'g-a^*6N`F4qAJH %Q9Y\\i0F!L&U4[#g:KnRY&%9mJ3UYH_ISJ%`'E#_+4c/E(`D7dHc^!Co'LSK4-W$T+=ho($D7o/OCT=X(<#/nHMKMs+d-gr9]uk(,-4S\"$p7#i)UKT$Obkn7%_9*(\*4^kRo-F)9;[6 %O<:pI!Z7TSP/Vu#$ZS93a:b;u$n-'"JW,]a+If\DBL@?ec@Ec#<.fXm@)a26^n=R"M9sX7a:l95P-qNE*sr%_j>ftUA>oQc %"cm7f3)'-.)2-BY2n4>=)@+5a(sWDT+WEg!$XnQ8(#UD_8VD\(AE#m/6tYEl5RLpZ"+g$R'EYKDr")4$E>O-T+upBhiLjmR&-3.* %ih:+N=0#0SO*pYk96s$7q?Z^l6Hl_Ll`eK`*S]",s'D*c[^>RNX.O+LqYq1([E(N8?f"c5ATd![oHFAeH=2PG&Pc %QS=eWN8k0JQl/6o_?!,j@/?YmQ3,rqlj&0H#c@g5Z[@pdD?,YZ^p(r!#Fkp\'i!UO&4[Eh3(tT+DRL)b7RWDXNT20q!s-+!c)O(L/$[RA&*GcG(?CEQEZc>1+s+P@_e9\qS:tdL!#%/9jO-#S).Z^c9g=MVn5t41I__dGEbJ8`mRJUU %q*Q"iR_W6$5C/7!(MJm#F(U%.6\#dhEL?J\(pH>M<9hlj`obW5T)#cL-K6-SkqbQbc$3gX3%"CMtGD*KD3,m5![u/Id %*P777aYTT?@OhV2f9B$[!KFo"F!baVn %]UrbUN?AcOasDQFQmi?s?l6ia4u@;rJImT+i#,p9KR+-u7&_;m7?RQLg.4m=Q%T]#&GK$[7IVpleIp/PF,"?6ZAKtd)<@Vc;N,Z* %&RhI8&qjW3SRKl:M;eLAq*Wus+sk'%!!EiYdG3]./qF2Dkc%)qN.i+`:Op6:CapD3qiOo]#m;*k"1\YIpcq3`\W*^BDr=T`c4KEcMUc']U>c&Bm[WAl9J7X!F)%8;oOK/&ogd5N@qFW^s8qElH7m9)!IW2V1`#iVHu04l5L%b-19Z %-7`3637nH+MheT^YbV<54?X\KpM2ojH`0k(DCa(q?.2cK,&JpYOkZ"n84M$0<`h'Sf;!at$a!rNDh5jomEYmJ*UWKueRS]\V^!D0 %5L1O24oOO(Q:i_i-8\(+bD/5Ca@pZ<,a$gcV-4^G*%RtCQs^9F'pJI/qJBnS34)mRGIS%h!>@eeJHV[M$?D`1$ka835nMb(i\(SJ %'QSPNd`)KlmF844QuJq!u6Are2tco1^>t#Tsooh+fpXrns]+ClZ<9-2kUl`fVoCKbjI,c$:<(A2ML1'k/./Latb< %5(hXD@cJ+NNc[rs$51CA%b-W^jl2pE,anQ9kk_5[TfC>n+'?Ao'1,P#6?-lL`#fVsLr$``66CftE<.-?s(/=N+$_ggFR\3AQSjEt %5u`1+JOYdPJK14)O"2cA1[,,sD=FOb@7^7A6Xi#%`^-Sj,^3@AnYQQlsKI.3om,>QuncEB%ps %KY\%?>R:8daP\LB4ZIBu6"H=3*EUV*1UkZbW8ETs$fo,/BLsl"VBX%U<8^k`@gh\Yd62o5_.E2Pbn,]cLU,X^?[$-S*48]r;KNnhQDVYfo&_@rBJKE$=*;O %qu(]h5O=e$kFa86FoMm`=.h3]242Z)__$s5C;]EBi3'p]q`d"ak,R7Kg:dHZ\%AS+%j-l78KTni775leD;jqFKm"tmaYmWhfc>M< %QV(nu?B$cIB!DOU51CboY,2$a*ERa!)?NA_%:]L[d2q[nd3-_q:Ybe=lMm_,0NC\X)ZPca01K+Rs/]9$9bT\\9Cl,<:&eg`L;OrM %G5Lt'n+C5+cOM0])EpiL0b6r4XlfE5k69f*+2l>%_CXN&s7cghj1fjXlkZqD^YK\>,T_P5m0IS;NRD44,?.'EcnX/Cn+FPjfFFGm %e/u"?g=gjr9PhV]G=\;*jp_O!F+a`V[kgi:C)PRd4o^&JO$$`qIFo$!Bt-+o %Diaf=55j:g/4Y&5#SNj"ne(jJ+/U3nntG$+$6UYU69?oPsmA5X]^e+3qd+LO4Go_AYQ)??q#27=`c&eGC%1)M9g %ltB:nYb'_>qeLL>e.:,goi@.mmhoj#h>'=;MEAmOFu8#2q>D$h0u`%rIst:M+5YC %&]=cr8==0s5=''Ug=gGT\si+1nPMO;2dfVMSDYU6kTGTh%?+ie-fAAjeF2%2(Gp(SM#",A7"[SUQ6.)iU_.,AgKu1RBCqh04u]#! %l2GKRg],BrO!T'd93$9q3REtP^9QO6lBZa8K&9A:Tnc!l8LtGdl0,&$B"aQ/6n`/RYG=,q%lZ9to+Q>B";p6dT-gP#5'>M]H%hem %D-4QH2dd9bB$8)D(6ln@4hV\lLbl]FZlB6d!LT'MApYF5m;TueeF>il\2!uC*%&%D>G^aL.6%i$[DVV^W;V`;l0D#Z/A%(*GscN %^su@*j4B?;(C+3m@^[3>pV=.3D-u(=YaB9X.UdJt+#$V?J3%=a_PB6(@uG0Ho4nJi"jmEte#S$VZ&mbHiMP?*f4_dIX3s*&)`[h@ %#VX%2?p;uhFbsS(455g0L\7^Ud'nJ466fh*d$=cNnH@Hr\YTp+`$7Qb1Jk:n+!F77/\^PB<9Fp<;5hL1qO %*KJ-9,beaCKeB]`2kDT(O,5-+dVo:4f5*>1SbIFmp+G8*4KXV;l](&8>G7A7d$cCefK;L*q3'U[ %GK3s(BZtP"Trj,d%B[TS@nJf@a*?6r5kmTQF/Q+[nS7M5/iMJSRWm&_lJ?f[lNB"nVf!830CTFtTs$^[d6p'1q4EXj]9Q&B1m-m' %:8BHVg'uU`LuLH&Ik'iQ0V_<]45B8:THNJP7&f7HQ;B@iM!]B.4V*ib/gLpmJ'O<@(,]>QfQ1UOJ9n+p.kZf\BuRRhM %S[\":hiIWLOb:M^W.2(]n*>rLL]/+XORE=W]bXib0&Hni`M8htd]j`5?rt)1CcGVqC28onO*XF3X;C@o1LLS\+m>`"h0oAf.AVs_ %^Ub7jCUTX-JZ:Q_%&'U8/'TV]L?E5*lJW])qm"Ds4'Mb^Ib'eT%0_N?iT`!`mYD4BBe+?rZ4%.LgHX6pRX_Kn<7:,$O>L^uL%'Gc)J7rAp-K*-klD*;a(3RD#l=HYO(+Wr3!F#uCcF3oZl\*+MuBe+;t,Y.0:3u.X$)Jp7B5?4EuC,8uZe0G@Slt6]T]hZsUG8qH'V%$&AcDB%F %[>H>@ZF(pBaL9bBqV8"T\XmseHLRsG$@,m+#)aJO-EGOIL.>U@aW#fk>cG28?nf3g3L8bA%s,oC4WJ:;Hu;sYZQ&4Z6pu:O32^4,p'E-+^=.,Q!/>*'`L`?2[\5g %AS-k^q8c;a(@&#Fo@X>$hN^^]%\%=O[+aq;OM.d)DRjo?Z`]a4-lS6](GJ4R\M^O"h3ZaldV?E1BjRT,7KX8lqA!(J2![\mce3'I %f^/^?LQuW5_RA2.[c?cU7+5CGE>5+hVgVRtLRB-hY]YSHoAS/;nB.!))3RSU5hA$[2^eLX$@]LfaLB3[diO+aN$Ns.Ps"=22S[eX\AG"F<9ZGkW %?#j#_I6("V=uC-,7cf&E;J]BtZ,!tmenmG.m=jM$B0jDW^VA;0fl?JP8hZ?cLWDG8ie9Bi!s1S8*CE.u&faH?de>_B3sQ+?'Qam?q\H/K.8b#cfJ(l[F%(1UaoCAoqu=\n0>I3Z-4bphAm5NN6!T %B?]h>WU7q-*gs^-LZsNS`obsc?4NrLg\M6PG9isF.A=)0d;CV*=q,:@=1f=A;9P=$N1t^30p10"8sjB8_0CiiCjFV9@\[`alCRJU %,I<>i#5Z;REP'7S8h[-_Or;)GeWS.@@]'$m3um#V]p,*[;hE/n?X9r)n2Z*p9g(m&Z*Jl\,tOp?WoTS\-^uV7VaPk!+?cf?G)''^ %ehbj^5!!<#)dH0CfF&!=]HSi(M9b,L)bU5(fp0Y!fMAdL>_Qm`ETc0r@e_0S!iGkQG9mk^2kI^N`*#.qnQ9o.EVkVMaYO@he^Hgm %(XOR9jr*@h$t/dR$T8n,cu23;3r=Y"SK7*8!ot$j0h?Gm+0Ot_=8C(f[*>*fqfg:e1&I8-Ff'e>WaQsu;B;8-g.tSZ7h`CFplp,M %^H(d-@]]:E9OHraZ-^A"/TM2F>\D+Eg^qR@OJNu#KIM5nBF%Me=`SGJX.'S]Pk3#aG'Xs\eF%7:L-i`0Q3>?O\m=QCpf/fdj+3-M %cH1o?/0q'u6s]>84eH"fBn&,[!IkIU)+,c;p=IE"B5^Idb59)U-mb;radlB._q"g;lMs0Cl(+ZHE]USEUV,EoEFbqWlRCH[a.1i1 %G3ej_)Y#6%#U9gc(tCtIlWZJi,pNpckD+"o0`SM#*M<_ETGbddIC<., %H]6]WXi8:/DV(\B_#;pf<,:dkVCIYoQ-LRoiS=+8A;@JA1Y'e]Fqc^%f'GA-HTd5eXaL,m@@3ct!2$kAJLM?#9i]rCGHSD]HbcX@(,gb(@gRVS\B!^V2%a>!CFL%0(d?BXQJdul;Nb.3T1!MefUa<]&qn5g-cbfUU68p]5+PH/ZW(+&C %_YUH[.DfgRkAZ4P21lW!eKk'W!%*`FrM+i&#'8NT2uIS#S`TVfVBu'JISE2-QpE[*Y@P8&2rW:H\sr.2"+Ns"Uf&pCSdKeL/c>!M %PClS=^aI%^n:rRP<>md,($I?b_#B?c,^JMcr#JYa"EMsV/0Q(M=9+m+_[7A11LS9k'_@gOW@3@QNM^+6O-%&.Wpmqip%m%n=/e`7PVlCAaAb:g$ %("9/OQ*E&H_pDd,Y]5pMQ!c(>Rq9U6.',Ba;D`GSEQ!Pc_o?gZTh8pscGGJn/f>uhPK5J8Rq$=k_S,05Uf1;I_RpObb`Pp>K%6U8 %:_G4FW=n;QD",`&0iDU7GpGmJ2r0XUm74),[dE/h9%4>`3?et;QpklJ4tQ<;O!XjR[.(TD;T=[U]-"aQ0UUJ\PVECMp_o/YlAqpI7_Wqu)&&+o@]3%\'42koL6enb66n8:(52hnP2r`i>OK7&b7/)NGU=p %!\%O!/@#5Ob(=a+lN)k/`8e@93bT._GEAcRD4.Bh1#n`LiXo3ma)X5@7HVDP]m6:_#(B7IK16H0+*:,Bi8R%fZ$Fn[7>rW0("NLt %kJ@@8'GmFJ&G#k]lsI\EGWr-<^jq0Br;0\BS1Qj$@o/3KE'IY7e>-WE#02Xt87?)lL9g<_TNLkrKu@+HO`o*C,t*d,f*S(Qa^d^IsA>rR^_[%53j&+(Be5T>Q*(Lcu8][Q2X7OOelh'psU5H,r9s( %6sPScgDad.4YP0T\!!?7>TgFmN.j82JL`=UkrBeD#T*8i!.SOh>kh_=\V8I\&lq(Z`@'./[h0>ElRkFZ]FjQhFdE83r %P`Jb\1$s:e>o8"j]u7C)o$.e93^=U>gCO&bRbS`c!.O9H\iV#\LRZ)YJmMbt5bbU.]kt!&14!U)MAF>'i5-oEjckLk6cB3F+Z1s*kg2Y'R4YO>;Z4-mED2U6Wqqfi[,Gs&dA-U8A-8j$tnl2#sU %!hsT"E\8_"(.Bdjm[u"kB%(B@)7fd;7EOiK0j.m)nD-1'\:HCnu6ggMX#i9u:T]p7*l[ZR<5Rn0-=qq0J1VCM4,5 %Id[Dc&Z%E[3/[T``DiBN6$^#a^I>%aBr?48Es\'n0dJu%"s`(.eC>]Wl>J"UXOq[%^B#(%I&piWo]5E*YX'#OQB\B %HEm+'J\B:"a@)j'R#Gq"f]gc8G#0ib,o(0tSViD'PK7^qs#b/hjN789:UYX_7*\`%/<-JB+]HIC]0BrM8A2Q!$57]P'.ZDq-fTc6 %B/"&*[8a2jr&h@rdk3G7f658,hEmDbj?k)3S*Af!fceJW(Fh<^4D.<><[/Wpa7gs=Il/*/nF/C.p@:p8>^XZ^fd)qbU)+YMKoB'V %WH!)jl34--`g["nd**r#6M&Pg?.O+@Sti*e5?U\iW3,c&gmB4AY'".4X,AKEL]-,oC1HYLis^!ZI@s%aW;RiR9SZKlssc %o40DW\HfB[Z1;+18;tu__(oB,6"R47Mh6q*a_eN"]O4:P5C0b!3RI*3SUNrK/+UbDU2o3O=C>n(Ur.[9+Z*Xl*[0;ok#^#@g72$is?E@*u^49UjrCKFM@&'%8Jhd9%Z4M:Da>IPaV/l)0%c(YLVNHkI&CoF*BA[8!&'ppZWLH+XX? %?=5!n!A5/&J4;QYFH2dOWIR-[Qa?/W4m5EjWNc:^pCksTR(/_X`Eq9K2!u3)A4^1;ndq,2Q.1+`GD[mu[@)orSu_Wc%A.!TIn!37 %TW[c8h(H>S/;7C9fZX18C:pb4HU.I"1J1*_1J4#^PK@"Z>G&o'WdVCp:BO4.Rk64)3tSjK9>KM< %beMa\@H@oj*f7:T`+m2i8RC4X:([i:I=kdS?1aY$f3q+`BM[7d7]3%4WApBo?_He7<8(!>"J?/^b^_NF]ISD!nW@]0-ZHK9hnf7]?R)7&a%$D_2j:T$%A#NLqQ$:K;1Z_Q0R;,A+Pq;28s7#s:BID#?r8AB&m %H8iJq%#V)p1&n]NH1FP]W,qkjN^OP7nM"3VciBb"l'[8kJ*oY^.F`XbofK/Mlm-888\>l.\2^,"7qot=Yq!j=?0Ej'&S,MM*;dsX %)Tb^L[QCROQNg%P'+;:TK+'oh3bQ/-'dIaogs`ctj-M,jP;\fum6$>%F=QAA)W=jj!P'd-Z,RI-Gq]$bfg?*0Q>D/3_rf)'=/d*o %T,gFJ*fYHt"@YXs!ZYJBcl!002]-JS&oAQ95tBc:r7E]dSVXp)HbEouV9I*M0%F-,hoWg7@kKC%To@I/=>f:0V*Vdji_*^"('tAe %hNo+A=Q7e4cLr>L/MPol`PUZijrO7gIekH`SlZE6:)F3Gglj[ZgLfs[Ucp`Q79;\%La?q]'Q;_"d%4_-?"<(#1\K%a[pXAU2`Ft/ %CtUN9MatQ>hI'mgF.>Q?+`F>X&IE4,&<2o9u[A3C8>ki>)DtDK%;DL?_4%'.2MrB`?94 %NC_(+e*5rEP-B@.k<1Vhk&'UeGNaioT"p(3Ut2/"+5G[Lch:t3-LoQ"_#ZsHFLNTUs/:loK)E*D[hUIiifYsQ5_4#qp1DK#;c)9@ %@W0O$qX,N^7<"=FYeMfM- %L1(#*@UQuAWG!o&/Q=[GFsO9-)X`c!Gr?g-T#W3@BCM^Fe('ONiO$V('/"M^l&GUm#7SJHdbVD9e2CLm#fq@fS@f1[tL?<0`c!9fs++_Z?@^#r6GH7P4l!0AaR$uQ^]9YY-]:_=`qb+&\`"a.uT %dH#2IX]Oi)FLtk>K_m:+e`jUNa#@cr6U@heGhQe"!8XoiE>>i'G9c]?bWOfD[GCkfhTjS_J:h$%fF%B3YepYIqC8TO5_jm?`d0?Y %I#6;^\,/=]8L5SN#We),)NIlg/J.Tig9Z1-_oT>o\T8unKC-6Gn#Q)Q,7aL+j)TLj`Hi57VZbCGWW)a\L+\VA.[bg5V\4oSp3N-- %=p!JII@_Gij9O6Ke$X@hmWff9l^=keZ*OrH+iJ@=NSG5H(VcVOt+o;7m#M[p$A%i$--G:LDVMA`47F)`aa$La`CI\j*-K517 %'b+I802ucqpkelF^H3D5Tp6@4W)KD6bcr#j#0YpO+1"Q2'B,/rJcEEa?4A %W/mG\C20dV+Hj"%>?1$[i9\j*!)Q-*rd6eMmtd3JiZ?F5>l#:/Y;JBX%_5CX2u@dN5II=$m6(p$afPa\jm7aajl;;sJDeDeX=@'GuW3_Ll'c.2h,rWda(i5oiBKRjZr/c=HD+(M72:6#[; %+6sVI%jnp%:C$Z&Z_=S5pHbbe^IHW&1_GW%^oqmXET_$IJR8ZGCF[gZ2W05D#\h=WTuP+iHud0af8e-SY^'/bnC\*e)-[9fr0@>T %gpce@>\:G1pu#5lBJAahH$8+u#=DSaRF1^AI_CA@4h:=*V]C5Z_4P[#NDKFUoG*?3$ofJa9At1\1[`6^,+ls$1tV3kNVQ]MORa%7 %)^gdAGoE[-kK]7:V4BT-[CqpmRj68CR:E[G+C:2OO>%!N0F!4!8sp)d4Bj"EGh2d4n\9:QemEo02s+uJA/M:p3p/:&+?t&CPdNVU&W7HNj6+WfL&$9o_]3o[#a7?&f8QH$,o2gm\Ej[A$pInDd>W%"(''@*iYJ5JVElHs/m'd\< %$rr=l8<(`1YHq'KQ\6/=(o)+Ij*Vb.JFHRYXoPkW`pP,-e=rdFZ(C:Yh1ntkd52&rr,AJqiT;p!qq9n[jlD"a07oMh&^W/cK@@`j %/;'OplW!ahR(C^+HsB3N>7\[Mosppa(F#?OeIkcF1:mAkg$i>QP6:Cn9YS?k?lTqH%#4+s!8-Wr@kc]&pQ//qX"/t3B/DSc+$L.Z %8D&c8*9e3F?tZRS#JZ\tp3"IV(O>IP\<8qo,QocGTPYXL#,ARB0ppbL>D!f;oaMZD9O2GH*X&oiMtdYaqp"-Ri5i=X#%o7I27T*p %[)(RHm2A)?\IX>%mr91lP?H]!?T+>WCe'HnKP>?_&;N?q&@BI"#1@@72,Mr[edtI)#X^Qn-lO:RL0$`a0E<"H`3&cu+d"2)%6*,< %`/n54/jh\ZbSi7_VDglf\htGtNR+DoB\C$89(e1c;"5N'L+7%c1Ygis*/935//aoTeBH8leH1Ies21D$Hh]95*nKbLiTVpX"hhQ2 %geigXk2OALh?gb&rGJZQ(d;c[L@Hrp2,)WohCuG8MhYg(n^F_FHOGSS_>U9?n&C8T6]!uD9q-7LBMFtt7f2i:cKNF+pl1l9jk].( %d8;->eWr7S1&)>0)ah(m].k4,]bhD@3bD''+$YaQBrc*p^K(EU;QmG]9?YcDt1H"R$WJT;1^DWMXm``W9H7_h8rb1E2*&QG&c/G"u:NN890pjb"b[rI?.?D%%\dt66 %mTnUqmu8%*0>;>A9Lhe&k&ILY2:(0(#P2P7n6-7J6X49/=$Cr@_lsHQ%e"k>aF$E2.9)Ra)+IXg72>]Q+4`[VS#LDUN-6#2-pnS[elJ@@s^@4CUPtnkcue@V)R.XT"G+'c^'A+m+uaW_+oa,Lct_Lg=p]Ek_$PQ %]V<*GC0U'Y0D*%D/8qQ^7G:PkpZ[R_@7uXc%U[6+E)>)"_K#1Yo/[5Nfq"nsSIZ_OjikEuI;PoBAr.#]`UUJE"eCtGVp">45+A'Q %0Dk"H.0eq[,%2NQS(9IaHsD_=Sc&`jige>@cd)LcmFgT?9R8q( %NTWsDm[.Ycm*>"h1O"8O1V"TS%Dk8Q-Z\WdIt$i@Xu^Wba-(CeW/)h_8_njPHRasDg=$MF&>&W_qjM0cD,!0KackWJ8jCq?Up[u, %-Dqg0Mmq-Bhg;ucR+Y,6mY]jiH+!,Zb='S;BsmfOd*NL!AIc[\?Tk\BHr"tJ=!'-7T^T5Wg@s@hWL0*==TdbUQSJ!f2"(OA8+S@;,L!cmC[Ts__tTBM=NG#(_)l#[&KH$Brns^/8Wcb\qM#De %mmT"(p9i";X8PN](\S%.)1JqjcBeN&KcNMdb::/**iNrXT2WYpg.C[d0XfKrpRt]o\-Z.jks4G]&\SXu.`maUWLh&Gpo)UHVlecL %\=&i+_XA^*R.$`945ubn2C"?sd/\RF9d0'eRVj=U:->S`7*V"93Z?'Ro$M:)[Yo=7]kVY6?a`Dt[/W>P\!quSAEIA;CJ4u0(`dpB %`'24;mr?[u@j[dd%NY(DH9-ksFj63HVApiomQtKSLhHUu`,3Ir9"[=;JG'YGfuA?unRUc@M;)n9VS9#fDWn_pHaDPTiM01YIidGKrM+FI.HZ7.-Z#al_Ef':j?" %YApXJRjMn+Yr28qmmsni3m2qd1;:AM$<`>^gMnG35Se\g%s=4%qCn>h#*5p21\I.&h=Vk:cZnZq5gRGGO_OLNWT0#?T9_K-obe_; %SBhpZo(kIrm3c3[nU]XFA!oKn]_".>StY>Tl7BX4D5?($CUU:WF_="R#&)HW=uSR'?Y>Vpm`g*&Q[:791$WWF0Qk&j!i6;0h%FA00i@ig %N9g3KL[fb^,UNXhPU?(3okcJAXUS4'\Va-$^1DN"QuBI?^l'EuCYhLOB<0c:a?Di0`h;tOIW6r(2Nq$d*k!\Uo56HTc$(6KH4e=X %6]8te2Hh"@QAK0.em9t9nU,UnZ\NCuS.0gJ%=J0Mg.ckelZ/,t?VgQUfEV*%9q+WLm/DC3V-lNYGC>KV+Q%b^`;_L:P%3&q(ojt6N,uMDNoY$jRMO@iPGTd>!dIg%!PF$ %((A-ra;3S;R`Fg1)3"0I-D!hYVI/_AS,.I5Ja9&*Lh2:S,3Vf$]m?pE%Ba?Yj>Y[b\*nrFs+@:O-f7Kb2Eckt=[)($kR[ha%.k@l %_*)W.e>badZ1l&IjH]V4Ba_Rh5Bi_@[?A8;1[?QgSC-\%^>2Dlf5Z/]iqps(k91NJm=>P'?39Ns %W-XB#gRo_MBEiYTY(h,%ZEh([j9)Z!j=[(B[cXZ\rp6?]&@/'JqN,dKWqY1=aj:O*%[gKa)n[o'3iUXM]VCUJG+&Z>D\jti/E-=u %+jMjIS&?Ma7P1-Yb2,ge2d".jFtBc_%*65j\`\/Qc,q\_h.8oOKrK=)[D+:F4/qq%urf2,,n@JgMJ&pK3Kc`3_QboCR^aSR(krM*IB<- %F8'R#C!qt[=ZZ$;jE;KuFTBJMOrs:C6q"ma[ka^a.)561YNr`aClY#sPB %*=bpG5A#sE`OVkj?&>=m+WOmfueH;Zg:!flm6&X,>PeSmVM<[8"nDie5"a>F7Pk+ %*&"H35%-q'C0reu:d,(WGFM$$Y#Bg6>tHMf8t*u)XWoIM.F?6rnG):pO)NdY!]Cf&0e6:Rlc=6Q.,l79n`!?$c9(;*Uu9Nt5Bj3Z %qsDQM;2(Q1:UOqe,b>g>"*EgJ96JshqU98Y%@^)U'U098gL,!r[R&`lFS`H59ii?h:6RM+jis0/Vlr&J/^u6Ar(#S[:5``$*ds1> %1hPt=9[cj3^=-]6On^adX--4D07kEoB%K)QgZd#pup%ZrO9)')Y4Wbgfi][i5]BJlHf3NH%f!bP@_J.AX#6Pr<;qB %=4/OR0k$I3GUJ@Fjr[R$G+:?`l&N^kGEO7&sZj-i,qE<8hI'g.UGbHDe&nU`piR@+Ys*O4m5Ket^=,\oFSl!sYfh4D[B1d=:/NZ\\*[o$]s#q"_;DA2@e-'j$-QU< %)2l[^\q(A)'Z\pU.iA"QS_!c62jLIlVmSq\mBtX5$(Z\=>NiLsT9g6RrHJ_\o*V&&K`&O>_B[t&m0AH4bBc-9aH#qqjB3pT]!\nN %#),eon,0`LZ7L*TcLp3<`3%'n8G5/+cmdq=:7B'>ou;1/-QJ:@j*7TP:=L_19A#0C,DBd5]fRGffPNr1<^?B=PB6Sr:YP&ND2klm %mVc?nOW%QiB*Zn"q@P6o-mj+kmd9Ep@=Xmq:VBZJ_i6L-8NMQ@<[?/Y%9E!i*21[;h?7_a=@8H#REBNIk3\K&Y@+8Bkt&:_d@.E! %1a*=h_2ej@Bl5+h0@7nIJ;rmBH\[HX,PmB^Au^)gI9f>WY'6rbE4N#?@c2RI5)q,L>rN8i7>7e9U9tiMgG)dM[a22=hE0=? %qS>a>N#V1[mY` %?=kt[^eGWEGTpBLIg@ncW5V":*)S-]Fq;^_po^1QF=d1-8O3>]+@g@B/["_lGC/u:P7;dt"DL"i8n(J!?gTY1l %50H(Fgbp&Mka-=<:GVC.`VU-EM-#UOh.9o2GScrG[G>m[49Xjh\&B;Cm)YT)>cYPVDTt2l.5;'B %0nD?P>:Ql_W\TVZHNJ8]4sTCYbd"M&]HX(gBA%WZeKR(O]`f_+kq'.,'ai\cT"Rg4rH[Rf;4'`#WIK[Vi"D!5'In8oQ+.G]UKmsV %:]T>-.[#BrXg6[GBcr-[U2t\c*hOaS5VKF]HH"H\@W,HFJjn.6M$4qj)Mi6SPHmc4`#`-OLk0C04C:g>/]+hq(i(+F5tfZ>*HAlC %("lMR_2-Fm(.G]P\Y\F-6.UC.IqXPSd9php0"_@bB(Z1q5JbbS#="C4C=>qtB);h?Jsg[?LYbuN]=A0]*S;YpCgpPCmS*-TT^=\8 %g'beVT*r&SHsM"ZpiIhQLFjGnlr\g=cK7"%,c/<"-Sb?9k2u\+"(D_&?.<:a<]@mS%s=t^>+tOSds`kH1-m>D41DEu*I6Q1qB22b %X:lQMDupPa0JT_^/>L^f)bPbkG7BXn=tTa5gVJ`6MnFNt,,3/uAD;q?L)!ZZdLfmL@?r!$g,C$`/c;4V)?F%XYp2Nbeq/mfYaR%l %-LQ.CEt`74k:*FLGOQG_$i@tM6c7Q]("goc/iV5&p7d]7/?349SKFh&.Ek(5g>0ePYWN:HsQVhiOCf$QJf%$UYCtB9Bd0ge1*di8DTkDLBEW4hA,hgfJO5JoOt^R<.pq$X)S,N\OhE %*)&8I*-=FOVMH2i@40=a,q<1!U,6,Hl;b%=/]6S+=]IeX@kGG0lkl[ %OZ]`9muRF`ALp-ncSFV4^m#V#5f*7E@7dgiG*/JG-HO4X!WduTV*eRG^d;L86<1B%JY]i%m;M,AZgd0.?%K=QE!Vt"_^n;Sg(>f %"BZ0Z8!0@kiq0T&Q_(LSE?7/4:ALR-j=m$$*n[t&-'hU=g?tJ8oS:c5aru&N4V-q`R?&)UY_qUaMBhiEQj[]Pa%XiHIHQG)`E7Bk"X`0YBj,.(p5UJcE4j)PfM@2UJpHP.LI%i=l44=porZNZaTB81HM@0*NG5?uHr6X*.YM;l]M %L3JIS:Rmi3!#\G\k#Y=,Rg7*<#c5q %;BWq4I5*6[pVKMBHH"u$5g$*Ph,7@;P1e.'lBJgCG%u%YKtF$2f4q"a]R8O5ENIhV>2K+aaYA']8UYkW@FD)/V^8sb5^&S3[re(l %qnh>.cQ(ucAj_je!?Xl`XL)m"'X4+(U&@p'#h`VJUIX[sXDNkcspb=S9$\Mga?g"X500`-3G[MV('u^T-/]$9qisK`P,_AOKZH&20"=/(Qh]imt\>Fg8s51("27)[6?:qX#rk',>F'D %*-N.j(M3ta$**kt_]X)7]EtCo3),\l*1pVK%P84$c=R&AM))CRpouIZCE0TDBmgW3Y?WM=RQqKI9p%+##9,DoM+`t<5?/b!'\]V2 %ZVdNHq0WnE-W#<6VE);/g)jL2`[CQE7OhPJpi:bEh2.ofPB7R?YB2/di8X=tEAi":bi0$'"B;,]FLR4N`hR?&'UDO;Om'Y0mtft[Ro-#\fj!mo]]J29ngUZQ %K.$gSPba3g?S^ugbuIg[TFK",-^UsS1mBG.UlWq];8n[_/F$_.>pT?j'LmDrZubAW@aS2G_K+rrkB)"F'UIY4!U7,U-LhnL0\ee^ %Kp>u@o`ZTqq*tWE'"arI).Q.&d_j'5DueG7bGuo-K&u+c8p+_-4$.HCG,[X[J%K*NN)XH#:;I!$3\i4GoQXI#RAocJWO6,r6p%[: %B;Z)KoR+8YiPrq+7/?OO8>*omb74BUV";Ga/Qe%BX/,-aH&;7CYS3&k0G96jMhINJb"Z<#ZTs^6@Ws=t@R09T>LZW>_NIOhD6#jW %IFGSSI_*C?1^j[Rk]8&^TYEuo0t<.6MeN^j&UWH1%%YS^PeoLYa]s*dCN8H+BFZ_(XYKhQdMQMtla^tO>Yu*r2TTnS&+_M%S!Qr6 %o)M&!XHX0I)6ZPU%](7RoR)`M"Vk$n!E/,sIYGeYe*iQ[[,HL50"tCeh_,4,HEZl.arJq9BHB %L^p]45366[n=)Y78UC]19\NQf\_qghZX1e_b8ZsgO,Lj)nY]G+SDGW$ao:,.2*8m<9^m#$"rqbEn&,lapg\)a:+rQ3K:hj0\DC$o %SrNBD#b:"=O"nPY-J3;oda3O1F[ZQ.)K0+gpeE[MfWim<1T\p_H64stVmG`Kq4URtm'r6s$LB2q8")"%=cJ_$#@lj%HgfZra.BMk %3TFVBQ?sNt%]'O0,S)QFF(><$.D^K=E=KkE.8%pDUc;"2]OTg)`.5"RpWh#$^5R>@8kN_V,t=?];+n**M(R$a&g"dJlh8XsbZHQ_ %)Ml59R&9$l[L:nL+#FNb]U6dPF.0bDF>ZVu*WslRR4;h$0#jZJbn:\/A=eNK\_E4T<4h\nYZtJf+)1S!brsR1gOR4!h&)[!ZZQJb %Mb_;tI^6d1U]F9OLLPt*meiBmQiHi)HtrO@<^\XhSP&,qI5nT,Y0ZonN)WQmY@[^g1%t2f!*C0Ks1+D=Mq`G %2OIUR!j<"[52$'8>AF:_*hbrg?G92$A8?qd#(<%2dh_n:p$`-i8Tq'RJU^HRB7,!#)UTNC`HHE7,e'sQ)^tMm'ih$:amN!MC'8Qj %A^7&^h=;CJoG%Z%E?u[pgWsb7HHr*dOZCsk3Z_E3Hp_%QK#`IC''ll-.R*1GIH"j6.fs;(*`m_/Ie_X\@JOP`f1$;:1iBPq*dUrL %PB5@/?n(gY"BH:FKBccp*bK#\,#_Q0%th,lAV6g?HC1[o2*>sX(4)?N+-Y]>:XE/"6kAUjL6;CX2Fbij-hdqL401:jVrZ7ZRelG< %Z%*#AKTa4CM@(#g=D=HWZZG2;W47ak=R6efZ2,ZG&V1kN0b!&_'srN'TD+[>#"\&Xh\:],m*dW=AX\1Hk!)*ZNC.IE&6:[VBplF4=rBUrD&oO'#G-QI80%M#bja$e/(4 %ae8^`&!&/n3djn*_uO,8NDGG#'ZQ85MIQIP',6(&[@ma`bjN$);%E.SfQD_^3[o1GHba(+X"%\b787E)nYq>mct'QbA7Z;`)X(io %$LEm@ETtpcfHM$!FB>APZ"Z0b5S+l5]dcCa[H.qA@b\+Nq5CUq/jq?^\EEqo0f)pm]=JMGV<3dH6sYBuB6IiQKtLN2N/kYQ]X>qhgfT6qg8e(\27 %nT\0G?K9PBVtYk=+pJua<6AuO:7tL\.'kt^!4>EQXsE3miN\nfgt21#:)4cG7Eii,csXs>p*n/H.a[+KOZ!X"3$CZo)Cucj"\>dh %TY]nnd^>aa&n(5'c5Ti<"tQc&?OdNG4d906R7R'W>mVE#a`V]klTg*QEuj6()h^_]ANQ?'"`u@3L@"=@!d$X-h4];NXGqV2,9'&_]\=H':hH_li=kMQ(&1slg`XW*SL9*Z+Np^\UJu/+BN3)KkS:gemAA&m2pe/^)Mc%=UaSK\GK&n]&ha,i: %UOqU_X]AuGG#[sVAA(#Rq",_n*%G&#'+Ff+$7^:i9GPZEq'&eB*$uNpEb/4S*%"eTD80FF"Y7=SpSt0"3D?ZogO?ng$C8R4K<\Z! %'eG+cKmL9^.Td/oXKu.N'eG,ZeQK&7$9fuFX.Y(+0YrVZq_BX'?=MMU"j>^+ZAU6.K&pl[OS.3n"j:>+Fd?goRELdbDd@$(tGW2lg[TN6>gFp4/=Ig`A %DgClbM,arTSGX>Z^9`86LFm+#bbabT^(aeQ^*>u)b;[aVMa_u>1o#s^`tkGXnI*a`l4i=qbp@_p25,rCn]&l_d)D>]MpK.@ne1/m %[^/%PZZdS$=QR4&MWeMUqjOe/m(7$d65O!h/cHel<%GEPp`8/Dd)?e%T4I\XBL*GAN\/hDo3^u6@3ql;(G5GLCb`P:I1a'cHY@N' %ki0dj`JX?&$G-"QCb\&]k>HEljk+#k>4;p'-.[SuQL%NHb%lhk@#N@$G9Mksjt0Cc[eMEA<3^GP[eSW^RG\1MPNR3-f=Rcb4qUE_g)/p]>S;fi^,AG`jm8!X@[&abZi4/GjjUV$Lf1rF7eo))nT,OY %SOFkFWISj#L/D!eM-h-qHpsR8$:\1oKTKtYP^t-]]OH/^iTqi#5UX0.q);`Q`De7-0!lR^-UdWZ+* %Jos8`HgjX0B*%8pI3b.7elcC;hjs`cYg,R],*LU/Z-G*bb\t9X$Z]Y3>l8rQcKF(iHk!0`0O<5da7h`uZS4SMg@Lfu,Ze?4Z@Lrm]V:@%Art&+re6YE*h?cJ,VM@@afPbO8l1 %'dRs6XL!G!PCSQ4_LeZd>&h^eOdXRf#KoNSQFf>/`(_`DQsl0)>RB1\B\S$:3$F3A?,S[G0> %/q+88i^tSRiqsg!B*%6*hobT'Yg0mGkX%N-]2I0oB:_0!9tP('="$9)S!WB:4r2Ifn8)^3Z'`3e&^aoCVN.:O0[8 %FVY%_p^Odc`]=L=@O1YoYg*;5#06IbYg,R`VKf8\'sQ!(&c$WZS^1rQf>'G*F8k'PFdCcNE.+goJ96NA'7LbK=]4_g-EOOG]miJP %ZaellI9>Ygc]PDaFV]_4Zi!"go9k$e=2I!+`cpiVcelQ"$iAsl2Qi'_54pTZ=Q^XI,)9n;FlcVBc0D6>oHr->i0r1nc/LPI^4U3% %7l@'PIg')`3i\Tr([&8Ic0EMmDohl0Y#udq/GFnSYMbl";9e:].BF!1XH%&X-2(&*hrggomj-nLqc0*tgXUWm`NbX=;'YXdS %=WQ$D_BXOD2@k/44U.MmKcERO7-^au(D0Dh7*-fZ!5E\NFI2u3>U@?Uq01kR[b!5AX*4MGa69P,@( %2c.R>5;h<%CT_]aYM#fk2uE,iFTYCiE5e^oXh%SNUm`c8k+Bh4DQY>PGAa>hh]hhcB;qBJ9s#hHge37B1US:5!("QHB0SNE/Y@Gs %[U%mek#AOBIub2YL"2(/juC3n?d6&ZH7n*olJH*irrhK8Q!]$%&N5?^Eljr$KRDM128`oe`0T"T!&kd0h`V6Q46>\"g^cV"Cr@OXVl;6^hN4/?K4jSu4"(RjD@/dj[,@]\]!RT/Ng9\)9,sM^)OYOH<:i).)'fC$g=IPb(7mZ3IgBE$_)> %M3k=%ZsS]hKM,JXJi'jTLDR?YhKuPf^8f4`!a(3/(&L1C1P^=HBtUb$Fp@DM-VmQV"\!"&=s.DQh4FS %PF+uaq$lpDY#(A>`*>NJW8b+q;+7NcQh8g5kMT_W^C5"Td(#@qkgl-e4*Lp7=aW#mlIl2:l5[ %(ZS7T4Kk%Zp2Z!$-A'YsWOE:/V@\6-WYJ"oklb_5&9m9VAIXi*;l_`tSq,AA]!$(0E_K@aQq)Mu!Cgd-j!.g&[!@X,e.otstijK'AM@KeTm1"9=I"?@QOnF[fkS*c_//m0^p4rIJC %gR1nn>F=fJ4`5:@?Zt>6hmM-lb5)PNggtr\F]L<-(dRo4SM&629IR,\^ONH1GVugiMCZqPF;;e'boaLA7d:E)64&8^X#%V8o5!IY %Q#WrGgh&Gu+#UX9##B'(lV*r'Htm(GX-KjrEuitiq>Fi0#X4[.?W`5C@R,AZTG''*dB.3n*h(pF40^1:_k#'gc\m-BX&kaL"8.uO %_n^%r$'Wh?K0*mH#ep4V0K57TY@^*CeuB9D'/7J8^G#e_X;QV&!q7R*pI>L,5;*>Z8Y6%XBG:UZ?Y/2.-hT1_)j^UWc#.^5T+,d- %);jdSqM]Nc*Cc@tP^*TK7Q3El+B72^rl.Aj=c"!Z+r`.Ri;l,jf1akJ.IkVqFEJGDY*@!sIGgOX)dJun838Qr"i4Q&6s&Kl?ehE=4,kk:\*1k5rl047 %48d&j='i78Gc7MVMim^mV8Mk1N`I9ec0a7Ed7W[nE\'@HN16mTa\,cg[a0cP^1%: %'49UG`(T)gY*YY"`2=@?EQf*RcpbQ2l-cDpt1!]hc8q9TYIO54u]BKA04#t+!5NdloV7if@fD(qVRh% %W:qDY<"d&\-G:[Skrf[.@=8sd0D48niT7DprB'4_H6K@M]e03:)9LZ)_,U+W&PT+fB>NWUm/s8#2c3>^#q*92q+0W<�J53(ek7 %9!R+4.eeQ==1c)U"qU=s5Y,k7`R-?AnT$eNIW;Q8gojc@NB7IHno"0O5/7#E83O_M %5JNfIgAAT#Dqss.n[\Qn[Fii`is,:M:+Xj[IsG&?o26m,OYXUG:'bb$19\b#G2^HmF-i+-4QYWV4N4cWY*3c! %T:`1Ci2T;SlTYiU"g?#/jg*+l#MAG&$FT0tb>'S=`Oe`75Bhig\q97uYC:9GGf=a1+3uBIq(@+1*:FqAH$K9If2Wo!iZgah5DYZq %J'7TN+K)Z^-:-j264in_rj-6EiO/XZ-_J]YaZ$QI4M'^C7I$*&ai;X#oppp97]sF2^8.opmQ]UqAXWoY@qCICPF`#.=$)P:IYlJ( %J/V,JG,)@_lQZ8nTHk!ca&P]lFfN9r?7)"7\E\M(U9m;>k:7$dr)`[66,%EuM,4%Xq=Z\brWAM!`2 %X9R4:q^q9cMadKKrSuf+M1"XBIhbls-aq!"hRn.j\eL@+^6-;bLJt0_^?oj)'8Q!SKg'qu)@j+C0,$OOHTXoQf1gTj='f-j5.P>n %I+bJia6J(DI!d)mpd]O5Me-B7EA:Vf?)]-B&'Jt=..8[-&1c;jh.9O!X*CXq/d&.pM`4nCF9(W/(`&&g[o-?O-N9nReJse#lS?,/E%)e4*`]*Z'TBAV+YrME>"W,`&e!=Wr3-g[*&*d$V..I+:\__0Re>CcI %I'QNi\sOt<E+s3?j\G+#uJFfi!s31Mo %.p#VCOjDNtdJ<+_rtoc&qVGe2iD9d=r`Q'@k$(oi1U*BW$N((-I*5%E%Z1uYck%Re"c^5ej"WXraUb6!H[p?_bKR1i;qg7k4mPmPh(7CXWUnSS1$_d3(s,M@sda[>d^B"@93i^3TuA!aL@5g/_Po' %%)3`T2l?P8*Zd+%jkcW=f(]YGEpk9GHhe+P[ZfQ6K,!EUn#e,6*rLd1:_"ZD5or&ZBYTRra7+QOcaE@n.5WdKkkVR&9nNMfhu.Y4 %TnL0,VRU!9+;1P"UJ*R;STR!KaZiUgP.hnEY2HF1I@E4!Da!_ag.]8S\(C0!01G;h042o`95.JDo*Pf&b;BbbK7!?pR/6W)#YF%> %EUWSIF]Gq2h]LiB)8RU>EpsD79t>_RT8:V0Q@J6qpq,-@okO+q=,+U/kL<_WGOFL$3;pJHM.BH[FfKrhoV17rr4W2uWU5,>1&1T( %V=L#?K!T>'jLbA]r==DI"5gnOR(CV<7;Erh?1V_"h4D5Ls%5HSI7Ho*b$j"5j7la+"2CaYVFH(1j.om.qU)!gH'M`/o"iH)iRHJ. %qB)!lq72k6]o=c)oV$.38 %>#-1BKdN\4Abs!dCttB%r#VD$T7?ki`8)QA/%+4kuY]9SaI]6Ps0r-U`A"U7sN*DRdec$"SG@H`$s4u%F=r6/Js9Q5+%jtPLE%mQXd#74W[/7d\$&*@rM*.GESGGM2sHZO$!d+pg"sE %Pc(+[+*r=%\,q%$n_`^]*hic$kNh/t<'L'Fdi?Tjrq+\9TA/7,f+Vi`RGYm'3!l`Nq0R/Lc0IajG?l5rIba3Mog/ddo^iuZ=O&2(VJS1s;8aoo&1u*Ykd9D4oII`2nnsN:Rh`V/j.8u-T(MjlLS",#_>bj@:b %1p%rcbi^V9Bcjoq-b%VIgpl^8N_/8'hEC&Yi$9BGn"JJ$dk3:t?6SPO5#0F]Z %guWmt;caG.8FAY>Gb/G%1$OI@?2`H?8#:h?9S-f_P^_OMU:?h/`^mchWN4E>/cOkS/j/-5"PVHOc/dW'OZ1M8@an`(4bqumedU+U)tCOd_)jHj>bBL,4_k>rWgp)Ncb3"iKLeD;&S8m7kJgFLha'8gG:Z= %5Ffoj1/i`ulS$?"(0=o4SVD6jOa<%[*'F4R`%]o6e5/W+A]D %^`>YA`C-GY691E+WL;u6YTaApob+_W:\[9=W;fHr^>A1UZ\Nr*m7/8Tpi[9J"8<@D5>>WNc&GSi"1.%6=mtebr%_[cil4Cor_(:j %q,d%Nq&[e[S+Cam/2d.7+,SAW#Pip$2VtReq2UXPH*um:_-^Hf\3]FMJpdRbB/'2uNJ!Q/F54R_jRD&lUSFBm/pL:=IA7m:F8>CC %2SIft%EOI/(9Bn2n$u$M;SGj;hg8E$Wr]X#l\ufCarb$]OeZd-YDBLkE]=2?65=Ad+K3j2`69s/]eDF%R:Dn7)!_]AjqoGt*ifg' %rkXk+qs`C3Yqj:&?DVr)E%$oV4WVQsntlnL(CtdcouAGj29j-JNd'M:d>+W6jG$Rlr\?-QeJ%1[chiIISM'C03dScpTS(QhVeIs+ %.#(]idc(LcC%(G!(,=PMNFd!c-hp[Ng,i?=:'3UQP'AQa/jr3VFd[1*86D3WG/T7R:TGc!&0His=VlF;9CLK!dZNa'BW32h_OAN,eNqVC8o"VAH56m8?flK@8m@;Pk.<^4OTNob.?kT_;T4e)R?)9eZNl:]R.u_ %HILjC3+et2H=M%4PDHm4K9PP(7A!?'4sf$?-+T/>.ad/+I#`Y4Csu4@%\=^/`6EAu;SGqMrSMoMpfHs:Z08.@P_bp3mg5-m0#5*X %'hgV7m(ch6&^0QMJfW\",*m]e@\k@dZ.pD7@7Rl/gL_KZWZfb]33S'lH/;npPFFrGW;'I7`69s;m9r\:%,sI/KD;=0"ia]/_(%5Y %"B@j8^k%](,Ce:QpgY]Bj>90^amY/K'7B"KINd3&3DW&a20+q)H1in%7W7K#IE5's'o^7bjE>Qo03bn`mV`C]m+RNjLh\\1n+Pl4r^2\*A!+7ja$*MRT98gTg.`>@S(=n^ZcshPHXXPNHa?;\K=DWSqecO&H7nN&&GjfFjH\F$ %:90d0YOCYk2L2,@U\g<-P?2K0i00L0`)2>/lbb:$,I)YfS1ZU&WE[I^3/Eu4J9,.=&2V?,[a3qUAj-F(P/T`2*5`SpZs8KL6TKo< %V*q$nL2&\r[`L&m+S[9>9j[))+G46p]F(6P6Gf;3`tt;5:V.T+WMTgtl.GQ]T>So5H)8h#mY,NK)P#Ir[-Ad0C,lg5-kro3'GT@$ %E"VF7C6_NVFa=JV\BcjSV9b>pAT*P/=o6b$.dV_;2^>\O#?)>i%NL&I64dFdaqrA)Q%;9B.'E %S%Nm4/q)pLb.^''kif6X7:-as.B1oMW#Z<Fc&Fd_#\>+R17s^mp:]FK]j#c0Da'4ge@`0T*!dba'@`0T*JjjVUH\?or=V"'p4[SKId]N.7]O)*6c5ZrRp/leU1WM1^le2&! %>T/;"^qCQf"t[S(^b]+7W\G^$HP!/^-l\ZfWXkVH,h*<;gjlc=Gr_)ElXSZ7j3^AC'aW>K'[IKRY$R#8"-*]@[$W2DoGGRbG_X?+ %\*4hnKV-/qoH8r4SKs)ESFF_W5j;p,J&G>,F7bi>9^jVb%V"Q;csE)+/XLX`/;%-S'6&?*M"\M\i_"p7N9+;,HMnD;Gg1_`\I$.! %iFWM+UfI)nS=`AkS.3s\s6tZMlkO*&/,P'4LgiQ!=2Q\:U5R_VU<0!-1S%R1?1VD7pp:harBP85ZXie_?ZrG6\[+MU$erC$!:W6-L=d\C56h6%!14Ao\G=a+1VEi#lWl@Jn'&*Q7d!*h>Q8 %K6ABGr#k??29T_,fe[0CJTMb2fQ#Wp6.jY$/#UqNmR)qOlh:S2I<+^l;G,.I&p.X)qGLe"OK]cj[WM4XD(5"_OGL^:qs2P?i6eQ[ %(7#RhK`oZs==sta(6MZ/k[kNMX=>MeW-&2C:_0N&`QKi!X(5%!fQ^$kV1dT+Jg^+-(SkF:]pV4(c=",L_2\ZT2nZ=ZPjSq&_h?iu %A_VhHO^<8\$;sm-R0jUh.9VVjQkq(rH@-JP3B"10NB0he[9aUs\C,.EaUOCd"i6IKjjsnSp;YJ!)agD_*,9Fiq)%M?cNX^q7Beoh %6+5O+6A7!*GkJ3_nESE7bRH$T2Mtnc."_&]4Y5ne?5"rsGl"F5K?NQsa3&N_MI:3JJgaD%Xj`Nm8S`=eSsigWY?[>>:B(cV""j1UtD,-SDN961C3>HSUi'iG,(IZ\\uTuWl"I,F?W`L$Iq6d_:s?lmg)E6>bb=HF'; %,YjQu@Q!tsg@hgDi^E=Yb:7?2FPE5A$jcUa5mX@o5RnsG7_3L;\KnUQ;kqUP@bbuaMI@b7)^=da*n&;Sb#[Mcl^>2T::qeM=4bdqd %A,/F7*5amM8a@$;M^lFUM%f8+XF1Xbl1Ipg499Cp9Au4\&!go?2FJZZEf++ioG&;Mq\O7Vd/^\M9:>Mj>m.m&;u(rBY>$inC`Mg8 %E3S!V:nWWnKQ7fJfhNeRb1:+p#@XA52JP.(#fXWk$54,iiU^At'\Z8uHk8*S5V#%a%q7[4ZXL3)Ma"FX>sF?ed?%[f/)leR6`\Fg %i2Q-JaW[^>jQU*-gW,=`1)_P:_S6Vk(ZO*3?>KY@>9&Jt`8$0'5"3i/2Ok52+'\]]&:?aNcLMn;m %i)I[ff7hGLD='hpJgZ9UN&2YZpS4[W9Hp=dZ*oFqlU"hY6u()S5B@E%3h"mH#pFSAE.(NiaBI4-<+taGC5&a %-fk6tb(A.-AH!#Xlrr[pCU;>A`PE=]!apq5H%fk7E%YjioHN.A,D47;p_;snRMt'D).Wo31JkmYNJnG]R^;pU^NfFj+9l.aN;d>R %p>A/J[Od*sm/cQ%VS*>J_A`CRS0r#aPkrg?D;)#0d,6$CMiP(\&NAq#o2?YjofcZg1SsJN8qj#?>`t6bA5=Spqnk?1Y3bK;Bi\VS %9&%RSr#r4bL<+:RW`#^Ykk.;4jo)Gpe'=2dRONN,p2Fo`)6P";Q#OMiL,]K'D#2>Zi0Ie%N:G %@JBULkk,[:&]*;tQ3:!p$A$&Ob`G0GH*GDFYMJMKX4QNqP!YqH5i.qh$tajX?+:4f`V\Qh?$g'pRl^#"0&>RES5uN]d`(a!4t4SM %Dn1?`kC(0^%rX4-fdH*.hN;RR(JF'SSBZ&pCaPA6P7u5q>s0nO'+Tci"9X!R)CD+Lg/LlMW?AuoqM@?L1Q].F6.*cMbH"FV"Q[\K %lA=b.]MCuLXpo5U0.+O=pgg`(6kI)H>/G'R#ICn7.-+5s7I[ZkH4.UnHjd9,@N$R9lXNskXD9KT@f;t*0GGpQ14n"93>,RgG7(Ms %c';URp5F`_abCgGlDCgdZDf41gP[pk5DOU"VXj%are#c0O+`a$RObGtFXO"n05RUqBp_."1fGmV"nog-)s`l+.O0)";rXskq%,s\ %Qq@_'Rt_ElKQ&p4^?7SC9Ghtk%bS5544'#ki_"4n/Ju*Ch_p+PUQA,^U(Q7U90lL)QjXNQ`n0+$h %R&/NEUTCS(\kVkG8XS./'Y\YXQkVX`QO7H.W(k1J/AEL#h4[F5b)Qh[$@=KE-GV"424o\fDP`rbrC%4]M:bI]KRBmW0:sUao>60u %c'X69L'beY>-!Q>D_=cIQ'U^0bmP0p\%t)k_:b:n0Qog-eA"3p[EdL[u'0UAmOdE29_(4fQIGP*1?-:4+2m9k[7_sY@Hn%nG^ %#ia3M3.q^^6Rm-TO782/5N+1uVoW?`cp%#$KtFq,qIResffSYlm_!nWdTPU?RIMiRX5Ud)ZSlZi[0bAV6c3>`'H0[Xo%'@VoQoGZ %\?aG/DIJd<[@^Ks94/:.+u`'dF`Le00O_12Ja9hFOOQB*D8s\)!Z>OGBD-Qo%n0CC<#"UBghLjlHVEsc& %=6@b]Cu/$d]VBq-I3t(,*S0dXcFkAD3@SH.Hng005G\6'8=GVb]k4?>!n%*8E-7Y+C_Ck;<4%2+F4lVXX&N8$HGXnYf,A^Q+Ci!s\al0\f+B%F+OpD@)_a1e/:pudmE..2O7ZZM4:PhZgoT?sFD>8O((o@a, %31':h!j7*Tn7kgV02GpSMppsNQ6]/!44]9#7]4d`8A,s-rN5-5l/c5>^*?VC7U^`f)g4p,L7f0O?d9Nb:CSSIW:[dqK9j=N5&bp+ %jkT6:002.qWP&8D^/%);@ZFOU:p`+p!P0(Qk+RbM#lm5:k:Z6m_3KoH31sW3?JCbtu@1Tee.H17A[U56/9h;T+7L8K; %Cm.rs4=Na^Ab&HSiI-l&j["u#RTJt>ncUdg=Nk0&XKqa#5NIV@g[)RgIkR-Lair %$H5>lRQc>4rsl:P'oc:A206'Ep/KNC-?.D"TPbOf]R5#EK6JP;1b\351P&cG"Q$^eOm4nn6JS1=P\r2^dcPSeAd@$:3tM^(F7bXd %gn9eb6]Icd=0d)crs"PD*Bm)YjSa32)b]oc_39o$[\!9FfmuIe_,F(o:d!bV7,0*YmIM.ASr.DmNA6B&AYL=95?,I2rQ49eXBuU9 %lc0b(qu=Z8e/J?s(e(Z+ijr>MA/Uf"@\9RCJRC.3u(10):CA'2:BY_pT_3;chiV$_9QGtS\[4QOMQ*E1,hc# %"C,3M,jN?@>"+neglRgr(^[.Gd1HrRDDd27^Je@[B'WVY@FB4&8eA?[)2*L[USGM5R_lgV/Xn>-fj)5Ae"k`5+F#6#`hsj?#39AS %?JAXAm'UYM59W]_(<4N<#35B+AM`HJLYm,m&D[a16VL`XIsbnP>qiqOiV,mL*a0_WU-*lQ3GrJBopTr@`3+u9uLa&pHJ(l61I %4;X3VM7EA+%='^5W$RGTM!8IX[5;_Rlc3e2=fgnEo=-H?ga$3%eDqK7#op%'JW/6>78SS3."\W8:IdI*f[duV6p\0ELeknkjC?Cp %i_/Wl8L)gV*[hqfPu%#YQ?:'Ca+.E0X?,@ikD;2`X,cu<%LKb-q"P]/#JoboKkB-JgM"5hgLo%KTB0!\dh/4llUc8.)3eO5$Vr%8 %R>KO705Qu/hGMX9Q\@!!QY#\*qtuoq5XZ4;<*13F_'_&)Lk"4t@au("aBf:qCYJ)1=^e*!SBC`H08e/%m;TDtLeknkA4f;m`J,'m %%_&DJXr/SE>`8fCG.87"IYc0Pl*MD#/?8=EL*[`;o#;4C^-4I?m]/:$c5pr>]r!$D?Z`Slh0Q'%)(*][Xi6+B$PScZel%I:_>(m? %&aPgE:-$O&;l!LH^dZ"%'-mdC)1Xd$r0EX,@XYnXHd'o0@ZE2IA`,&tl&@FWo>1XK(Uh\$@`8h\Z2Pj-0G`7R]'E4E90-(/Su_;n %4mjjF(9S[Y0GYRq`#$E[6e9u7U+e=<>Af8$Gp^1BfZKnTEXYS+FFj(Qe]O,8_qo[rda!3(5\]%F,!AX&=,D*_o.mdoQ,pdF\4"2XV>FI.ap"2Qff35,TSd2l1O+012KfPCS%Es0&ae4^K7O\?$9PK+]rW"_Y]"6KG3HZZ8FTZBq"DCk5kZt$.im441f$"@&uPG77Pk6) %,WOS.$M\RfjMG]l[.!WW+@sns'?3Wd^hX*V%W%"P>8CjH.[^Bp0d'E3%VL&@7Yo=Q@7]G[=$@dIY/5j&59Y_V[?YA^tb %YT$a:Ib/-Hn)^WJi!/$c%Q.7dO>a"ZX'89-q8dZ7MnZlL02._BBUHS!^XYt^\"bW8=sXf-Eq6lXM=2:b(7bdGXsTXqEXA4B#a_^# %>j8Y!5fkef'A^h5I/T+))CD*iB=l+TQ&C1WaEhoS0bPhs,]Sfi+on$/AtN-nB:ck_Gs_A+;d?J@7-B71#O/ke&oq-QL8DTrP0:&m%TXfils$cq-d:;fVCa.!Qc4NMkMP=S7;n`gP`@^QT]R$O %,)A4$pr!PQCCG&[A#L1[i0"TI)HXNG'?*^0B!A2=XYI2"NM5cEP#oOQ;=J7FSFh[Y)TYM+B%,HpRhd+-4'GBFeHf_Q6b4(0Ohu(H %\NERquVA"HEt'dX<+\/aO7-$(FY)F#L.lgIX\C"k;6u=k!ClYU7Vm@:K1@dC&@q"_mr@7mn0mH"eq!j@Zn` %E1!X8<^SYSTg9i_CS28]R!/6GNWDn'"g-;;d5Z)XCGF=EmiSj582!`FlENeqR) %Jh;$UoHI^'oE[*6hN@g!`pkirG+<#*NXf4oGHHF52/Qn;YE,o %qL?s8m/2Z&Ddm?C?IKrH94/!af5N?YJK8gb)VOHeNI)Ijpr6L#]6^Sji1ddh_;,o"&1DQ7OZ;$!":!n/GM(5M=]`Pupfflc"a@N` %LJuf@/qWJ2&Te7T\>3RDgM1HMlN\W]h'#asbAsGc]P)?uCn$?U\!)E%b):j!+:&qH$#D5Gosk?Q\-af=$Q_Se=cFf5\HpF;#s'F]"h^0V %!q8(e%SpJR&M3DN't".R,XitA]b[Af!]mTT+:;p;Jus#)+T;nQTS0VJM0X=IRu:ZI>Qd/$AC&X(.\mdfi!KBu>QbIYX-\7=bE.Xt %:\71/cZcBZ2;BQG:+%d@X2V<*IA4L%7:WatOnh/kd`3UCjH#0H*%J:JZ\PRC]*BWE%=*r%4e!+.e:Gkn]eKm2F>#Q$"nr?G7gFbi!?<-0_3%]31P6732.j@b)->S?J) %>?%i+OlY'ail+6ZJ69oO(fR2[8pmI$m1VX.`,t;GGAS %hO8F&G-QM$/F_B$Qsm1>Q\7+^.!)6>8r1*jX[>-KBW=ul14*)E>J$V9&lNZP815:j8+6OceV>X=4upgXN+/jh_(Z^%Z9H8>-2K?b %NO+9d;59MWAf.=NO7Bqm,L(G\-YYCF0fh@2.XXb"q'U9b2lVb6+%'tgW\QJk[.bb(9GF:"Y7?>/'W.oZ>hR^af0K:-8:)Za)WM4+ %b'.Ym^NFnU/R!QFm[,V1D4iLo@X\M& %`]Qh.W7"N$NOV'(F#f8D!\)9DkP;udmr*QeYD]qHWqdBTN?:IkTNl)RJ'hsIVJ>^`=iW`BJiKhTr2X(sAcX9DJN-ZN"O1#k@$PP\ %0f9;K"ggsTA)YJ4'":PdA"caZ^6h>7;3"sI6kVlukBX6&H7a2@k&.5(Ppj"B;5*DIA&?:P4Q4Gs9;CGbH_.c09kdH4VH1pk>&&Y3.0q#a1(*&ue %T4Lkcc[m@PQa4H$!_W4W*`BG2RZ!19)gSTf`"u5'k&n=V`lD&1QaZVO42t0MG=<%n8p'.\oZ`$cLDjF?UPA/s+KpMQi=cgd7`qph %R_CMBi;Jt&=]A2@nP8k>mH@uSV^r,%o5U9>,b$gN2nUT%?88q!l!a%p1""tYjatFmFb>lGDrt,#n2qfYgd$#%R#hO1-5TV-n>!i3BW453k4sI688rjY!EL0*GbgQ?^hGZ0[T1eX(3_g7_9])/K$)_c?tT50\.m#^;ks" %%dc6(Y\LP;_d(krPIT',9c7B)&W#Fh7IXt\Z`$pr]dLbl0VsG,*tMlX&0\clV1bU?Dp63m9h!L,kY)rb^PsH4^XD8saa$_^231EL %&@@0D(&O;m`J.%'``mod:CFha`U7tZ*@H&SDg^(M7;9f&-4^@E+RQ7K2c$:i0"ch\$Bg^@s6)9 %17ak/8r<;D(/"&I*"K>KRre`!b/11$@\B[I;76Z6Ik][43/+Xg$a[+T1"T"5<@"69#fQ?QGikI9!f*7"i.etZFS`uiE:[Kk('/=8 %j#jiPgEq66;>.B6X*Q*bH?E2FfLog"]5k(uL1tG#XM%$uKBQc26b;_ID$OO"Ch6!'5GX^QXL@1qbeVl-`=2j6.im@NL%7I&B,b]3+]8Bbm,D3(,Xg`:2_\uB]I+W+dGCq_'9'sDK$/;<9pV!V7hf= %XFY6G9mTSF2e0B42YJo8pZ-9t;G)3/Fu(]@l9/2]>`%&X.?K96aI^!p/L982Ym&p1Cd'TXgfS,@#22gk0'bjN.ef4l.(#I3q8EoK %*o6#<WQ'RC2JF($J`6BArknfUQ\H3OGXVW2:^/d^Cc %o9ACWhL+,Hjs.MI06oPKGa;G")?R+=jl4okR>KN*eoE2r?;Jk#E?fXp]i`ndqrkkFmJuhQ9O_8kX:c["d`R^!PB3&Xa],noDqQh/ %9;1mEo#%\r9:99CX9^r.ROJ@oi]1mJd)@8eHq %mS@d?-K+OL6H1DCKe[,n>'j]$$J:8e($)]?jsU$6_h?8AaIX-n+$mH%Wo.l;-)4o.^VeF4H2l3\]r]ug6R:a8H3+raZOdpnL]#-7 %Fe!JSoDX3lE<"8(-X24!L;^'p6D18JJk*N07AbYDh[um]IfuCVQ4S_cO3nqZD$:6ppuK:_+PfX99mUe,+ea'EUFTXi'*<%TT7"2& %8'u).7ei;)YN#^cKReL]2s_+1j1eB'\7J&1\ASgdS4;S0Ct1`XR8fEoI.V^rcf'a_O;+jg1A\9-_36b>H-Y8fEXKgmf=Ph6]cn+.@(70S+nl`na(m6+0%Kaeh5;CABXj0+03#D6;2HMnBh %"\Cj_+k:@H5$G$Ei=S1"-T^_"bD8?o$:Ajca?VYMbM0`#D>2$\cO&0E7BfC45?c=?A.hKmPYF-&mG@VA^%"oqn>&&NbT^:1LMbqQ %J[tHq7T^V!(!q=\gUPWS35hMr^b*S,dUqVEflL#sRVJ?2"kX2eaLDC)B1@OIHf*8W&hhCm\eu*Cf=RYWi!&&+6j^=_mUI1B#9(Zp %a8$RA8]C=9>Il8rcmZmnfF?*"EaOccZGckLm>0[,\27)soKUI/cXodcONNd0K&+l8Qd$4V991oCUJG33l&g'1.UiO2]k!5Hp#&,I5PAhmq=bN71tI7lOrGGP)Uk7^lP`#nBVrj]"#J^2he@:nBVrj\-FNN;3<@pB&iFP*C5dLpdqi4 %j'0N_T7e>#f<_8S$k%%NVPAk@=@$r2N0mSAO,`G;1La7M)?mejX3:X(i_fjHFAh3R?@I[-Z,/udC`@MLAl0\F84($_BOS";aq;Gs %4AKacV(afUg/s1f'um+?61N'/;1XlG'1oAK/!>DsobiQ#W;=PV)3l*Des/pq;cp>UpRqlQ,VX^/C5p\ %'&Pm&<,(O5Xt9PrV[AfFDqGkgep#HC/H/seiPBBIoWc],+F$hkYUbXHb"HSYnK@ueF0&^@emcq1l2*]fL2jr?B`H8JHa2=*hPcQ^rd %$D%7,7d%[&d"\W_RBG'%g`>Nt=bk`u&l[XG]Mo%`XmJL&Nb9JqaQ3++hs/j!2r!K+3=+\koj4e0M&/KX\OI)RBQN!GQg:O8CM*A8 %IB4^TNrSH4@FrZkSWiZ@c#p?uXrA!O)Q8G\]R9:ENc1M\3:AKQ$1)'eX6c>r-hJ %\/?(te0pu=@9Z]m\Jj6s@-!>nLfkdAmjco0UXJK8c\3eOr*!%Hos1K8GE`gGr&\4#,;T*C:!ciPC>E)HO%PH6r>8IYeBN>gL==dH %'XR-K-nm?CiAH)*_q0YihVXPJE%e@n\\`5UpcZ?q>nXSjs(,?#^b*jVQ@ru@8H_tjJk+QE7hDnmk":EJa>?T7n60&2,WnrI@_]A?0S.[Uo8=@*Q3_'qXuu,8Bu3FJ^9gi%0AbcqNT]1KSj,J,O7t-m^JF%?/9j.Jh(/jA1D_t7B"N;:87QFL>VIYca='RdX]*VJ %1AX(Wrpp[&$nCbkM0QBGb%G]W12T96fLF\!Nor'<.k.Wk*(nkJ%9m+;fVfb,/_N2o%S7P<]Lu3ZWeTdG>Z<&Z0PoK+n8*@-r>[bp %[-/p/#44*Zbq&9eBF3H-B=]?^F4nlCSEt:LDnQN*\a5]s@Ju<#-+l5hVC*Zr56*UBZuRslo/;Nh(0ECR,[6SE;F/fG0$C_^hTBkY %H&%k\M)SoYLf@eZib__QYLs5(\;a9^Y?prG0ST8F2kW?H8PBG/:g&s\4K>[3PpO!-#@$4DYUfoo7?!84[0"`cQ+$Kn(,B"#i_hV" %7A%e'>\\8VfCE1tYn/H*+l-0NafDrke^d:IY"%^8J5A-!GHbm@<'bi;A5;V6$nj2c(XO$A958q!<6JA;4ck/P_.(AbW,*%2I=6o] %mbGWCJ\"tcPsr.$%B4dc5\7&ch0at"*rLE>K>1aT_+#'LG%Ir7b$p*6QFj`1jeJS60o%F'-hUjdcbBWG5O*[IP(H1p=3sM^3VfF: %HEP:N-%*.6(>G?^prO>bC`4M=]oXUqepZ4:_"_XtXNCp0Q)s\fkOr:$Q5AK"QALF9OW-Ifm`Op(kbN%^g+@!icHsf'iC,2IoR+$. %A?(9iA-+Uq2Ofb#fmoKU(O.Sh1p_m.#-)Q0+benC7M@%Oq9-GA=&i0ip[P'_pEH7/$ps<837W*+k=IqQakQ0ZgLE/O"V@_kN)6bd %7.+QLf++ZSl^@AKS)&1Um&#k-p#YE$Cfj-:c7"@&o)_\\`+_R8%6)QXU&CqbQjt`,eJU*-d#J^=/'&"XjiT$M9"IC"Y19dd#!L$5fh_'j;4TZEQpI:*%?^TgB>bqEm*DSXS7<8C %1'sCBU$Tp2e&l-SCGs8!DO^F,SB?"dZ1Z9!/(a.1BOO)*fX_AY@g/htXN9B*"F#!0jl*ARFju+1*c/KCa %f#O&@(E%[F.bfhsgK.o1gsp6sKk$n[%PHNBB%@PH\:R$Y+u3A+.-dP`]00s8(FDu*)rsj+[n4Hi[E=DI+,8b>$[#;VeuLGn\-FT8 %00WAO$OLI`)j_Aqep:q2?@;4W1Y-mO69&atGl^d$ffoAA]WbMMG56S5]CLP_BW8[=:pfT3$QGqN)Pn3gSlb\^qY6/`.(YbpOr0N% %2E0+ea8rfLdu5DL[Fe/u@<4eQQQ(hVMk%qjFeOJEAj9Ajh8iEGh^C9R@J9]D(A;+P#Ul%u8A]XU?GM951_OQZ/9XlKlg.YSB+L#N %8IXl=62'(Oi?e>:021T@-9dhP?'k*7lc+47_eg5_4%S3n*gLU+#/nmU=d%=AU_tR4mr'P7J"lki-mQ(#_/5SEpFMOe^oMmM.X4^7 %)drqfcE=R\=ph&o1_`8j2fM[g/88VuNDr@DsE_U3\n\X=Z8H6g;SE8EEql+H79;pR3eXReBg1Ca:VQsC\jY>:-r"ZBO)\L0t*ki5;\"j0. %,?-tT-N7PLVT#,A*>4#'-q&0\Vc;QUe8\bI//SX0p0JBT]d,#4USG_- %Om(bO`)OO>[21`G[;ju7=R;IAODHbj5\-2f;!g)MQjO\=rei*!0/K9T\KSj[%rMn@p^'o8D2hu!#L*n1ik/e8$/.l^@g8>m.0(^Lrgemb7.@)0I[(&M6[^N,;P %"/"4LaBC"/"U4meCGljFesRpuOgTX_&%i8,WLfTSW-,e8oY`4LIaa>J-^nCQJAPYZ<3hYs&o$/UP2_,J%g)#Y<5[f-+iQAV;r2'(rNG!+pOe6A$7!][TDX(7t1[u;@jk'8i^L`#o< %o!fW%)!iH?Gu1lqKA/j+7Keb`J5GVC+J`$J_R[%ZR.WUL/CkuL3UR`'h!prBY$o\s!#>0*!DjDT8sJ^Gd^Ed[[r8n+d:$<+]pKER %ZUnH9[`St$s#,3^/,&=/'HN><:+@UKnmiZUKIE#O0R.1P9\>5pegZ%l8!1)Q6J(&rKUM99mbS>9hJLl9NDeL`8r^Ho/`q#`>!P1= %PJZfX!rm@GjLmRVBVX(cLJlkOn1EJ=Bia_F7QCh4N/kKO!\WnD7%A,?/<%h)i66s#Jd#plgBB4I'N;i_u_mVPom753&AH6WBtOQ3ZjIY1*"knXWXO+K.3APm[?bni^GA %IC;QJ%GJ>h`jDZeAp(3+&)(tU.qbl2Gk/[-'\k)/@!3n6JQG8PWD^+N>^!tIaH#V;k-AK'"bpOmL)<7Ya^lh_fU8Ul+FB]\gu,uE %e$.)@"9E9)Y-NXgcpgB*NeY^Hfb>^8&@O_,6h!mn5*jk\Ou4c.\pff-a*M$K%\UbA")@.""Dk'sKI$YO<0b%dP9:?A)G&Q0IhKTSj %\.ro.k/qJj'6\!3f[#]:uF?T,il#hCi61gF$lMelpaLu]#&[d(.U]N7u8aeA[;>ncH,+9a@ilVo,mmQ %I)&KiA:G-f;dJD;I;UuIh5QZY$VWBBYA*%:/]NeI"mNR&k":Ct("1_a#Ob+dOTc28Be7aeCtmr+N?)qV1MhuQdcI_fNIB,\5IJJ* %4e;3hc4[S)3SkkDB*D(]gPEQ#<\RcG_(b'8it*X0$5=3^2P+pr#sCJ;Q!fK7L' %@^EL&Up8#YhpG2J,.`CoS`,Iad>j6'FN9]p*P%C[JfQ+:XK$oc->;mUXaC!g;.SE4/=X$`QATKcd?s(6K[%h])*e-(O#][>IKYNc %_ZX`,0bn2n@04%J9Z>X"gPb0-XCDh`Zcr%.U:3I8`SBTL"ZBS[=YqIr,`_D^SCR;NoGF7\@nY)HF]XeB2*X5.A3%!k+>d^KXR;l_ %V8kh.X]'5p+1"KLDdg;M9WT(0"0TI\[RRp$9WL+h4,q9KTj=(d)t@Z-!#MQ?E`:qYDnS=]G_2"53)a8E:$oo%]H6YnR4dk""^VXF %Ad-l:8K)8(frT_J=9/N"(EP%OjNFH8]S:4Sc'$F-A)ic^Mbj&APYMDa`C1LP,)e:%$@KOq7cIt=P;gE-Esb5g.>\Cm7#acEc/#*P%E'"A;`_g5Y3sDJOOmX-c7hiPi->>J$2T %G&<%:cX.B\]>OJcZWLlTn+df)L^3'P%#,HP+2_D,K-A3m;1'eS/E=i/C)1u2S4.Ao.k(!K!WaiWk#Kf\'[#j'RtYD4]tAtQ+bpG< %H%.rLgRF7.hL&!c+Dm.:clMZ?SMWHq4Y_jkrl(&lp?&.CRu[U,YN+I&]YSRDuM/I@9 %VmPTe.9+PpOKK\A/@l9BH9La`_0L+pCW7bd1*re,nhDMfjn+KIZ"TR6g('=fV_>PR58o>M\jL^8QHJ@BXFQ73!=qbR'V7;N6`&U, %(VMj9q+`r>'l^ddJ.SfOE)DCWAXmN@\^G=.YMjS/.USY[E.*_q@k`hSUr$oaE=*TYZ_UeSVYPDmA_8R#b/0%YJl6/h>ra(O$lFs> %G%G*-AW_t)(%h)cO2p6n'`7N/@Kio.JdfKUG%EBu^W?BI+puc^]K?\X^"eN.jXdVdMlftpp]W_95(=1?MjNk\c!K3u+g`Kb_K_h0o0PdBpE^YW#J)+?i!a1>uO@;UimmW3A3YS$@="?*cO,_O4>7p0X%FJ %hJ%^mNY/P=(_+HgW3F'DN-Zl,Ip$8ddDn&(9>(;-73H8F1^MfTOW.8CkK`R54?kVas&Yk*)AeBB)@9u5mbT7!XeE>%#eiI\M(0dml530p8Q%_)-@943`EbA.,!]Pfb1CIF/aIl\CqZ7bUJ[\10JeT-@*3](tK./k.hA"hp %VQ_.kVijjH*T?30-F>t>m&N^*kG1&'/oZ47$s+u,3kUDQ/CpH`R8.G9:X%HX?I':?CC'?<@2Hes76WcT2@o$.6R"n2mbAjB5H=Y:ANS]i_nhuK_n;abZhO]cLAklu %r2WS7QajSj%TF4f3)-;'b$%Q*ja0R83)/9j"#G&i5*7btP?u0X$_GX8d6_Ss)\$AI9(Uun#<<2.i=ZiO\US(@gNmssg%*"[%;o^D %9ghL,/bl>QpH7M6VjZcAK:!lH=1gO_g+s]n;&A>51EIdcj\N=4N'pqceP'*bRg,]W3R;oV1@:E\Q(0,j]I&lDp'19"2n6WlBgUlu %C!k=2^VH+@?I'B*KtY=I@Y9"3ZKXl%,8"'\%$qe(#.I#?ggCmhPZu>D=5BLDL&"hZDfBX#_9K#NpK=Y@QrfSD$_&)m0fRTd.#AVo %GEHsAdDG%#ZG+VZC`a9KBFEj&!E%'_ZnNRP*,Z//_X`[cF0WU@[a$FsZIk")I/C#eYq(aI=]p,`f!Hrc^K=X3deQl*go`4-An<]L %gU&Jh^W6ja3#=d+CE=Jm6rG-B7IX:L20sj4lg,t"ZU>TiRJ6Fh'tQ@uH::,N5NLP<(k8R,`Y+q6`QkSud@Bqc4I3Qcq06)f!20&IZ-dVqqfs,,4/KKao`-jophgZg\'>F$aY95X^j/i?gJ+k\)6n7< %S"5GUoGBc-$F@oeXf00>#Ao6Cm=X'=^"h.T5!,P*4O5`B=N_"La+R\V9]^rZAdC+5YK,H?A$5&?Z4A8&iB!B[.&s7?UHlKchmNCFQB!eeb6qQ$3r\><6W]S<* %(kALkt]Y>M3;CAC4*PU't@D^u8%.*bhr5B#q62_>Ek$SM^TOEFIGh2q=5eIRH %QZ-pGPDEmsH0`fE_(tAn<^V/>Ln]\*V]bH3Vt4.Rjf7heDfU,KR$alJXJb3Y@=m>D958o3nRY'c&'?rF3)Fkp:*6R)\7qV!o(sJ`lM*Xm,k:LLIfR9"i]`5K7X[op`Y!@on5&3Hur=%@K@ZiOaU7i&qB>]Y>ms"BVU.YpPHYk949'`gTa)=[.ld %B,:t1*URLC+H82m/Ye33^Ru$L@2]N^caGEC8--Yt1j4gWYmf+O:m@a,&%a9bkN[#%_FY'JZig&3+Dbs9ZlNsRLM!-dFkfg:Ji7YI %DckiSoJALpf.@7A+,gFue(F1P`iq$Y@FJ]@(8plaE17g]m>2B$](\YI(8ld/"(NPM(:J("g33=K0d<[%/3)eW$IL>Z<&n %%4[D?Q5<]R@8#X@Ol9TX$)8!j1tKL)iPmRChkDt$;[3+ZN=G\5i#)]d.SOgdVF@r1'I/=2SLQ"sqa-!iSe=Wde"XV$WBuA(&g[:_J]#`C87?eIcUb-&"VC!T'O5a%G,i>ZL%hOOp/nqM?#=F_@;5nN#X(1:Y,pCm %k6]GgpuH;OP;NDUF8A^pdK1LRq"^A1d,@l"ZZG$,/@Jhem"d+o-;c)F7hU>s0UM<_a5]%I4/_u&K8$CFShn4)bca6e^8%/@B9JcYb!p6`#n0Z)Li6cR]pW %/92?NXjeZ5UL%st>*t?cp<:CJR=u\R'VNC.X5ap&?1dD-j?$XK1=bNo"b+U(GX"7fqjZnNRPOQhQISP"7N%PN`4S<_qI %L#*rknc@Ujn?HY.(4Wg!d(pD+P8Vech2bS!+c7/eS[\.e(?>4k4#I;oKn`?K7h(F4M@0/r/PBMK1q.!%K_gShB.>_1AcWFUT)Mh)p2ag&ND'\=)eD#jd%4CEQs!7o`WE?p@u'4.K`;ErN==/S%-Hr^6+/+tp+IPS8XtVp<>C0:nonnId7'6gdIZO'8#B6!YGH()\*^dd`S#p\H %!^4I/8=U7bJP)K3M:^)X8NgqD4RcS:JcA#^Xqq]%nOa2NKYObnZ5[&]pVtkr/iM?T16KpEgnpX,RtQ0W`&e6;Q(5)'6,]"?#c]mB %gm:Pb&rqtCVuir4E&cs4c(_aS(/8U7l&\EG1D"F]??:`)2WUc(OHC)l)QQ %*Rh1dC*6n\(Y!(<;4NLahg+MZk"5i#O$GI9*N;$\Z49Z,PAj)39-&_L!/qNQN@Vh;Ki\m?2&YeT*RFb@2);\`]']`BEaQ8K?E>0RXn6Q[J %P4M3(]Pi%uOH=KsjFd%f[P4$gmtu"mqQe_GFBp@Y,#uE'd

dfpP;8e/)UEAb!$.Dn>P63F`\'3boGo`=)89`?E3AJX(m$GenAj %LJHbj%oeUPa+6]joeKtTKD;^3d0P)6-VFD*#"om=n4+i8JPLibg2/='?sN)`8a&aEdWZU%fY.]Q %Mq^V\%e)M@8tMAFT+X-@%hJ:$]&+=N`MNC=IZrqVWI>2U,V0=$4@K+8>QV-FA*!^K=4_JSB9_J<)%S2&P/(FWe/9ZUHC%-;i=+P.goAe5MR&b8j?jWh!OV=*j&W(8r)pVAMUK92q@%51>73E6j)5;6Mk9l %^0ICj?R4-7b+r*7QYd5,m;`c/%62kiJKcH#h1L7:`X/ge^'?%YI$_0"LpkDk7!.$j*icj.$jjP'1goB!?kdR-GA1t&Dfntqgtm0= %,GAY_5Q_5M+!e3KQpp1_0rVnE'P=^$I.fg%6pq\N6@-s?E7s(^[W#.^S^[\i(sO8.Seo;6 %!13(IiCu7bIAGV4VKfN4eP+rKQ3WB=f4?i6+KHE5G-/#$'g9\1R^7=QnZL'JJ:VOP9Vj9kmu8u3BkAc)EAi]9 %i,(T9Pss(N=LdZP046cp9SRlZGlE\<%.'!X44GL/`hOFmmH%@)YNNq,"05L=G?o#J$Y)$u2u)K7TuK&42l1*fLbuF\rW-]BtJup\<=aC9_Qfg.@QXXXql[h@`FF#>)+eK7De. %&[_oiV:s!oM*s.9bgZO:$Z4"U`$Q4T@;%"!Vr2)eLe*NL>SV2S;6*hsmrhVbhkK,[=_jh0Ms %IVV1QM`P_;6\`:jD:,RF`/SsJ1hTLO"q3PB=XRb4)r-o>64P+2ppN@S0_7k^?GNd(\@8o_9m!j`'HLa"$,4Qi]6lWehV`"X_??#YV.d7FqL8c21"[bos%"1M[Es9WmLFOmh+fbd]flK== %kpp.*O$Ws]K@5+d.)7<8PhrH$mMH@s*7Omp&-X?N@pjA$kEmmQVFZO8"a_n:RsR^do<.)dFRSgQo^!:%X4pgLZ?Pj&5P?C!AqjC)HT<%aOdil]`ST!+_cL,VZ^Wp_P+8(k5EXiuqpfA8Vp;PPp8R]l-Lfs;r)Z_S-U]qS0Z"p`G+Bh-?gj,5hC: %)P'h7SCB\]WFFN$AC'BZ[$#bie..h>UU-8DP2+\HY@paYa$jlBg&8Tr`,X8:_Ir7#uXC/_*LOLEW-]kLnt&2G.gXd/FBJ/b=A%kcLMh>VVT?(R-5Jn%l.AZn5+? %S7/>W2*k/4W:d)b>NO`t,pp/R.SDOn\$MkC2\rd@]VB8,Gh8:p"bYQm$T+G\U1S,mf'R2I*A>aF4S9=]@)PrMFUc\YfCH%2%,VpWA/XKZ=Q(?d&m6.*u9(,gO5[b.p=a8r#tOE)fgL_b/F %_/B:LnVCKAdl_kJ=5o)bh,Z,LX1917#m^c!5?"O,3i9p>JuM]^SSq=#A!YN0G6AV`/od`B(*BZ5l:"6\LIK-bX#F;lOb30OWjWQ+ %&l)U?R@E^R@g>r-5\1^3fX.in4KPc$hf5kOY\@%2TNLN&!48BVZdk-]/n^AlY[2aO7KKF5G4fG&IBbX`rqOF_!RQQp`5pOj77g2XJTGY?)KHOL*J67>bD9,fT;e[-c"F %Mj;6i'5`t8ojJ'=?EP4m+/gG=cR5]t4;$\*Zi&uG%06Jj;lkS!+_Yug#c^KE@D5YOLJ %cT1I7+.osM&sCJA7ZC9?$4"l9:H==5m7r@.CX.P)UVgT'6*Th7,2("fZdA'I3T/7eEKQ%4Z7uVfZRcT$-mNSQZY %Q7\#I)Tn-J/IY2h+eE7B>SIE#e6f2KG"lX3B*_b*8W$a.ancVj3"+J#$P1,.SJ!er:7?:5qgM05>W6r69Um(P\GlXGga%-/(MGau %3Y++9'A:a,IDM$*:\+4p=o9^]i<=RKoIYc7#OS0=VuretnbDEi%283c`YS$'_U]S/In;)koMsZb:GZ16LOi/3KZBRri8&;s$LP"rfBSTHN[_h&CPMu*0>l&C+-"kc67jD %DBjt(omo>N*!)%2o[%73O8Fm#lH^cH,pt)%$M5m8\>?0s %'b7imTe,@$eBSC\`CuIcOZ2b0rb*dQ'aN@Ds+'F:L9omt3r;FMZNk%2+%-lUK'n:-R66*r"N`ptP6k=fl&:(b_#[]+6l(=bbr"Z? %jbl6Re0+'IVo8g#/Uf=(ru9$'*"C[a13$ib"kZP[W_oWMR*H1Ut?$#ho?ngs,p%%mcJq$f>l6afmM.YA5R+"!,k`ugp`8/'"=f6T+N"Z,e`IQZ`/!/rFBT*+p6njTp]])J/uc]hd)bIHuHDc\N&m4 %3bte^/EICDgLQNW>^9Kqmh^"Cmd!I1d)#4T3uEuj1^_onH,/>#kf=kZ.&ri4d3t5:*uMk@Z+8M=a-AQ74\Ze_CSG"Kh=UH(&T3+8 %%SMiFIM>n0lO<](N@H42-MjK@^rWqkeF8"i=u]^iC8c0iTP(OTE8mNgdtTT]-T:h8?i`2/7]3ePV;9&TXV0V\rQ?;5^JH0oWTO]WVWe.%(hdk4;`%k9,dI@jFKjZ/*6BmurF^c:s(Z+SE(jO=K]W!en02EnU1$sa+XTkD%b4mRN,Bg,=VV$CWNB?oV!N'kqf5O)BI %L!UHW0$m9AaD!UhF<)3RT(Vr)N)tm\U,(Cnb(2sJ]<7kRG0>gYpbqS2B"&"3#d%Z9qZ\9o%fN8/!l-gh:DI"]66sb(gbq'omH9]n*[^m8e2\<=+;a4a,8# %juIG+E>4F@okG$ZJ*I>tX11-nbP"juf-#Y4la)*Xj?Ys(Qg-l.hF#bDSu8+4PT,F6f*pqYgM\.9GE!l[ldH19%$PEQ?E7mGWnc[&`+`6OtI'ZeNL3#ZF64S0[U4aCep]J\eY %/pC^=5%ZhIrh[8\S_orJ;i<"T6qWb4mo^JZa930JER%+RH/,F:Za;5C>Fb'j4mQ,-W%d<@%M88m`oEc4j\HNC/`b%%=#bBe=oZN* %lR+\2]ouTN6YBKg2#R-s.\`+gQ]mW&YKqWDD%CUJb"f0r:N$/"[LqlbPM;ce,;gW>:s>/=2K7),4A2>Y0l\dQ:aiWqSVf5FP!*eRlWHrSH %#h+KSka!\%o_MJdp:erTp))RQm,1;%a%d>4BWqtQO'03*pi2hed!rJZMX]W@-/$9a8S"=oR/O@)iSGR0Zi?OgP/oU9^G=^TP+pdX %XM1Rr#;4+\QR%]55)q;3U`kj&pRJ8dQh7alP!m;-Y)W_qp$h+KaL%Ae^tU7W[(O[NXM?.kLsP'A&D$Uj4#J_h;h$,n&`g^16O4HNu/p0hpDlZ3Y>l>!1GY&'O)(/3i&EZlOhE?uNM,a]8dd/(D$)[jVJi %Jmpl3JQ%IM"7pV2*F9_U.-u)N_!FKE4>PcL.G1`P(t3VW#M1M8FoZKpQCL=UsdW %/(hMU6?mLK9@A$):]/l(0V(N\e3hsq0+M6M#'b-M68P@cb(Uq0+5PQmUg=B1fpJV<.KOl`N$pX[(F[6 %,BtqYi@;*Oc25_JV;=!p(@%oirt\]-OTkneoILbKZ-M5`_-]A3KQXZE7JsO5f$Uq/D=7Q!fe:KDP!Em61gu\>6n&P!1:_R"id,j%R7o@+CU_TbFJDSQI2pW*ruTimOCedBbcRIg((uMGdA9taJ2s3kGWuN1t$>VA!]";+eE4A3!`_2ScL*S %5*k:F6lJ0I8[MFPjKr)d8/;AtagP1oM2T5:fN4'>(Pu?9b;uHBJh3%0#/Q4U+BfQ"9^(^cRL7C3Vl!p+#@Xr(%5/'`Q&gZ^\30mN %]I;.5^p63Km5toI%pHkbEH'749q^X>O3guc4:(EA5:mA8Klt[a4/u"I4=^o_im3a@T\JO-Rn@>4!Eo=(Z9ZTBRL7Y+-^9>8.-dMc %WKWN<2Qk,>3s]$tOX0i_7,p0>,+7b%Cf#e;`^QB9+P9@mPf'nV1l/T;!_3G!T4P-`l6[RY_<4'o<#pX?4pQE!`N1I2Fq@iI2k,AG %:;:H85n.C"?QMmB:_2#_&\K1&jET$D:gE^^4/ekP=:I,L`G2?ZA.uqfQ-c6iY>@USH#-n?HZ3]U:KLLgB9@/@SS*MT^lAXI0"ArX %jUQ%bU-MSJ]l\rW%jHG,XFm`l=mT=0m[b0+CQj`0H17Q\FSb?BS;pRDtc7lI\)U/<\-^FOlWUL3PmfZM%afE=[bOP&=k`]+U_ %F&kPJTs&C%4%bN18/H`&ae,5;;.gHY9B>jsTX6*Yij2\lKbjoM`pFL-)*m1N6R_FEeZ%+fgJrNj7UKNLh!!`^m+GraK651pC@g2e %`Ns@#DmRja-33p3B\*-N3I#`G\S'M7XI#Q#Zp'-*i*sa";uFXK2kGY7QXL1V$*,iYS48uI\*_K]Z[NTe%5PeXECtS1Ti!hNU0B(4XP2X_PVdFibPln,FaF0 %+BnY#O@MB)J,\GH,P@p^e1G;6G/`53Q@0"X3=f[?3$M]Jp3!,Ya=ZrrO7d_U)"5N+Z8AZpBOa?kpq#5oop.p3RA%Yclc %0\fZDqPbW4ZX961iC/'cM[*X;'+=(iCnMX\fd$;`(ib\iEDF^"?KD9W? %RZ2YL(ODM^;9B\;PF`QdcO.%?fiu+k&hS(DE7:3jKU1IV$kS67W*]uV7@U]6*qUXr&O5i0\H3$e%lWJsc4&8I&o1mj9I.r[Tm&W_]lRgI2B<,]Ung2Yo43RW,jC%_pF:GDni\?WMh1.#K(Wt\S %1@R]`[D)9cGDGkG^BZ`OeQGDALa6r$MA,$G.U'GL-F %$7]-pOCVu'8%^o?"ZHq.lDVc6muIBqORg[_L3u/+KHJ5L1ghD9!prpO/N2h-f"8i8!=cV[CSN)a"TZ&1AI5"01k3EZqe#e0?Rujo %SEJ<72e`_Cm6psls((^uOk_&M0oVApOk_J-SL3i!%n+e(X/"nYF^Vb&'8eBDNJ_7R\T2M#Ab9n5&$n@DO3,bCPg;X.AnffZ+_tq5 %f%Q#lPa`ZhdT..>dM7b%Q903Xgr4&aXS#q5XkVacQ`5PbF5^9]\VP,P=2MnU;K[&*4EMI>h:_J&Q`Z_B3m]j"YdKaEmO'biZb7Udd+qW-!qN9277?+sRu/F1ZMN*=:G2NjEhV^]+rRPGT/CY2e-Mi:ELK@$k3LQk-eD`"jQ`p^aub*r %UVj*j:()aC6AtB@'!jIW\^nr5=T[#!9Jb;j'(&F/9T_MoSm7"rEm7.^/8fJVE,KOs;&4m_LRqaSc\c]m'sW$W54Rc*9<^FARiMo5a.?=KN3"2UVrA($IMlRlbl1V/(!N"7F_dEPgFLU.(#SQ2I0VEt"e3--G %ok=S!L_^d1E(P4u!c?PHg?/cQ'b],epOLoEn?QGQP`BE:[/[aaEga766o3LW;VGq_Y5U@O4]G16[(F\D6S+.5WDq*:;_4i#+8o"0 %jKapjQ0S54iCASA/58h�"9\."3RL=(ipL(W_`^;mtgZfW[K((VkIUe''LM7_?fc(VYTDP8"hGo@$C>gHotZ=/K+Z3np\5-2Dt*/(a8&IB54'&kC+lW*SH/hblRmDfZ>Y.6ic:-Q58Z>Z>r'$Zb& %gM23jEo3pN)t!";47k'E5BQoS]:RDocd78kq[=8<-]qQ-?[K!<'!;(QiHFc/rr,ZJi(oB"k[HC^]m3CR]U1p3&UAE.cTd;V.G&4e %gr3.HChY6L-qt>rGCYJZS>bFYNGNQW,j'42OQqm0`FrFPUQ]Jm*Ws7:UD@kYX9EM19rl3d_ %CSU?fV1`,UiLSoInE4*1K)1Zl#cIQcW[^3umPc6VIF=/i\L3(l$gFueNh$==ipa9(4_[FPP<.sNh&BNNi?e6CFLbWJ^sdR!nnuS/ %9o1u:Scpb9fp/5MTg^S:I2S<2:Pi_moeTe2F)(Z3E=L_uc]q.P]_08$3f)kP8N[e9r?9.o<^Ufl>:XcTQ=^Y6okhA"DgA;:pE\]M %17bm#qtf^eU0Y5k,>3[<5]X;J57>5SI6U%'B(l=LEH:pmk[T^*Q[CLVI@Hj8>rRq-KD(Kn'=drIdjJHDr*ic=mRS^OdRG5Dk`$G7 %#TE,=q6;oTR.KBK_YjggHkV7ER7lC$TQ>#hr8?mI$O)%OUW^nGRO:f+m;cOW:G24qhe0ZQ0\fWVO_4QSeHLAlIu74&ghbP*L\LUd %P.Nmq-(Z9\B$%V_^El]u_bF^S5>/r9Ifj]&Z3^Q'j(6g50?T/KX'5Q7;k%Iii4AiAMTdH3RQM[3E*N6d6.iZT9J"]ZqO+b\/h_0J/BnG,F %p-pgK%UsMYA75$W11,>PNkWs+o=B[@gle`7:QF,7CFUiP;)7Dq-3MN:2\KUrk.+#Q1pp48Eto.`pmlECnms6D-gu:9*lEo-742S5de? %jdfU2V06Hk2Y$@@19!arQMdOnIlLI%.;jEfoj\d(<9j>pXI&J.f0pf,'gh>q4s274f$D53N1RJIDncXG3)%/Ft3<9$FU@OoSr3:kT#bX %<8Y!:TC=E*JI9%ciR+!_<6Fa'/l3]QP7<*N7QpQU.W\TR9/lEj`P^$d\U(iOcWlUm!HDRp;G!b8AgSIe<9)"P%1s=7*9s+phjG%T %19%565Vf/IXqW55Ci&(+P"_kBdFU1R=HuSRmsXJ&%bX5(VL.s22];+4":g!T?M#343tJX7.,,!GmBAD^#@0i?%0UiVQ'#nWXrG9F]KsR %=dk@nh4=g)fNhhOOIY)/-%ErKdHTh6V(`DAedA/4X;pL\XmfsjjR#nFE$SWJ?3;'m;hE5jp6.*m]S;re6m:5qilPAc.\&n!]_7!C %G^lsE92r*fAcMGF7\V];i+DjsAM#A-,.BBjn3JneHVXhF,!9BgO-b<%j$gtX9g#C_nXVHPh1)$531Preho7h^e<57=4AT`a8cQr< %QCrMO$a0&h^Lj57rSt/P]t:'==^t+Z;akUKFNr(_E>EGlJTYDbK=UaS@W=QVFY@3j %7F!jZ;@hk8aV2D[GIE9^Bd77uj)+Mss*+8+MkjnMV6/'bT*Y=DOV$i;@/S2&jbcP752E3jLJ"#qD4s8'U>1)]SY %dl:tUECJooGal4bA#0;!p/,1kCYp,*_=8&HWn1IK]^r`Dro7*sdqmECVtIGgkH52e %Ok[:Bkr)QZLMjlSK]E>G13C0&q0U5%oGF/@)T6^cq+keqaN]?Dn:iE?rJSTtXh-Wa59jh!@G4.7-FZbE=XE/$G[23"O)pB*m+ID, %m(O(/WVTE\+`N\X"CVfkO$=<9?:0XGp=<>s].(<]?H?6Y\g]GCS+*],=LQ9aAmF!0"^@W*QtdY`FoBKq!,+6N#1m]0bd2CR7QfPWeAj/$O`S&SW;[)lhooKkb7.Pb`j^_T'!h18SK:B,_0)hGE%&tPLg\;2Y %Q!M*Wp6>U]me>80jBd+MW&QGcm%"!#@:-b.DIJ3%:DF]U3Ybb:j.a#PV)T"]m=CIj@UC%i+$jI_4fQiQYh9)g+K3f8@Y-@r=.so" %+?/^/;Xil9Y..93fb3^-F]Fg!Q^pS&arNd;q7g\Z6u\4_Vpip%a#6`h,9]'o,@5E4bF^[3N'3ePF+<@-5Kaa\^Eg=7OJ'G`EJAZ4 %Zj068<1e]s\e/8bkij.^cd'o8/G7^YZ;mY.mZ'39T7pb54\C@ %.gErBAa]*Cq7oB'c;T+f?tIr2JGJ+-Jej@r?b+j2?c9^-;]@lEk0#boih;^2D)LkG#=M2^I@XH&j4kIJi5V3r>l/]9`7"p]We&EH %gt?Z:ZIkTbRr*M#0!^t;^Vk'KYt/V_?E`64\cW*gR*3qM=c>_8bOOa(96)70=/uBqXqRDW#C2btI6alTlcVL]:KDG0f4[3Xhr%:J %6]9Bc#3GM$adDX8JrW]Vpa3e/'2RF4?:,DCI&g-UGB?5e27<6bTCR?%?&fnc#i-/%8k6&TpZ!OJcNkP%NP%/HI'2_:0n[d/cse=&9$Z6e)1@EYJ_&hV %C?CDClb.>Hqm)92+`BPt%Ye)j%mKIdC?R4u6$T"Er@^Sl>V/rB<.SYT%.,l?]=Cc?^#QRAHF&M;MS5!NdBmi*0sSjf1Ch!RmRg;8 %$[E1@1L:E+^_iE&])V1>d*_FTK-km'+8U*I.K=M`n1N3R^^k\'1::;jNCp^s^>;RJ"XuZP[p)$t-sh24hWup)"C!Zgp5EJ6'R(Jg %4>O1Wk6HlkfRA;E_Eipbs&fWG:Y`HHTJ0(Cco+fScdk04!\p/V8*ErjbXm!U<$^bV7$?q_M;j0VXsT\9X.fiQ.[^[W.RT1JR@jnd %aX&2Ml$NcuZhZO=4+/0C_kVY@cQ&haYS3dgk)'AP+.$tS$\*aD+a0BiDek/Pr0d705aL[oXCAuOo)]d_)P!0: %rT?>\@^IXgWuF9cDggttK8*NS:?@Y2j:NAC=>aFs6T1mKiV2NX-qne#hLbd,GE'(NQu.gn3HrKK0;6T>Q`N9`Kt5#96VSU[!oOY# %8n))#P$3?L'J8S"cS8L2$`E4D+0RlsiO_1*EAr9(GLKCKK8cNlmu9VqGL^?B\IU27Z00p*+*%sB75pAjehi1E!@q1^.?7d\"BA0a %n;KK(n=^o+,tN!.O1bka_tOAr#`,0rG'/_[q"Z?K=Z?)"bJ$.U:@cl2 %qdFo[89RA-K7Z0/FHjL[7A*3?1:.mZMI^FMG"teab:FP+MH>N1E!'5++8T1>MK7=d\\=UbP&n)CLB0_n"&0!ap-5-u1:6q*fRiKT %%2OOEoMV=)fMr](j_9H];HX9>*h?t*(DdRUPZdWF.([!\Cp7Rb=0esk6-?eG78o[l5W/;H,fcA]*VVT;J4!O=eUp1VfI_)o9g-o: %[LYQWj^,#="%RS%$WgYQ1WM.AY3^R$k)hXF5!1S:+6a)5p"`l=Lf3o)Y;r+ub$jH'ebKX\Y8C5ZdG_'L^?cs5$B3.K=,\I6)i;-C %C3GNlf[PaYjlp59]%G[>Q^@#&WdN_F#h5QU>Vb*8Ycn"I6VQDD?b3RfbPZrd1eDS9F+%S2WsE; %-ocja@*e)s@QsR,Mge(OiQ&G!.*ili#r_"fV^#&H0JeJ?,]BG%'?j7?[VO=L,?*Pdq/I,rUY"\"N*FrRS.0B%4+B1rjh>c9'SN`o %h99,gq=s7N`)H$ZSa2k&O+j5_35V@-C]tp)gW+\AA6*n5C%$q*ABS9D27,o8@k\G)BM\V4ir+(,@97C=-[`IO4S^YV_MO+,?"l11 %a?^)IKV4W3;80Y/64Dc4JiB^f/6(Q?Y#0o6>FP+__KjPQ@,8HGfZe2( %h[&JN%,V3gd(t^.c^I#:)I94aS8RR%mM*!i%eY3[>>+r`8;LhAeo+d6R>JsHSB,FuI60/u4L9TEc*_(*Q,/f+Pc\ql*9uP^0!)us %Ei;VrijqTZ&TT<%/iY@5K3W3-Q2"J!K&R((0E^3qrch#HS),7pQO7V]KS%Z^9p.-IlgWB#O1&Q\o)/;pIHLN+#(FmW?YAJH'dKYcj"p,LoZ(-/hSF2d*3@ZXG;d*-\m.`*kJ_BkdO^% %Z7-RVA'Cb?I=_AG<%c0r7js0Fp:H`!pN#Eg:JQ8^PPI/K%fJ(O+,oj^#P5%snP)c?U)0r'"S3#M*#:_;U[TR.N:5I]59[M-Qa %%me.3NqK,mUWM3Tf;c3XZ88B4-*FLg#Zn'4p/+YLG+oqL5#Pt[+bqL2fWfnrO7)'R!gKZS[.`P%\mL&1&Q#(%8oaQ\>[r_NV>/9/ %is`dFjlC$;og2R0a]uJWaj"qh*ti+Rp/WR+*"\`\[CR)gGk,M<7*0nGlkuVDJgPB"UM&S2Wg+R7?2d1NH`=ET*=09(-LqGU3Ik(n`-hSu+X7(PLjM'L=O7 %!CCuob!ipjXXJK(Nq?tJ+X^MLKHOUJM>m9)+TOcB&4_QF$cRTp`l!;#N(-aU!7d"&$W&4$pj=eTpli\57lp_&3JJVG;Db?U)DscL %cm\IXEO665EnOb="ZiDN)V18[a+Zu32eKK0@^pje6p"akoKES81r8Bj/'i-a]@4pXJKDfjGGg_:'A!.@G6]+F %Vk3H>hjSfV0E8a&<2<^>NiJgbo[tCoQ %hS\Cqg0s?EpFoin&2r!aCQAb5ke/lss-'C!Brt+WHQX*KW2o'gY8>.seY&@$(th*!n)60k'%f-IkWR$lKSgpWl+Lr9[=.Zg^/qSW %PRP5aVI+^BngPMj)E#4c[Y8M#X?98g'4**:/S'UH%9;pbI87f/#N+s"`VW,SP5?F*iV+GrKt\cSX5XuU_$P-W]+V%*oV%Fcg3rX[ %6p'*5r+Ef:1WbP'qJ86FHZB:MiV+dYm2r#tqhUN-1/kY7PG@PICe^uI]D=h0:TUuBQSLF7%Vl?.d7m/_[lN %mTr0S/l$F$GN$cJ9r[5sRF(tF=>$j%2)FX4j[P]M/h\OV7[D-$t#U%(-oNgN=5h*Sh)BB86,nSZ[]`55"iAs4Uod)S8K.@Z[*`]s+"9UG5RYKuO %Z&?Seg-E'E4BtFc+M&Crh)sW$EfuErSEo2&ZnchlA\ECE\`m"4.E<_UfjX-u;\k`+s_-9#4&m]_NA<+eAiIc>C\ %B7$[a">.?^fWPEAfO6!mnHaj5Qb"VT9+rs3;`*T2sUX'XckENXT#HqEi5L%dHrF[P@9tq%IS"Z5Z"Fj %><)'5pB)+LV!o=C&=\@2/c1^4;1_+:9&R2$q8Ieif8D#J*QKm.AN@Ci;,R%(qonk!pCVl-Sc*fdD^:>B[-lE.+5?%GA_Zr>#g!=j %+i0fgcV#.S%q;p84ca)o^"f>AN8NNN]eC]SNB^c$(\%i9\2?fu&5"WnM+%Cg8E4?90`$?h>/"bN+I([p-T)V:]1K)Up1L=t1Oa64 %k#M&o@VrOHXGVJV$,(.sAQ9/L+M`;#O>0ic@T[8i%*7XT\0)'iR)B6GDm9ZOe0P%e5qnKqOE3]!Z98Ckr-DTZGUJBM/kpkF70*%4 %hss'HUU)enKPTEVBqYn9-rea&6.Y+K2QLkB"==e74f*I7O`Jfe&,q\M%VM`_G%_N(-YmNNf]2**d;tjIgh2Q[m %AhnXu6$GETW(OQW?Vu,4@,k\)PZH4U4/'W=4V(Q6FEmN;6ikiFQ,2e2:4rYd&&cjqO@',c79*F$4 %S"Mb'(:!D>B>);W>+SF>\hO^CTgdlj$3%7WN;$=WC96*ZGpKQZ;BrNZ4WCl;40;_o6]4s(kq.51?#I>IgTj8K3uqJ37ADl?-Xgq4 %MdC&!e43?Y(9Ltf+ET6ePuQA?7Cu--9n;*o!:.ZN>AASNLAZ3``tl@:7Cha#cG-oa]\1-p(6,cq6'c\Dh_o&SkVI$u5WqeHiW%6) %Cs6hFYZi#&44(6$j/ho_ZqfPH'@e"G(6,'Bo)O8qWo?]S000Fd%@0S[o0oKP14=)#1C]6;2);/)`oYMa3N8O5ofLXD@kk$TBr%3S %rUO,E!#n[ni[-7r>"MIu*ep7t^O;IN#NdJ8R>5WtJ$'0QDkFeV9GJ&&WbbFp0rbV!0@34q1$3bLgqPYr`5DAaH_Nq5c5; %d`cjCV4tNK?d#TpM\^M0%CPPW[qOu3C.R]cCQ&06WIW@&7H9n9mRrnaU])h`a2tqtlGEp38ASk?ArD\E)"dr`,^$lq/K.n*I>bNa %C=o7*1bn[aq&5"D/K2=-+E>9H9Hh[f6,!e41j&W&6(0"NU/B-Q:7@nkMhYD4rURY8>I:3OJ7krIGGpj?(g[%:4[8%7>O;/#!jf;W %dCHc8n79g[Z#bKQ_ZDnpT9Sd@m]5epl6d&_@81C=)K.V?>[F(O.!(.=0FOF %]??VG2cm1@LRLW=HLpXdkTQ[Ys-@00!K5o/ku.E'9YJ!B0cAcDKeSj]Y8:-<2kS+92:S+r=.=hk9X3H%pFWDrS,63dc(W;" %ML'>dXqT=Lk3L9?kPNZm.MN=V[WC-kb_q&TFGe\sM-VZbqr`TGq)c<5n05*2hVA*FNr>(fY(*^LhHW2^F]_eaTic.aqHM[<)T0o1 %I!Von2cm1@k;dPRp#bPiju[_Fl[&/ord&X.ie#K+W-dlT8Ap"+@?8P<^gDR!WFkH^o;ZP$t:fS&_;[L/m %&%e($26]8IW7se*DNpuFXuE<6p5s"n9li:VL#>t)N2C#HbBqs0HLi]4``=\A>(NgAiL4s2=-Tlk#M^'8V((;:RNbE#]&[lY&J@"dWZ*_^&;> %C)!@)GIPu(F&MifW#FmtmoKsKRmPV`KGiCTmLq>@Pq_)knDjM?m$3h2l=B__lHKVB2U0#+aR\%aOLI2$cmgF^>5g%g#]&L9_5=rKfN>RmLL, %rW6^d.hEP#,(".9qD+]X[;a+ZnEf,0Z<)1O"bCs8ei$/rat3tOg.CMm,6uF`WIAr!$N_!('>cCH!^k:sYsmKLk]'\=UmVm/St+lI %$#?'Hm?EV;Z)&EA'5%`uL9;,ab^\4AR?rc&Aes4F0Bq-aAI2nm3B9.3U7gZGL[q8@S`Al'0Fo?E]q0[T^l+lgA,T:QiSk1>&JSk# %cVEZ$6[a@cg"nm&+c;!UTLrEKWF.LY:?$D3W8i$^a!X,U0PeumCo`CjFhJlk[cnR!-#!gYh?+pVN4Ok %Guqsh5#cKrjbpi&SYd:mB&M9XaQ;;ta!I\5bntJ8Yi>eLABL#"VQ3!g`cmcu]^>*(HCWPe3jMj]T-9QNNltf+9L?sm($e'Z8hR6a %NR<>T[.?Z,W)t_\C>4]t"f(CrV7d&-)eR%>Jl0@,ehl)Ya'*Gr=Fmn[YZA>XmNA%fd6+E6D#sT8I1IpTr`s5\fM\g2A"A=1J+@*r %"`*:!a%NL5WKF_jf$i\U6_hFl14=>=(EY#/%_a48$e4DHI*lhEge.&^JR3B)e^g4*JPO91`YITs\=X?_5 %M$SuBhcMX)Ub5IH]4iNu?gjNb1+p[Jn!n7N\:)&3,b0Q_]lSY5Bk`ePMI;7)(EICFC)Bmj_AOHG:npZOW1c"LT^J/-!K`G9#S@QL %F]`8Ycrk'Q]2FLB&A"7^d&p>'I>$>>:ufH_+=DB4Z7QN-em2m2-be+?FO7%XH&F\gP_U;4jQ[_9Y=2Y!GHK0HqH^?!<7o(^:&h@ngeS>DYB %:(&j^jLF%sP2l@C>-apECuI#i':h:29iGh]r@7`WP+'/tC3]JF %$r%*"c-Z5?'Z(cZOKW=RY4Y7-%54;@TJ#(._!rM14I0LjgLe3!00WUSq@ %r^7d$4017m<[>)3XiaoOj7/cGY[F&$PSIZHh9cbjd,t>j-j:&l5SD$pKmd?Vg#^=BAr.^++AU2Pp[NR %XDR[7I^&*La):Z\lH175&nGu0S8bl1-:-88L(nkP75K3'lO9(96MY^`Zl"9N_R4d`IO@Q$-qUQHQ!=NrR.?Q!A(nmiitieN3rd+/ %n8lr!1>uss+,!;i!iVNV3nP7@Tl1gsh(!`=_]!Ju-o1,E'mSMfq6e7\\&$;k60N[Sh?kHMGeZX@gkj"-'#?-(:B4YHXaM9'B2,P8jnRR)rd!'e_C->A_Ko(`MNp,X"gNuKHr!VPk9(K)Ft=o'ppq_\nibBO %FItjtK902gC,ZD]6^(QG6)_";7>oMEK@#T/Do_kNGc75DEY(in78j"`a=j,0+g+_R?L^+gNlfn7q".0roKVOF3Ylq,9au#hCSL4: %@YlGuIs?g-ji(heLWS%NsM,S%=S;a8Wbpi\hK.,\"]u/99B98:,"_q0'Petsj4\o^;d=`2`lq6dj6XoVDZJAFdoR38=,j'AcKaAK;44ks8-;Y1K,'im_@*?&K %"nj(ejjS$`j0J*F@UJkoIJCdMmO<`\!#%V+@536/;#d`80DZVnTQ)^;psQ@Dd08`A[5>T+Fa#>u;@%*[]Ea/fDBD %q6<^a48"Tq=G[o+?,2"#,B"qOfAGJRoU*hu0@0f@Pnc$EW2r^QB!XuK+RkkU5StZo`BG*IqM\D4*kV7DI-KGR %n#/-(^c.TdHCl,<3?KV-PV6W?720@7J$UT(4YQJP]YpAU[.M")USFYlf@?'NqSq$3,Y0@brN-Q[Z*Fag.;H$0+L&tO+rCOg+PhKg?nc[6Sa %pJ"le9@jYQHR@*ZefB(*SY`$OeYf#lL!_heNQ=?Ff4Na/QsH!3_(13dRMR-*`'n(#r8W>BTBq&p'Z#9NbWtP,0,]K_.s#PW9Bu(1 %nFo\/6[O!Js(rHIX+hDW8d:dn@iDHspaaKm%snhe>uBHU3t%g3]T1FT@Yik`]qr^8dJd^jYICH1JgX3^&Z_#g['Q/=(dC>n4GO"*R6?JohClIZ-7\k2"V*-To)SQ?N/-W4(YokhdOLYL,hj`>hcn7SCg;3i]Y[3j1jdDY+* %62u5"#+8gIZoGfKK$ugB"noK!XD?_cpe'aoQ%7!k]tP-U>pVDZkgD0r]/3Dg>.-:*I=>]'7:o[nASl/pJ!4$N00T,35G!AkYV@T3 %jic_O5sB(dLXFqh?'cTCB,+A[H!>t;pHOM76'Lo"cdgb3gj51U=s'G>e!B*9L?7CQ:&%sM/4VG01!=V5k1nf[5RsClUTY3%ls<@Q %F)K6F8Nek-4OE\(JP\Th2GqC?>2P].692eYa![%;h_7C%\-oVd?ZKC+"MT+6mn5GB73/![/4(cMp]PBkX>62B`$Z*D>CfW#nVL(H %D-9ANH$gfm/I`p=FaPC=4Si&,gA4)AF%fL_+`jcY,\pa'6E-$R[XrN2ef^2Rj5(k(-[17om>AX`,tuKOfk%E/jDHIr$WcB7pbg?i %:8W\SFcjqdhm*Dao$m0_R76WQO[N:tE't/7_&5tK.[1f0EesPei:XXT%TlQOs2gq<`:I1^8!f,>1>Zu[,"PIU#Q63&!u?MjPh"VR %gsI,8],:&&]3Xf0![5Df#7DgU].Q[Q%3FD>`,`X;JLeBVe8i@1"';'EU>Ad(?nn=f_m-'2J40N@ph3n8/EL,M3DJXJ]gARJbpI=d %ERtekK`7br.3?f<=9MnDV0EJ]0qO(s4?Shh`H^+4GfM$<$k^Ef`]56F$kZOq#oo(U((P;@)0EsK@GuasA7[uGXVMBuhP+l#RTcAU %Ru2iNCO$?cLhhNL(kcb3$7[`'Eh`j2GRd&GOf)';QeC/MX<%n!WU8F_<:tLNSlE_M!I'kDibeR?*;!sJN;>N,!]3O+W(h\K)IrdpZ&'66qq^&FL`^]6kUFcG.,F\nN5k+`"3pele?#_n%d^C.4+r+,B6kYKOreG%[uY!ODJ"ed(?t#7/!>9K5t! %gQZ'OBXbp27kX_d=C3G"#Lhh(/,f6]H0NSVGDXPuaW_Q;Y!P(DL>4\nh7;0)G=[Q^*pguqD=Y-t9/]q1;Ss2QVEF+`YR%0dMS&%^ %%(<415O88N6>re.Rf2V5DAksU+-pUD=FMG2T3:6NQcGVkB^m3&GUUoB%cO7/$(!)48rc/LQf81')qY6U+B0p6FC.njhuW#*Yf/s0 %%+"P'nhrZ.L%Cb>#5Z_uF-36i)a*UEruR('dfp>U)rGH$@+sO)d.R_`U$'HHrU&,mFRB;SGeLe;oloh0f-Vp(mXEm.E\sGSN&WfjQ)7,;0m4=ON=U %>I"LICjpA3b%>c%0;Vbb=Z_PI=,Ka+/$4es:;`EX\=fYa,BTQg@"[@@."I(hIRZ %I2i)36j=(e0G\_;EXWeG`3&+9j;9S+jW'X-",>)nM`EIOOp-i'*B*$m#0]Bc@Uh$!^]9;G?t1ft^k<]/KcHK8i1O#m@Lc)gLW!p; %9TB/.IUcPE.5m&cc(5VsG<%060KB=GXV]a)bdVA5m-lb`8S\8aXJcS7k!j-3oQciDo,lHIAc=pC;cj^K>r,mX`pE7O(E"n3@@rms %32X47KM>e8+p/%[$YqaV3EaWnrR%PY-O9:\V %^]5Z`bCRbi?k1%g%SVl`F'-_=aY@05@`*a#SGpf2)H_hX#a,#0!**hrrMt1g$mgWmL+=D5Ur4r1"tn0/;IZ")KD_*&9!!.1Y14st %?DV8A;kSc)o*VkY.1j./IsV?&m1]gfb\s[M*DV.ugha:6PQXtL1MiE;Q\IQ:s%i/o_n"%)fWQZ&ZjYsJ"BiW-$ge#'p4"f,(H@rR %YNE(+/eCc4"iES5[=6KegRtsE%XJ,7^3*DH,&DI*6fm^?$\V8E$AO*Ig'*'uKS!X*Km&#&kg]mTG(/i%)?qZ1[\IQ#d:Lr?4S"MD %]7.Y@RQ63`__po;\`,Llh-oY)CkpCsDJ$.bfZqM)RhSqD(?GtZ_,H'Vi_*]ZFq.jG,XQ&[&+0(u@RB/n!bp02GB7Y`0U"I;giQPe %":)=2`.dmbf5p&_O'oGJ:f&bR6m!jtrPM5B=XQM1=-W:g"IB+$ZQ<;WD]!M8H^BsV$.A81DM*,]Ko5(>W8C+,cRRT"kSO+%@eVlE %)uX5*c?$0nP#P!X.VnlV5n=7/%TM$OT7X6-1**=-Z[%&/R@\"fFBn4;_^9M/N31)p*c6jj4]a93nTL\X##A&,D*HTRA9iWQJ7MBaFin&IRt&$juERl0!&_0Fm4pgINpof`4k_s8N(A7>or:+LB3eVkX5-MF1S.2Kp^l#'3=\fmeE;gdp;@Y)::'1,/3G@lum[p2;A(",=I'WAY4P[ %o4"8[fig[pFc4VaNb1YpW+sJg/?uMgcN_](qUk)]4NFA=>?n5o%t(MHEp46)dLE@dJ_:^S(85[bg2N %!\Xmq'/t1F3J:+ol2#ULZ%PNS.-?G=hq+JTIS3+PjYQDOY=>kf$Y^uI2rW*_>5T'OX%;KQ&@cY5fO-i'`7&=^Oh'ND51r@$7i+l( %R9m4r@\qpM&nGk`M^hVadU]4Ujj*Y'g`\H2/Z.WC1).X-M6[-n5f`2.=WDP4U0P)&l7Itqrk$WQhlJ]p6O-%ih6-bIZoGSiFi;mh %+ASgN=r`_4Zr,sp;R:K5G$+gEGNh')&[IA*MK;\'jGL-GmCqps?c\]I4M,l,LL=u<6'),QcMbb)SHaE35>cG69LheNc,)(ilV\JP %qI]9F38Za>T"\>]igYg)>KJVPa)!.8PE9:%%X),#G38Z,jB*$n@fB?$pgT[)_]ONfkiO:uPQjAFF[(fA@Pk(?S/FQa%:`t;;G^-] %[o:+[h"fsZl!?!kMQ/nJ?;u&s;P-64#=i?Z+6\p_U6aVn)!TB<(&;^AjN>^ %D5]n8?_84cJrV.\Inurn4DGHQ+U;EtC([3c??'TgC(W1Yi!O-*C>&(4?j19W0oL[g&%.2u\V%*s[>8>(eSDs@e08?;n;#DK>.iY" %6#e!VcP])%J_j\(G$d2_J(Ooi?/0(#nt%k3bMlr?OU#/Mj^],IPG(.]qs80ANf0">X?cID/)6HQ"]LWCJ<@L(" %HEB:I#)7pG+e+)Q]c0?;R4Wm!WeE52Hh %kU6Do:-KHkMprsb:Y,K-2hGB$FB+4)7jRO.MgZD-iglbfIsP-4IG]@LJoAT1"Vb`H_cccF\jfWqS'muZJ7`gPch;WQWSk?/Sl@/oNBQFl0&6@C]ah_tP((sJG4dB80'q^,dXIdR=7'U"rVBAa>!4!1./,`1hTbD5<(ZFdN %!jY'WBof$:fk&g)H7HI?.U4j8>u(V:F]OiB:P30gIuCUGmfFN(A/p$hjbXkW.QFo)1pbQ5rPA<8Vg6oVKr0Pg^"&ZIPhkk\0blaD %h2Q[mC8_dE9KuYMYM0OO0X4._Hka,?2c)'D3fd0eR8W\djiN6-b4SXf]q#-LXh-[^Ln,jJSJ40gH-7Ot4[T9W9tW.[8<6 %\?!uZ`+`K)bR2rpTflP&`K^@J.EM2HXdIOD089+1N>5COQtmN"Xg^0C7'M%j\#l&6jafm@Y:NI8PkUSRb)u.q"t?.Thmc*Q4RB&A %+NC`aM?i=&Jf)h@'Mf,Vq0bqDmjn?74R?ps^\:`B!rWmq1BqWi5h2i7*G)`=MHi=@2mlM78klQOC'1Y%jN-F3l`H-Z%-lD@+-uMa %?@&4^Z#<"t@f3(>9C<`34U>XoQ[Li(5!c$BOb-QQ*NG,7-lU_$=eX`X!Z_F>Rc$B-e[%T'@tiDL&_C(,(IhP0(?I5CZY1hH'"VZQ %/rZ7CpVfH[b+a!%r\@Fg"a,2N!#A9=LRK'@s!!4cSho0bE+hsK'QsbE08pOeU:)b:Hs'G=?"h'Tcq=@eMrmmmm^l',)EQPc%]_p" %63^abC8n6bWkXD_7m]WkMZ;,mVDee.r1LXE %T>^T2.D6+RH(GAH%4Hdb,)gY9A'[Dm`Y<)dmT*f=Qmb9[2_*2B<&sZqCUH+GOHVc7K#7cRl6i?.<2tC.8JORM %5c#*bj\O27'"CS5^:Q^a@W1*:A3&r!Ocs%MK6]1l>jiELnU)DWs1J2"*:jMrb8jZC-4>4^@`@3D!LjYgg&8+KZl[l/#1c/0!e2bBG\ACo*7JM$-r)=rPLP`SDS-860^X7gd?gmWJY]Z\lAcMcm$hPM1EaV\F?YmNYpNGJC$Ms*_j,jh&2K%uRuOipQ7LG@F,Msgs`jV>iV[l %D['rGL>BFp*R"0L'\6Y3D@l!H=daAaA_M!"=m_O>^TYk+Jto8_*FNsRe-d-2N&Uq_/l$o^a4MRr+bDSA'p@k&5X#23oiJ>o#fQs3 %oB=O!B>968pdI1ZYA4;"pu\7DPMGPr`*%IPJfXW)H(-F+S)A@!ZQ6QnSsHm\\.)XN$g56QH(-F+)d`D"H-V9+2LN4UOgjQf\&l5b %BTT^f'"821MhOoIEoK!a.ZMR)FG\aK$tHQkS=I(uX#mDlrg&Ap*/#YagJ.0rb+@Kdr#2]P-/ph3<>pt.kn:I>@sMVGD7[Z&%`4mO %9p`@afZ,hkgQLMu09OXh5_NVGh%Co9$A`(:gY._q#<[UuZulhG$LgriNGn;8AeTeBXa[R25nYD%J`X.j5nZHjoL?[abS/R%PG)*jAqWJHFZo@KAf)dN\QhegO.]P'1kW0e=O'37mF39Ae)2?B3AlV&Y%fL8ERE:RN[m(Ha<@X-51q]hL:G\s3UJk[%+Pmq %XED9'l^SmS#V:A;=R+BY7pob9@B!1X*.d2oCm!@A#V63h[8V\tJ]2t(=R"AtEgOYW3 %er.LB%<=WA%`2tY#.^8-K*WEAa="_rJJac.q$#nbH>:2($2TRc[>u/L<"J%Tp\4jWo'sF_Ij0;ZIO+-&jC*S+iI!b"ppp0;%QlGfAP9?6=Y-K %-."&T[;3jZa2D,El[U("LQ)ka,7T>HGbM3="QBZUm`V2RZ;'V'?&(%EC$'h+)@A10m=+(/92%$(A_O:YA)0pc!(]>W_IW<8N+0L" %B&LQZk%o!@hh#)7OBSJg584K.cZ4m)99f8IlM9$2n(sW$Shc@\TJJREb$c:U#!SE`O85fsXR:!$/th;Yobq#0a"c51]4)`4he\.] %UY`s*,B;8,e;>le]ZV2M`tl8=?;OnrcN!og^EiI)EP\Z(8\5eFZ*Qq)%;_k:HB."0KM/Sn9]r@qq7@la %O[d)%c0']A4]rAk/*=PC="uoZ,Ptr!*k5No'OY;C7DjG&f4o4+>DM<8%<=WAlHWd<26c2UD67npOF-(eO#q\,fPW4Olt^"P7nQfC %29:dA]!n>T:(;6:+)7j93&Ot:Q(/cRHlAZ1Tm`SA %G8``3#"Z/d8\YG.i'\>(cs*$8*i>N\$o?C$QmYrX-]rfK(GDRlbTQ0[Z,`DY`?CZhpNJG'N[R+oV%YJa- %D<2mV0c68(<^MPZB%flL;R;RqEY,YrN([h7^)jhs9j;adN7G;#RM+%0g<)t2Ljn%ber*:O@$u2W?S6HJ<`%%LK>G'<"D]6!V;&3" %&8h*4o]riP[T[J)mA6qhVnMa-itC'<P4bk/PCmhDZ@e#_/kEar`X._3EpsTUBSAbZFV;Nqs %]Lr5W3Cdb@nX;2BOSHldSQQZ>`Cp1u\E4gQ&QgMXi%bENcLr*iU5ZQ@<,usa;PeHO-`!#4Q?\>23K#-SC9b7XS?k24qCM=UQh(Ug %A7;UL\=@3)K?sn29R-h'#cI^RRrS]N\o*M:\=BlbH5>o)ifI`j?9V]Q!f_=$H:J*_)p>(0jni=?Q/jEYoG.'phtfts",nt$JJZob %2(7CcUHV$5[o6ar,6`ao6J("O*G7<.F;]KXpRY_CY/e*@71=s(?0\,r,R$U>-m7!*HHYkk %h50(;?gLuIF%uqPkqj:AO[5,KJul@^iIp>@p.dG\%,6$SrPfHYulM.b=7\ad0qH$XmE?g9eMH7jNF_8ZWQldSn;ISD5hhXjKWT"*''s[JU(Ga %^7q7=U)kf0)U/\[;1TUY\DUSVHFT^p[^=.FhkF)!AKcu.+feH.^uM;:Dbsr_=.iF?VO98>I&4D(G=IZ6%pDeW2:)(S57PS0rH?Cbt5.CbG]R^t6[\-0XuS1g1CP=[UQ=)CK)`DJIU8(#Ui8H\X=:t#-F&[(5jpF9.nqMK=F"'7bL/':am %kNERn#,/MR&?%,qiNAY2`Kenbe<'*!dAn8(Sjo %87cX!Id4RVl*qOH_M],05`_!9\\>i5?&#s_%;M/X>#h^o %:aAn^/3_C0g9/KErU'BJI>o8f0]*U0s*+?tNig#WrtHXTlP=;"[kmOGgi^3r0D<5!t4=\df7s%CL#h0c.BTed&cs=n0\ts %COjt[Gl%ktJafibhrD[53empR_?:lD>A\nU"t+jX%,USkhaf3Hm_pBjM4;]*,`i?gXa+P%@>FTfSa1#qggVS^eDq]ed[++e2!GTPHZ:5-3*O*?qcC$A("D<*-9T,%'KQ,P:h40-pqP9j=E36RV=$jDs>A^-g %cp?U6o3+HdYLS`HTK9dJ0OL]R!Q8A7[fu2Ol6$9BT,$dGlL^COl*k]#qDD %D"jj+:2^/&[_cju$YRA<06bo!^8k'\KWCq_>/GJtA\32! %`:D>.$/5V$&fXHP,]"9C@kqPs]lZp%u]:!$7<\qht8WL9g@l=_^[b^kZKBV<$dCIT`0#=,M:Xtd"67^H[_%gqP@`J7V60:eZaA=XCbkB;u?"FIA?0mk[cu.C" %ju9.I\N9"U>B56%(g_!Y[cAVULZMN?CV]U+'cB$eBu52&5umhlRG$NUi"l\)U4clIRLMk[:tqC++er_/fq>.N_*Q^_2Q5]4BEmn?2O;^%8(BDK]ka@eQ1jdG(5!cd<8dfBpeT(I1tM208@c$(-BaV;Zr*@Zj(VGC1e+JRk:IU$XrUZ8^d)ZQ8f@l\uj07 %.L-$-Do!EDS3$*)]5(gU=nK$7!eoMlm?SU(Y6R5$Zs6I/7i4Oj]?ZL(_F+?@8mEe(?IehOd&JqWQ<46l!k-fn>@J&O8l-*:D+hMZ %F*1aL+AB6jepsfMGn6@n&[k$]D=RQ7`Ot4pI9hoGku>0a`-E3#)AF^=/BB3>!3MPEMF-eQ[B)[!,0X57PhqC`l"mP0[noqXa2MkI %iqBd8i\#gqMT5(r>r$P)]DM7<]/p:T[6*VZVP7&(4!rIZh/sUI3s\8jpYEZJ>.a*`r],ejMeTVCh[AD+2r[`u2'`C-h/sUI$PhI3 %XPI64#WJ!PS_KKg/ %lS&UraE:OJY?Y&i&@N:,fLsJh#0#0?M)G9O0r,_t-ZBWMfuX1bl\&(XfnW %a'fHWBN,[4mK/JM2UVLYh4RkI;2Ds*%S<[Rb=2;qaop]Yc.=;ME+0k5#9`Qo+=F>U3C;no4E]X7a*,#8B@.]OHFV3g^j@bqRqL.: %LLgl7M#Lm>n\$@.:jbO %%TT\\G4Mi!Y^]?#,FW*sho %:8[6#J9I%JOZ7=mH::ak\@i8*mVCdB2Pl25IB]o;F9gS?qO/.QlXTZ%+cB`9k!^HEGmUU$3(D::\s9nd(LJH^"`FI[YUc@i1-#8% %OR'P_l6PO+oeoue>Z<":f!NhV[1=K1dn%[!2HgZQ.5]JYU5bI8g9[c_qqXfd_DYS"4Xf2YbAUZ*/I,\ng60EYK9$g-``d%&CHu+! %,;+d&\b*AYP#`!Z69_YPG+u4PIS5Vrq0m_be8L2[1?cdFWo"Gof%LAcNqt=>CH2[tlF4\d`OTuXlF00_[5W;.h>H4nW#gop0(uH";mV %+[k@6eSg;p>F9oFWI@LAhGUE90jDC=@R9VRX;H;IS7UdBO#ASh\&F!XaSsh\&>rh15^8*Di*"K%RRmY %lcf)6D,i6n?bI/Drp8q'N&)V>MjcSu:1lnIb,Mc^`Lbd4Z5,:GgBpH!L23^\<_`sD:^FgP<-)*j6(M$$SK;.G.FpfT)TAc%!mssP %,qm&l>q69O@.a-NM4KQ=']=fT+r(AO]+Xq.)$-=]Yf(<$]28XP$LkF80m*NRPm.9G[_tZ./WJ+,Lp'pA7XP!7.*O^MF0E](IPtHoiR&erf>93Fm;5mZ9dM(]:A^D!X#*+c!M> %e&/N38IS;k;J;m^&V$)jYfC+(-<:jR64`<)LVQ]BV[D:\C@k=F"Un$b4.[7][,_cN'KLC1"U#nUJC %LA=OSKp"8IFlq%TFIp\'6b:>^SF&$t&*Y9nKMHghkoh).cs'N:po0GudR=Z)gpdrB8/F937'IVVkfL;;p0,#Rni:!7+$[E0Ua"&* %e"Ss?Wh8u^1q7V3,"]*[?lQ"WT[%""8Y_EB\O6[7'UEO(Od$LWd_co?!;1V0X^8_SI[O(XJUN_4-Mg_7Zjg<*iad2tWNcsA3n3mJ!+=&,89n4dV4WtBfJtdd- %%83rA`H)!N?J1?T8%'^:Wp,qTromea9U-cED!U;tk;etB+YTFJf8$?"Xm";h/.ahC@-*OiBVT#9L=mVN+E@eV)ZtoOjn$Y?2:+;l %G039$WI]4e0tTe&WI]Neo8sr'b"l;l&34tN6DT?%`u#9V).5SK*1*/"%2,WO@(TgY9^8NB)4_Jcnsr^Ec\WAaf>/-n^$:B+-8_<"qT7O9-j-\stMi5V[0'Cr,.?1Je)5W[+tU:eiN>[Uuo; %i3dBsZD3,&[T;WUEO#)/8U6\sRZs(=$a!hEPV>,hA'l7Cr&%0!&ghj)8ulA-X]3_jL/Okh8u75@qVu'C\l&i42K>QcHdiIaDk.k( %'kYe0YaQb-1H79=+Mu0]P/6\MP*kFLN\B8!1,tJ1/:&pb_Gb!6$A2XMjE"b2ldD`]5l=khpf&(u0On-"b]@2!\t9VZKs=C,nP'Q@ %?+a%fK9@.FaFXoaqNB0YYtg#31R<8Zfh7p^kR*5T:sJ>hJ"a`Cb(;mBW1(Re31T.Sj29XRt(l'eOlBD:sCeb+Ts9+6lN0L[sQNbb2I?d26)ALYZAX]rDmkCdFR2qCGZg %^=YA#?T5Bc`orq?FGk@6e.PuJ&dHP,%gDT[d9Fph?QPJdD3e"^"mj:>s:9i4se^c*+sC;C@K/PE;i5C"7p'tZ>Ad%cWOl>6$rkaJp?2ac3P$nU/O$l1-#;2i^)BW %Vj.l*K!i8k%u:JSQFo!Q&eFsS&,m:5J?NTR@YVde_>1FUKhC;0LYRL:[&TO5cpeCMqBubj,VN:e<'>NdE/&fcDo<(X^#!FQU!]UhQ2t2J,$/e@5 %hq38le,YNIp^Kn`L5$)4`Ga*@$Obn2a):]d5;r`2VtW6]U-s6h?:AnGWuqj.rbQP/ec-in<][V.Tj^eNa+KB,o3l>rNj5>DO+h;>]"S!D%=s)L^3\UMlRY]m@W %46Tj(Q)k_^#;)[6SsdHh)jk[G?:*PrKjQV3?I:iD1K(HY(OlA+k@:\Oo=?j,P$*-+\V9`\a2n7Q0\]B:>g?dj"fH$hRV:YO+Qn$kCBXGN83/\%rtK`>f$V*MN]nkn>8?`D`(;;eaFU)a'!'- %R&\rUNF1qdVHJ-gqlC?FBd[eeomP4Ydk&rEPce/\VV.X+V_u_npC!g5puabbcg %+.Z]Q(Onq#^Eh67adukfFGYWmTgDA8&jMH#0A4Z+Q3r[DY!?;4<%aEO_lgoIUerVCt;NNda %kdW`PPCi9B&YsQEHTu+?cjg(:i@HNT`eFV;1^d*$;o;abi@@M/jPl#.JJM`+B6=iTEQf*PK%_!D/spO^0DGg %XEEC@fYRt$>D]X$XnonfXX%$W_Sn=)RXi;r.VkRj1H#a#fa+4;Q'I-lMtOKIJ(fnI`mZPh\C_O4@F#3R=(32%EEGcVcHXkCEZgnC/q8?lp&k'p^PM^Jm.Nh70c7=U[nn?)6TRgh=+`kj+\3%6;rXJf,"N-Ko6f3;F9X-_66lc'(U`!jA"X[U %8.8)er%U_NGFq)&MQnQ=P4F[>#8KnSnMck9;KDD)#-Or=]&8btT&s?1.E=57Tro:'OekWAFGI7*8.>,2;^s6j %dDsL4J_4Si`'?&1kBoES=4/B@\UKq&i,I0Jm!&TN_!OlNn5r0G[f/%3R`lq+#P=`N>;$IQ>BS2KPE/^RICV4W[$\=$f2"\T)K=*S %O(m/+4X.",([mIC>IJ&p@NMYo?_m+nhC!g),"#4)p@aB(@,E>8WmgoY$t\h]1>o'9.SRFhEKdKdo7-bq;ploRd.c]A't5GE'#f&59(XT %1gk8m0f^t:F_<^"9IIJpS#F4m9HSVOkUh4SnTn7;;;D3F)PF%(n(=#&c9#r)IDs>RAD"N`Mm'oLb*FnP)HlnfkND/X+DV0\%>g'? %';)Xb_[lh[6J2o&'5:(c-a(21KY(?F[<51TG87_=]m93=^Y/1<3BJ/H#-N4`KO %-aiCDD4iVa""%jr_Bh]uT92f"_BmfUI`)8:4O/CW$B:Z5#[C(7PINFD=ZcV#]SrJt).u`!pNpFH6o\!%_N2Lrk0i_lb:G!@]5G#Y %nGR/^qO01ek'^0.brKkjX^o+4J?er3o\MgSZq=O<]\Z9E!V^2"JMb=VTe>#M):&f*A0Xt:kW.d\WQRQ+GE'JWnU22X)GBLGZ4n3i %FPojAjYZ@&;!Q5)F+.g:lOHW"2t\jnIJpI_J@&E2"];;2Xi5+;0=/!$>YXU8n9TK3>S;?o6pfG)BVj&[q095*iSeWlUN;ZLCuWu6 %a(.SdYT/dK4P\(I_5^_qNd5?(qcO57Rsl:`)t6oDGkD6=Du"\hgPOFb(s2h\krRiU$;f!]2*&'FrG;7\C@h4YW<,#!!&o*nXY0GRjF!RGr;3*Z3-&K-uU_%ufY$6"c'[%ufY$ffl\e %%h.=424=UOoDEVl0U`)%6)%2-Khme&97V^<-gZ#*Y%'/u&hL[Bh#jE4@#jh2d0$-q7,_E#f)qe=E_(/motY5j=4:`-?o/)s'&:pT %.RUD=-?H7D<+Jd&BLG!;RKI.`muk[?iT&LH[nlDe5K:;)3aeC/ENBd[5NDTf#99uF#0B:pj;+p(2@e0+I88>R&/AWF5M?4OR9;=% %Vth*>*jH-J$*A?q5HIF&j)r."f1"VR1ot-eE%.j4i^U\RLO%'nFL)H8d)irU7+1_%'U44>*Z3-&EuK*FH=/Q7%+[+Q4YW<,VWmFg %(u)A+b4HGN%bR/L+O("`3FI*+)a(@4RpWR,m[ohd\$WQfAU6(5?5)\tGggFe@!XP0?M8LR1;+MU0:3bk1VG,9Nt<%9*':L7(j!>@ %6+@?UMAhb_(d?67N3*@Lng%L\P-$^D'F4YK5FL2^f^/aBj\FQ.k_c\!MQX7@3g_m2&QVMG32]HY,$srIq-E[;8ie,"O_D!j^IsZj %#`K$h,^Zh]7b:'Makj\cH7RC/6SR,iMI]N(-#AcNU238TBgK1.=m72YJ\K`(Cdl^9W^uh/p#+;.P"GA#I%ffi8G:^k\HL_AU$ND; %Cdmt3@q:pnRJ_?Nm(AS7q/'GngnKI4cZ`IefHj>>=X4##\']E_gHl1VjQ[r$p7.]U)WMG?Y1_9V/B!^iJAp"b=t--koO5MEn`.1t %i/?N!.Pil%^Jb6H^1ib&YQT1c(&%AJO[f5AL*0Kc5*2:tA%nj%C\`c96:: %].u?E.!q["50NB\X<^,gs%kHW+hRae6HK&apm^Vu0b$:pYH\tkD>6:(SQ/HMQ)5+/`Ys+b:8h]jd-'s*:&.0d';E+e5>E%8-EN[e %]'qBsdZqu/GKDN^R=o\%$'bo49'AoWd">NG8XH1W24`,F'H/=*^WE'e_T6.P66eGQ_h@';NrPQZSLH[&e]3ogc(Q)U2"(U?:Yngk %%Xb?#jVfIN4``]-&!,Ms%.o/+Wie8r>HOg?g)!m,3K&mMdD]4`?"$IAEhEqXmLNSeNW/bg[XQI%4+23S9-CFJ^@j8.SOd(,<=cl$ %g%[%"/bJE::NET)*rcl;0Lft8!_nL90YRPXB&-'`(6&U7B![C>&=uBAq-:9"TJ)K %C#(\J-BS(o*QASoN?=D$eR:S3:Z_glE+(LaN,Ic$5u1OGhI52dFWNO,>R-;q_JG:?+i2M;60DtH)%t/!gh`eW\!nWA+i-u\"hHJR %OZn^Q'Y9g'imm=ZMuV#\?Eis*ad(E9,qm+L!S\_=;-*V+9%0QM5W!&k %YH.#^_P=4#Y5*3?i/C)TX.Vc!XK+0`32XZfX0CFsMePn=['"l_6Wt.[+o[jpA1CtX9T)2<_+tZ%BdK2iq\QZ-EU#%GXqZk01$C)h %oCFF^IU/cr:fdM*$N/$`A_"C$-nBaP"XtBCAT]q5131:5L/gI.>*./'cJ[m=+7c-#m!e=jmn2L1HSl-@e'"f2]CX%jR&';jScA$- %i*'t_6HR="Ws,;+XRsJ%fd"4cq-jS$?^p8)IqVaXQ`Z?Sc:pM[Ml"B[.(l.$&4-su<"'`WHni&SdYWiYbRI2e]en,dSugr9_#SUF %5#Do`QE%N_8JV]br'K5_jI/kd09^#fjBn)<)T?hPLH&=4\sFr3f9K_)mdfHKBjQO""]aC%6kS(P$T6b`Uj:X2@TCmj9U_=8M/G3, %b=&G+X.R%Oq&;@LbGtaq:IE:b>7WOXK%=lM/LM&%4CK]=1'\!bg[M%cD,cGNBC)&&h:ha0^Nj.X!QfSsoJ6I4kl#pHot")JIRC1+ %:4;QmUj.1W;6XeIqB"Od7*1SG).kpID&m#rhG+JP2s+>*]s2V1JD]jhI=M9ZZ?JQMi^$g(2Jg_c7Ue?4ErD?a8*:mDoT*>Uk2R9_ %o\Pb>V?LR*43o7"o(sb'VpQ`1ETX4mpcLX!FD$*$2`J62K1WUTFD4ZPcIV-tlS3jKO`TNB\*&4OkXl\&gE1\r,=cggbb!L(r2u)q %AnSJLQd$c)FOi:78/<_t%Qo4V$f3OQBrl:iWs:#[aAm-_1bGO-bS,?`8u)h1/p?A_@0*^(I8c&#N)\fb$CL@>TY$gIAOnLsN!9RT %dY7ll7g.Z)2e<0:GY8:NRA_ZEVU?B:L'0k&)*fK>)\Q\l/&d8Hs$-s5a@IBok]9ppjU;HMNX,\07,!`1k_S0S(1uE$ZcNtp'r>Nt %/^3@tD//L90M9U(*B`*VQC2YtV(rQW+/t[R8gTbeI_/.qeXmS %8rb".`FMrBKp(I>B>MQI5JDC&QYV$[8VgafODFaW4*q>'I0apDNcUo?!eDti37mf+ooc/<5%j]O>],U&TR/`t66q_+,\*)WEIfmt %k8)IKC$SAKq5s!C]k-Yo7.CW]Hh5)VL,O04bQnTH`P`L%ci=\_67+f_L42aB$!DWZfblp'L7qa+S/AiP.c+JbNVQB=eFs+euYP&C*G7J*4m-1q6#51%t;d(c,F %:W$OE^jjBASX_=-s!'UBB%D;TF*@5&d?]4H9>b?9cXjJ4s8?[3NNq/k^<)6![e&t8;iQmlDjd#_-/^3&kJ!65rM/aS;c\]4$M_U#iJ-D"s'DH:D]kh)@lUfG,JclUe-dcG!E^HZ+\X(eXoMMjH&a#Vbm %5Ll\YQttcTC4u6sk?ML5T2.'h4m\2LFD`A"dZ8GbM3o88Q2[o6>[MeAkcK54$M&`*.h?6L^ %<[*<_8RuISoLCTI1;+H?[fs3BSG?^KG+7*"1VRbsHApBlZ^\^Anaq"3h%h^!d$%gjh%h^!5ZoM>gB(t+lmXBfg\b[<.XiUlp6@L- %J,B8u-p8KfXgit21W@VU_fThQ8lneA7*56U7ZaC(m%t(Hg;l5+'rd1[S=%qp9`0Q@`6/\b,DZ/ajH5:;$Z^R8UXrL\h5Nm*a4pdn %,!GsY-hkeK=!!5_g:X[gDu%nRGf4'T>gm\*$7EKV9H'=<&'atUiog\1(-=B8k.lHs5JF$jYn(PeD@n/?q9JXR?<_">n9IN^&cB9C %pj?im"&bXQr4HS8]QXjoKH&0TT38+UZgmVXc#6XkDH>4knM,7FEcTR`Nttna-7iBcpTkl4fZQ2dIL*L95_+e?[(),e %MiWjS#I`!ZFUJ_j_4Z&)?76!;A*_=;L,!GmpA!ZXYh(6NZl!?)QjtCoZQ(R'T`'Xpc"4o85`>F>A4kikR_BW`R$SF-K,G:nN;8;) %R&5s":Z>mXN1q614BZ\lj/4BH4Gf-P[!^(4F25`Q.J] %0=Bo"[f4[M[sUnnI/X&#@mnCpO4!.2AB2aK$):,#YYTGaRDICKM"%qL)"@C_[X?K^@qaC?$Kba+VJu23_&TPZ-l86q8ULrtaWb+& %[eL]OpF9X>-,(n?ia_[-UaJF),X-t6r"EXJo&F5)Fcka@>k'O1qrS3H.>a,E\Vh_E?A9-+/[P&Df-_mT]G1/*LBeh7e:F7G`L7OH_4BYYR/isQ*0Y6@U4%Q]EVT\5tMJi+h/LI7I %/%XEWEHlc?]ln5S3=g/ea&In3e<\5E#lLDrQ]'b]nt%R*QYR&4,_eZ=O3;F*Ap(X24t1!;%,ET-$GJhAJL7_]Mq!)Von1S/d;D;1 %JhMk(9*kc/U#T>uEkZe7=6SXkgs%";i%*:W:eRC%7i('B8LsQCXhYfqi+3UMKjI^1]9$(_'frW+HP`pj?gr0/',ar[o.MhlZG=PU %0fgn(=R">`efQ/h1.99XM_eKaY[6]A/Q-Ad,Md?D%#L5)?Y8VFT-'.d4D?@?DuX]8>;t`Z5`;`gq=2"K*auT.&UNHh#\aAGhOQ[% %2Le/=(dkO.B&kH=3KE7*`(-U\IsEQ6.Eu5SG?a8QHTT^ikl7j2?Z7fN+&@)+:ReV$bqu-$)/Iese(qCaB/u4t/KCSW9lis:<"(Dq %YtF#7MI?P%)AR=c@qqcJ3.>B+?*Hc:JosQ5RH@i@pmse&3k8>Tn'&!%LCdA)O%2-4E-QGon\kIYI"%Uf9f'Ya"cG'/="M7n#XeHB %9nq2CA6_A16&;TW&hMc;5`(i.K`-n*X4\tgF6E;YD>:U991ndl5,iNP,p`gcr2XVE@Y>rV]:(A,"8d#rO'>q(A%`"&0B=cI=;Ct3iSo6&0 %dtKuD>(g@8Fe]59LaZbscu,jV?)HrF`k)f(FD8=Lg9Q5ae9"_\ %V+@IVdn-Qt/("3htVZYt82mje$*+s%UB=ai-KWmtShZ/p@hlf]R$L*s2Q6Xh<#Q+EUGX`s> %EP4*=;;Bf@ZmPU/oLtV=mn87FKP%g^7&hMW7VJZW--+&rkmDjI5q:.VFPF*5b"nM41L93n#qH/eB"G9p;hJ%uUO86I2_?&;M'oCh %Y44W5gtH?.QXTJ&R_MhO/dKg12BtP3mIF+^'a[Zb"guO).79p+)!;;rV@:kaP/lKi[(!%9HOK`f[Q-_C.7;G#d<%!nMdgTF1"]^u %C7GZk=Kh'CE7nHac=LrLgKT,_#(4Ie@Pi\G$5Qn1hH,9U#RE&1p#T[?!eSTgU2VF1h6-*dQXjF[^Il73Wa1X#A$'.VU?(*tI*;Aa$-/e,iXn9Np %)lrD$W@l&=='@d9>`oVMq?;[$JCtXG3Q; %Zkea-<3\7c8H\\_<3\7c8HY1K'X9KN*[7[\PuZ$:1PugFR%6Vp02(?lN/Kqs4(Ii^R":g2MPWW*65<4r/l/?gUI9r?tY'jNls8mcuH %k`-!dc/[7ZTO#lVdWDIJ!pR@0JP0)cf>>F>HJ[kKa^D_ne-H2;"FDeWYBj^poA&H6NT %rnGA'C)2TSkBFPUu5%T]bNpfU/'f=;SD6@@>+MpSRc&5H&"Juqqa'Y\b %D.V\l_Eu7u_nt:p$7Ho7Esb`8%hgF/;[Dn4Ujh;ZQr^W^`Wt=ZQr^W %2G#Q!mkKT_"b]8:H,QLZ(@_/ebcF35f&\p:b(BOT8"FZe.uQlhPE1F<]@Paf+C6Q+2rp"DXPN?K9!Ig$aY)h1K35IQc_>T%&8N&K %:fTP9W%Q+L@:di,I.FQ3)@I6HfZN4=iD"-"dI)GY=Eo%>9Zl:$W0R&52*DdnAJ+Sr@:i*;&h(i7!MGHAlbh$/T(.SWqRak#^C/s_'C9B!^72*"'l_N#^C/s_%$bZ!aa*n_XGVQ*_%n8 %CZ"L>:U\/r(!gled.<`"'@k9J(E!DdpToM,N]u`5J2PG-H3M>[.P?$/*ell[_!Ana?=[Bse:ThaD,Gp9O^84]ZPq9tSFq.BB%qC+chZ %)W)61p[79g*k\0?++JM%7Er"7UQ+XZk98VCaSJKsQ%7p&+WqH;F1mK+@%bmA)9Ck+g4X!+0/e3\f.d'g+5O3Y+"q_hXNK__RmURR %bGB+ECqJ':QYVrmN4q2[D05&ZjZKZXM1FIcfQX583>`POeH%iO/r;L_O/$*@G7i=RG %.;X)L`V7U`/UXiRMT"W+t5Y*Q9Nn]mrSSt`4No'Zh>^>0AG%g!#HU4^ZofLcMgMOu9F%3aQVUM,S&^N?W %hjp&#:@ruJ^,mk$SMe/XkIY@El0^5cS=K&n8pAm?q!P5*GBbG^kI\(Kh-ggP3T$ABIppZ_-fqtHdbSc#@T'p%/,k.?\.c_d;!IDX %9g1;hSX&W'emec/G?4WqVHYjAp8/J^+?>#63@:@X8hBUtY%mER"@iOtihmETkQnEag$ZoaV>V8XAm+]]?hfH%ZEP+g^B %X=S#QJfjC*AS&E/<,T')Q^%^lX$gWF/h:_-)W4&rF$8:9l6ep1F'2Z+Ui9;HZ#I8D7!iW7dX-(,$XJ00V"\P8$a#YhOPZbUNW8%f %K6"2K=EW;7[7&h>/N:[*=44@+_/a$ZdUP5G&saJtBd`89/j[$&cqU@qhFUU\r/2t4%oUT1D2Mq!]s2OeZ(8'lBG<1f)l(_7=`<)L %qf=R9N8lHJeoVD`R(1og.6`$C;5dn+=j[Ab"O:s(X\i9G!Mp*-]K[05D_,.2N#<4Iou=l1`kd*Y(5a,^\M:2^@dB#-bDjnFiHDd, %bDeB5ST]'rg3O[dH\D.q9pZ(OuL!,IH*KoW4A)VHIirFeT10ltO>LcmL*FW6j;]L4!s,BiN&^Ii` %DM%'tDZ'-u,(EH*"\/,#A4:&Y %YZ`G*_q+o4U;-i&'`.o@rFJdZW_m/7@H>etPpe>l`l?=Z>ClJ*P&3]=YcHdNojYmTeli0_I$lT(fr%:CLs2pImYn#>JJ%k"138^[ %JJ%ha]*bPP(cg^)?)pSK&cFStF!XV5&cDn0Kr2Z,e/2JB*KRmnH%p+70dhNg"ZDtCi=[%BpHGJV]=OA@Qnl$o9!T/`HN($LgpldS %"WfJh9NJ"*M#Mu4+up!Hr-^lRWG#P/hm\aI69c?H9ZU6>k7"Q@*I.PZ$.W8'893O6JK_:OSoVl0fsU#-'L*#_h7!fKYOS_d'44f: %nu-KfITtPt%t6*5q@.7Ec!(reL`c!"-:?Z_DquW=FM5"qAnLJ_h9Q^#d's2gIM3aqZ3JMED'YD?#K==.hhK[o4;jg0md5QO[TM[P(t %cB_+A]8a[?CY1&J?&n:9\uX#lR7?l$b7=fcM/g)8joW-LopNhSa5GJW,>=J%3<-j37pU.TfkI'I5*qh-;4=Y( %Ui.EArqKU7erifTnMXS.[>5oN[lT5M$O$ae9Rf+\KFKUQ.#HE;@08\I.'[=;fN+IAJ7J.n68Sdm\3.H6I,F`:WoV2gTE=]e243.ZJ^K$%\ %Z#pS!MQ'CXCYl7`B:i,1m+QHnn,A='7<<$S)6K[8=="K55Q:t7XD)7d6M8s$B'3M5aXGs/p%_bQZg,OL0g %W&Th$5Frmf!aY%":n:hTL[@g2J,d#B#o5Wg.d?_J#Fe^%%MJ;m4AQgY%MJ;m?k6;'K1)k%?7CS5F&<1!4RY+4SV'?.,NkO9)5(/. %jilSjci=fu]%#Sf(CF"7j&8sH@tW'oMFsj!-!;m.]!rGm4di4uN7#)Eh:g5;-/g5C!tXgm+LI^L[e=M(F]#_%Mh[i9r1UnR/m/Ng0[^')6A>*32<>JX7ig!ceIN3[ %5R,t/dut%Q?FBr>.>bVgE0I$&33[Scg9QsQ0#VfC\gr3\YQ%i]1],`MNU6]qa`^r2YL2pqS?^N"?WIKh5n;WMSM<1]U#$"uI*:l( %SQ:Es%_*Z@kn3/rLYL.pMKr@ZgEgY@BZl:-4!\E"pgE'L0%,-j$4F=UiB4VhO4d./6Kl*D?_DMD_[6cqo>o%BDs=LqXWO*5IO0J= %#0VN+Q+ZpYFg0)X+JRo5P9UP=$$DT2-5ge7!$$NlA4%>mGT2`jNWg2SiX0YBP["D4m80B'BLrUl)?C=2P9i$CBEU;]6fMOi\_f]6 %K.UhRBR70*nkWnTb[r0CTObP!_i0fKlYgRc(CNE`l__B>rZOR,ugZ_odWb7 %KSgIc^Gn"1nf6JnK2u#FWDLD0cu^E5A2^d!9e-qcfH9=gfEMW,Si"]NS5Q&rpDdd9'U/sDF`PSQ'adnIBt@]Od+N9C.Dg&D,a]eN %jc85`.SUMf(=6$M,3Ta=r/)_O,qKcD2uMROk`1SufSj_4V*]atCeSNOkHd_rB:_;ZD,4?+mIH1PM4B9< %MP<+dDPWQ!2au"m.R^oCjd-;XB"71b9_'X8ZRL\VS2\f1X,mf+Kp-giFGbu7_j1#"oNf56"XI0/RZT,7(25R0p&kuoF>oPjgk".\ %'fjN*"NH2I0U"K)'$NTuM];V %cshSd2MT//1SZ@M@q0JH@(J]:a2[&Z34%0[3&UsXS+hlH_>qg*a^C+ODPD598*=Q5B9BTBaDUhicd>.=(emng-BOrVEp%?f=j'+R %7[4%MpEdp^?su.dEYTG=?Xj_&!X0>qF!VEDBBq4f)jdbDa;W#m5c@Of'/N]^'H#5)Qp/Q`^a^u]Ss,W[Mg(_>Sl=5h4<37&6&(U@ %4=?-AFV=57i0hgR)Nn+f16Mu;S$r"W"7(4q-hMCopp3p9O:9=/@,.cBhI?FpB3m0rZ]*a>q]E]HC2d8J^V*+!ZD2\XgZU3M+.H6d %fiX^=o9IFY8nr>20ak7FTW1H_6FU-:1);,RPk>)A>(W28>Rfl9CaJ+r;djm2U=,<(8*TGeNOD\5(ocPL)`b8TW78So5g*)Wo&:p2lO_/%q6GV-U-epMj+Z3XbmRa#V@B#c9SgAmR.sf %c8[DDM@Ckgh+nW'L3,YZ1mGdM8?h@$.;.jtG1gnjh"t?2;WX<>cG6T*U*2S4S=,/ok;K-W%GG:rn+.nEU>qCmGRYlS"A-<\9/u?W %N0^U-J=LU?;XoI]q?$f`m=#K1`/R]/tT,ucZ!aY"+jMQUJ@rFWcV>lUBE:$@W*?6:b+b+#cn4^';^D5P6AUa[2& %nlR9/B'6PR6g&!R*)JC[p1\.[rMS1"qM4ffpcir'qY,UoY2kS>.gDMP]U=OhY6Jr8e8#-$)5#"RZO0;*B@paHDt9^Ke3;V8%(kuk %Q#esg')F.G,sQ@F5;tf.HPb"^<27mDmP`In236<597:H4L3#qhG!OY23ZTgQElQuk.FQ093SRZu!0eA-TVZ%aNN_+'(sY"'h%eCBtEn-<+/H?(a8\++Wd:Z#T1Ga'h\&E%2&kb?C;(]V@d5VdDhj(KTAt]T^/T*a@aFli,2(lcsd=af0 %V:mX`eJTmWc4kONN2Cn0%Vli)="55C__5[t(MP0i68dqE-"SrBJ=`lb$k4/#LEjrE`Sb9m]\b[fi_iJe]XTs?g419_1j+#rn0J`^1K,"[f^ida(rg[7JZheo0k[*Ek".*q?a+9+d>Hk.i %_#G?AH^9#LkM-tYeM:eQRSlGtABA#/VGt?$(9q#fVtJWacIkgnh>FhcYO't?%N^#TeL@^-46pd]en<5u1hJT#8:T-TC"<]Z1#r1d %n"jGC?`d?kSj[\+?CZ(%-jRPA;oLa>5)n=pV1NbRHlBNhYu@uUnXEPMn1,Q)n+198I`3PHB8!.,-k3_\R]!9#'@P7G]*2>HpqXD' %42jXP&&ItfE#tGR%1U"5eJ=M2ofLO_fk;!B1c/$VCcjNdI'Y4qM[eS1SV1O*=X9`8TmNDoLF,>TZh#hm1Qt&lR%9T7qB)6:PhcCu %hNaZ_q"0N@nGD<*qX/`8#\a=Q]#_$;Vl+M*$nDdH0Se\5BHa>:9`Q[cp59kSY)<=b11lk5/Me*JEYtgEl%h/q1YaVs4LB2$nn<(X %*HnDDM/)JH(*9UhTs^i._Wo8$1jTuL9q!F3Dm;l87^a])9G)qbF"+&"a%]BhCA)]+,7+ag<-E1p'f,6U&AU70Eq=H(qc.Mf9UC#A %h:26U3PYgNKaU1!8-CQT'+kr>Jf&I#s6\?0dXqd9Xo3[Q8:3&l"Ur(oskHpBT*rOd4h:)5c5LqdcEL0bS6>j:2 %5M5aFU'1i!*=plupE(hKELE9<,5]IoL(d3YV_=PR7*M?CEanPr&K_CW/jN;oMRt!%?+@KeT.lV1&`gO`e67Q]0`gP:tfq^XbN)_X]gja.CDi\V8O,Ghbj325]UcHHb %pDonpmE*S2/AOE5o`b&Qo>\=3F,07]=gKE)@mM]=!nk)`mp[]4D^HR_+DBHe3R3>`E7-k=\[h91O2cV.LYo2qI!H\0Pg-b*OrP#p %_n>*KV`iokr[NbA10hKXjSP\98/Rk6S"2jF(D,$'m'E&'?RGV2-]Ja"7;GB$DQ_5NdV$N]qp_\15LE-f1@q7Tl9i+nP0&Q$&g1Tg %\oTAb5D,O.1QR0=m(pX)K<<#.>%8:4'#oUoTd/dR5%F!mW?9JC%OQ=i(I[Y`D`0Q.KCm@4E,!XD?J,,UhAppgr]JIGXO"RTgQ?>;+$5pOm;6AA_[a,[>KuGa3=ZnZ7)3[t` %5FNA_4YW<,#!!'?&$5b2Bs',&+7rUJY#F$K!mok-^L3SX*<>>m<];8P-$A(A%ZMf#PWD\Bt[aU\iA9O,Q](B/1Non8&u\:=8'tju>Tp:Gh#@lRun&8;RD3PH9gD?poKQ %5(>hKSR'B8@*(0)]F'V]0A)%WV8+9e'I>655;K"tYo"]t'SR8=d9kr00gXB72!NbeZ:W@EF$B$j>a %]F+>MG"g"LE!s"dULQo>,#t0+9t>]q,I:ApBAD.!T6/YnbuL-LI^9knhq:QK2kD.$@sr:^)J(0rc?<=3gk>5dmhP8J&DdeoDXRR(;=P7s#PRQ=d1JcOFd?7m?D:^BMcPk27(EAP0/B9`a,\3+Ma<0n/c+0<5lb.V17V5h*7b_CJ9e %/"a/5g\4Jb%RTo;nIE4$#TI"/5=0:FCab6u#/nNj>0?.lh!.Yd_G:[S#>q^5RG %XDHn&B[9q;1V>HY)i/U:7dg2lR`*.,Jb`Q#HsM?E"(f;r`7eI'T=/@#bN8\0kj//-*fE9JfKcA*EYDWE-kQ%*K7g;OI4gQpoKq9< %M"#C?.\#Kj9_R#-`gC7Wb$NH25O>l3Hh[AE5)k4kH/9_@YVT4$fYVeB@pZ=_f=+C"ODlP/^CrLTZ3B.m4iRam!+@9ohHW#RF.!f)O^RjiN0-hbQ@cl,AZ@kD>BT1c63P`!0'.oWLqhWD&ROK2Ap8k"rH%87XMLptW*Eh2#@"At/hA[LSa.8Qmpg3U5Q %BDbl,OljO%&AdDCmO6g%l"#U62peh-lN$Z`oLg@CI93F>$8!pIPN\r+opEh.sf]H^FRmLl'3ACFiaU?OsPh*k7JRP%fgd8ZI0 %bLTrUeV.%PP'%Sc+`b*D&p784lR%HY`9InfmZ9sK6VVfQ>TOKX6Ne:`j;no66Nm!7aZUhKLBt*[&pm$J%ZsDW9'-_j3^g4;9Cg$EmSW:p]D(Xgk;8MY'UTu+RX$*6-_.;>P^+I0-h-n1AY)HPagkcCA=gki,C1Rbb<5_rWTK$m %:F,JkURFj$4H\A'p+BO.W=Zl/$l'Wo>b2K7saug9`?o*VgA=c?OaciimSp;O3<)]00,'QuThNsXU,)I[AcUuACc(Rq%?&dm[-Udqg!<:t=-A_Tkd]/?] %1WA+p_a5L4jDSV0SlUA7>0>F@k+"ut.1g[.S%h;L:Ao"*\2ecijc;J,_G3)2Qi)X_EMj;0<3$JkDmW;K7SuV0.1gYhl;^:..1gZS %H%#p:Va/l@P_F_!;]tEpT=C*6,tl*MR\#tK5G+`,[B3BkP$LZ(h%Y=81@N!L_HjIce-]nF@\it-RTaV&/K*r:e^T2m@6WCPYi:jX %&l@%GBRfQ9JGWq+IgVa-N0JGs`]ErIN0JGs`k'@Z'<&ZW&6E`kT0W?,6htSQL6mB]eQ7d$Tef&M"6m %@3ima-;.Z]oh)?3&[o!dd`6VXqq(&[7gNr]@*m+IhHjL33^[[W^)#?QSm"gi$si>G(drZLf*'\t6A^ZWfND"%T,)V75ln %kg?uJME0qpB*gm#?(.+Zfd8cDAIYW7Mc4C1BrCnqnS\'0@5T]6#3`:kmnckQkVH06adWm_=Gk0^[U&V28PTmKfN( %:fTVELiX>@osY@k\$41C;1HbfSCddO.)2=C*osK=V3TprF(h]/.o0L\EVV2tpI4Cd)9Qm6isW!(h+bZ:O2>MCIFHuB)/XZ="jp7] %VE;A8Ie6J`cuiJR58j=sh#/%rAi.5:n>7KnJ=&R+h#-jB0]W.NBBdFP6M%XT:Z\e8Pq[RQb.]K**f>p3'tQ#LC5[eIN`6XP_3NC( %de%4]\fA#ej&WK)>RBdLT1Xu"\.[M"fR%0g\.[M"*`f2Zi%d*`+&1_l(.iGTW<#lI6o8TZ:C\lXBA;Z&=MZ?-DkWA0ZIW3QpV+Dp %lHf5Y8ntIj.j[c/Bpr4Ikm`eG*s67T'/^AiC9@!^Kt#],8ZgN&A*"J1.B0]f-0MVb>/@o@/%/>RCP@3E9ml'b\b(e.t(LgHB`uJ;?NlT\WC!q`tM-ILCR[YLmXX*eQP95PHWV2XO_.#NdGpg`Q^DkOhf)d>mYarkSJ"L2i`+9m'Tk;8#..9'+V^p %ZtMc1p3\>M#pm'YGq?NWL$Rr^8_,O %HE8fZm_?ETb*PE1'+qMO>G6$gGZm]ICk]m:THRB??n4(:Ac"-D!aD?7a2qH*$#G=8[:%Eh>$rj;Y(bcS8h-npDoPZ\Xni+ZKM$t* %T`m\qL"2RBVmO;J)dPGt)Idj.dkY$.)>o\[8[s4/a/;hH@,WkY16RsWU)@8#NN?sqOVhBf/LEKc75MN,S\jBc/ZDu70!8R:h?ACD %MjE%JmO(F<cB[r#:IN"qr&`l8ZL %@hk0\8p8-(-*rFI0+[7/8T5uK[qm+3c6 %9HCJqcNe[283abu&/ck>R--\G&?R^id@-+M;7OEsBo2-NsRN8"kM>"2i%mGlk8Z0kemJ[']%G:hS+\?Lmfl1'dh\.g2/ %WK/i[+lJsMUR1N1+QI:3jaN9[I]L(O./X?q5YJlH0=.5ie9La1S.Y4O$E:ebdt^oh2<`_2Q3W=^^Vte+e[JE1S3sd.9%N;Tn1%<- %=WB#>P%g2i/D,Y,R>pL$0a/a25DHbf)Kp8FnCjE54$9ej4m8KnWie8r>HOg?g)&Ga`J#]'3As)`\eo@3>iA-0b(2aT\N^eA-6p8j %Krq]JZ8"E-DHJ^Vf0&FT1\l]\I`sKjAbLn,-pG7MHdTIRGQ"rc@7f<7en5mo^3i;6'%`lXk09k,!@;.#6r?kE?tm %TfbP5hm;t&>LVs*c^L%;L\5!Dp@CcZ,9oNhIf?L$j@?#pr(a@hnSSh?!%9tEMU=?e*OnC9-RI,2Y#5!lS[Q#1%u+.q;O)HXZ"VqY %cgEUB8q[.QYM;lbEOUnUgiAfSgGUt&'!Ya&GX.oQ`Z>[p`1QJNNsAl;LK)]p2*YpJP""&Eojl]j/g%Hm>K5:d.?'q-nJ\Q/\>lC1 %Z.c/CC'JVbr %@>X\Zco3tq_fBT%%196]E(ank15@1N8Yc5!i$g+j2$DL,RMoGKfO)2/Z1r"X\ZW3\Y8S!24J;Mr@9^`njU,m)+Z %L;OYkYLmV-EJGk:Rc9lE#nBV80\(7tLF"+'*'I_n4"ST4E_YC-B8"$_m&oEGOi&+uMFT9r^I7S4jj;'roLm%G7aoGXqSg>sQU<"< %X1fk>D-Xtq\?eB@GT.HY>gj@H[rDkdBh?A"\;&bb9$-1WQW)Sb_Ef[/1q+`^)t7;YYEP0/[rDkdBr\uYGdu#d)FuR=`\lQ6P4Z9) %gL>rmc:7T9i4`Ah=4^PIqJ+EAT<5B,`m\%Z)3aX*4*RO4``cgg3PLlD``f,#_AM*L>G0@A_JC)1hA6jRaO(o\_(lY"Oe[,s4NiPO %3%\SWiKHm_Lj6'uQ=Ua[$_T"ERUm2E2')$V'!dH_fB$=>Viou%_Wen0@0F1LdO_0?<&<)YdCEko-8i1&d?c[1(91[3m,Jl.XJL2\ %qEO66ie1_C:Wm_#W-??p)2/tu^`-poN:,h#7W*J$5caFS"g5lS4NF7#7UgQf^4PeGHSl-@e'"f2]CX%*%sWmXf5/?<"9"Z/,?q>e %;@k-(4)VH6mF+co>%XJ;f^8*IdqX']T(a?=N0,R4M`pQ*u_"Kq`T`M*@E\$(i1CCT3oYf@^(^YRQmKC7':g*9a$[\`bZd`%(f_?%C:Ve %rok)r&^5uU@tBou5_ol7RcCeHVYclp4Xq#"!.Q'J^U5YsA`K3eZ/t[?/lOE]d&ta(ulqQMZ,._/(6k(9jK30cPqJL&3D80cS3?%DH>PQjq!`_G^T]-+h], %^+d0ib(!XMiA.f[!^[L*JXBW0Y)_1#9J,0PW+%Xr;iA=D8&Wo/2fc"%-#@>4%Xb@[-#@=)s!>tA&iR/YE#%A+/Tf!qTcgj=/Xna? %@r&?=>3@Qg*#+LM"\X"V9J*nA-<@Fq?u!NBRUF5iK;jPhbLkB4Vc?:u._'8r-3j\fh6FDSYcPf,M&bUAABN9b,c]$RO]dAD>>*Vu %dTC<;@8fhZ0gu_E>'ge`>>gYC!t1>"25?%Q*di#3i(a'`#[aRh=/D[4)lWpiXVO/^Ctg@-gpt/h#4EN %gmp$uTG@>#JT3QTOnkW:\9hC14<-S')l*>r@bAWT^oAJ/Y%?q]MZ-*nm`\H*Xc"6XZ^.,<4503--LOY#/J'!kQq&tJ:Y[Zjh)(Z' %l]rCQju.)0.Z"q>oQ7DG6f#P)NQ&J+Tl0>lSO2M8pNh]4S_(p5dBK-!cLsJhZ4sS`TkVKNh*f>%\5V$l]>:n^Ha<1"?lqOdC@mOY^k@7hPRm]&DK^KnDJAe6HI0@N2[0al_m+!7Dd1J=k,\HqK(ZG)lTF@]aSM30[1LTWkn5-KTnioiLu="EE7DgdH['go@_$5_ %d;uC;E38^J`=f8)o,GE1L95j2>4H^1#%t+:(M %]&pjtD>[)!?u!k3C-sn1=a]TQ)hlVhYYfYW*76$5kX$!YajMH$&#S_/>aX7j96,^n0&4Dp96,a?7.*Hr'Zh(>\27Kcj9cW,Z:K:D %E_.D<0h`N]R_bUQ.S#MG7j<,dC\8ebs58Zkn+j\-0-O^.*Co2)4h0'?Lh6ZN>pWCLpTk$\lq/k.U`T]?Fp>j0;uQ!EO[$:qbQ`WI27*k.o^KH%'M5('e6`CUsajHMk3O6.(MYJ=)b'=890Dj;b`T,\O$H9FaB-BEZGh8'e6`OY*:9Dcj-bP$U=(q=,XPK %[i+b(Ja%8BXCThOC4F=^n4%T8q"%s=V>'hS5aSMg\]T@2LGq&<$q[g97CGF#1$Y%*R>S8(j%%`8GMU!(NOH6@Y_Iq.g]W;^2]7Z4 %XE=;shbVUWomXa6+7"u+_ir[CD0N^BZ^ngLcXKSJB;=t#4'4:#URd[,<0*N?79ACC[#W(cB\]LA(tmQ?eJE@P?GHk%TrUtI1!QW= %6[5^,-=]o^.J,La4nR>I%L_K44rK?H-f3Q)&:!6uE"-t*MT9N%T\Qck %Fc0lJcCK`iC`AoM35'+k)6u&0`t?"PcAsRLCTcjJf5#lYmBV;)LgAi)?$iTKZ?oN&<.:TiP0,^88;5h-;cE)G'OKL*.3QZi)#qi-+T$1,=NAKK3PD]ef-%Zl0SeFMph.$+paS;QfQDIX!i`DB/#Hi5r,(o4%[9:5HbPi1^*/SfB-4)7,uGgog,f?6ShROBsWsTg3u/UmIr/&RPS'ALCB0 %`#$'&Q_Vsj4Gfd2[o\W6i.4)E*HpDY0(=eu-X2uKDo`kq74V

L7j__BcIOWC,*DOC08#nh!%C/NB@&GBk&E((U^jhp/8D7)\`0YUKG;WZq8A\. %RO'p;9q#e!3(n*!OduW_HlE,KEZ_!o\E_'qpF.` %Jn;ZK_;X46;)9fJ=ocO^9+U3hQ3Ch32+/f>[=met&q$55C0B8\P5K&t:$9YA-*3Eon6ZXjYIi34Z8$EK %P,`*@>m]VuMQ:;k4!2GAASpGC:iWloIZ#M+!AITuU=Fs.L,EgJl_`([-E:bD!Ri71lO %qT(81Wb%1Ve"CQ:)F^\!U4bF#YEfp5.g+>-0Cs$*YKm_neZs@6q6XEZ]Co5sRpGX"L/opl\e=rS>qMPH=o++8`4nZYfW9-Me$PPS %GAEn_,LH>ejAEC03CK$@F>.F=Ci=q>hIUSi*?WF!Eqp6S#O]i3ca^^8Z2hE7[`\S&[)s.l(2es-nQ>TG[*$6)C[H&@XRoQHbB*;b %*OO2N/^IjoejBo7]3-KlG]\,o^\Rf454biRo4r;5Qui6Ss'+`/GNQ>`G&mQ6H=!"G_+8H<0:2YuH1(;hO43Kg91IL(]UXC39W)nq %*tM7*S`TTFH?Ej\24N:OLAUSoGd-W5ph&ALhrNHdHT)>LMN0=m1)8& %cV(@OBWB7Il"/FOA,.4L]4bPaD_ %eV3[S<8BuA?/YpdUq2JmC=f9I/t2'W?+;<="]Gj^0&8rp?'ku?XLn2aj49*s:[NG1a%Y\,8RgL%E*)mXQZ7Gf;_bH4mMe"=jXcNM %;kG1U^/M=Mt:Di.7!@BRg?_Nnqp\R2KDSfu:("';g`>$LLhnOQ,nO/&i^U\RVg2&$<*jG\=&Tn] %9kQ^R#Ql.;W\4kP+:NLFWum7E&>nb>fi-n&CR`[[%$PN?J;6UoeidagDte^/s-tF"BeVok1";M.U^c06'16WK=ij?#pl<<;*eXP) %s",Mc[=;Pa/-e>.c49m/.]]^PG%RH=[oHIPX6e%sp2@"uhcADpeLF5ed+>nZNSh;D_iC.aIh\`db.;7pkCsq^b5_3?A_hO&"kib\ %Sr%>7h*DP*6.>f-Gn:?Q)*NPtEBHX6%o_rY/6b&+1Zl[JE5eh!AuDC3A_h56YsR,I#H=$>L,60k5$^SYWOmiedVFPQ:YB';AR#`V %_*#:^7MX'$*KbBTBBU),'Zt=cZ^'P4gj'_5=m5Rjl<Vl532f$FsZo,Y"R8?*UmX:pcZAsB2>UYLHb78Aq %7\OY:A'H/lP6[TD6"^1hKTqcTM&8Mu4-ptLH@E`Emt@Qt6K(:Ak%^A0KpKsEla=]qH"D]VANTe*@17A!"c %Tkr0L;hE:A[e,bsB9U"#e)A?Ade$IcB@Hlkq?`_D^ZhZ2l)-b3IZdh^bE.19:adiaIU_b^P*^X/Rk#AeiDnpQ4oIdOhlBV!QsO)N %hOQTk,$JQOQcR8!X+_7*D>HW%ZF@Hh9rlt7/k]uF9m4I:U]-nP"rS`u0;Sf`NVlN-,_B:=bA-UZd``#@sB#-0Gp(;aImjlWc(LDfi94%hLB(7M_gHn'X-/qG$R"FBY9 %Tb2+^M!:tUE"j-O%id,Xp[:5!g4UN%hrI@7+6-7"iST*n??Xo(>fM/"Ua"A1Ca5tO\F1GPoiu7qA0uJ[5Sh.f;$([%G\F=^$e)fRj"BkknMp(.4qf=Q^4st-5O>[CoJ!^f3(UYD= %f,7F)ipsA[eV1O&Et``UP_Q^;\;e1?WA)7ZB`V$Aic=I8Xq2C3S`fc2/pp`@\m-;;CNNb8YgTMIXm!fa-=.e5:`]d%=+^*B85f,C %(9+^mOm]_2d`S?C?.m!-bgtr@56.FeKYIDsAPC>N/[gPta6+(]K]T(!d,oG9)RW,9CNV`$V,csDN0Sn8YQbbi2&jY4R52_MM\C/dgNQlc++$)ZBieifd$a3`;^<)=AN8PUPYi\@3b8S0m.'d2Y6W(8l%2q_\K2U4!Rl.J#F5J!q'r1V %:19!,SB@85m8We[gdi:PZM2?b=^n':08Dohc4\%0d^UT%`"JP)2$[iEE:ou][:IY^`dF-[SmRsqp5jFfd$[g):&osh6Sj-44a@;^ %c=d8eeEgV.DAMl`!hpm9>Ui4XCde_ZY+-#;-(JI.F/XM>rYL:e[_0]Mug>&8p%o7Mn6(:4c21``hRI`aH5;MIL#ArnQO"!PfCLQpn %<4'3,j9kTUa[VaelC%9>WC!)uBT7gfJR!pIHqBuX0.&l@'(Q4?qNu\nKO_hdYui!11gPcEiTH[8jNJqG+(B1c7QW@Buq*G#Qk7minJ"_:I+hkP?O:R^2Usc9$N?.Ps[RZ"kp(V$`c]6V:TiP`!X#9,sf)&,B\;>)`0o %329HH5q4"c`C-[BpKM!>bMn_I?B`6,2a5k[oJ@LH,BBMXkd_\W\Mb3#8UpP22@hP[hPp055aV24*;U\J_G%C>^2Z=B/;q_X)Fqs(uW9DoV'\`p.K^l>O\b %bub_L.Wa-:M?VHH$ftKp;CoJoU?X*'q".5-#s\&%6]]):=LpTZ-N(4Rq&b&3,ML,YVI\Iu[9?6cSl:ePl5MeCk>)JcRdbrthS>.$ %iC_I@<0,)aRJ\`6]bnHZ*Y=n*sTI4_b*!=jsIcsAX=;kUS! %0\9Bg9aX9a(toDU`Q9(WQ/9)I?'?qQjKm_Gd3Uh&&D2V,O%:Q#_NK#G@WkMK&kQhP\sq78pR_lr1 %IAo#M1f>Im.5=:(a($^N-F-nunIF=[S#H_a%?gj:i_Us#Up=^4-IqU %YtjV!HGmIf1f>Im/919-&kIRuLLfs`P"C4rS@DCQ.QTqN'AVOqWk*KL=kV_'Z3N-a5\sALA.K+6M,V]eWTGBqp4o7KK6hdj509`E %f:ZFuInV?LgjY/1guA')!>CFW8Pe!DpkR7LH;`jAH^qY")?8'9Gl9DRRN3%`%$@Xq\1UWp%lpH$Ye/=Z$J[%@X%(CEZ2?rAAc^n<",?B4 %Oi$s,+i./Q#GP,[NQ`'%)UE$g,NnSL+N[TkddLg1fI#$g5E*q/rs?L9kjs&8,LVU-<"eSSj,#ne4PkIf>Bn3u#0"4J67Kts>[L5` %N)?@Y2p!,R7F1&YM**fiGeOXnb!_hkGs(S'U*fHJY5&(#bA!l`>j^5qQcNeY4Hh.bDNnd<#;&^^#Hd1LeLbrfKtGY?b[I:!Xm>h.D7tu/ %@cOlpn8NL*37qTS9>gr(@f=2>]6X_qj0btda_3Gms)0$ePQ'M3Bta2FF10M42nuN^44Vn=mL?'ggiED>@6'=bBQX?H_aaKt[S6!, %k%YlZI`(p.Ya)Cm.ptE1@)p[NK+4SNYkDMQ/LWOlkPc0@i[aM6@XCbs\I>Wop6J&L,R0Ug)=>pbA(nVU"r!VO&gE\S+ZQ(YPT/Hc %+9\I:TdUIps?od,u`(_mK$5dZVfii[Fs&$Eo,C*36t-(;:C5>AddEaBsj=O:p9*Y %bR+qU3*U&\/cF.P!s!9^CuOVF3O=EQ29tT0nS^1uC_(["n=LWI@]+(i*Mp!n_K@PJQ8$:p8t1TI(c>R7>0OX\h>de[@q"teYQkir %?QPS#aFN4\&eLa&V"pF%nb.%6atmEr%6!1%]9jg,dg$:+E`\%[7pYf3Mc"DLP2o579?[BUL\W[@>%.\l4+:?[W[3ChREu,4fn,YV %V@/R*AtDa6*']l?FMVX=k41)ml%4.g*1DjRpO4lf+BLH.;OiS_Jm9uq69F/E$$*ib6_"_qZU0=IU$8Z&MQ?f_iX`M0`A/r3L_YEo %Z38me)J8&0[_>oi.4%tG[N?5%)%cLHXJ[]@*ak5l1jrGo#UL>BFYkQgWK3)BI[*4AU@fA %#>ES[H=1!^MJ0^MM[.6'X$AmWI_UeT>4YW<,7TqTYH!iH6ban'`idleI %gPEU_5M]^SjCqQ2"/@kak^Ht6^eX$,i-Y]&02CMK6IUk/nd5r^PF,YbQ5=qh"AQ)Hq'eXIBC-NKUUJ'QRH1g"VRHB-$%d0"E,%I\ %N`!=R!n;C.S."K"P-?e#N*c=ID$MheCHm/km.b-"_sS9sE-3`4dO0'*5O;h"s_'>V`:/Hgl#jBYiPsru[p9)V=.6($#/X^(Ed;9ZG>52RSW= %)CKprRBE$I2)B]u:pnluu^,>p=';!>RG/8k+7H1Y6k>^#F@".dZZ:#g!RU*RTe-^cS7pSrni:,6+Z %L/Gp$pZD5r_Z)sMJ)`A@%/=1CV@2jPA,'E2eidagDte^/s+Kb[WL5A`>5BLrP"_3j?1NP2.6H"4mMA@PTLbs'emdUeKlSqS=GoaY %YXeRnRa/iZ(X-u\hj#`$p;DEGm9,*(>&sNlg].uGBZ]eNE#tFD)/B[%qm2pAcZ39^aCZuC57?,PK(sJCohSs#?6n!BG8%_MSfGMj %i+KTa?#"/P]Gu0=R4ai\,Cj-fc;[C#B0j+0&AQMPkp"BkeD,\P9UDW?<0t0iQh,k:FgU6)=UqbgmL(l-RWC.r;I!(m;QS6cT,'L% %8lu5:Q^Qk#k@#MXc;d$0^t<]W>;r$m`6*[B$?,YRH^q./XV<_WcFYu]O;bmnN,uO"U`BtERR<)P''JO&8[[8krWZSs$hO5S!:.L& %QGru.(UgVW[jMrq/o5*5H>$D\@[tV54po9>d'E(!PoVICLK[i>r%UJfCYSuA+1Q@_>K"[9HXBd%M_#fqNRI>3`!NOso&OG`+>2NY %J(2ge0$g5hmR%FA).oFfO/'$[s1#4E!s;nYAI/(]S`NiIH#76@oWfXuZ+QOjj?3cnk;V0\68+r%N0f"],=]O_nTdN3d4O7L8G=fa %_D&D/ZT2Q<,!9%gLK.SN,Jl\&Nk`]"'j!-tXrN9Z:=u95K/t3hcfJ"nKL^7JQjHP7_QSA^I7:>n-<:JkQ^3ccC\r>cj(MtG]spJ5 %BY%XYKn%X>]RQ1iB(cIt.P+ob%"?E\^Deid7rQCMdc>kF,\g$4WPDgHR.[c:]RkY'f++D(KM)KB5EdF('ba.)+-8W%eOkI=h6G='XM2\Fp#h97JN_(,Xg!Bt%KT@C=?_`2 %Ku%88]EdSUt=ca8UrZeJSHa[.Ma='E.+9l6PN] %,hK!mW(u)epOhGTGkKu0VKbR-Is)pN,Th%^MeA3CH(W8Rg4"Uh%LGm%3KY;+GE"Q0QTj;%p[%'orKVH#(L"`OLRIX(M/7Pm=&4Ra %k41h8\Rg.OT0aHqNH`K+Kr\Aq.hK']5IuC,kIp2l]`h'P+>j_Ck&Ip_rl5p`_/e\Dpet>b9b,9V[Ef''SaQB#jd`BXMO)D:*I-Pg %.X9bJcVadrDU?Ef`L%KlhTdSd@QKV^TTN4de&f!!IpWpFSIF.:@nuS,4#=3%A-#:jS2"G]3r)B^\iO:]+0dCH0cb/F %!Tp4KB1Bgql-\<_ZA@apWr'nD[75@)aU2BHkSRdUIdj^D78,'r./(rO)Ibb%e(1_kuGp47'^]BC-;CerNTu,BeV=44%Gf&NcA66VI;"i$qE/CcXa$SqZ2h+s!.jG4KQW,HoEs!O79, %MHjsY74$mB32]O0tq6)o*Ri.i6,MOD^sX.n<^t^m[,'P*5cH*#@6rDH-r(QbJ41+JF=ZR.-PTclfJR6S+T[irLW2B^^aH; %i7IN+2XR_3i0c2:I/JS^REHaA\#upl83=$ADVb\,9Hl\sAS-Vbo:dub@Ji7JqHT(fUU.N,]+nGPj3Mb\6`6bDPm7nS]Z$b',PmI6oC64bj<`kUO3[,,IbnXeZ8f0K0o?dda+Fe=E^Cft+&C?S %#^NM!4F"Vo?$#]HhRLUpVL'D$$7^;*Qg;kWW2nkLjBiU%nDYgkj6s%Li5NIZ\6Dd0"g?+]:g:bomlHsP='<@$DI?OL_2F-Z\0Y'b %"Y\F2BQ^#WK%EWs=)9;DXoU7hK:2PHBh'+7EG%t*T`dHj8h5-6]HhWSP,;IVK?nIn%4/+N<*&MJod4VmPZI:bn,<9\oM`,j1ep7a %23cH*;d7*(mTc`ni:Yt(M@Cm,N[_*gB?o\-ZGThGs(2K2tU_]i+$!\b']WY8m#2Iuoe`+pr;IK:c.AMFd.4R%#:WSf\>5&]%'#+ckYBZD.%u %nuG,e86,O>=_5Gf;q8TT3">R#=^ggA;<$lpGI(dSK;P\bh^*hckSI1J^.U40TmC&qH/+ug,i4P"ni.q*28)1hoZplpEjh,+0CF95 %o'0k]nBh3_#-Xj=(+$gQ/B)"$&U&JfD7)I[MmBHg6[/fYNU-JC2$#t0H0iEjfs0cN(7T0[F@;R7"lHSA@]'SYGCG7Ad_jJPUi!NR %$"^b$];h7G[Xu1#_."brgWIe2WO8k`,Zj1eQXX1Xq(]W+YJ@RJ^$g[eUMQulgXLUdnMZZ;q@BRLI.IcPo=n5g`V&tiITq2Rs5Q8- %c!=jXRJ5V-WVP5H)u-m)?K0]B.R'2WhrB<85K)Z89u8cVbJipi6*d*6jl6$EZq6U"pYtpS/bUR"=;\^pE$9lQT@,YT;[[Y;QuZ(: %VUi][`=,9jE(-$%%V"[Vq^W0a8eDQtRgIf*m+NgLpS@&2CS.-__M6/o4%HLKj5!7=l`,2V]i_P.[2(SU:)AlU;kmfu\'J)4d9iKe %fg9>1-S1NZl=ro2W48?Lkd-Au<#*)_p;2tn&XH&QC^Km%*6o>d_=DP+Gap?1f@I9XIX2R][CqHC=Zb:q])OVMA0W:, %\jM_aoD8?u(%,#JC$_`_52f;ljf1j1\^5/!2ZhlDID=>a3&=ook#)nf@d*Fd\a6s9VN&?Uf7WD:Y\;*/"`Tj38LjS?EM:P1N&be=mdLeRk4Ln2[LT0EOX4P3:LesR7e(IS0 %a_`e',L\tc&oBCNT:[%mP%^$[gGU><,uL,)eOLfi3^4(E49XiF%V++O->LL3!`/s!UkL]o5OHO[D*0 %a#A44pVPLb!Up^3[]GnfC];*$(F.h)IqhM_i7*;RSd`q-g,E__V'a"20K7C>->%hUDPJB*D6PqBdR_KGADI %DnedN0;c15kSO6G1e&jju" %4'(tO?l;PBK1#:+Y'T6LW!?m6pN:-VhQcA'&%;!)-%`]O8"/,3^2W@l*,0"H,N7.3$#,-3B5[Qk%QAm.D],=G5B6VUY&2'adh1pF%?)A:4de(&FIM<+msMFto&d8KOQl#4J( %r.ZYB>2rXUZ'H2[GT`@_UKLps]VWhg(i:FrM47f[Q<1_3+[_uVQR"L/7^Ka4pJ"sPN+R@O>q%]O7MFID/it"AlgTV/0/jh>lgTTU %9_&s+KEY`n>C*f@P1j'BQ_"hd/GIWVFkd#9EQdCYsLZ_^kbH-p$.L`NJG,^F1W%&@XDh %FD-L2%uoB'Rh\32_g>`/<'GOBa3okk\>>(dG[d-NnJ.-lU`n>7^+<^_(&6>X)(TF\.j2O@j\[/7!n%I)a&IkuXE\q@^VpI?]aD\Z %5^I]:;lH`2o4!g8[$m?9b9kG1sAVeF=?12LeCp_,1?fr&.Fs#Kgb?=nYN(rBT#G'[9Glc2;e1lM'o %[ZDnPX_!6YX,].^5m__@PK"QUbs%k1A)ZS_/T;]aOVVf.JF1c$'k]DGREulBT$d %<[@k:Q`)fM+XPTUrE^Xane#`S$.8/#3C-mF]5)l;K7*$b!K$#`fN"RTo(?K/7-s,\>Ob8i>Qgq`4Ll`*J;\sCK(lt\^dUM2TkCY< %^dS6A&^,llJo2+EondN/YD55E$..rOWf?A4gPa"KnFGHDQXU%5?U2QMuC#SbHIN]%VkA^_[Tu+X%/K*?`$s+S=N;0>gWSs3iJ[DNSMP %P%X7TmJ5rCB$Xlo`(`m?^!HOXf&c+^O4Ed`H'@R?BtlFKqsu1@c)\>L&cNY1g-G,`cF!/EVu+'Qp,gJ^?%8s;<]c#APV:Cs=1oRs %X`Ca0.:(NV0pE7JV?Q0M46`I=@r&t'WIgO^pJ;Ud?sB:V2YuI-.^uSWn$Zf$(!mlf:fU=s=`HQ^rjHD:D9Me1QM%^=lX/80KjH0G %3k^S6ckd'DO4a;bXcB)ONPqoVC5snc66l$=8:s\[1$i,=O-Q<@RE1;FhV)Z-;r+m=8T[CoKWT=TEaiD[)ef]j0?J&D3,M5>3p`]A %_6G>,=UUjh.;WX9.?.mi^00cnV"nIls1ZQjZ#KE1c^8]@fiu8k2b$?C'hr9I'4^^[%OpI6kWb1R#k@bEh7r*2g0OKcjKLQ/Nf3]:Hnb< %=-:<#]H,Ya$I4Q2?;V'/4>Wnl3\#LUf6oc/mtWnI)-c(Kk@HE)o'4J($iS%aD6eZW38H,-B$N9>b3an[IhERr.dp'+j\nYk=plul^ig<]'kbQN(X/pTC&I0bY\,c!_@D#HM %WZ0YPGKr[O2%4=_MW_66R>hQN!fG8m2,]>_ME9Ci4PW=0"N9!o^FOqfJ:b+)j*,'F5X=[,@AZ2!3_I\6'^T$n$3\;5/S9)p#mA0a %4bF(*592%_2@B0SBIQ))ZV`^29::g'1E5GC(lAM'LhEK%Y0V;Ql=No=C_WuIB[]h!AttG'M\ZSSf7`:V7;*edI&OmO4PVJ*,nLXf %ke9VZWP)G(mNOt?+;T[NHt@sr^^2JuFM1gLe3H8=c\'bmUd.1-)hfYoU'(PWI282rVG0S&R>ms/.SRW#_B!3mFH'Yu %[rpBMM;FNC1C-"Y<(0Gq[s?,H'N@BC[L23p<1RWN]aaZRuF[X[JJ9MSb,%V3Soq3^K3HsAK %?fW,e6E?#`culK**_rVgJZa'jnBdHE!F63t+9g)%VTDW-!@^HK(m.Gd%S.laYK*nYFmUG4dk)>FM;.Blh2u7f<*X.9d*t!5* %ANO*;/J\p?&?RP/BogNJka3&T^I6Y8A`%9b+c33Db>qp43C]R",3gf#N\(&a=SbIb,A[-2Wq>61p#7X2E4]@S&;iq447/CL-CS(h %F&:0>e0O9I#GH+`k9>RUi1Ca6@Qm*d51Ui,X1F0I3SXDLl_ooW]5AD3X87!iF!Y:4^\h-`5Mc%V<1h*BAI1*ZR&qni#t^6gi`6iC %Q%!>26n8XG(E@'FUm2,MoDh%jAS%-68MWq9UP2Og,FOfH6eCqrn!&LG%%G9R>%e)_X:fh(,8!biF4A]cXK6S&[?$Wk8+/ZGmrWD$ %t%[l(t5.IXtPk^mq@b>M[2?<5HA%ihoH-k)0&>+:VcdH1])&U(5?X>PE7L4`qT6M=l;(/>IF`=d&5,qcJK)RdkTpV@(*[Hqi5[XOttql?B@[nX>Fp %bIu&1$bb:NH>d\8@".;L'EgI*1`PO0M;hl2U*+_dOG/lk!$lhp!SPj3"@/-jAPt@]M6HOc.7XY*=)u4q/Oub<':L%q*+9]__Oi'[ %[Fc7da4q".Yki8=#/tXPJU_*c^OCJ-&#uZ(b6nP#!8BkY,H@Xm.>?;0UK`%@&J@=KR9>L_>[@10[jjFAn'6N&ah!c %c,=o`F5GHZDl'-tSJqLA9EH>nrs)W2*!2d]ra&on-NC_`#D"Q>PS/*,k@Z9F,?O9_eO?M;)P7)5[Y+eXH]0Sa(h=DPrKkqf%CNp] %PC4A9%<5(YYgqLP5$dV7Zsfh=j;Q\A*S8.ZBNYFA^>iCi?_e-I9h=U?)-9do %"'`M">)LOT/`1P"oWC"U[a9FW2`p[J9?srpO98_$VA=Vaar8q'274-d"'`L:QBAV@1pH)Rj;r(k.0EeWENRE*oGC_KUOQL"#*A0, %V^gJGZ^&/UV+oU:3-!i'Vs)6pYgT!::Zq7\q7n=X\9$[PMr1![GD!6^lf[tWEOprr\.l?XG^B:F?<0SdcJt(R1-F+?O1dMpY3j5@ %\qSI4]XC[nbpHNCiVrad.CjlmAmRi+o'EhgFKmhJ2ea,%[Dl,I`lF-i`pEm#r]*b8gRW"*#KMoDY&dfM:aW6)n2]:gh5%*>f#GVY %3_2Y4YB:'9,lOS[(b1`05`B(D1+G!'Qu,!dKfVTNPuEmls:H+G`?UDd)0Cnf?>6?;\^nXnCpFENDem %gP*Zh++K06Vs90(Y&l7%2fhM%4=k9#oD-%+eQ"ikf[D=LqTUkJ>)VOEW5PYe!YV7:Nn%B`7IN.kZJ_^jZVU6]Uje'+"`p$q/P"l( %pe5P$bG=/!=!@'h`2Tlqg]7\_iA,`7Y2ph*=91:eC!:D$k,O'hIH!l>cjj`#EaUsS9Poo([`jITM,RWSR4YbY<8uCCBk@`3j\7kn %A2d\O=_^j3[[PmQgIh'dYIE4iVc(binB@+#o?hq;%IY,)l=s;\0d)B!QOlPCnlsh`A:h6>O4YB %=6RH5:JSn=/T80(J,7uMgScc?ksVWXF0?Go.g++VKVi=bZ8*-EO-WXUTOh6,N*2'/k^_LDX:4`Xd:aC=(r"oRQ\UDM/A=52VLt[g %d-n^6I@'C_N?4i&1C*=1f@`1OC21!#:Fn`#J`$'Z:4-m#h#CW)5Jk`)G7/K(H@;<4*-^$QL^Kl^i(K %0ML0pe.#&%)uc$q7P'cj5=XT]#bVd#;$^)&Cm76uD;`aJ%dP'rUoqZZMBHVEO.If#`8NN0A[?Ra)a;85@h]i@T.H3n&Ot^^F4cgW %.)IB3Qmm_5N'ajb_PS$adlG6PF`A:)!OJL0mH,\'P)mYLejLQ8pq29b]"!\OIh'-?l=s9&"oYa\*pU)>]:;eh4,g=t9AD<3[.P_e %m;J:E?9KCFpo:$oh`gsE_MJTu(+`q]b^s`-\(L[=>0%CZ+fSr""nTF1I[MhuYZ,WNT.8Jf<@qM5::&CVa2^Q)O7S1'W+!8hr^@&] %.rQ4NFQ<5r)K6DB\)=sPe\0,qDKg<,qiK+%BTX-U!4c@c@Jc7F4CLshC#lqk2Q>7]/2HqZe9W%Kf/MH]!?M^ %8j<.D(d7SoN[I,5e'7jE`$oXq$X3k"uVI1Rh:bYU_^dS-L2ImtjWY*MY,9[F0koL\`!J?W* %>RueSJ3ci*>RueSJDnUrW?)nu!AflgU)mDJZHtI9)2/L:,"tj$64:>cKeSo-$D_PqXMUeA=?%7^#[kKYI''S8d'[2ST=*#'fJfho?g4$583ehK?.afpW!7!9+rDFp_XH %(!p7J<;e4$(n5%6McOhs0]2=?mABcoimurH>a!uj>G#cnQ9?/0TnrVsJ0Y>]#70OgZ)C/<*=q<-N$FKB(7hDV)k_Q;=lS5EZZHp)&3#B5i>n=A7`jt#qI/+Li+6RBTkF1)mp8FDX\@bBfNcU1A\0J#X1<6r07UFo2Gao-T %Vj@`&O)si28A^C.R2Nu"a14aI$1c-I'U9&t&TXDbaree-_fOp_tDT[lXS4c_sY(1c:\SulA %$&46&i/I#B/qm:J$B9*UWc2X45njA0R$2/!658FgR!bPQ.hbhG37kYr-/*>k(37.a31&O906`oo.<06l/&:1;-YgFsQtZ_do4BZIYk,#rO\(2:l"GtY^H>9k^,Xct+*Diq+P7?u]D7C'5C]2E,<(/Diq+PP6EPCIu@iKNLs^>rEFTOo%)p3ZCIO( %^%,:Dao]U5<95j$Q"BA2o2d"1=]m7Oa1CoM3@4CAA"04<[D-+YbK9&,'"BGTrEGhA=hF[C*RO_c`"-fe95*->.)>:BP3%K`Ib*=eTp9QhH3LmP"`92T7n\l7L%kEfapd!Qf!mL^>\9)JcU+Z?*htopT/Apb+9;g0r2f!Ro6r>nlQ5fX:V)P8 %ohkU,IR"8#Hco7FI(VdpHcqdJ,T9pZq&YY(+o!]&?o0tW%EsEiO4!G^1sfMG"\-B3d=>gE3_!V`oBs8\ %6Lj(*fd@6saib9j+*5Y&NOG4tn1,q?(MmF+bE!N'0$'+L'B@oH,Wm_$m['kS)MH*MO^]s8Ta&%6dBPNED#eM8W)stp`*G2N%=<() %.>"L#)W%WJBNQ028],:!M1DF2D\W@q3%C5K:"$gqjG6nV2G"!0)0q)/D^ifI>f!b@dlf;[FS*r/HhtWhaN"]M0:X+X(gajA-cXnB %$t(0CPN$0/(N@_+Kq/FrpZ-0bWjQPrN9U1b[]9[r7&#Rdu._W+1\K2uUIHAc4%$WApW"DX<]04LT/70APaW*q"r,6hnmW#F'DF5_>><"Fqp95M8[A9qW/#>A!+ %HXJ*(%%^sL4YW$$L;&RV&'WY-QKj#UhN`[6(s)f22A@X^T':hX %>Z_LF]uS`?[uG8M[Be>s>h=2r`LlH5ao!pf`[0;F^?1cV9!l?\bqG!T+iFums]WbQ)CGk2-. %-'qD+h]gUl%+AK/HdI1]_L`1&LGGa=^ub*clf+<"WZ9H8051?JiI'%$06iKdNmf.#nn\a1b+[GIMl%q+EYcs@p[VkRr1#G8:]pF< %]aKVNCA)AQ5Kq.uOQVtd-M9$i!j]VKWE.i"Jid/WV1UtP1.-i+,OCKChJF=;E-bI-nmUMaXfPl*n_Ra>Z1s!DaUY@E.lQ*6)()]o %]OC75paQZ;VHqq8R>6,@jhd(6De)LD-IbfTq(m2GBA\ZuW3)E32m2W.9?qA2b@kH"GJ<:-%p[6*m3GloWCnG\(O`oH1g;QF.6.i: %F7TemB\0#=8q?N`rAchlDhI?05b0b6FEdZ*aPRMCUj0%J,RZc(3Dfm?rf9GWl %'Fm=i?GDEk;$T0aiVbB0[gUIh\).q(X^?+nGl\p6'XWrck65(CFaMEW4>6WZ6EW=%K*rIs>"G7Vg74][jUEf^MAKI;PrEg0=7STa %\`UQo6u!QPTmP'XO2X%QMS=.D/&C<4F*<>uUu#W\-k@_7h3i<&o>Jo);Mdh0e/!dp6$6>4a.(F+qO>-!QP,D:s>aRDV6+]MEJ?Vk3bn=Q94 %H@@B`i]l6V3>'-d8M1km66LkL:l+JKI-f.C-mOBLiR"b>q<(V8Q"B>1b:Q-U=BPZa3KgJFnYC-V6KH;K1kVsJqoM\FEDa8cdY>:2 %%'^9-.[Y^BFGS+%aVE&3Q_fjU%<;40.]ZX86WrsF.\LGG.P#sRKmo@:$B[K_MNUc\Y2(H@[Ii[_R;_Fdc&3.lNVtTrKucr3V4.ao %AY5h-2=Ot=X;of"b#O81!qT&'HE:[f5V"C2lB#EZ?@!dc6p)!OQB$KePOn&Kk`KMck^btiGXs+mN_#\jU?3'ZlHNN@rTA0;16$OK %L,DX-KufiW/ObYp&38jDe,h7-"GOpgB,f:?9Y3caKufiHA474^7.)s2M^sF^b/4\%rtocK1)c8=rPu-sJMS_.J5#DrL.$]R#%XA* %@rq$NFUYs4=-:uLh6C`rj'QUBq+\LZlu.q*.uu>shfnRfQ2?nVm52S[G;CVGO@4=^N@$G@rG/oV'B.?(b`E^\)@LeD+c5]Kq0es\ %+Ire!hNacjKBu!NS@aS*1PdXk[)s@=^1]9ScJK?)^djV,oF_\/aUHlfX6j#O15"e#(!$f@p/nS2#6.+T8a10I^I)H3&,*q %kN$7[?&fY0ArpZOf38ODTkL`Bc>6pe_n@tk>+q.RHjl4"I$qgG'S2OCW6o/\+Ybs7<=.m3o;39DVA%jdkh_@M1MEDq76EG8%\L;* %PE*k[6,T(*mH!LT6!lilgbIl12[7cni!!L89)88Ff`o9@Ek23[pBdtAWK%bo&P7G;@Q@WB?M5h]]UZV&bV.\1QJlHc$aHRPe#[G@ %oX"$7-7^A*lXqY%6\<%$(7s[XSoa%U+R??C?--&999,WucV"f`6eK]d,p!?2&GEH77Lk#Z#l@aYr=fOV&GEHsrF?6L6eK^_-QaMU9hp5c.c&;C#7[lsL'Z7u;qKu]DZ[=tlG+lktZXC4F:hVSbIhZmr7Id_Vlr;?g\3q_gHB(Ql %$Bk<<1CG"QC2s#On4].;'I5OnVR5R$43,/9b(^'iK=qN%oe.=RSQ'QfG/784SF".kg!]9#Uc$s4m4Ve'Q+fgcfW4OPl[N,EnF\'QK<`TWV#E!mS\,8f8-$uWlpL-3&T7<5q$ %-\=3LB[7uMk,J'F5kEc4pCgf[.lNhYT5IgVI,=1C3`V`Z*>kut27jlGSY/u%.3NG"\$XAm!0`*2,d-i/i<\%`UC;G\: %&CAbg]W6m(a24#@OKQ+I>lLd=SX\RqUf%K.k7bV2MhU2QA$JE %klWQ!9gHY+Opbh;g;nA9+/=0IT_oWiSV7`20IP/@^t.iMZ@:J2+)+eT/'1$:n1lnY0U*57AWUq-/ZY= %ojhZ#6i[!A>3R-*5LBFq0`HaTaR,%3PH!Zkhp#6L]BfE":Cd8[8D'G[ZU3^B*1n<2*h@OZ'N)o@qn@OLeh.!e@i`[mm:@-/&NM4JrQG %@gsY3MWcSG>ht"+;++dM"tM"'F?B$5`eSZW0L(t>k"EW9""#8q7UtI(-Xr+P-cSW7%lD=7DpcTF;j`F3,3G8TJn?1GqjCqu%-AD* %=#OO#LcG\*0fELRLcG\+toP8*(/=[E,es@3HgWYd.J7en%s3$/p#6a_YBO/h?ta-3MraV`-=LQr.Ti;o]O0ujcaOj4Fn=; %rCq]cnS!']8))=,7F@@L9e9Mh[Y]IcQN#1HlL[GnBar?\rR>bd' %R>CAk04*t8esfpWGdtcGM",r,pk.q^dITDTO0%e]YGb\BI`TM]+nDFG399ajjdD771c&E7/_s8[+O6i1FE.D!hV:B/S*uuA-+BBa %'#7KUiQ#_b,Un&WIFmX$FY0AS[O8t@Nc`;Kl$2-EE?=YX]6ZA/[U6DZ?hh&gBclGJFKb([od@))_fa&o>[Iru7ai`0+0QW%Xl@Uq %1Z#n7a-SSH"?WmVfH7Hoh=]C^A*7jjiZ1gZ@-6rn*.PaHbthcMQaO7:m:G-Xqt9%4_pht2[9:)AEjtpl?p.RpYjZsX/]t*Lq82J= %]#MOu8$DLW;71!:fpNW)0Y(pC\qa:9>1/A-tV9 %Ta+s8*II=iF5)-!BJ8eK\)uuHe=sXi@k;\-qchh=F*N:fT!PuDfhm.so2GZYGAd@j23qt@CBj6Z)-%Ld0\ %oO6.t%:6qk_(p5QJ/3_8n,>C*@G]5c;/cm=0gXS?nZYLfFde9EkYn%_l!UZ=BQ,aOmP7Dj&ip\-\W+>pE#2U[>,G]skW8 %aMPJ("9=\M5fiO;Y2nC;9F=]G2QNJC60l0<"%r!%l##k?_<5IEG27#2G0jDTEI44f4Ijs0Zeb:iCqJDQbk>_N=82H5L@nr)0[_K? %f(9W%KNTd="b+JIcGRP$bcM`;)CkRL\fjdC3pA\L1%"p5)#'Hl@O;p7'/7Hs`(YE)d!os0l0OA:&=AV$V&MN1pBrMX*']GKC;Ub1 %iN`24s'@ZP5NpV!]`OA'=B68nE]+aMbJkpqfYY[S]T's@!n`,m:ZaibJ,\6G\$J:\>QHs/p;=$)\H7#k)imh*RL@%5c4sS0MkF %6[c*Od6Ds^7X+f$7j;RFXbJI3QP+,e:MFmP9c`JOb&"f"G.rbh<\"31>uet1+j$">qUTtjqZU5:L&Q0n6@Y>mL19+(aGZF7=h1Z/ %-f7Q7lSG>Dd$Nqc&`JY*kZh//pg6Z5\N2rr&?(E]c#(&(e5l6e#PP`T8.h]hFS06YHG^heXPUUIc`,g%kQ*BlceVmqod$is%=3Y# %[KVM(JNbg1C^Wn@p[U,*eWIDC^u%N'i0\jpLhU1Y?Onl@$SgK[j6RrOD]u"I`e>e@m("U@ZTai".XS<*p+:P;X8#nT^&;Eg`?&n? %<`K&>@f@-Pj1K=d"kCT\=frNLGe`bA&G*@BO%Di(4iI7M`5Xnp?Onl@$aHF\@g_A.d-\cbMgujXIWRYh@uM%C@IYtE5[E:Y2/iel %N@Dpu6\&nmSghbGRW6g>6Fg_."13>cf?BTu$d05pFj89sT=]lGh_hb(%3.OLr2uI`Ic9Q8k',(i*N?\F6,",o@%rYif.7%<1DS]TQr%@[U;g)FoUB?#%f:A#LQbu7 %2.k[cS#7H);rQnA7%Tn8\,k]Mh/bX`=e:?8QRH6o3,bal'=F9phU@Q!Ns'F\_-=^6<%V@R))@KCqanu?j(FjuQF-e,"KdUu3]B-(n$J?F[n8AdY'VY!,<63:OR-p#U`E?% %GR,n4['YHF3!;GN$o<;9dY#Z$K'B<"79,cqp9A@2/C7Z__6HO4@HOqV*j-kOGg#L@;uI7VR:0qu^T7olGU!Si]*5PM3p@M._%_bq %\dC5oToMYH&>IKl9hUh^C[g#AJK\A$iO4UAb%sL>]bCfWHM!j2J.Om>Y]Y"&geQTuXK"5-E %Z!(oJI4U)@5$Qe.i8>jB?-&'jH@h38)AmnH/Ek-Dl_b`M7mhj,g0FNcO$A#%IuH,YkWV!Hj(!Y#Q'Cengb^a"Vb/!P;cM'CRG[dA %#;+T3HQgGMb^C=ClI!4R_*:-Ga=2sU/UZ1&nDoph[J5"Q?7EuR_E9a/rtZi2^(@[h&TWjbcf.polGZ<6a"W!:^(KM\)b0;=.#]j@ %NFF;"ksh&\"uDl*ZAgQ!%;)JTA/esK3u-%i"@a7&>oCcjo@RI'(R&cjH#,0)H;LINjuFLL>=N"RH#,0Z_F.dbH#,0'NPl+ofO3pU %6t(aoCbRXU,MNLq82#&9>.,"Y9?\B(fSg23BTIsi@;>tXcTa_+J1]G8k5+"[P)%q$\UPV^oU?B9;hql7WPXLq_^WLO&;i0d9OU8A_;j6g9M %?NM?k^6Y+[$Cb?1EZ?pAT]sF'Gpsr7(NU/tr[qZW(IQ;F87ga:]`Kdhg)1HE"ALNRb7!G_D92VH4Bd46cAhg2]:?F:2EUSLN`LnL %`/WERjpUL.IYq]'($! %?\MB2h,@RTGNWHd#&##lX'fl$;-[\I]@)=n7s#cTRM`!PH._:5PdZ(8ZZV/=X!OQ6YPNQcGt+:el'eYrZsb+6_V`Mjr,oK\]@MC$ %B@Po4I,(uG^hXHNJ*![n0Pc`:Qn7GGIEG[5_>hT?>*dbK($g/^rVCZp%nAT):J@,I+QOiE5B[Nd)FW9B)&"`"=XuK#ft5-#plHbO/JmUc]%5K0DY/&kBUY %?+=:e.Q$.]W4kW*&kBTb5NXc_`Ace!]QmH$/YAoS8L%R:]h]^?OuVG)pO4N<+kMNO!7b?&L_j=<5!rX"7_BXc3_#98G/%-mTuE*F %1trm9KGK3a6LRNDTuA.\nF&,Mdu*I<\O]O&`mGG(2q_)_`:`\ %B,*#I8*?Fj]D-0j]TK9L&!(d'\G(8F*f]aQ\!^iDS=P[WWOlN!OuR41nO5JgL'P\*l8\o.UIWO2msWm-%MtZ*?^"=qK4jhl)7_M[m!)"GF`,VGA`FXk@Lf`ojPq+@E5qFt %1F&L=n\F5m.QYY71@^;E3$V\M&`=O0#_ul6`g-OP4K'?)%\E3/5P!]\jSrmXE[X&FfY!S>mo9F\d;sHBR#pn.N#jr'>fdT9)*Mq. %S@=`DBCs+c'f?UdUZZm3"%#2Cd0"#LpO3g$7Sb#P\Ak9%K%P'6aBD)aBCn0-G_T9`Srl#>.>2=jS\*V9/tP;F>\g;PBVbG[aBZiX %5U4OGTs^`X#rL*.RBbB,((g!fOU3kmr0^V2o1u#rleTcVMXJnY8#d\hOhmk].j[ZW:;iuM[[>b!RPdm[JmtOfFSJZB:9V13o=KBl %["]/]0f$7\@isCgdj9HRa!']h@9IS@X#D3M3$b;nGSqVX-(j:>l!U&56dsEt*PPZirA)WJ+9lLG$hb+r98JArnYMSEml.ooS](A/3.]KKUDPF'j %l.VA_8]F8D8\Z*+oX)!6SXG9P`YuPGCAFm1T7*b2nTi$,ABG/S&O"1PN"8$$lCrZ2]N'`R)EfiM_M),C:]_Djm^)_>-^OQl0j6j='&`b@L&/HS8%?T;EPYJkbB!6""b@N %J8'Kh^E#m$dFJMZb*G_S#;0pMdEX%An&bp!M0:N!nG%BpM)uk(p)\lMV3-`Z@\::$**1H'QP/MMqc&9&nLP^`2*)jTgd,HE4K&2- %H2Lf/Y_.Sr/[USXn'.94_:eAOF8N@)?,UuKdc0N]CNo8r'Lun89;1s/YIE2G]m)+,pq.Q8knZHmn\_EHfPGS>*O&!s5.ii?:o;4SV-ZKpmE':M8FBhUj3GoH8k)'VR>ruFj>.,O=hVDN?jbPM'Tr3 %+t]$mAHkNK'CA>bUABQV]se>54jdjh_Z!Z5K26_dW2P=?7/0SO0AEkA/A1`5!>lhrb00VUdofgm>MMf=0[k[%'enYiADEXcG%up= %ojG$d7"C=,UV8^AR8m^@H8b>Km6[:,DXG^(?9,`6n?0WA)nhuQ')Km8F!=fr %B%)E$IQ`$VT$-MKf1jZVZ60TbB?UD@fr9@Hm@aS!`%hYa!E7<.=:\c;LHaJ6/Q8;``ue;E3V1WS_V/B2Tkhl(E4GV=4@YGTe78'* %UuUE=*uXD'L3gX!s$BlWT&^\8IBhW/h&@`bkf#Si,!eB=1YE<)+VF!JkEI5LQF"2h_;G[Rd1#2l_r(l9Do"7kLVZEe[l/[%/QVNof$TGU)XIZ0 %8:/NTG;'n>rq9CjVn;),Do$Yf(gOQg$mZY*i!Qd!>f/h8]uA.'Ud4#Zln'>Wn8e$om4GF7fF9I5]li_cgp!ZJfF0AsHcu;UHL*4: %=!>B;qI:1+@I1,$PA#EHFK`YFhp#tU1$BDhPkr-f^T\S\+mgk+=3=6#P3ab%'p*$HKs\Rqcnfln(1% %%0h1&U,K7o>Z?&c2uAglUD<:;o7@Zs$ZA%m5m[gq#7E-hZQl,>nPa,ame8M+q]m*H60EpP0[jBj!PNHtB9?AbWA+*L"%naF2fJjS %l[0JHUejQ,[P7T`mu8)pUtW3;NgBYbe%$g4rdVC2PNT7R>*t`42cBZl$ZkKIq6c-0([,2N+,igHdEjmX\N!ehI-6e[jF;n+R;Qo;DObXEW>90!,Z3s(j9^s4L]J3+T6g%KtYs4(OEnSH.PcaEGX4Y:gH70C4cLWWTU^>T,L" %p5?3MMj8P``KCuhEBck+Qj:e^#1Tm&o6:='=t"BB*XIJFQoZaudb2+V)6YV4Q-L+hX-CX8gi74\+nrW)^A!9?b-3k]kd6D0QV?oI %o)G>^Oh5s+.iY(C0q;*gCI_Vbk489k.iC-U7NsH&1ToePS39s11;#AS/fD!Zp/.-7.I)/O'4o:Q+,<7%aV]16>HsF*?>%^Qf6HF` %Pf-5Z8JQ_0H>p!On<`4dTB.A_`].*?Xf12Jc5b=r@N9E?FQAB6/lqY'iU^G.!86@nShL<+Gegm6*g%:pF@S*W+uJ2; %?Qrd$)]PO5_Sr6>K]:McV<(BG*7E)aN@GDESiEk6bhI,l(*FF+At6Gc'<4?k+qmlhhMa8#4Y2P?5;R1=(/M?amIk3kG;NuD\a@cn %6?ff2b&37eF[lOf7W*R[e#,4K,b/Y!M<^+sm1`R/\g(oNQl)!emQfMY`8]*]H!B$_=6&l*UHP?n1W^rm*kg\+Os[c8%GjOPp?;#M %jCsZ%F[s?_0=O*umZ*#``l.Zgdcg\4bn3[9H(#`^?$NP\C^.fg@7kb7U+ifQ%G7qf\EW7S::p([kf#c;`8?cti %HP8_@S$AE%YiZH\D8p>1nasPL2rcRs54l4Mf8T$desdp@%X+tl:Rb5+\:a.sdITD0fWnJk;OSJY=+*h*::;%gGT>?Obp_djK)Z %Cu&[r*YgdhUZsJ<6]T1ACGajYp)1@%OZAX@^TPEkP)-]mCgDb`8k4).#uD\TYtRetUWY/?EJ8V>_T46td:3nmf(9WZ]]'Q*n:'>Z %="_VtX132Y13(Dd/od_d+lsH*\3dci=^GAsPXAVek$?(RYMAUQ-?8.ko[44-+g8DoQ(-.g\U\AaMG%36T4?+9l=m-9n!^dccnp%0 %L/.^qqSboLPR$Cg)-KH6%Z,k?,@+Q"'jieu9M];LkcCQW5&l%9LPl5o5i:nt=%sVLg*U9H%(qAZ+e.YG.UJp=]H?%C+`eW)&u'gdu-MW@Ib\9l%K5!735H`k?fQ0Y:X3&R/99j %&Ja\&"+0+qij[qpc$a_!@4qn#Z.lH,GQiNb#9uqQai"o=9nnYVK8_PoC*C!HN":%!1Jg7tT;!F=hA9FXhCnHHotK,[qHp%llVmHW %*+2Z"UAModY$XStJOQ]3>LflsO?7/fT@-nA:]B-UM[19.0.FIUXpCCEILM$^D;LG0UuDF,UXb&\FM0?d=]$K>l[=a*7?r\3pBB0$ %01J7Zn,$9o&SeRFoI5!QHEVY!cF)c/8E\S426a]&N!DCA&cFmN`n6'6.RXp,J'cp?Ao"T+/u;/]]q);jd#$s=T]7$jJj5rAhbb<* %T$+*%!tLJ6p(rj/^.)K#)P;U@=TSKaaZ&$5)t3IIi?7W=Tf%hoMgFCATp**83RNEUY`=1]mH*.%lu,%rZIuF38ihH86+V"94c/o: %\WuLP/o?b'k_Q%p)7^.7,[3GRbI@/&\%+E@^(p5/VtCf'Ed`?^eO]UKo<#PLoX*AU(?#]'@]rf7^[=3QQt(cTcTB7g5KAN8qqRBO %r,Z[La,2RmG!P'Fo2G-eVjEa&cVMAIhh@PPcVMA9)qcFNKK(FU0O;lF_<8jl!'?aj?&j@7Z!p&>:J5DhOE6=Bl$,M)I5*HMLd)&m]QXr>-3WbZ&1Dg!9F+OD/e1)A=EhN(A7Irj#a:+R %FbY_X&LA*-KaCGoW03"OIUtp7&5]Q-,nk.]bX`:6P>&@0WJa(V)(*:j'b-d/A?a@066e@U8>P1=VkrI&$5*La4!U78I!uF:W@YP= %q#%:_U@NBpq->esP@*7(5nn]V/r>XAcgR#CiEd+B5)/;+eAK2u(]TnVg*'bu/YoVEQY %Q2!AmT9AF`8+J[nT+]@N7.iR6YDZa^FE3'dF^kuhq!F"*,I'%lm@MtkqQ9IMYN:)?])2qg\"]#3FF]cWhb/\^/.ZoQ5":< %'H"H$dL5h4cIW"bLE0Sf!T*&M;c:D2;4skX,;#Y>=dS`6D`Ll!0s'_oMLt@^5=8".IB`N*`c:>c(s**VM60d4c%U?<-!UDSVejT% %pXu#DHk^(>rsE*k`EdVs3_$h+2(]?qUG-'H+p$-=o9FjbDs5<,r3Cg&[/RBKa.*m?pb4b*I['gt&l5Qg+Y([-,(k7)GW.GC0Yi4C``"*VEBK]*A"kE,@/hj-Q*4&Klt*)G$*;CppLC';HHmcH+:p6:rgZASg[AHsWTuj4rJ@`L^^Y&&%_4 %(u4_Am?pb!5#`<1S%5gONo"O05&pV(M4Gb]C3I*_p?!ZT%E18,SXt7'fX3K+;Ao+4,,gds4qdBB7s)/Hjui=(6m6iM>"e=T2"L27 %E5fdoo00LaYZ)cFoAUlYQ^"HANb=.Bq\&c %*d3GWd7(]2cu*I0F@u.`kK3-Q*cS817jJUV],W>G^RY&inb'#IhTPAjUR+?MX7n)^2/VjPf$JbDB`&9!Pg)(K4mmdY*m3U`a]?nF %6eRt+mj(T40-j[t-"<$OS1?%UA/fgL]\i$,G8mOI,D0tEggd^C4modKWRB5[A\4jI%XXfqeVikAe_NFG'1MrtA[?U-bb*qX:m7]F %H9AIsb1W9EHB(0k!6rJ[[>EV5AGk:#fk3t8piaibr[q[91A3>id5#5"Ze^$gMkgW7n=H&B1.4BppWOUSIFj6hmIj)d:i3g'BT*j) %>f*J=Ji0&3B:kF`5gM1"C)CZAO'bZpmuNmOWH1;W;[js+nY)o02I7eg%nBui[i/kKq"XLrYTMJqkS&HH'qOoRJj#SPmY^:QB@ %IuGVC:X/#D_C&CUKKW]qM)V!O&b[nC)^W@H'`3cC:McQnOHoFiq4.cO&hNeO(\N^F#B8YKE^,1WqM37?pU4Au&?#RW%/l]W"tLPh %rcJY\:?2AlM>o_%!aot&#(H\@E7X7>eD#bfkZsU;=&-m<%pj;VlQlp)>]IQ8)gX$.p[j4j,h?bp?rPsnqpC!jn"kS2N2;s)C>\lD %Nn^a]]t)GUHMh7MV#<9**NgQK8dDul#DqUdN8N(3g0kcq+(soDDu!%C^lUiB[rQTC2")tD0""7qq="4^lOc_/6_B`CL&)?Vilg#6 %8u"Hqhcepn!%RUphi?#@n48(YE>!ndJG0Zh?e%?gC``cSPY5[hp0i#,i-aU3?s6BRM6T][eX'jpP-hl6Ar[u&fW&SP?'Oqi(uLsE_f %AAuk/4]_Ye"nlKGZZ!.$Su])"AUTaWmN9q+=[CA6)#KW9abi2d2]?`Q!m5NBINdrF>DkpL.I'Vn7oLjoFeccQ\44Z7UWl=Z72`a> %=dUd0NOVm9RRW@F;H3WP3b/%_"I5^af(-m37B%.;BpGDpDSt0`SDAqNgR>>%jtYV`"X!lYc1BU:C*[tla(uDsF?<3Q"`C%b:!n6Slnf/u6t2o?,jM$IQ/$L\K=eFW>O?ei#WJ43Fg?ZlE;CQanJ2e1"K0LqT:\,k %0qh0XqA_KY8f5$6%fUD\Ci7*'7"De2_J8nVL%ndp57]?6lR50"Pb1F_?0%Y(dim8#grm1A\p7X#n_9D>9C!YsT^6h2taQ %TkAV\+Nj21a]3O1D$Tkk\a%I9^W9E!,]*cJ]eUqNl.-t\_ap0uO44hUoESfA.:X!\4pV&lq8j6r_"tX'Q$S@(lR<@t3!9k^/%5ebnVQ>dAh"XSbQUChCFg/4R1"i;m&ZgmhtVW2`7+OgBD`-(Q`?buF[+.n@(PV8Y4d:!s&?Njhg>RN %iN1nlc7J%`o4\s(Y-VTPe,$U1Ci^i#4MLKQ$3(sdhUg'?62JCF61,I_Ei$9G.Lu#Od/p=l8F*!7aHOAoSAfc\On-c5n[uoNa %AsOj_B7WPu*REYIPD7E/oui!<[sA'gIZk9GHa&;+"1=1:`D]!Y!13)/\9`B+NM(<\B3_DT66iG!5#C%&6>6Rfdg'V$gA0mdq"d7,$5a,;bZ.&@A?>s6B\<2I5Nhm=5#Ak&-J7GjhZmoWPPlFdjcH!! %oSeGG3T7Sjg^"f%eC[DPN\IDFmTW.#,X.k%0iph6DuWq>D1OOUekQ&%Q<%6il&M`)et>6/7X/\6E"nf<`sl% %bNO54&8I/Rf!0O\$u1`<%5ZfP*Rr`X+,^\FN3+XEAVq1:N1Z1s3/ePdN3+WWC8`kqZ=(p!.FaaO=NQ:9@k.qW&YCgTX^,33Q;[sE %n,6pU*KDUGh#&J7q4damMCQ[BU/uo?Bs^caX!'rWiu6S&>)=9ZjBP/::O:>RW)=%oPB:j?.N.^7]Vq.#P) %FQ%Y80NJuk'e%MOIV#/bX$Cs-3PnjK_V$#9/d*>,`,8A,.SqRCARH6$IZ'?35^fXt:I"WT5Y\,(BG)t&'dubNF&[@,,#iOAo %>"B;9Hnc*M/Yn58[ET2G':Y6Qb@cIa7e''g9pMaEU#*2H(PP2ZqIp0C4):hRSgNkf"P4D"N`F-99$,CPCOO46,VP/78]1Q,KU:g] %-,Pe`5Gg!eTgc-*,(->I%$=!1"LgWH$=.0:ZnY15/E/%9KN8euq1i"!;Hcr]6fL@\\?CP5MS_j8LX$T"0ZU[FAcJ+#.T?6q8B(fYq6kHFL^j"MiU6gS %be\hkE;F&9,Pm!PI'=Ue')GZ-/eV^F,460\"*6/p1,I60!p3leAak?b!co@L0rQk$SL\;P2We0NJ2ns\*#H(7Z-;%hNK*%MW<#:= %#6U:0<#-Zc%L+HhS:*[W#6U8:LoVYrdh7"!@UP3q0UBWG.ttbY4FI.t?k*AlLD#\('iAB4TuQuO!alKB/;GDZk$YuF^baXMjuCiE %8(tm3M@/KR^iI6E;@q'gJE;Ti-dde4nEig>#BQF*6Pj/7.gY9Fa>,e=$^i<%*]`7-*(iQE:&'1QLP`BM^eAnXK/jdSN$a$J"O+[n %q>kbp+IId)bD;a"U0nIc/0e?7MLmi*9Jk'`l=_.%&Lpsf]?O!M@tg>h87e1cY&p4#FP6<0g@`K#CosLDdHrmQD]ZL'\I1@iW?S(kUMJ*5gS`!Rp@0_AO3:.pEO]9O*nT%=i,Q=&4YAf\(5BrI9&r8+(BGk<2Zu+l]'b]: %*&_Z*h2-.oN.o?HW,,-;mfgW7[YK!GGUA30aAL(!I"R;mT3+odEH[XcDn/Ht]M&gd"gg%iHKJXVYhE=68Ha[HH^Ni+Ej48%M@bu( %e_Up76a<^J'ifq/_5[_\Sb4a'NB[%OUcZFL3EYZ#FH$UW@C)M'L!SZaBlCQNI4ciO/0b'Ee%PjJnn:2"hH1n+p>0RYMQ])bY!ea+ %>iI6:hWED\n_UM.f#ZnDT[hhfVUps8Q'%VZ4l2Hn48P.HdP$=c4euDn1R!EedEAYXYIaS`[p!>7Y)MBAH][uX7.9F#XkLtSmsT;b %hWb#k>G%T>=\HGM\sVLiSTfdYG?Iaf?ge?(`aqHtm;kJ=s,:SZ-Q8XhpHMU>`-g=?G_V.6pPeAuC!j]*41Fa)d?RWBG,#.Ar)B.R2ic'tj]m[i?&bmR8!aWX`9?n'+IBJ&Y;j %S(5j]TQT+YJKCk;olB;6mao;&KED5;@%6SEG+S@^nRe[;a>eLQ$Fg,>@IA&EZ`cELF[.;7"UWS1VS\Slok37"ermWKWm^1)i9 %9^\KqT:F"-0fkoQ3;_chaib8GC;-r3)EC>'h,h;Y9'B$FLZcOu62UJ#G##Z<)Jo$Zb7A6Y2Vui\ND5fS!\<_0pke/46ssLYrFet7 %JfNFWZ'IUogb2-I+%epC>'h'Ln3`$m6F-d2/$p5Vc#8I&6P^#'6Q>B/UIXI>dgPu=;,lL_0_)d'Kg,EkB=2iU %%nh\iS.GJciS5::1)#@RKFf&upYT_K,(tsHef'BuBMR4E^"CnBp1[\\UBbA:kTLc-kcNXh#,AX.#78e'4P\5tHpf.b&Ug6`b=L$? %\s"DXXYoa]Ii$IU\]N?e(g)S<,XeudJ:WD&6:/U^'da]j57,_$kC+[Ed[h'rkEU[QkbH*&/4:Nl@P3u"Bl!kY@=Zu%i)iE/`._1m %gb1iY>S+WJ$P.79&MCFgMKXd`Tq"_nrM#`CFHmEPP=f-l`I&N5O;W%*_;, %e&fScjr?K:(7pT.3n'q(Cik^/X9aP%YEYu_QOF9cUn@lc0*]T-I2>c0$fBP16hO_@R2JGD'bA\d%)KfAne/V0gKI(KDJQqlYCSCA %cV/LNLUn<])+it1s,W95=W!AZ33ctU>M^?Vm\KZa9)lWA/"?(K@J8%m^6X4lhI[e4%\I%d1qJdofG[^-0&sjh7ZWbnnZ#$k=o$FA+E(sTmld/'3fXdF0."nc)82aloF!(ZG/$krh7Xg%o_.6XMZ5CEMU0W$pVhS_\e_[M %L$[ju6;tMqd.2,jXl`[-g1e]`j]FG)LuWC7]SiO%k^h:39#"@Zlu12nNEj03bf?cbl`[)!Q*W"lsslnUKRc,VJubMZj'L\:>\>&L`H3:f]ZRKk&X$6<^1"*4BaAn=lrh8Rakh1$?mTD#R]a27A+ %[E7_CB>QU8_UDM#XCT9U22q]*EQ*6C_)=VK98mM/+=M01s#*>>>NURVGlIQ8U%!7!0_%>DXOacP`Ed9V=7$2)GKIanJN?oLC"uV\ %IWh)omC^G&!N0#;+\;LHCb7B!h8-u-EI4\S0FpD=J3M6^T#G6dZ@9%u>KsW0f*ae&>g'n+a&2)4Q!p3+CbglmS-sMBAb7P&a13<] %+JWS;50a=MA/RPRoPlMT]L4m-"m8#nFVERj(OD*5kujmEF4n55p,L[M]DW5H[L5Tc %I=o=@RWZ-/7cP*T=PVp^HE5>I<()0^,5T6PJ>IU[Ld7KmV';cTPsLSIK(Gon4Coa;G6KA+AE^0\aG'5a/gJaq;g4@'QZ!+QB\c*T %?'^fk>'I6IF2kj#WG(n81m%:jbc19gX.I:dOJ]W\WXGjQWOe"`\gD#XOmYi7"o[YbR;_Fdc&9%>K'E]u+lV!X6$K.E:9S6$V@,8c %JsKYT98Dq=!U!+n_=W-QiiD.04='W&q.1(T#;hkmAQ0##.%C;>`p=jkphJf5E50c+LU>a=]R'2#6N;=9UF-QqG9N;b84jpi>F&N_ %+Xq\maY!/OTmb36ZA5O-2Su$u8+r$%H&,])34"CrT<%^]eo9l=H)AdG?#V)"g%0r;rkSJ&pHEf\O?[Z^KLd'ejpf">7jC/6RU!q& %2mf-o0]YS#>n$I$QgoM:mo_P\\u'rd(\>nR7)Cb/AN*>:+W("#FEq&UiAi6[B:1s4Kh2skHC!eO?&C,0BA##gsk5&Y5A$+.!+ %pq3)>id4]0iUabt)F!rod9$hLYKTKI\n>gKogB!b`,Tm*m.Jc9iTA5tCkau89&=GfhfLg@St0aHbf[$W2.Z&&7H<^f;+%_UPL?d" %0p?g'REXK8mq)#_(\fZDW@iOp$Q_iMO<9C[L>GP\D4n/Lh,rq&CV+`%hB&joS5OoKCD]irgXnK'^Y\YG3k+GFMt+^Qi?G`d8dCqh%dfLJfZGcb_e&)B5B,m6l/KnIBeGh/f&7)o"%qrOaXHe&m['\ %K^lqm\o!6T&JrW,b9C@$-+[2DeaUBf8p%>bGO`Q`RP*1_><*Hp5P;QQL1!_YN3@NB"m+^HY#/)pRSD!0R: %_u:aMjKdmti'*oC*o-,DB?CP:GnM-]>UO1c13ee(FHrTk.kCB4H?77Z+7B`l*Bm^AtS&0!.UoT#+/1i.2X/k`MU9'HLYHEJ##'OS.UPAu#FVS0';)N@HX#b?(MM)+2a,+O^e&ma8iX3Bn %,r=FMi^t*3.uoH8rcoq]NMNT,1G8o513$bQil#.#Vn4:MgRs&=FXQK %3OR;D>\DSI75YVM:s(X*';!c'AGV[P#i#'0_";@!R?@B#>41hS/h%s^lQb"D9M"3qr,#a7F(0@Tq"t0_@&^4DkO-NM"\``/<%##g8"jlBd;_9AT>58p6_Q>U5d(JobmWBbW4?#E %UgLd"7f5VIi4Vl6P_r1Z&8+(tQ05I;N;1gAjKKZ+^/m3rGt>Arn`71D%[C-C41cQWm*ms>(A-V"$OY_+^RuD0"'2j_p#Pk@431hl %^ok(MXV/R'Q_RPc9',EZm!L?"T@PZMp"RqjZa0/-M;tL'OaoQS"+#u1,_ocf6]$TYOMhGa(b46`:3&eDEIbDJbLDRia2&l>pfp)4 %3"G!3R(JoU_Jr-5c1>ur?rqmo?65]uTVrL^jdb^&@N5XFTa&ag7,l-%XVks*7H'dSpb#HCA&JgjbdNM::)L$?oG3YG^I<0PE9eTW %U.C:X""RIhhQN:p\luX$E.&Ou#mehNcTIU<.\Te.U&\adGa/""tJPo6Zq"7O'1%p9_L$-kTY?*YhA%_rk:D,dn"gb_&BA %n>^E#XERJ2M[Z@F/>GUdj.Z>rpkV,/6m#Dl3V1XfXPfWd-%`S_81SrT)pf^&7p*Tc7u?`#*"lc,5"^KR9(F_!e/hp^N-Vmp>$Mq] %u\h^K48pHRk;144V,`WKdWp_X(`).`BYmN%<&fr>S %-QqUV;8T(rE*!sq6jFU_bQb)f-]Qee0/;sDAOO`HHVI&"Yk(Gui=@f9Wrt7eT4&q#Y*+un&=ojYfuXt_X+]n5;9VFaS5M2HP+qd_ %'1j/i_V%d0=+Y"J#^/c6oL'Nt$!K-4L5@1e9%L/^FF2S**,)W`-/\MjWNMED3J365Vm*'FauN7^gaHiWXdsj>Ti^4^XqKeJJoYd\ %o0f'O#mn5M%H$ClCR0`-pVq/?ddb-1-VkHLZ;9`HjkP8sISk?]BX50N2"sI3]c!EObhO-dou>u:MU)s0CJ8d:NKe`VpBtd)/^\fA %_-oV'9_r3JQIbppYtPNnI5,dQ7b;o:[5G@Pr\H_.\6[AqB%\_Vg[.>"R)eYN>)Qpqb\ah)m#+?S09r`Jul1 %96k[MHhPd!Z/#:a\Lrf4k;prQ]>uLco)+l`jTQn:C%-.Mb7"%jND6UgQbAmp]\M-0o"SOB$8S\6U4haX=%^2YCcBBfaC'4V7X'q= %aQsE)-j:K,5B8_LL40pfgcr@m1FK^W(1`fg6(pB]&S1+;;!AI1";u)3j#;5X"PKB@!hHi6oG!7K+'lPJ3jR_tjrQ<0NIPH3hB^+D/h,fMKfB9/o1rf8&:AF)0T9B=ugfBLn/#iePDu?NE5$NB5 %6LH&frFPmqqsa;L]OhLW+ouPqm\d&5-HjGV#:i?'F_[:ea(UYSa$XL3qhRY0bYoJE[)qqqT!:=pk$+I]NPB>FQ;)OIiiCoM3I=[* %l>Yg_Dq[A<,rC %ZaHqR^T-#O?(&9W]o,9f@-#.^9@YPZ!_[IDgO>J0,7cRd)p@`*fQ*#I3u9@O83o/jYb;156`+[g'4\&PJo(3gZ^:9@(qSST7f),f %Y?hPflco*7Y'W(0jdk96Im7*(_?)9@t%Y?rj,N/Z8VY:<2k50i7/H`:_j\/OQ+ %"6A!0AjC,$2*6#]^kM+G%J3r5N*=r,[%@2!HioF#3hC=;P?N@uKSfBge+M5kDDQ^X\XVsT-$%q3>C9R8I*JPWO=e2JF'_u=q+Z0< %kF?tGbMG:ihR"ANE/e"a?If;'g>^::k63CojqcjXm8uL$53F$X143UUdu0p6(]Q*sVAFmH2(!k^QsQT]]4]'?Kki8(ie8cHa?s8H %8%aB'(g,?>>h+a]Qf,/U`Xslu9&;SfARqqH,S8F\Qbs[I:i.C$?BD])mru<3]H.i9h(Boa&_?FA\Q'tG]\H4N5%VFE,@8%^9=PQe %Z\'3HXB_T!>U*Q@N!MEg?@S+M&Y_*3`A?Lb&e:a0D`7:2>T1R=ie>t*iC]lT7_FtiV,8H/#56In0%_5B2MET>ie$PdeH]#srgCo>/)64/0(irL:&C/!hN&_KYLDrM>A'@)N8mr97JrRFX5E6F8QF`LA %NeD!3c,'Xjbf(KG]ou^KGZTbpAXQ2+jAj^n=Q[&9KdXAT@[Z!-'fn!9QFYd??;*8SZHQl:nlf0Uf>1uVniB?gdq)f.p5$`#Z5O05oD;Wcl*IeB[VYDi55R7l7^"5BKYI''S4KC$ADOJcBE]$&j;ogq,Hl!.?Wm6[-=gN9TqQ+so's,C$G,4UbD$QQQAoL'5%"?$d9$*-@[DhT+!peV\t-5H(f8"GYm1dH$_KZ %Kb"ZWoZ*CZ4a95:A@CU]lk0[hnQpDX1q&M\;c1W4rC;jh3gT@B>5p#2PNYS(NN9BL82-#"; %?LD*3R`eH=/,'(8O1VNLbe+'cX,NZDLLLM$s3chJIeP9M>Fa"5@-*G\h98IkR<8.6)HcmpA`?JS3bE %hI'G!Nn(1?*K<;KNQ3)fX=jdn41+=pe.AA)L9XAi:;i0ReaspQM2hfH93iXKrscO %$)C^_IgjMn"F0b#[%nfR;;p6#R`P0t,mD1+Od$Nt^"!-WNfEDcIB&Ej5KumUD3IOW;GIcORW=UDUmrPg09VNNUmrR=pH@\E1attA %[_WkODGlR\'3%r'UnC[24PoH;M[M9OiR,7mMR]<,/-p;g;70KYbB[#h7+,CQLBS.-8pXah',JM-?\l37*t]RN@Uga4F@:A#/h+ka %&g>-HBj5dd:bE>$r@VO=K%dP\>gT5gm0R[%\0*F:*^,^^L^Wd^1'nQOd>*UG6]cn[+>2mRdF#WL79n1aCX)%0m'r^$]a6gR#i^H- %25h-^>gO-"1jXDC`s"V75qdX=)Bugmmmfm$8"UWF>VIuH*hLL4ids9\GU<,7P!F]`V?;Mr_W+crP6i./7!M.[(j1Bq([/#dJ@Z"1_@*97R>C?]]F."L][e^[ASi8HqSY)<4^&]81!MGAJAH0Dh^$(sdqI!/-YJ20M`rn=)BGhEI0Dp3Y4qnD;@/JAK.WEdTl8#D6)WN.W4ii/b4,^u4V: %"RkgU?XOD=&+qT&n1T.X07,B6p>>tcpRNVJOhflieQ"B;22=$.kH8tc[??a[+N.eEq/J^H-#QVLh#P;G__,A;!.;Y3qT.Y[>+@c*u`*9iA.?0.Ftc6rHcV;$fh1,q\dFC2"Q.2F!nbk'DG$c$#(b77moMEe5?! %LkMQH.48faq_F@eUn"+B,l4*RrhLYc-YUjGA0qIO3C.?YOdd%1XZR=uG#FEd'?'MIWC]BR:=/Va,UN[d3C1OrQ^JO5jTOQ@+u^rA %apFM>"c5f:;GId$ST9pGUmrP8LP.<08@j4s>TSHl+=S\:W03?9A,RW)lc:(1Ts %,RZ?j$Q'kePbQ5-g5/+_IH/EX2Tf7qXI2A$@1O6pW%ruroNn,%T*EJU]M>=8guU4Di0d7`\2tQFcYqoI4T3dikI4Yo2Eh7f+p5`2 %EYoW10Os4b!d#MXKRr*YRNHdq&98U)(=V,qi(d`h(bn5r#)9C`i(nlk+DoWAH]HE10:O3qj[*"c3pUu5$ %=-ZqeZ>s0's/`O&?$*P+hq6gl1[dr1hpndaXD-qiFq"br65_UU"^UX_S$6c\)ntb=`QSCn;o@tNouC6R[8T'VFh8dJ(\WY1/k3DZ %&+Fc1mc?hAQ-df?eIP16]6&fcFGSdg0=N\be?l9UMa]52GLF[D5."Z%C^r@V-[$bn2Zqd&i8DS'3*"GEu9KcYCGO1O+] %=e#/.]9osmYM[=]G!/3";YI`-)Ue(`Fh8?Q_scSYo@YGnHGXni%CpVu=Ik%9$CU&:8ELem.!%DQOj%TY,naJ5^uk9QS^!&qg8Cm` %#EoG\1\\p6LA%%!.9+-(Oe4(H<^i[0MFnU7P+[6CCk?cFik+=h&hFjG::fi)oJ,Nk,DPp>gTk?UqikasMs#ZOjBY.Ym@-c[7KMno %'<.,ub@G5(i5-)j_K/ei-_8\\]oG[1pEfQb53_;B230r;DF/#j %&k).Lag?&6%d1mFq70>_^@;e,a$\a=g)EM=E3PqnJ@REWo,=e&(*Id4.@H7\EER(8Q %`d4c%fY1U_?LODdA4O>ZoCBFTK1).n;H2=*8>HP;Ge_=j5pB#G_-E/Y)'i:*WcI;M[RHimlu.s^/6Glp%f0Q?20^Ehpd9']2boCT %$&7Lr$i9DUqC0-W+k>fjPB2H=N'8XiRqk7_GscV;6`1P5`9E\&RM:o@T)?No*(*7Lhq/m-(d`9,]_KJ,,_b=+_n*"L^+hY,OIZ9= %>3*drEI*d-FOMihP %hPpb*3Al1=hN4#9@u=WuY'kb^=u7QK!XHtp6?8(Vk-l]`LG^hI-7:;h\$oWD`Ad#Q,0&k-PJcs2HK4T%T@cq%X/-JX=?>7!crG1r %QCk.XNa*a!K./h"+&EAopL2Ts/j;&R:GRAD3VN\.%.WuemA&a=t??QAJ;YB2G3gNm!'?F1p'1e]p3rS"6+0J1N#aD^Q%l' %1UBKClNJ>lF?KREhK/=GSh4_lD1qeZ1o.!`h0eO0\"NKX[areQs':/Ljs>*a4Z'qjg;%mNJ%:?d53M9S4n>Ane\c15a8]f`mro(q %U3??rEh3DrX>4)m?-f<(7U3q@4c-PIS/f,3MqAeJ))'QMUo^(c\t1E2/m--Z:Y.tK$\>K/S#uu0&E,^A=Qt.9UDR*#,tuoHp631; %^$p-WLHLErkNLh>/EL&WNpu$)4A3$MO$(2]6VF'&i&#I#RKtFM0Cr2;0flKuhl0 %:"Kd,]9#D3,:+MDb'9?Cn?0,AH\Ig*8-3cj %X2#-o0ZH`[Mk[F_.0b<1^ctq]'b(.oehG]=LGcnR'Es];JcH&\r.C^N"!AGN/T>t:!"c24.4P=L_:^U![pX,)^*VcTGrU\aK/!EM %(n<0Hoj0o=!!idAbM"&5=%.P%CEh%>XSQVef#4['b1XW\!\jZXhjQb\!5^:EqC'YpYR#m^&.Hi"^0fq/(6;]tU^38/B++YjP5Bn1 %VJKcs%-c''+qB-2(m-_#X[N4$%/9fqmtV-50K<;![,;&e!\uNi!!idA$bf9<[rjjf6S%g%`kqb>>[LgNc)p$!U-"lZpf%G;/RA4E %-V5f3;!$]&T6.&qC.Z/W54l4h[[jZ,&:.D=Z?#'-Y($)H()a[E`$:G*LYK+d7FbVMQb2/Pk\.ZYr<3_3:J8BC]%I#QPuP!608!J( %QW0(1QGG/N9.J"gY_Xe+S;35+csnAS>>CMaBQXoI>@,CqoUZh*YP+""B,fOE6>gP2ja,I<>cO%gISZ4E'?/t8Er9&8\XR:_lA_eKP:&9r[U8j!6b_%`.@%rlj%(lSE9fD+kI<_Who=;MCh6?GmkN7h>F06]*Y;4QIF<6+#!":qq %A\-E@j&M[H;(,h.n,4YG(fiE]IM%iR2od:kHGE?So;u=?]k^B/$RspfN_)_u?!+R@"&1A#afb1(6f/-#+T %N_kI)VJ`,i@FcAX;Aj*7.SS!hQ_0@.;SGV%&E>CT[e%,$ICakEl'M6l5%I\/?-/TG>6\m%[q/1X1"cF3/$"+BGP>!QC;]l&P.qdE %5$&mZSgpT%2t:TFR9@n`eb0s.N#\ZYd/TA5`.-4iLUTKefHop"l=_>@J";TCeT/5$s6gd#]DWp7`:Oasm2"VQ()_W8-;>ujTUpV2 %SP_/"q=ZS,@@^T9*M9Is<\#uie%As,JY^_%\HM9k\_-1ZWf`gs,5q5cdY?$%![XTYGXU!Mr%j4s8/ZX:82T2+U`,)^-)?Z3icZrH %f.Tm.9m#4Y[Iq^q=?UkP]i!7B1Cljj>Q,.G']CJ`4=Z(-W9CCCG#SmN4M5mSY4H[)0BN#31[47JU361E`D3=8B7JV!][iL+SLuZ5 %7^:86g$)qH1F@:VY]V:PSURopWCP'*B<]\\5I/bca!s7gp6V?LQ_",BSaONnkHN7-Z.#]'RJ.VXVYjM;nr_0X;cKZ?2Z&l-;>E:^ %SU&\:bZ5OHFU#Psmh,At1\=t)bqieo%-n_/GsmgL"Wnq\"G9MX/"85^nD@5,O?hc:XI,Q">%MijaVp:s3/)!kN2H=4Ud:l=Ng %D'TH-A*TI6'tANCX*;$/$iD<^kR#.al9!k8.Hd!m;r@L!]&S!GA>h\>.'um0(=i0JnWGMdk4p&dkTreep#-e05IaH(6hQ"l>c2H5 %5$[%!KIB]Gpd^+s,uR_"R*Zm+WXk"77?&/7-[@2d#M"SqIE"'G-e"r*:_L559i4\\"3R %S/`_d7$0[u?0OD&g@b7GPZ0eBf]%nOe@1"o48YW?U;YG:((I;4G,DDiJZ]4[8[&`c7":PDGFP.lQ9P>kZbjXD7jK)coF(2F6r`%f %i$_bo0$2a"E>'Xi?QX#A1EUJ?3nK&uLQkuZZ7'f(7;Mff(!Zi5k7(:^0W6t_As5bCOr^coNg#$D_uKt%LW %Op^^>%j`"$U]S.%_heOLWF/I/nr!Z(WPGme:L?@C8-O+MKG+^o;ISoG(fCB8(SSbKQW,[9q"Vf0QW1c`-00BA>q4c#pS:nVMocQ: %/9"/a71C[]\>00S5.N*pP#QsRH76&6,o&u,:J>5K9.I^eHml88,o)sL^.:0f>q.P>4G#FYZm6ns/9"/aoXfbi$X?Tg:ZO+"^.gP; %?S$.f"iUitA/,JW;Sh.Biti).;Sh9pLCahu;?;us_h\IKWF/Jt7D_'hV#ku6LD(&#;IOsf7):mfV1PG-j6sroV-`-O2EG22;;&ni %XKoaK]M4Y*a_Zr"=_#[g;eKkk1_@KMT8htb_Xd[Z&eEbF8!%uR3g`V#JQMC@F2S0f%.]Hr0jN!i`.JA5s'Hli0WZl+&eFsS&#>3= %9E8rXM$JJdDc%9,)pLGOik\:Xj%g=!oOR*sX*Ot6EBY"F`d$;bknWWY:``GfD$%$TX!J3VA:E8 %]34(Jop=)^%Gne0K@\\%"8H.3YB(c;2Vp.)_^6AmDY&[[j-aemh[t_7DZ0-6FVPp?WAb.PmVTgK9LBb2qF)@[Xf/u/DMa!##'H4k %)C'5U7T"S(@jlsaei@ArG:P.i;aGYQ\%Qu?Ja_`PG;j!qA@!5EknZ4:na]@(^Bo_X,PX?r.q>R1r&4K?:+WOAGMmC8i@?jG01t'E %YJ]8b`A5F)"anF=8^Z?(T3Vndffn?K*3uYX_=SC&+h&e6`!([,%/h*W`E$$^>unGpgs8^>FX=&]nBI!Nf5fEKsEt`MH-' %*qXhgk]%n`ECDsSA!9c9l:KLVhnk*?P3.e=N:%en?fmJ%/<4UDTjOm!Cnj?u\]cKQb=PfS&+I!aW"+1/TYQ$GH.S%PpUbAT3Rd`E %1tOj;/"U/^"h#a/-Hk?5mCmp1qEYYdhXQKN.VjHMN%FVq^nB[(m]RjP;::@Kh"II"$ceDAo7-NC,+jOU^ZbiJR)"AWi!\W?$`/,S %n"XOWnR8FM-R;rjCjp,kjWA@qqT#(`_r(]Gi>PiQo.MNt*@97Zt?0(!%D+PU"f>^\pI?!>Tm_6!aaph,coi/V.Wo;'a %8kE_<+'4^qCh79b=k?ub["'a>D%HRZD2\!l;nXY^V9.r6KD*Uh#5U8OSa:0:Y^n^E>`bi[or^,WNHJW!kG:lMX)B%]LXW&rTn6`f %7P[Me<1V/>C-;t&#Hmhto^lE\F>mFc(&bP60qJ'O[Z.35DTm;IAIl?e`^2hGqB@W&f_Dk]r#8rOU&3K7PINZ:F&mP\NG`_6GL1W' %hKSO2Li9"hJ'2:mNFKHmn4*Q1r'l(q[O]1@KW299[^9R8S6W*>6F;LQKm[`OO&7=F4GObAqWXNrCBdPH@%")3X$Jre2@V %:i-`?lbDe9&%br?k!AhmDEKU18AW1-g,:pI&,;:EW-#>c^kQSulGa1FO8`SJF`TH&ShprO9/q6>#cJ:,BjeccbuaK&H;`d&P$TgZ %SW+PcEYQ3tEI=^)Q5-JO2i\D+%Xs9W2bqsSpbV=[ULh5Pd[FE^W4Ul^-+C]4^!24*J_;qN0_j\'`;NISWkfd%2pNquGAVU5AKUgn %DuT<%o/XRb6e85>\7j<<.>CFQ0S;UdN0UhUrIl8'Ra:o]6A0&:;qmGIk@^FT8'f?!dX:10LM(0tBg,JM\MSeU9CnS*%alA8Bg*1A %i3)KCE>&iSi2gm/6*"]`gFPGVi")DL%^5$:(CGFDYbX_m\Zef20sV%4H7cKFM6o";;gABJ[V6C/N;).a0p:I'ZuJhYIF=BT-s4%k[3?V/2m&n"J:qVGp9soKBQ@"&IT<9A`)E3@3B+>)s`Ylc\Xr2e]aY.st.T&*7tj.s1/K!TeK\.nlT, %PuiIG$?TMV[64.9=+Ml'!D`!`^KcK->_TptL&WU)_BF4n%?SkL`9%"2Y(AM;kqsru0ho[LjOl_-#!^91&6GR3EX\YSrW#$#:9Hnq %*Jd0@2k4-9Eu"%GFP@l7'\=qJ%83NJk`2bRAbtee\[3^^k0dqc,0$1YfpSepu^Vb@Jo4EebO@9 %LURIZc[2-(&e'BS[OT^?q=3KW^[V2NG%2pa^Src>(./o8DAKV%4X?>JmG[_>U0HqTbD$7_kH]9bG:T3pmIp%USO'`V"o7br&Z^&7 %>GpNLgTU(bPS[@>'+[ERdZS(IeXhoZ<4G\,;QMe#mt^A-rU6T/Ku[r/dnaC"Zi]Es`fh+\B*fd8K\#WM4'VTqK\ldW@^Y1YF3?!. %b\+ak>5/CUdePG9>Snfp8ER8TKi(2K=XLLHkHi\4a\68:WSmS'6"HD1,+['.B_1'o>%kB;bZJ_l>;DKf&^4nHXu*RB,_G]di2[<4 %@C97+_dpn$c8!@F %YmtE[>bpY*5)p;1:kl>Jmq8V&3/Z[rQ!,-+QLtG]HP`4?PO8%-`I1WGL:eM.0O&YjZ_01NpMcB:p/712f(,Zdd=U>YSa %iYs'>/4&@Q>3+gY@E$9p[E-V=6>Ms-_c]sJ2,Hm"6@teXQ6:J_B2rH0lk7N@Dd.a>t7rJfRhRuQ_&BbuEjeMeRVr-Iu@3^9uGA_A,Ri*Fl28(CC$7#U!",P8>6bPCUtbIdHM>%$Cf7;6DtHj'H5 %%8?C7UAmp5@YqLD*)#XgQf5T@/J:g8Xd.iIDkifgkdu2,r`.?LXfm2:n>t,meh9r[i6PO'ofVMRYsf"H&YCnb.r_'ur1_HAm]heN,`<8eR[tqd8J5 %6`]b3[Ed%[fi%8+q]oeWk)G^XEn.\dK3ObN`MBlEG!9AVbi_lT=0`op3VQP)?8@9'alC>/'Z`YRSS97X@Lm+hSRbTkkR([q/RXgm,;Yp&5B#U=J[A]^'tp %\8_JBL0TluAfTZ4't8YX48ATi=SF)K#?1J/MUsQYX5rW(6W+X_2IDbRCHnqkrcjoBEXJ&3\V'X&q%`3&4fi"9 %Q@r58gARJ,)qB.H!K93i)sWf/>'055HQBD0(@K9cKsO'fZhLF#]"3s."KrRH1;+[/X>"^CB$q?N7Z`RdR2!$k"G]nRZJRicISa@0u=YpqK-Rb %,t8_/Lp"lK@"Ss=+>ap)>%3.LQh:eM8(_50rhqVdf2Im^7eSouN^!;^Ib6Z`msKK9>0Nk0+;2-%#&sV?WIO-qpCA(D4f>(MbXQ#P %iA2M93ZE59h'c,hn_f6t2n9BjWhotS/R^Uu`k?6A9F2(PlV+Cl<,72tdT %TAoP:G$dRN'fVt`Eo7&,$?NHG5G#A@E?ip(4P,_M085u.Z"!P+$V1qB%8;=-&h6nU/R]8\54/rE8;q(''M*:>nL92\77nT>Je-h-:ur4%(]\ddoCZArMC5'.Y`3LI_tZ4D_X4JM_r0:C<7 %,'A_28h%,;7-Y=Pg&>JB7"4MfSfSL1<][CuM$olTT*J!cH5hr"1(SQ,%Q0ocFG3.HnTQIN$9oUSrJLfUOk:9+4F#>Z@!9Mr5rdIYj^p$17'[?%$, %3U(Q]Cq]1?Pe*@/T:m[<\"s`\7<>:ik$s&/tX0> %.XQ=XFtUnF0lMCHd^F7m<6c/u(!5kDZE&oiY"88tSB*^@m!(D5&]sJ=VYSfl7jY=P[rbbhm4EG7WP]Z;5?duTN?:5TYLS1^V9jVW %;lqk6\K>i/!?P9-$U[q2*h]Q3?VGt-?*3PGJ-E&5c!8TN0;A[lHJ39<0Y+A4WomI`K`C%l_*_!QcD1Z=oH97snh3TG>"6Y^dY%fCB?PVk8HK3c4[gBpQ*h.]HBc@FBh.`@S@GLY_(?D%&QP;:3,te`b(m%QQ?:WB %qSh7`r++4+(l=XQ]$rfF\<\/1<-#VNJ::ImZSOg"m[F#kldPP]H#h7F %HUH"c.C\cnIVBica$'N%:r:5Aq:4jtRsnEB.r]Mq*hKZH_D6f*9PFG;NtrT<<*rX"F9]E+LT.BC55c',1(',uBJP(]1AS>3B&SW63F(U(7QL9P2$=Y9bF@V!\&Au<3 %Bd8:_W"CBC&OKAtH@<>f-D:0;f).]YP^R'61d>d-JH#qoOsj;-35`S\Y:g>j)3?777m@\=h>'eDBmt$g7fZ2[T1r^eq8#i)RdBj6 %_*Z&f*?Q<"#Pl9c*>q#I;MpFd@'2V#![7\J\mmTI6j$)+BLKNSRklVO6+hdU]*Mg/^*IZ8Y]PXgKpd,l=?9\sD0hWmXC4H5deD[X %pEA$cp:niXSFX&dp/\](dV`tt#B;"L`YWt3VoTgWjRc!\R?>31i:S&XMR\-0KN+.5dAP@$A %N!Oi\lSSS*i;'4Zd/9Oec%G2WLpsq"P3DOrI+fI4*9-P[p[(m/8jc>hd4qRA'e=qL6LQM;D%Fp&J'>i(V?&Gg"G0R\/%(Pq?B+XJA`b'XK[^GUAqD-l#]G#,0bX[%6MqnE+#@=Ho?\(9 %A!/@j#U,eAVSl/q&].QrGaJK&)l'`hnN^I\O`Wru7i- %G[]&'f#c\u3$biW)CAX(3gNp#(bmoh+&bkYNtRqBAJSIeE5\X*V;[c1bS%i"Z0?eDak^#>]:@Rm!fT=VSO's>0.jhO-U(%or:H;p %X\@Pn5Bco#3QToMBa$XWjD4R39o54OAL^VOHQp()*(mlT2=bXb\iO24b3d$n;!XCP>>SCR=BFq?0%AQ&aMS/7>#\^J1US>iB",16 %+)[Qgo!UYF$s)-Jk-gT%g[mKm1C[>gN\3g-G>":='$`L(B6JA68WF?q-[Lq0\f;l"o4poaf,S5qcXT2*Y)^lN]sf[*R3OQFN`uE* %99'S/K6]k=+;/2.mI;eY7"mgi`Yi9HX$BD7KHP:<:)LKt>V,F?@_ke&a+Y9gYt$M>A557$>_P^\Sk)aoln_H"`"P*THtJt5eIBRC %P<&/DR=+'Zo45#m5ef]EoAhZ2*Pos`3Uqb9G;/Uk]@C7kc#KCWHDITT+e!Bu8!(t[4iiQ@6.l1S#f:O=jRVrubQT>BVo4)?aYE,b %GtZmjguPhf4N5]c:4,7oUBTf/53XfPkb]um1*V\>op!Dg_]#&Lb;S2pV%SLZ=9RYZNaX;W-F8ap"eImZ:QgU54ons2LgiajA%Da: %\d]rl=ib=?#1B9OmDg-Hl>rr9>YT0Gp^JcmHiqRGG6u#QQUrR$3Bl4as5KsfZZ#NlE49&j\\;/Z.DFCHdXg5;Phs&e_iKtFk"9n(6ftmpr;P)fj1OE(Nn((L153F)ac58WG!GN`H(n*7n7)0dB-l`4-T?dPqL6Ybk@no,:UANVgMa+r[''9gP\q7k %aa],GU413emTDdA=g(GeM>/6H:``9YbkdbEaD[`'r.(?@Ld-Ln2MY7$2dNKP>c7"6IH].Z)qu<_bHnh<<1<3<&krV68#IunU>,Cg %R7uG:$_s_g9!btUOa9N)?%PgW6)8GLV=2of$p8C-/q'WMAp%"[l8juOE2Tk)*2[hkBfgGH^QJ[R>lnL30UD]\3H2Jo^f$rh9$k19 %80uOV61CVlO"3LlQ,$"^Ot/goQ%3tflU%+Wc'6eF'r#;tL+7c+A!C4)HE%+rqh^N+Hu(5l*)fj9;,JY+N,IDHhNKHUKJp;V8eC6t %&meNDkNQJS-$53/[Ah<@.Y7$03`k<5W?7*h+e,M0W=mRF1]LbZ\J"O6$+^6OiHfg1.Ui1p,[:Y_;\-VRkc#2H8C*Qo(Ba]OmO+1J %pqM\L8CUm<99g&VHEIDLd'Y"%9n\X+-(MYe6s+gdW^Q16FAib8\J"O6$#'4d\.T&1$a4dMN'!.7%XDL3NN:LQQ'bhE5l,]5lTOZh %mS>Pk1+Pu0,,kQbIsVPfO\#ta^+[RR?dA:0Mja%7m,1#;OC,d=h6mP+GRp%2Vg_Rp>JD"j8CL%FO!&scan(]5>TrJdUUui9i!O1: %$)4W>e`RU]K/JSmb)^$4&'p)r)dFNgGXg\QLZJ"7huU0BXN?mA"8u\ei'e9o;uQZcLnWk;F"B*13-rQT+o12t"p0k7bWUk)D/#nG[c[j7B/ZXHXp55oftg %I(//k,30]Y'1>=n09Q;VqCY17EOGigAjJKm$NC)I<_:jJ?6fP6Ps6$-C)lOQ4ZaQ"C)e=8b7$&/6D4qJJb'p3C)lOQIHK?b-n>gH %]=C](E^a;^]np;Vn_9Dcp$kC!f@d+#s!8=Gmc8B2o-K&[7-Y>_HRu6gAA$pZ6$K%p`tO7VLqH:gDO^p`@h)DSmdZIqhTr8X2a3Y1 %2=u:Te+e%\p69MQ5+-gpK'7#u>%u,N%*,,]I*18n4dFf=,19U8]2@)TogVBho:qlOISd%TSiQla[U7Y>Y%ns>G+4:i=8LstkH>[@ %X?dCB_)8G1%nLXK%TigD'f9/_46V=F2EpXX[KVXUWR(NV'UYl7e2'*'"_R1CpaK&h0_=(e4-Lm,JV%dUq,Ib1QuAZ%k.'W[8f>:X %q"YE>ij09O(Md`lo"#?^/KFg]Ml=0X^F6PE;4mhU,M@d"o[,H&q3kZ8Mcn@4hjhN1jHOuoS/BH4Hu`+r?4Y` %+mgLSPud-^([e;'crE7)>1oqXCB8cRPP=J"en4Frj[jB`fqN>1mdu5jdUN1LJ_Y-RE1F"pSSamUjE?$$%7uE:IVq,*DeU3*U[sMo %r7p$M5a#>4;nSgbbXcbn'*=lg.97]S>VA!E#:t[k8b77S>#2/kgY29blMTKU\Y\tL3h(C4U@VSc%\!O)rpY;6Bl:n$4\Fh9S/rcCi2^M]nrK#1;\-CehEXR(r[R5AWC7JMhc-uSGP^!?/#rD&TB/6s;RqLYR %SU^0d]NJJ@pW2*oiV1Eba&H=nOfX3fms!_WPBt[!5^ucTA=iS+DcDk.gtg6*Osf-+rKIT'Eu`r>a_GU2Bs$'Kc!FUig41KG\['YI %PD(Xr+$Wm#Bh-NJ>:X'O2.3.l=2m.]glW[nEpMeuJ9,Y5SY@M)gPu"\GS-TE%`2FC>OWOZAHm:K_I5,?'g.cK_B-fF`:ap[sGod0,/IXC(g %FZL'9n6=FC^:d.Sm>9=^_Y7qU%W_`$HfDceH7UoB)tthA/\l:#gc(a5m(i)VTms6Y9FMO!0&+BZHBhHYZ;3=(E<:j[<>%]#i-,VO %/aNDL9#/"E&,`$2<'5-WgAHCF%T3SX<pS3H+g%&V]&3[[)r>2j9\K<+c0A(d5!R]rW %@n!][KG8O(&3VS]S5(8PL`T%L)7'WH61bR;(+DW^,P:K[d3p/a(nl_fauP8apR3:K6G([.kMV14e+X7b#n %_iWFfJ[)*"k6SY@4fpRCA'LJ1#\gCQ(i+*RpU/S8c^1cKMN;$4Q"Ulh&g#9?H59D4Ug]qZ98)u:3Xl0sPr+1o"q)N:>Jc$h%Ea-s$]]m,@NA\&K[+(2$5IZhIX<'n' %(M,(X<)CIRUK+/_"'M#G'3^\#1O^Y75SiK1;RTIX2+qhlB&QET.DrR%@VQ"BIUqGh/G2a+.1F%:U*KECj^:T*8to8JWSocg*i+.@5_eX`9$t@GJEbnX&ijoG@,XQJdJOlH6+%`F2Q+2 %gJ>!KCsd*H\0"l.U8qO9mq5fr67E=/i$pFV2jCMdj'esZ>_KVfdRO-%8o];>qtQQ$,$:5iD-Y-%i4Yt(J1QlR1%]ju&!/fka']@# %6T[Iik6_:DQlGJLdhN#R.&AS!M5>M?RpZ]V8Zb;%Zlko"88Ja8D=S)dN?_?T\sXNbkH34^eceq4Xl"Oc8uYA7l.r+$/28_n0sT3` %_i#H#cHp#o6Xr#rSr;O4cqRZQL&p7%+LQO6(KnY60]oG.n26,:'&DT+9]8G;2q98u>iLY]_i*k6%nV!XP/H_X`=D7cP&CnH9?N($ %[bQ^V*M?]F>`dC#2s]gEW3Eg$V"Zm];f:G+pm#8'icM`MBU-([B)RuSYM:>U@kPkllVm`>6U@VJGn7$AG/nLR*cn2/W%3jj@Y_.q %e)QtHr4LZ0d*fW<026>h^>/_c4"h@q?E=EBiT8k.oXO$>0;^#U,EP@5%6Pbfa2buIMhTA,id#'?U"#Dj>FpOJ!>AT!7_,KD54A7. %-a7DccU0"fS!Iqn=6_=YD]L)GJ$],_m %6s8^V>qUq!:V`Va0?+;QkQr*U)KQ0qd;I#<.RB"](-,!c0_$9aL5NNp8e;<)PZgD=ph=Z1$`Shc;$@Bn5&t$?Q.8"M?!XG92f)+#pkp9:FGD>sf/"qQ?A0SUXo:&Xo3'b03_Jq95q2'&1*\\)VWUgf_:p5F-<6QXfK#kgi+<@g5 %Uc1!12ugSZ)gr#-?B'_PEfcS`#nF_n[>'R,9dc%P:be;5_-E-FPCo)Pk\k#=+r+B;43MPcV0)Mp7'SA0nbV %(NQ1LDl0m7jIa9HQ-c)GS8Uq*4B)P%bbL%8p@mJ#arI&])TS&R`kRhZu4I7QL\Wlf@PV@&\Z*Yg^h%p7@m&'hFc" %K]skI<8dF\G1IV>;M=_W%UB6:S.Sk&%UB6$,IGUN;HKQEA"Bl69+'rSg.bXG[U\(B`ZD+^!rW`t]rt<$H`cK-U8[g/HrG1pW;qX3p%+dOMrtHKhFc9NFXk_tC+kR&[3F %YgdSkV(fH:%i.^4rdO#!697*ISr1+3b/s#J#On=V9pKPIdC*>jM!9PlA`=m>''r4M7iRf$GG>ps-d^6;Q.' %YIkdHO1/7n>1j<<:3OeN9'kmUrV0u2l8P#TEq6ZB8g1RSIMlQP\rU@?YXMW5KoUV.F/P->52D7']L%OBosWtYP9$Jc"C1^r=BWG^=S9S5"hF_Ml*]1>S@,],c\RfF$9t-%%.c4M3gb8LI-Z^5r16o5PLrB%o&aRcEYGGKB=ck %>o?XScoa8Bc=HpU6gVQAXAWA>7J:pA$W`gRfCF78'%QoNnK'#^Ae=A\":,L4[@@ZB&VT(eX&PbNY,0([Y8L9pTK@W_#u?95d(25. %6dpJi%eG'.X^l(&N=?_Z.V!U]NkX(lB!Ja%d0Graik9R1/Ytt:*;\49-i2H^2<3"`W?@#lHLZ$id%U+QGOhf0l5ZO&C[H(BM-!a$ %TT\Yq<$('p`*7>"%hCb<>AO,GP@+>j9q%"F2'ij8Qfe1SI+TG(':GE:iQpYj3U[Au%Y$BlesBpN)*"@/1\U8D`4Ai`$J[Q:N-VlM %".t(Wce-o_]_$Yt)I'r#rf/:?gCLRNqX[]&Eo/Y=CDi6P_>ak9VH;l#QJn?Rs/NB\2`3eC\$S;cU6/LkgHY];C3U(p#7CuZ@C6:dP"l$V+qHh/cF,R5')#X.1:Ur>If*& %7Cb,bc'^t?.O%"h1&OY#L5BTHPVaj6/<%&dNNa@hKW-BE>&++*a]U(ce>OdPn\t>h_X$eo2d!a_=o*j&%JhO$Q@?B@3r,+kiH)p& %9]fCPASl&LNu0VW%"nBR=.eg[6\@eC;#5n6.iEj34Ba-(*TF(D72tR69Bug5s2A0cSD*uFcHf594FSb%`o;OMUgaf3bn"pp9`BE3 %e$JWYdNtVsJ2#PRrkpY"Y3<*ImiVQRA(BPG_#HNTN9/VnH0ACAX<_Ob4o+ADkl\4GCSh\$t %>)S@<\*17`R,h/SW)X_iMN$X0;@N(R]QTM*=:7]7AO!YdE')kO9;8X,)5@T:r-t&$d>GotV'Q!%OEBL*\6DF$?`ZtLTfkk)o>NKT %V*;jhB"hq*^(0=0AP$OK==1c/R7oU3`A6t[G7&C`-@2=@@#r^N1Ph6Oht<5EqA2Q.A>3pNSeGI!Y,M@,6su%KUX)/mq"BXfU8*kH %mL[YuY/s)p2oWrIE2t38@.nIni`X'UF8Or)6Xff\TMr(krJ9f^.SUN`*I%/mR[<, %>_,\s4+T+K6cVWDq.H5mbVOV.nWWgg=BA(!?W73L@C2adRalg/(J[/icL5*D2.rd6-Eil76?0Ef5!;S`4/KVPZThR*..$8;6*r?( %I+9"\4A0fGrLo25a/cWQg"GEuPOi?E5/$q0ZOuKo;X.u0#q=&tA,8hn`_SMSCSeK%i5p>e/8\<>QfPT[gItgcf'7n`6*d0'A[fBb %R-*>]\Er_iSo`qt?!?tS*-briMh&rb0Nm/-q*im47;.0rRU=ELB\6\Vm?8-4\qdQ?`m^"o=p+2YN'`FfAm(]Y&Y_,c0fnAXd,B8ViULoUUVl\8_a=Z^Pn("kJH`N6faghS)jocEHRY[6;Wl51_WeT=;oI4Q4)*Pg@$$'MKZ292i[a3S %Rn")jr-Y9HIh^<+:!),)+:$*-q=7lb$_3_?VsadNeJ*_A)P<@M]\C6'*CE4.8tjtS"HeDNcKL4+D?FBGioFra-@O1n#KF:`/.Her %D6>8HhO((X"YY%%bS)S'BT'/RQdMX-8niPmTX1o3JZ6s3B-5cR)q\i@dKZR/]Tc:3$`T)fm\9ut_FdH([i'aprT.aB;-oNrj0tK] %?q=46:Nq[UMWb[@*'g69*Ni"[q+&/F*WZLPWj,)IMr;2ABl08i$bC-oP3Y6ZOsZOa*Lm;?kPE>7aTfu)j\'k_fB7$iiU*>(;OB&I %l7U0R4s7,^fd]'mN1e.)j'M0AH[c-g1#%RA(hkq=6J>Z-Wh_AZ6J>Z-\Bl't!MFSqQp^8iETo1VnnP77N_bfhK1_Ln^p`V\fnWO;F^/#u\1f,hlF;"9 %%!>h+gdQ=->ZbF7j;.JN/f[,5=l1>^BY(:+e:.K*:&KC,cY-M:^_U\q*G\u*pfH"XbM>C^NSZK$IsJqKp.Kfm:,i,?5PkU)gs5/f %-!@f=*)BI=dpM^Q?Y]?+&gdXic$nV/N9Bh7pMT7l:Y-@\iPhm*)Nj)s5W1cD=(iZH.U>k-g %bcQ97',=F/P(XPljVnYd/2J1B,H\tt42Ja%T[TY&+_*(LkOL]rE %<2TAs^tCB+VPR(<4dFn&_hK>0L+pm2&N3&7\m(!gi\b>#".PiIYr %1FTbmGX5)]*cCaP*r+,AC)nQ'MsKs,EGPaS8*Fi)_?b"p!(+3Sg_S_S#Brfr\039.$pkAlgM!5lBWf.^2 %LndYZm"uKpLe#SjOW87P*-:Bb+ZfJI_@:LF&8)]p_@X4nh"d#YP\:3*f1(?L?b2^o0,c!%o %a=s;!(*HBf-H$&Cn4d/@@6uq+dT2)9k0Ugk1JA(b^/+fTo)p6C'-bC3%NnP7g:0QFZ.>mb$"@i`'E6FkCdJ3aWPX=3&k,ce6Vr.2 %!;YqRLcXq/KF+FI?iF@-Kh%M,bDf#N3OI!T7u01TSIoUe4B7b&>`0J:R#kQU:k]2r:!!1\F/52@4d?@V6OWQRT#Y]frCqp5:U\1J %,7,%#h%C_o3E`koTbHI^KpB!DRoQ#WG%jrT0X!O]JuKKKQe$ZJ;]E?HDuN+/.46@W.qrU]2kIFKmlDtg\)YDlrfKM!Hk..+qoVR` %-!%OFSb70QC)gEdk,"(-$;pV"NiBJN[QRa14=$*bo[;1 %O4JOnl;p_5hCM=ckCqs'\:rNg?8fN#H6>4AI%9VT^LWkLnA_>Z7-,I\J5]q!V4WJISP8m/\PXC0Hg&%m3u5CjTN0mmgZV:g&`J(( %U%&/1!rH9<^l[3a3.kZm?@U$\h`P/qa0ip.ok`sG>;XlkElj\De]:eLb0VWbLc#=2UE]3>6NruZ)e %s&<5B\+`,tm'R10GJO<)o3[ngrn08NE+D;c@1?__W]T=]W-eL/FM7K2\[g;:U>k=;"*bJf#F %E-X@IrCm\gr2ILQ2JuT:`TGpq;,[G#MaZTE[<^BG`%j:J\ifqGNkiP.\+t)oU+UijLGI/lX\VQ.g^[%NiOfhfS?cfdN=?V.knhoe %T_K]_rPG!4GScL.IUQ6RC#m&3&X5WSkJa3C1="A]!YHm&*nHCO*IWr"?Z%&^SJH=0BqMj=ooWOUiK_h2NS_Acs'PP1UYP?LZL%%< %.F!lN#Hm`F@1,CO;Jp__XQ6f>n(W>?Z%'Nkr9K:>kC'VaX*9jXU1Y#LSs>mE`5>P;4$.lCJgG]&"g87#>6Ir5NgC>]@ubKX=$Cj& %<7sMa:jM!$e2AY;G5s!+^cs=L7rT%?*I6m]iDbDE+8p\g?PjN?Lq>12KCcDl-f_6f*R+'DNINHcHnSGQ[KCt/+mlau(4k?b?e2u> %qYGh/QfU#^1:];bF8S(9U=8p/G-R1<4VY`o07O]b-i?SAi4gOU[mi(--HVf\Y,sP$r>j*RJsZ7,WSbe!q71EJgR*D] %W\=Ad'_)sq]r`[ij<'01=aIG(-_E&mO<0qY+?:6fk\EAXWrVeI=K[9O_kX)V/RMPKRkh5BO\1.fD2fqu+ %&V,&iXI8,2.faSCeg^\l"^j"`Gs,Fp6u0kE-Tc_J%lls4$Y.C8397TI\NDDt7tQgIXC)oUNntpLh5;r)C()geJrh4Sc*PA/#ssY; %3Fe".H6DXZ/KmWD&Af'$oF!\%8(Q`T9?bf=QtOJPShK&3NlDAn&9:0SIb'm]B?2edr;*R`e605IUMIrur_<&7)[8;m+Q`fM3Cb4S %<5,2EbRo"K8^*;>jJ^I$=QCHQQrA&B9QH.YbaBA0[%&?PF5A?'Sqq_ZA@SRK&jW&i=_n8/k3Cb4Sd&N.,c<8-ApVqtmaAM=u %@>['kL)f.rD+RZGBdiIrCD:/FU/`:NbV:g4ple)AV5#%!;0[!Aht/4).M^==o)>d&rF1f[??Wce$1Z3",1pFKoJ*hpGkMMn^BT"E %ACf=:qN8I][_$Hcem;_8i)0Rui_CQu.CsPa1:m-*m^GdZNM+8'2`=.?C1IOA#M5Jn&Xl!@36-9*')`'W9Ri[oPit>(&gfA[Vn %o,/gKL_AW313?=c)C=E'87oLT2+PbH#5@4SEI*C7[S#Oj2D&;)UP6qtQXa`g\KfeU$ZK]9nMK]iWOg-=?(om1_UfA(.$= %.T8E-3";L*W\S[O0m$Q?WXMc.gkO-;mt"LU_17SCG`Q(^`-\F=mf@s"q-/Dge!PP:WZ?7pf3!,h@n+L8aJCdtdhkglBO,,VVQgLh82U>,TcmKP)6Dn2G*\F4 %Eq8C:iqV`Q:1pZF+p\k!8gt;ecQ":]oh,SBKn;hsM7Y0Q=&nP&qd_prM]HGO#Fhp5oVG>rTi!gQSfsNtr#9;HbC<-jS;$,LQ0KsV %Q"JGZfr8Jajl8U?-Ed_6?UW(V[B18RU(`$Q%2;MYXc6k)rp^:RV3E&dA*6siWXDf_[s5G>\VIrj$[O[7DD4Mh.O3)#m]%f'7&Mj? %T@%,[dl\n3-4_=TBhGgDBq]ordGBGcZ"[ZEDZ?5Z^\.mPZIa#/\p&hp[NZ?*Im/tNDrf;a_-MC_/AQ0Y*aaXbp6/gIPPoA?gc*m< %ids"t'NZ:b=t'F;r7(:Tgsn\h'$%-!gt)%-BATPDG76TDc3]q`.4E*k-!Q!UCfPAF.sX4f?:Os@Vl$LVV^(B)mbC!r+;u>?R%]o,UBrm-eZ@L+q80Q=)EKn,"s;D]#L7sKK\HR %]!fL('8bJKa_eDH.k8&i;:oPG-CS9g;WWn=WQ=9YO[7-A:F7ii;j^K1&q(RNVJ&j@9b@-C@s8S\?ttS]d`]OFiGUi@a_\>G-CX)1 %c8S06]Q24alEbCp:!oHro$pBY$]1)).JaoQFGG\ScfhkD#3ebG)=sE!+^*0/K&k!u$+Gqle@o:`*I9Z"72dG_q`=uGB&TDUrNF". %2M*\>/4b/%NC`,h46XTVpE4pXfZV148Fsb(cu#&?P;r!ug9o_mHYK8DdVlL9S=6TZ4$J0;@gfBN]L10,P%[?S[-rc;lS0j]1t\&@ %Qc0#E"_R$Q3;QK$0N3H%m=^N%6eASUN)B'Id]tAW;e?>b<"VS'eirE6Sp*gl'D4O)-)_EF3fr_!b:rMWb&fs@A=uD/>0tMG6T:P( %*Zn3'%^"^M_?t&54^Pu-Wh(N`pntWg:iIt:#/0J&"3j^FXaS(4r2>m[<\&c8BgDAR3'2*B\.'<5`9BS2`qV!eoRZZu$u%4K9..*K %q9.1n]mH&&P6XRuIUqtk"&J)7>fS)%-Gk!+=Mj[A@L9hdSc&X>27/Mo8?&SsUl0AMG&!+]Q7_7eFrPRGo^A-oU@1./gWIeW]BB9% %4hkHdfJu.,lL;+R/4\7,9k0`^[!=fb!mNM&lV,#2`3tomosj3tSRH(aGQWEn%Oe\I2FDSkQ8V;3X)P2;0U*LC %0b(0)2Ps)USY>5\DOq^YTmNO@13D'L-cX=I=;*&5lQ^hs0f/FJl8&&iH+RSad)08[Fg76#X78eL^>=;l0]-L#DAh\(Rb(PR4b>\i %2HGQ_d/_8bb7He/K!U4`+Wlu#LVMfi_hY:UJr"=R.!SaR("uPT<46bpQq=J_*NP@9r9uI,._&J*-fTJhd;=6_8IQa$kN/cD@o#i0 %if\qM04-6#Ng/CJ*($Je`KQ'10G3hH@uLI&&YCo"LlQq'OO62Qj=s+C%j*pJn3hZP(aHUu(l7s_4FG5f6oc`oo'k&_1>5S[/@2_% %*VWDc460V8YDd?u%*L2l;2fNp$mu88.08Bt`S>b6Jf*%:Qka&52].8j'dM_sLWLr*.Ik5:Hr(RjN/C3kV*@D4LG+J=8&\_Xpi[-= %"J]FlUe6<8@QIH,Q&*3I-\2+\3\"b/IYr#B%')!HN-J=GFPif4'k:V^dcsqVoV3EA_]BWJA'p"ELem;KTmJOFR"N3#ZF'Rb"`k7M=eLnp'CeY>plHR*:W+XB %i?Q<#:W-UmH(6dG]$=fRVS!@j3-D`NrBYXupI-!OY`Jf%YWLbbHKkWIC\sj\g&>""IH5\a?&RrId#5(38U(?8Zgh6aLT[Z65PH4@ %NGN22iS_rY9rtG=?ZiaLC+H`/iFbl]B<-OUe+a#42dbi?;@dr]Gn#0#roP\DYq#GOi+7VDXq.eIe0_EXW7dj0o.@C7"(5<*Xb]\^Ja'Vbq4NL+ZfInM"o86 %lHdAgXVmghpnSNf?m=S8oC/r6f"I.5QD'01/Gb'jM#Zqj0D`;/J,R7-LD-&2pnU$"GhWn'Lel12=$'?:qbX-]_g7V4H&60&X[I;i %NJ<;b2ErJ"ZCiE$_ZHq,2A,(9%gGd]a1+jM,^2;uh&.F&um6;29R&nc.5@aX0$Z)NF[cr&fh[AR-F3.#IV$&n+F1/eR`I;E]8e9;TaceeMp %%V>s/,ie_>T8?"l`>MihL"=?%drR(KhL)\j?N$TqG[+Uc"ND/;L^R4=Aru^SDCYU"S#&(P/3GiS/8%>qV724:nQG$rg)FTHs %kJZ]oaPQ1*/oSVFj6MTkEah\aLq0tLM/=9+a5h8,8mgGVs!>&P-+),6g(-@]F=NPaTRD%NVGPX&oOK)RDd-coK_E%">"NESh@;Ds %EdF6SR\(Dns!XSS\,50>Q4QIH_C^?q?AKMtJu+;Hnh*="+$S5:YK(9UBmQB:aR,;qh"g>-cjFDmrr0d0:$;lVMJ+.cMt2#`[K[sC %;Q;A4j.npH/^NmFPVAV1QZ4D9NA>]bfgcD8Zr'WLX8*sfNB>\Gh:#428:%P+@*1VmdB6&Lba\IGH93("g'_qr6lbE %.6O8obieJ#;L%k:>4-:K;U`hoI/m(1'=UC!QihSXV=+]JW@7mA">>o<*irdd&\P=K]T&i[MIuo"[khu2Ykn[pZrU=A#.m*N>nFP# %fZX6sG$m^?)=0q)k384HG2U\Kr:N2;3Ul)&7K.icf2#[V;X#h2`YQ>98[Tifosut\+,HV3IEiKS&BX>?ZD/d&0-pFSA0T\I5^(S! %#%&Xfo2:,c`5c30>^=/ccWkha-"F&s@X&55N-7;36IH3N5.b)OL7F&9k+YlTS---Q.gN>fYeo*U\^sp6)PMTJ#Ob^n2&o$Dqq5*_ %!dO/KoP>S^[*SoO[Z;4[rm=ZVJ[as*G=+^?q;k8U)q`$uM^GTgQN7p_.n9i?\M?,NMq-F#&1F98?8r8R[NT4\P&Q-ndNZn'V7_'CjeOA%m38?gi*?8WeIRa@CGc\*o[TGWNnT %km,nh-u^YZU`YAmdWYOpV.`;K:;'kHV$V%g0W$aim,(1d3P@-n>RCq7.jM'*I&5!6.o6[ObJ2(sJo+/'gPF*YV0 %14ARJ>!^/`3R!]7*F=ic!WLbUC8:MCF7[Q$;iDX0Y/IAF,B#DHHOrR=d`]Z@cJDuTKNjg$JV9_s3`=KOO?Cm? %/mEGP*r7=,>BE47VSSuECe3#TSE=nV_+kL]NUm03#-2=EL1@U2#Wn&L]J<"iOEDPLG\)Itg2RPeLPq84$:o<&0e6A=1>HM.`2mqJ %b*Ffha[\HT4l9U=LY[Knl^:`_%8TMWNp*hMKHL'CQsj(]F$<:<$+-;nL>Mb`:(a@*3[6B %L,&]@eT_f=0Bu6Pd,S,(7IJ[&#?'aZ`lN:^!g!_Uhg_U?3K.%-^^RknZ`t#XHE/L3MmrlKf,MbB/2n5:eWoi?X@`X3l7F;gIa'RQ %:rlP*eBM*5RbO9_[[f.NQ0`=lYotKm-Y3C$rS)4aD5%OJQ,^MLDfhUdJ/5bKNi_rCnRjV3$*#G^&3)s[51!r1 %lr]1k+hG58%X0f'@gAd@O("lcDVINC-$Y?Nr`VfP*_OoQrm1h4;3N?%5tsqhl6SA!49r)Z-G0l68 %WT2&Tr[5+@>FP)s9oFGO;kuB=.fW1b775u9WVePGS0i:'=SstB(F)R/ZM8(4(,NAI+[6ifBY,`#du6[t7`XbgB,N9qhZ7F\Q7O9S %/;uE\FIqME_bt7HO2n(PQY'd5cc1eeoKF5-/o#T;0Ypcl2/M1P%O1aC:_1 %cGI+rBCN'b/Bo$g3ZHk)7ZLH&c$?K`L971mn)rl-FL*Ypnr[@39RABIb^*:CNo5[$,>r#cRTX"h.OZ?g>Z5:V#l*eUO%^h0^?\-. %IX>mL"=J@kBspf0%b`tT>P\ufh>-Ge>BJU@qC-jrpIh>c>O"bmUTZ9X^E"a2L.5WMIQQ?*_D`*ko%Tl<`P7Pf39CYIG2ELIDNeRD %O&OS)n&u)Cp*U/G*61L";DqH6#lg(&-Ko %(d:F"2QNT':Vjm5p)B3TO>"T1i %C<$f^$&?oMA=3m0#"=_#%^L;NOfshD7l[)r%jK@>SFOPh,LY42&T]%&"qWO6UZ.[N.XrPm/ %#h^`cat_`oVOE:tU@aO5[g?L`X:iN:fqtfJdopiTWhBIk%\LJ['J1qoKY)8UQpO6YcM4BhASD] %Q,P%4(hdJHif:m%$>F)1(?Q0>`,o%G+GMElVR!LXE>PX6R**Rg=mIbQ`)Kd'7Q@1s,GqcPD!VY#11HTdXs.P]/[lL)[-!E-3/FsX %\rY+:X_RGMh0@bGc&O02_u5b0[$@ik?YZ3e"e-P9]$mVFi4]e)I>+Q,X*9"?[p>i=hf#+9;I$0fg*E##TC5Zu39ESF=5PGE'1LSA %DS8s!9qeVN?a#\DKO%t#pfSJ3YET?o5X36OQ'0mKS*M&@V9Ek8emiUTPr#XM&>SQV17-7?_b8Q2"ZpjlC@DOj4UGT9K2;Nu21K:S %]-'R*puI\^j#d%3]0)5K8t""En<0O2Q""!Xdo"kl9'E:6Y#ib.IDC=eHDT&bUJ3ZtLfp:dH7[DM@Q&hfX3u.oGL=7UFP#cW#H-R$ %U+2DGYEsAS%`\G>M1[bTV,3c+"!<6&;B,Ju':cS-;(.!"FPECe`S;0M#4O^5IrcYO#R!*A2uY;O+bbfoVkUq %g';/k)RW9=_G90m[Kk:S?hV7Feu4P"8k'_hPbP%a6icTUi*8Kqf%>LX&]/Z%9$/NH$rsj+%[?1PWmQ` %J_>\^_J]oo#5Tk'_Je;LFRqUB-L$4,VL)oF\J!@c@g8*%/E+(_Rk0+F"#Gd2&_"u<%G##d&^r3#@k>V.hPieV90U@Sqd_i3@X@;] %CG&YSIR25tHpjD7+YhdeC$TZ'L,!rG?6e04s"WD^pk-@[Gr=R7h_V:]\gPFK(L&g-g(+CD>3a;0/th&CX?`#4DC? %iO?d88SNW[O0pY/ELWA7BAc9RkAXGTNo+_,4.A>@Uu(45ieDbUaXoa]Q`@$El/DcsIsF5rFHbngmuuq%%MbhNU($.,r?XNqFMKPg %??.&[;]m>HXfW/&tk7-e9B4g[2FY&fooo"#7L";X5KGGp?gr")jn9cLjUo9K.eQNSAfaN8JCc`9m[9'Pt\Xcc1fo,Ic_L^0Qj;6;?;#^hMf8R,db%c1 %[OJbF%@s%M?/D*"eKcA'];XFS&;*ob!rZ8Y52g.'"DaB>[/u*IR;"I&))i*.4/%6XatVHWjOQ %'\hi=="\R:b&S-=MugYId&itM%JJ?`%W?N#l2@brO2/*&H2(E&_nmCW>OF`GP?.WmK'=#.$2,NV*7Q*je= %P^0:b?Q#kM;De:XCYpY7g1;8n2Ku@8l7qN4SHZC[>+Qm;pA>lE;(V_rc#OS2-'dad2Jf;8`uEim?^!`dalIBF]r\FbmUWiYa&Aua3R0JH4Zk5iqZBG!qfYQF(+PPWjgKU\nGpBdM\nqrt/!hj!cPtCqfi`VTaPCd;k+-*a^DL`W %dme3#D;#8t/f<`18>hH_XU[R66oo/fo>p"a7U]"C\0m'(2^1,e+K<5.c:_O#%V(p=Xf9(7"Z'21[MH3K-'6b_bbc/%+pZk+bbg]Z %@HV-90q2@LlI@hD='k;g%VIYTS1\N0"325@p=uX\2aI@nU^CUFO!(_5X7:/&4Y9^EIuMr4QUr^+HbQ(S0E\1(r/)gXhTf`R3*N5A %I\Cb8rEW8rF?/Q5DX_Z_FSSn8+,rbTgE,[m5g*^\p^.5/.#fR@hk&`TTJmkA(+li<[b-0:7IEK:+uPB!k`RE&>SsZ<9E1Al!E67S %T#L%(.k>ZqXmTqH[iTu?paq:CY3a7B=_Y#i%@"ftU1/RnE()!*>TB_&@no-a*4Xq)%8#-?7*6(Ul-hui3!!q"r:0\[+$@hG3^TK"!+>iEYE\2HK]JtUDW'=oKhHUd`RY;d %Q]IkRj-/0j",4Y@bp?XC-"cLFJhjkb_j %SI6t0a,c_g_YcMOU'`?O3:;qDPcruh&q0T1[*u-+Fejkh^cs#iUa9XqO,9"e/c;9 %__6Ir7F^jC5"S_5*)4JW\`ST>Dto@M\KR&qhZ^LN]]FRI_Zr/!s,H3WQM&9Oefi8"S(`"`0_'X0VcfDAV-D<1u<]Tc4Kd_FY*C0jLDkpN@&nLU1D %;cN?dYZ%k/m[NO\'`G\/7W4qY>c=BA5bI'@r:XB6_V6-cM(*a^..F/I$_3P=Bd_sT;tTZZiMN2\kA?`8T4DDghR$7]J92H'o^bt* %%7<-1AXSmjW"Ql"bT*7I%m&#k0,=2\ZlQp1Me/[dDAnTH<8?W4E(]NZ4B5175;6hO-CC0pT9hn-f_i[PO(B#Wk^^)HN/0/lFJ"oj %ElanPR!)qrT'0SCPfW@T+c-[oCnne0#8%u8@rLr&g17 %LYE]Zpj(0(RS35L1=t6?a9t0eEIe$1nVcQkk6SVPQ?uiTHUr>4?^bF%g@k9/!do?4EHV#R,j-TT4cUD^eKWBT4\XJ@4EDSQkmN" %(@]@,q0D_66LO:=.*MO;_8uZ:dePHRjt@gG/9j>dnhB#M[/B'mmak-r+$V8C:M>m9BAo(YkQrih-&0hI'%3p*S'P!_X36/3g9&1)>,:ampjFo!YJi)I#7T/P %'3]5=%akZcIg`kU[0qW>*W?^U.Dkm39V2\UTg_#7"jN4h-aZG-ZNC'IJ-dgUq(01e$pC:Q3hOC1'dY)XKV$O7S^5`IO+ %,:amfWbcHTg_#7ATl[[RF!.Kc[n5Pp^&P#q(+DV'd7`3cY('-3E#3O$Ke\Q\@>4G-.^,g**k+Z"jPW*lgJ"$#It>)V!?[1pFf%H5B6;_9NQfm;dPX>f+96i\0Ja;+Bm'mJ;<5Sbu@(+@sFaWEG)Ghi`Z1H_+LK)^]rCDQsD7VQDB'@DSIc)d)ruOV`O4!B]=X3m;d;g_7K9&f6Hgl;ct'OVf/H.JpHG(-+e#D8L:2T*pQ?a;*+1\S!-+l %fg#4",\!Vu'iO7L\OF!pJO]@eU.<hJ[nfJu9IY&I^gBp`mt\hgT_m@]eK#].I.8$J.7QmOVoN-MU9XV[-De<&j"COtT'B(sF@U[/MR]gRKe^sml\0">*/h+]@< %9"b(j@DC&(%PF>Ii)R6*FB.%Ti5&T?[[8P\D(+jBF]\0S84o,/J<8gDe,o.8HE&Ta6mZjGn<[L_c %]6VVW,D>?a%c/Wh6J`"mK]oFHJ@sLSleQsSHFu5o]GP6NS^5L%V-B=K3"13^DQI]Fd*LCj*Mo[p7n`'`i"ldL8mn[U]"qFf\>a\@e4oQQLh-j %`lAT:m*$^LPK6A\jXr))mW)>cD5e1t\-1?f-sp%oCZnr:#=1ZESC%IWB]$W8cdJgcq882ef`n">]DKidRK\Kp4m]>blUHSW_Pbsjk81QmR6(dNmojCW>qMTgr9:lslTDfJphb1oT %>UrN/M)Cb_qka-uo8%Y3JRFXQM0gi+`uh6gqj?ZrO0FWP:EZ@+mlp14>inu*L"B"cVrS]h9&)KJAS+Ose(TtP&eAp=K>u_1.Im.) %]_o/*98UF*h+cI>(MBj-5gT&@XH\$G<0Y>r@\%]pY96(4sVR'*j%&B3UnONP^']Er&F52'%V[J %O.MWNS9PYc1memdn&KNF4ALRVisQ1c)73t#i![q440#!^ok^GRNttc!CbdS&bYim0RWW,`P3B2ahtp;@>Z0X`gK59(DsQ]hC:po"8$'dWW\)r5V]k53@]6s>VBb9c4?<\A%_DV"9;!iUkhk_;E9]/:4Dg=I %k'1eI(!BKm90-hML6Ke=!HR$`c]/Ps%rQu7r=E&k4F"'Tk4\s\Lb'f>5pU"bZHSD=nt\97G(#dLo`hO_?bmP[C\k70?*;[10$+6;AV.uXnE;l6"saOnJOf`p.Ajm*#oulM-Sok$ %&^6LH,0.Ko/aaJ%RrLsKZeuOBoV<]=,0.K/<,KC'F(Ok'au/Z*cdN+?4l_R>gui8c)Y7r=oNe2i.OH>%LCHBFVo\\&=q2ZPcikIR %j,Rf6nI%I"E2s9HO.Kf$X^HDX*e!7.0IP-tn7[_AY*F'P:F@/.=+7%M%_6)U\JVSjV/a6>j_Mo8^t2gN`mjj+u",5D':(ufQH_j5QDf6d!%eH.SlLZKJAgZP^Z^f3pjBAfMYpF>b>$Y1Q"HJ %0O)>760>L.[%0Cl&aX.bo3S*9e="<#i)@)N3H^'X9"`<44f?Tp:Z5-Y/7/iq>>"L5>]cGr_tgRRRs%.K5A`i@npn24_/j7&l'q;5 %=UoV#GkF'gP %6)oo\)ftX&qd2OSg>jjKS0sD2ca&&DZ66IH/Dm3C4mDaN/-ijgnEjA%IT'&B$o\uDkZR&3\-qS)p@ln_*o7KMca(;00Y;,RHC"O. %1N,4'.5'gdP3YdVet-H&9eM6t%N:Zo5/s1*J,]rE0ePW4e?3J`Sn3CO%9#0l4j+CUC,gO*rEGTH*+S;;50hGK+33:?AN`h960)f$ %]>G8DIc5iN<6tt15#MFH0%QGV]9(I1@Kt&_71Q/$d*ZZj0u=jK;UX+\_oHPEiDc75AmFb?8/\\F:JptbD%EoZPZr5]rK>To!P6jB %^:NohOT$*P\&h>T/i5SOdP%@?2:Bo+*+MD"(oPe8j-[Fq?$=qL"JoK%)u-@(^K(@";$X9*S]S\@3/D.7nof-J?dS`cBfm"-4Z.Eq %@6>-+??cq>B6qfg$Gt;BWDj=Ui'_e4$dN9(CQ1NVY\nj97P&?Yc@-_F8=X;!3l%\dd-N3N+MVs5i.f>YN0$k+K0\(S^Lr@MENF$\=1,D-=943?+c0 %/N!oKWi\)D?GObY/9>"BI)i#FZSs)rVBhoBq<+"f15@#p$Ljo %JcLVFJH!ki4l$uS-0Q#AdX)X5LA?/.nbtCjeSi<>9*[Z/qfY2>!8aO2&7f`b160,)r@HmE4AH*O8Z"5H$F8Ia2REahIg5JDfPNjN %2p=^0iHsm;]mKFBNAW2Vl>Eq5h9*g0Q%C@'_:$e>II1q;)+BV#W+5bZJk!d%WW0hJ_TquY(2FEGd(Jf9YGuf5]73]t]d`H'(H;7@ %*a0YXr@J7uM?iu1)TQ>ZQ7`ZfP8$$r6`jX#_QS^l.3?LAQtHjCe#8YB.K/H4a+FoA_g2(Y`<.s&j`H<7ih<5,Zf01IHJ^,!*cN3J._S>--"``4phjf:&i6PF=#n!4nBY>0WWY-7.bID1mWPE^\c\Yn=BYq\!0D(0^6"]TR1I2/I+'spE=mA]s$e`oIN.TJe2qpGq.^Q\V;T;jDu=aYk;kVC`2&J.#tUJ'&h %OUsTJUC4iKn?TWaA'R-a"m8u9X,G-a_CcA(eQ%[,PDs`:hCe2oY!](cm"4hO$@d4?90Fg&n7N!+%>OlK2uL?0nAX<=V5C;'psZ!? %VNeem3V]"p\d$&JSLlj1q#@=P,.s"LUMo'1gHpb]FdBt>G\u>.*_((+$D-8&(0Yd+^q/U_+STq`,K1oRfkH,(8/5;K57(\NtKfXZ8YBG %(%-]G/da^18@rU8*UMTmXe`<:DhhZf?u[`7,Ye#nAC`s7X&$7<;@WGJHre3&RadNr#'0ULdkp<%oE&EW673^@%^\WFG,m'csl;,>`CV&FLs %Q0.UV=!_"b&8C4`L`piT:huBhNu0VW$r&XE:W/>T?jQ@5JIt93J0E]",F)\^@;*0F;9:M/I\.`la;cl: %?S!m?a;cljFm'2X@_WU\aI4R\;*^P$JFf\j.M]nWL2kNeU6TK#4<@SctqAtC2 %BleaP4BdPAiZ?;/]nL>cFa+!K=EI1fIa5roSYas'5[/Ch?i(h^JDg/W*$-Lo@R()a*Z0F=&%n[fSSH(d_6%muN;[:FkV:bhkO+\_ %F13[r_o9I/@7aC<,^HsQoi\g&H/#' %#172ki];GQ.5_d*Lr4Bb)ttt$MDWjGa?Mk&c^44_BC$TC0\-&o.@Ml5-MJ>e@P%7lZs+'PB%I^VjU=!1-7l:!qMJcp`g*qaS).lM %FpJ%Lh5p32JJS,5BFXqpOF!7o)1pV%&>A:,E)g)&T7UrI"17/Z>dc.r.u&M!G$`1P>^nT%HoTTuMd1JWHG8^HCu10c='-d-rV1=\ %?QX3'adlP-1QO$(m+;2je?A=Bk,PnLXM",+*4p%uf#]aQPTCH/XQ['f($+nEUVW&?=dgGWWECsO\ %4fqQJj5W_XE3m"VOe,WFDf5sR3RL)u+[)r(kDaO-BXlIt"muL&2gYooU(JWeR\L&"YC4aITT:k.T %DlIYFGnMsh(:4i)OaGuP\^\!58UUELXRGt[lh`G+U&/(-T=uu-hU9gmOn='iZpHnT&lIPQ8Lk5,!^L76U$k=m/#9Y`*;YAF=86,[ %aVDTAe7aQ2e1)oLd*2*Fo*X_rKrRb>it^"k$:4.0nd=VqKof5jFGNSZJ;AH+9.(cWo*X_p;dmomkn"X@'>h)=BS_SGQj^uCA<]EH %#bdeP(fc5#;JKa,_LMocD_W&*k))/cLq\J7g[@SQlk0grpBT'D(A'l<.0pe>+$mk'bMRhY_3K`2C.d"YO(!6%`SO9h.4h"hBQ\I[=Q795^:m"#m^42O,&,SBL_&s*q77cu)!,h2Ps8947>& %8DPn8C*;MU/pLEOpU`uP/j\P=JooJM>-hbXj';)N2n\$:l?3@$`qcu_WfB\Ec!FcXn8p*r-gSK0.i]k>kf0tD*IS- %h%Wm*4G'tugcee)T4PT9na5tFI_5^Y[aRUq`q_lV='!LBH?<+V3h\cGB#>ST5C>u1*.qH^1o"9PTZ2UgOQe&.h4hE]\Zt)s@crZ' %%1d;Yp%M(b?hcbMQ@:0c'UR3!T.Cu&d4NDs(=)RC+5LrGDAaF=^8"nm_(E%*i'+_0c\<6(2`a'>2S:0DdG]AWi?8Lf:P\,XL0("g %mMk3,L=[lCFuha(2S;>H[F*r3%Q8_+1Y-/H_o#)\Sds)9%?K#>$QYft)]j;pk3;@Yf^NRPjuq>%qK(OhLZcp:a4C\(\&_q($=)A\ %TW'!?*BV+L,W4U74<%UGV8Mn:_s:82=,8Uj2S>/MZ`VW#Zf/'I8iG>2WD$o*Q*!D)dA7t/C!*V0:=7`4QG@*VJ\ja*qiO#`](-MZf88p)9c\ifA5Wj./na/Yd %b8.++Hp#$&h6M`*MhU@]V?OmG,4@-p2hbh?TpWEQX0G?A$(1-"4)W_<@cB4C[LaI-,@-+"R#hcurn0Vh;Zj=T[LbBJpnS;nA.*s0 %7G!';0uZ5O<18fMqAZoY2]L<+'>3,TqGpsP\E!qgW<#QS7@#/L$_j%7%*fG3%CPke.RscF$`AEi5=Z!>Pol!W:Q?"7:jS9Y\f;kU %`I>eW%$NoE*22Jb;Cf.TC^>?rZ?L=\WFD.[]^eiJJnXl+c1<&?H"NTQG"m:9C`"rGpba#@4%DqjZE@c5'rjfMNBT= %T6V>9WF9n%\m(89FIkiiW%*Q?"\sN0ff75pJ&/ti#:VkaTH`?oI(>K$<\_Rd"]"Ft_P,KTFdCW)KO8M+)@>B2[drIFXS,[h?<,?B\aSeGmLIKs %dRVG,m[I^ECg<*FHO=g_i-R?6,'UR?jUobtTuH,&!f8F'HB6TcE_I)6hAWC9DN5\u:Y&1:j^iT63uZolH5J54`7Q)Y&mt<#fW5NC %?cCKa2CVqPUZu.s]E9nJd=;pM:'Qg&bs!NPl?],[EbG^]:41nnK!di*(3mQ@53b&s8$1C?o^b+X**s.[Ge^n^^8XNjmR4aO3k5;P %eW[`!okCtrL4e6+bqgl0U/[]E:6OTP(?'pLf&5ho$X7Q#6i_6L<,?3ceh)<847&c+O"iIGB7&iVK(ffX+(iZUU$]tPs1k&NpY&uIDD0N]H9:+YX:4")$B`$&EfNf\\;:?99k$Qo#*f`D1JQ(D`K#b+LGe^r&[UAA"[p5)M(G`-daOXaK?:YVVR3=`(cOWgq %5nil[AnQ/T]N/nfGC`I`T$RU"n^&V\es#/*9lTYK/!H/E1su!o9MA3QcpS-M:'dL!hR@lqfU/0kTo$S5jQ$VA5R5JjF#0MH[a39f %[^)[(^EC-5]ZJ8/RK0W!#u1OL*)_>$!bd2"$TjQ9-T"-T=Ep%Y`HhPZk[-j.c-e<6S)1qRCrbJ5ZsCG5%3mB5_gtTKh4^=.PhL@l %1Js>DU(Y09/lEi,Iscj?Ig[o8n>Zm`(,<-Z7hT*Snn,FSnWMGGRu-@h-h\qk2@itF^hK2C_#M,j3Q=p;@G2`K9V905L3h4#?A %&4G*\\$*"#n"U:0`ar)Z#1!Z5ad]3d%=G@#P.1C?OuH1Q)siS?PIu0m'L=QaMU_IpdL?:W4@'28hucq<.W%u%_*43)9GDh?&,o&bcK+@DE^jGck](J0^rX5H_6Or-dI49]YbTZ^%"jsbNg=A%F473V.9@jZKm'YL,bN1K%S?1<$' %I+SFg>Oe5h0SXKftGK+VA./m'r#*Ni9WuT4iYQDid:*URT.9jBQkU8XQ$4GSrBo!Qgd. %QfE@5"eaF<&.(T3eIgU[%QsUuORnd<4$\f,E=-`54jq@])AU1fZd`5F%Te48Y$'*s%7O7+$?iR3#1$uc-Hn.e$\Q?/ %&MUO(iOs5'A4;Q[[%(Gp\NMOI!ZmaF=jc7ZXA5ZZn.a+$>YPM$8.4H:5k#n9Z-aQgaC!.;KYs8Yq*63-].ek"2SMtkqF>Ap;cPAnWDE&aR6>rta%_iZF(;/$=8>RWq;^pJb %+Vh(4[)t:fC[M;(_JnMqONOEsBq_iW+&Xum\^prUO/&DJCP2Rr>%JYdY"dFqbq%OV;8eAu,LsADm&f&[>C8bN!a+^Bh7Pr+Epq@t %fsj-dfmXFCKRPE7l@6/oblU5%OI'm5r#*QJs6h.85?_tfFAe7NNNSO=I\7ALo[@[T9MX,'Z2TlEB):e0!D`G&>09(E0l-6tN&XHt %/$7^>d0"ZRQMNO`cQ%dnkj%K%Ji3-%bZhBsk77K.q"W:@r_a6RM9/gB,,jT0Y$b[%5r6`.I=g)L'SQ %@GJEZ7Q4KG8iE6PDN28S<[YN)?+7gZor7TNgjPEd3d9BuGL_-sQCYX*NOti`@,&6XS(JLVF8&Q*7u$;N_6S.6%1N$@bQNrqj,a@= %2N>'1giYuk![Fkpm+c`!gbk=%bW9t(_Kt_\_mFL:X`7E2(+_Okh&:J\eXUL>Y$9rSiq0eCAg73N,DIP]g-?"Tbh1[T=`j(05F'eM %R$HF*8Q32nI7p0&]b(!XGI!XP&D999TW)8:-jelHb#",1#7G8a %!Qj/XHlYF'P4nApc05-\o.ZY)(aZ$*a4i]samFP"6b`!TFQN;PcL-(I\8.Iaj^<.bg:?(_4I2QM9%)(W4Z5GkC7\XAT%X4]1,[B0 %1[f6\%ur8HkgFqHH)V%pNTFjPmo0hK`_uQk4Ef)S`=d6N'h8S(iC`,[+[g*$j4$1MU<@L?0loCd&RB(($0?9_4'@j'#H<]AFL`q\ %hf^X[h,`S!7]d(qja!lW]!NE'!%%J<&Ut#NIohdS"'OT48U>cIoV0g"c@8E3N0En\8^74#V"\5ZhHuPDB,:M`N]`Kse5?+FP%Pmf %eAi^7=/n,W-bKEYPOtG!Wt=/Dr0Jeq)$=_-0$BY7l)?28223Pqhj5W\ms0Lm=\R;B)KpB(N.)TJoF.@mfObB6&p" %K?fsi%in1C^>FcR\H+)spuIR?Vdhdt,nZn6kp[OkZ1qK-%sGqg!(CR_H>923'$mam*PGCQaY=6]F!erSRN*mPJL^9m]o`E+igoG! %P%3(VEJEOVD5Z+42Qq=jG?Pg#oE\m1YQ5:<1`9UO(C*3YUri7W97nYQ6Bcu_b!qWKL@asb)k%0P?ME_:Q8BImHaj9K@h=AKZ9&If %D91me424,"0FYhFG?G'dlk_%2]*iD$jq#HAL+0P#BI&D(@@6#WoMm&XjJQ$lG8E;M?8)e;=#TJ!#+[1G84IGM%&ZE[-[!=6K8B80 %H,;95dG[j_$H%fD?EPsjK.qCQpqe_;:#HAr0F6.U:&2UZr3?L&4]`J4jMPqj@G7l9'8G%0HSa7@Xp)sV"N/4ajijs\l7grZi<-t5 %4I*?*p_-@pa]K?KLPLfn%"#R=1>6=8\pRic:K%;@gPQV,I`(qL:H/lMDdFs]DgUW96UjISJ"3)_9-l9\'qEgckcNWk31q<%!coCn %r>)[`H;J()Mh.+W7W"J=iGE\nB6aaka[(*]KL^>S,/5F+3rI=r&r/Lg\"(6%&@I6NdK\#f7OK,"++mKHPa4 %)^0gf/*9kXbC"C'<76F*#)j,C2"7U4=k6,CO^SfW-W%`T@XpdU\d1TQ/jqCd %?%R4VX*]Mm9+D8`Humq=U'M>>(a0117l*Pp=2+LfPcDPGh]-'8_Yh2;LjX9jOHAQ/L<2B0<`q@'(u'FZr)/4jPhq!TV;ONk;L1uW$4$3SOj[HI[1)!r,B\Rrk9[>CN0N1NNhPAp0N&](nGC%M@&,D/FBq6.^dqa= %(+q%d%uf!AL?>`P4tokNQlq.RJLttph.;QU]APk,;AU0ned(o"Oh/>qj=2^&J`18!dg(&_>r:H%\\N0"3VuX/K\ZfdT)B3a0N+/$ %P;Z4TL\ueQk4a_\jun-#Ub4>EPRi`&"\-1L@Io&4]"m79"S[J0]"eG'N"9aP1TS.'">PiGN'>]SL_#Ho"buM>#Tjn_$Oj-k+ad[n %/hl4HK)<>SAW5od18k_Be-2`B]a"+[Oh/@#[bkIV0N&^SO`qDY#=dt[_u%Q,I:/j'0M%]\p47XX&/P.(l5"hd,70gS6X+#(YUFc5 %(YE'2mK1;T7CXak!Z)\ei'TuU'=bi6qiO5L*XZB?.!Yln+fK7'F_$mZ.tU=AO[U77kjJ4$P/'EbUr?5!i/rY"3]a5`0YAR(j=QCq %7eshWn.>:F6Uo0235.4#(+)YF@'U"/)DXpV5\au23l1EA:2?:ki#tZqA,*jW^UbRIE0NJ9eBj?]*^679'AKNi2kcu,$)E<;D&Y6& %Sr$s57Go=YY9BY$aW+ZV+sK^F]N&_!lB\7#chj;DRB^?lYi^7+W?L'='OjG(lZ[LaPEM]13l4m[Jsf8Roi:G.+uXhL^`h=ukB6OJBU)V=f!n^RRU0e]R=iB>5HH'h`9!m#" %J=p=0rVJS-kaKn7i6S$l-qTIscM/O]&"9jRNWN\%RV96b]bQbLMT %4,I\:Q/%"&q.lC6n%?B9!tH#/PO`qhV7l_0o,hF-"t'.UnL8bf[8(P^eiC;n;Z-tbROYcOGL^2FokcpM\ZJ3Y0_r#++Puq)"a;Ph %+nU5400\>8>(iTt-get:D9\HBqrk66hcnRoa_h"?TR]IA8+K[[>@3SFhA`L'pO)r,T'a+Z(B@r=.7-\Q$Yg5?s/@j`XgYB5JC?aEZn.jC2SJjQmg&nk\TGceu`p5^$SRB6L_mo$G!.^O:"6(7#>1AQ[1U3e'ROW3[mc %89.T0hZAqjcZ(e)r;D!W=_['6,14l/CaAl+hM.s!_k>;8NCS44h7p!Hp"]c*17FC7kUlI):rsXO#CakB_$PGR>fJK5D(-mAkk4XM %=%s,Ck/jTuIs14Xm9mKddck3'/m1b'G+\I]W?*/%m:/dJL"i="3)5?sRj%AdS2Hr8qkJI+fc-Y-\Lod`0/'c`ok,tWmGc`e9%9Tc %X("4:i(&5FDoipS=-8$P5]t\7,3TZ+YRjfPSk4!T%*N-Vd.E;VnTD*4l'MFFK',i9dq5)DA*?,&>c>hZI9]:'<:SrLcW8CL!@m'C %C?@`%02?ln``/8G?Do5T4fP>lH_*=GTM\+\B_tG.-ce03"I@.KW)5N!t$5M5m1Vj2#3tZREEXQW4^4.hgMW %Sa39PLkT*q`^XMc&+#Bni4e#/?Q#m3>.^)TL3(#\6tmPTZfdGUQAn'BO3Z6l75QHAF;!J'e8V3qg(ue.>!L">6F[4WFi`1#T)9k/ %Pf5d*G*$Ab`Lh%L5<.3%kC+.=(5D0J>!Hqa=71"N?]'8Zr\r3f0Km[h\ra1gpbsQ?RUWC^B.^A3.r7j;9*a?lO:"rG1kmUS3plc0 %Woc59%+T[dEV5B/!['d.+V8t<2O.rDg%#AJ"@mPqSfeYr.Ok2cKKt`qFQO`HIgG>U5/_!m4WtPd^T]M1GsWus %`\e82WB^h]!NH2f.St:C1Mh?j[CdHU!Z8?Y??Rp1qTK@PSou\1Cg$./=.+YSf>9X*/&R[N>mjVHbR@^IZa7)-_T&hAC"Isl;)cB.3j&%//Pj"0r6-73n=Ne@kt)TU %db'ER`I]#:riU])1A"1OfLgDA[Eoe$B@udfVXR&eB%ZYWci/n.P_Lbc],%V5bR@^IG-/M'+(dR_;?>Gf[QNq\YX?:OYiTTNd[DK8 %(q)Qo>*seJA_?R\CI.Y:1W.e6e5EbkWTnSk?-$nNTUsoUXp`q-Y%9dMXLaMLlrnXcA_Mk)B%Kqg$5UN[0Dfm?[rKn^MDmW]iA6`i %cr2,:M#:G=9o5P.9B+EXCe=gR4.TP#W,MPH8&YR&imip&8d*[M3'OIcVF48R-4l%;,8p<)n(LtkkU@)X`'>M4GtaJnLbQ,q8C2Oa %&:&s#>m$*+Le/Y]p022uJsFQto0]*!O&0VU-Pd"L*u2(D6HF`@eV\1hlsek0gkCq1>L6^!4;Qe:ElPa,ff^X3FXsaXDsDZc4?,9@ %"pJUl="CR*&]A=@;_,/akGrb7nS(EMYGjRDnS(EM-%bpjZ)Sk?Ucn0`i"_9'FO %,-&CW9oUYNILt'KVW#+VV'9T`R`rVR&8od.6T72%;fnd3XG.;/EiU]L:]KMC8>_3W?QHgO;B$QrClu==lO(JgH:`s"?WUM/Od.+o %HD?PU`;2ar_/+n\62st]%<-;B1eQMB+QGL8Cr=+kT4]/\[UEm`#smmeRchX5JIP6`rL%q,?Co;o25_K(=3"=e[1^H<]m-9=>DrL#Gpclj1JT-Wj"U`nktrF?sO]qi59;Q$%s2\&&=uQlF:*4DS^Z)e(.I0J,\9 %"C\6UYeLg0$]uI=O1&6GU+g?(o^BhsZJ7VcAD!hkU$J,!>gW5EZsLS]P^(<:0Mc?5Hs2+U^g3r_R!&92!!N-U^#)%P1@q)Xcs*`H %9L3X^AB3HOTADo,lb4O_mu(=-PdJo+g\6sr/Ra5^O3hl7\)S@N`<6=qA?@#a#HL4+Xg,"\6"('#[m:I*_lT>\&7$*lRI>#+6HHZH %S,)J!+iH/F@HP2/2$t`T`*EJ0^+=R:+`8tBRebg!XL&@T0["i6P4;_n;b*eSo.po+GN]=?ZkLfsD"?$e@P#M_pt[-SWl7"j$V"_G %r9hoDC:ahSKAR\16:'ZFr!kd)9I0K4VWnFQS^&DRh(JXF45.%2q<"u %XFoCN'8I\_RMf8l#kdP+YMaVP>!qT]d6,DnptYs[!/kh&IV6FA:Vb$PpWD%'LG=H)EX@2=kQj%_&*r0J`Q3X`NY(&Vb_+eC[gjFP %WpX79r,1$s?6o*G6ZR3fTRHL;bDb%r")o%@aC$&F1nQ?%iisGET&V5s^:MF&s(VRb?>Nj;6Ij!AT9.)Xlc9C<)q(bI?-rfXi %0?EfK=9,n7#-0m5>1k@L"/LBI])@"lA$@c8-$_g0_BZVm0)S1^5d!cg%^rL@Ph(a&aG%X:/uTP_'e2WqplW*V^`/-'>U/17pV,NB %B;I!j7*ZD6GRk&QqA)Q9k;+WrVsN`odrfN*;L^9jD]O>g1WtuWo$:6C/[s2V].?D.Zg[!ZB)#En'KSlIAbH%sr:ASInt*MO?g_EXGbBlk']P*tC>?ilEF_m=_>ZW6kW(;`S-'0mPiKk"/9lj7Y7Q8QaTU-mIpaJ]<20_$8r%C2nq %&:EJgA;=-Y6f=-[,hr-O%WPtgWuC%ZdG`s"2higg^[SAc_WOC(b2Po0+7$;\)N5\rGS.2gf_cXt7%6<;Flmbl/5P3MJ %DVj6!b43*mSD65Tal-925VcL7r]$,2J!Kl@;'*lE$_V'9_X=>p$q)/&cscsun/pbMfb4/AfiJ=U.%q`t!g5.c1VVpMUQE[&GM?b# %a_n#\rr=E6IGLh\NEt/5F["eB&dYCl?SKM4NXKY)\5Y4fjV;kqn$bbOmn$DAp";k8@8]nNilc%,:hrW#H=d9Z.bnRq(([u*r=;d\>dTuf@F;eJH#EtE;*3(G].0F%WV#'Vh+#<83m@(P7rnJhN> %m]h%nf08Y8qlT)Na):iqI'c7Jp#Wu*kduMOq?!Va)se&uP-8Ze@TFCF\[L9U>EB35d^=31F)ta69msifg3jrCg:ek19Y2#@GqhkX %fEVsp832WYN,goEK$[?tA/(t(_U)/b9::Qj#d?"\mUaeJEW.6s[O`3A7.Ar1G;]V/b+-D`Bm\E\\h_b&:9[$^XBLq!;4A %?@62_e8MaI#1^P%k-5WDTb%0.QTN@/!P/A?2Peh0Ca/-$^m0L,Nea#jas4KrrjL/UOD2n/aOVLq %2mF>`b!?[mi:S#bKVG360_`^>f#!W&!`(#8=:62X9(6BEC"B^]'U3N&4)M'Q".p]8dM\]$ %p\#$?QK_PJJc7eom$uRKB*fmc(QN_J]PC4]E"TGg(up%W=20.-RbKQb*C1+Vm6&VX"]CorP4Qe_)CnV4*TnWo]>>=4:BUH($ras] %jNH&sT2]j&7VeBsA!L?#c&dWfalhqFbVrTD6R5>7k%QAn+>c3?[HZG4WH"Fs3h?No5e+g$GiuqtN/+pR>'5c@fZdhJ%@f(7.=$2; %rG,SJ6VmaU*\1PgAC/6;.iH2Dk]#6MMh'`OQ6J*AMg='XQGXEiGQkTuh\NEHP %hVMI%^uBkp-;%_S=<)Ot+E@K61gL3,^iDBUFQE."Y3,mh0KtW>7Hl_WSQgScO@MQH\"%_g)/&*:J[kfJm(",I@kju.WtBL,L1j&3]"YLo[? %T^+pCgD_gu!q4$gfCjNf7DKj_m-.^ECbYFD`4rRo%*ICSa2;bE\(&0WSo<9:`7j2M[V0LY;09dJ>]pnP_Eiu6H\<=j-SA@Q?*B2fro=L$kGB2fs:^%gmaMs?KuEi3r5AkT,pCNJR:RVShX %L@Wl!,p+%e5n_0#ZDBAc++)]d2k*DFT:P=("CqeQ/5XTbQZ6\(#1Ea@Qg(7Q;tfC9b/ko^MbYF;1/VW:CNg2u?[`a=e)Wt=FM;dA %g:Q._Cm?7jRmV$& %V,9glEU98:H[6XQm#UHIc,ckuX.Q0%f?W$(cQ:GqberTl#Aj.l!l7DJW*Me>\S %7DDt$"s'[JMLNsjCf3p!LER;F-/jU7QL7fE.Q._4mP,Jjb9(L+U1K""]&*TMS_UH8+L4:;r`BPTX;IT^J#n@L %(_a:1d3(!,_OA/bE7@[+/sk.0N%Cr`Dh6Q$e3.&5(qij)JN["'6,0/TanNr]q-6=::@! %/C9^_":'@&Cct>G9h)dJ+p=#;g@E9fOP.SSD>@ZnJJ$W,a'.F8%S;6rk'VRCK-FV/kc&*F[f!CrAV[(9^3-n1-*JN2rDX3\JlHEA %jJfN\;dI>;AEa;%TO'ApB^>%4;2`UJMYK!K8SdP/iSRCaSk>/pWgD_\0@liF6!u'IQ*3t-S*71RWcEL8fg[(T]`e#I28K*a8^!r. %b/nL_*msA"C2\]N8_%cU.R@"L(?W'P1Nq5EU6U0.U02Jf6qrM5=#SmOdN-PtrdJ8qQL8.hE"Y/-Y]L,VKq2ITgm2s)WPd.)CE)&= %*5^,EU-m_]5V,"PN$RNQ:*_\J?@h?Q2j-.]aUY;+0$l(e %!+-5`+duhkaUY:o14PI3:S`_0US'CN>9s;pV0aI?%*&+3%[5,RW[2IJC.C8VmS$NL&/Z&X\Eie6N6< %;10:262DSQW'4j#+.oJq9g?WXWXn,C@'$k-ojRc0agn.0*E%_(@G`g_!i$;IC7Qg?&XZ:7#`^(2;10@LPhuDRu^ %Fj*kkOW@>V%Pa_AkD"l:kY] %KK3^"F=6Z&_Al/tqeXB5#]n@#C,ZB=,4)MP@N#\FMT%!#0S`D"De3BCK_^E6YmNNO&On007+[+t&S@lU`j([LEZr:>hc*#[*+>3d %'p'@CZZ8W$0Ph_5OI/cc3eZ%H.h'<<$nG>&_D!lNC.+d`60&HlN)h:.0FTVYlH7F#1#9L>WWo%j@_.CSn88bH(cF$.`;#$L&`sWF %@^\=Rm#Xh]B\Vo_7t`n*+.TT$Z9p+hTs6[O.m'O>*C=@>+P@p'kR`pL!m(qO7#.)hHofq(Q0?T$0kZX8O@jVNO[Ti7+dM7&hCjFj %LK(!8Fg_]$4/'js3['a"X\:@.]AFU:#2JC8UCC)1([,m@Vi#W8e[MF]0d<>mD4/+gY]>Yg)D>Q,;+^^+fQA$&R%7`;#gi:gBI/Usj5A)BV<$Me*^FN0]@/UsjU %T1T<$bQ"$jFc6@To#Fp[#<0'WO@jVNVS:DjCU*)BDM8CQ[f!BG]7)J!d31>r"d0m(M%7oN$RRs2&fkH]IaB;PM[jaE<"R_+'se&n %BWcn)R+YA]8D",]b_lr70qdlp8p!UiWY%#P0F8&@qb'qZG/u?&cuc-]aptC=L\a&$/N]a@*J1"IOR/'$FJu75WF^iaU-hIe$m[p1 %,.^bRIK8%EQ0;$M.QaF=*GU#^oWgh6d@jcf#Q(Si_#&[nLK+5f>$hoUm#Xh]BV`po5[[Xj_@M2h]r-i(T&i56`X@?C-\V!23Xif_ %"L*;g3Jq&QR/'$ih)GoJB&YJb;<3GHbS`h\"3M+Qk'(qQ5(N!]8p"b-?-p_(s-gBto_(c_:$q[:qZP*$^_)-OjXZ>V="BW&b[]m! %VqiI/-"hf[%1:3Q'tcJ3?:RgZr)*"->%94@e**JfX3(X3iB::AIAV.#=Tt?\8I0Ts<;5cN(?Y1"HFeA_P2#s#L4%gf*_Aq;cpBCn %X/qO*:HD,.COat+HF%a7KfGf"K2u@I-p,,dE-BSto2tVV:EEnI)2*]j0P+;GX8Z`ro-iEc5cFA)e(`49bZ66DOU0O2KmcO6*EoN` %ZindY6]5*"f'/;c%l8atGgc$Bb8k`VZOpG4h,rW"JtCKbWI-RZCakA0S\.[]pjK+@aP[.PM&4ph9(?I#%BneXoC]2r9p9Op[sOEa %V"V1pq(6HXe$cla/lD#3psY5q#H-caIrD*CfhXKr(C*U%o/mts056d&)_Pr#F(7Whe[f0;!d-O9JT#`_![D0%K %3:LTR2Lk\Gb8dd#Cl.)"CV7A7Tm?Lo:4$:SL$?l_J+NY@X'Qj]m,:H5AZ!/4Z2F.kj9VWNo?R110KCLC:G74X>7-A2X(,h,N!Ws: %[X7hsIS.RkGUo\r]/pmYIECA*OlY'k&c0Q(GpKsUO<`0/8J1APfn/g[a@6b*nodKb8$hV`o!kJI*`kRGK*Ke'BD%8.a\i'4FjtK^ %o%IaU,C8gF'dNSrN3]J9;,iM%X4Idp]W0U]<,C^h&loaVmNmIb@L"t)47Io'`H.)t:K=ZpW#0J"LT4g=*s5esk#KCaUb8+#@%S.H %JpX`nqH:s4^!U%_8r8f8gnth49VT(6\F^L@agDUG"jD+aF3+coF:9nm.lQ.>EO-pg^1)%H`7!,J"3;[rlgII6%L@]b$I9sOp8&pS %rAqQ&V,)^;'q9'ZO:8RjYBY$X2l+^%kB)"+0`E_#Rl@P.*uVYlG,2`LFi+c-SL3];o*F$AWV'VMaHQt"eV7rW0/Ei^Ig!6(6YWo' %$_`D2a74+LB.+tj;JB*24&U"ph=XJ!!+(Td&a#b&[!R`h&a#b&&/GXLKGiCs.t%L_q`KZgZKC/.6s'oH2muG^"Z&BtQ7k1u"j[Pa %[,m@V^raR(ji\*K$1hirV79!U[f!BG]O+d6/Usi*GtKX7Q9Wq56oJ`%+)>#aQiW9Yfd1JTC5N9TBZoT46!-bkfq9pHXJO5?G-pof %e"\LEXC]G;c:@Zn,C;*ig@E9fi-l#`[[q%0\]o]5E+Tmg[,m@Vi4H3Y>Q.Ql2CYmH?9,6UWp/VY8CMi=->:RECDlq%+jlT? %ej<:W'=?k^[1)G98@7K>[I?q0pR4h0Z7"4lgEB.,5K:"?5jqd+9ur'T2BNiSO[#,>/,1`nVoqt4Nh7ES^!P=A]"?+AROlaWfh8T7 %165>$G5(k.XF[7VZ0[q2\*_"Qh"U`6Xn2f9>"U+*DU9goS5Y%'&.:J2;l4Yhn;(u&KBGZfU+<]qFoG[3DD,q>:io`Y=N)!Em]D'> %G[?rMMHQ?!1li5h>@EmNfMEBSGaf]aRDI/qSq27&Hi.ir1`o[$; %p2_'PrD[1u>1%ifI%t$%H-&!/rf#n">O3P;5?_tfFAe7NNB[1c5L$L93M(%2^i`gnPhWNP %Va8Yr@32@U?GDgU]O1*X;0VNh,oV\Jtdj_&'R-W$UiHZ>njR!^X?jj,P<+k7ML+Q%Qm1YM?`tiX%43Hr+ %Qq"db/DYo]2j,5LVT>NI4#G6NIE%R-tRWMPJkQj-m;R']Q4>3DCZ4 %73P\uc=mVg.gjh_*_)joSfF*^H=dj@n&]PeHN#Ulnd?1d$dot2.11(K4=/0>cZ-d>Tk1du3A0)n9$),$.gd)(7'KN&C0Zo4bJceF %#d.fDQ><)PHJ@rP\-UMW)(5h$B0?FA7F,r[!E^t#NXK#Gd:oFd\`c%++.X$373OAR*/^a:PNT]`le.'RZ?/5CZX!,B(Z\fKZ<[#A %Q[>J.CIOqb6UK(=d45RO3YjVGSj6.4^VWf;aV/VuiLWY>73Tt@S^S:Y8VXXnbD$5S*=rVNA3[&:C[or*(N!!j+=5s-AML+Gk[MD1tq'$6h_7QAN"W:$1Qp19hU6(;0QL-CVfQ-jeT7 %V'sja/NjT`8l5k4jEXHCCIOp>P+f#(C`#U7WZLe">:^JBYg^e=^L[m@kdReeDgc4\k;GWekMJ&"em^OgKqe&ih<4ecFZft1'S=M_ %Q[aomFi-gKLu+EPr*(N!;Ko9Kck]PKU"Yd?&8d,#'F&<:VH+B`H7ISr$BYpjYP)DUJc0.n'*o'O4.IusNQ.U>m5h!maJXQ9@SM>!fbf!j*n%0dJ!Y#382,o<#k?sV=IE?XiB&_LdIqt8",*MnUPpK&'Sh(LhI %ZZuqCYHhBDr`F6a--n %9t[67SmHL;d1KDl#u+a2.Df`$^XT_p\bNcjbucZc<2^r?Z(3Rko<*ZaW@*[pOC9_f#]@6B(_irPcs,J;/Z_=$%+!XrD,u_t_4?Vf %A>>"$@J9L#?M'#lkHDr0lRc,F`$DlHGAeSnpo/#1)_/b"_(Z"\Pd7fSQ!^t)1!l`r.[DX+\WYOi)rm4\)`5PTSJ`G"c9!*(0:&q# %3ek2Y.eWdO$4I"u+UQs$`(Xh/%\I_k"g"H9)A9Qo='q]`Nd6ja.nUMhI1^Xa'T\ig)mj.Gr@H(\Q$#[`r7YJ4^qXG@T%]8,F(ata %V7Z\G%d3Mu-r`?9hSmSRV"gd$-sQT5hiI)_bi@t13O;^l6-I1Eed-]D_kIcL>Nqi*gjLtUM_D!iX8[<1lIRg25,fI/j.WMLEC;_q %ll,iSeHS&7%$RrgS0Hgn%a\&e7IF-XO3j'IlCg#b4s/iA&%B/NFFp.]lKS?+:";KbK0M2F%_Fu,<[qeF`J]G(Am7.SVG^""J!YX+ %Hb[sN.;mA8V2q`@RadU7\"J8(SkJf^`@1Eq.[Ifae?q1CNV+*63lIhsbm?67>m?XCs*(5%/p61fhE$pbdk+$F!M,tNBB(Hh5>OZt`7dhmZn %!acQBO=#dA#'q%-bttA0$3pmaaqPPc_)1Q\dhmZnF,$*8Bad:rR\T'RdhmZnbphu`e%jqi@0=s%4]q`2IWU0:Fgi])n*K-"6!?PG %8dWo]GM"o@>3iMOd+3C__2u?p(J$VR6gjD-Qp64qgV>Db0Acc^cp3's?]jCGUFZDR1rq+HqoUmWnX[K'K6b$/a=DhpDSQe^.B;YaQ/b!6".]4RTTs9lq[2dA(gA]KkY>HTWD=_>)_)U:d=!4Z[DtTsrV//i %S=nj(12a5*o"-lQ+O.c^&;M%`Q:n-2S\&DYe_#<(^I/&Nobo[9hQD\D=9!tT9.0cJ<<"h(-E[==amJW#s)NQeXM;TFY)JlWQ01qq94q_9E?'c=QmrOH!cuj2=*TIMV %nHTZC6V7D-*k_4j[)S9a@Vgj;SXc=iVemV;Qad6N?;KAq/*&0=2F*QjY_R?0/AoKMb3hON\(nHi/Qb:YRZFmmDt#"7kiHco,pf1` %C&0t&4S;k?H](Z@Si1q:<7&-Jh"mp)>%hOEkTmm-W:nZ_ZnM&NNV-eo(BcHl9mV2aX.Tc51cmnULTaq(4M8&Pr0J;!%[NpbNZOer %HR`ma:V+6p/P3FD:N]1GMQ0>!3k9"qV&?XjQI-EkuU!u#HYT7n"s+j@9u.EW@=kp-f,R>IPJY_igH47u`Y7]Qgp+FfX_jK.P-ePCrc<.B %Rsgmc(bD3]="S1d64`s")R.@/Re?6hp@.o?g9("CQkAnA.C%_&_cl5a[QOJ(VpNku,_(6m%Pm_LX>rU[/H'jBpRap;KgnoCA0bmrnQI^.mI;,rD%1sSZL!$K@E@[\m-#?Dn?g>DQE;KK>V_KK-;r#QA6uaIA,t5R!H)84sMqRm5MbX.i^-d,8G==7gI?mm# %"WWp+;!:5qoEi:eKpBoT=[9m0l)r&00^F3C?U1O.p6h8ida18Cqii\8Od %n4J@?9>,1edJ`!?Jo2iZd']AU&Df@+54[n+SbmZoJ,HV1S&+j>A+t9P9]KnLCT`VNLgsuK(KboDn%a!,Js68C!&YC3qlX`\Mh9$2 %%5Xo3G[<_A@HaL>OtV9I5Uc^QJsDAo_=3aH$e*CWHr<=VOuD@@e?FOE+t#*SlG* %iVfus=;$@XD=tr54;V;FPKTSm#=SKfuVYR%E^T %2WaYgDS_`Bka?p65GHp&5X"=O6mD`[Q@E#S7^IDQ.jf-no+0Fs`=XZd?+9`!d#[uK+L9*RKIf!q"@P0DLX95mQ[n:Bc0=d0E=2bX %V_W]"Tchd-.\$6hM2Kf-#F]'68S-srA?"*]_NTA\oKE1jDU#6;lb[aXb?rIuHR5P%*S@%SR?YJ6j]qb$A9Hn&f+7t9[9+g@8M/on %ll\/i<7DOM8Ii/#8M(Md70GH0+O1Qf)hT[V;<1=_f`Tt`Y+/9jB,oP6^*FK:4o`<@Hm`,CgURHq6[D,eXsRMBn!gocP^Qq$Gi%iF %Pt,4Do7gN%_"Pd(s:!M!+8?sn?V[!@f`)O/-EiuqOnNVfq^2TR)$m1j`a,%irOVVNp()J_@c8Co:.Xmo+5R?P^.o+bjbF6SqC!#q\5L>_A]?Ylr3DV$u)@Y %YYUs8bhkZs??:-9hV9TYATuA#EsQP;PiAAm7U&M*5`4`j36`qWh3?oMpFTo-0nC$7#[^4u+N6_B=P-ed!k`'NrjfV8=@r%)ojBJ4 %74Q9_,_?Y;XC+pgFH;-5[31[m&`N]8;EX1$p(68$?&Zg#MPmGHh8FOHV0MdH"LOV]9CZsFW)JY1:@%/t*^_@t %o8Gb4&>SeLY$sMJ+9ifQ!CGosq(/,NeYX&,YIBsk'Mlu`Eu!^iPiA[`JkjHW0?"#ul'9E;:5Xh@$^3sdIjpu).+,n=MMIc>-A`N; %;EVc%T1q$]6ReUmFQ=dg@jo;ppL.=GGRUEn.V%Qi`a^F9e$KJ[N)+[21g=NO)4r`UWi$\pTbJ$H0Y<85(eX=WpWL2dO.d9VIm&X? %?AaM"L>9am%&J3Q&*"hQ@jo;pYD]FuO.d6uSp_,(*^_BJJWd[5-mhhS'tq29nJFmg"OU/,k:=NP;G$C`pL.#U*^_@t9]K[ZJRPF* %JN,lU>)HB=aZ.WqHAM).9(D-@QQT0g8!Y&Dki/7"bUuZa)=rctT3)=s=HU+CIUF!ASfeX[G(u=B)=uLn(lt@):OBi-c4:=0`RFZj %gr+FGV0E'Hj"H?*O8>ga,fLEb:GEnX.A#e.,Eg=UPi?+!(W?u=8b(:MGZQU@6ReU7J9f9m@O`fJ@,sRa`)KVsmCc;&7SG,Io6*>M %-mN%p7?"+`ZUj(nr;`nfi2N6uiNZGBiOurc*M.]f^oE=9.Uqos]$d\ooXW9VL?6'EYGD"2G$J$b&+6IPdL$[BH/@+sKag`=L&UYS32HVXlJHhE&M%*&)eLrl!5'`Z %TQ>=g!S#%BSt1l(XpY4&#N;]-D!&!F>4EuJ5RA;j@=j`n&k"+L'n+mXOUDCQI]Z4$9C7s.WMM)UK-j9RP$3GS-=MLje:MBsGesS4 %WFbG6fP)pClaJ!FJs=dUmh]2m0L8*,BCR4p@$37(i#/bQe!1gu!#e5BrYTEu:JZ3Y+W-:j7B\h8r*j`tr2PEB$& %_ZWc&co->_h)_"t:-2c$^Lo6]BdnIGTh,hhIN0]B/889r&gg.@/_IN@ShNH&C:UUDUBC.GP)AH^+0Mm%?Wbrh8)9-c-?@VBeE37* %A9;$$Wg4'/-_D]_Q^$_-;]4E]HR4/*9AP:0&2#]XB:XNQjS6l18!R63>GiHI;6>%7Dk6G+Qgd)2g[WK/.p#1JjAm3G\NNfqoo>%qJr7ke`.6eZ5((rZZ3EolgVRPTC]<9*<.#I_a`QJSK2heh*3$Bm]C1r,/TH-g]\ZfJ %Bu['1W@,B5q%j6<'E7V>ba'fc-N**[cs3isRd^ejIs?F`>Gq!FI9?JX6CgUnMHUNA-5;j-/iPL.3$1L)[Ksj*3*##.SXG=Mq8TP$ %)#O*FeIp2Vb^#4A&/b[IG]I&.`a7,*2LuM_*7sb@D,6!/pi:^5U^!Lj5!.<0D$6eqiKd+cK;2G,EfRkibkQ/AU@t0,plY_k'.a^e)qu;Sm7;!d1)Njb90T6h22#g3N:u_j#6bSr[u." %b7:KpjBJq2rUYeVGj8e#qr\L7J?>[[)oCW_9Q0816m;_K87S"?`CZ5umUb`7!r[6U8N#RG:Lf`K`(nLl5V2'H:$c55"_irI\qs^]M:7U;fLc=6?@a#PW:gQBs+]u-KH6Q;,Q9#F`?9.Fc/9iWRL1(Xj/+&c" %`B65dE+9CTWa]`Kf%X&%n)In_ZoD@YI?e!4$C5R_I9PSglrop2l3K6i-rXV2p %rf`N#=mM`iGn4<8B.8V?fNV9HM3S0*aCq/5IehluD@]J%HpdP-8U@)oOi?9$fYblTJ_qR2$6gY=?,;/P+[g`7L7>^H>"\e)_rc&h %bXnFqd2?,?@I?qWD:P@DZtaFZQ?6<6WTN09\uIXmjWOr<7r-]<,ki!I&t"(gDe?HnGdCuCHMLKC!dokAToLQ7eCh"m[6F#>:[lf- %V?(V%qt5q\o-M*GA'RT5i+DZMb1P%N_..Kf7F1Zm_FS,MaV5MN4C?G&lT!MFb %@@!rqJSR+G`#p55QAtt5.U$Mk;(C&_?6>dsd'P]s?%O3-[7L\>Bsh#Xnu@;-lhd:Q(uCr0;>NgdcQ\HE%t",,dcbfDo-BMWL^92< %3#A_^E%3k7*76ki>%'$1TO3,qdMm:/mCOk@o?EE['!niXMKnmH5^to"cEhWUaa33Y]W;To8#%"j7\`7K_nZ3s^?R5R&ll9am[)\dR%Z[I+u\.sK`oWk%h(RB:T!DI/rP&jpbp2D3R)d9QGWc;FkkH8h$L[Z1B>#.rO&URiVho4!b02lj\7=Wu#[^^Z$ %;U*<=%+.^p2"JjE9_]qO!ftPL_[n14.cSdIlBYh6Sp_q'LXG<[h'0_E,W!i$/kIs<,mF'AZE)2>!$R5Xj;nQspe:MAn6s7QIh,'0IFS?^8P.?Dd, %Q'H[DTI$d1q?;YZ9A<=nXBfmHfom[TO)=gLQTb5o2Pr3M;_IgVXqWfq?s[QDs9p#%-MpRrSa@`ZeqY0D)pH!+-6"V69_3n5Y@[(I!_Ir:N39 %jRNFYE$kmD>]BZ.ONS;VR@,N5+I=J6&k#pEj\,ub5VC@he_2Jl)KL*)0$&fV#.Zhs(Ol'l+I='rnq:8>J4g.P\a1,FU#&UWGSek+ %O[:Zr^h*.?H,[)95V>jJAb@;]6EYWHG^>jW$BQ>49BKSV/ll_WBi:;&g"Fs_]i#9I(N@eiA$jsO-!LH7.'cqC@!\W,V %BC;gi"'f^]WpHj%\Gq6tjRNFYpl)J0>[^VkA<>"+R]>rr,KSsQ\FBB,+lq@).=;an/l09Z.TEAi=&"^Q0&(FDXkN9'sBVqrPRV^8&\uXC/J+2JuEqcRX6IjiOp=P4,H:$.(K;TOG^n;7)a)4MF(^P(5Be` %?>AFDbi?/D;!%6;YaP)2@n?)fpK]8%gk1DUF[8u4gjc_K;`@&IlnFCK0AjS8R[=W`V4@1d!EOU:4mr6++(D5@pA$q-Q %#>UW]q.+\'XL0gP^-a(YIsg7eX+4ufctK&Cm]eK6WI''P&IR>mBtJtDki,%G^5gQ5k%rkRW3d\3k?FJLVaQU'Wh/tgqd10_'PmBk %hEaMCZqo)*hjRO+pnY6UmcfT,/uB%9<-iu@1X8a$JmkpXqO^AnON)q#n!Er0L$N]k,6 %PjTmCJTS6(g,JO.W1Z]ob/,?-cg3f#V\HQFf+L@/P.cW4+M.$q%2;OF_\D'UB((;/P9>;Bl@'RA4`&r"G2W5C226]2A-]8ep7BC@ %OJhQpBCAt9Vhrmskd1!h;Dfl-MAoGZDe//*4o4M.oL9=]!jNTukW1#YoKE';4T^CEO@gtBj'u$CZ)a+0AFF59Ks6h?ci2UE7#fXe %Pu&/kX;NC*,^m,We78u]KlYf&\pTZb&Ib)s2Hm#A?RP]@I1BtF^G/#@Q9i4*(L1o5,()Wr8mF%G2]LNe=,ki[L`r2'Z\XQ"XF;u27Cq:U\`*7U/* %1;dApk.#hi:#I.CF&5MAf<_+,W,[4B#X^0E(?6NdF&5Ms'5&tIo@AtV&\ee5Urj'#]9nN6*7WC\?Ao?$[(r*HB\p\>4e-QGbo,$& %$HPp=k+J"C*oaXhC.ZHTVEfe>[:JWag1GHXe<7hdYSOu6W$O#ka^=sX`?g)$)+!=-I\ZUpRD\@D78/cEO;&4?l"uT^`PiqWA;V_A %V![i[(;C_T:a\D#%L/"%fNQVt;aH)dP'TO*j+.ukkD8QUdVqu3.abGX>o.6i2uWV.;,a4Q5X9'Rm[%, %YS[o@Rq$:K6iuB']!_d"dkffU4QH'U75s*`4j[J:`G^.`oE<'\`%t.!emq8l)M^:8grYhE3618t5!I83H@gqTof1"V_0"Ys:tWhQ %0hF60(oN-(&Vk"hj7EoBMneqCSE'5]aci7SoU'Y7SoK)MS1F%f]m_\0S=[1Jb^gY+D'Gf8j?44tq/+i-.c!W+D'UQl]D %3bWgVc>e/^BNs:P`T[Di1nX#?:NZ@Ps-^"gC*L$uhrs6\2f"]6cA[Y66>J@:2CX(;2-d:NiT-W%X3_,>'`$-ETBl'obL[tFP:9EC %X;MhIGZ\*8*M40r?!@_=r/MgrUSb2Rc %Wd"ZkQ0.-8d#2A?La-(U[D9qQGD$jTmJXM/B)$DQAVM'f/t@DV!ppTUiXn$H`ScOZB]Y#Qi=&90ha5)XhNI`CK+`SpK#T,?jG6>E %,)jJBF$uf4&Pejf^ZIA<9*Fbjkj!r*>U!R3[-Q_j&X=T?o]f0sFh#!J=h-r9&D;(=JlOE80LX8=)7":>J0=uQ*3sUAJ0>QDd$76, %%$;ZeY$,D&dTAQJlhM'6V,_ %?.Aj@O1X1Z3J8n#j"<:?`B.(0mpDt6>f72Ql9U`Gb7/UQ*o:k$9*EjGbuG$L\O=4EWQ[o3as@+D8=a0Ui3#I#o.V,]rU1o-^QPGV %BgE@8XljCT.S7aeUj/%iJqtc/Zb.d-Mghdn_ZYF8P!esA0d(Olfo;0MSg[_k1<5k(K&bgKDTX38#(BpMIobY*b%F5&qmMVSJf(A% %M3K!sb$e>%hk&m?Ubsn7r:V:h"=DXm,'(cVrBqV"m2>XML^XC#4la8IM/Apf^HLVk"dX_sT!T2,#[nJCm7Bt8h1A=V.F5MB]dJqt %kK0O*^gY87nCobe)g?:BniW=q6B`$@c]dSq;E\'.4AVj7$,)J7"2B&0jk.N9l-3R_j7Ha2R[<3ZF?G]I>^6R'n,?K:Lsr\QF)[&d %1X]%.`p)G<`l[g_3hF.+aij9d:X\:bGqpC9OJ'cJnCr$1=)0L#'DUr4pPicXG(JNWY;e\l.IlskRC<^*#FPaEHTnEZ??pgf(-IjJ %"2@"Z^/@2\8PJ$R0A%d`dOV[P+1XVjKi54kN-tEq(+hmkBSi72N7B5"b(gh=kG5CeFSo`,kdS)&?RhkY2Lpp %Pe0#>`)!Z+TXRlX'VG;APMX/PV3TtjmFP(`(+<+*_:&I><_ISe^3B@t&:?L2Qg,Ds%_`q0$h@^cJ1h0"6J$nrpi8VQ7n1Gf%6GZ] %Y0,Ca.&k[a53LA]_;OBEI3hd-?u5^g9J,$qTSrOP)"*1Pa_&3Cl`Fa+FG]`")")&/M;-<#_a&:%^\#2IDLpqp0S0Us*eAHpUJr8C %i2u,[BKi&b`Zrj#?cq&,joiD^Gm9^QqD$9HjqrU4D_W:=bc\P9KtpC[jj(Op$oH$"$]kO<):MMi<(,?.68cIT0n:[',6Ur&mjU/, %.(&OuQ5G>l(g[g!7\+GW7p5_%BtH)>js9RTk%YbX8_31&=m/?2a6BrE*nq9>A_pe`A'ZqQ[T;8AfUr!-OHRk;:4HA'FQm5+u %$Dg_J8#SAI,of675n#0lUCujkDe-IKC9,Q>bQ5Jt]Y5o&0F*4JTp=n?$2&87$E[8<:+DN*&#V;hOm7Wkc_cfh"eLsWUj?!,4gepU %&`iKc>UGXO+9J-:W+U9p:eLDZ?K@L8=_*X%D34S!F?bd%.8SJZ\>3FE>e0`EdqQWA,)!b"Ohc %5GHp&?qn'O;0n,>EVd@L[A0nb'gP!YVUW4_hf(;RFY]$4X#oq*k95HFl0]8!pG]#1FR+/Mr6?-hXZ-j>d>e-ZMUA+XKYjHfHuWPf %M!Fk)Y[:=p@X8n'oPCVKT3rHF[!B9YgqL4EW2m(h@"'nG^9me61'>soIdDJc[8RY15ma8i,F%XS-glVMY6L+@V/a24GNen17OV@L %5."n"pp(XG%gjHfQUWBd5,cE^9,Y785pS<=SjuZf"ahip,I_tIE7^85qn_Tl+A'mW&-_O*q1>Qloh\b7Z)AcpF?PkWfJ^Jr:7GJU %T3@7<,Lj9cHRGk7q]N;/OY3!>k1f;mU"a>[go+#KMI^N6*54'%,DRnnC[:sFH"*!tfjBaF?L8O:]l%>p21ZE^#RIN]*e%I_<8$`s %EcD3)7^K;-pX/\[pZs;*gdlgdFY*ApaXd&_=NopI]%GM*#ju0(l$#QOUh$$Q*&5EISmHJn %)BpcFK %F1HYpW-*'sD6lf;'c!r$$JmGeWi/:]Yu]Z%CrP8:%"nFc%lTMdMMa#DE_!=I7.ZF)5iZqmk,$9@rOgqr=r.4o.Gt_Ui>D<%&ThJWV7YA0F@u %JZ\L*l4`&Cpa$RG^%"J+RD5n]eHT]#i=%cHMr>)5PjEpT$_6b*@SG_hs89-OVNc@mFsC1QDKArEt0b %<,i=[jUW-Ji.57tg`.FVRo3ZLp$Y"i_Cu@aA3[%C^Y^u#HPQPI:\/FI1Fjb]eLG+^UdF8$\[4/GlUKTMbItg<`NJ#fX+l)K_PIk, %hDohh?!(M:!?X8;"i6;L_p2PnP%s>Im9a*Vh-7 %Yi(J^;?=[$+C?lVY;FgN>Mr'U4CS$>9ou,9')AMY%U38[RQ>\3eBhF$#H;t=MON:JZZP^(+$ZoPVC]MP(4V-EF&K<&7[b+2pYBaQ %OBiN.OjfHJmT7dXGBP[`PBq+s;+X5UdA3No^@ldL_XSB^dHu0^G.MHK?:X7ej_L^F;ek??$.?o<5l^0O5cVWqhNj=#T+V,LoFAD0 %gs0`DneVV!BKU?SS2)(F.N/il]E\b`UPd(/4,TWgGSU?6JBlGF(LccaQd3lUfkK/;@\$eFqfEND'iLB9_E(Kh6Yi&u,HS5nlJO_h %nHb4lbq&hK#?N\)s#/?@s"/Z&qZO9#3;c*8gZ\AK2/tuPgOS!9&96`'gCtX7%JG_`+`=5l)c&AC;MXC1gY`Q'#!+Sjg'/oE3f0=- %]ai;Z[LpH.`!mGuK@XQ[3])>fKq:m`3])>f`A-hu6JM:r>u9e4r+R,!1$&./T2\J;Opfc$e>_pc&+bC*^8h0:kP %;&pP=QIGeAI%^rIP2NKS$=1mAVk?mJe!KLf29<1c4cS3:]_7n96C7#%aJR`TSX"2NJX[=/e-CXA&ZYK% %\%i=B0WQ#NlcT2J-="oQ]BL`k9#!&U\D2!pGE_/S\li2'gNMNq:8!,-FS>gdH8$d2DD^JKc_MiZ>*Gs+T6.NhH$V,8BEd-II[),5 %NlGAhp?="n0/h8nWhI%^r0,s`Cq1tKc&Cu'h/c:b0lA)ZA2in$$/JVBS*[R1L_2J\SOF08lN^BsJI3m"mh-$["Ns\ag8Ys?"Y-I$ %G=W"T!g\M-@,^sF$7Z<*-!7,6Y",5DhcUkrJ5p?8#nZ)Q!J`U$-l.K6#8'0u"&^;W=F %p)bp+5B'Nj2EWB3\/,+S:ZJO7Is=cLHUQ=B_Z2WHGOZ2U5(HAc>5VlPUKbZ!fe(f74/fJNRjBk15\M>t$%=XDPmi?T'#5ps"LL\/ %+9D+6dWb]W/6C4m.-?7rf4rAAL9PID5=bdfOf>)u1689X*Z?3:;Yh1r%h@1YbaDOqbHRU9_@>kHZNrWL@UZKnItds;/t0%5^>A+] %Q)IUH'8X%I;CsPsMKq_b9!3bsG6-hkb_ %+XK+NTWErnT*Y.-5F).Fa3_W.-f^ptcdXZ_0AmS"8a;["DTMAF>gF]@C^9,N&(#g@4"ZSmNqj^CmFqg(-=3o)m?sl4RDsD@cKCHRAfBD-O^ID+5@+d6Lu@3lL=/H/!/WLi)=n7S'1@R0A+4Pps%$cpk-9%9@pUn@\NQB^^oOkH %ITXk^_*^#`LQha)6U]-XQ1@`:pWqd99O&?$Hb@I5G.+mNd(;9PI;Zb7Q4"OH'sk[#?e`9I=g[i`-RI9SD=qriKrUrDa@\Po"iO(u %&q/R=V=N;p@J2q*ET_(#b]^Z^>+K@6om?"%cu,sX2bWP&p)L"2!e84B'/[d8`iZ'gIS)W%U82O8ZBHZEK6`n`nC9sO15.0rGm!$" %)M4Cr>rrt!W5_k:1OV1:0c%=&XrIpK<9*dKnHL5Pf_Q)7D;p-`7HQqm=g!hOe*_AKikj>F/^TuDiMd6imgefc79/U0(gIq2)`1Em %Vcl0a54TThhT+GokT:J.2C^5:[FKg@SR.OIpUl]O#0td9Zh$W?[H>p6@Les%+/@T%%g!7^fheb:^`C(Sa]I0s,'^LH,t>o0UVEn! %kZsUd#6(T7NL$='m[B,XlY+j2m*\DPc?;ON3rT;!T?dCgG9a66;!OZe6N+X(aA#aV,AME1Hc!#J=B47KGC3"V,YZMdiE %!6_,V_^i4Za0U);=P0nrkc`8r.rp%!Z_LPL%qgN`gekM'>R^GAoJCoF^lGdDQEV>!/Lu=,,?A8:EEQFYjGO7VHqF:RT`F#2hC-M5 %M3:p9#`".UgZbDE@krRLT;%PiNGAeIoEXYSp>P4K]D[sf5n-<5,4)OZF\5m#&r],8QJS9/F(b',l8+0E^^:!,pVpAN %@@lJI?F"/E.5V@gVJj[_Y37SC2C#FnP'@c8S>:+4!1m$fJk-pe5d@CN_SZM=&71%t&&ULb`.ukfQ-MtmCo@/M4BkS5j243=LV[22 %@=6^TGaQ(]KWk$!*DHtC*\36P;"_Dq*'^F^WTs*BTQ?U&&$/d)REoa&!a#CdOK.ESmFUEr3UZ$A>I/)=l89SJpoD'Z.$h>?33Nk$ %3q,_M,Ur2i(,a<7"?@EJj*jkN6%YVRG=hSg:##u2)(V=K:c<`pK';(tWqCp857\(kg)SWeZ\hb`QGu_h7Sk2-#40V,?H/T?GX7nr %I2jk517VXVe4>Pu<479B,W>W\IXee"j$/grhjBZ+N;ms[$>gM+FJO5IJTBg&FqY!1koNit"$!8!$eRCN)(6kU(K0m1_KTS9/XpPkTIZH82OB%rS;*1]]rFPAi6dO-C"$IlRpq`#]5,3lX/a'0"+lC_C$l&Zg_P`\7>eBd-mmfQh %^^K8*OkC_g)=p^(bo9]h?5X#R]#QblVW;%o0>dTJu29o`Td"m^W3ic;"3k!DA[gN>FZ7GLr %l_pK+`ee8CW^5O]bM(8boPCYXL/]mTO'sc3h3;C'S$JM]]ZNG2,J"m+\!VF_dB2d,.PpE;8g'Yi\9Mt9e%Zt<3)O>;o\cD"UAB1\ %Q$qYl:Z,QiQ@4Kags*HR#S_IkgcAu*TAeQdhm5ji'#07@Y9.X,/+#Y]'!H,d7q/mX]?':#d>]8<@e],6pjZB$'R=NeGb?/M;rlX) %Gais4$#bnecrTu4[J-KVAi"<6Y+!@3>(70[Xl=O6c!tV0(A\V3RQ77cJ4dNB^] %$'-F]"1atk,TKfFC+GK`R1@+a*D"V"/^r*VVkrfqD^eAFNe,1I0*DI>RKm*@:YaYskO'-Cp$p4n2Ka[6QXgCRR!iLIlNgLLlo^>H %gf>8(MfY>Q`b[6jZ`nCQ2J2:J(8TR:^H9Hn9:j1K"M<1Y*J %ZNZ@g12\TNZNZ:&)7L?8fb2/%e.ON@^fc32k]*u7c3AL'Te:Fm>]?$W]p@qo*_Xgb2I8J>*>34ID0>)KHW%cPqb,L%VK\.k3$D<* %1o]-%-S/`D*eJ!*8n.DcI>4nH?,d.D\k?$ %7gAQ,O$T%kW_fNj*7F-^+WZA>ETgc+,@C@*[iE6:L:h$QE\Q/"dmE`J0dcR)"gn1V#2QA)tU`RAapf^K:qnlY];* %rOhTQ=_;WJ1c\eMLs!B&9%t(C]80&#d7kY>Q/Y5h9sCl1E(:LnM@gM6TmM_7-.YX`PCl0`Z*g1BghV.,b]6+\j'c8QL(`7)!)d+h %P#>b6Uk.3^.j]p7TrLoN8;UbA$r9JX.5AKDWN&^RPaI=%6Nu*g,DlAq.emj-OD&SK8]ok[8E-OL2]4=9Y%>b,\M7Le].i?^g__a# %Q,]$jF(<"mVECEu3.)7]J[mLCQ;g+q%Ld)Oo2X/Q[iF>L!PNG6"+0P!J6qHN=MU7CIA-^KC5dlqXYl`_%e/S1?L$C$DbHH'jSkotl)#^J(Y'bBDblQgFjFV?$AnkME"e9R`An\U]Pq?mQT$",k %MGeS[4%Y<6Gcl%^C='GnSa7\:)Id"C`YWg:dPo+]S4qZL9A^;=nI&nu/:BmemS0A=Lo#$G`Og)R*O55s*.f"][#h:2(46n)*O0\S %KnV7:Jk4c29A^:2M"D^mo[/HF*(A;9=F/VThoM$&Z1R+ENl;cqA"uFP$onN)N4'ss^*+7)FkGiP]?O%5\$3tGD]c&0Sg1H^ZHc$c %;q,MUX:00uh1e1G%2<-a&\ur[KdKOLiCl<>T9J]/P-/DpZcl!bRo/h5*h&*kqM&+R\YAGHV/M/i^"%3FZ1RjIRKI$Hfs,\+_<,II3t[R5bj%YDdO6t8Es:>_DB%, %n*l5=c#6,(`AbW(9dh0&AI8j#\91">b&;LkIW@*!%?]PN\,LY!\?k.\>Z8m=MINQ4=.g][.#ORDAAe2FeEOiZ.$d/J46FJ6'ZGgJ %\>(I0S]br,PI`FUR^OW1.Z$G&\HMP%:J*14eSkaP/'-g4S-r*!78MhRjL8q&5(-9Z:ASG;f9aHCommK)8o5 %?YV;PDk;,[>:0@L"2Dotm-2&*,teJ7:]-B$gg2KZdAu^S3q=Woe@fRN'pg1)c\k0:CdC@?cdS2`mP@"ZQB*su2ukIB;7[d=2UUMe %bKkeACV$/r>B'RdJk1&QpN/\i]MG4o;dY[MYYPGFV:KDFWLJ_JoXm0Q<3UI1s(juk4NS^Ocp(_GY'u1K60"F2B+(HCR)Mj4;VLPf %WcMY^>5.Yf\Ufu*r"@^ZjlWEA2M&!&b0:U@#5F!>MA*9b1F&QKp(JdUE(A+:V`n4)Kk,*1[.PU?j %\K)$*(WLnR2o5j4"e#4dg^#.s>7AX[MEZokrD[ZfO[kEU'/a.TAk=I0hkJ&':Gj5a<<"cUf5*`tn+0HKrM00)8i<6?j[3rsDJDAm %3LQ;(cd_Llbl(LYNWXNaZ1V&+\Z+`&Sf+R(9K/4Znk6N49a#%gVkS!l%\7Y!Hn&:qWSD_A]`EeWT8Lqm'\#q?G!%XmKr(Ea9sSE1 %4.,iCga%6Ncd10`I^l,^0_3WI"L4?9G!(G5&m4jkn+9!dQSd?n]*#gs2@ASkd8@o&W/e: %RH#j8ckW/I6kJ#o'RtKCT^Oa'E1lLTAOIA]iY0Wb<_A&)O&*-ALsQDRI&9%56Li)D?Cb?.#fRmX5Qa(UKOWpSGY$4b*%8G]18F8u %n^2BGp]R]Q9G#?o$K#W&NZTZR(n[J%muC59D`-Y1nQV7YU%mX]oNd7a9!&?ca\B>E1F^`74i"5.';5OlU,tPaR+2S+78V[p$]S!\ %nHnfG]3Z'IQmI41>sHngf5@3oZMjO^a!-B$<>Y:;l.)=ql>Uh=T:d9IJ;&KTIS>fJ2"b@(.]<>n(ilkM*C8V1,8*/+LZD:jFGAX] %C4(5UMV;2biM`^J]O+VqP[EFYm9frX1"r.67ukla+`prib[UZ'C0tn=q48k75YhHZW2Oif;h>j)^&NdX7BP`b"1sS>eB7:CD@Hne;DT_LY>0c0Q55LN(q94qOiXQo:1688-D2Z.EqiIV< %R*)^+n-8l'EBA%/oW703:@$e3MlmG)47*WKSd#Y#dA^^1X=sd=Grek3,E+^5!WPKL_2dZCV^=eAjNK7[1JCGU*8b*NllcPr7*c4M %4pdHZ[K<:EY*W:.k_:)(Une/"C`T2=4("33\Irin#O%J;%[rK*STdd(E]`rRVY2l9nI$VH*Y50p&KfCXO?gP:!Nh_elXSuu-!j1Y %a9`*5db.8hHO"[Ze?K+-"Au![`)ao$JHUGC!T'*+fV.bg*W2%P@,Xe7(MnU2j@2lR1[E+X"oLJr %<)5!mL8^mP3e:eod(ijUhe`nMoR5'Xah,(D/*QVCPe`;\FIV^#C+(jUYWm_[Su-*]3Qi57gWQMg]FdsXUo.kc*b\_QnHA/i47W2m %rVC8)Nf0%Ir.f>HnPT$44_oGfoU7$a7FF0EJWRY+fSq;:QHi0@J %7Pk&_RP#6%bdCLgB@c$>."!B'n)d8ios`eT"A^t:!YAZN1m4h=ofN!Wb0@6\X;$WJ9GQ?04r-HUS8Au5mt#)7RbO[ %:dCPib_YXo/=@+5%J7+a,BpegOT5sU?dF\drPslpa,Kr(bfKghGFiT0,?ktu!aUH[)4[oW!QI-4P;@*N%;mp1k5N-LV(@toP,^?O %^2s.s4?YK[YSBcWeR&,Y5'$T]eB+j*Vp+N?24K4fl*0@koXn!M*P9TW`3KCAk+ani:_ji%7=5rt5%ibh0"cBGh%kj1_]#G1(gIhX %jReTJh3f%_=(+>>BtSo&P3J+Kld]X_/)OT\(?O2kB1k+Qp1M&G"HMm_F@dkY[!C:n6=]7(iBCRd4!+%hW/jIjYK&[o%6-eS&cti& %\l*aK$>6ft5u5M!-\qc;c:Q.:8O]W7G'fpAf;k)a?QkK^"1RIfq$PSq]lD;&a6U.T']*i+oDKL)EM\GYC3io&q_+,G?o'p)mu;"S0Y2\@\H:&h8uH`?mL)+)j@VhRA#9" %'i(jFI?<4OZtfo+&LPf=aF1eUs1ZaYoYCFeg]dt8Dnb((d'MWBCgS/0EZ9ig.Jd>o.b00Z2&dV(WiSG1@rs)J(F:FSrM.S$)RBD^S7'dtlKkNs8R<]DU!YN[J4>UHl41E(6kF&%<9+[g8 %3iNM\ltnD"28,5%d>ZSB!Io,lWl;%uiJd:QRZVi,kdPLXRZYT""R\Z6'$j5_Gn\Fn4>Y%riCc!Pn]\3Mk=RQUn]Xu3fL:B6d>Z"" %doK+'d4>V<&>anF1Xc7("aeTDd;8>OBd9(?)f71q9f.KAQVE:W60J#5(0)`IQ;k6CD^_IB1>_m5s-W)jYnD^+%oHT_?QWJA`ah#S %URsuB%sc85j^r)XE.lNPSK&aDdnfkSZJ6GgD9mp](o/![VOUL'O`W^NEi'jSRRUdh]ka_O'rbQVnuA,rXGImVe/n7[g^k7op3al? %[AsG$7(oebfi9L?46q=&UsmM`W4q9rYJGgtVDg;=T2=FsJNWJ]eq(7\W1+j*%'rrc(eN4_HXBh4Z@9f*XHS^Z#%r"`b9=PUR[,1KL!@\Oc_^kn!:9FK!1_O#V)NmCkHHK>Gq==p6$FpKmhIG+1Ej/4JM/JehI)B&FEg$S[ps^t8u$cEqZ`0c\L2>^@i' %,HMe4[a+.S]Bt[.fs8;`F`)2AL;TE;gL*R1KuTN=gL)]m&/Jp4XJ3PY*>W:V6&YQs9UfiaD8n%>cEp02``6A:S7tK&:.UmhPN!pF %iGk_hMApZo_r=@Z'K=)OR$PmgE2JJ_7.-RZZc3bKQ7AAiiWd#6$TZ[T;U[022^UEs28p#fN5FRJ4'eE9E2H?RUm+\_nY; %M_f3Jgb"YkFZ0an(+%,+CL %Do?`27\HbbAFi.C)Yu&o&_$`>8-6;8GHusjmNhA=?"ia4\7rWXhM>kN?s:_ij,KFLN-!qbQ9Sj4Z)kdCBF'E.#Q@$$/oCZF!Zu.s %FKB^1VFu0g$1A!Xe.ejWf?R@'Lgl@;^44LPEVrO*:$')>W8_PAH91clVu!=fhaXg>mL'kt=@iZ7c!B[_t %qcQtc?S!Yp1FYo-?s[>1C;8pSE\V]9nq-'dl*(%ZI/=J!2rFi-j5bGu)?$i=qN$t'iG(Jtn0bRif3[@$@/jYo:X&P+e*]r>4SdO+ %(A]]]3"f?$!4sQS;?Wg_K&K;[bBHct3jQ?*;PXao`Og(R0gfWFR^)sD`pDsUYiBE_GRY3mPO`t\R(Ir33<3;nq&A-h"0#J*XR<)M %O+%B%*i!2)N;iQFd)]CZCGL'&id99\b-#nG)M), %YbX<>J(1N4I%h.#n4?oMR0#&%DYg=7YBTp$+26:%PZU&d4s&El,Mf73@,Asp&h,M7q"B\Oh:bqg+`OCPS01.=4VaYN=[;U2sgW>kpoUoi?VpMP`eE\dPnrHoqC&XROnVp_i@'+U-V>9hifIQ7%1ct9BJ^QW@M65">lsp.*_O4mK%dbm9 %f@i-CB1PM2(lUINfWZ*=UgI1.sb@EJ[?@3BC!g"8.t$.0?b-aP?[<(,"S! %Y@Wb6YBB*mF]:H6m5ON8Gr'kMN8fhRC,'jS".cm"5(TT1)m=%K=fLMYdV.qt.1S36Qt'P4[&eC^FX/(?^uff+Q'#h3?1RK`PtF6C %To+-%K:XE7%jCIOYq)knUoio(3"NNuFUDE01)0)i@mAjhB?a%Xo2uXb`N@r6WL:`1PpM6hbq.UC=7QHAKBZ1Dp+na2VuOBLnn\*$ %FMA:Bq&$5gTAOnTRh)'P:Xl@Ve"TfXr8&>Ucndr:T@gbpF%9:#Y?,o^8+XmN]^arVrPt7Bl'HFDT&a\oVKlskqEh1eT!C0E\M!op %Hp.>i$T6='?.p*'m^<&L[]h+@(!87b6LiVSK'75/T*iOVnnmL]Yp^<)I=eY\Va@A[[[=1A^kZo0-oRa/[mKW9-V,P';(1;t7,PCa %;CLb)0$6lHUJSVr$1.9T:ak2.XM?W6d8ce=6T*A<<+!$Z%Fi:$TBIn@6_C$LE_`>#meeRLDgep)=!>7u[D&1L8CJn;Fb97]@U7*@3oT\0ZsCM=/L4)e3r2/R)='_u1kO"+Q-)Z^Y<))h %?AF[frq'`J:u4)nX>s)!s>^Di*j-4?7>CN>KEg/O-`a4Z[TI@lRn=6[/l086!HrMQine`6>V6RrmCh%kOs41sP+mW_GjH/%cVSP5&>j_28YpO6[YQ'0bP;L#W3JjVBugE!4\c%;WHC;24mig %U9qAYEskdOc]$Y?A!ojO]F'i_8JfMAI#4bnPj$A9;-D!o/Q$c]9NJ&q"Oa%6<"HE)/9P7EoIopF$j\rN_:s_Eq/!H3Ul!Pn"@8=h07h'mhYaOrLhYGf/@J$`MBAaik5F\4&u&R(AJPq8?+$*q"NX]1^CMZ-.h?,/Vu>!QFU/i %U,*Q'b?QE_bo.sB6*:B')!m9.I6qCe"4,6?GCo1l(VNla64gjZ&YB15bN-m#=AHRjVM!/2l_"a,R#\1QR0Id^`cSRH %Ed0K%m*1,f"nti-TJl?sT+kklD^'FKeXFiPJ@lbYOX7Yh#G$Cqoh,g&V6OA:F5[N4*8WAqbI#VDbNA%/E-"Mp*D[5<7jL.R>4JqMgkp3#BYiM%ljgNVqGkKE&smgJl$tSgDs0q+ %blMJRh]OX$/-h^0IffofO(fX'[11b/@6*7>ru7sj6?Br1od77&TfM%)ru7o4YT.VZrsb,;_fEP\>mGuh(tPpQmXbqn!GD8dn2t`) %i&TWn#+<>:3T/,>A"Vfh!Bc/797e!9GRjJ7cufX24I:=Uad3/cAFQ,N]cSGCcC$4$%X8J5Gpk:B$JE#`iZ2-'N_iAfb3HPbXmkO?22hLc7N4GWlRGlB!7#Fl1ZP-Y89]RFh>_K*FHe)u,TeUVlUQ35Ed %50)=WpQn&[Hu4M61+WYM217(d%_*\Ya)h7;5bE['fCE;F>R9u4g["K1VcQAQSQeHSmo'gi]2^G:qWqs-J,&A=ddiI.D\)(K(?aOh %XM9[aHeuJ"Xo"t%/VmXeSU9('4?PuLTBd?N#dI2Igb''cCC(V=r:Zc4c-,5Hq,(pt/>d0/dt;H)`\?a_;j6T$\!rF+8^V"hb^B.t %okF/.==l$"IIpTYF1&^IX+@hpom2ldr1XimFe\r=@n#]DJV]2M_Ec\.n=U%o@e9Jo21@q%j=3=N#sj`jn\g)bN9@E)HiOjRKBS$Z:9#[u\U&/\]q;U/+j9>&0XDXsd#r %L"[FM>jG4_$Z4lNLL_f!jOo\rd$4N %h1&2#UmNI8-K>`L&mLgH/U:N_Y@^GH7/8%Wd5t_&S(dR:G.l_E3)6ndgBS87=ErGo3f%r@.Th;"UP*4GSb'`*foOfF2k4)E1*:/L#[>qbuXOOPd6WCt!IYmP-!(\cn1AsrmA[]]GnYt`/j$#Ml[fc7H %\Cks^hB%]^UY#7H;(UJ&%)S@L.eUb(l:9EZ*s:u[W#+\AjO?d/*G %>40B>a'FQ1+b[j>)'i,%o;T*'5m8i,4`ocMMJSX'C>0([)j&@66i,m<[d#(?QS\&V$)f9P^"70NV;j=K%dJE-<\N7fi>lBNXaGIR %!0>u;Mj.M*0r0S)WEVC,dq74#7jK)c41\^X8C"@Y*2/ual"'YRpDHJj9^5Y[qaeq2l[Q6Vkm"S$f/>pjN9oCuoM)neu"7Zi%ea=uPO %c7YkGhE9n3^p>'hS[$.i#AO@teL]T*)=XjC?\EZ32W2D^]j\_rXGMX-%!^u]+amG;#!>0[,:CNG^iNpO\Jjta8PT%?i!CS2idnXt %ep$&i7F:S])^fj7:^+HJn\D59_5X^On\AtV'5.pfbQb^K>\cM-4B05netW-PGa1-/Jl3^4Qjn9U63p%Ce>-t?e`(G]K;ri5idod5 %V`pBS.l`R2;Y#%EO7&R6FYE$((9$-4#VZW9B[&To7/,m@#K_i.o3smk%oXX`qHT.,_a]1pX4O)JJiQYkPk.s)JkKRLVjpBPo4;R_qHV0j(pV/!CIk:tSq2Pu.!fU];.RCma(r7I6Vjl)BFpMsLr$#8'Bh<_o%]_$B#c:_=5C:GRrNeuP\._CTUV-SO_0nq_$+mX/CFs_acpjEegW'?3<'em1,XRL %hCiX"Xk1I?9.CU"cMj[rES"ZTkY4-231P?P^-1;O_WoqJp?`0\I/WRJV0;98[!=[bIs3mH]R>-Qs+T"6kO%#Vr"gF"4`B4!bU)du %mWn^'i-C`=AXT*9hS).N7kpr`ceGq,-@g')gMucN_7h4LEt;%2JkF/.\#6QMq!kjc^-+dCj4s5Y6j6?24`B4!HG=E=mWkj,Fbef\=YNj?sI=N@!`0?SV3B$ua9*X6*i`k"&_'[X$Rb?,RZ %.I.9E`k(G5US4cq0\3omLA9jriJ\pM,1OAf6t'Us;3E=5),brU']G-%-:T*B08Y9"M.32Wc3Abi'Rr[grt(%(bR#IhCL7o>.*dB3 %@4?XZM8E;ertgkI%aim&'VqN];>spd.*V"4DONJF-mfs)31-7)+f!Z5c0I'=QF0K]T-@-;I[?.(W=Lk(`2m%&>KU>tIY18WUn9OU %gORqg89g7FJf^%FU=_^qOf^(?<\"P'$;;.%^I@Fj<$C;(eNkR-e:S6>%_SeVV0:V\r?Y>9-W0Y@g]!B^MTR",^gFP-8'OZcr^&Ua %k+^;SiG:$\R7RFeV+iKlAl@tAHo!2SdA0Zna/"6%%\65Nc(n/c-c9@X-A@TX#X8t@P-?eVC.iY6"B(g;d8dR\q*munRZ(HX_Cp11p5?(jI`P[<*N\R`,4?J5_o!K]F4_u %b9=Ql^X"=Bb\M*R08K1Ofn9njJ8Xd@IcB\V2L!]s/^KG\BD%2=g>MT.4o=(r=*u!A\G,9NF/;n@ShRk^Z3LS2/:Pd80KoisUZRO1 %'g@(8%!j-s)Y>eokF'SF?p-e4%=5r^;+2D!]Gj9RD'I>9o*=m;..V0fSSEMUb`*g(2A+C7?B(\+"!598&I"@Ij@7NGD52o]9uK6? %6*l&V0SfchMXD8rL=7+2__=!+.,%(@aP82m.pi='U>UBmMq/ROJ] %MDgT@dPl%XXeTP&:W0qD7.I)LngKY?71;tgm0_"\b$A9kpYn=KZR.KnmPs8 %9eNXZ6J!NBk)lE]KY@hfH,LXl %@:jS6M5.<%kC3H]@ME#4)mi_AYn;h9UKp&?Fus!u\"f;.L&j.+GXRUa^ZT0`oKap0?LS^<6$sQulN,=$l'_47`L#U9W\]Le0n9`Q %N=aT1j,F'b:NO$U!#JD(FO<`cWCZ'sec=O^4&Vr*Oj.MCq9L)QUT9UOgbFXNH-u'@J64ciF/HpQI$\ %J0G\TW>:VqGL52/7fO<46IsY4,l7IFK$,QHaQcB.,H!G['mVcSh]u"h&9MoRl/'4[N(-#rf(=m>c0(AQ %`'i4pc=+o4puUKrEi_UN`AK$)ZoJL\0(&p6\fOTIE6KHXj1ficp&4t-!NqV(EcF#R'd3+[U\o1Qc&Za95),/WCY!^nN.mRUCJGuQ %i@q?<>k9$=pDG7)";5D/Y]=_XQOD*F#UpSAS3V[P/?E)]ZR(:i0ms7?Pi/'iCYh7ZX$FnJXi,e/es;JepG`tK**+\pk>Q*.K".Z5 %Odd"q__i5ho=,IkQ>_3^F/\BWcQt(3jpH;'ED"=>/V*4+@8KSBb27kW %nhpI99?<+2ME;oB=M-P3L$dif5Kn(Om,^$jO2%Qdko(W6/f(Ph&nA*PPs&%2>kDEJCSHmc,cWZDO#:-f.Mqs"%Nl]4MJ %[XiK4O"Scm&'8JYnjft>]W#B9!Gg)anIR97TP(P):s0T.$-,%l-[#"/ajl_'6Q:EBT*s20PE"/LfB"JU5eM72`l_ui+QS+tWYXL; %Gir#ek?,=5\%7e: %Mheg(d8p6CBQ0i);,`mmK+o:L7L4lqG3sjC3adQ\]*II]s$D>p>f#0uL*hC+[U`lO?'G1B`lTe.9.bRPqaWn3dlU*)Ii<7+()]St %=Rd!-Ej`Ya=jSuNbZ(=j)L>Ak'39.(9jYUF$+4@918aeh2W\]4;d'7+,@6%,VI%]?fBleKT`e,UY]?SagBYDBGF,YjW'%iNe\6>8 %%4,j%2UmJEPR#L!H3O%!823eb;Wi@3EQaV^6d)Ei.$'^]J7QE/1&MJZR3pR>C:0h/'A8M"Uq5'!oF1O[P4iWbhA"@H4mBJbLD&^@ %A00u$V(XbXDeTGS6)-BOAQh'?=:h#o"k+D&m"g\^TbZ^)"E^;6CT8;HYWo?,59%\G8@Jh0+N6g388$>R.X!S.CNo>36/jY&c(>f< %eS4X8iLM\d!(L:+MZK@o67W_i#(]3GDMGki*Eu4^58=d=JkW5R!/sRWGm0g?++r#W)?6>IYZ]CY@af %CL-d^*C4@:,6:*(c1G9rMR<^>f["H.&=r+b/?LY%0o'&;3E:G@`S)YpbjeOEiDD9`ZnO\DQMau:[WBVN_gnZjc.0oK+%>/>e)/4T %nPL!<4hT7e(*>sW*ec\4D"1@:iDFhoArH5V#kHMn8haNj$\Zp0UIst[_96X%"^%PWJH3KJl*F7;'>%'5l;ucdtY@I9I!d=4sDf*J5MVrGi']!D;mFZtpX8])WX4$sE<7'NV %qKCddk.-O;2<@"1%#O=.l5/a?_#'T6b^8R=o<[m;b-0l9hfC[DTk>J%pX!VKqG6XXc1'iAJ"asQro/5? %P+m8@1(Q&6+qeclr"B]U\;2Elp22/GPH3tK4e!lr&1MF@Su0.U*[8Sc$O=kfnG(_*@Qu019@AM0>c>3JM-8uOmg?)3RYjh$I219UGP/`L %<.@7[iEQ7Ol@mR7:at(7XQ'GFXTGqE_tiJXQ?Bp63Bl@*X/)E"n\=^Jpq&3"!m2;7(OY-jn22VU.sC97`N-9-ptB)5'$:G77;FFM$&UKYR[h4!2.n&q)gtnK+;8R/1*q %h(Cnib$W-[e,H9H:%q@[[nGb@",:57;-BB:.oH*fL]1<%8V2Xf&UfY9_?)pQ35+&(o^fu"LGXqU%add1YJCcO_',V=BRHY=H'f%6 %,\`"*(W)\Ai$4D\fekI>i[a4]\+8=DpFmY\TO2inQ>ae1Gu(4HBr:Y!%<3/@1rK<'X#LJURc2qQUNbRS0Lm&jfGu+l_AmDH\B!_N %@Akm:lurpHdkMs,3Vk@%NA,$V0#gqbmh/)7bg?V^pK/8lYlB@l42_9X;$*XiKpOZn3['Pt1$r`,eFgjTPT&!\oK[XNPPo\=dnZAi %Aad2]R.E)E4B0S*TQ=Fon&")h@\<6)7.3]#QT;8%VQW!5F^iF?dVFW=RleG]V;p9N$ %mhaSI04W;n,/Gtr-&CEA?7p;*oi:XGAkSQ4l`*@XbQnTq4HDKUhbU*AqJDZp6s"mBVND7:OucLFmc))umuXEYd+,V1eT4@TlO!a? %-1p`q>"Z0Sh4CrgT1mDUGZ=-'G:T_":KG)R4DeD`qM=R@p11A):NqdjEbs7ZOmD3!H)[9m<7)R&=,R;c\k2Y6PI>QtSS!+BGF`c-P+pUmUSU9al`qC58^-I_L`_.dm."6U?&"g/KF?;lP$GaP+'*a0r>1IDmbNA4B=0rjkBW,SeZQX\_o]tT %5It%iLQdj3esg9J`'5Ki$ %q4`1o9:i>2RP3a8o#UFqDA/`,KhJ#@GFC1t?[1Z-HDgQG,+gu)DeGXaL6jE%Ug,92auUmk?ETOg=i$fC8?4lJdOHN= %K):fVj[tq5"g.]rj\#(")dh+6;RtB;j@Yh478%5!-!/5g.V:RD>Fr$BRP.j.\`ER4Vtn1n9F/1,N\k+n5nm(sPc7XO$H"%5f=P,H %fN$ju.qN$OaKFWekNgqI_Wr%o4C@P6?ecOXOQYr#jpQic*dPKVBtg7Yq%<[!*?pk@k">\"FbhmK+EO-X2s1lU(qp,<;MPOTT)J;; %&dM&m5aGbH;DgmrNVaf!(8+eq68p&=(8,q/#\&$05dOOFoLi:;^pAMN45C\\cm/XlA?\m4J-D,>W:.TW_#cGH%]=uZ1Rh@l=F__) %&A9THWk82F\i1#D,QYbF()@9SDN9V/HFGpL(81Vq)Esu/=Fb"C/VM1HZqYVOZN/BeARPV.+!&$F6Xp.c2E..c*[]7h+/3n7n$E_FDYlN$a.Z!&g!)8SMO_E[2"aE!MbsnBA-8ZJ\%D.6aHo\!hQ<_X"gpgjp!r^*DpO&_N3VV9@F'"t0^QB/Uq.D78g!ahQ#oE2cjOO5 %6dLZ4K3gfi*onUN4X.R&:CqploE*b<@"6CU5qelo&&2K8%=/'BH0Da41$AeJk>>(W9nQaPHeqg];FIo=Gk9W2V_cs:4BOqNaiR/_ %nF:\iUE*k?YmZ^[&4A&]ZDX[uSbDGG1oma@T/H6XDH9f"<:%uL>\,:a8T+'b-Hrd,CjM'f5pchG-(IB)#-;?8SG %4#!A2r\kttA_YJ]AD+&0]o@T3Y&q&UcJbS^Xaq2+5VJ-AV)?V7%.&q:n<_<.oH/mq'N;oEn?27q1N8229T&`WE6goFUgco]u!o1m[ %\:=PSIK&ChUm?ci]&cbC![mDC_NXhoAIC87s)dOu#c1h,"i8%P2D&N]rsUX#J_P%-52,G'X[Whk*plDpZgdemOOn3WlO-gcYV.bb %#UF,TAUhNtnlOaW@CN$p4)j1f?co)8#9?=*g0_O/foYN<=#`bgACe1e3Ctb`OR),B"G\m/1EINeB/%sA7g5j5d4jLUr'a'!dMUmHjcE>;i$m.,+Hpi8nYFBu`p?]L1bbnoCg^)U^q1LZ0)pi8nYHma\+ %Me9)!6P3Z8l(u/6!fJ]]j>uZ!#D0,U6E]YQ9$ZG>+h]^)Z[_2M03b,B2[oampI2[CEYJ@Pj<[\IORS %5gXX\aE@,S#(s)U6E](6OMUOm]VQKjXa/u9GtTs+=pE0fnpt%9\hY+Eh%t*;hbj"T?2'UIN1TuUcui]'$CDU)9-7cf*]E2DI6uP6 %+kL!\,Cd,R^IsK)k^ej+Kt[rX*Z1jYL-*%QHXNWZ)#>hM*a#7?@IA]/3acWTiS4Oq0UWP-He9HndIt@*]oCYNdI@)=-(hZ*12o!Xa8=fRR0#_/"q=V4lWS?]_.+FA$s[`f*=*?9rU"r[p=u9Y!tRq %Z^A)a"[!u3T+'[e4?5B@ce3dS-_EsA %H#".X;R*d+=LF#:E=XJBFNcl`iZ>+a]U4%WPI\_#g_7WFbWYjB$0%#P34nM^Rq(mVb'rnnm]d>tE7O-ngj:Ph)(T2niZ?BqE+/1f %0cDU]4\X8!@d\6o>#R-L4G\@JUb8Z!Bpj:[O4=]i^IW7C6/m3r3>GcEuW[8'6,nJ'p#-!I7B",,jh^ZUVHo$YeO]K([`QuZ)V:<3hp7*aR %[j.&r#Mr=E,GGq8C'5-l;mia$+t=oiAL*^BFU]b(0,:/QZ4F]"Vps_F?*pP;VZA2s(AdpSS]mah]i$:la_LgfYcR!)*"VLs6JP0^ %bXb\&*WXAjE"(7]/Kk"LOidg]$c#WrYqk1c&:] %-k'd(2S,pmXiACV-A_7aL!Oo;kN2#lbt_mUU,6#RN%ti&G$++);gGr_f.)'F,E99TZb!a,cmg<;!r!O=X[5o8kh5.#H#D6gkjpLI4Vo.WCH28!]$F0@eiAtaWDOia>q_-/\%Sj0G,+bPVrIPQ %e`%?i7``8sY%[=c>;Q"SMLHAJo(C$rPa$NQ^WV#q/[i:m[a%R\eNW$Fk-1F,'_5Z!]JLq$S+15(S8/d2\fAm]blVFm!d_;1`=C]4 %Ebgh&qDN8HXl\O&!oT;;FNsF/)(!!4"63BWF5*G.TX+`4]H7R\BLe5@D9FqjG?=2,,C>9:L_sK96#lY559ARg6g28_`3SOdWaTif %!p`=*lk_HXG+jR/CAsGm,jP2"2sW,HngjK3Wii^1>R*phB&`Rq2r_/N:V4rTeb;C+F0F*M]<%FnZrSQ!:G&RVrBF?JuTWS1=.IM&(9)8Gfgd5/C>?UN^-;<$ZFV7+3K':eL!j_9@Z\;b&@Ag_7(,K1eP.C,g5GCg=XTa.Y?9#QpY+(DMV/`nf0^kuF'Y`WH]nGVZ]Y^"?UR0=FitoGjlFg-"$VgC/MtbLl4:',WL[J^> %^0@YN?:JDCSP^Yp]NL,n:"$d$Z*1?U,^0&=Nl3_h;u"f`pj8Wq[I2Y;qEJ"FO7sl7UY'c9p@NA5s5T&KhXdKnJu:QD$H(-&kA&jP %1[@'SpKYsi:aa:1#BRDX5Zi$XGps!KS..":$5L#]g;?3+@%`)oE^2,,H=04slG,u`;fu5.<]4-b52c>nn.$ %9a1LWqbQugpqN_@fMt3:+"!r&D$;=#CVkIY' %8_n,nK2r081DXR*033WjfFbdkMIUDMgbh$sU%fm#_=QZO%E0\49&6muabHf8Aub)uI993nhMt115[$r+\=nMd!c=MoO(9[.O*P;( %nO\H:WeOS5'VAnab<3'p&a)g(!TOZJ\G`a6\TsRri6uRb1tr.qV;8"J&(]<&m5@J@9q?f:7Ra9r_fCc5]?Ni01./Zj6+<:]]?S`> %K,kT5G+20?[lKmohT<`fgMMri%DQ9F\(cLWXSfN]m*.G6EK4%lFrNqt2LVMU;LG04]_S3WF)b[siO%@\lp9Lq2TMsWA.7`"ddg*c %1/M_p]31JKl.uY)fCf2_+_;"dQNW)^Ra_a'=rKq[0Y`J3%(#'Z3j`]mc'< %]U"nIq89#M(Ge-j)V#gHg7&'g04XtaT:VP*EJ(f'6I3ma49l"G?8+>Y1i;SX]bD6fj!q.V_OX#*l,BQ-Yj[b\$O;4+1%:g@*Joi5?!P&f(rY)pX79`1g %9V!T8JZQ@tp7^EDoJ)LDE$3?h\F\U7qTh4jS:)fkj,Q&W!oM+N4&NA5./ZOEgkhaGaF`6>O,X?Kp]6MBGLQM..(.N\2o0Kbk_EpN %k"A)IS(8`e7tSL4lJHWWV3S;JO:fih=jVi]J;f"=5.YGZ4\\MjAfbQ2-"!u\?7QFKA-CE[5,RR"O87*3HE00Joe5rAP%30=h_J\q %Bm,codL8AQ-2D;aKF,4+WD8%&1eD#UA9tD,+X$'CQ^o*0,9Eq3B/MhLk_9%+HGf/k.5,h_ %XhJnde;sRCVDi1GiT2SdIj+IBO;%fLanuYaJQ$,WMo5/sOG8XqjkJTl'33ePY,c49#E]PM5]K3?nY#.l[5]@__thU11&Z31?i8Q4f0-MJIi3odRG[3"#X@GXr-'#1\*%l2/fbd;Bl.WGA<3!l)lpd/,GT#**O)R!U,:)Tj^e %8E+$V(J4:@QdB]%;KNPYlX9'aEDdD00c^Wb46W=I`L)ZH`Q9s8"+P78HV?s&p+Qs@:jBY2N&_)b6L]5nQ(JF^_;!uR)%^te!e\N$ %g@&29Bu286Hu\cr?@O`,F7`3H0BCSHk4kU`=sb^,R[moc$)#Dk-:n3:D_ZEmSb"E3cYsVnS"U\4rc/bQ*F57d*ERfed>Na[^i&dR %k:3";9iG([DDZ3`P`/KOpMn$,$RbG\WML7rB`H6:/]YDaeh:ed/!E%ooc7BVmp+1#IX%[o425Y'l+U"_CMBP*`oJA*i>qN= %;97QR:5J?_)Ln=<87!Fp,"&SJ0`60<%.+Q%HYVG`j9NMU>P %P^+3@MV4Tu]Znc>m])g^);[ghqm6.+HSDN:Q2NoC/%<(ChY#DaVeGdMPs,%K;iugu,u_`!97pYtM:SbZ %XBfO2o#*p$m;pgPc,\.tKNc])!@B;X`dPO0^REh6J%lt2V\Sm7e_/*r]1sI %RXf!o!`]\QCEJP[qBDOi'#*@?2Fi9UP"q#j%uH9\@hHQ^1sG/qZ_1/4d*R,hhL_&H2Gtuer;Aa0%amck.CXLGM4\$Q7m9^tULiS/ %g"4_=rm:4gXu65ahG,ALT$$+TLp)$_h,VIq+g0Qn."Io*rV5*7[]@mB0+3IQ/s?AZTO@kAhj*?aEDs-i]"a,;[ANr4TB^@IV#T#V %f'7s%0uV=RMd&N,W2ak"&0niAAh^gZ6Auhico2:rU>k]_@ljRKfQh+QD#3^nX,i8j@EPol8AbgSG=(_B %I8G5-VPaE5P@7D^<8P*Sq%:&!17J]An%D%(_"]aE47d^q>Z9qPT-NeWLVQ+#:,0qd^\:*R(W+]N\hBQaE-uQ#*Sk[mn+#tR'`6YC(I(l!GgAY(=1D"9K8m^n^l`",DJo;T<1M3Gh8WMXVAoN_'5,5#NT>BblPj$RN %N$lB<4LkfM4E]M@3gesfiMj0>0>EB8Q&HX>,hp7H*@hM1E,/NXaffV/.VlA/n58%d32=AmR\;grV,HA'c.'Gs?)nr8O#*Dm,]bk7&Aq.41,G)P %WFrE!UjVf_q]j_8hG4!XOmk`5m95:.P%8/M)0t3bUa2?G8`hijs-0=o>3oUi`U"BGHI/4LP><.f+CL_e@S7ed]pX6-e4@(Q4Dkdk %>7gW"\E2B<]VbQUk%NP7q8cl)mQ&Lb9nqUG%>Y7_b-1kE2?@>*51,H>Nb-le:-YVrbk5c %V66;.o.ASU[+jUo.S8Ob@?4#9YM[N=!XXP7?'rW72e-Q1:W\LR^.FPrUJ$,ahib1Wh]i.@@Fi$e-.gU'10JH'N_l!hd`M.-mkYGj %KWPAJk=iL`7[QPYl1DOE7jKt/Y3"EE_#PKt99!6Z/t>@I!>4;iU`sq[mL.25kO9][K0f^P9<3oMA$55N' %CGGgu3"L9'E1*$_OR7AAQnl#$H;J_c)f.DS&[8]^$/$`rl1.b7TTT\XUdg,#W!E/Tm8Y5O2>1Q87+3"0m_CI]K/l]e#je %.lc=eSU$Hc0%:ALZC4!2/?AI$naOhk?*IeW1X]6MeJDY2B,uGE("[J0V0!Z7Wd@&$#/lB(ImWo^0_]?RWNFk:kWiDae6C4p#fKX[ %jq`3ME&hadZH%sV](GSTJhBe#n!>u^GJtu[r.cZAC,'jS"/B(!ICDku2dY++\t?A7b[Kd!\%qqn2'p_bUIESVCB!#%?duYkYD9:Z %/=M!9p3mc&Z$LQ"q"1oNNU53CimZ5ZC1L44MbcQ1?hrM=>5!Er+d2MnKRZBYR$1bl;'B:r]L70AEnr<);cm`/7o\[jfe\G?3JL)n %,uHRR"3(nG1U]9!LbXW4\m]`*\-`l?MM1-B>l>D4-2?ca!LUt(d)7a'B70KVEp$@-F'g>@*2ZT,=t %oF+I529F:M&*_Xo/OET=W3@d4\/sf=m`e4&G\PbH9=9\ceKTm %2B`dCWr5V$<0Cadedc6Yk+urR;O,8PiW8J*8b^,d[WFa)B)]jB?3:bXBpU]IrKM,QN!@5P`?g-bGr+\T;@eC7Erls;(EPta&e!&3 %!(6F_E:"Q>>m^K5SDL`gnn.$hEF)%_4h$/Hh5;H=O&l]"X'>Jjd#@dlT?;IJ1pmcct/Bb(Cg[XtK18l`]'dgUO_Xg\c3ig?d$9U.?q0$2&1?rB,qRnDJ:sV4%8`%XL#GI4Yu'bPYd>\5T.K %]i-Kk=(dt3HQQ@\d)&sdKpMQTW3QGR`ksV)ijk(Pa-=5?N$\aj2M]m/h8l(Y6$dp[,RWuZaOfXA@rP);Rg'kgH8HtLS>0<\I"'Dh %/a#&M#oY(<#!Dd1#o]U&Amo\W_C%XecHgaR[4G(nk"="YalrG2^dE$Nc3+SSQNJ'mHjL]:q&jW(BTPV*ls'$,BTW!,.d)[MHlbf( %ZViVsXUpbj@B7b->3#*ORLb"iC2(HN:!b$Q1\@8`+G.TVqRVN8Pa!MPpG,+Z\m]Ac"a_^>XfOuR0AV+Q3gQXnSY#pT*#O/aYJV>` %fK.\^ifgV4`YtKqhctVsOC5$uO`^D_F``OX)cYC+Oj/uMlo:#\ZriD7(=tV,ZEdBOjpk5tPPQT*c*<'&Ce^n:>$4@:%!UT4*HZm' %4d^K;3SSB]a2^9dBeh!/+u!d%_q;&Vq16'hS%LPZTY$;PYX`[rMZ3])p^=b@j&%(LEcKq-DJlJLEqhhHB5VGF>Ui&+r-9(N%<1fB %<)6TII_gI<>"sI+s)0fI)n`pl]#54;VjaGP$nq7aG'k#025^U[8N?/YG:9b<\LqXd4!S^foD\#Qp.q!]3 %q^ju#l[Y.:qA3KKl"*e@$cU^H3n;c4;CbeVI/+'UAjI<"s?WJsZqcR>D''ED>l)%9p^/Z2!pR?j'MF6JS$QIE(U?B_tN %b_@6dYVZD%OYkmJ=3Kj1e4k?LjOedSQ`."aCan?H2V[5K,.EH=-g@Q+k<@6_1?`JCe2%""l_Z>3Au3e9Zl1$_L>D)8>)eS@e(8.% %RaYaV22a7A&,X<0/n:db<_FK*]AD"BJk/Yjh2)#]N3)nIo''f_?d]aC?!At`+C<)J,jfp@lluDFFhI#53rRRmeK%@2&j9H71BhJJ %D=f_2X0MZ,UWI&7Huufb1aWBFg!(iW)+#L=\3_V9/e>Y-c?:m+_T&6-\/>>g5^qT%$Jh8u%&%?ppF<5u&N!_uKfa4C-\T@.p$<&Q0e<9tKi$\N!E:MQ %67AX?^/rWC2X[UF@%oL"\&\,?g90?3f/fqYMesRk,Y\PuO^+ufRe'1KEg!UO.YYeOYQ/6'r9;>1),ad>;U_d?4!DpAU$<`MW3PWF %%+T)UrDYs&b0=g<6bZQ(k^W65qRAm<,u6u^V=o&98",TmDDgGda\u(^V((:q1*?p"0hZ@j.KFEs++@3r9"aLjjkJTq4=AZJdcGNt %1MC=&&e%]:lAQJ&S.s/2'RD5XkG8#N8PQhZPS@@=*o&tulJJ=B&hWk(HV-mAn`3;"rB2T/+&?(Rp2MC.g!6]NU"_7u(^@nY3ejN) %l=3MOU)9?9ai404J<$&9Wc?=M5&BEr6n,ZI.`%oplVP8_mU*iNEHG]0J,f0$)ZQ;$"9l/s$F#L^J^5j2$>GBZ52eMjRdt&/FCM$YDNmeZ==YTs1DVb\@i='KIR3-Jg^06j %DNG3cL^M@*nPuDjmJGe`J?/.!oWG't+Y>2!d1B?sa.Qe#r7VaY^[_Kqq#-R27UBr.QXr$jFH"bM30kWO(`bp=sbK'+IPZXa*%1_",Y9fD-e %eF"qM9<%(moP%ikO:jqtKLOfDP,+Kgat9I?7%,a[60^=s[nF%OSF7II3W51EU_u4'_%7BrU`%rtJIiU2U`&U7=X'E9a/^UEbooC3 %"['KWN`RN7\-hPgq=1IQq5"(R=hRA+T=]cZ'%G$e@DK%/1&#GY6.W3er3V_d.A>05]P/l@l!#3P)5aOudsl1B_eKO/2[=jrC`(Hb %9AHb$XG&1S_VFBe_ckuK@TTK3jAmoB.&Ose3-9[brNl8NI=rBj_pK6DaC*/F%[f%!=F=6NTRs$##LZ`S>4MG)anfXAa'S*7p9sr\ %,N^Q.5>oK4)r"ilbQn`f"j-Urh6s3V0>4clbZi/s+>n*@mVE8ooafn4I+]8CBoQBM(5r-W][Wa`$VAY&ARSf)XFGi6q2_gRf`OI_ %JbM#:6pIOH3]q6c*42N^/5\F_LoKLMfG5iRe!0mkjPhC`=m'raK=/25s,uGP,T$Z4YC4+HS^GXmT?Xkl/PhLg1V];(*F1,SP* %^6;hP7=O;*,421WrMHBQ/<>?5YIJau,5'AdRb#/BZ2tMH5m9n9P#[JU>A*Veh=enRCcUI$jN="!Yl#WeaOP`k0QLaHX]C4[65d>^ %hNd6Mo:!;OfQA&*"f&*j9^M-jN<*C(9bQ4';/9;^M5B8Yq %_LHQ/QGG[j-f%/`RDc=uA)9ToIrrb+Uc,"g>(=mrluQ7*8+GsRBroPo+CAq8Q'9-AT:d`V;OB.1jb`H4&VKHF54Tg2FK>NcOVF$K %U_P*HWq-Sld_?k;&8o0ZG4GtXK!K>h(/,'j)O,r279!T#Ld>0gO:'O[r'mYj#H?oLM@;dRG`YN/U$6]qVI_&#g[EAX<2@6p+S),% %8e@l!e6F&3(VM"%;U"`3UhM=/e]Dm(MDS$RLqMoM8CLNVKuV.qeb5F*4;I+VCAT^V1<"Dj<`"GlR`2nEP&Cd()#5-q78(guT;T9e %PpqZ>*ZdagRH".ADY$gQOTH":^@P;LOeS[-EL`qYPF?Y/4S[Um3`!`7k[nhRBf'4Xo2HutU@+$4S>YAu8Yg(?=[e3r&!k6u'ks+/ %&:)T#O[KO[a#MCDO[KPVPJ(O"7I#C"R\q?d'Qj$Haco9,J0*KThq'XD55?%;Sr2d3[*;Oo4qdF']\AXRAkTF>Sn`/3.[FCqC4'Yt %5VM.<<:tF+144=ppm3Vood*BY44m:e5IHa#9&mg,@GVpcc0GaX6s!^P7L<=L=bdY%G^Z\p6V@>am:'FpF7ALFQ.KYTF$I<$YP+'] %k"s.3^<&mMR/HV(Lq2+!cE@3@OK[dXm)&s@&,BrM@2AqL,+j(##^^lM["j#dLN$TO8:/FE;%MO\JZO13N-a1tT7RQr/8puG5MEu+0M<.+87">LTU++\FP"R)&+J3J`Y&&0WC](GpD!_Wkc32gip5r?:$)pmd; %kc#GCg];h`MHL5CdduqT'6jTT>WmDk;Y05&oC('/?CtSkSpufm:,R5gT]2/""Z='l!*(tk="2Sa-pPO%DH[hIlnnrb5N8eMV3jlIf>$U<%K1lG\ofoT5m\aAP*:Lh/m^9j=.(O[3Du7(5t[6-A1h* %M\=eMUH"9&Tf;Q%(b4YZ.atH&LflGc>j7([pl.tdXC*2P@'9VHZ\!m5JZ_0_Z\!a1EFdh9d.V1n1YOac=,,/oGJ!B)OO1C;h*pcK %bbq:=fH(&pXqO[ZGn5QqpG!8&>h!hqIH/\R-DL-NWkJ/?E>?^%MT+$aPh!MrX?rhTH/L04Mp/C4[#Tj+P%9RhJU]4MksFDOUtP,7 %GI[rmU;!"&'e80]!Nq"lQrPiJs.NMgB*Mf#dU`p6FA8IDH9>""3Xq`Y_CKlXQ>_iHi@bV\O:iM'-9felU5]@'rC70OK %Od_(&($eC)7bZ;Hd`j-,)F67K!XoK^6kY[bfMEnKE3`B-A#!"/Mm]k!a`:!*?JIumqK:LVPF? %XDl)]l>q=U?m%sETJ?1%%h-BnL1Va:g$]mpVILB*+QgQ*5KLbJK^7g@#8A_B_!q,L=MJO&^d*94k>$H1nU#'Hi$dbO=_d6Jls7,8 %er':hd;*4SWnlAhh:D=Zbbn3m_Lu4pnYKIdV&[Y&e0r.q5@HIX"HeC&+^]`36n+R.C3?e_VZ"C(PCNQ778o,9&])oF;J4mck,B2d %>(T;mf(*Qj-&WI3/TeuJ\$_Tm>$@X$DtHFOH37)E.p9gJKg0n#n^.fG3FDE3UT)5J+7i?JC9C=gkQs`g.SsnJQDTs+/'8eoiRmo_ %4''qf.Gh%&"MJ^oSDf\nV/d8uTdKmu[@!qDoi:XGAkSQ4l`0UWR0mUJHnmI9mCCJ".\Or_Mqui %CV.#@O&C67->8lPW`L>l@=kqe"n.f9KF-A0(>eBK %BP[EHgR>9>/V,*DMAlKWg=0#uT7YMjBU`1W82p,CX01?J-ZbUohNa+]!4S@DF5dN"PSVJ*@0pJ6H1D%oa3>do*qU8/S+?_=:Z:FI %\2sc"LO:t7FF&T.p5lK?&0ZgqY!(jH3<[W9s6ZN$QK"r*7,mf:[>0,eLOe4m(ZILj\$+Y9Xt74hEOCoHjI^FDt[fhM6u%oUqAnH5'HP^Lkb(Bb_ql2cTe4V:+ll^ %Qo6qk;:"/gl1rn(AaMiOYH?;$T?LG(%"_*5BBq6]5D%&L,-i];UQOcsjh8D&5P^:RLM]1Ot^ %1_eZI>TW?B3Mqa3l.;?'o3u;n#%/3fIh0jBjh<8/fl&?PgBQO3eZU/JCtmZnrMfdNMXk!M;!KMI>e211q1EgJiX88fi*WZ^5kr;U %jOV]Kpf)qB]2`\rnEan#kET.]qc(Vl!lRH6^dDfh)i9Ta#C&IY&`UVIn=Y3H__Y9g>fUgX<,8$bFX:96&gTSiC!D)T1VF)pj-9@6 %DF3X4OTF$\4@tDGG@]jJ5=;MQ5[A>T]uhC^>\\Hp]q(&3ErotAQbl#=-Ii)j@)4CQCXM;)B1tY$`TqHp %;pnQ]XY'[uQGLGm)*c/2U<5.;2mms%n[mQ(19qXOYf2j;;G4I`8bK'2S%H6e8sO8^U;T5O_Ls(_*A3\1(@!XAZ1u=E)06a'4k4LT %jneel^6^[GhUmZUZ;QTJ;#JdBrZA,Zp\#1'dD!Ef;dP/N(QtL$cR]#0m665pN@R6\\p'6p)S;1BmZn* %LO1dgC.@d@:4_W69L;CoBupE$&O^6B1k+$B,:d:7$'jJs"EgL)l(aO=fm %1`MsNpBj'<(9$/]]+*&B"93hl+k`(WK+?<+U7g#(PE.>d3qSTkdJ)iqPWHFpZ-N)[Abr_S;K!r/36T<%iBubWd2nEh]N=U?b]E(9 %laUf)8SRkG:Wn`X*#kNr%nO5:+K1Og3-?d:3o-L@QrD$lWRLLRq_^;lFUKX@*\$%d-, %9/6mej>(%AAV]2Ag$,"PQ`K%r%PJX?jk2/Y+\ks//m#lCh_2VfQ`K&Me;^f,9a$80j2+&m:&X/5d+G9@P7>d-<4/!/uq^2>[snC!+SQ5OclLE"6Y# %:T$bq]mEK1o0!Y'>EY0$hhj?pcZ3;.N^s<==iQk[Uur_23prc,Grm,X1^+$JBe%4ml\,Dk!tW$RXiD$TB3oTMY2kbXj:0ZR7!E4] %&$1PeEBrhiHE$2i8YjkKCql%"Q,NVirH3N+o.$L %L\)4t:rJ\fHE"Wmi8VqB^Zkk\8)K"-M77lQip_ScT/(8C0LL>`C)l1(]:gW,o:t?759pDE %l7Yt*Tu%7Y=WrU[.5:`a$h'CJhQmJTJXJA&3b+j40_:`BAlhM1Ci5EZQNDf+nX;,Z3P(EB".@0(9OEWG[WXXl^',gR_le-$%Brq6jDo,";BjEKJJj<2SnsU9Z]SL0WLcFSG7eE"K/b^%j9(3A]DV93BWaiM.Dq!nt:[4=X3s[?O]*8Xs#jA&I\#WX,o/-meJ? %8V`C*h_u+&R7MoCpJi %8L8qCP9k"Y__n>a-sRI6Z5`NhXO-B3OPL+fOIK8o.2>-Ze1+E<)i#%:BgPB&^%DiB](,.>f[>6)%!0X9 %3C0GpbV@l6FI/Go@?0"nL\"h0_jhlA\5+N((0bI>A%'RsH_5Wo51cm`H`qPYRO9f\m.kSN^^RE-G"obaNS50V-fm3JRMNG:""=5$ %igbBRCXDr)!#+1,ZUPLS[;2kg)RG#A2et#Scs*"t?gQoJ[$3ba=_$KQWJ/#.#!fKk[``Bq$/UCsB"OSt[i?H`=-Ss@7:i,lJY4QG %;]08XHj%hDO5FMj@jFYVc"_CDalt*7LNYmXl]fl59/%iJHuo*dP[c59/Ti_F5O2>1Q87*8^c/Mk:$JIG2@nQ17qq5)]cBIc`;/F. %f*%3Q6JLDQaNMhjZ3dG7SUN'WFf"Lu(!^WrK:\'":KbfCkG72.UnZ@V]05V+N1TW9)+#:H*M`$M;hr^(Cr`J'bjO)QhC7WqXJo,V %QA*RFKJoK%%]qEA+gdNP9Jnu6&$+s@gTc6DS07Y8Tab[p;l;US6YHR*j0T/Z2M('__\,9T0S3>HW7$FI#,HC:45!C8D86E\ %\ocj$:gA,70n#]2h1GG't]Dc[q(7]-cjolS/a?!VHWP?_q2DBOT-#b_]0,3%EU5FmElZu.J_=$<[ZdCL-8'mS*:s&#p#D$XuD %=uSS^N.ohG2e-HjcoPeP_kD3gUa+S)=ta'',moWg&f>k&Nb&FlP_.ORIF5XrIPQ.uNt %,"Dp@Ho#YY,2"*(@;Q\Rd(0DP0dMJ"hII[6njU)lREcH]ie)^VBtm`8S)_2!mg*+g\cb5ARFYZ[ii8FbXGImJkQmkNJ'&4/=`9Kj %BEQ\oNd55d$OWHiWnq"1nO/C*/R#`=(sk(HtJ %J2fAaK`!JZT_B<)&/=np`D<>4,Dg<-2?4jH*Nu=UHHk6X%Wgi^h9"ZR(4IK`M&M_!0#(%M^N?gTTn[?UDF1ll[D#;0j5Gig7;XVc %;sRjV>>o:=(Xg(J=pRjW?!L=h0T)q/Oi?Qjuk<\t#AJ&Nps2#qePrcMY:.n+MM&=LF@?)([)3psL;mN,XGFakEUJK8rq!d_% %i?qV:q'ZrW*%T2I[#@_i.[4%D&0.8]Sa!"W:/b-!mlg\J=AkQu.'$qo)j7'J>1. %>5#Jr>*j\E8%#,HIKP#$pi80==,c.17CALD]7CFWWW$BG"TZ$Y?7qJ&d#Php.[U`9)-R\@"Eimsm3j!d8eWEPQij %"dPhH.2LtXP$%3"'k$2SOB?Ic$:eb=bX.->ILWDr`s4TcPal+elC\/Zke10@S?Adl@__\2cKI[q,)1,H]LggQk%CI&H5]4#.O!!VBC*rF#7_2:JDa-:DI2"ES*'T!5PUV?VoO %D/FViVID0JpI"$[RHjRE/s3+;JP$GI%4*cPIb-W>aAeNt7An\Joth]:lB0*-0esJ+MMqN@MRdPe$ce1!&9>XPLEJBO!4:,&:a/h( %n(U0-%4b84r$kcV`E2qpbYbfaWkQG7UM+CXkY^#.=>='s4''qne:kH4]fTT3WG!:s,cCL_9ta`f7ePoNkrPNuZS*(J2jNd0ZsCG; %/]\L*HaD5I09s[O5&W89,XqXqaVI`.9P'[[gXD'!.W/!l_Kc$>UMeV_enN`0QQ'SkETn]Z?1r`q3:427.fHk>c]%:ds"TCTjf=fZ %m0&W@>@2>3V"\#Q85)jn).a_,m',-k;OQks[QIH!UTWCRY&;IIfIiB(rbO[(Z!EqKl,= %5+]--mGgh?E8)O&nSb':si*/*1Y %/$8=^n6g+a0dJ2,XtPR=^PT:LIYpsZRDriT1!A-3rg^q!s)o-Z*j=0:>,b'X:9T:-jb24G+DmE)7'F(j9][[#!tk[haTPI5Y*DUm %d?%8\gJ>F?h=BW."5QC!qtN`_]8pij*4dDj@pAQCrXMIPIqp)ooZ:-0i!m6*3SV/pBMMKA1H^K#]sfp=IXT>qGMljk7fO<47\Uj8 %FC]N2V$qZH`c=iQ\k6KXVg:]FGrTTs,Z"$c>&s4ednDU?AT@>#c^6kD*HiE;__.DOA% %#J"gC3\?'-Kq%8@P@^,tL'gq8c"jR!Q %-:uOM%*QC3-ms6P`r$<#<1,(X>#P4]@bLnUj5rSWYI%'oR.ED<;W9FIP>uAfXb#3/YeeH3q&PGT$t$N#%U3%*=tCNlhH<9)RAn!3 %fNo?,V[gHD!opMgcToKmNo%IFR5ZpJ(S.DPF,e+s(.%%T,b3"&0D_*)BDB;%jP4C*;_9FIm/ %38+I](Hu5L!CqL@I\DPI"WZpG47MmH\q$P=GfGU^R=u\_(XP.N\7W %i03P#1=!^H9!E,5>n>@#kK%@?]LR>@r5p^VKq'$[Td1#^8PK]-.j_?n4c[&uY/s#-70g#++XIMaKrCHX)c!]#q*@tMG:j#)aNA-,W'L]]qYTTl*61b>]$g=!WT7$pN*#5I`p0i?al2m^F"OS$e %0&T]ib.HRGlfpO]K:Y\aZ*(6.4a8_.YToNYWe[,=au%Z?K8PoIpu$>J5-B!:fWBqdQ#'m3'Q-)'.0]J3/aPK7Sm"44!W@>ODEX@W %%dqrDFmB>XMdMOrXf#29Y("%tDnhl.9#+"`^YT%Z;d!l^/[K@]rHbhg4kLotpZiPQ^&<8aDEW5N#_"qs]2CJC.,%)AD&XgJ9]qEk %22]aPV.^N.g+Qs2Ln]ECiUemEe**?.*-5*'=WY"@&VYlQfGd6nD'FPE;+/eY13uO.)atHX,1miIC_TaRM9pIO2N!7`^AN;aDEX%c %;=)n%Q"dLaE+!M[[&@EtbQ93dldkWEEd(Qboj7QgudOF/f>P[tD;FZ03!n@?mGnj<%VJ4]s6q5Y^F)QV@YIP_-!LDGY,0a?Y %"s#.R<<*cJA^[>cF6[$Z0rU:fkq+`AIp4^l"cYD1/kR2)^5Ds6:U+_1kQQW.go9rU;(C;:lC!TS< %;/ju*[d5lSHEYTEf6.)mfK7Ee`f]ZS?\'iHJ.0FU[NpfQc2e>11oZV='"@pLbrQfD2f]8Z>8O]N4jPBGKY+N^Kk+?4DM?b3FMQ<2cciJ[NYuTp@oo6R"q! %\GJ*(V4r0Z6u!I";Lt9Df.,gD(p-,&.^6d7^2$9Ai]ekC8un&edU:#lON`?'P)u;1< %ZjQDdE)ObfMS10_#OdQ*\hbY]<%=Ok`G--S;X%Iio.OR\$L.7=-imGNB^q.E"6FiCPk_FQs*7'@jlC,GRAHsRf&lV0>H81?qVc#q %acqCY`@jH6$q!IFB!O[qfYd28Kp$oRU.''%S*sJs3RLB#5_I#0Z_/h5Kh!C/&$IZtK`^gTK&(=9(6'Zer\W$;SlY#Y1h;#dh_.r_ %&ib]fe(ZQ>MLpJ*k%H-)"S$__)mI0jR:Yi`k$[N8JAa#!Dem.')%K$PR9N+L/t:I %V/QsTmAK:;qs*Y+p@$8LNrK$b,WbeH01XTmA6(YA$->V2#bl3Ef@m!O4@m!j<\onf*a*?_f'r_-PDDp++5fbIJgO`.X_=dFU*=!eR%0-'T-Wp;DSehH4fY\j/4p^0Emi-eS!34T4[4 %qk(LkE>qEm(nj%9K;@6UW3pN!68Pbt/[67gs7A9/:_5D7o=o@2JcK.7tlBO\FmN%iQCla@beSaZ"-dt[( %.kuG+=Bah1(tj0e]Gj:`rVW#H[D%!?(Wo<*>9!OGlD'Y/4l"+bDW/diNZ/)_F)=b8blhV1$CF;$@#g %Xe=s#fWFFAoGFG`5UsKOX)8Z!Ba)Bq#@$%-oTV87j.8pV(<#7t!R5aV,/IM'4U]Y'4J#[rW%Q0?3_u%Y$BMa;ai37lGW`;n5#)iDQtqF-)u?qe'3Ii( %%%(hsmLUJY_nbIOO1C!$(-rLmB3%MuaV5f7_`;?Q#'5cq8jPa*PDcm#._P/32Lb<]Mc8t_;Gn%U9PDYX@o+&hlG0&UACqcpp*,-6 %4L7(N-&E/ln]^8p-gW/bkS5uAWen`Q)L@g6j@FlI(-e(e/#XfC(EKpTV`8YJLccnD[96s-9q:WiTlTmGOYj9ESh%WC4Pf\*0d*9I %kZQZkYe*Sl/UnWZY\@]>2](11GCVHS6T?:SGi4;I*g&:bP:E7@>8sR*I@6M0kJ[W-X]`bhLeKrKfKiS'MBEtd^^f`(71dDtBkg4[ %,XFPa[EW*Z&DCKl1YAR_5l,'tUB@H[6L8[6cg[n/HXM>:Wk2 %4^(iIqruA,Ej71)r_1WG]ls#E>)slY>=Ptn@>GGWjNmooeG(/gZ+%/r$$bYT@gEX_6468Bli81RiohUGBr0#7&o<5kg29+#`Gp,m %l%hA)5b5M7dqq<5D.SgS3Vpba+nS`S?lj_7AuO]c]=4UYTD&'4f(.nq"J5>tFPbVB(KkU'/HN9W&?eOd`RNe"=5>gl.-SWJq`Vt[ %!H1Bti%9G90cF.+37Q4BoBj892>LR4QV>4f@L+Ba5bHDGP/@+ %1hNJOY60M?6P;,S%kj0d1bIN/q84t'rPb[<5HP;sE8Glqlo=UHg`'qso%@U,b^,SXM\@msT)E?!b9ErH;qp>>6oEk3U71+:#eNL5 %\!#"IVRt>+*NqW#HMZ_>VZ.?[(ETokD\)-o6G;In?_K/J;c4Gc4I(KNAfL6@-!etLjN]&E%WBe4`;M)JIDjEMb>2IUD3]2t]t)1t %Td51`-cu@0\r^a>H9CfrI^=pGbMCWQiZChj-.D+3Yj#-BI9S3NWR?6Q7&SL,jNC[ZVlc0tFI'[Ah.ph%Hqd+JXa3g]X[.#`h<@Ec %B<1Ql[_MY0'YRZl2W24@XiKqdBo99"rTD#* %_kEcPBh)TlW#nf\LaTEWa)!E(o8\9sNkKt&m!)7]<;Pur;-f6R*h^KRR6uHR:1.5niAR+8p@&=/YXTPVls1%UL:tWVmI;l_*p1q> %jGs>qa4fC<::BkT77#i*0IfA&XqnrVTY]@JZ;(s3>*jHXrO;'n1J/Yekf`o:/kV%m %qpe!@q;Wdp!KllY-kUR:*)7$i,=^#\lR(/,N>OrO %+\iD7cq-!Icp`ndP@TEVRV3PJBU2kg7lC:2dNPF@u;ZF-!#oKs!U`H7OJD$_De'o[ZRqpVS0,f"n9h. %2mn6#Q*0H9oL)S:FPn2s@[N$6qE##o*UJl4dT]L3X3)RBRW)i?d[OEZ4@p$)6je_;DE$J&Rb_l<1P(8W@[u\br(Sciq[;.^Tpo6L %\d4_Sno&9:Q!_V6Q@DhK;(>Km%c'W"0)Vf:IoFPONeX+Tno&8Oc]s#`/cSBoIH:u( %X7[PY;7Is\]Q6Y1B=7XV:T/j[199No.l4f3@;!"G-aiFH"Dq2?I+D\reaf?^d]:+OZWd?l>5q.>@`m3,n,V]rmM:q>:fEJQN*bH,`A)@nt4FKF5j^ho_D,3(R^L1g2J;/ %rW528_:+]PqcT(Uk\/WtPFMq48&q<^Bq6K:Q!49WlWfQE^A4%S*t6cI!Z(mlS.p6@lDpLeR$.$nJbRA[ %"e(UsTA`"#6EW0n`=is/'b`+>cl(Pn`BQSF4@-5dY*`=DSo+-E%`I>u*/DE(Qn\0ApLZ+!HJfg'!<)<$l+q:XTYHDSOl5lY3_$jR %L#Va7*CPHtH8Nn^*N)uojN$MYG@_KPDpLq?j@IYT*ecIAdYe7+LK;SHd,0GdDgXN-.3/3]pY0:!0)V+3?G@J-[^G8D>BIjfN&qIi %>$>/o<8d5A:aOc^)Rc_sLnluBrXY+_G*]0TAKYoNri_OXPZ%4hoFA!rO0n_:d"@P'B1I$,:>`$^fR53bSk9JaQf]3=!=s:KbCW5< %i!k&CGSfYq::I";[JBkR![[YIWdm@Ug?U*0MW0om&/G%]D(sC&)9%-HE^\@GT^$T$n;PmZ2Vps8,[XUd>:&3,m%]cEm'i5IY9/%$ %crf\9#rsok%="H9-^$:ORRT0mkqheRL76;9=(]tmrlRP$O=\9gH,Qa(XIFt"SN/K,JR>hAIl*")Xo<>Z92r@G@`d-];Jb_Yo/i95 %pfNTZ%6gq)M6"6kD"[a72n!mqpl$L?T'#)=U[0(u-%V1C's,7rW5tceL/"J.8\Zpgt#DQ"0QO">k1u %XW5#--E*>"DWRhe#CMR9M*UV@5h^?fL+1XM_5EE[<*Lt0R,jX+(Z,bGd^t&N`SfPk>48q<68^k73P"R$U,nO"?SK:6Is-N@^GK:6IqWjc:#a@RqYa-OXOEPGAaN %@tNCnUh^>Kbj-#\,H._fBAli/YmO^O5V_Xt`XT.EPfhs%9Sc)"]ZWe%\o]s)X5Z&Th$nhE<&Em^.4T[0H#eIF*))(4Y*W+`4T= %'Z&LI7Vf0)gIg`T^P*H^BiRm/4:Lk#:XN0D#)NDsiVRSM/Tad=`>Qc<0]OkQ@<.#H5GK'Hf/74D&fdb,4TYfY(EE/Z\8gqDdrVV\@nn&J?IImp8:(Z@4l;:-[cf.+%I;k$_r0g8JIei2=;sPhbg6\(>rG>, %Xe=%#+Qt%'$rmYj#_GIQKrlIB;X$otBCER3&paRR>r* %-kNgcAkOn.Ob!KH;p,lg,U2=ZTRYj#;$]qVZjB+8 %V_pCFLdLUVFFs2Oj.E]@N+aem]>FomW7iY`k57"9QUQ)CpO,quUM(H*dlm),Vl+2`;()I;Yp+@PK %XgN>T,)r_4.OFVi[=($6g&a0saOj\odIFkOPd.Vueq12`1q*,X7eRK#$3?d(-t@%t\IJ"e7i>Osd/+Epemd5;I_S8g>Dl>ai9fKa %XlVtp87<1MQr"'m"4%JO%Z3RQH8Yq]+:s5,/i=,\5sQ+cFKE>)f!:t\^^CrY@]bVVOQ>UNViBoWoA2]?RUq#W@=84SA!+X^rr)gNG$#^7-]l@b.BIB+D(,P; %L@kl8.>:eN8kJDNAj9\sGX?_=94kfu:W7+g$j(4N2eVX_B6Fj'-;6"E[:+IbcTYAX?a[Y2^tS"a$?a-'Qdr-Z<,;k\HEo7Koqd+[ %l.*<2_`j?g.l`G;fmDgpkS*XC^IPIC2&4U"M.n$ELW_0Y2)jAS8d50Z!*[>[_l$ns`^j6+HJ/2G^FG9=6$KUTnrq^eos1?rMnse^ %%pc5\O%;;Q]Z'#n8Cf7Ed%_q*\,,]a7Q]@ma.&t]qCB[X2q&%s$I["I[0fL)^gt,\X[5o8P0C(/!hgG"!f&/ha\//[Nt1QjK6f)A %<`)(gA*^0gIq"9-VX3cb"$aO2!^MkA%_]h(4U62JU\!@,'[;7"?_d2K)&(d;9-jXX49FslpgF6G.k^92]IO*+.k^:]F-8%7miAVo %32D!gmiAKq$\O7%Gjk(.Pu;sF<(d-U7%q;4#'[[MnF91e2&\4#Yo1*GsA\10#IFNJ!YTrk.UB4IM1bUdq0:22pt;99mkmXc640maA[.b'5^?N@ic?lHr(NL)72l]lHZb5!.=G`kd6&!f'M\"f=I:-6*0O5p66;LB'\,0C*Id[ZXFM6#_,ZHG7RK9r/$boO]JN\V;/j65!qKCFeN:KM..g %RRp^h!mf<"P!QgD,lL4 %5NFZsH`/t^bp8kIoWEY71f8sJW"QZ]gE*F4m(hppYG\)i5gH[KFlb4B>l25kRqcR\[Z/kZ>@i7%BA?QdQg&AZiI5Zj'nLGo.k0B(ad/<+);tk&u4QlRCkA>GqI338daHHB-C9-k@c@_ftIR6&"K5ST"I6N&CF?_BM(\6]`B+IP]H`\m1\('.2pj-E*!d=Lo %:Ai/+,;['\fM:@j8;fWJ'b^h1W\SX`#fN-]?!QTr1em<[$!]\t`K:B@*\Yrr!_6m+=4dO"=82OHA"s58Fl8 %c(<&l#$T9eDSu)N#-AMuh58N2#LFr(r8Zgf28j.TY(@L6)s:/a\phsrTq"74@.n^)pD[!^rQ3Km>H&%=qVc#qSk?C5C[oTo@Mjf. %Q]Ir>Ge0YCosrn[j*p)V%njR1$EFT\`NltoiGGRh$p**8g4?>9tY4q;mmn!b/nXhhRR)m6;ohT4J_!Ih0Om#U\" %"o,V0i3X<$i!F*eLt3isJ=45?WN/.f^X0Y]Dma\H9!V-$F0]1pmF$EqrL$i7nh,RlY_="jQE;-FIm=m?"m_Qta=& %/5Z>0A"D?t:$mHE;XE0K8NoE.ugEBier*A4fSt*!XqYn'WFarbqo1?.eWJ %bXWqp"i,!@_$fTZ73mE0VuCoA0":n]PJrOJ:^;.h=l@@2F^R_;2?gl(E33uUL'`SNi.;=R>"m/]NrRtGW0&+c^lHfj'913/%.'AH %e^,O&lM4Lq6ljo7]5N:@fq*a8gRTr2 %Q^nONS7]fQHNnY4rX57Ic^R(K\89J]Q_M<-HNnX=3F_6)KaXiT#]SIg;\"JB#]SH9&2)]nYS6`0FBq,r^lBZJ*8.#D3/jhL0dAd0JK=^##TDBi%dZH9=4kS(F^PI)0N$c64TdcD1q7?t;[\bI %,/@c:RT^?1j9jAcP2q[bqL5l8q.`VBRJ3a"WN?oHWJ.A\Y%aFL9eG.G(QZc51psD[U0([/Vl9jf%ahfQh4muXZ_-*u.Mp9Kld,49 %!<&8HpGHL>hACS^Ned*"XS(?d(qXb0puJ9"H^$Rs`/qUT8W4"'`Bq>kghWOuFnl&tY#8p)GuZUkHFqA>:$f@5^"hD_4/]cUK4JsX %q4Y_k.s\8%\$kE+GWi6u&+^4cae':OH^iuG/aG/"#*&81_Y/tachNWl[*n&V#rY+FD)WR(i_3dIk#N&F]%_[]g<(P7F7cTLLH#^< %gV2LQQS5an>Pdl(O,n-0:MrtdM=:(Gl_TN@[_A&X>(29/,4o((Do7M$)fHD^@]B?jq,@(>"0;eKqI]NuG2Kp#I%ti^ %jDE(H)6N;AM.9nC@39(dT&ba5hqX:3I0eu6\jDZpBn]G\mk+2nab+BAT]SH[GFlCHYN6q!H&"G]q)X>7qM-\aD*-@4>.f6+)+M3qSr9$4(n#K^+%_X78/M<'#HBAn7`MaGe-*2inJ6e+HLXH[\8KT(he$HK %?##Uaf,ddXrUL?AGIdL\nXpQS"XjUtq-S4$$I\EB%AAG+n#$jKEBmK'O'QZ_o7,_Q%;USF%H]Ln"*A[;+Vp[jF%0?'iMfGST& %)&&tZQ#nao\];E-X5(HJQ6,\B8Kd`URWNaRtk88`FoNJ#V6?o=]^@lg`3fqormLmcc@oO(E>d0sc.s9'>sRLrQic %Ot,jsglbfY>NmI)jfFft<_<][a5DICMY2bu4R-cGauo)% %CMIK?/^0pFa@WK0&P:$\N,HBT.M)%PQLG*;=Ee6+YnO@(*O!SS?F&C5X>kc"]k;ERi4J2`]=Sok&UTT;g>cTG4jKr]X$CZ^<02@U %8dmn[P8Z!:,JBa+bGD]tjl&(!A7-TB3mf]lW&>J!p8Qi2A(ooh75ZI\<[r?D9W2"NbC0eu7AkAru@(P)]co(R-/-B95kQ;;q.'[Va523I=M4FH2PB2::&+G^<+Gh3<6jM3F'0pli6:$2f_boMfj/''sDZc:EKR %)_WLgT95eu0RT)f%jRe>IJnK?*,N=T;],m8Xr@ltJY/'4\-V^WLqUmSFSiMW]/&,aGjj"kCSa,)IX+78m)3WPU?f+1EB8+<4m]lZ %Y/'mD^Qpd/7BlBRDnc059UPkQ4Pi'MB\mm\Z1PHg\KXu6fU-]I"':ct2cYm'.AqON=fHH=B\bdDg-$Y2%ZqI*8&Wat;D6mud8S0B %,J%4HV""_Th'6Cr&:(2%6Kp+;LWK*;"P-jP*?oHFMUc#(Wp<#0qI0MK([7Dmh)AcRMkmph;`6sa(TAB@n!?JSl[quWO]5E#M4]Of %dTLkC+Yme*J\$c4\q$gN %q^ks1DX_@h^+tS^-Tq)*BC+\/OhLWQbh1Ah*m"Qn;@03VF32#I>f5qPY3(g;#NBJ/q.5l'&38lLOcdFSD\$h0;*UYa3@%bp+huCU %5sEjrArXsir"KlEEsSDC+RL>Tk)^:a4iGkj6:s@BH\cH?drTdqr9YZ1jq,6ZjRuD$=aMdAP']j>=F*q/NMW*_Zl*a/G/>_E^+-/Z %66rZ/jJubJc!'*=?2!t(,YC/ZeS,&`jh\L^Kid[NB@WXB^UFO/WmL[+H=!j]jb?uXl""iS"RZ@E*#bYkjp9h/Xdcn%rshBfWMV^G %N8Vo9]*UfS'3&TcWqdOGH"!4gT"XZ5\r5jt_fml"2igs_JS?=sR=iqcT)qFtomaW[B#R*Z%#:_OHr*khT&ESBP4errp')I>hS\$! %pV%_`Dnbu2bLps/78%qef]aU!QUc@Ucn?C449nO((16mailgr@,rlV.jcNl:6m5laH))7fa.a,PMgH56YTs_C"a$CC`0Wu?=\P+= %9eV6e(ZW/q?djq,j^hDq@E$hAgb^nR0GHQX&`ac,d$j:>*E9uWa]VosW:Gl5@45XR23Rk]X]7@<;*2Zt:Qg.sMnW3`1T-3P3^kpF %!.uYr"dnp2UOQSH'Dru85#7\\d(F3F3e3^g$&q(S9t7`bj8KVbOIKfSVRS1!bW>(S5bk).Hl]rKE"eA/Tb::_>gIt^U`U,0^qgIt5?KLk_>i$1b@-$Vre#Ek0_c_)rAVd-$3U='f%;>:6jW^O %MZ1MAA/"rt:9,!3r^R\/P">?i(&]N%!o\XY653]AEUZ1B]+(-5U4'$4.T`g<"Mt,:kWbG((C'mIR_m8Rs.bHf.oBIQr/Za71Pc9F %i."_u+0UN#oH2A`&dA<1UAlKA+T.:XraRYtEEAHN$n7iA8$1 %SD2BbO`NBU6?#K*'Gu-6Es5=4l6:U8mb8;1l3!E0InbjBi!pM^"UnBsiOHWPRE+-i2ON`LY&b0#F'5E'\EaB-m0^,FR-LJ&T9AS,8`7$3`Rpo/@@^Yaah@r9YKXLg5:.p)IK %6X"BA)I6ArkfPn`78?EK;6bG#g5#I5aHgKlHa4pREL!7iAf9St>Zp%;"='7),q %A3-tB3oPL9hb5CnP:]U[0#%1X?43Y@nt2*9E_(kY`\BqLp\+B7,dbo8$)h7r+GmXh'e.dl+k?t@q&tB]\=?iUK:Qt_'53Mbs3+$D %?mg[a*QZ6_2FUjW;dh[u%!?SY`5*Q2/rBQJG]EV\f>Y&FIJ`gO9^]t[dio1P7J6iC3/?X%1M9.f[D-N'cFE8D7MX?;>8 %>.:85BuN:"Z]^fC=+QZ/7;&MO:40@.#?8J=7jKEFQ-iC7!J#.$ks5EgDqV\Y7fV,1@aLa_`$[Y8$!mMN&teO'-ZiY4,sF=MGA`&( %jD2#1CgNljaZj(_S4OE2Yqlf3Ru(L&QFN(<=R,F'R3+&tKpIg2G.9s0G[!<+=AOed6W>K;3Jg&@&A,/tG9p8'$'Z;!C8=EDei=l:=nk_nH+k`PLZ\%l6`[$p+.@\#!Dd\Bn=dZiV:UQ9:1@\GT6O6bI=@66L\"+Tl$;G$Fr>#,6l,DBo=oKS(7H8gPC4AIpY3/8:kOke>EdlQdUD75KH^7Um4m8HoG %cdN)].p'6Q1B;a06iBD@*nPVo^CA(X<9/&s<#Y+C?LkUSbniCc*8P@AcPaLXbcP6hP/ln1go.thI[GC#BBUqem5a3NS:Q<+hK($4 %4RSjED+7#:\%;rQFL4U0\?>W%k(!0Jj"SG$,+[;WJ;7*e`?()#4>+`bdV8[%j,trEn]?PKDPf-XOn`HGN8UZldV5!1aQ(2Y?K'u8 %-mn9CiHM*>H?qWSZ:Gj2i-2C1)cbnH^UO4U#(D?!b/b3fk]Lo&jDda$R/"Tg*lg(LTb+-E$V/_N#o?@WO"WU>l$,&)SM/$7)aF?%#NJQ) %IN70Ro;e@"r4%NVl'"j]#!_N3bomW_Y%J/'!9B:#a3i&u#*;?,+4iS!60F50ViL"$dn6IN6([$U>a>IN7f[F7m>#i5afg/B!6t`fGc3F!!+Dr4"$LB1%N$kth`31gi$Y_Y]%!4%,uH&H"-\4$\P3W=XlaO;;b&LI5&!STB9nQRG6* %T&emAamm\M8TL'D`ACm%H'1*0R(kp7"\8p]7oYk>Ns&"-5XYcpi;Jfd`?6XL)C$+t+V7M%F0*HE$50'7Ji-`]\6WjY$hR*MIb,Wg %h+ID/\\7FGbXd=t)u[BS_4F9Noi#`\VB?s&)UrX@:,6#L;S23]Z,NY#J^#VH+pBkoR6-G*%/uqt[Ydhq%WoW.<`(h>`+, %5VYNFXB;_P66spJf[S>Nr_UF+$r&dH$6C*A^e<4?N/.J52?fN`XQ)`$be,j8!DlPF>;bJKintkXB %2mqjT;:l\QPYg&7CkUYP0G6VdhF6B-]-Q'R1_7NV;FKg]3Y&!YFe5\8\J=f.AQ$n?LWO+*57:M@N^2F>rN$K,/_,S1BOu@ZJ3_'c %W69-Jdd\TN.8[LG/7lk;(YsW?/>uu:!d+V=ZZJqqF.dEdIMQ1:N^2ENr@D'k3!+4)p9S/LL7e1;I]^L!f-ls!)peL0P?`E/@W:$C %/*kMo#@9ec$'Qr[U9mYl_i!sHhV!I<(?*Q%a=Mi#WB4'VXr]pT``heGH?%P^5h.?5oEs(3f`YTlcYL%40SDAHQ"9(eD8bG+T/emS %W^@A4Z-B"\Wn#V@=77p;ZXeT&0#,k9(p.9j%=c7mc^.5\1\bJ@]N`(*",8'K`Z-AHTl<.ANaV:c)9cM;#Lf8)abbKa$8_+oEN&lo %Ca"sM.(#"sDg\0&-iP)5fRXPiT#6iR"MP88,UYRNr&IO9?-/Yu`8A)/&jJC>SG;4)>hX*53tbP%U"(o%j'\hR)deVh'HkN>6,rd" %[b6BC5:4+r0*e+dXnhQ(SM:.d1kUQ!0]4XF+b_D^G1YXcQutDK\iJ^@8^7U>iAE6f-(-:%.:@gmUeeL2G*Yci,rPMIp()-M#[j@. %0U*-H^_tpp'UcWf^%YA1q3EeN:d1d(o%DFg#ZPP!)A7b;LIE2,;Ql,#rTrb6@Xo2EP'el^5TjT/,RRN7a0i`Ss(&KV-\`k/N^kY&R[>*?c-tN>-WSi<.G\>qo#dW1g/er.CnctPFjcmQcE(eb:_H3"YSZ`.52t*&ekJO"cC>cQ^opoPFqhpd+@n5rLJ.?Var_a\rd:'5G1PQ9 %KE+u@ZJJhRO%LS[`+ANEF4j5%0(lQ#b8"Cm)6(I&&$'UI5N@GrY@=P'^$`ZViT#Vrqt^GP>LZ\MTr/9joZAkSXR0?n'b\qOG0GgV %@=7K4MMofR[76SApIhp\=@qZQGn7?a1\_R(-pHfD%P,;Xpojorc*A+7SGf)n+8C*lBH7Hgj(%"1TJI?!`^d`)2Mt;F/hA\?7a)>b]RpqEa[N=.%:(DPEnQ$pHf%#i,cq@ugoV>QK1).n %6GJ4_"tBOLS$5CT@94G!c`IL!angsjAroR>+KU`Zc6/6k*9=kjSO"Go+9HP;kTc"V5pDR]*_LL` %)'kT1R$*[W\h8SIO@WhGcP70TK+oorOKBF^'%9%J`1r.12*"aT@rcFe)QHhgeN()PHt&5[f0abN0S^Lp/!,SW%$D!b/M\[)9$.f* %K1).nZ9@[bAru^\-eXQ'r_=.'/c9cXmS;4T&r"MJoW"Y?,$FRM3ujfg\scdMinFuT#feOM_acb1E+Z_1oOOI$O[S#UcK&CSWJ&+7fH1b_ %IRG2?dYXWK`fI(97sK_"21@q65!ml?]s.;cCB9iL()\[IpecH(gW4cM-B67HeLX9/5-fCj"cOO#LQ>9.A<%br;u;\2omd;tD#B)M %Hj%d0Yjit'n<%5BB,a&B`&G.2\l"/S@D98tgP#1^pu\N,NAb#K7n\EiO#1+afXlr!>REto_&N42,8XXq'`OsV4$?cS\^'W!0O+s7 %@E:HE5KhEp6,TPeSkBg+;h(2'5-9l9RE+,l:$p0%KmDN7 %2-c%/LnoJ8FK<(qXZDbLNU1mahXhB'd@Z:0=Oqh(r@HSuN&4e^FqI+[/nO;a+lQ>uCE&l&pZZ@Jl"@h+io4pV[DBmd/9,h,2jX76 %gPDufAnLP148<`\n>Fm@Y+=:3`SNY$Glms5Van!Tmf45>o=O8 %Ca]SF>:;#fXf%bcWC=<.m`R;<8h%:Q0pp*U4ORX<=(/jq!gi$]>JlnBdQ`/ISk*JHc/ %+H9:4s&h$cO5:U]]Tq3&Z"bQ%DAq`(hnJL<\,APH6C/I_N)J?hr!M+S %BXKN0B%JZJWidDb*P>p'lV;IcE/l-/UTjB)M_C.`_KgOg`>:S_4%O/DY;N$-:.nGCGO5fViSr%p?Sl=ps/Z;=DJ*TMDfsTJmf"]B %FELOHrn>nc[?otlqU;mAXN_A.C1;)_JQ'*QZ?Gg8NW0a,[SF.'s4U'Scb9SU*k'Vjn(*l[(XqAW5uhOm=dg?d(\Xl$/lrkXQok`RFsh.,VYiqtBn6#i$Hm'Do]6rT[`YCLo]0d'ZtdDWmm\njn'TTY5/+o@fJ]#%'F^;%BZ*1hnA1Hfs0t<)B>]S#-Zkti,*G[W2/97Z(GD9GjXUndf-p;\`;)&qThi2BTfZ= %s8%#<4#eG.F^0iK`hWFo61pT<6ZdeaeX"Jje&H%/>@$(/hCWSnZhB`mQ/_7kIt(%QWB;kh-Yc%`;'n,kl-a-ro<5s %Tm+q5>$ugdmc=0RPN`"o5EO'@asDdI*bp2h50_eg_J:ne4BGp?M6q%MhA&PRBa'rrpK(p12;;Noj4bXX1lWm*[iK"BaO'g!Sta8rU>i=CD?2)pjlSC4s"4:Y9?aiNfeX6?QA5\9poH;1KVeA1b#PH.WG?"n1_S5*=='5&P<=5\pBEHcNqc*tHC$1kp&`u>7&c+@jSQG,8T;,V>r %foJJ(GiX`NckS'5oM'C"Y"5iI=RoIrE45qHe,&fV^o7r#SQ:_7YkDtmGp.r8Z/Co]]#Z`(\#J4dqJo+7KTC7r^T$p7NK.71D5/Lat^XQ5+S!J#@9YVXZsh[kjQ-&%CHM) %Ml/Y4r`&Id3X>F6F%XKs0Yrg?$SN&fa5Ynr!U6uj(iPpR(-J-G[8tO>nkO6Mahkn`FNc1Jc_pc&XHIet;&`G8(4Ve,$D`_5e]1aQLn?Q51&- %R+A]%D9JR5]oWiBQqg:aH'`%*bj(36a3m1ee'R?drn4Y4O1[0;(?5i$dqSceBoVbWd-7q:-uiA07&8<.UVn1kktpWOd'T>%dmBeu %R42aa3..eA50-A@F8.4Iq!j"PRe2e3iBo,S+,A1%+UF#K-d`mOiQ'3ta)H2*jRBEPpqUZ>jmZQYCl,uh6TmosnBF*GiUGn,H**Dn!4QQ9\L8NPUWNV"RKqhHXe/8Uf& %G^gIg"eE6+TFZ(t2p^:g^1W!ec)EYk5b<&Ss:M`+ad7+1VPDfHj2/M?4!d%u-:A]eK+KI5%E1ss(07TTmClcm/l %_QK'8Z[TKCX#ZqQ\k9p6]c_P%@`;g_.HidCOM]l%g%X(Lqq7RT,3ZKUV$P!J/UIjf?Tt%QRe_U092#)03J/qZ)t0,;1=qdNhOA1X %dRTWb$i7]pm5"O6k?CU@kjA-b_hF*-LPggs^R\CZgW:J7E/4LNC8a>R8!o(WHKR %*\oR:I!=M&23`&,QgK=P)bNiPUHRhM)""#@)".40B5J1LN:n7$nr^lp,^K"gHM4*>8FksX]Y]I8894!Z_`sS]4:iKojS>[=()%XK %jO#@#/C*IVH;(>!?(mq?)O_<\fK[A5eap!6NsV9?JXSeQY+_c%'H`Ftd3iN12etZV0MXUDfu9[^3'#s!l(p[DP&,Q@mj^_hP%XU;*0EqVL#'Jd/Q(0+/n@012mt+LM'npq6;mOf.*jloGeAl'n'E4V,bgHD)JS*)&a!p?)7s(T3_4l,pWZ?#&:'@\d;OD %XnOdCgY$R.Ink%"fh05O0I92hOH^)QY%PMO-TV(OOa6DW&mqS;#,V*1iN:bW?ekqYhO//brI^fVGB!KdhE/&J %%IUjl]QZ7A3hg%+bB"E_YRl9KYi>6_$]4W7JHn@u3J#_-#CS=VGpU=SB0?&W8TTjI4*q4()3,NKHRHq05RK"\-*$^"EV:u[pC:JW %X/q?,HcMJ8)Us*=?A7Y45+L27FP]([o.U+rrPC=D'$>PKQuGUdhK]B^&UEhaB-`j/Ku86bZ$EfFHLG+]+u8U-=tM?#>o<#N(pl>= %k>-(_>%W^B:=6aOO7t:);sClBcS%j8.^!q;96J,f>YpDA,hM^#ZM"oPR1$HoXI[S@r$V]<.a&1Rp3oqP'EVr&%bPs?6I\X-@=rF'Tb,RB?+:"*#MT_j70=cd"1B3]Kj^f6M/irdb#fn_ %/NU3Y/hhE?1V_V'%tt":6Oqal5h*4fF2>:PUbHl*[KH(3,^D+\q^`VNLEO^O]XR_uFE;e$.f6g&]$*^=G]-/C*WjYdl+DI)8Zf1> %DRE1gC--dW]j=Mg^\Y;HF)b:u(aJ?4\`nNQiA%VZPT/s;MMdP(YIPI\/VT3!@"E2Kcn@[pA;q/RmGgqm>tC_O3Kb4^%osYr\tH %5H?$N@]";GB6E.to1nW@:YqbFc_a]/:#6`a0QaE@"PZDi(_VjGZNu>K@b^B_$=0\S,o4S>+GpHZ %VKW\AC6]&qi/H;H8J\F.K(:P2A(r8k>/_PQn@ZY)^$:*HpM*C=`)C/cA7H@G[<8F4*)dafZ.kqd:C.4T.Ie8gVC0cB!OZVQCMe3`6qA&S#`[Mh1K8^$h/3@,ak8U^sT!'aQ#7;NX3bKgFF9]PpZ %k)'LAj0;B?XCG,(n_!NHd=$ouNQ2f";M8aHp,/*N>h(NB4T=\hY.5Q"Y(2cd/7re_IP%In-J&^/I^lcT%h[NtW?$@6Mj`>)YMZCD %H!JWrZhG8q/M(,"k+B[%TF]aRP4`iB"r+Njlc9QY?jHQ](?,McG4S7#FLugJ(]Y:'i4^h[O%=g0HrcB6Bhe6lT0,>EJ."!&'AdgOZJA+Yj\Ep#<@)ni0/e"*60t$&0GO`1ZcbKbsgEOFEHNnYTZA8RKm2=PB='sb(%eWDYU;:CG %I4AAhG,PL)ORk)@A;<4M"2nn^,99LO9AUBkLGii9o/pj9./gN&2K,1KM$2V\@a_kj% %Di]-J[RV+kpBttEV\TK'm:guCemu&P(Vf#Y:e0g12NYV/ZteDpTXcqh.lb'F__dS88%Xk#G%"Tp_R-0f.?oS %qVD/L4Zp$hOIOu"T)75I\a,l[hE82P$HiV.kUP_DS\CaueO^bF7O>&2/Q^g?j0@,&VZTMNX`X+UZ$:D[O0'`u47IX3=TP]jXiG]+ %h8u^)qKiR\DhcVRWX7^jd!LZF'CHs9\'IJEDhDGc,q\=@ia!I">jJNRdd`Cd/6,8#V[n+j>R"*@L=p:7F+9R?TtbLTOC^XH?`f+" %hP=#rG":aL>nrjXMt=2[B+9Xh.=T\/A.Q&-nL3("u@HlE?o!+$G%s(2qgm'4n]M9*("E!m>RZI/,T:3Z-uAE %Y.41IfEtpW1`3'qkPBea3,C_NY);E*oM_laeDg)6?OQ;\'#35L5L+5RKaJmrp!o`O %IloB@m^h$m*ILJA8f'$`n?+W])C>EJ'[gH!,@_VF&S=XIJCYl[5rb+=[?Wj<3^&2Cg-YISnd9\%I=j_M05OXk?-^.5^0>soBfV#^ %m7bf*5K.+u_!HBGB#9sE00a!&q&bBr\u&KKHP]AHbIccMM>l@%2:Gbgq5M>m='i=VDQ9LlT*B]R2ATMC\Sj#_q6R/'Q?TUsau(=B %)g/+=E4!\>Q&X8TiQCPqj-LBr+':*82pc(G^2PBFpY9*Ta"k3B0s_0^V<\I<2]'r+EqB:Wn47.sio(N\Slkhe]BVa`4o\]c,\ndl %^1B"2C_jJM)njP=6)rNgm+poAZI=ru:';m)JQ?Y`Iss8tUVbZGRsK@l;H"6Al'B^SEe%D'&@>8Rh?U,3a?f*n66Q %=mO8Sg.F/.gda4qqNhUTP66*\b`;PeoK:gp@"_;:eQB@g]$,FkH$9JugRX+!=ro55`,i/CR0AI@UmB$o8rRD.n3UiRF=6@:DH;@= %_!1e_YJKmVYMC\2S"#-*4ON:Lp*j;%4!-maL:Jg#C^#-J]?//!<5P.CYbiXSnMTLOJG$'^]!o_l]"ubR7e,a3p&4&J2oo6/hLL+$$.YpihHb\>c&^C:F^V@3J7C?W?^`sp3oq.p-8*@'_Y'=QWm!BiS$/"JY]>)bf3a,NFqrpgo %/\JH/O&AK6]Ps2IM,@]b=QoLJHgNV*'SkgJWAFC`.d:,QGIb5?4-R4AS(i2N[!)RVlf)OI,C=R'c"W0N[5F<>n%<6r+>\+XHr^qD %qZj1iZ7]FUAYe3sT"-(M?IY6[g,[7i8uobDlpH&_$@;DuCR(M;X[5o8d'44a %jVmE_.@4'Y.2?cMAU(=D;C^nB#hCJfb_\,M8c;T@:SP6(8Z>7t[0fL)Gl*cb[0fL)i85_XX2&U`0H,[7[P/,C7cs6d%PQZG)Jg6b;HHj-fKHrK$_4Ii@V^1af'$r\Z9M,$VIKIto %qtuBU\*Jd.P/,",^eWsu`$;k=m3ADWS[e%86DK\bS>-Hhq640ajj%gGrTX<.fR$\5r^]2U=Kf#=2n?YF^U80h\IJPY#J??H;3ZXW %qgIe-DL&Ah>Z<``/Uj0VC6J$p>fc%Zrc@&?JC? %g*-#YQt#7kZ$(r=5pT'Hc'7Y"k8m3;Z-Vt9lE1:2,-U/Z]^?u/6XG4^Ghked?'9$g/i]u@mEiEp_Sjb(*?p,[&M[IACZbS&7+*d@c80T)6TsGTPeth-*ZfX;$*,%B6]RiYjPuf&EuSZ;7c(2="0'C4/SsfIIq?G%CMJL7aX;aj_bTK22>RX %4A^B\X#VF/D%CVDLOaWbclV1Kek"%/M&A,.Bb,2@LObt%+/U"OLTtUW[.emtW@)UZ>$!f/40?G2o.fL!Yf`EdGU-`eXhi!mEi %qegC2"LYBb'Ko-@pdhOO$!s*/+GK5tW[)@^W\RYs3m;KOh1_6)ra+#G6U&(2?n8:,fU]uM^*c5s[nlH9>)SAdoK02ShaLbF5U&k%-# %dL4h$r;/-u`L#b__c%G(q!ps/ZmJ;_2701r<3Qsj09>agU(Lb(Z5Jlq"QIU'UZh0h:e`TtC[.K-$e4fXBR/R\H?Sf^0B4qh@4;%Q %#0nl"AnTeZ(6<n)ScW?Jm&kUfj_!]*Dbgic]Cg\[QXpNW-1A"dFf-n(dN$AgT`&XE2]pRTZG]ONp"= %Ba/5:l0]oPr/Ynk$>-Am_>gH4;KuMA'`="Q,mC?G0_c`48db:gKYd\e;c8c0&H;DGeRI\t_eCb.r^TEWTpf=.r/Za7"'m>ar^Uhs %R]3SZi.'7sa%e6&!<8ggs/\V&0)4>Ck9^N77n*G\WNm`+Ird1D'E&/="2`uGe/DO($3*XZd!t8T/uk-;_Z-P9!NB.?n38E!:S2qK %"TP54U(2(%+G'fs35p*Ipb=T9q@?J8Ku*efGUurKKu*d)V(dgYs&%0nqYN\mr/Za7e#RISn3?3%.LGQp$$[ruiI=i!+$>h*i."_u %T@HLI!WSphs!1_ir/Za7"0.)0p`C7LB0*VX_#L@s5GXF\_>fZToUl->(Bjcu+AmfBs4QVN7cs"gUXcmAeY?3O[Oi7snfJ"A7Q,7!raqWHPcdL1GN&Vr*$oRc@;OnbsHLbDX-Y+EGS,/0q#ocG`#b0#1- %Zol;M.aT'&s.CQeJArI:"p1O.:Q6G%kk6G$!63='X\mQ#gm39Aeo$@PP6V^/V\(JJF %2]mc'*&k&Yf=/c2!KS"V$X^Ap%U.^[f%!_nT3_S_8-F(Z\OCjXqk(lE> %7d-hF1M1d[i-]GnWJ>\/^8i#ERR,I?'pmaBAoPbCF4lTb4B#Y7YmNZ"`]=8Man3lF\?&q,L:#_B:Qk,d@MY=8Q(4I*TcC:5^$<\>ASF?ECZ^.0Gi.dHuVn,(@q %gA*o_0kBC?kJ^':N@l^tmUTa.EGAOWCPjpRXBbD1"N$%o@`c<[.L_N2603A)9<#Uq=Rs)V+M$Z;-gSZ=k5lSP.a#9gSs(@oN8'X@ %W5e"t:ma&0=;.65Y:k-t'5OjXZR'Ud=;IW %kZ;'aeB;!5b=2T.h\')OPF_HD1V0>QI'TRd,dQqf5+0)GWl<94]Tt\)aL#=GqIn#dZ1Il(8JYd?qjmN]>5d!tIIF>@=13:dP&@W0 %E-_W&-+M;7:lfn\&jE2$KpFXiOEEW\2B@k']VqIf?hf-Z%!ZN^;1"PfJ>7&TcmAP=&"Fc-69;eWZdh %+R$QCT*/Vo"+oE>:BDP#WEbWPo8aT2%`mp:HG1o5&'a!ck".?@Kf\h8d(nJRj[2B_e\=j)\^8\B=bmU5hhCcBm#3Vekn!ua,R]iA %_Kcr(+.BqP9bQMSo66mb@B%r10A2$pY\,]R6h>Am%BodFqW3*A$RSFLBV!>bs"!`b[[)2$3Gp:Flt_oa?eWlNWN52haZT9jq3/jM %%`I5O)(b"8N([fSm!\-0m1BH1s"`HV4P#6mE)YqfalB`QP)cI;a,D6@aQ&qB-7u'DZ*EO>O*C`KV-o:Y/a;R]glGoV%b3B_$%4;u2eGN0RAj35I^Nf6)\Sk=o(*Z]MGpQ5pYG]`"dI?oY,reH""#O5j7q&_?PEO1iG %2P&Ek4HB0#BFI"3jDda,P>:F.pg^Q76Di6.PK.+>'VG/BiusK$4XN#UM+A\C2f_lS:LY[:g#7-945HB$/"/TGeUIl6^\a)b?QpVR %>ApbPjLD=*rT[p5n2j-iT9AspJirIlIYrkB%fLefM,4-3EDJ?J^r3-]=\1'OVGeeP`$[Y8#sBqn';+XWLMiP%ACKDP'W2m8m_Y$[ %f?E@"Uo7)cKYWWf]5UI.[!lBbJ,D9[E>SD+AGeE!gel0)U@@4C?&ZB][._du';il@&Q^'u3G"@!AKBX,bn&q8V.`ti=!,iH]hf`N@X"@#XW@MO_A#:?5S5TU5\*7@Jc %!:i\Mj,WDVQjk?2RQ:-s`,$hVdL9Aq1o$p-r4"#!!9B:#a,QL2hg)6kpi1^W4Oa?G"+K$uB87@t@Mk^m.01RrW#3Sdrt-hpYTH9n %a5ON&1%<-.+u$LH#p>9357UAPTZns0e"N>Lbg]u-L`_DJ]KinmVs3^0;tDpgimff?m>q]?DL(2cD22A%%Z0!P'EW_2anW76gCCbf %LHb'HJabbJqnW_VXG&(R00sE0>c'k[%VRrb;Rpsc3N)8+bB+"IIo&Nd]4k"&_>.fr\T-&dsO<7nPmtlMY%/q=9$JEDaAg07PMQVZL*^ %JVLLo4IccN>C9!W@Q5+6hi^a7&AtK_Eu$s8$M)1+bM4DO]_&7#5$7Nbo)Wp$893O8Sj9pPS_7NZGMY=nK)$@-P0D:I$]V*Hk`?.&L^H8* %9SQLPm$:br@NJDj&5cjanMs.ZF5`ZSDO9)E@d3C5+k.a??J_hA""lBm/21s#kYp_tN82Vi8-0bi?mI0iMVCSG`mZB"&#p$nX.l_\ %QBj5LcYu2T-Al$C3$O2g]oJpc"+?O+RQNMjPt58hZD3UtS"2rU*g(P,oLAO9,)J^-RD!r"CA--b5s[C"QF_'Hp,em0NnSakp;"A%g+: %c]T&f2^nX+;/W_9G0[H76h^oO(PY1\Sg0Ep=iT_0HeQSl;L*.b[% %qcVJq(T!m,hl2'JRY.`'K3mO6-C4SU:NGi#)bT%s%8Qe1/Z!UIGYm+dFk\"^2j?Q4Bd=:u9G,q[5ft4**Dd*b:"KIo)Wh$9"+$V95"gV:^cP@GF:pKfkDS/)T%H,"&'qtW79SG7/q/@TK30I4(H-ZDJ8PFONH %Q2;O]:2VX1W,XON=bJ7NmNa0/H"\Nu"m?qFcjBkVj$L@rUa.>e*%,u;(+)&@Q\1&/J>KTj2g]u?9gO(bSYMM3P0DAmWi:h>odtS% %l>lCIes\gAY8HPFj0u7I37/q?:6WC(:1t[.$#sF4E#L"iQ/WP4uS^rkA8nr4XXe($aL$\"K?VkVm*]aFA`%^e-EnJ^pYPp[[qN**,+-Asc8^$I,S6t\h@ucA:59sC"p;:) %-Ta(S'GoA,-1s4J%8NW/l@jR%"Rs92[nUa6m*;!!J;SU`,T;=rq^.=.0i*FhU,pss6"icP@U(qNs4Rf.+K4i3Wc:c70hp(m&6'3o %,R["+:dGY[UX(l93]pVkQQ=]]kr%gJho\.RYCRpKbpJ5Lb %92#&!aW=R)('pPnLD'WgjONt?NU1B_q8aVJ!Fa(kli"[II,#Nn=n\KqQ6:S1#7DV]CF;f@O/!)e2&tFg_Ip:p0Yg_Pfn>F\S+6a8 %8od2U':'"B._lgje:e3-;$GUheINpQ\7CZQ^)0T<\GBZs@G4E_9sar0W4E6]I$eH*a^gLgboAALGREu)H_G4fW07\5q?B'!8Ja!` %<.HRa8g!_Im]V(A[1B@\XQh1CDZ875iTc7f7N(9rG*VL!*ud$ig^/_*C[oH1\flED5F*Q4rCfEh7KV6E#b/b'!f5hUG4HO#S@\Eu %?e45Aimp5aJ\lbQ*tQX6o+?g555-Ppj?72HFfgK7cdiT+/O=5n&Kgdn&!@nN`lGlA!8i#l(nZ6$W@0sZe'!`]JOO7)._]Sq9EN17 %,?F%M[8(mkDa2"&:!](aa[HqLK1).n1>RS6B96r1g5>3]inK[>g&J1kXNuq@_8@;D9L2"/G<`KfG %h/0QBr*$t5;K-^sXAVd'R2kpbRtld#htYTn,Ee(blPK-edAWZgA]JR&>s*Rh*j=n4(9\,Ri-:i*IbuLr9R3J3oFGkUb3Z2e`7591 %prKJ!7>r,9T9/RflL5CWiY48!6s\C%*cioL`j-qWW<]a9m,LSRZqYI:Sdh4NeA.KbJ6a1/5*uW1-@`FJ-_aiYL %'fLM/*BmqUG(jDjR3]JVnKX`TF0>s4)SS6.0#V_.0RRrn`PIjDn0pdE/sQjglXL9g_U28KGT\bHC1^Ta*StZ)>o?eTP`[d7EOZ]8 %&Rc]<1gCAH/gT*j/qm'dn]@qI[(/,(.N5\)mY?WQ>RK)PkdNr!/eqsKZY.47P4^@CD/LVL7#X$JOn0ebRp5@(W5>BMZkQ1u#n<6T %K4bI9P5NV$:$K4kn%F"-glroV*i=)&F/:FL'oqACWIk=YepTofBntL*&gQ`Zi6g9nfX`O'QMnfh+ %.]J>%NS;^14XEn6<6uj&qcP%=X%h4il*o,_"EWsIt6#&lbiDOijGa./bpkkPD"3f_%JbiLZ`>;7YPkBL14'K&< %YC(Nhm%Dk^9Kd8Vri0N;KCX7frk>SlQ0Xk,9D#.0,Q>G_fKHp"AHqT,`9s>^Ka57,&A*]I=m>OrRMM?$h`_8\)Qnq#%kcbB"H`4YCh^\@Z#D %4YA0KQ]&W!--8cZ/LUM/>["J75u>hW(u=$&$J>5KkRI*sc._3@6qZ*t(Z+Q< %luMXj\;8::6'mMEa(6P8E-/XR[JoX`J"18f;qnLL00X)b/&g-4Ig+C#G>=??fA#!UdZ`h=BJrG.HJtA2oK]$\:so"7ql_b:4j2l_ %QSM382=r8mPcW]r]VD*:W(>`,kL%&YI]80hNN@VNbh.VZC6#!'m`1;`o4fY$d=GK7$G-=#8.Y(u@4VcOb/2n8]fJ4,7VZs("7n`O %A^JM9qD?7"_04u8>ICXl0;$D?EHq`$^2Ct)0Obf[HE@_*.c/lGZ7Z>HM/!c;X?+B<'Z&r'n[)=OZ&@HW%jV$i0NJ[Qg!S&5LEtKA %qoJjJL^\;541`PA'#F<8"R2Ufb]n@[tF!J_Rr'ImXL %+fZ7)4]d6RO@'A+DpO_9:lh_Yo-A#p:tS8S64+o4j1L*:Z+"S\803ei'$?j-AAbdbQ4&QFb1e\dpUKj<[L#NK\-YjJQ'>qO*j %a]/$_(jDqd-IT^A.=AXRFLN^r/Pm4.O6mF6L%UoN^(##B,IG6 %q=B$JQG_?dFN/:QR64cU`6q@s&mK*0Qgc7oU\&j,S#]#"rE/d9Sn+0u2k;P`RB7pNVps&DF(b/).UP)Fit[NpRVRaM,T>E-Y!1*E %Ti"AlcJ?B0AT2k;W^#$=RQ]O)mOLj\ID*E#J>@?9&7]gkIu(;\+\>W=Km&2MBk\9=HWenT*W9mmbNCuWIgHtNEP,$ %/23fab4:9ZM2CA#j'd5:>00>@Nk$E$&[g-cgi.InM5[8n-aFKq(fXp8JW.?9AMFjA;6P?256C?#QJ"@XFd[hToU`UU=K^T15QHSR!^/fDtRM5oA.b&;-`qt:Iu'PBs+."V3#dS#(l-m %3L2V*QGOh\WN@/mK4U%@4^ZpeNg1!n(s9es+XSJ.R1o"fF9U'.DZJ:hU85)u=Vp;>8*h)WfO?%>.:OZg_n*/-Ufc.s/bSZceg"AK %-p[5@l$2De?@5.]7'3(;:M[+7G0lt4Oho=*@&c3!H/Tr^WBbAb=&`!a/J[K/.p,X\[8\OrhG]kIh>Gj4UM5l1kj?r1+X:_`hq,%Z %c,%uS^;h[XL'3Oj[W,&4)P3GX<\&Q)2Db1S='!>2_=T"(@H`#hjgYBJ?,8IXWh5k2\)AOmX[",[UhI2KtJnb*r8 %L@JP&FjcWh_9*muZO"E&aBaSd674K5N/r/Z3)G""M]`.]0=_q=#>_0+j1@neK^gdips;/^s'>G.HjhDe]E9fpNlE0[B2LKg@!l%T %70P7H`%iVJ-sWV\gqgA %&>mg"%gh:f7IcooD+8^t(`rj;&#b">MS-?O^2("mao2?eP)GsRk>1dO$B=G!4Ln)B'I]#NcF1p4E`<*f9b%K3k*cr^rd-\@CXn%U %Y-uTt`1?m;mGSd@rQUt4kcO]c!?\.VS\*A%b?]>*ICg0-1mbcWkQT$#'JL^nn-+_gUjZrIr($B#:O.cVUl"X3K@)0q2p(u"'8(\6 %U!+F?]m4dT:KIkr@B<$R=')A1mAuB@Cmb1P@'MVN\,F@m*)d*+&Fi6tQkU)Q^V)lW`:>lgh3hs&P\57Z$.I %ICVSZD:`7[*hAY[O-eK(:tuE1SnIM7R5?M1CHdF;En9L:b?^ZQ'l7$jI:UC8f(!jh`:UD&a[^AA$^^5%MUG[[%`9\t.J9:Cn.8p3 %Ys:E>`R@Z3F%'4PE!HC_9(iaBPRSp1N\'I<,8U=WXQ&@RbZ4s`%lrE_I_eLb52hm6i_E'SSpq'3P%D>%^(.:C!i(q&l_eLgm(K77[i\6;,,4N]h[4,!=%BMV.X?2;*:TE15CCVZC))n06&O!i>6bPC$;@t. %M-HV[,@po#S;u1u363>00]#)^H&2Igm'q_5`BtY,0iO%*`_$Ec0nNF4GXTn."Jmln#ud$/f]6#-Ao %K;FpZH`&r\Fn]0`hE0XF6oll`1b!'hLP6"3#ptC#pK_mt4+(>$j],.G*NWaGGnl>5%PrlC-\2>Gn$'+e).!s9]ec\s"2i:F]fWmZ %i:>`eB&CORn%a!U]'lBbhFTn*MGW.kFAhM.>B&BBDr-BFhJplVr/:1T,NVV'pFZl(N88hnf?$O4U@[5%nreD!.H.p`7Qoo)DMe,E %l0fGEI2AIKcCd%8JeXOB"]V"!m202XiA)Vak_1Y_hJk`EY3WQdbrjiF%$gh2L.:dko`14QL@6m%?G_rske),T:,bY%8m6:A)l]D) %T?Ni"%VIBka`c&ZbEpkoGL#5?1=m+phE)"SFd`*MH;e)1%EB<`.WEDTo"*L"RFTWL]fOI$[)UtV)Lo,ql0@oJL[;mf %^=H#47Nn/*4RRjt'=W6`#\Np/B]pB;$3=8"FQhK0",XP4O$Z*5T)qA>'So)kI*5@;%@0=[P50sh/eeAWe:kPPSB\lAgubf7%7W`2 %"?$(/=BWr^DNGs>OrUa[DVfBR8DN>t+m<\s+*!dB[gead]YnZ9hR4,K\BW>e^lCJm&`NZZVW1J-k3!o_qt_Xdb0B"KV8Y;d%C=8$ %/]LN?k3!o7Sk:q]HZk_BW)o8SfMV-`Gh]Y*I0#Y4(_@C=g.Fr9T`=_Q`T1m;pVURaWor9AYn)-W/D\1][[1jZ4:\suY1l2]/21_Y %_@]A[PN7Ef,dOm^\Ub\LW[q9ljTb2P@-harRPU&7EQ1gC=gDT:&hZhcr`!QA^?X`b %iVOsfF@F%fF0VAuZXiGK=mR:%ABBSb>*ETATXk[hXlDXHK3&oIBcReL2j-k_.Uj`CCo&>te4k=AfJ[]JM:*kqCn%u-*%eT.-o;.$ %qGQd67"K4(?(LV0+>MM,-RBlrC`CK=j+D3do*kQL2OLc^X&V^`O!KY7.\rNSmC8&]gBKiDZ!)j%]sb7dc0(K?8T9R\uQsLWEkW1FK`_+FgfaPB$@]k9\Xlo'`? %NpB4R%Ydr26=P&K'FKCB^u*ms2_m$h_!5dh_fZ\5ccgJUCk^;D[F]lZ8oeNY7](ca9)9E!H=t.Op1Wk!]X%DunUH8SkLPQ2eb;*4I=@4&i]i>0$PcJShN&`';PUpg=)D\,\Q2Hl)2q;FYgjRA\PBOM,S7 %jEtnI<5XC,$ZNocb^;-2,'d$!];>gGc>=2*ZM"k;41lQgGaEJI\jd>deQY-Rs\)PrKe(AEPci %CtZ]ZGOWA).?!LM('OVbT[TUZ9oYb6!?t;a:deQf6g@YU0&,"-6IeL- %>]q@b^/4&0k:aik9s%Q4nf`#+^8;[EV![q1dC="";[Y$<)7XM?:Ar,[.i=W?CMEn9L'a4F".bge.ejrdBG'*PNKB@cep[42]Ci[[ %d5Kn;p7k^'gNu)j`@Rf@]W-!1pmEidHMde. %T0Sp<"M?dVF62]drm#VSRGBepBW9^+o=8Y/rZQ[+^"1*=B?VWf\D2J'MrXJj_EL]_AcJ=+I2gO]b'pc`TM:.DfBqb+8SWYiK&Su\ %[U8^1B7+M:/X`XIW)@@o^Fh-S=*)'WmaC%P$q/,T]!S_&$`#h243$TRpRHam,5#WOfN8aPhUjLP_kh6[7rQoWe8D;>];pk&PE\#Z %&7!ID%jt7ip?`9KV6*eifXr_Khpd&B+.BU8b?3u=dEjYt5Hu!RYLTuQrVPBP1DnA5B.,Pc7E4VB/%GG2G9t%@Z#e6&f#">2l`g\m %FYU*(f=,)TVi0J)HH^$jc^u.G1\:R_q<6bGPgsnr=9I1^.9!gfoF#"E-3'3/<0nMmo?_fAc.!5J'B8:cEdI,TjQA`JZ`_t^O'9&; %@s,$pHV)8eBBoGY:OH#\>*YqUjp&F)ogUZ(PHh2;^8KR?2g?A[hIW^LB@T.[7US(?47fpYFUsL75**3nqk8e&=ofh__c63jlP$ %084VNgom:I`;>^B&,,EM]MOV-g%F;WHU=B>^rZle[DbG*?['1&sZI^d`g5>1@QF&SE@fG[i;NgA0p5Nj\] %5&Y%ga'1,#oEMX?-L-SV`6*Epqfo=3d9/]]I*mt'>8l12Phj$;.S.-6Zj:3S>pQVFqqqW7VHA,I>JD)1S!.Kt:#1d>dbd6FCAI^2 %/$V!Yq8,UHo[EJ'.-]TiEXD^GV\`Zm5@O%/A+P*Up@cd$oC_bI+Ol9".!A4K;\:i %aFaZk&]la*`)1p+OpaG>=`j#c>O/`r]%,"FTU4&>0UHi=D63&$I-p@gU,2=m/!B#Nfl?rJj'st:'/EsF`6t'mbujPFn.r=CAbTQa %)I,sMYf-hC&!S>b7+WE!kMO-iVBA:Cg+/?Rr=Hs)l5^pjlM39:@.b,Tr<,]+Q-mu$bI,7kkt;702keKp:ZOeXmu6G#G^,< %8;%MBfX1^'o(V(hOV_=SoR$"AHf;,OG&mQ:HnEPYE:^#qqg%aiQN,u)dUHD.lqK+Hn&Jq;a61.g6@8)%H:>Bs@UchRGF6/1+Q6fgeP$m-['CXba<[f#OP`!Kfaf\W+#P2[FP#?k&"e/OYl[(orU.)NA!8Z=,t.\4K>nRhOi_:O(_91e&S,_3@ZQ]a&I82.`upe("$]lsR_;Bd]I?iP@. %2%='Z\tjb(e+DKsTn\1OG+`m/$u\8soVhAC2;FD,]b\k6a$,d+&XuQ1Jk_#;YDb2f`$#*%OqtT)IM?$NBl_IufDn %6NgJ_^IP)Jhr,Ug>DHne#+bM=T8V?GbhjXSm1<"ACUbDtCPQSt?c)Jl=?Ap7Wp0:83Wnj1mSCHp9>QR-1*_J]]e6Jf\cl%bg %,@^$O!O"/PmM_-Z^;-HKo9BmmTBr,L#_PosgKG2k5A5MjT:ca(RA*)ak-1qPmbclCKK;R,<.>SW\8 %V_F*NXJiCghVF,:^Pd76KN6TNeX6ZU,[nIpW\Y1a(;[S?Uq4@<`obO(ilj47K"2(!d#< %h9d@nT$>s#EikY_S@qM'RRZ!USAc'54S2oiLp%]m-'J&O;N$T/1\raK`KsAHiH7i,q!s^7hX6jen`>s@YhLBgI/1osQktr/^3n?: %Pdgkdj_K-m+!tIGMkO^6.F$8/?48D=?p[c1(O?sW)283U*b0ZH`pZ2&("IYm9DOn9)MV-hH20nS)X(hfcQ6`r=[?6XZj"#d7iR3J %"#)@"X=\jK@PBe6`DG6>+Vacaq6g?Q,9parbLc[7hEBa:9QGB7cFqlm(k(J?L3@WY>5%dYN;2s1.sq"JXqH,*6tljHI%cTlP%NnH %'Bh<_n2tZ;H^FqrSU5_\kZ;&4oo#;WT&7'p/Bsir']IgTQ=d#K2S*tU/^;Y[m$j/)cO8d'<0Si28MZ28p`FWN$L&@Hn3?3&Pf^-G]QYM+r^VB7_5AQe#KH^Ao"tF*kW_KN#lgZos.ERJ%/racs*+cSh9^i_KugLH+$#o %FaFX"XSD?X0D&P_i[\ODDD69?;+]aTpG!Wf2;a'f^MUVH$, %5%13L-;Q)'!n1f4EmpF*iY>Sb>`pK=k#?ZjN(HrUNrHn5>=f0\fqBZpP7-u/oG8k9>>LV1:UnMj%ab3"2f,Vc7se3LL:c!s2Nus-g;lCYf;i()qkd(FRE3h#IltqNAih26RK`H855$mn\Bu1]]$f>5'/.W"Y(@oO %]-GQ72(Fs+L#&rK;d_TR2=qk*lP,_Wbn4\#N1-$d]\M"d3*EeZC`Ia2N-,JD1,D7g!u$rbCX2BA7.oLS'YO0CRo&'$%92@se"fMD %,u[t59Xu^nB'$VZ[S;$M\ZjO5f#(!un2\rn/e?hC3k&HZJQ]O4]e:``(V"Ds5RP6,>j1Y]e.hPV>aTcjABi7ShdU2$Y.Ui@r)?:W %7WPjOSuq-U>J++Lkdh$s>JXK9@4&uaai[%bbYH?HQ^%qaSk3+g]W>?a)R,ef/(_p<^hL@MZ>rO99]L!^OCnCD9taR?@pK7L+]Z)b %SkAGd]K^m8(N3\tc,e$2UL%n?/lWW,LBnXu603[-:/2[=/WFT@jH6Y>F01Ir6iZ>ssJ %4ZZVk7TQ\O*i"scQ)ghlL:MWmoSnJ03>)ET`am>qEn"C]/XI7!8Ya/S90^<\2BYZ=jE(%&R\AHSJldGP7GKV_T`9>+jnn=+-l,kTt(`U9g)5DI>";A)\1#Lns(i\YR$Z-_o/A09'EOoD6+5^^?V!%5%8BY)s?hS@g5JqICm9\NRXs %&t^.Xk-,)iM,1;2*OE`1f=V;O^Y`L52QpQ]n7<<^@coQ"@7!&R`@b<@RZ"HCcd#\!;X1tMTI&Br)_SW'%pG]Z]l<>82K'JF`u8m^ %,YJIU6W>M1W'2p]-EPcGC_RV[bt9Pdq,r[qo#6M9J<#CK.iGDZ>1qF+JY'DL;0;Pi1`h]=p?@e"sm]'[N*?DuWECc@cYfGjfa/s+"4HA:q6IKS#iHJ>ZX-CQ#&[O1NP/XY9eiT:EQl85H)FqAl1[BrUW&h5K^VL(?KY>QkL#I[[>ae8M,0 %4t<:Rln'Oq5>G_D"bI2nn`/!V$[kDMIXIUE!5*:^J6WG1r4eS<2iSn\e=#R.!q>6YhN+%!)iPk?<$-Wq$@WsjEJEim1#p;%l^/,( %Q\$:a)R'H3Ss4dJLTY=cGp?Af3*Kb'!-0O`EHA%E6[XU)O"5YZ\J4tOjlp>5eqN5BR9kT,@-_Idd3[0:1P_;&UJ$s;WP%Z'N\6GW %]qY&WrsuE-mQOtjs(4LoS,N!*ANpLGgmt#7,U.;RWhmh*r=g;;Nh/irJ6WG1geRt^I:<9Jj49Y=hK6km+32$62h5-?IXI<I3_N-2sVsWsjT-E:8:R3I1*WMHb/s&$[kDtJY %<8]e,0Z.$uS-h5c6)4iBj'7]=*(6e<_l9k`Xb/59BBCi2:sM8Kr+EK]5LRp/=PP_68eEb-c3'(mj(KHsM]-dOV`h!Kn[\6LN/egs %m4Ca9po_IF'dT66Yj1+8<5@oMFX*?8W&W+B+Y"V\Jc_n_LoA*N]eZDl(+teVCVe"@?\?Yro^X:2o/Gm'8M2>4@Rrn@Z_KJ`W=Xla %J:q/7Ud?2uK!om>+tD4W("dZX]bD-h9C6msFa,\]B61-,O`k&$lWbbhAs38GQK$nIR@[$s(#2nW6h7lsB0G6tR*f$=CuQ8I^Ee\MO?ij"L@bjt %W\/d"$bUGkWOhKcX1.+Y5QA=lG>J;f9s+G).c=9)$Rb#X"IeAJ(?R)cVX!_2[7L*HSA@r/9eAfq:Y"QFC;DqHJYg38e=(Ur6Oo)1 %2RQqQ:Gb`)pe:9:[7oJ330jcZWTBQ_(=(>69J[:#dVtXY:<&AGdn-$/&FhZd'UAX7LMponihn>nL/W#bVc"F+,F[eQ^SqAu=0bpH %:/f?`@dL)*r(Scu:#J^qj_nn]]q\g`N>YGBFBuhk1n%)$RjP2]4_/jR6Jb/TK3^1KlP](&2V)fB"r@E$OT,FT^99ulYV=RI'IMTNkrf1$h,?"A@D'[Q0Fk@eR5Jn88)mZ(>STg)Zh2qRdKeH7]A3\7b?C5GV+o>DYP?^u^=YQ!' %FL4p^m9&pkAM9?ekSo#h,Suu712B76fX"t_rNS8Fi#^pUrCpJ,:.&_)YNN%.n%k\RYiNGgct\t$4MBpl[MS@XB.)YG<%+CYi$&%?<[5mNGcScP,`_ %+5aT^="R"gEDfc](67QcX>s$N?4ss;jM)T-LS9f!k"]q@ju@L4^3$?l:b5d$GSnU'9h@??5]#ITEoMRU.k8SaNg8\DTAtSd]_Jk: %Dm1QKn`Mk\1[*P%fFDRh(@6>m.4hF;H'=cnBn_Mr\BsX_>ETYLNY=.,EEuB8/",&199NWHiU@ieh[VFui-L'-Y5,:J8E$X*=n>bR,"EI5XCr2bp"45;Zf=.IVX-W*rk!j5BXZBaL3MU(>XGH13X:U5B,aF8h>2dmnVmIl %kRUCm(P5$ufF-:Aj+XgXRk1i=Cp*n>*X#%aR%>gZ4GX^g#\$Y8NlU-`-g5gf-m5JZ_3^9F/KdaT!#l8s$A*g+(L\]t.L6+4a932F %XgGFoEVYh8)EY4a#M)I!lR.u+]=?U,G"0.C/r)jbqdkY#BFk(#Iqu^2c(R)\jZ.Y<##4`r`?eIi5#l"SDp`$(*hJpkF*n,uj>'!q %E60.ioa7=P=M25Q(5q&a7_us^/UQWgeR7(j,p!1pS1"EHTO0ed',P&'kfJ,d6@fE.4_F7$;>@X*1SY0,i`u`&n2Y"j5$YDVTA[R, %m'@s1dK=;uekqb"_-XW*_M:eX9KMW_")K4S`AhChSbscKe#n?=5$YAuE^iA%+"efm4>2m8H7eedbsW&GFYVHeJ1^7::i/5/AP3H9 %Klq4+IZ3";='&"E/c%&NH]rrQ([bZGVIqq4GD^Jq*/:!8o^tY?5q4#1o288b+/f+2!t7@5!JGQ+8-srUYo<_VLFMDjS'R1O&6bl: %p7H\2iklK!_:P'B4s!nJ-q>Q"pq3?C_g='u"/N>.4\KR9GRlb7,T;W&JbS*+qEi!m(jHSZ&F@3L7rADT:*hf!hT0MdZis5X(C2?L_c/N@_W=JkJrE8hMlGn"mOqVue7]7$kd7U#q*"bSO&^95l.lLg$KA1K1,R5ef:=CQs<&p<"K5QjA%,J!Ad9]<[5ZGU)HL?(PLj* %F*rBk@rc2n%L'i464G/_#)T-h'ijl7&nqEhlrgR<+?h;Plpc6/B3^&1A]&"qF@iVYWc*sMbYD+7A%>8R5GAW0=^D9'nKY"/<_Ic9eB#Icf$-=ZDtUO;69Xc^Q"m;g %ILRb+^6L6@*BsmN7+1SPV#,=Tnm9]W$h#+"Q\og&_tKmnY8P\Q29=rr5CWN;\,k'ki51fnR'++4m6#S)a?sCL6&Q'=k*3YFngdZlk7Rm;cJNk/rsq2 %c.AbGppE&XDfV9T.?r&E2b*!Y:j_%'TSKbf!2I<;YU'bp#'d3^QC/VsGE4lRi$<"d<`+;*X*:Ydu-PF=nn=HhoT=cWkD%77Sh[GDGZoR"+QPhE0USZ>.*$nhsm-cXfh[l#\(H,MJdSoD@Ib-Lb %,QWpU?-u2'`"#GW5*lZ0#Q&n#"GEpESo;SM.*^!C%%"j0/9HqIFgPmc%+V\Z-$@bY)qPbfF!MK][osdMXBHG2?GdbF*%lC.;QAsJ %g4R/4Kla=b]:#S_kN\.UG\QGT3nJ5?/^#$[C %htO9_9=LK*J$f18\c'j5H^@;(Renu;RQ6H-2]t:J_;2Y`I5u9iY_!^,J6*,HG44V;MXaAQeA*'11QFd\2R=g)6:Jpp? %"@[MhB0SOU)dFQ@>A,%PgbFD2k4jnnWfN;@Yl1iH%lD=6%?ajrfFP^&aQY++W__7q'ibZ-k?Z^g'tAT4?jC5cf8P@9dd8Krb2-F- %QAe;0$/$Qp)(kY^0,a<)Zg'd'Iu0t3>T#mQPRODe!So\CUJt2[(t('XRYW"T+nf,t)PrmC'Mc[D'd"L6oFtb6K&+:GNnbjV>[7uk %;s7Xu$ZZp_*@PTm$42O='n5]7P@!Hui=TGnj`7qr]e;Nm\KE*g%.6[GbI7[Z<"2S&7.2[nH+[K6"ua&=BLTNeOA^H&_Mj;^DUeBD %o@cpMC-X%`$2r9E48o>qH1\Css/)Ai=NTR;a03udc]pG7kjBt"0;]ON0+F%u>$]C5apT4QEB>)VW)OA2Wg2_"r%Oaoag$TOY@gq] %lU'!6`b5J8dh!_01.M1UF/WG`D@Y'tb,qFG[;.YD/oG0l&Z\p!2*4S8\=ohG)[hY5ipL`,M18uaEq%-HfL(.m&f^U0*Z$C0X^d=f %o4.u-"OQ>apubL$^^Q(8Z$eCA):]0sj@ir89_(89JjPCh+khO](cj_aTRp>2\ %5Whk7@WS,3.L:236gLDYjAb7o=k!/GMi`0F9@IG?k#T5gR`;GKrMmk>-pD6jRO1X='@b-%nTL*i0"H3g/9.aOED^tmmFP@$`.:!Q %.c/H>24'-._rVc5S'&\(iJ&4^7+c`G33@f&G'rb"Er(78u@Nc@b3Sn.I"q08*$PstRQGGn# %ehA7@FBfSBF,DbO0J.p2DFUdB=Ma!\/*Q8R&#NpHd,Fee0IAh5$QWFH_jT_u/9L%P9*c1OQPQ!jakS4(/di\GmtW^HEEVMLPSqM0 %=4&Z[hV/Gc3\Cf2U4tMPEEVKN;OUl,\c>>Ybs^0;PFCO;d(qhb-kdVfKatEp_O0Ps\n:poNt=G+<9"9\5X^6-6qAqB&X)Jr\r#U- %gI0(n1BDeh-kdVfKb!b;L]H`I7OXB`[*knHq4P4^e92Eq"@WREts;#&3_?B9FZ6?&9(et6Qph! %>nQDcU3(#^<=0GW=)TRg'I^o$>Z"qiHq4O^lC8-76MUC[do:B3:^CDmbFIJ1*NdB# %pZJ`tFtK,/?EW?J^EPbt*<2MqEmM@o3r_J&4G4f-b,/R-3ANTNMKAPogoMQ`'*Y]P]6H)m3o!`;G!JIfu=YN><(V7df)F6k@7W#n>Ju;L:SIqJK@sp5XVC:;^t_g!Z[J2rSi!'#A):Nb2R*9\,4]UrR0o)5<)s: %lXsR>!=>mWNm[XSfa>aNiT!4*PkTuEX`BkIl&"6=^iI5-CLq2UCr?"GY(B\?li$MR7X!9b3t&#f84j&tTS7+qP#?i` %O!(Ra>k9D@UINkp'T1%(b9lkmBZMAd@?a5FW5E_AfN*J=*HT(cCjMcO&#s!m^e0/I:L'[0B] %IO[K^nDuNa7)e77N:X5L,hLR8Er@jZ#@$eF;Bd\R@o38Mj@%_YIP3cF]$=c_**Oq2Y8e$>dM!!!I>>$S-!s`oZ1P8FSue0f07QJA'5YEa)F%-m %\(9$WiH9Qe[pX@m@-bX6*^SWLRk*]E$Y/'a_1H_-aXMUGIXahRbP[c@.cA/9l_b?YI1-6EDe*f"_S?+brn:Q%JIB$rh<_MaLa,@] %qUnnYn^#N2aj3FtZRso-A^@JS4=C?"I=oE3m&Mu8_%=KK$.#;='E[VL;IBbMj%$Y4?k`Z]'uKS!P)LdlG`-E'L#p"QTb)5LmQRoe %L*.%]+IGA_5p?"/+`8-K#DI\'C'56fA1C:l"raNT7?mpMo50Tdh,*(RfUu7\\-Sn!m;RU_h.dFcGt8VN>/t;1KHqRl?miOK8!XCp %Ta'=>$W*>+QkCl9]Eq']9P;WpPCAo>"6;e("!Uf%Eg+mbk]36]][O_T'8E.OsM$RR8#d-oHcE6O!m9@J. %n2WhRHoCCOQ4*Q.pMLRC4kmqd:!YCVaD0:X#+,k2X^TDOm]C!PLC5K2P2(Hq'%dTTeCkGo8b;VXZeW.JN*f9(kJK`3['YN4^gV:T %R)[g2mkS8;!bj8OV$ZM%2ri(@A3D.$GY!\O,8("`bEX5-I>6GPek44PIal);BPZ5_qmC,=1kfsk;4IJ;2h"1Tt]mI"/gA+$hsXE*gs:T\\/CDU>Iol>5*d!S!ZDQnK?-5MoqVUg3Je%:XkP-$aWe%;7CKMm;;TF]aPUYBS9PTRCT`k@+/ %C?)659,H%>Z+3nF0!"FlIFUu_qi@,D+.9u=hI,O./*'+c_&Y%)t5iFuNin;M"&c004?,2$fmohVMeZ'/e%$X4m7AC1tOIIE8_a!6/;J7DCsD4<'.%8\$DmhuH,-gXj`HhT6\>tW%YOi4O %\@((6mH1c9d&n-\h$j,_4BH'I''>!,I0(m4Haa#Dl2jj3Vc>m"g=aiB7rK]U^DQJg"n<*tM %eW$udnN0-0)3Nir*08u`<=NSOLbTrmkrhS%Q^T*Ae1Dr-Zj6] %1pmGNkB=oQ\al,/resg=F$$1s*LdZaC2SedJ.!gM]OV%lXoPWF36;7">QOIrEg$\%\H8-a'MK9Eb%[jFSu2b^i%u?(=Y",o5]J;8"$>_XKHAg7#oC,+?:/J%dfD$9%PL(1,3a>i:G3Yni3S;o9ll7=cCZsp %\:@.f&i?m]*S>r#,&CeF3j<,e/GS`:8KPBlW@L?o"h8FfY[]EU`/O%Z#BjL(?NMk7[pSRtp'ANHqZ_5F %M':9VCnFGNgq+,XbOuD3i"\^D0&(SiVPe6`i3Ib545_'EJBRWqm(i3:!LKAL%dYSnjEWRMj0F*jeFhZ7M9?ArT]4"'#8!d87Wo8Z %FY6q-Dd^Ujq1[k7I02R@QR#M@q"9P9>deQYa/Ua[j0F*U!N%k&i3Ib546F[=*1-%3fHIR_,3,sXHP_9RftN"XCC`dgi87EDVHJ]mbhD4m";i3Ic* %/ZUN?f[e35=M$0rof5*kqr8NYHNV*43SY$W$6%YO.%UhV$$DF7Zdn?bieH@d`F$.sb>=a,tDlP,@,WnU3VC90GK-`>70C+0g'5 %CFuu^(iI4^q:cC(4g6$j%s*30i=d?k#s:MXhfe:N%W %^oqtSO&MQbJ^+2s,Q;dc@\>_3Oh35%U^LLT'NMG\_86@T&kgt(+>T8!H-#2IMhiY!5$2#N^a=_-M;)7VUVi9/ppAACX.S=d+>*7_c*1MQRS3&-6Zq)^E(s/$kt0(0/++FImsS.krU(pqNO\Z0bI5_D.V[uEGHkO[ %Z"]O$f$^mJRPi7Q2YLC$jo`Uj:jf5(E#A^1[$?iprke&fl^,o&Y)[_alW1<80c/L`9rNtn^Xcdl+r_T4ZQnfs/ %/s0q+\M(Xk5?.<^YIR8GrA`W>I?YP-6@NdJgHOIeFZY;J423!l0Fu[g[>(g"KX+,Xgj:(R.O/hINf$VWf\=q>%u3gKDpdeCpu>k-hDAS?-Q[9r2dQC]tKF!6Ro53k?$XqH]3_0;&VGF0qRL3 %<0C80*U@dD=UG'.-hmeW#aaT-j^[ghG::j %`>;4?oDAW8fXEZ0H#_b#U^,OJRl'Xp5fZ,qN44$*He'"j6*DbR%GYhqh%N?kuD[S]XD\g;hqfoE"rj0kA",O.2I6c`_Ph6)o\Lr<,)q.02&/XgR^($ine56p%gT'53X-W-&\hGO6kt*2J:N`QBjY9^U*UT %j)K_>NR*JoXtY+oDr-^2cn[@p1uIAV,;3fc-r&5AUm$[-'GR\/4W(5#+Xn.A9suSIK?.5MUf:TPG#k_cCXi'uA#`RX[4K\*+GBcX^[jN4g\\O(rbOJ?$GbsZg'T:!I+bQRAaK[D8HT1[H&e(_:2VKOat*r*+"9<##emL+9n#eY-QGo7OR3?7e25Y4MP %0bPH;&^2P`Arr+[.-QNBdL3#N$PhN,qGVd1oI!^@pGSDRtS,[`:r;W8!gl.2QKHZrAd=47%'Fs-pGOYcHU'hOHZGEGjkl%0\J]9^$N<9kQII&[RIRYEUs?']A6K%R0.@[RaG)dj%&uWAt+[b#%K!JEG3(Zd_PtKiugF=HNiOj3'!EC(F1& %83.f`Z18otfH(BYB^PH=ZZ/#[(.p)Gs&9ajLX;J0Y!'_R*!5;BW:gd(EsSniiS$Xmc(W7bVYDi(LSSL@e/mUa%`.!jW:nTY7r=?j %hs\Ucm??tmBtK\D5&O\Ec>PTS:Q;9J2db+S*Xn18b*oMk>m.lp<>0V00DqtS?4B.O)a5&Z>c+msn!W18qKtHi>c6ligXh5ZHJ/$% %!-/P.=I!>'K7=Y!1AMEB8I@I('k/3'h]Lq03^W^^3bK*r7L@FVdVl+hc4cc&:T*;cL6olMYr@2?u*hjZK^@[tpeSpcdhn %ZNn^W+OZhucCUbV8:)GZ;OHB%1M,i67M]>pl",$-KSqLUoV1Ue](gU0\*(S,RKW0BqrfX[Ue(%;/(;1<3+:gi-bUK4KhO=rU.Q#) %53XquRmq(;0snTThN-C_@VC&GpPX:djca"A]qUk`P*GkgkM5!\h`VIGh4/)47Qd!o&3((%>"htG&^`c**bVO=HY`IhV:cB:N.&30 %es=$6Obg""-XcG?Dh(Y`p#aY'*\Cg"3SaOac:G>9M\a3GHn4ETrEK9]esF"^Xa_$%4Qk?bALK0@j`c96E>%p5a*X@+u?):22Y;B@;q<;7OMrF\0I"Mt,:;c5S^9GIDc %3[JA/PXN=eP-cYeEbFGdd:-Y]*u4_Zfc7leIoQ%^dUM4oIoQ%^Q.HfVr^TEWi<2MFn38E!cVt[3i."<:q@@aq:&&'hNsu&`UAs.H %('af6UAn%!,7a]C7K8dfE/a;$Ql]K];:0lTPU?n=7hl;Sp.Z8!O'7>h,2n#NoH-'[`=b!u.Mk6$io#;coH3o^io#;coO"s>Afpr3 %MZ*_3M(n]H(&\Bd*5^W`eD&$tLCjXgUS@crmm:h$N;QW^K`=osIkIljFSHpmrJ.bI3;=R1rJ+Gk;=M=G%K/5N@hf1H7n*G,W^->$ %(&b%dK`=p$2GDL4"ok?ls#dguJagF#k4?#d^YeJg\pLj58[l2`LMjt>H-@rlV5WreJBk)-d'I;g!$)]Fj&$N8!hAP7K_?Im3Y*Bf %H)C>_ag5On?U!_.pFbOf9!(2'CGPq,Rt3XgI+`g[$Wm?\qHTh$>[PCtB0V(DIV8hXq*BXaJ/ANIP_E?bTV6fFWm5?.*XLu"7;MTk %M?7kkQ_MW$@*WE(l#M=^m/9ijWPBMP-$LtUU;*5*/Fa(kq1g.kJN5S1 %OE\sX:7KAUA0O[Qi3npJGgJtS*0DYoBO*LN;hMEiTqrge[HX9O--[-( %*gb]FAr8(!bO.nWaKB+5Z6/I&ai[W5.!&dt;dcOB%m($)EAV:Pb(Z9Kr#?R>'GtqmV5!fukt6M0\S/DC2PHp'Peblu.SYelPq,JA %"D?g?A\eC@$(I1flp7lt5&XJ>hO`d@les(:;iB+_drOP]jXMH>$8]#/?("q^#[+_6=_/.K<\@p'nUGf?XBbB5P;\E]ca%!47?8(( %'s0:/b):IW-NRs4E`T@&9$k4*o.WOKW<9;8b5nJQD1.cb.%.Ok[(4EOUV46%rN>n5E, %'>n')QJ@n/_DoXde=O^cPht5T-,5B2aO.PC^/>STgi:X@ZV)'Fgi:Yk8d["QVP[2RM,%U@1i&s%CSI#e7`fa]9lpHb;>a;2>eN?$Sdn`uiU($'#_dH@j_L-\cDol`k->:(1$EdM:jOG![ilXq4n.o7qP<=['FSK,T'EpL%5# %/PT+^b#G^4a%=>:UPnJlFRGKf'dS]4>9Ere2RN9-emGAeQoO@,J47Q>JL2VEmhaB$C*qG+^F\8CTZ(>mA<:;Q/nM2>SG9HO7N_H) %U"u6/Q@8R&7XTKTKbVkCl6GEdp\KW,O6@iQ3I+DFMY#dHIKmLL(7kc[BY_<0oW,.+qSc/fc^":dj?7dY_h&PoS2q7\k->Vl*,2:K %e%IhTM]H=!qJZhGA)](`5(amB.?Q3*O,<>/`Ljj!p\*$U-,98@oYMoack9H=Kn2ljUEosmD'jr`d+"r]7uk'4:80EsjHW%@8(cHt %9MejYqhkCOno=+32Wua4(KNW^j*3*:]jMG)httWP1%2s2E=Ct\:XCB6="R"7"Cdo(_Hsb!P-e,5KT;?"i0a&E,taa\q0kTs=;B\9qtBX++HjS1Wi2 %Nhh_:\P2r$Kmq]/1/Gq\9eDWYbL6&V$^s(5rTl&FL4*apaQ%0q"hCBa.\4#SpSFqAZksWsA=h?W*LPqk$RUor4n8#3Ul`V_qi%"J %msJ[]kb]EoUUPGrFgC`\Mjjdij-XS!Z,bsga3bd2g#I\+j,Q97?sXX5cPaLXCr.1SnXT,2c6b++eA^f/QG+DB,dk[^Q$V70)eoAKY'Tl-09HFFr-<&+O/dcmZRMq!P:)aVV %K-$Yd`2=ktZ9AnHr/OAjG8LqO';$7!nDDfH@B7De-U*6eP=*4UJD)7pn]=->LL%D47'@Hu32kF8HX%V;I'V??24ZXm4DrQRfFjg> %AM'b71+,7G:F]u38P4BiGq(uDG]_\^+eA>8(PEl#YF1=#ERC;*s[k$ %#=/:'aLL9IO$a'iPcGo25Anak7o-#l`fEntC>jJ,X;rM;)kYM&&qD'ZI=;]W>RGp":N3oHjAPL-UpOM!pi/*&6t5MHQ2F&b?\7h. %:a]2\QSA=sH<3iZlbqi(m1e]UiMFVj9=Vl4*FAT5'8%B^*I-T5P#2)OInfVMYVJ-:c$oLJqro3FI\Pc@?.i#*13Z=bECG-7/lVJ- %'`>J8#+ci$pi1[efM>13r4#(!"\%FkdFIsmaJIh8TsgJJ$]g5g7k0AeLgff5^eXV(aJIh8J^5F&%4+K4_6-+$2O#'V34K3Mo2J'H %j*'lkfK9lT5Ahh/7N.q/(nUkM9@*[()#Q?)66Zn90oSn:U/#Cq_`t3@B&Ud=D`ii,-\`Cf[+I2;:H3eC153gY4H]DY?ODKP!Jq)G!pRlLD'+:5gC/]nj>8T>$3c][R5F?=\X[E`Br5f\HKc+4'`&>gf39APAjVuLSu+%B051;kXnt3 %+d_F)h9"VlLKsUoS-%UQOA!EN_mAe4OA!EN4%\PEm8,?_h"6Y!N8Q!HPu@,3\,e5 %s"?.qU>a/+>)X<$+CI)74M=&0;,mI<,DGF]DK5[8?f&:@hY8pW/AuKCf4^IG^!7J?$HoE!ClTW9Kc!R=j\k+Yk@3RQ=;T$G,t5u3 %oe?'ETC!/VdR8]Qp@B-T:%'(4eNk$;3bfXe`dpE$%5f1kpslZ2mo!!B^2H'k=q`"n!YH/>jIme66j6c7BTNQ\XfGnB'gQQqA]\p` %(L4eE1bFR4A^VBi5q3"@,gdJ;gW\VA<(q=W"13[\7)`.!;m_Nk$DIU&=6?P%(/Zf-mt)'InPXTZFh8>f@,.p"gQbsBY3?b3$Op[% %+;M6)?u^P3`9i_kht7GYP`Q/1Wl%A*MULs>5!]6:=$^M"N.o^8*/Q'bbS)q79giM3R7+;b_d]R9*A+7krlM--qRi4:*cJH28/.bX %81.8>AFEhs'tmn"+H;9GAtH/tq]N)$In:=aM8I!hm#XL+VA@Z8]W&L?9eAf1[C+/^FCoMKQN"/'of#\J)4F`Y4Va'RWF[LdGsHH+ %e:K:`DlPF>;bL!*"Zu63[4i>W1KBdVWC<[A#,gbW2mpG:c't`Vhpb!M,qM^Ld3u:Y[@GH2*gR"K;[]_LdT@F:r\59A%=D&dOn9j( %1n9VeSpb<(NG.Q@r:ME'NQYdFY^!=FZS\2L(3\M)@VIe@^P^1+Wls;LEpJ/)<*fL#(/-p_VX!_2[;\$M30qR417u8Wg0.=0q %+p!=%Gjcj#BV%*62'/),%+:gBZVZ's]E[iIK_fQ(5F0J$J\!$%=m4O_qG5#aC.W?9)EFtq>C&NW4s'Lq30$PoB>%C=`56lAga"-: %Z[eRl&Z?YST;AJkJ\!$%=m2jG$.KF;cU(\t>$*a_5Kc43`D?B+p9SM'e^&E6TE!R0(;?t^J&N\bG/T,u`VOZ#^IW/hJ`DbaqqITX %."NEZ*P]%#%o\8W^lnFtOr+sXMM5BGZ-tbQ3?-^bHS-iV43]K7Ueoggk`6-hltEDU9Ac'RIdW;K4^X>s&P7K9%f=QqBUWDZss %XW]itc3`_cTK?:Pr2SjQ'#d<>ZXks'DD*7,rJ2%\Q:<3S31V<$+\j1*SBRDqfca,h,l#n.0EdRSZGNi%36hf-fbrS\M1#67g%lF840X:_CP=X8me8T@9K;08*78)T)*g26(e?YU`G4C0OOfB3Z]!]OSMGrjgNAa^H8*$sk0:?[M0it4ishBNZRSOtTH %>1XG"Pl_46<4VqXOW?Zk;=r/#R5N]RR@_EINYE5J`H-9$MpLfap/-V0tVt/ap5F/VV=K=$A&V:5hAFE$A&D40P^LFZ-.92LcZ>69s9!:-`GiR08X/Pio:q<@t4:2b'3%'O/UVi>h%N?l.)kY %5-HkoD4MEQXiC+#ai60LV\I4K&m"eOPWd,!/cJmUdp%1N.OMVY#p5?4@1+/0fn61^a($h)[baB^A<3I>'L!0b:d/?M4m''mSH9BO %HZXVS8kso=ohA_!'DAnr5oO80P!+age1c\0Zj/:fJ?FX/_Ohm!gr3k2Pq.#-@Kfd;9F%E"*=i+hK@h/H*0>e^V2!OJX %,S7D@d3Xn#3UEV!kW+(U@CL'kA&URu^T\:l(lq5I4X_c\`ogXJh8BOC^2,Wfi^*#]:g:$6#P?l6$KGXS4d`QoO^NPF]EcWT8A4-o %0YUr=%>NZ*HP\('1:/5pI/0S)U,%S/HE>OTC`[M$khgpU%lYPbTN#pO=#i\]snkT<#ELQ@2'A19TD3q)"c,P5q@0?K#Oq?:h#De1!Y %P7XY)YcdZmDqDCde)gX31T]V,eDVY9"m<<&U!jSe]G/;O*HsJb4(OKfd2QULMBJh9"g225FtO=R!OY43dq2`_=`m` %4fe0,B)IHGHo,gR$5l(&%NhCu;V_$ZQ#@0#%]SDbQuA!@KnI7=K^d7F[n$sp_X@XsV&i<(\.jeO-U(cB7n[!6R)![?#M7,>*A04; %I$>R&jdI*L(bULMJ+Qr5KM+H^Gi<1f9A'e!WSp_rqOCft\XPu1Y7J[Foc+-PNb:caLJ(A1q82cf4+Ka0g>(-RP0rE(6DpX34\P@5h&>\`t2l+)E"p%]AV90LdQ`"%"$<+>8gn)t9^rTn=&iq0Qrg97l&WS<,L,_aZ@bYACZSXVQE"F>;m9:^PN %bl'*iLns'>&ifQ?`,I.:WRV39>cmW4_;*Z^U/Q=td]V^bE_\jB8mmu%/qs1*Ndj`#\.n@Di=%f9iDOo;!tIn!7nZN?bBD]0$("g; %5EqV;NV@HFHi-`3I9s)mqW6+!q>5X>Y$B.t?_D03qgSLo26Vr<49g#?pj67b`alX"S/rKlioKHH %i?"?B8R*.L4YEMW0d*>?%oWSRN=?=*r[%1@H/FGSiJB]MP6`XnVVossY5B(W]u\meK&#XI;-46A;2OSmAEn0&aXhgF0)j+'7HNuY %nb9PXLpg0h*g`(!p\=]J;p@8Q[nqd-&DKHW-klW15rF/9+n>JhhQWpRS2[4rCh;QIe#jdU)Lt"JanG;g92Fo5F'@bii'Y+JurT>-rRgU`L;9^h;`LYj9M1i%8knj<]L6bjV%G2-B7#GZ%!+SksS'f3Q;%r;6>FWi]J*0)e%l3n<))n\Ij_A:I8]`rAm!Impnud7Eb@< %]=V,3R'n')c.ZTr:i+_=2lj,$:UTNMm/E[RH0)>C=cag_0^G5gKhgB."0'@;9=&5!]`.6;]`jVI$tGrcoqT?cb>`'cIbe*_"qB.=Qo8\SKGK0f<`Q$;Tk[/t<&@ %"OOK#-`6\91r(1H*03Oen,Da..DC'V7HL//ih)Q(PnNi0<4M?8n&,q?]Tf/9SsYC1MbmBuM5g=)Eoun@[8-DaEGK)nZj<8$dXD(9 %W2H+SI,gp]\VMlN>t_ppN7B%$=19#jg&(a2XH8*?a4l$jI(ehs[r+.b(M3iORpJ*O%!pnK"tQQ9h+23q&($s**0mBdh6n?[pbE=N %a2?egj+uDV4FrufW/b%]-[a>L>.3&'>nB*/T1e$)q7AS#>9sAqo+#mn`)M#!CJdLh#;?&`b&TL!D09K %N`F_ocjaKYpbMDSQ%32(5cnL5k(?3]V=-l4Z+3nF%X&P1QG2X\ci$?d-^*Z5ZBmC->Rlhg^cotQ\>ShfdQc-e>^W's!jM=VSXlUq %'=uVo6VjK@Ujuufs3*PD8EqK-1@k6WI,pi)0bZ[0NA&ol7lBkR8M.[C %#$&'K)kZr_(N/=*I<:Z@+l(0%.ls4n8bCqs>96uE735:CQ2Dr`aQKo"5n+L\aQN2=aB"X;W5gGioQ"IeT50o3g\C.7K+]a:R:bOO %g%\sa7tQlLGPdKS*TLGtKp-("V;3%6QC6b8HacMHOY?4'oYJIM>qkj*p3^@gDBn$qRkI>5;o#c55U.?sI?mFPo?t3a7_YNX>Mntt %oAVqXdE!+@\(g/@dsF-[fR.#\\S^A*j;@]?2EjQiOj@\#S#$&i2Y-[p2O>2#X_uGp"c'S*&Tgo^^=Bc0S!5b(=9$Oa0Q5FZo8CHYoY\84 %F2p;:^f$fgh[\"2pGsDFY0YMOgA*`cbl>=I=3[^$I?bNk(p)6FXne0FY%o=%J;W&IHDuftb4fU!4";nVL#R84#4u?OLf^l&/Zff9 %3D%G-@#r!pp$:;]J95)Cn^)L=3$JZJEN/W[mk$]-&fW*39Ab"^]nNSsA])kVQ-4SHf,\=%B05Fg(^_=p13Z9V+bCl&)Q]5E&A]79 %S*mK"utar#lp`(A(u<9kgJ>bK]4QK,)>r0+;7)q5Yob=&Tc"VYgufGD3cSe-?^!]n"4hl#%B4=8%1$4tk`R]eZY"#_ZOZc=2U? %/+d,#cio%pE^^^1(PG4s!,3cJ\,]bM&TkisiuDCG"OI=)-Zg&&=DosfS;3XcWU7B<>e!UO=5Y)65o6&o;7$t9qJLbTLO";A8XVY$u$bg-XEhkr'AmcA-U`'-#+ %njmGAI6pt<&RG>=<44&fH9&-8Q>\8r1^l[um-a];+HS`'gDluLI+6M\:/8tr6QhOW$a&dOf=3kY#Ge[26Q_F9c-G8qctdOXH/Q1S %_)Z?.+8:jVgV2t<(H:1JPb[f!Q9C$FAm_n\H=('&XC %TB$=]H"Uf]Tp7hljIH>ADKi,`+R_1<,upn*G:)u$)=l('^VK_V11cif1D3Q>orIq6cWq5?1j7c-.:u$m-o8#`N$A:,Ee&l*g2$uP"G+d0;XQ_Y!',tZY$hr#j[-+d;ZH.,^tVI>JXLd %jGl]2>JXK9;8nXRK/rCX8m:&lCYPhNB5N=trkMsB6mKAMF5A9-nYi"^i4^#ooSVj["o#\E6(P4;^)*lm,"V1=S9I)(-\1h1bSISC %Q!t!:I,eXm.YdR:b^"t($OHoE^@8 %nM#()j@U5X73H#(b\*qDGI!/.0qWJOH=+[BQu>(qG=;[shLdiWd!ZQnH4T/N]CmjF%Z'r#_u<5g@W^&qhr.EH6[FfZ>g,fd&*CNG %,Sr6XOZBs3"R5l74h3PrJCo?GEcGqT>L.[Sa7[[Rj\>;1T3P&0!;e^c=?posp>Mb&hG(1c[I\[Oq.o;tcttYSY=qKI\HbH2h.WSD %f@K=tlHkh`Asn;>A?4'K$k#/96Ef.rBq8_R5.%mnmG[5>a]+;To>O_b8^4qTho=Cuh;c1ZEAdQc`BPkg7X\o`aYR@K[Q\u(Dt'=q %=j_&Icb(^6TYY2'())<+qMZN,EALlQQS@WaLd(H9*#JG_]u@MY:Yp`/(_"f\bb'd:NBRKk'a9'-Ma%'[:sk'Bq_3Tb6iT+&tl=1TLZq*dssmRKs:m#@kgl&qE09m(l/^#Rd4/KARjeqp.aW%lk4;4:`3a%*"5i<*7OnOjJl44q-%2fQ!&d %IAj)9)Z5[9I2E4]@20c$M1:INj$k-Mr@p)*0I6K+h.TG-/QLM!3Ki'sP?h.3nA=;&;7MW*>XGBE4]c6QMgOZ^'F+5iL;53Bf@r5g %Kja2>LSG^WLh,eE]1iJCG2C6nEi_6TA\BUUH>'<(5PIu2oamZK!r#Lsoro6eclRmepl?'A@D6Lg9+Qq.Z#ml[U"f'r$&E'cLZ%J+ %+s7*[&)h,.iubk>(m0=sL4>"/f\*KRn#lU45QB(t25e:M,GX8GZOa;8@.Zp!n-6TZb]rqWCiO0_bR`P1#*BkYGucH_X9=_Hpc0>`7cl":k_VTOQ&EOgVTQ3.3;hYJf:[V:ZK0/S-P:-3`eVUu %]:d,c]5s03\1=_Gg\J7,L2huU/[L0`Y^:?Pk^HtX_^Bcn)kYV_Zps]AmdsBH"'r)(;I8[KIl4X@>1pk@bs0R)#pj$p_+pQC9.b5GEt@F5[!jU@kEQpa)Ieg" %DDISujEu"HV2Y)6U=oq_b2M*[5R$<60D%`r<+,4`i[)shC+2f,3Vj+Emn=())AV2pHneU\!]j])I4n#ck:=(2"hm/4SZgtcQd(4o %l[6OGj;PeV&."%Z+JOXe&p:'E;5kX:N!u3Bo^^,.oXi,(6hKaq"9T874IZ;(jKDW:q/>iU^WBj_-@a-2rn<.^Aj$KZ*[mHsAj`d@ %r\,86`Qda_kuWmFO=?;=)Hd63Mqc,saH4b.gXOu1=I1Y]T]N"WSCDVi-bc`,6+4L@`"Q>YrTm0/S#lJ0`)4hQKB%'^%5[qlFCt8i %_UR!%a4VlG!)!jQ,HV,,R %s7s'gSNkp\2-3^Pq59kNfg@@sfLZF(U/pZ$\e4;e!^fb7d.lJWt'F3I5!U,U-$m-q*\e3hjZZ4VK)7%kZr2fcD?0UPkOAfUlHq^lGW&%uUq#&Ze* %WPAso\.+.cnrACX!5@lYU'>AR^tt %g3r+uoejFR5&Wfj?3PuC-B_??",KV$i;\dE?L2WLK7d1]hoIqZY4dgo`H0^.Wc).n#&"`ijrn@?4Gq[hd:aVmj(G!K.MhgLMMZ1% %eTr($DhH`=H>B][o$EcI2_K)`baoIqZ0M'VB3^6&l=pV!=Emk0/#aRcV27N\:g4:2-4<1_:]VSo.M0un"a#8V>o9;g$L%!/r)"%H %<'U]To*[p-:^*8Z71]dQ5m;@t]01`W*E5:Z3QEKQd6RqX5VG\GU4]Jl-E.kL&07FiDRHOUYF\O^:#;.%&04_8#AG)>1noW5[Z#n' %TE70UcA7JDJCE6,%#O2@MB,,2U4Xq=/8(:d6jH`YT\gq'd6VXA6-V'+cAc?GSZiBQ+?HHO%WdY+&>Ff'9biqolOo0?i,tuQ6Zc/: %B$a$`L?P933hlCWft1kY)d*`HK*pgmX8uac%P",]UA0Ba3iIQ=E81aeFAMuYYh(62d6Z;dMCK1b6.K.r843[tcs`dN88aIHeP[*U %KA%;tpPY$ppdVY`[lFE\UN>'MhJA,\^>Hj?k`J>pg&kj#A5)i/"Am+f*]o-_ct=-4SOC;;_.i5-O$sTuHBGm'b3#YR5Q&1<1B70f %O'SMDg*k3Ro/#4eZa>Va@)6$#Uf?,,^UJeZphP1I7W!W;QInk$J(%em+RJ`XeLI@-64pA#]Li?ue@i%-R!0]QX,uTg9P>6BMnUf:$VQ:S,E\u&e[K*\SGmNZde'ptuan2pQp$56aHm%U\qJtCX[0dCq2@GOq>k3rcQ<-h'; %g9muYFu*5A:`Y#S7df).d^&N:1*fTTd$ge[BCGSeZU.-aL,4)k86HXG+(s;][g<`.?U_>H0!'-`/j^VA4E=HdA=hpV/MKAk:%Kti %:7g("IVE]ulg&UtoDdFTMe#7l]U=&bl)YpB4_Q^@)@/'2`R1S\VE-TBV+sW>8fdh>Cn7#_I@:-e3mN53cuiJ3j;>,beijMG%5)k? %'f]du?YK@"cbUe6-VYqB*9?"qGU>1bb5*\bj:ju>'Ju3/\H8\+W#@GnVgRBd0lRJG8[9=TDD.M*#MabW1S_Mm*]W7*:()9]3>rLB %E3^I&_(99iJQ'ptQK]$J=&LDD=,j2c`VjIO``qp4I^R";l/i*hV*$o.R %']2jR\UHID>t[=5&&Hc'64'/C3\bCHCF.2\8B%6fYG!i>+G]C3Q/BF'2ATX=We1u<#kHHu=#p=IBQT)bE2H\98TAOb<6,,C*$L:3an-6Kf_CTV)_jb9k.B;KhC3W\,0UB3)`SO$64Lt";NSf*C=2^3C(i%6:aDe+!MS;A@A45K-?*G6FCf@sJI %4LZ<`+f4k=r?`qNQZM!L)gNc3_?p`Mf>p]=TC*Y0mn6;&0p04I>I#\3^&;`WT,mX:?%+aZEEZ1`jKEdAP,cXt=>cKmFe?(X8_qJi.,hn)f]S]7^-rqZAWF;"O!E;-l5ldO,(S^rGL@q?Ej-d[ZDJ=XgdNF$]n63$[;E %GL0dE%`+g8,JgoNe1Wa>LSuQD>M"C_p-IeI.T$"O@8+?sdR$aq"CE\FWJisA'0N>U]#RnnE0$f/S`!WkJ+kP]Zqdig6.\Po"-.p:*(e77qIXm:'h3cWcM?\fN(J*+ %Kqi@9=#)ZG<.Y4t;)4"YcN32W))u-3*,s1b*4p*UhVqCs%(u<^>"5*HJbQm7BcZ/k],g9bHo6RLGO5;^aD63-4?CT[ClY5D"jfjG&fCF;NF&e'$9"\J%+'sJ\H'nN&eO,`O$/YA&[r-A_ %;:MVDq88FX_F4SZd9m9lDqhl]mA@XpOV82j)[JL@c.@>c#DgjLb\.(Q"*6^&7jjk=?UFKTY(pn2=>\Crl,:#5O(Q-*#L3I<%0qmk %G^1=]S+Y"gD7P,1h\gP1C8I,3EFB>W29GFAR@QXi98)OIf%Cr4/]L,=Mo(NBlPLj4/dahg^X%DK+1]>*O2DiYd3=no!gb5qM@h&! %(]p$icFBiS.EgNM"YjAnn_5U)k:)9#)'V)b1W+'e6JlA#/l4];l'V)afeE^Ykj]@U"ml&:Y %G"X'gc$-P=e+#d1KL%6]*e9MYc]r^tT6GgK:8G"M!-HP4,(<6_(9W3jQ[SQ[XMp)He=5>`?S@?Ci=!dLNa1EGCDfo8ZH)X %.aOSgaa<%u]>S[7;egW:I6]S7WI].]$]23Cuo+ %PU@u>a_=S>S6e3Y9[:[HX/30S-7=XA;44_Wf$\jC/1/[gQaA:j-]&-C%jY^@d3rXiZC$+(W?j72?Y!_&3R]sd*g;o/j:m0&.S'mO %Nl,6@Zm7LhQ1laSMoeP"!\^(F/1.8a0b^DFA2-)u4fZMuAMH2:9G=_:N%?G/U64_GWYV:(>_a?or>:uUmEtK_`./if.HCeS#.[95$ng]fBN.I4WBZ7hgg=(r-pE`[+9*/VUh;M##NTW %K(,]U4G[:B1&rU%pg[1Jh`d\93b&q'ip6l!iSZUta)C3_5M'#,B\9:NCnpA/qMi]t8uq97n([/X'6=-D*oC=jOR&<-,4?Orhm2tmb6'`SUZ`#p9=BgNLSo"B1Hk>* %-00ZpD#_E@_#s(NHrSQ.VtpA\KNsl@o3V=EaptVe"@:Z\"pK/NLVd5"`m8,EN#jFW(Nt?7-a_?ZF9Cr2q2($FtXehhPjcZ %!4lJSRiR*9TbMhn.cB>1WLrTimp#7]e$E4O9f.*QEO=+[2UTnC_UCs^fgGoIOepB"(trZ!V3#+/1tdLuei$^Q-5q>kdFr7]9,2-3 %7IQZG&N$G)`n!#".iecD_qub6";2MQcb.:BkTDu6jT4ZZ1sL,b_/0YRC76,6dpOOKd2JBa[0@7IKAL=4Admhr.=nh>@`3K.lXK2["[;olD8CoJ&IDDQrQgeW34RLmoIThL9d?h0C[h'rW#f_s/4amXff(6Fi'b\/0,[)g-bDNb %b\X):fo=nC>5%B"$Zs1FAJ$F$:WTWD_?_i;B(&C]89.tm02K=/US]EiZ503>@Yg/siLLQie3P`L4e]lA\-JfU?V6UMB^%W@[:J\i %f8[;f+.>,1PluPR1b+Ecm&9QXKB9:j*Yf.+SWc@r#rZUodA;s0`62[*)_0UO11*4hJRan(&*/>I\tttZ\,uMLu(l[=>.2Z %0V4T=orr(c'2c06h\pfXJHqbuYuMtI;)GT7f30`%GCLaKTPn3dJB9X*Wd4Z[q?MD^@&[`mCm/qd&Uci?9/YhBj>,F?EOoH]CX/Dr5un$i4FGB,g.>oRpLmN-M1+!0sdB %IT<[3;$j_tgQTNs.BU>AoWON,AB'DPQ/^;i3U!e4PXk?#5uXE+.E:3(@$GYY!=nJfj,[itVU2X+o;4:Z^F@5be_uh*i+2S4S!8;fKLE`uFicIQWo-1.Uifnmg_92%u32bQs=\.e43$M'ojn2!2DMU)[_bNe]B-\lK-jfg1"CDAB %pnik<0I,adnRU_i`f4o`o0@h10jr"%*(\7&>[WjcqG0Kja>.Mf`s$4C"iM'C=^&;+9RGHnJtH0^"F"CgVC\Y=O]0TDo]lc5!]6e@"rVA"c^!tGV@9IGq#D=7%R%Mehk:!1pmEid %HMde.T2)`8H'i#%nBPi0QuiO*AuXL)o==1]!Y40Fm^4)W5%EGeMP0s398SiC-D\BZ9LqM%75 %cBtu'=1T>#@`iJ%,sB-J00J@Hkq=dY>"A!6Z)!dUmk;NS797R3dpI^`X/qOeVnWAHUU!d(Sb,::hj9W!l=>PtWk=QtVnW@[ij=qO %EW%2DN1iZ9]T#PS@fO2*A&oN'IsFa`jK,rUOn1C+J20"snd-mib'h<\iL&X %gj-2'lFo5,Y'=\HV@=#N"8q"'k."G9[$LE6XX-E$CkKV4&lLL<.,7[Ug/`uqegSCf1Y&ElD6.*A@0$/W=(s(;SrF9Bg)]RfSt>PA %p0_k7D8&+lUqTn1jUQZPW9?tlS;0^/6a`f=h0GqP:['9QW2)7L+)Tm7>slul8/)&u;ajfgc%H,u4',iM!9mXLb/7i/$rs!C2MN5s %8`?DLp;XdO/3I>gPg2`J0GWPg2A-/nWc>:c2A2Jgh.)'$Ca:nX23TOISW-#<0Jg47PL@8"1j6oeD&F8&>p+8AM[@^=i$_%sB+pk/ %pD(X"ANd_TCTLFMg"H7^jaqsO]j!m)cZV$GdrPoMqu,]Z2&g-#k-iXKZ=R#0f!4S2Cob/E*456qJV.GW^t:9FUSTOf!=kSdCGNl( %#tA-4h5kcCKJh)3A+Le)F?K3.OH)lMYq9%3d.A3m#$&qrWR.&=BPZ5_q_]"F%I_/&_m(r3fK`S-`3D%!nP!O2lc@A%hhm1j3M8k]6ZpbE %/5!;a%Xk@rd4>rcWXRG;BGU)A>,l.&ZtaTp.=,Q'e\%rBGR81b#0h*jC1]\,n,]^?a]g0=TfpKMkaDh %\HZ2Qp.lLVk"k%W\#`5PU5CGHplEQ'U?YjG&d)0$E&O/L6^6Qp9g153DQaC %M0cm$osJ3MXJh4&WisZVg5?:5U&*Keg2aX.c+2u\q5Z,T)^McZ3nsFXD:%/NQbVgC?Ce-ral;U.-e7/['s*)P?\N %T>M+?C(d7B4U#s'a>6uFm;ZWY\DaEoclP,HLE"P$#jlVAEk#g*\%(]2m;ZWY\D`mkHmFZEi&R%hE.]0oL^XH^[Qbf<45Ab>&^*un %3S_C^EV3EFaA="-;ci]f&4;"J@k2;Y.\"uI#1FQu4`9JZ-ku9`gfPS70ZP!dj2UA'1NO0t1)*Eu<@_p93=\!SQR%`f&<8pj8ppGP+7riLLbEZMRtIeTD:$^tA,QHlC\?\_StC+_QG,Y>(!qi0 %S;5ZuRUN-#eRPr(fD?smI!N3$geu7Ma,D>X4'Qj'`Ql3I!i,O"3?m^4MFnRi^3/3_^@XNKa5*U)h`NHr%Mdqp8\Fih8Mq6S]@cj&a#tb'p;!HJ6pU*).*WKJliI)C[D(@FI)P;&?TIVc%g2K:_ %Ne')&GCFIM]6Qm9hEWsYfI3o%2!(aKU?-:OD,Eha1W'./=jUdh,q],l\Yi]WX=!rhB0k;(ms-Y^Gl4q"HYIG)&`=J=YfIE'0LXi0 %&Re&7,Qh'r7ufaJhDa0lmnF<9q"2s&MrMART,.912@%B4Xt^gO4PHuSc-*qb^aJR9')m^DjNqVL"lNmD]f\OjI1PX?BX=DQ*m!Bn %-Ml&PAb\psggacjQbQI2NdVL3&3b[+QH$agiYQEH*&dO4NokElEjBfeX8Pj7I"2GLg]($?5P?#iNF2MmqF,DY6/6Y:-QXFQjfhP6 %Vk"@^?1rP[oj+DAbGuBlPg+CO]Y_j5p_7OYKZ-%q?0r+1d %E=X-6cja[IK()KJFQ4QW^mcGhI"3>O0[%?uI"8_ToGr2Ei<'3;KAEq!i<*jf3c+Qk6-SQ)UYN`l#\""jC8'$bR$aR?Sb3N&N7NZ5C@u(AgCMMp].S&/r9lV+G^n,jq^,l&8l?t`<:s#K@1h1Ph9qjfS:%M5!TZ8^qTVt&"mjsX!lRA %2uPt.E#9nVg@M:c?,>R-"Iee_)F4d@5.#DhREf]O%^5!VLH?p?FHn,[!8"89te]&1',Z%`c#d0!K8(:J[i)U%:*2e(IrPt`n:&+/4u1^B*/h_DF0EN(ZnC(m8? %HM>k&fAWtdH%YE %Pn18:L)4?tQN$,"!hRmSi;JJ+4UPp1-QPptL=)tHZmL-1C@elQh%WCq`.5i\08SAE2pq< %[k;0pltk)C&hZ@Z]+,&'70U;>'[l2E^rl9Hm!RAu!PQ!d\01KrJPFL54RXJh[gXh_jUTr[Wt3XU(!03/D(r"g_&2)RDg %d5?#a!a$bMm6^UMTbBZ#S$fuh][GFYXDS"'0,k?`"5YbsmCl%fkm`c5F:,qo-mrq>Vdac#0\h)GrB %&TJTdB68RTS*XKfhd9[H+4KoQX>?Ttol6odMQH-E]V_SSf>4TkNt_jU"/;jW*fod%C0/)%fFS98KCLlE&N1o9mbhtNK&3&p2;O5o %2C(O'*_%FIKkonVeV/*Nc,>.GWM?q)^M%`$-9$kH4gjlMS%NU`A"HXjJ+kP!kGX8-RPqt%S&L6VL5cXaNj;GT/@Cs>#)m\V52gJKW3EZ]KM\apqYE5'qhbl*=6e8qE9m0-[V0Jmi^gki6\)4\[A-0](rA<`X'oF9B4nVXW1fIDd`j4.9*G&@/d0%u.mLlSY8]Am %V)).\Gq'._UYMa>V#A?UW+OOa&RA]j:>u/i"DkMlcI!0,h>*ku)Ua2@:b!+IM8oQnAiRg;?CDrgY %bU)5sRTU#ePjU3[C)NQ$4%.!2=bQo"80JmIR3E@Sk$;r%!Zja3fBWnDs9+'ZTnC(uBIFoE4B;Q#fO*eqDI]HXsIda/K[(%i4ju[4Q89!Mfo3DoOeC)BcA*GG6k-_5% %Ku9He6,00pfGjijXuQ,r/sM'Rk5O/\Q/e3+9:d-j5bM:\aXB*:f.s*Kl#G;,:,$'QT1X\;ZaGu4S"OgoqDKFM71]G"_0]`6GHDit %q\D*&BU4sA$bajU?Dc=+D;UN(f7EoB6U=\`4urCU<*)_.er")cgC9%BOkMkm>pMrf=,mAK1>+^K9]'hq+rmkRkf^dIPh5r24. %QYZm%'q8C5gVlI-4_SDIY\MuX3l.^],9"qrrjpq?>OU?[ZHsF%GBgK#$I-_^]b9)V&kJY4,MfUcUMm?R5MuZoU).5fhJ9UC.5Sub %%L,G`n9+0AQMm+t-:'1"H:%(eDL/Yi6EpBh3):?dC7).VELne>>&bCudfh@n7]b0(C`RHdh@I>5dipn[Ge,ROJiHPm,SPZ+Lo8FD %^PKt'YWZ8]PEC\!$&>Dd*"YFEA[/.+Dj[9@XGGm#dSi"+(NsNh7,MKsE'*nu"@PL[9"#j#B[6*ZBd2I3"9LV7L9Y@uJKsWU0FNOMlX\@d9 %U>T'!6!^erk#NfgWIJ-?rjFT\D.O@3b+puV %-UK9_cE-MlW.96=-_u?(7"mH8;UL!hiSE":hYS@"9e9"54(qVW:$7f5=W&BaZVn!_r415t>^`LN4b'-ioQUG&[H!VIc!fb]'%+8I %$d$rIG.H,k27M>R"RXO\JUk%XI-h*X4lSigu3+/+no``5e%)Uq]NT2m90FXRB=1YB'/2+:W:QkNW?bAgQHE+t!=WVm+h*#HE^$jcB %;;P=Pp3O!<2/B<;H9om>Pk9$lU;](:Q6kt5*A:823b)Wu(O)$KFFQg]DF?!>(ZZEl)fYrcMtnog-kGbr9U"R,(?P@)gp)^IJjjsd %hDZ3I*l7rC*8V/mB8gm5TKg=ufAa2c9249ENOT+NP,H8\X#!?LTGQ@J^a*"[+=]*Q53iBYG0Xdk-CGG]-$5>*^>eo:J(YeJUC!882q#M %%AYA>d(&/+B>LJJ@TngkTWX>!dD@E[U@WI!G2+&g]qF6q1;\Vl^]I<9e!cdN=6E1a,:o2`/<'#NBnEUGJBU[m&IZ\LhRLmt#X:R$ %aV^2/J1UYu`4p%Up&+bK:(>:K?OA',2BXe>iFcTKb#YPX8Tpbh+R)uRRZ(5$Fh,n1cJ&T]aV+r>2a0$&B`paiMps+MRLHCt"@==T %Q0:&-K\;N>-DO*lo:sFcUf,WOGZ&PpAO:&c092)X9d[66a.gZqrdB>PLD#SO1,;Q.4mt"t/0msP^e9+dmbXEVes^(1US5frd78n' %/O_K6Kh^L'TueS5,0Gqpdt9/;dUY''HNmQY''Qs)Qh`m&\djOpcjUU#ro*418K>^)4c(B#g%!FGehOGgm!(oT %>gMEHfr]]XYAeZ,=uk^I:?q[Dj9(j`Qrn@#,RY)pa/9n4,(t]WA'b3oA>.uK3$/^&Z)Q^KdIRAj`>qZ4Hg#iBaQaHXcAn[QJOpOf %cFu#;/8OSbDrO2:-a6WUG@-$n_bp=l_Ea[7VHT-)WVKQI%+^/j:20THO`%KX;#gltX9JM'I'AC@,D24VFIlO/#+o1^ms/TN%fh/&T9,ldQW9G"XfbN!s4?]6E %Rt=JR8k@i5FEO2dT`f#P)`4i69"SaW.kX1K;3Qf^coI!q"hp0t%j)2Ech$=*g*>n!8CO"9HdGWJXJB#q4i/r87M^>'ADmtqW:S%' %-t%oc8ARZ7O=MIVUUQ]I16V@9YU@>Z^/dCfkF4/C.79+[LL5c\-BreK9\INTs/;sClBlNiq!+18lf %QM1G0\jis,?67,OlIgBmLh"Y]*E+N%OL):Ma"^RSmH!^c=)AItdlIOK__-Vn'e0&YGYS`u6m#`KP^D1([/f;?@_WVo0+Q%Pp1lU: %[m%P=m$M8FL!ZC7bRCcJ69)60OVsV5$OmAJ#i3U",KhP6;Nf8L%'fCjOrR,e,\jT#;]CFL/>qE[d!)0rL>ZW#)-K_N$\8LG@UqJ& %04aDs7u8dpi.Z8*.8j\:"YU"g11GYG"YXD^!_0/MU>U`u\X8X"@crH(X3\]mZ1C`BJpb[K&0B=22Q'sAe_N=m"+-mJhWlC_uWoQc0B46NsRX64?Dn-09,lMn0K#c8R/bS*[el/_`/dc^n %:rX*\NX(DX5tCQVL=D-N\J6uIRV`oSkY>H_%(spk>1Cl>2D9`t$SsTWc3kL=RS:p:4"l9D@a*%-4"j!6WmEFem(AE*ZSOt?:8`EL %YhJ!;hN,?t:+jL+(T3I`cO$^-S=ND]4su3!e&dN6_C9,&SPELuP`lpD(d10$AXNG;S>.G;T+bDK3'3\DHqrn:E-=9fq4'^H`n0JI %cR)LO^DDSN;*[=(i'9P_:L%9MT[bnbj)dU82-_7Hp,VsAo'f?&5#`+,(E3Y$^a)AT"T2mnKuF/r@\8iWEQ?&_jQ1FaeI>l`PF'T% %4YNN2!?F?OSUD.g#`*C@4S?,Ed:6?bcJP0O']+Ck^7I`qJUmOl6'IFr>Ac<)"k]B=JiD68eM,^O-+/]b1:5kO9.=ZHca1l(EtYDV %C$eZ;7jO-#U_`<#:XE;$ggaqU1h-O'fUW:G$`6)gFshmk$M(i"YWEGmQC^.\hB]m"&kDh[(mMg$(\g&H:2g#!JZD%n)9&?9-mLL3jdLX]?.&mYIR]<__Q_Tt&.MFBJaZ;@#:Y"Afrsbhd(H#gAl;oQMUM;F]hdX]9])ns`NPY[C/Hgb7jCkBEF_j.,$JSdLFl>bt"8A>9uk %_/.4+\rL+:$2/sWr)ACW?.TI1a/A`5/KS,"&*?P3:3tXP>edM2.Pm+^V-`O6!)[M@&>Hk_411bo9<[c4\kL]hhd6Z-1mZ>eXMg/8 %^\Cu%E9;KR/Rb'8.)mm@<71N'2GP.aLLshogJKW3EZZYr\CGsa&.[9U9P#S-RI]:[;_l-k`$9RoZV2*>rS+G45hqjJ#s%(dh)bDQ %p*Q5Y3[uS6A:\>^UU1KUKKq>_))8pp&828\m-44o[D:DF`ib7_l[,af$.np'?S#0-DjmN:=-=pb&Y1ldHrtS_(uM$<8WUHS\'rN)d?Rb;27"TEI*g\VSH$R'oj0jWJ'V);r7$*lJ=Y>f"geI];rOS[cF2A(8DbA]]NPSNE%H]6-AL6/qLo/ %L(3Hb(I7SXk?H^cGXB8s#;b@s[)S/sMg#FY`-gft5k60i&PN)kDWYa[f?0Cp0mq_X)]5Km2T^%)K,qO2hu\5JE6omeg.*rKmW".o %R?9m)Q`s8^lhYIl9,IX+gd<`_irqg;"T:_(F?r^Bdksh'5H:g(%pkUM4n]YtKmZNL]o-_a)O2!nXo<34NnX5shE=-Mj^DQk'5k_D %g1fQD-;k'2g@oU1i;C0Ybi9Ss:Fo$.l@-V3^Fc5XBgVL%$2\4Vl+.X[S6ME.&[HUFq8h[UN.jiS@$AcB/KC5s3.tP^_=BudJH1p2 %NMX*sL9^)[q#o+g^n6+O7mc.(/,l4RKR+,O'a01V&F):6?Nc$K&F):9?0R(rS%A.G1"W*\R0A?4lT\h&]NE_K6=9TgNG_TiKOglKEi1f?pbP9U.Q`&H#^fZ3S2+jI/onEDT!UGDt*&SSb(XgnZ.&PaZp?$HME3LDlZYp0BpO>uVRZ(iPI@:<@/P1UAFbj;Fo/@#*MCrC)E_q+?In,;/`o3sg=Fhrqr %R)]7bF^)5A\mRrIkUh'nl@Kan\GKu,;`Cu%rboS]rG`&@nd6:#[c,Ur8[\#Q+1@iO\qA<2RULRNW,"g#H'IrBoMdmCcbFL(:&2=o %HfUgrUn=j))=5i-r4o%r7Xq[FeU*-4M?=,NMMLpeMjN)EW"W8UTK\8#l%gk)7b(p=! %7o>@FT%[&7.n7nNUFbmHOA^1>F,5bTKrT@\#:.kLA[MH0j*3@WY@e,L($<7klOam6ZDIF$k6j<59H5mIo %Q=)$hW,?gCQA7f-,n1N!q'X[Y`WJnUDoSRUs+&Q+Dno_Q>g$9tZF4a^*EJQVnV<[fju3E$@CWkS6p\6+6?2u?a+kjtgcB=[5'M09 %61iRLPZ)lD@/$O]6"">JE!PX\3\8eN9u&Wa=3=5gCSm$=P@ZC05O_OmTedI_Q1IhpAUsb`#0k[I0OMl*N8!$BV16Vs?f;uYZed.% %$RqTuX)D[d=7ABfhARZtdVJ$05$m8uQ^9G;mdK<+QE*K=DHc&V7FAE1[B9m8\_s7`G]!9D"`rh8rl?Z)SuEmS+m5ZYi^&D2tC %ob#U9,(f,>l'!:^a1+Y4iLi@jWKjkYWpP_V]H0&G;j\s#RQt.nr#Xlj>285e3]2c+]MKEi;'\7[OU?.9Y*3L)hh8CmLljsSAU9G+ %j;81Jn\E"2Sj5J6l.7%o:*g^re;eC7OpSnH<2%o[:DZgqad]2P].R!dkU,$[-h` %J1jMXs/XQ/%-mI5i60u$`XeSt2t?,Ni!6ti_rU5)7L?:(b9J#j3#g[MW92[gLG2ct60ld"Q?R,I]g!8a*IXBsb&tc&WZ`p:g'1e[ %n4Q7n5T[cTFu!cOFh`n7;^ps>l'Kqi)H_#:,$tE-al*jZ*/55)B]e<@!/hEt;eiJ+^\o3*:\%/-cn(Qh6H921K(fkjTNNs7[uZ!g %BAcDEl`oJj2/l0?L)^tc`Q0PfSNaA18o-Nu9t-;Wd0iW=Cq(LKP?9G(3Di^[2r!D2:S9!ajRn^IisK+RPPI<% %#[4^+)6Yk'Y[j:AL9-<:)F@gf1UMlflk^%$K[kF2O4VIV-0.Jr)l^sGGq6XU]W'@\R,OTr[MY%gKscGVG8"Doc]ssQWS`'1$h*-t %YFc"1#cLJ=+bR!734K,'@0G0P=$oD#_?d6>ZTM*AY\@mB,SQj`66[W_D,1-D[[?srm]YqYk4**X?]prihQKN1$2Z5%WMf32ROLJI %Su9iO!tk?SApU&+k%*1&4N?04`F6U._?8Tt>oFcPL$(&;;tmsj$?_9[])TUD$hZc!:C0s'a3$)HD?QIaDD4N$bWcfT5`1tR&K.GW %hp`*5-Jlg@@#?U.0f/4-^_C.;,0A-kM"ufo'UU*"b7i)78MWf'_T+GF3]@,;$f3=\P9@iFQR=U`nHC@BV@!j$id4BGShS,"V!)ZS %iF0n'b&7W\T&J_i"&kFXA_>/_[BCLe1?2%ji)h-sJ.tYMaoeN.+Q[Z1Mq;],)l+VS1'(=6::0kHV4Ohkdm(V`WLE`@<24]5?l)R^ %8)4[W$[!7Cq'M$V)N?b"Z;.lera<7CMGqI,l?"0mA>2mZlk-qsFAFd@>$p(Gqrm!#=EFf1q)nZUSsqX])T*mCh'F`B)d#G3.W %Q=,/qL.R=FH0=\f6t08Mq%^6^+u46Xf8"KUI`6,iMor7,o.*S]63qZf'1'T((OVr#ZO8Q?ojLsr>P,Ql:6Bbi]Ej3D(q<,B@-Af/ %\_)[E+e">b6PoZ2TJbC)]&`<0+!O\sHiAdA%)^(=9T8DX^Hl08fkHC,;$-<':lMn>-g-EcEC6>0X>Ae]+"f4cH1$^=>H/cq,LM< %r/OJcr]-*5VM;:t@Kdrtb"BF^K,tb=VhH1Hh'-8]63.%dX2S#+k-&4bqeuhU>fHsM[I]ho2-Q0u+-4)]aTF158sN5/iMKD/(U-6V %6k%)Q?[A=$GZXH9EHu9.#`S+HEUBD( %j>>+/*);YOcLVBu;pX?nj4*%,3!gOu$1)Uj]?\I<;kdr(NRFXQag>ob;7]_$r^Emp#'Stt2V#E0Zpm7RKU?0*H(f"PNRFX1)A;H= %bnEf82Np\^jYM#do5=,MFq"H,BohJ#4?Qno[](%,oQ,"@mD]?Agnl!d9@YQ+@2_mK7gV)?7#r!4P[MO4.,MUg,DROrj+N_"J=S24a%>IWlKu)A=F/YWbUYrr %<-ZH?bprqo:!a:^_/Vg-2aM@:cZ.amFE=PRbj86dBhMTRlA/oVpJ&=*Vf5K#[6+'XfG_?)N26bBZchlu6l*-fEQihk,$#2E,\g^Eq:dXBZ"&T&4fX3u,M&WAh/F5U2m]@/j2T&GjlTV`:#jQ(=B(,O-_TXpe48f?iIc6b'IBNBoFBo61_Y<3gDpC*p4HhTnHi<-Ej>GYg^;gWW^G:5`>6Ynj/f5Tn(pLqTOJ0k %04=W8N;\cS>5S\b#;;i9Ngtl80XFG#ki,"Q=5.j\PmI56p"FV*$G%/I)u&q`j[%(u%d;@mhi%jIP %'Bi:BV;4=nYghW'dS)YOW/^(t1'=$c?A,numM$S:F;h-&Bo`)gUXd!j%s$uK1Q2&djW#i@\Tm1H#-X=k_[`D1X%b^AXt.#r!4o-J %FQ_``U=EY1D(b'UC0gMHjQ2TABj+1^68l=3l'$\FmH#Yr8FW+c?S!*^$-"?=W^_)`&r]Uo]&8-9]^&@K91)$-"?T>Q`L06FckS&5"W?615UNKL2e5n[bT\b_f6`8rQu!XW]5rhk+'0*WGEc(ucP7m(.WV,tQBg)7A"4osO)Eo:-'iIGNm<67=-"4]Z0=nf*Tg-A3!W/9AF59OX@: %rT&l5fT56M:\8pKMNU_ua0/50T-qgGauh.$5HHOKKT_sE*6]dZ!B#2Ugj;#LdkSqcdf$BC6ZMSrJRdC4GOkZ/Y>E&"2I1DQa^/hZ %Ola!(7E/fnku,;`>%B<7N_M8jq*sea2/;290#q\O?)&'LJsT'KD3-?MXBY04$2+a/:E`# %Lu/L&)mH&Yi]"!ESOcR]HZ3()&2X*TY^3AGMVj6egs#-E/:Jh>Dg:H&^\EeM^1$q+.=QW3?)/4M&[sPA:(%WJ&^iU0(*\3sXriQG %IY3hFFgg?XINq$;>^ZY42ZdE>G#X"eN>VV%Dd4]M'K5!37f5_Hhjir.*5uhu,GJKQ@r#aIgF,\"O%NsX%a<$A2"tiWF%!R.-?/Ec %g9mIn>5Ui\hi&m_hVpI\qW:W09c(Rpj10rW`FUH/8MVkR(.Jd"E>Q:REF,3]/fkVO;g/"khJSQ3h:d)!Z.,aGV+L,$: %"l.7A'j=+_Z0Z6$"LN-@9tD36Eld0M-:&Ws;jnc?*)R7pf`i[PJiGPHJ!/:5S1%2B+/joK14Sd^5VG*,!l,V#Y!Nil76iNqM$JSb %GV9gWB.X+d1`L&[PLq9G:&&3j1+hf+Klb[@21er.SWk$q'aMI(7>c%NP?U>:DqK>;=$"cS]p"NHeg %Rk>2f]@MQFR'VcL*!3J:Qds5(!.ifZ$7JnB+YXjbl0:Ph#gC:q^fX;RY^O#u<]C:9kd+jY4[7ZNR]5i^)S08`+mDYh#E^jF_+m;-T=[(=e'o`=Ya^eLX:oEJ;JjkZ1OSL>i %cqHYFqC_,)oRpgB'rI(ko=;?5`O5,QZ;u_s1t/YB".T[KAh`hg^f^eRf#Er^mXT9*@(IQ!LBt6Hd(P:?'5M#[#gS>!pEf@NMHdW: %YLPDC?7!/;/Z`m[-Gg$,9Tl:e@9`(d(dWf=X!Ms6N1e#ZmTT$HfO$0V(lO(n_?ddWBdWt<0S19"3Bk_V(dWd?a,iLt(1.D?KFp&. %Y(>b2KFp%CeBBOk/h%DA6RR!`,![7ZG'\kZ0`9<=b$d"Y/20;V)[sV,%%Jb5@2RV1Uu2Xe8Mgjn+O&\<('MN/#h+&RJM7MM-h&>g %+MnC&/24VGG*'j0?Jc9YrqSmHbAIht,)d\qgq84W>(hW"[>c7?#'clD[Z2D$l':f*$pfLhPU(bb4'+'Gf@CM1=jhpFn7lZI,HREl %BdeW1:5'I#&P)ISSg8Y(d2Qr)m@p6+n)mc5Y4DeM;?i-Vebn]5UZI3;cu^F_#U?R>bDjf.#U?Phk[=T*@Dpk(I&-feN1e!PW=jaf %6Z_:-/3R=l$0JqJUr4nn_O(#&RO38I62:"Wk`*e>$A-.<_]]B(2[BK"Of>&tnosJr)Z%Y=7/)#rYm.eoqA)nR_:<]2jR"0/X)<+p*rW2$mrd>pjj$^Pi,UQoh\>K&1n.-?` %CioH]n.-?`fIh9,M$Os-fWH7eJl9`NI;V":+7NCGWPFJNr'9.UEA]\M`RjRZk`4Q#:h5K2-&]Z%`fr'(nki>LF!"]$QAm0sgb2ko %e.L.Nal9m4@1h*/WLZti&33tM.p3j)&";22f$:i]boNi@GZ)EYJ.qj;mYt0c+eE_s/C(SQ'UjZXF'&&e=13lLS9/;&J_6.b,b&#r %]Sp-.O-Ok4Kc%EIRD&QTS^2mO$SOuM&Z^$b>K7\rpOhqfaF"cip9:tIZ1D+]*6`*diNpn](E5^"BIt#;6@nq`bZO*Q'J!kqh1kqEsq-g?&Y^"RCURS>*2l!n4M3B6F14$Jlai*Eo-@=GU:/#?TrtX %Jle]'eOn?M>O]edOW([d("^(78_*;]$bOsk$=8RM:,_6R.X6rET?OXbL26+>jV?l]n4M3B@^RffJle]',lUrKU;:_qglbY/G:7+Cir.4Gi)a\gdRi]in`p,M+kq %%sR8!mc0d@R0[)JfmIY&`[=Q,rp.OYfcLaXb %JLek>O3hs>8&m6p[;S)ZS#sQDp,?/QAdW]$NkV.`dbEVEkM[#6,,tRpEVoeGm)`UBinBB'F7U?UoM+T;?fg>u2pnfIZki]I=ho7JLe]/%2:?]]m6qRC.Q %H%?[f.jMnF32u/XJS0L;bB^o51,kT[44$S^@>Z^/6.\PA3Nd_;j8i2,6&P))hult`$-t+HqeZggYh&\V(KA*!VBeH*+WiUeK2.U04q\X.fj.[Mi_F!L1O)Hn!!4l+2K(mqMGM2&N?+h_V:+?,FGG%]j\mK()@.N^iTp %XN:jPURAUkR"q^aMB3t_+oFu]aWWo@-XY%hjrh*mDP`BY%cFKTP$V!'mgQ4[!SkEMd)>GcZCj7QBCY=4)H@Q>e]Wr3i^DXJ\(aq= %&+]nE/Z_Y,NRQ]2MZ4&M4%A1->:mLA^C5E)NUg %SHuP8YbD3c:;fXmcb9[s'N%<8XitJYAj^Rh<\LQARW[%L0M_17b@h#D3lKGj(OZBAU^=ROW %DujnX5q]Bg3DMg0Cm<6.3+?H %,/5Ru6%dq<)V5/1l3k:Y1Z;2I5m:"<'Jlg,0*2*2A[ZBj\[E%\Og]#$e2;"R1^?EBMNBPphf9VSb %CHHd:M8gi="k;L.:P]_;i %Rdic*YNW@5fbVOaQ)7edQdMn&5`\Mdm;rca_$g3Il.ub,8[\ul)YfF&C8:X!bWn?9?A,mJ?8@A?SJuY>h`oVW*q[[Z!.e9h8.G&3'hgYD45ED?)a0qq3DfRJ31V:H'paOH3.L6qb)jJqdnt2/u@lK26LKQL5#9B %eut,_h8?bI6m'A!!l5ZbQ0Nrn>&-"iE&Y+d?W5AV0;8j#Q4rZ'@?9X.4_uMiX``D*^6Tn_V5hKVa1IHAY)FBGhVafS:+@7&S6VKS@'6A;Sk!,?0$Dn+/:-E/0T.PQX\Y85Pd-)97/[*+EH*Hsr# %.UCX:U-gEQouBck.!H]FAhICZkl$+if_m"dBFWkSFWJ.6;&FppCS\D!IMWlBdY"8OXQ'>e#bSbI7V`^->-ls8qW=qREg5X-g1Upe %Nfq%M)m'/:`,33j#.'RP">(C]'hsV)dDH*;0$jrFDq:["81@6L0<0X:Q`2JG=8SN\g.KfD#07?M!@P8=pb)Hg48l %EV[0KbMsW^YWfej$9FS[=#_=F8i8HnO)F3EU](pra*s,TDZ>$a\6D2`Fk7-rk-g6bf)sh#Ip9U5*\@?>G1$.j>_[GfP;^V>:,8/H %\h*H6"nh'So.Eb0AZjKMZBArcorMl_R0mU<`qs)d&3DNJcO5$&C!7,O09k[4n2"P3(FEaMSJQkl)II)i(sDNU7D\TT`=/0leVb;S %kCrn7q[YbEjQ)$A8Yt@!gcLC8bRjXcD6#`8j_[](OIk5?1;f3B(P6N7*Z9^K"/Zca).Mc_U_(`]4"l8YI:d)ISJSU(0FZ/:4"l8N %NGW9@FA9R[Z1C=GSt/fnSldJ82?+_l[V..=(^FTpBT\]7i0k+R-7d3Yj30Vi'ne:W'm(gB:Uq0:;+7'5>_ %2#1d_]!s#)6A=tr4UoX@Eh)TpPkV9NHm1tOFr"P[*per*P_ln5D6:!P0!ag,iuK\6@=._)S&Z,SNX&.X5t==Yc.OPe4n&%hE#f"N %Am8H>oWi@".X,(Tp#l[4_Z"T0c5&go^6($mP%dmUWjB:9@;g7!D1+HJ[CgN5^R/fB4h%!+A'p>\W4>Ue2^Ehqi_XW)k1>`L,mHhK %r9:Z(5j1Jd7kKBQH0q<,=?RPpR`2u692#)+3Gn1jY.!j'LRsjf<@s6qP=@-NGQE0SpEmm8,/f,:H%)o!c#!9S\MZo;BpoNP1&.D)WEW?CCD'BY9"!b=N3PGJ&T-B8mEeM3iD8:A-NhA:_%Np-L?-BH90aIu[H3TPtc%PX[B1TJ4,6-k"D1 %5XCF)W%:42AcVRhW%:3g!X6on93`3JJbgH^U4AI(2i6O4'#bqcU2Z2OhFa'iRo'A(c`BQ2U9NC,<-Ztlf&l=]04-0V!X7k2;-AGC %m=V=Nei\7PMp(q.o7lhV=AeK%W!)J\=FF$^hrX"q*#9qnSL>tek,tTInL.C^`bZO"of$-?iL;WppH_E^u:CW2dL,*Yr[O:sM!`XCuongfmZrM?q:)9&tBWLXpIcT]qJAH"?erMgl[uM"-'_oWqZ2dZ52/kcS %$30V9"r8!7A:3s.rj1J&U5VlMKr8]#,9*8PW:24@4#j2.0IJL$puH=#O(NcCnMNL=gCs3(o.iMsqU/U1Zd3$,g1@1k*#[QuR=[&F %+$7.^ah3R.fdBSU'E6Lg5/+hf5N8/-dT\>ZSI"7SW$LkOoG2$OJ`&kml)(p*&5ZDB&8@K?kq,!G?737;fZ&PpQJ,@-916F"-rTB. %Dg-5IdTY!9]\L`7p=n7l;QJAH02?"?j_EqP&56hAf-U>,]h,>q\J57MZ7S`$kG5N.=u0155g0"LDR)#J1o[=X#ubN>aJ9T?qPM_F %Th);T^.i@YFdYj;74,FD1bB'U'qWpT%[LFE]P+FgUm<`@"OgP:8M,$iVUJ_28M/T^Tof@F,IOaSQsKt6P15)J!4l^U %.&7WM/uI$"O\%,THZ3`*?PHCR8m<(/Jh'Vte2,c2$E41jn.`un0=-?\Um@%[BTi=gOBPaL8j3)!4p3T"?^h6YC/'r^)?5%'0@ImW89kM\9T]`ZXkt6CVEScC.1(4-CcY&Y9oK&RJd65TbH14rW"O`ST %AuYtKT7q\bN4BSfI$PHj=+[!hK#@c2>_s#>Q6`f@ojRYI_p-#^/&BMD;=3sFk-M/M8\EuIS*3o_g'\I/?H&*PN#eo^eRDJ-FZuiC %a>bS.5TfO*A&nj-*jDTRc96=$m9N5%.b'BAA>#5#F<* %3>eAB08/b(5/sLUpVf$qpbbQp_tU)g1(k*_o?c'W#<+,f<40Pj$Y%Pg$8$nm[WWJEZ`p>Qb4B.B6FuH:RM6*#$0h=@/lLn=.AG4= %'3rAc.6\;kq?dnmo4.qPFN3+3;#[Wgd78,?]9N,F*Y^J7bcac01F-VIJI#F[cb=%,_8-QV)2f3RTG&q`oVtiREib=aKp$nfe,X1C %]o^336]5`4-n<&`WJns?i!:@=$?ag!5Ad>/-K34o3aQ\(7b,1_\JR7&'r8j`,HF*&J.Hq %_hm8c/.a08o2oVt%H?R]3/ZT!LuWO.nIrYLO,oj'buO[25TKE%_M[6.W<+ZiYu:_6MVe\qK@XQFi]#H^T1IWFkbLuFM+8/m&K`#V %q]`ss`'e1ds!VT6qgk0B*@%(;ushJk2Ol1Wjbu!FMN+'[Hh1.KTr4'[m`eDtk,ITV=k9Og*1X0E5.W\S6`S)^9(1kZnaZmbhXI&Z %^]g&uW/j2e6n!5'(g(0)X*W.$OZMj89T_rhDRCI"uJU+tLH"aX. %#3L?q[$hoJ:PT>%ZVLKLI)S:A`r^'QFC]2_Spl[e/ncM1@W4q-AF('F+"8[I'*S4ociQZe.2*)nr0Z/I(1H8Y4T,&N(US(jR5S$D66fah_H64;r]N"9^I#gIHZ7rR$kORZ]/3?>HYs79k+c$VcJ,]F6URZpZlJ,9]b!q41nCM %S,&?"="C#SV,&(jr5H78(u@4UC!g@es.)>.I];Z,6,."%#-+`Gm!2+g]TreMp)!(u!NtFk.8Qf+$9l4t61shi"5Q&N$Vm`>L9OJ( %&pcI=/g-p$#0,IF"KgQj[Q\SCVK]<$9-m4jdh](,goVUHk?`f]n>'V_2brrntL#2W.En`d9^4igoX3`EUU'--kmK\rX %71KXu.`E"5N[Ms:,JJ9Nc3DDAZZ>\uDs-?o\QcVbli"CMaS&4>[8/-M":dMW=.7,Y=Zbs79B-%B\i4,(Jq(T#L"G698D_Wpqh0:' %Mn[rPhKh1&J(QQeh^$j-$0TU6@]=JcMY"<%0*m-+eoCTX\[)[W/K`eB3Mg5tmS,#!$l?,b$Cc][?s7a$k=.`]utKtUTsWNK1h=h\cqK@/\rB>N+/@^Pq"=]Qo:+!cSAcaIZ,$a50KLf507L.iNjdiZ=o;N %c[tT=+@_8"T-[Vl!MMr/'RZ4!Y7)r8UYrI(3O3>ELX2Fp#-YX^F=#*((<,HPCjn.nS&WZko:ZZFk*4@0!"s/Dr((.//>h/3r2WP^AUA;9kcsJG8ma %-AkSp-tge\n4@_hP#)X&-`e3Im"l4\Mj$?"gj]t/96T5UZ5C'#i`RMEdIr&X_Q. %aau$fZ0Y/I"]t13-n2GrMh9ILAjpb[Zc/(V[Y(b)^$/a;"g@Z!l+2INq:t$'rD;aN05,eL]KNC2Y>it$j&moV/9m:\Yg:Y5X(>1* %R>TQhBrc!HrgL1b`*kkJ-]2CHl8@HfT<).g/)Kq_U=\q^RS8i@hG##BH>kQ+$gtUg:+.b^6?teFQafqA'?X$,'^+I]K%)Q]3dDP1 %&u6;u@m%D-_.suN@j6eS#uV.o^dECTg1RIs;>9[pE_\o88[=H;?%UQmX6'*0pN#`^,o8p.W4I]&`O.8.FdMsEmPb2j3e;uBT2Vg5 %B[UNl6LO/(j"#_'rqb:d&I=0n]RCg:^VSGbhg.hsoZ%j+SgW:_K[s\io;)<>VWg6>\dE?sn')^)S4Nj/i=jrn/lHkJc57@N&r]Uo %]&8-9Ht7FUe^5uc*MEVr'5MMkW9fP"*bN"M%]@SK#"ca45-hdSbq/4e4.JXT2(@8fT1GI`8h`F8aR7t7]pC%/]f/IGD7/n7iENNC1O+2)kiVppa(`R:7 %DH#BK`k15C4c<5qB@P8RqG+beqehB3\W=ogesN,0@=PFWI=FCh+;,YYFr\:E9Vf=L1`+NLX3WXe^4pRgl]")+!RJ6d<^C,h!iD:1 %F^\+=mA20S'r[@-P3cB]'Vm!Ypr[fIk83a!1Q+I38htfbEE8PZ5NFN;+[em+3Jq63%+peT3jS8$?/VJ'"*M1N0bC1ECl(JML<`mt %4=)@$)9+>d`BYE.A.i1W:,F9Mde',!*_J3&A7N>G1@\T^_SYaAc\/s_afoD?hoP,Sn3O2q.rr8%;>,M1LJVXKf)D^F>'6u-q=3+dk5t,Sem*nu%((6[S6XX_ %m]GIeIHV")&U4J-:6(P>f=9T(%XWQqb"8d!;jXbEJRB>AqaFU*SBWb'C.W@QfQ>Fa%F2E,=INOsBlLLt#4n+)L8u@%JM%eL8@#`^ %3;\[Cb_W2S3%nn)o7hf6Th9sDZeu*ol+T->dbpXN6JmK()Osjc+,q6sR?[r2n\1YQ3'.KXr>%I(Y1Yh8F%h4m^F=%WR/F*ldbmI\ %oJ38Zf`S?6>u7E7Tp(qC9nTdYi$;H1)Vi7f/gLnOSrG%aJUCj!K`Ae;KO1'#I+Bj`Fd&quH(4U%LN2X(:?71;9!0B4Hso %W9[qFO>:fC*2`oIXd8LEf#k16D)TnMDn/7`l3]MFfC@4+#o7XqlaTmCV'6>EoNGFGj07f!lG[!\T*Y7JsU]h[^aC9bG,LqoRV9QNana9'3drC]c;[&Aefqq8R@=q>?a*QP_YB$+YEa(]#bJOD>-"Fb(QRq#W1*r7mF: %oNm&@P/[5oCqta'c$;T-?bkckT?M.]2??luar)Gbnc`:^N:DO*^=Q>I3C5?*^kLUP4efTE14Q2A2=t/>N)'HJdg7+nakX;$$/eS/Z$rd:?VAIu6sMY2THe8p]\3"9hoTcsNt/jA647?.15Y))l+PihRuG7/ZH,@8liVht';:,cfEVP[V9hP3-f,Y@.#TZ;qYN]hTe,m<)*@?I$=t[W/iXQf1:(nm %$>"4J/9"0I$Y?I,6(s"C^[:XiNh3;pd2*:_rY*HK)XU_Imf9qPA-9K]SSIR4U1*Dq"QZCpe,Iltoq@'Q[nM %/R@?+90(EqkT!N?;ORJ]nD4\J]hL"p6dL47lttmLAo:m-s0>ZPlKi@k^D(kEK[/GO9rHP5a22G,djB!gjX\eRVCDH0LX+bR2,1W* %'j.fOBm#*FX=,_BTkAO0FnR_1ni"37TsM4BPIIe013E4JD=Y+\8'0Vb:#6)@:&+'lg>m+!h_K$A2Jr#n_7kWIhPOT50GY%e]hP!/ %%1S%Cg"VqfUJ<@Eb+@Y[D;+&fO'Wl^m-SN/g](\7M.;:J(GDRG\_*8m2_VO4Oluef/fk9E(n[2i=B'qdN)(^e%mk9qPNSP>JPUg& %i.4^VnVQ_YcSa)N-a[q[.)G\sZ-R>4'KE4b'-5jlnaHf1(nX(6&.aF,N).=d?W_"m6T6WL[W::>5iOm;8h`GKG^(GVP[JljHP/=] %P[JlJkkZJJP[JljXpZ&!ikd)9<:9;OBgWbNQZID>1&&``3M!hPM'R.c3n`,'&^AU&X'3.t-q^cu6;]BHA'9/5F9lG0 %Z.VHOiN(#U%:nbD$%rr^Ld(TEhnoE*J:Dp!^[fGK,mYVZ[/WOF&g/[n.IiPQC4&@6pujg/e29E2lDmXd4LE^l_l]g^K5h7-L,g.M]0"eo %-&MrL>6Q%qK;?H#@LMJIoAsP0HKYH9I:!MJG9Ae`+_W8B:oO4UT`!VpA]4kQ#a-1pG/p"S[^g[uIEqW#9Y"Z1RuSmJ8'Zi<9%21n %-N=L@R8P(gFqoU&8&SR.hpB4LMY$+T/R3-%X!Cm6`QJN1U?`#r8T4H-R/U.ppK%asSriYhAF5/(Mi(Y;_YA\n8Pa%\B:sb=(>Q?67#,Zb>%BeU&Q1;t1=e/p6aJ2-#rW\3^!WI-PrTD(:psUFhK[/irpCpRISH^:9 %9-nY/h_9"Eib(iHDrugY4JccM>M2="H%2J6#\\6ifW+GCGT\m.@g^`uhalK-4]nP-(_jaGR[j22kGk4Mr7TVf._jaGR[j4I8 %AY@SX3SsWV;Aj-]][:l\X@VqTn4$@6F@BBo"E0(aQ'3E:Msk)tKFH&ui)C/gMDQ^:(,0`&bgeX%: %Vj.YI@s=^>;P\U.4m:S^X@Qj?Q2LCuQnJ.`d_,>rI.b$"d_,>rM-?#W-,CPp]s='t6R6nD"q`dKRP2UqD2c-GBYFf0>ZR5k&BCKS %iu)T%,^9E;%Ee2>o=54e'>/H8Q[a`KT*0*!(^e@Rk*+__YJ-[T*ucl+h_G?in4<&?hYn29FG$&Kd5jbM%3!3-KtNKS)MM6XlPO1lW51!cgq;6R %R:!/ZDIIsGQ<3QJ3o\42kSk5.E5mcN4)RpI&4dt(a?,%?OsU+!0'ZVh\fQ$uZ]1Y7(G5Zl%XY*@UJVr".E,WV-*q(,[8F/c(K/YO %.6Okm(K)t%h;27FlYp1tlspn]*;[MNI'9](OF2lCcds)iM$2e`8+W+O6U0+#PC+9Cs8$)Sq2jo^ric?U^]+I4lX0\8?iS:ko=q4? %_q5lrd5HkGqj,-D8.sb^mJ;!Js,10lYlIR()ZFe0^K+3\"d:/1hu,3\<:9;QI]2nb(UF(5r@dm;e'K9q7)s/gWA*r@2#ZX\Y1Cuf %.D7L.SbXN0QZMijE,?%-PbmeYRPWeQg1_sfqG(TGc.UGC')IF@bfJKj:'oSAk?!_Io0du612+n8k#]#1Xi^A';#V9&.P@nrd+X96 %VW.0nE:k5BSD'Z4\[JVUF62RBm*>oI_8Drgm*@WI0+NbdZF9`R9;\.:;/A+CWQ(@['ZQj8A#i259f7sDELsTW_Ghc%bdJEKlYo`' %0'/53c!gUqP:pNjr;'!ZCLB;JbOBGb&[#:d5jQ4k,XZlgp>;2r]u#p_0TTWXXCF%jNmn"eEEYcio_&$nni(QWZc`PJlJKPE^Fl!? %k-B!8A7iM\2L>>IfiAf9a`c@iFW8R.H;mLNB.(oQ2fX.R[TGl6q;mA$`MY=EP390oRpTWP.UCYE.rW6oblsLUr)-=kmjhE5/c`7$ %5ttVN1uuO4Mo2VKb;0iW8,7`Q;+*\`8[;&)3R(cTL$7B2`K(/f(=`> %337%-W2/U9Dtg:ir30DVXHV4VF\OaM@^mu<=o4&IU<_Rb;F/d\pg-H+_ufD[U6tdJiOs/OohCe@0CbsHsmN+hY,PsZuJur_f;Bf%Z2\H9GsD\%QbE=gV@P"GZK[liJB#;Ig;RIdkdACq\+>:<_'0O %SE\/KP#?*5!!OMm_bj6GNeK)d1im1XM6I>_Xi+5rM@JmOY,HN6[7Le%p_01\-*)?NpbLQQ6$/c[&Ucmp[;C7\^4a_X'BX\H!Da*-dDV#Rk)N4L"ck4(>g'E %[&mSo:0Un,e'oeh%)QJDgMp>e9%OeW`i&WmHE\1= %Q"?Nb[+CeKr=rVa$>B[3-8TT!d&X#>br99Y1IhKs=sB&JJOa4#B\!fpGVo]94mY$!=E]V?GCQepeuFr"QQ %BIU\n-3-kZXf!M$Z%d9VF&B^Q#^mL.<8I!0X`s1h=a;^5&9hr=])5$_21&'+kI0[Cr6eVem9#q,\"Vb&E-aar$Sd@tjBfGu:77*q %2@Hn%NY\TE)^q&TrKCUP_+e$2!8cdbZEu^M;ET3mLU6>Lf:50bVu-5ef/[<*"0B2O0#_nk(LN@jN>1gd9eF'Lm.YDlY][V+>W__+ %qmSEE6prUpNYUotM*`dPB#/eB6)_cB/R83F+Q@:s/koa[:6_.+D^9(2MOUKj)j6^$\?Z/N.2a'ALUs %)?mNBj"0tu()sR_qiLtW$V[t'@+8Xq(:Yuk:lG;"nP^kB[7&7`TL1=2U+Co;W5Zb-YX9TA[FfD=SUV6(>&;D,7<3&FUD=fT5W8p7 %/Ke?`njY5)m:38a:=QS%^@22MC4F8\*m;dt!N9j(TbbD@dWG`D:Aq2hN/+Ck1t87#j6EIe?3PgO!EX[2n+NCE[]U(hl)`#c9BENA %]m6K.o=jkId]Gmk!,g`,N#'aM'ea-f?h95*7'GWZ+.pjkrL7GYGe5/nCJul]SlX?6XgLaag@4^NW,,tq[7MO+D="hlcs/:TgK*!M %D3E,GCh)))))D\bZAm5=V/&\=5*l/t4\OBV]k9-IlfJ5M0H[WG,W2rJdjP)7`t/$,q\*CEomAEXbUc$6DdqnSH>V1Vj>HE%$HmOU %1u7I<9iqU@ZB)@$$d8=pcUb?s9Pbjfs8#o2Q\i7A@ZJq=8Tmp4X^bq`.?;VpW%K@[E@T%/pO2Ef`gnZ`+;`#C_NJYQXPJB^,u)$Zf%Z;cI0`Ic909A+M4TNq$LZK)$/RluQT;4Sb8-ms<]EOWuS3f"lb0("g,(_m#4n %24.aeZR#j2`KOZ>Reat#br/`W\M,SNh\7HGEaW"$q%\`"_\11si2P%X@C_ikDpU6j_>K0S_shhNOSfH/EcGJhJk%_75<0q*&e(qi %]2Da[T$=I3G9n&[-(&%jI7kUi9/+,tK(jm7Q=,.FV@+FRMlmD&*?DW&p_BQn,;R0rUC%quPj=A@:ru %a#itB1p!G>QdL38Ttr3b8B&[5B>l@r[[Q!N%D@i,Jm%hBpsYBBZLGg_N(?V*.>MijHSHnV>rq>Q^TCX_Fp:2+dF"E;\$ZW#Qd[Q8G(Ro\Dg %NI4$UNq^NR[+V)YVK#HnD>)J3Sej">D/+Fd>5!YQ^qXj3BldW$#>IV,^',P$5GucG-^%.n'NL4HF4tH!#c7u9]er5cRY[DZ%ErN2 %^F;_fJZ;XJ:7FCi\.bh9k-WeuOb(LDe&j\KNMZ;$Hqp/jA9?.RR%1V,,]F>UD'&TP!cm"2+CVW4$-?nfBd1o.MTTY>YGid$Vp/Re %a[?i6V():%oqi$:3GfJ@$67OIN>C[PR5[K\qXZiXhLs7!`#6Su>>HSeb+Q8O"l57JcK#3tV.TAN*2i+;-3bBl3dO?oBNa*dS3]Bg %c`r*U!d[-W)`ht^,I&WkEi2aGTTWJD:hci-`FJ!U?^_8Uk\fl)qM:_"OhQ_5PQ8@V42D^iGrCr3DtK%s#JLK-AMgX_#%%N*P/Ml( %)g^HnDXf3?(;IX7$1h2`P1,GJb*7&U><)'Ua,+FaE`,Y,!dU0rf8N.pGNW#26sY5q3/5/l2C]gWWi!T*\iTBK?*qlTe]o=8b38&O/3 %7nqRLnpEPZnD9e_&^;tI[A%nb5]m`l,J%(/inZn_G+"I:EC@/B&L5>/?U#rs61\IOEQ_4c7!N\9am-OmlA`rVZ^37R0YH6q<6KB[b@+'1<QI$791 %5!<1N=^tcf!3YL@D4@)B]!0oGY254fj^^1W+OT:]k`'DdD&*Yj?a"e#D#:*?2)ejn(E=[/np@N$^3Y'FAN6INZ?UgRErE]KT>p?> %:CU>PHfka\A7;_DV;JIM&D7Y"Z^hoq&Sd0 %"?C^C@`I3dVf_Df&;W8"dsElc4^AqS?:^U+_./grWpm*d>]#\]fn8'#4Cj!Q>^]HZ*n.mQRYRk\[^_jB4)ZN6TY;4Hc.0X??U)oS %%5nUX7S?gJN,k](JZD-QVd&Cac!:d6%kna^R$3\'S]^StJ[-'k4MtKR"b!n]Xqn2M8eZLFq_p%p>u"Tk>Ugd31dHIWa766u!M#hK %%N' %L#[@b`uUgSa)Vp/_0Vk;Rf>9G"@2&1*Z'=NlY&q@%Wq&f5NC$4RUOL*:9+gS[0.OW>5M0AC5JpV-T&4Va\hFq%ht_eJG;IcO/T$( %XL./%5P!Y%Q$D#Dr2?FsFS2QP;FdUMI!IHLe.TEV\_3$kk=p&ZnZs>5cCdr*?tB.s0/CK5fY$Q@^=3cV@tEJ#I&J>%]J"e=K&':9 %q[kWl"SZ"Tqp>n"5q-C;Rs.e\-m?O43sXX>U%T+>l[(C++5*fCp@X/jnp>]9QW4)4Y3'?'q"fCRh=Fhc+fl;WFLt7;-Qb3'3VUoY %<,.Ou-$27@%Wt0X>`JWA0eHuG[KR7tQ?AT>rjIplU-7+\`2_W]#\h=Or'U8(N,E2r0rroet#Pme1-E %NEa]'f&ap<7P";eI,l].ZXuj");KDh_g)s_4-F,^8)%ZWDO39/30) %jF@c`C-V:N\El"@a`tpV<%i$h!CA*AH,>AJg5t_Ue+LZR %(F0rl1mS,rPn>K=r'5G]12-WPck;Y4@A:O7aKIMg>g6Vur@LTHXkQ]+[;mA@N4RIWC(QP6dpr+RPO%-Y(B'%qcn&*a5LG5!M46qp %Nms'#FnCa^9rot+Ce8ZYdD]7O0JnDfCJgBCGaK#Ch4E3j6Vea)1d]YMfA2$![qsJ-:O'qH^Cd'RT@gN?8@[/+`@-1C%^.(omM?bf0^>TjG)VZ^r,i7#g %IoF_,c@cb$K11E$BkQgEim(-#+^YVSfcl.qJP31X1-pWA*p^-Y)^rK)*uT,VV_7CbH2Z$ %'#]4OT+"Eo2iHLmc]`WccraJWhM0T39!)9X4\\+62i\YpAOdi%0VK9OW5&E3HTU[Z[r*R'Xc<,@1$AqP]&TXJMJLi?jCYhK,aAAS %A&RLdkUEBG:9T(1FV_EHm``piI%n*"n4B0/.8?aF7^"Bi/(\t6+;9I"O^oqt&3`tmn$SAHV,8EOr!-)0jaE++$1,"?5r4$Yq]a$BMHg4aC-s(tn\l`RE`a %.(=Yl-n(M2<4_U6f\2kT %mhql4;0gJKcf.`<&[OU=VUk*WMj*9LB9!'c1>,80pCY*!LK;U_7mnlOfdZ,dmrbsq_5_o8.t_;HA9>Gp3&ODO^GaJhSh+AH%2>fP %Jc7\?*L@pKS0a&FBL,Q+[?b%l,%YMT_o+#YUR]AngEW`?*FPq %2/\IBW]=p.72/OaX-H8DVi,%8;h1e3&%=oUhTlAX\Z2PBUHDRo-><3+a1c+54'+XPafd#9]>__N5 %Yal0*r#C#mKC)q?qo/;uF0]lG_un&s-H==79)GU$Yq^q*Wj23ibV5>g/YBte9b"UeRh;d7bBijgSA<8&"WN)0a,k'(iU9B[G'=fa %]nF-NWk3&qo#0`8kMU[rlA":3EXmHV6/>@b6I%kU/g*f>k`X@Wmqci=Zrn]@\b=Y9o=X'TtNQ>A)g(!#DsMaeJh\3LL)As]_e%3*(WK8bM)C?45)lS<`3D<%3"#Ve)Z5'Bk!];NO %LO`!%igR__.A.nPT[fSMFEPd5RH)jR\+pqll"J\8$JqsXCUm?$A)1MFjLP7icK$% %B]ae4YN+RtAff@Bg2KBbfZ#?6\96;#`[@Za"O/jJC+=D4LMkaV6&U6\X_VpYMglIPR(SI/:*[A=5Vq2/0TicZ)k'@(=4RRoBI:i- %=W<%0e9(de9N`A(8LOlBY`m1\.`c@f8%&5%[mC!4!&pk"2S$ %\,#"h'`T4CC.?e;3bm&=iXW@Y>j$c=J301PA/G=&u53#uHrr+FFn!Z5!gjQ+I8Z)0.dI:*V0J%=,'la>L>>sq"DMHi:?>"9GYk@WD %T7YYH:"Y4=hOhX^J=`K_CrY*E?%"fSmk4>p!L\>t_:5<5+Dth.NOFV!??07e2La8ubNOpIh_j;F:$C`TYGfG3:oV0OAkj"`Jff4?0Jm[dM22MhL+P)BjD(9PU9R0m`qGn=tB?R)njFL %L7Rk_m7B&Tj^.F!MYg`5e#XGcBaDBZ$jSLa0"Ul[3#D$Y>htksfG\Y!IWop;c^&t.`^%Go&8U^1hIl-2OQK7Y1*=&MC>aMr-Q5FDD!m!\&#gWJ7D&a1>GaC&go9>VM^gq-8iKGLTP4d>RC6tI0ON]tZ;q=]!h>H3'U+85n %>`SU-)4q@9X_6bZ*T,/0;hHqf+=(qgpMcJ%6Vge.`R;G9^Ga]A-Vnsmlm7G?*tO02_s9![POV7=ga25YirMW\2e-*E?f2()Msq7% %XE$,!4L+["[U)_,+%1YAQio!hY>(C(mUhd_C1jBQG`27A#Um0BgR$6W?f9iAk[mH18M"`FhNTf%nVdZr-8O'oNdf6p'o/?\feo]% %FKqoaL$&]JNm1g7i]LKPn]bc %o5oNjg2qIoo5l]u%n?87@4W0*QcR4r"mJ8apoZoJajXh$#cRR%8=hI'nsHR4ELs;&BpI.JV^e5$Z"['@NQe>\g1D] %GsnR@ipH!IGB-*7K&4r[]5XXJ9:VolZeMo!l-?Gjpus-C)E">@ni"sGO)4."CoF'QX;$WPKF %b8%j:/h&&'0WL\eIQVj]k`4k:k6_K#,^(g,Hut#eo!`ZXCpdY4(JNktOtIo$0$ml!QrQ0#\NCK7A(nI3\Z_Jpj6iR%m-WEJ-b[sF %gckQeolOd)gY'Qdh5.THqfd3$GJm8I23,;lh!+Ltm,I'n!k#.[B9t-CbpuDX,"Q%'@n4Y)+F,9>['9W^B\%aGYWc2dQ3KW\OrT:i %C+Ql1&ZZ<`gi2/%\g09UG<(n\&M.6h^R.A"(oOCdnM,%?\5fh,_/cf%>VgLm!6\BcO*\PKK]Q\+\DW;LZ!?]::rYa0%)!d'>%jR` %$bsU]?e=HGkqG"]>bD:U?>,$))lV`^j:\uUDs!#e$e0.h^530G^sEHK55sJu8H5u?7R:\23Mkp`ZEp)]i6-d[7[BDeUWL0ZKH?EO %Zo&;R>G)1T?Fl$0"+6A@e+WL<3'K"f<)U,JFd:bBnU24bHOK1^.B&paS/B96Y419NlQ&pRR`fJV?1D_=VmMi)i9OFk5q=JM\sc1j %G>lP#Ys.)$F[>Ki\shCNMF`5"afk]I2Zh7>RGuHEYbhW91BY,5=iroc4Ym2RTin7EZTFm$d1_uE73q0.Z3ocA;p!gE..30b%aYV` %C@8/4hTu]%`e4,O=eV6P?>=J2iLR"L*uLik)D+XZkHV2uN$dL;Ut.&teEc++,fto0mgV02W)A-_t-u<7R %*4sefT>k?SV-^YjJUb>F,?u9qQajG0'W#,\*fF+c'fgW&*t8$X9@SeqlU=\9KiZBI>-GP2MHVZj;D2_(N`k[:;H;ToQ8b$T0-q_0l6:eam0+,$e %E":!#O-C*o=_:20">:7Djf*?@?pm0Be*X!d\Lq28,oq-]S%[03`hhG5h<\^t%"oYrpt]6W.>7J@3/<0\gFFCg0qd2-lc1u,HNhI1 %4&Rp[GC'M6a2?a;O)D/ZAhSC1o'#cS9/qm^mF=a,]8*NKXkrsDn+j>_V[N7i6n._:noOnrBY(dnH+LdC(ob`;ajXfuFbXI;Ks"&W^5Im9\p@JFj>_N'Xf"hd=Qut@ELndXr(DjDbMZ`LAEEN, %%H+Uj@XG[o[>Ygs5Vps9W$@gHc_!>ZXgt/mL65]R,cd$1f5)V!.4'+[ZTV)$PP3p)uUY&*/Z?'G,.3p/n^7EH9 %6m9k$Kb9qg$l!47!_99hRZ"Ckl)fFGK'cg+lmV+efsrjLBt+0P_^TP/a,,c/gIe8k8e#rf(W'X4SR#!p&FSt>IC_guZn6)AY!YkDpko %[*&K^_.iJ%F[M/Q>_5sZNltB5Z*7KL*#F3LhgGaMKt[pNbN6ca3HIFlo^__HE"(6PKjUb\2=(d_"FNAG"g\MOJK!)d3#^PGBBK<^PM[\+NA$b%i,qr-t6SH?p)m;g)[9=!QVNOUV^.=\0IcP?)/mWC/(7Z8P %][4s]ISVl[rSgK[oRgat8+\dt$d<+`XGu/"_uoY,Y'TBP[(#0)?1`\[O9k-sg>EFbN#$$?8WaZC1VD7(!n4AW040Djd9"Y_^Lg+P %F0-74$Ok;%PWl<`#)uEldelN:gR$;F&?"*;_Y.P6eVI8l7:H'[lWDqG08`Z2s'`241`!E)*0UE0od4Y'2'`SI-ri[s)A35_O9NC( %_e*J`k/Dk5IUrGgL'/2/C%L=l(k1/T5)`;TL1(+q.qcDIkd9Js__;lB'*?'fBj+uBSP5KQaQc;.]l.cmbcCJt.h'>q_VU>)!/=YF %0l\n+jRrl%2'`TtJW`!4@%!jNU3^gcd,_Rg6_hICWJ9PQ:]+HbErE/=WVi<-e,[RP_d %2\B*2o"@MA]Hj[AY`YBsT""9cj6_"Df!8VK(e=5B29arAQ`Fl!Ic&]gT,hd.pMu>H:BOEDC:%Y)(i/(E)F:og"D`QP=]DOI\`/dr %5_N";D5Z*VK*J)jE^e51,W$?a=.2NZ%LToska/2&T3O`='B7Q*"7m8OHV"9[%12L"4!2H&)No*sBZLpMCNt,bi;^$H#%JHM&6Z,@ %6B#35m'([/)nQkaUFge%(PZ)>k@L[CCt:3^`\,-t"p>LW2KkcMk%AntB^F/iI?^PZoYHIXU7f0#q_3Ss="IhtW1\"YY(&"Q4H?ZS %T@Ej@E*q&lKb.a\,ZA;>`%lN#/.X]'iZl);Dm`C6(e8'PjM47m0OZ_[_->,qmG_mI11t7A;>'$%Zr&UQ)o6k$1r_/idK>2q2L?nU %-Y!ss4>puA&7ZMGYLG^A]C9sDBZb3G1G(DYpJ"Jo+j3eulg[lUcaUaCFl2\,nZ&ML^*-in6Tt=8@L^H@VQhu#R-Wg'T4cN_N!*@GCW8Gn3&im>t&NZ2DA+UtT-t%b//`f?QYmX?UVT)#^CH2"<(ib7\1pPZ)T9-9W`)S=oKo;V'8B^E$:gq!.D\J`")fse,B@r\g8?_,EG3#OlE %IauPSI`9F+;qU9m6qB-+pEbMa%&4GIB];k#2s"CR_!md\kM#jpjqs]b:+rkW50n#f9.?7iLNkC;0;e^q]]ah67R8\ig$;e`U`ff> %\c5tu_20ZZ&J0&:VMjEbqd&Z2!l:!Ho+ePdc8GeQQG/!ugNa0uj,#5]8L3gb24Ib(hj%heZ7u6EXY\X35N^jk>R@1`gmuQ[m;]T^ %oBo:!Se498AX3ME=_-WV]SO90F7pfio?YL2A>]p*3g4\6Qa8Q;G@r\"?p.\WH$:T*D.I/A9KpJB5-H(rh\\_-Do-lbR'g+.]JY_MBoS@**(41@^sD.C>8WBn1fNN\6tGgEQ?[i\_3CuL@9=JHJr9c2I2c?+E( %Z5PaaLgJ,S(,Oi_j?T/M3Dl6\ZJGtl7`NEgYbNVR)As>9lcgs^X-'NAM"#1taX^mt/&Z/nN-U-DBnbcK0]a%H:R8#;Cf?fWV%pS1 %N%"6(l-]oIbLK9:`%sVf?6OZ!+aDjHo*X1"$8'R3F^?5<>+r)u@EX[D:QBY"42S>afotIh*(@=&GkT-0n;IKmG4B;5d[e63=bq&9 %]8Xrdhp/A1NEt0!VccN"(Tb_ESR([<3D*eJT:<_G2EkS`]Hg"T=KmIuP9^JJ)h4:cVVp)oj5'JV(@0rn)DB3aTo7<[)hI]j%ZQO2 %&]$=bG8SR]:cZ0qHi-gcU]26.dJp9'kJ*EjbiQZ#cW%Kt56^h9L`*AEFr:^_X-NIjGm%c&QEQ %(o"(WS/q&A0`4Nge*Y[REf_8c#n6KsWt:,]cK"]5>7m#H,5AWZP6VV.,"pXAj7i5S29A6$Ti6#0[Mqfrr)F=ae-8'kXL]0M0ZA%R9m7n"= %e^2\:r:aD5eG%PB[Hk;?Ln9,.`/D:u#7HLmr,rhRp>I\&Be^I(3AVlW.[H,j!dV%DV>kPa!t;RE<8A>,,h.60hT@?5!#4l"*q5,4m>_OlD=)>2Z:7Dd#H_m.T?>uGcKTQ>#`.O6\7R?MZj+2h6.*1J&#pWH7 %3;$\`@%+rZ&'lqo[]-%jZkLnbR\k2aC]$At@+,gs!:]3i$ALNRL#LI8'aSf^,WVT9MTI\dD>oFALD<&8N,n+l0MTB*&_;_[j^joj %1/3&>Q5g9RQVB)h9-71g?BAXX2]^9tf-0I"Zm2%lIA2NuU4a`h^OJ:#tcc++=+VeX,,- %,qEU9^4%Nj(lDRP7H'S"=$LR;qL]' %)*Zgs]%`I_(*JO0,>VV4AA>]ZE`pim'A=,3'1cel6i:8ESYUDiqY\(fdAf(J4WY^;!I#N[4fhQ6=Wd;+#*$U9RZ\B@"OsrYg3goTd1R,0@Nf=IGm$."W?+R`lhtE&RA% %U\RO0E2RXX0j<+#N92KV__]&)m.B&TI@*t>+-TKV@u->j#>H"`2BRr++(3rRCd(m`ch3hAa5j#%Dk8j/N[CB$9;^J+'6.4KRT7a6 %l"BTr2#4pYp#Bao[e-j#E&@A]EpQYm@aMR/r8R?-Zb:?#XW/FZS;S2ASIapqnj-C%cfPn]jC@GW"`,mAo39R-n',P0$0cE+Y5gn1 %noV+<_UGqUl`*'VT7hhk53>VDLWq3kcfATCR=sB]o@4R4$Vf>i\+7,M^A#PVY84t[?Z277T! %?,7oiCL^eVcc>13k%+&YDQHL:H[I\HCG*YH(MMVNuWRY9P$AG&fUDA_.-a9?K %\H:oeBcFkQ&b>"CV=0UmrBk$.tnHp6)hIhY,M\mWsdjNV`a@-N"_eLU&=N(ZI!6`7k,8X5; %ASm^o_Mh6]Aqc+aaQ(6X[K5Llq;`[gWS*@nAPeKoe$CaPk&>Oe`8[7"@uC7#L?+(Xs!^O2cbi %P%l&1'Z!Qp3b)Vi&bGib:c3PKe]qrEi#a1FS#-tNeB-Pc)L2:J,)40IV$_X0*!-k1A$qdC$pbK+ftAq]]*R_sS<7`9B8Unl>dPaP %1F$J8gb"&32n%N]KYT,=HDs*?HD;oH_l)a@-N"6W]m+7P8/+S;o/!A)nhgaPkEjqA?c!+`ce*Z,F^P%$?`aVAQk"r"=##;jS=ii0Q"* %ehf+%&c!_T`u&:HD#D]h28A4e&&XT:OX`Ire:?j5sIRp]$0ldjnjE.jRFc9SD %&34.!).MYNL<)Be#1t.UBgUnQ*I':G\9(_b^&cJt.`mN`?;6<@_&8+lqCK2@e.Si:9APOd)4WGS7;jTK\';]p*tqMY3\7ME%7udm %!/9<:4g)/<2*KRFqdAAGY-^4CO?.0$a0YEJd^HZSDm>rVf,@=!)dY\1Zn8Gr-3X%P;W[r^VZ7R_73&9?`?5NQ5or#dG_7KA!@2E@ %/+"#k\c^9KBGR<3PNUd^LE(hP*,D/uUZVU[VZ98XEWC]\%KZ#gmr>1@!M+L],5&IWOJkq^JDmeRjoEnt3hI*LY-]d`7V>=qO6bl" %W=4[;mQ[(%8:"NT>?kurfg/bunQ7k<0Z!e+HVhIALU_B^u3m;p5r[H\#gRSj'e]i&hB %YF[ATd-!UJ$>ssnosqYoLOKTd&\T,ha%P.mnJnu,D?.$INrNN>5C.WS_.1HZd5AG[TZ:^_>7C*_/JbOa;+W%:TKi*K-?JMW^3S[>Xp#a %DI,tRhH)rML1]t(O2l@sVq[8h>5 %g:H)u6ACC#N;]u`%6Z@RlVXpi%A"B0or,lH)6k6J>]U6XRm(*`X@IElQWWpZ5F84Q?>3hgh)W)Cc9%2`d;6p4rJm<\%GF['<]#.f %WFZ=GFfYul_D49P2h!u*Ycu>jEJF.M`p=UtoP>V;=T7k>?\mMqMW'HRG"6u4e%F\]bX7eX"s*u=B_IpD0Dg_C+`j(-IY3%aej)"6 %D?rK(%EreUHQ5AeGYF(+SEifl,e#k$u3cBYP]^7jkcNfaFXr!GD^GVC\br/)ck@9A-V %(%oA&OeX]`pgCi6MBp5N=I_q4O'b1'$l=Z;T3o-W\cq`KKjjLNL!@?2aX+o;=G$>`M%dc>4Bi\/2Z=*m3iu$h$qi:h!dh/Gg_GKL %+haW?(ma*B:#a*q"G83r(71X`^_M##EaW"$q%Z%#3^1FobcaFMqjn3h0Ya>@J&Q&&XR._![D*3#"n2&(?s!J1@26lM=tU8p/2R8: %%U9)u(m],Hh__=nn!'_Y-rp@?=DGGbN)dNP$GOQT@[/Ynde+a/=EPdF]gOM7-1dqn)?0Eg60qXEQg%1g71(u`PFAC'DlAdMX1QUVMVO#PaX!]N*+>]SLIfjCIh2>To#G_MHnpF4u$9q75Xp&KjA[8GMAT3O+s=S2Q],dc`].TmB?IU.D?R %J+nP/,#G9/b\h24q,M>/(2fT:r*1^1I1%uH.mJ+:-7!u&b0Biiql&f'&6YI:@R?EJg;K=$JtM%Q/usI;Q)hGj %2O#Gl7qr2^7-:!Z^_,60(G^kkSAM!c&YQ=q-[)\T(1Ln'$HTaVMqQ-hT9g9"R.(.T(U&>>Fb(dD\7h7Yb[`6jmSL]%5d#a)$]rko/*R,+8:Pq4ZM(G8BDH,YCAt4i'9V" %A<$rS_;+&\`A/[WieV7cU1bMg\UHX(dNq+BpX)XrGf?Ua>.j.S4?--gfU8JV>4VFR#.hk3'(PPp8<(e$T3+*n_r&58f@67[UNL3> %NP0!=GLVuh21^#Rk]ia?Aiuf+?9emLO0>-F`QpI#rO[.lJei+(OrsD1JC_]A=4.qU0tpe#C&]/A7oNJs:KJo'CWm/C82?g=0jnW` %MXLnp_,ajRC-_s!4h9!MR4G9(fmsX+* %B!O:c%Nb18NS.3cK87,*NB(-tK83.Y:;506_#s+WSVY3Xm.MMN@KrAXZ-d'oZY]f#)+t2nG6\YHh^)EqK81!o\BBW[_*]PODdqjR %g5LXmKJI[\D(_g0f[$L\C!bG82]@qMQObXGc`Iugg4Vma;q)`0U3#rtq&:R%AnZ#6Flk;3P7"DAn`BaU>ggb2JTF;SS %Ykuf7UXOQNe/$1W,ll)1Xa)oD#0..>MMN*8!u*Hl\fN2!ci?MYJ0YA,F8>s/TX@L,'.g2RO9-G9Q4+9BphV4Uh8@h6#P7IPd*h9PChIF[(b %!BCGQk!?#kC/7K6hBT&@+np9OFQ5qlb[D7\Q]FE(U+or?r#\'VUj@!js;qSErai#A*p[2ner;T)C(->-]XFA)!&lpO"872'[cXK"Z.t/fg0j %!o>,!9-Lqb-Y`sZ(N/pkhg&.`3SKN\P/'*2O*moQ@!K68O*moQ;[;X?S^*!oo#LViW?q&J7C4-k:eQmfb/JhZT1gB"93M)2&jfjZ %3Og.k`a6N0FU8nN\hY:B(XSPPPgK8ZNacXdcqcB@V:RL+ZjI0@[+;Y]6$f+IX+XLj+4F'lTpC[mWD\Yp.d=Lp&Wc/#.ZO;hEdkZC %hBf7d,SOL@/$!2Z]g8Y&?eq33'83jPS?Oj %#9/:Qi]ISA*LW*h>j"tgmg+(NRGo.]^Y\g>k/ZlEIl\oRF2qlph`+Abu2M\*R?I,c_CTTk %ZoR+u0@Zh2%Q!#q20g:&]54FHo.k+]Bg),kES(,Rm:jH72:HL$Mdp3N+!t_AXZsjs35q`6?Cr1c3Bek)rQ(>c!qn4/rS]bb]5_hir9a!hg$IH5@*1HFFF1ZXtOhh6Sr'jC\EAd>p"A1S+W0SLR@mh1U^F(1fdh_k?RD0$r2PWAoW-*alpIU\'=c`4KPsu %S(b@Nc4)lt\]sjl%+Y7%PPCFQVFr4b_DI8bafu$gCN=MAd[r#+@]+'.,m@KVXi6#O5fdE.]X!j+07A=a8bJa0I]M\cFmRng,UFT4D/M?^F'u7a`SHhgEh?3O6?blcJ`+Q/>f9[SqcYqM#@GJUTSq.`O*)i]-,2W %7MfK)Z8`p0>*ABm9QkdR$dFj?EOp=\OiM^LZ0;OdcI([Y1M_n.B'ts'Pu469 %?7>;P7BA$WYl8cKi*?/E^+^-Cr]-##0qfQBA8]W%C?T$O(r:]2pInIl)#cq!DNn/hSX61iDgY]rZl_b):5mqi:@^5b.pE4&H^U%H\J#.GFbpK_tVOT4/N_\O2:TsS8H6gW/1cs>k&I@%!?AF`Y:V]dDc1:>=@XI<% %H^]\enpFb]]l'IEpY*la/%oh&Ik(D#K:.A.dEF`?M@.86qHf^OOG]@)?XMl+=IYr<*!>0U6.`bsT%B9p;D@\QnM>iaK)R+0k^N"J68+JSlesWdZI>`Ik5K_t"RAsj+O22! %)h,KXoe%UVBL][ab`]HoD"hmXaXa(+LY79uHt&+*M.GO'/YE-U]\kTTm`tJdl2<-6-NK1qEU0U9pf87N]@P69!UithG[A%[CsZ+6 %:"`\WXaGK1bg#Ci^\C4_-T-!DEiN@7j4r[BDkJC,V\]pG!['[AL_(k1!UmEh1@Ia;Y"tOma@>s2nFUP0 %?V4+dM,T@/p%=E&"OFQ\n$'N>2XXoi9+Q>\2j.B<=`f\98]uKl$>pp,DNL$Nc[P50fF9[p>!rm8E)bADI6IC#3O+A=!+9KPj<97EILH^L.93=ZO^ %Br9t<^9p?"]"!cUoD7[2W8&b!=MJUCD6/ae-M5rFN %a[dN;b],(GmO@BR_MYX0)L=Y#5>sLZ:Y']K77!95q+QBB1,N*ZRg4;_VSgjdH:u`;--jsCWTNX!NOPh/S1ST-'[tP(pZ"5qT!%Dl %:D`68KU/iGgOJ!%iESNOOJu^#]#8m*N*[PKq%H0#M-W$Eo-_C;?$\\a8DG9$<:eJ\ME%1[O&dS.ShBH59V.iYs%Frl[9)-)cW2CU %GQ#;'b&klL[eIO;VZ4%Z7;lb3o5rr%0Z2EecI;HI[5-!3?2n.[e"3P`qmFXfIfXcE8"mMgBWZ+QXu?KJhpWN1G-9Vj=WY1RVVneR %AL=cC2Up%F;,pO&+'i.Wi*j>dho4?!j_O#d4/1?s0RiQVN?&a7bA-3>/&\l;)0<)k4-tt7iqLFsgUUq-5,!-PlkOZ23Q0"9uP>,fR)@lhum"j18'SA<8&[4B@5%t>C6G8FL#\%di^]*h^2=Jp/rDC@[lkFbQ\lA":3EXp6# %;-=g59+(BVUU<\@L7IRG27J;hLE(:4$VgY2"_!&&/Tf":_`93DEsYl13A*/]0sb-/**;".>10]]$lkUR(5[o6:nWR%7Md&CiCqW- %!+4PH[EU[&kBOBK)5r+[(V5gL#&;dh2+.U_@-FHQ@0?dLi3Ct&@Di=a@-C&/*F(+7*D,F-9bpT_l[WG)\B'[)]ZcmPYr,Gc %]hVAp,;#41:3f- %oN*!Dc2=8<=6k%Z9@l$>e(XN#QRE#oQNi-N6fT55"bq^%+Dq_EWEO-#!XG*># %d7!@12UHBOmP`HG]-+rYW(Q41[&Z&KGIIl8K;9`9ecp&+#)W\1ecp&+-HTRs)d^n8+tmM&5=\KqAc?tFoQ*ROMsLNr!WBE%Oa[e3 %&I.8s7,+'rj4g4aIRUVll&'@nitnKXbJB/89P"cm1MYajDMC&Q_LBj2pf/L;oKp[B:=YKMY-+P:d_R!Ikfg^>/kV-%H_ %[/MnL`eB/"b^/-`E:*cKA7e0Xf@b,,11!VA^Jes80ZT^=Oi-"/f&XU5f0tVkd)YlGUgo:kmpS\)G[+0=Ai0r.#3?WKSI3QkU]qp& %D)-qK0`*,,qQ:0?U[k,&!C"J\:mZt@9t%*Hl"0QT.nmJ//$djoDQ0:>-/5kQfYD&STNIa]4=f$$Pt/_;q0o.cc0+]3O2>0gYKAt[['91UC$Ft,N3*YBJ)XY=CcTO5CQ,JNSn %$jfMTjQUFnrUsd>c-i.n)Wda:]KQJd:Te:b)Cn40($8hO0iqiD/id(Q,FpPA?)Ee]jqbT8Z,b!@oDg)(Bq*_g5>HFq76q`_R?Jas %q[?>O?#V0\XtHWMlf[R# %\2dZ$:rPHd&0m^E=9f?9_i]LN*r(B.JQ\NO(i5L'K,&Wu)@&kNj4tq;oB'Yh7RTqnu'gGK\'UtnknT9?9eoZ%ko5mFbZAIN(ZK$@1 %Sh=skR'&&]Sh?N>Bt1aA4^C^81@MuR/aN0eQ,!8]a9C5,.]6jZl?k"UlY:K4S=L&^M9kNimaT$sFtWB2]#T^-Ld$!bJ;?UtErdfF %W9t#$F%N^o+H^h"kiK(7F:#3n_->.(XNJr9je$K/cd%6k?3O49LPbArF<\h`Cf:GEiF_*"fu;"fKt^2fB:$m!"Tk&^mOi0b$0pm: %j6eZ>/)SW)mt`l+PWVBr4CerBN08AgamU3%Wh$ii.R@@UnVPE:+K,Zh(1F^GC[_#&95H,E[NqBm8FDJ3XQ+ %2Odia_?)S'=.6Wa%3kb7A=k;^p^SLRD9->GN>kH\!G98@'>rMgBj2JsLHl:W]s&U3++,*ED,ZA[o>2BF<:*uLoD5:@QV1OrN.3E5 %dA;.-E3p9Ghq^`SRpZnfC9@08/[[B.oGlhS(:+ek'naZ5J5/p8_5S?\7>TW!=3nVBMVd`CR5uh%dpI"`lY(e!?0fei+K9p@R=Uh5 %(,\"79`@b+AHo`>R@`4Hq1tWhbT2h%d&SHZi"cTp\>UMHsVQ9]ZAO;cprS[,U0KPGf4O %^9q8]/hflrr2bC4RtJ,prSICsFX#(8lU>7ZZ=ZKmXS&/-c+Wt)TD%Du"jOgkH'W#.*7ZLX; %'f12u$Ojq^&*t^aXS&;9oeJOc^fiB;o?j`DS#l&](ROmp8f.M&?mY)+E %kduW[#JnDhH;Q@E1KRcP=tbb20*Au-WV)u>HbiLOW:_?G_i^6&B*UhP%P5IqC$3:WQEY[5WuiaY %UYBS8lue3TK)DB$4%CTY-RLNAB"4FBGC0-CHg-rLOK.9%)T^_$'q@UH;eVQ1]`LM:4e',MgV]f@.l]`L9\"sRm1gT_0?JUQ]n/CQ %P0BiYM_a %(JZ1jInplZ#>J9d3):>M;kikhZtpO,+r9TJ,4]$HShA3X;G3OXM_G+ikNT;B0>=#132pm[?"St+Zk#sul-`k-grUd,R]Bh,.*8jK %0Ffj+.h"dg8Q8J%H<8CRPrMPUjB]^u"GM-4ArR!Od4(2@?-m6#:uN/:dfi\-?$Zrqo>L#Lke>XS<#8IYV9q.S.tlK$m9E9XcZ)ee %>05+P$59$X3R'_:G-6A>5aV9RnmH+0J\H:[Q6U_/\W"30MNGb9G-9NdW),PlBR8LcIbo7N=gG;/3u;.MI:3e'kF*jeII(3ugt,8s %EHfbMp@dh6P?qs3%c)g&b(RmmV5FIkGBQDuGO6Y_M7X.$rP6]2541$[-O4g285_6oj=Y^1m.a&d8rGEsYmb3A-\-=BR6pNXNO:98)?BRU/IL/"#@;M(4K3 %,GBZ,7OOP\5Ri*Q+g]?*Hp-Td"DZkU0"F/)k;FC!-: %JA%qW[oa_KRC]&8HX4n`I?B$A7=LZlV'5J4s4:Hd1^hS;gqq=Tfr(][C7mLB$Tk*7nVlfE8(Il580XSm9dOl\Tsu<[?-j#69\`bi %]V-4oOLVSSGXF:2,J16>*!4UI=ta6:2-C`(:W]H;L:[!>0l=$/KaZ,kH)L@eSLddWqo*1E1/_fFe9Y!E^-HlSZdt&Op'!$[0l+HN %9"k4Z`Vpl[bfPB$Ef6l$6c+B#l)%IZM<#6T^`Mm-GR_LRcU'1"=raAEW[__;@KRGX-BLe]Hj(cL]_'ahk&[!Ao1 %/@+Dq>obAspW^j2q=_PmJmfLLR7s>/(l#5n,R]?8(i21ZP'\#_P*hjr/,5#!fUL?! %XV*s)eLe/0TB@WL<\W+Ao9c1U6^J]`8?O,Hi^DBg9nZBHD26l!#"-^pYZsO^KB_h@$PCt6Hn86DV>1KWjsuhnJifA*o+fJrOZ!mP %\V>e3P%8RCL?.uq]0.?Y%3a9k(HO.e%D>oM9rqVeN*X$ChI>jZ1Nob>q_Z!k98?Y`[T&Ps:H`1S&n:3J1;!VgKJAEk1Uj$Lh2.&p %bP3N&U_e@!Xtps-4SE1d(qX/lc=ZGV@dNY]232JqNA?-].C*ARd>fc`\*3#Gs`C7nB07rHW6&G1j20&:IM(3_:V2X_\-Hh&@/<*?ODfq!Uj9^7_B1Ds)Zh6"f34-L-!_U4gr]/)HZ,9(3,ZJjkrB<2h0 %aNulcd&T*6Z3t$LMPfb617q8FMV^9%mOnB8BtJu>p%^N,K%r<_K+.(F\SpE42Uo)%\SA^!SF+WZNu-(6[Gjf^F1e,rA?ba_>A*Gs %?VR]7=O.NVX-%rlnm[RYM>uX/+:-b!1?W!_FZ$J^&\X20cV$edE\L4r5=2:=EpQB15rCDM7[?GD,L:CWKN9>X@UsTR_lJpA290ur %ltM0>[!CrL6M@cQ8S6:!r;uHZ-1_>(79dmVm-VMi.F)&@Pi81O`_8k[6^?hHlBU>;26;Q5%83%0'GX^nICCgD#@HR %"ih/mDbgYt`4EHFj+6/($=3.k@5d19TKO,Yj!/2)E6X'se(=iM$U\`X`6`c$;^+5QfL"Uc]Pl*JpkXo8iga9HAFADoFTW&PWW*GU %Q\o[f--5DqPkQs4:9KLhYFmJ3Po;!Z,1^q2V_Yopb>PY]`#F\VO#t7Jg6li^4'3`/]C79;MKVCkCj=m#",XMK6tl_GH7r#O]["3F %'R.OAL5-Kj[(%W02S?14%Oph'Z*rn?/U/L]1Mlm@[BSiMD:hHD52RWOZBsa2<-@dpZ-ZW,^jj$DQKg-P`8\i:G6@k`d4IkDcXoB*Q!(W)jo1pq;p!,;F`f"XZD %]K"W\llVJ"/f@\,:>kG,orUla:,`Ub?]MJV,.a[6PigL&q$Sr&amkMd\Q`Y.lRcr2WPnBrIh6;$G %:sMqZ$4Z-g+u,ZUi-7._+l9c(8rT[oMsjHn&/K%_e^V]I&`4lo45H<:fLIIGmp*GIr%k7J(0:!0r?)QF %=69ni!6reBo*OOT*/tKb59io&m52EUZb!a57?2q_lZbY37#o)@57>Q"f*7`.)f5/Sk/C7F5HZQq#R*$ %fFF1e)\@RMmRrRS8ZgOfhu1jh!Fqs@aiCLq6u.b.FBGIlf9>f7riWo@MXKQ[lg5.'@dXIjQD[fPQi#fG5$Vn%Co@bQD1pdNO=&=R %#*&O1JSUFmVe8",Y*fTOEI4"(i>T?Zl,pZCaH_l-Zh@OTY(s:(0g23n6CAW'3U %=BfS?^:>MV)`/fpCPaM8,u?t>)(+58.//l^K:$%j5N+O:\PmMP)8\OAO7?u*fgj.q7FV\8,bihDKUIp\=DbmC.Uu]Q`KrPdWs[a(3K&q5eptc1C$E]OO^*BjI&O#R*ZPFbfo1a\fdJfDI\)nPruDshn8qS9g$m/1^Ne?RAAaTDVrD"^ %X9D,u%'@p:?(q_Y-+HFr<1a>lfEGp?\P`JQVUu&Z.sr^c8?iQJY_,n?jqPFAh]g6+!RcfNpeSuFaSFSq<<(Z3>>rD[)@G/./M8?iQjE<9Ceg>p0^T*uG8;j.lANtXQa>Z0p?1[M@GKfR+i %^K=K7HeMT&+3^i`/2InD:oo/gTF %GSjROWH5AAfV)/hXLsQ%muY0*#ukZ%lC=5FCYuTc5VgG5]>^$ %ZS:..i,6+,%>i>Q,K+[+\<8LGnNn^M5FD\U6o*Sc=u[+A#Vk.+ZGUk'0(bklh+4h25(p-`n?*JELCc?H*-S(O&Aj1;)u9?:,_Q[O %hc/35LuC],)rah?n`3'YB8$YXL(?Qt22:?BY%*:5F([X)E6%'7`6dDnoDpo0g&\Ujs?HgLc(]$&qrVYmC3q"cY."fP!-pQF"[$XNGTSML,iptN:iS>QX.P<@`Qao3CF3Q_5 %DX\-mTU$j4\cI5"GY:r7](qpg/N7U8>*?t0qeWHs;bIb)\RnJIkt!!9h>CK?84Sj2)A(A\7)jMn\e3JU6opJB8eT^<7)g3<(>"^; %3g.i-'@r=7pn\7uZ4ZjX8s`7GIL3T%\?mMU)[lZC'(%kV4FRV3(JubUdFD(@pa%-u&t`4]/P5THepR6=h>8N1\mXFtF0_a1,]_%e %-6jZc8cF!`4BmsS^SGqS@TnqbgoHg.,i?9CXt<4u?]nqp/P01<`H=#-?Z$`ggpYGNQk9?N8VCI1n5S,EhbJV)*]4"e8ZmZj0_MgL %JPsmHeo\-%i5741`Z3<"g+l407V\k#RWF1j@5d=,ho0H:_2YgTZ&3osmmc$m6ND"V+^/bBi?#>%dt&"2g<\Y.?)b)5P0u-&[I+nE %dum*[P0h]+XmDoTMf&-X'$^I^0l%1fG1YJ%'`8al&RHSTFb3Qg:L@&VC]&ZV"]W$SpBj6XB?i_;!jgM\&L*2/[M %BHjcm-lPsI^HBXT-tjfQk%@?jW%W9L9W?V\=8Lh]qn_9f?9>Kd%ieuD:[7U($/?p&g*?9:b+uFTb`5_d%hoq[1LP+an2N#).t1;ose9c %p4Mo"l@J#^eBMnTW.eUpG`,FnQI`>#P!)`eob],jJZ-Q`:"d.)oR8MLW$Uio7uiF0>"?Up_.d*N;%(2k'Fc0)\pA0qC;OG%s-6^i %&\EA5F>W($+'Y?K(j\3(0e/SZT2?E30' %n@'*N^R4q_^H6\_7uWY?CRdk#\i.tkFFO>4@N?hF\TMRi^^Y[Xd,MT4UXZ\SNi.)td3$alSSYjjbrs@=gKHA??$(fm?^s7/!5E3L %m5T+6'Y62SOX%n<;s;r.?S#fZ[/HG?lImfT=O]0'RlL*\hkVL"&AVZd,8(g"p)?S8:J"sGYY!?H2f\1C&p!2+>#+ELjU=\q^:C0"T2pJ)=2d+&5jOBSt],`K6>XqTG\%GI,(*i."&'a*,ZKQ%-:,E@9`.Q`# %B1Y5D7^E@p491fRn'Cn%/(?_=+Uh!t^EUdI(`&/mfYXggGB619q'>lqOjP2=@0u'tFN,do_\11s)"2mj0_&FE7q>_,/ed!5E'l5_ %L4paM07LmQPN+DL_>FYA@j])K,PiT&0^3`=&YQ %Y:*JRie:@Uj;*2H`G:#,^61-MnNn_@-*aklD!/$TV,L/s+)?Xq;GoO0qd)qqkPJV.8#i5P2NlJmM)qAOg9g^mA7B7/&X1[55SJB2 %7HLn=PW&.L':.+E[eHuq(@MQ)2&DM+7P9_?pDPQ[NEg0NRKu(RObogT&T'`[_CrcHg47R!cM1!d3Gm>cC@q$&a_@O:(6"[1k&@0m %'1G=sU54CJ,3f[;3Geo@TP%V6:)dIOGhefI65'OjoCE=hd*mbHDXrp4Kc^ju?XJ1C;EQe^6b<8'BW3k8a=7r>_"?B;Qel&)p\Fjq#2mRF*pkU_XM@g8eo/6tm)t %-/^;k_&(9,]kATHO4h=8I3#eK0.j`923lBmoSs7`?Ol:2iV.VL0*h+Nh7*ISja^[ip$@+Oj+&cfoWk^O4Md?dHKj4#+S^7dDreXu %j50XYFWqZCq$s.orPGUU1[S8R$"o3$j^s#^SP/),Jam):iT?`cae#@96Nh4W#j?=.rgY5BOe1>@!*ubi3a#^a'B6j57qt%$,(1Pf %JKqH@N0YWmnWd)4Bi-uP`pRM.NbHEDh9;I#:PQsW(lH)!dJqgmiNgcttjk8g;]F,O4,?imTC!e\(Yb)o+,I0$l %=!KH2Q)/#g0)b3<>&96Y'aRt1k(c;9S*d9.m95rXT-jdM)lD_q#g/[T#eCN#kPuCuhe@6?Q4!/bs$c4Z9!lU>gkbtap"%P_< %$_QY7-,pPqncH*=>pV!SC:K?1VERX!:UcB[nEEbR.'Jl*,sU`_[TV#q\s#-eNHlh0H0-M-1%]RuZGsP]J[K3D:Y$AS2`p\S@FX2: %geY2F9Tk)Hp)S0/^%9XdD6s"ap[tQD=rF0!"._'AMEVs+.&[`_R?#-aIfIe"2KBpV-q^oDb@- %)uD/1gMSp3]eZKhDlhrP<%J>TS?Rke;F/og'35D`AjABC6d9QqAe7QA`&I&H`f$2b?Hg='_mr%QZ4"_!_;d#l6'IHc#7hti9P'QU %RX%t[([1(1V=/Wi7*MehGUs-=S!`HRJHd/3 %HR:Q/\.0Q8qP`nb/X*V7hs5mPi^Wq8]V4hOgQ5rc%N`B_dWu')kXJ3HP`0XXfn$1m'rP:#Q^b`H %*'W:"1OrI.e3O2Q"ZeUYTVNkuc`g>T5p,NpX!Og!Fm.h,,iTp$et(WO,aj#V"-:)L-%ONfX;_E!qQG3UfG?SiI&>M*J#7^Kt+/?LL*ZJX0OtR*rmY;`G_Om$Y:B12NM*Ri!f'g&dO+UseoC0,Z=QgG`'?Q7$@NtVGK3!]dpDK"gNW#+](&/!&NQPf%>G$(haNZlN %r`RauQMqlffE$KA]gFWoS>WGF8eABUamn^fFOX4T?61S2$!']:p*2mU3C9_(*ogisnthZ1NQfXrj@_)`lb^hoj@_)hSLG'Gd>]B: %3]=Ca`/@']QLl^0:A,piGn]%Dh!@PFaNuFDS3OCa>S9!mOY=+qqtL6[7m*^rb-p2pe.Q;kENpSh;G65cn?X3>in\M"XH%c#YN:6^ %+U$^3]#SFM3O/;kEguq]0H\uNHM7#dJF\&5"-WeJf4XYH<`Vf:c"Y;Eq[0ptGKR0n-"H&W]M\a1FRi:/;[X[Q6`%fF.`!t00HESF %U,T-+:?*iIb>HQCbo.csJ%f\>T %Etr$d\!mm"*MKBoMt8@LGD)iO(sX@^V^^>W(b6!=h8Jis@n`.uha,ff2p:N64u=Fo9\9*A^0$eU" %rF%37md`\MO?OH_G:f[]>7THMKt<4:HUskeEjR(LY5YU`ldH"62>u]j%ruY4]n)W/R_N;b0"&'S"CX@3#E=sGVl'X9[3*);Usr6i %+bT/PNjJM17b?gmY5LRjhu@eH!d&i!faf'EI2j2W,4#*`A\;R'B@bE.QlD="n("JN]AmM;2L:o':?^B_FZ#0V`MRpN`[T\$LZg=U %51-jG6an$":nTVmP)6S@08O*\$f4>uLCFPcIJf$pQ$uTDXL8<=Q/(MY%12rA(*h9+A\,VJrImL1@gugJ$)+Z$+3:V&>/)r%KOs;u %;msr!9,eVocJL0ZFoA":=6k%Z9*ABF#Wc(]Q6Zm`+BQA^BCIn\2AVh6og;NH'[)cm_3,4Jc.K$@9\/q,)I]])X\CA1m`W6BXD %[drY7Kt$bMk@M8*pl/U]j5F7Zg5i=R7)/A;pY(t[O.[sa>OJ+(-\$VpWo#+q^\/>oVRdWmAR"U@Tukst:>*Xo%Gm/_46I+'"oHCp %rHnLS&Rchf(WYDiE*);)hRVD0BLIC'ptPSFl6Dets*bjskb*F?oT*N@8sc!5NU!1M!a)RVB3BK?<1OW*JtW]8QtH0G@'R$e4u)Bh %O'.pMOE7qJp<;O!,;Zq`JH-@<=:)OJ39.V\I<,%!$EB;HB$L8+O#l@?K8,O6_^L&=9A(Lj!CdY^(]P^EX*AfG)aUrbI %H5IFOpZfDB?N0rrIn$QPg!.l59A$H.p;8?7Q.P;JFjR[4i9:96U$q\lZ?"\o5?;\g6W0>J*TmQresi:\WAUTt"E@f0PG&<@B!m!Y %H*XAB=0cTt=hsA-V,h2h4\\+62i/;kAPXD-DN`&2TLT.ikeF`TYO,ZOad#K*[Z[CqckGbfVe[`^bin,"^)/qs5bcu&#!GE-k4JHG %WO&mWFD#JcitK-'K2677UuYF_9O:pqtt`[BjR_qqHR*ZmZIP%I9[oO5P@mA5Mn6!'^tT2M3'9_Qk?X6*kXNJ43&];76h$ %)SFf3C8:?nbQ0oHb>=O]"AQV2GA3*7#D`0(K:^c@b+Q#nC-C`p5@cspJt(Wfiq1+9Q$.l%f_'Z<=>bSAnML"Fb&,ue'pQr'We"dT %\J="5`ncpqQNQhg^`l".Fq.36Bd_Mg@asJKqGj($*U1Ceoh$h;\>s/6aX5\g#L"Gf1p%ds`dgr:4>jM.op;qk)<1+Qk!9HQ]P"A0 %&SS&rSRPN5G.U1%a^iY9E0%a!<12?n_#;C* %9S[3`WHmT3IPFo5i[m/n_uh%:;h??]b>_BshLZOe9[#_UTa).V9\mATrGfEL0+,8nc"@[-JtZrQZM/8#@#:pWS>Qb+"\i'b3)A/M %1ZAeVid/1bY25g%D6W`>-a&+;!sHsD+7>^QZSfW#=GYJs<5=%D;TY'-Q5N2]TI^P(]$NJB\1;`l<,fph,l9&Wj&s$2E^97qnm@q`5]U5Fp?B11J\%c*7,'+W.Y@ii/`o$MqC9(4Joabq)J[p@-Ertb;J`!1L0j^\N-ckR %,O&HrKiI%mP0Pdh.5F^%ml[=#L2NKLi0l)b%fGCSem'hETeZPS^p.JYS<"(%Je9r7AnkP>=B'(QINM@7mVmOlNI,pNU3)YCP+Q&"#dud[DW&pTsirD@Y5]pV##$5n1e@r/,1b_Wl55r]1"q.GY"jD>]9)qsn8erZt[J56]`\HjpN-]C9L*/@Y(+ %*d66JWtud^\2#!*cqf*NZoGRrkk20pCXE4;`sKOeD;\CN)O:6h"Wa'!<'P0sk';@U;F<(g?C0O[5C26eF;X-4RVmI;B*gn(^Jfn0:AE"WCGUStUO@cI`sS]cH-WQi3G)9Kr&Ul;BnZ[l9k;[YIMhe?7L.SPjl>;cDB"MYT.e?W!m"Vigf-L[WZA %X(Ap!3n?l*q_pt4([%Op,IAcm_fhf?n)"2(XJ'I&aXt#&mHrJWl7tp#PQ= %WN!:G5JQ3%g!B^%nF?$FmKF,q:5<,62!Y-k)XcZ!)%M6q/p%H,21"6;M5u!poZi2\VnZMCf!?SC[5$#^!*=5+%I9D3hc4i5%t/g9 %6ooM)j6:oX&KLS7_@.*u/4:B-8ZF.7"`GTTS[B=Vkj1d1L^8-+nbCn`Z>PbC##BnFi %Tt+f\]@&c*9C7nK(m5arF3;?;F4*_t--(i?L`XS=c=2/Z8@>%SUN_)ILPI-mk8s'>Fm/(i\QHG0mFULso]-;hJ\C+uqd[?IC`p,t %=c&!I7"&c3^e"33N(`XJS6gFPrW/'[DPi[H(B;Y1bN\X$0++SgeijJe(7Z^F3-R/OI^QL[>eJ%%BEXQ(a6h(5c7e\UIrmKCAR4$B %]d[S*iY`3n9OtZ^2S'(jY;s:o.q!53;kJJ\'B&*V:>Af##C,[eIq!.1=Jtj.kSom7Fa+, %gXCjRP2Y[=kNN$qQg*cJkNP=jA`i7jkNRkp4\4]!Z7mNQEJa%R/kM)@G?NV%ihGSYG*.H>.!ui5VotZ#+Ni0Pb.g@9FMXE)?!Z[$ %MXtp]+Wm;:Vb?K_j%^Xaem-0[L6>5g%HD]EoR';`%E3S'@X$MDmB5R7l#JU!#kE(/13%HUoQ6q]YVP[^V(E(kMmAL3#g6Z>_Pp9. %.^jCIh*8qK*G?``QRa'C>^1sjjur*:O;d>H)9?LSP2nSmoW`JJ+qfGC1IDeoft$&>Ju1QEFtNlT$+=nHZD43gLn.2%W>(+Bm9Jkd %jM#L]NOsi2Yd[smTCb_`F6GMU=!epC>o#;^B4k:r]5&ei9'bo69hIU??$tF5OrW91j`YjY,2+GsjO&<=DNoNfOM$`Zg=VKt=@9D] %Z8;jP_MF6^GL^B51]VYM@[/*MY3'p$R;nQ\#9%(ARUIp35p1#EYliAkqj)dTeB)a9F'LE:Yd.L%bEeF^rn[!&4N9!-=Hd7GH;V2fN-D,+f'D=-PfV^AVmNj<'Xf[pN!S]P0+-I#710p>er.E=L">=p[9ik; %/;?g2n5IFn?JZ8H%m,Y'CV;,g]k1&OoNEmT`ts0t?pkiDYbJC<]dQLd/5>$/[9g>&=tbb200O/9E,uSu)) %`_!S'H?i4WnWN"I!!52kS5b1g1a*^k/=2]M(rM@>Af'ghs=RAhT]HoM5plmIkQZHWcC7M)oXg]`KAjNFjh8k0r]4*$;BY %]Z9L78dEAV"+'(Vm1o!Pnn?:(eEn";l1.S/N9BG?,c]\noW.)kPS"6>Wc;R %%Q'Ac$M/Au%W82-Qb0.'I@$A&9:Vp'Jh2:9oQYVlbcB&C>/SP4L%%_D^5J]>aLR8s(:\ZktQ>1+.!kK6&ciMOa7^G]qp#!lNSJP&b)L/q<E8d,`nF^h)71@\]+!'<4Z%3f1H9k#Rcp/%QWeQm+%1Kq/(')1)"-Ck^ %1f+9A08mDo&q!OkM5hAqeKVQ$i3/*o^8jJ;[OaNGoRcgqO?a9I1+#1)qC^LR7B&JdHF""l%Ti[Kl\0"bEi=gNi5PdR<5:dVosd!Jls,h:)\9bgWPRMYc'1I!DgASKTcKP'Yr5kJ>5WI`5#mJQAGA:pZ^ %R[J_Ucn%/1codn^h-iOB(Gt^o8VDo<"8&@kHKrJV\)n$'7*l@U?TbVPGXF8X3-8eMn:kOgL%37b<_gZ,^\V>b<6e=b/ %Xs%DmP\CogK&Ue[aZ%b4Kg6L;FE34h@JI/qa&!sd##!]kAjSieF2.0Zo-^`4^L>^5cpu1Trh_(AZ.\Dj;JZ4jf+!oP\Wgm\=#;sR0]Qk %gYf%ne^fE7)Hq3/!f=-$'RWX%02H0Q>XQATkrnM*RBL#T$aQHojVecg$YOShau(I)]HiEY2'f/UP&08!?Cp=$qnlHsaKU[&N2mN*SBX,aP%rJs8P@N*X0# %1p4hN@!RDl(]\&$^>hsbCN1@m-`WOZrgf@WpG^?;N/NEtanZ!4gK,M(++9hh0j>DBE+)Gs@`1lMki %F8i#H,:^?c>rkH8G!o,9(MGZbRe]gqSL'+4JG=(1LUKE6-hDA[>g6OgS1,P"NElh)fWAFGN*Z5W@^U@c0m97_i`FaNZ)l-["7HW. %@[;0(jWWUP]/=<`4t`aIHX.FXA!\Jr_/]3#]CKD->H$/rmq(LR6&9=nrd[lQ+cPe]AehPL6`*=.RR?3*DDm %X-TU3adodj_Y!hc"Zn&5rg %f6Vs%JHap>^Y\F*QP0Xb]`(mPauJ,cS65Ig6>u$=4gAj5b'juF!3]]#c=HG6\m(APl,RVBaipu %"X+(]WN9XQHPt]`6dW[b5Z(Y$oG5_U`OqOjL@U,e;-Vf-Y@2Iuggdetn+kMpp&h@X/Zb);lZ;PbUYOnTYblT@gZt*SaMC!g#kF2X %Np'W**(Z8F-V>%Se9_[o%/\"3<[6X#.#G)r`l6$7=>1/<)$nmg;GqPOK-FDO]TVq<_1rL %@FLJoYE1oL&>"=$]L)>!6AK',.^+psXjC`9o2'&qB?.>+`uBl.9\Jt&amkP(#?)]Z!g_DmihU(s!(O+7F[X?[b8`j^=o!N66P8J&e %.ZWhOdn2e'qetTZG+l0)W/RX>T=`foV4RRp5lW]f/@SY9O1ociWj^g;G-4uFMGQANBGFWr]U2p9mf/PS$tmVe$Oij;g$t:._llH` %h-Nf$#K[!A#,BD&pCJ2<`+[pf:`$&8UW7&HBA_e_"ij(']PIe#:b"mWHM.N\B\^k<6L8P9r*hMLB2Nkk_+t[)h]cQ#X<`Z7rt]Tm %U$ptUUOh:bfjOiGf'I-oAU:pG7X+U(Ork\\b@p2:f^tW#>l4t"rt[mU#epZ:D\47I]qU,V>ND$DeP`%GP)`+mkMIKO/LqTpP@5;u %?qB*%*KjhJN%n`/Jl@WJmC.">11[9j!+3:=_Q]IN?(\UR[/DBNO"nQhR++BNJj7*_8\/,)cAP< %nOnrP(:0Q"'adHQ.!uIP(.W %2rQ7q%s6iHPg80O5PjTGEjok6Ta+"\(%WYO'c)F/8j?gjWj%F[?hC?s;f\Un'mE:H\QjhVoK6G8!Eft3rW#6ZUc'(Sl9ZSoEiq:# %Ms^GPr1jCuCBL,.<]_\H2+LE'Ou^;B.[e&.Y*#aCh)QJEnTN97gM]3ZH_9X#L=OHBHH4mC&&5rY#3TrN)&cb#h[YbR#XZh5P5 %$a?C^Y6-++H@VR?Xh8g*ip-Rh`sf2ILp+_B$SMQ,Q5YXL!:cjLcq,gBA?!rZfMN(2`cT%P!:_):UF&aB3Qj_E+e[]D1&+@'#nZ!6 %(Lo1+"Ge`0J[;%p&Kng>'U2nY#`q;!=3LZVFEi0RId]c:Y_.]FS].;2c,hV.",_NelXJqjPO$hMaf27&D627u'[<]!$#=jZY0eMr %/niAaY6ZM']d9$IlmUlZcopM$Yj6q@WeL6Mg>8[ApprXOqb`C;h;`VSh,m`3X1LHR*[f>-Yr4VIUBEa;OpreCUBJr(RQ*SQYMecM %NQ3QFWgiI6e8k0#_(1$l,q'"V&$I+tKNYPM$@Me1YW$G\DT)?f&/O;b<<=p"fWbdIhZbT2XPB?X^PsKPa,N'nNPW=8iBqEWV(b)d %YT]Zo'#fWfcNQOen0*-1SpUfP6P/5j`eP*`"=>ElHjH.fi4[ITLS0jRm^J<:SmFcmc8GMfCqY/J%hZQq/(G.LaqZCFFF_/h$3anE)&'? %MC[=tP:::lASn5dlE<474!p).5[rJ`^5G0XYtX>i#s4m5nH,,@jhn@W9alcLg=>P=Rj.WEq?U>4W>'e#cs-'@EHu9.,al-!b=fa, %ojb]c/m`uGfM<8ZOQ>oc(jel^"\Ih:g\Q8r>J.TT/kC$HSg7H06'?]qAptZ>*tqJ4jRCWkHV?gnP+s(T4>0qIOrQk+ITQ(n8933) %iOqGS"\F`#,krtn$BcD,'"T\>$BcD,'(!FA-qJCJ9AgWH>EAuQ(J]Dc4d@2uOrXC_ah/!;fYgZTZ11J[kI30>E*4;, %,R]>Z(q>+j9rPl4T5qSJMDWsnjBti-MDm*$Bib=HqBgc %n^e+C4Ragk]"1Ga?BQ.=Xi9FhbTu\>Ju$?[(RhW?qYAOdFl&80L=m\cB^m[L`@3X(3ngN&oIQb;0+Z*53+IfQXui!\FD082F_-[% %\V'+/060kG4SDElj6XRKA!JGB#Br^6I-#[;7,X,G\qMnqZgGkG@_>WTF:ql"[J_&o7TA_h])a%5m?WhGo[fJrM.aE?<^\n %Nl^OZ^h`*l%10ZO?(XpR293LJ.^Wo-jV:(T?(f.J_/O1iZ3k6J`c:A5ihV]Z"uFFR??\EDp6#_BMYHVn/=pDqJ,1_>P/H<7c3+1Aolt0i6%Hl(aOPN:M2[Pl_.T#euJjld!aA8%CfJ %W4O3L]]a.;bp5"@3d1-Qem*o_?Sb@FL(5XRYWNVcSX@gV:;rbWIYfAi6U.EIZka=C<+@kLSusn1U)&>`0M2t2=pS_[C9E!n&]EXT %9FtsDB<$bS/HiE<'o!=.bUPfUCO-%e2YMdBWp.p_jOl*!IOM"h8!99;b:7j5&*B$g;2b%8;V1P3Z8g?#hWoW>jERV7eM7(@^"#GG %MapOG!7X?4,=rZ+>5j#n,%.J96+Bf0C*@M:8J[(ba>K4cU)&>`&E4'd/Unt=(4o[7R2*-:(3>P)?;"!%H?n4U7M:M\U-4dmlN_Hq %EW]a8I)-W,@*A\2nHPH%(H7otC.ZN3lG^q7dH$pn8t.(HUhb;t&R?>Za4s87X(\nGh,#c6[Yc[X>.*,,O89f4oY+W\;oS)7a%2@']&m%!)_ga.PGDo8D;k79-qQI)fCk=&q-NuO %Q@e)^heq %+,lQb"t-e0e%p_sZ0aL6GmQ.:;5T>#+ccMUGcUcMD]IXkP5Rl%_M&]\`1E^N:C/\eTo1/=(W*IpK*uU,gM]EBNjq=SaU&$%-tD3# %Z_f"PX(Xum+P_^gc@)`+NN3-0B:ChZUZG.WB_FZ5K-T#JK_^Bo6:D).ST %/baL;e-`:hBg]+D>s8'[UN&iL,V[=aa]rKpU)3MK=V.kUQVT^=]CM4g,NpHU)T+014Vt(:7Qlb:GX)+^4uCG.pUE"nJUbel0\Y3. %m39KX\:mKiK_Y>i/A*JUR0J('<$CWTW0J($nEo!2rT4&&g=7Ehb"2bbqYNT0UPLp::0YcV`MLmJI %iGQ%(Do`Y'b7*78k/4Dkeb,o14T/r-aj'^'0NJ3?R#7jX?U:(,!5]>KjN#D/;bc)Lof\GV(;^AFo]O\u1-JZX+49D!OD.LE?lc\_O&0*5K;#MS*,k0-pVZ-g;#JN38,c(su %k="F=bs9b:^Trc].Ar/ER"chc85@njV%(,W`9"@gMZ[i,FF!ZCZlOJ?7/0N;RF>1in#cfB6u_ffjg5Vg#eaTBNO>LBS2Tq4-!=JJ %)]:^k^Fq"5NI4d=/'X\7=psk6#Lc'F?R[7uN?B)qoa/fU@nQlaRaX`>+uI2n%6M?j!j+/nEnUdnAF8C;S^U'2.HpUrjg9B#h6;WEn]/d("gse]l"q=>o<5FhtfuXL>Fpi%Zq&u]hBt$aL)3GKJ!);g0:oUr<9#D-#EYlHKi"E8LiDI@3Jq2\bJf`';=_) %$GONri6.]0D1bGaCP76->Re1g-!d/I?PH$&3Zb5m4i*J5*OgX(2$a5dBZ\4@g14R+2tle->daQ5L>U,OhlaQ6X9#tuPPb"Wd5HMko[4Z1,\\9U!Ommi'*KgM+U"to+bTn=u]A7\5K:o3bF,WWXU %WMMC=n.pr%&_RX0_@WDf/7NiBM['Kk=EKSEK-=Fm@Yejp(c+YrpeCc1Hf)Bb\.5Zg"hocm%YQ)Q[L&pp?3ta^BLD6ZU"o[q-Tc4. %A_E6t?@/=;B:`*-PIS]kX1,VV,'-J=b7V"nWmNuL_%Eq-7$t<"EC?Wo*"a\g`99_Ro\cD2_SHi';@c7ZLfeY^U@N7kX:,\$Y>97\ %J.g'<7B*auVdEAHW^[Oi[#fXihQ90)Pn$UE@d`3gd6XPbbTZ:W5%1MPECB:tNYiV-8IKT%Nej2FE:gN:?"[5[c8#J8Cj_8!Pp$3` %2a0_GFT%N5X7>;m89P5,>dK+Q$PY2g>WBM2XTDO+26dLlONgIml%dYR$X51c(;>+/Ng_D5i+o92ATdk6Tm0'9c3r:]D$"4t3@stV %Gm;5U"+$8WVCQq$#hc5n^5:)Q,:/g,A2917UPKd^H^?HMLLBi)]tdHLQMrVH2Qeo^@-d %qo0^ZL,3'NkO2.9/ainS^#iAkX,bc/No[=A>&Qn;*FM4,95kmUt(Gc%AIuL$$H@ZQd)(7DZ082aoHE^SUD%49bZf4Wr %8!dc$DDX!N6[I+0mtde"iEV)9,6eA^%#V/AJiJ7E*Ah'?%iQ:,IP0Nm7&h9I"f1!Y`/[f<8bP5s*]Nh.1 %q7(XUQS'qh5IKQRXf.l*5:81G6[,hijA+=BZkc5-L]*Dp<@5Ygr`Zu'c2ir@"V^E+[5c8Q!-NC %b1QD4G%q8!s6'n=*U`9Od?YJ^fi,dXDli(n*Tg!VR`tX[8t_Ge@-XC<=U?'4X66S2V1Fp7jl`850.%7P-VQ %)ZfZ-5\`l![NG$999ItX@o5mBNhQgV;'<9BVul?VKQss0oM*f8s(F`TtPZQ2LKq=Z6ru"F"mJkpYC#8ZWR"p_IWc"OgBj'A].&L$du_N<,\Fa'!$@h@1nuNDc)h.%aODRWd>ti %hVbu,9LimEPBDi9GsqBIR488UkL#U+L$pL#r;1-GTfUE3=8JT$DuNFIec-LN(O0!ndh_-KN?B48WoT=If8[**`7f4%ZS@J`oDgm,X&\h,s='Afq/(MBHcM8hsVJ%`*&QXW>f %r!OI@o6ntV*1+2t.`d(7>n7BR8tDq#(LTJuS]1V9FFDcIL&Z7Cs69CZ3F/8m7N`IP++L^W^TMJsDONGh51AN)M?k_3eSRE"j1u&7 %$0LFSe^o;n("[HN[ADpGrnPb0osVMWAA<2bGPq6&d9J5@U*9NDi'890?,R\EHo<6,?-"]D)6M?OVVW1;HJ!tJW'hlYg5h8Ck."8R %VeAdl0PkU_8>`gfqWYIm7K9sgUL0f,$`kf3p,kg?64Wagd-StI0$^.J@.%_gS_gRU3HL0[Lu$OWdi/@])=nG3Bb2uiq]pZJ9usJ! %ChhSB-WOLpKTZ2fgG"d[G8R;%aAUa8ZQrsmL@8Z@QD=h"0l9Ks@uB&@1f^^i%n_1iYA_usF)[Lekm6J7[YD!dm'nQjh,U\i %<^)JU1bFubra,#qI"*,Cg4Dg!<&U.L#2;-LlJ9::po$![pe(6pI;QgNO,QZ6Xj6`DkAK+"Gr%S/U!@+*0h`sk;lucViCY$,GI'n@*J$8Rk?ZHI+ %eZ.A;QpbBC87Z\X81liI-GH28/:c@)`Ke%i-@/LB6K>FZq3%#V,C,#EacDYGA[qTS2\=!\; %7t[9l_g/luA[@FBpl'ReqtmRM\SL3q=9VSqY\s**pHS#8?4NPV*/6oGHhH2[SJT!&\J]"/HCa0.K@\Mpr1\?pe)0FB%.?u#H9feQ %4u!0,5Bp[[oQGoF?/BYNWa-WX*[\Ht&B*sBgS=/P68,aA2]I84f5'm@CeW]>P8D_hrb:F=JVUSB=`gib[9H-J.3%iV^]9?I[XFpE %X)H=dQ2A&,Z)&iC?9[c3IE^J+]@K)".E+MZ;lAt6#(csPaC!2_`BV]2ehin1d(jQ_%,eL-e4FB4;p47jcCUIo/,/Xn!?`fgofET( %g[MjHNE!]GW1l&EZRqW-lY`j!Bi+mH.U/JM>i)(T:V""@.kI9S/`@90:0cXO:9Zn:4T4Z9ZCYq+Y`43g"hC(K#_qtiT'V0Ai_pnE %PJC])*n[Wp_T&;-8'[Fs6tSDAR48J+I[E4C+;sHV:,d6rCq5kI[uDsP4L+[akL,,Cmak879F.`SGBff$2=kUY=*luC@AiV\AZq4\ %hlufqg5Qa_@h1X!n+u$cFo*Yol8G./Mj&"OJ&lO0jsoTV3_9G?'o:Q28dh"!agdeY,?"@Wb>.Hn/f)qarjJR3&K=2 %9^dA,\!SXZSb;Zj/JBo"Q\4s5gi!AmHR9(D6bcplSXlX$S.uQ*VJbfV1E904:-Bkd-ca%r1:_KH,PQ?>39!SDrH+-94_oiApia)* %[;E%)+P#]l#&ZC,gr6:1jW0`-_.bX+L %NRl:ponTA1"PI_/,hRbVk74ejG?:j7eCN]+]$PT)?!["`?'?N@#"jildtM'chpk+Q2ntd%r`\'>ior4r$g&)QR%>p!Sbefg4C+WE %Q'FSmaLCZaQ)+oc#p0(cdfr*?&Q?05ndpNPSu6%SGVE,n\M]0s9CI#U.mQVp/qYtg/(%4*@^I*skp,>5p??&Ipd?#*>) %cE7%"WY1Q>ie?KEmYpS!fui9WmWGCmD/S1uS?WEE#m'=?_(&u>6tNp'F'L?kc,4RET%\`H=*0JGG!6,Q.RbVRS'Sge5Re.86LbEe %I+?EA8`ub%OW(0L5J$[IQPcZPa)jl!Po?TPTbfC-;?Jd='[1Dj(!iH;lUX6)0in2aK';OOcs`tJ\.TUfRlYkRo`:?BF!*M3mn35DgAMXLJ+\<) %"[Y")@m?A2)J[t++)dGG9!o4p3ZRIV_(,<5btW;GZ;439!7B1nFOE%8T0$76BJsuqSDD#'6m=JR)VpF&@?gXYID8kb2QR8V`,1$: %2)s>0>3>fO_mn,[Dh4sMNVn+7GU`lc=Y.+47`O(%r %MJdJ6\Ziq"\G?er?SQD)FCsUkJ]72(mDBk=bN/maG!+?+FIo\mcED$di]2"GB6+UW&"81fm$"FKZlaaO#EBSH]*n@1pthUSm@PG, %4geTgZR$%)b(W(#0:i+:;6p/)U8?,HD>n$0RE.KQ!>_0j'L*8QeZE:)q6C4nk+d.T<;,)/Z8W]PnbfllNX*41W=0qf_gDebmLarc %h#fKpSYbhYM5T`"Li@>r?NRM<`PF8.mF/W#c_.8`FZ\[!7c1?F_9TPf1U]g;03sg3>A'l"k%Zmrf!k.,cJ1lSn#i+#:/%)RF*1ct %FK$C=Zc.?i+$&#bqabGb`jiW>jsob@s!u7bfSAnC?lIc@N;crJrP7lZ#A@30LM(K.9mZfge.X\4)sED6T:XcKep^ZAh!G\+I^:>#JgqiUkpruUDN8l\:ggS %E&2c>[EuN@I/uU.5AC'HXjesdd2JEYYP)p+p,tC`Z"`(t%]7#E#N5RNbTaN!aCTpXB?cppE+eQD`.6O$mn,5q^N\.67a`29o:=?e %6u_BLB"N$YgieTnpYn)Xq/T$G]BBX#X'/!)0a+p[.B7%kN;?NM3&!icku!DN>Go9^FoF-KS%*8$.,24niH_c:;I&L0NqP6ADJA9W %\hD1.#siL`QV76k21aS24[5J')?0VQ<(Ed-q^dJ4#3(kZa"-IK%r9H0s/;V7M;:?V]dH2> %G$QTp=hK[sfdsLUP+a7G %@`csB2L`t*quJr;>"p%Jk=c/*]Q4#W/Mi"iQnl#Hn'p#8(9O8:(1Y8OCX2A4RU4`B/EU>.e(%"=\d,@4c//?d %n(BOmVos7)\BoeO:R=*5n+s\#U-2e>lF=FdH+MeWM`ae%KjL>5:5Ysm8tU1]JPnU9em9GAFij5s6(ZNCeKrPj"UVcFit@bC?)HU6 %0&K*,]+"@F\E[S9ct^\=GHlJ*aB8Y?4^E('QY;sCaG-.n]!/(?:@"'V:Y1g]9o>jl;KPR7ac3I6MLu?->:^,=LumkVrF,nG.+H^' %ktL(14n*XHnp@s")@aW2\m1j$Q7,OqV9E0?^X8?I5\%B+7dCRG$:mV5G;7(2DEHH!!a::uh %5K=?`.esl&oN=;Z%hH;X@YGC6s$R+OY3D3//+)[Z1t<]sjD#s-+JXmOm:^6g"_MI.W!i;O@cB"'Gu):_,h*!5ZDB?V[Dg]q %0.QD\ks3?+0=^ju"G%^r`BH\&,4QdL2^MSF/6?qR92VIj>[EHV_>]V6**67k"Gu67jFBu1C:Lr>ncC\CiKq'*)AmcL.Yr"`ncC]8 %_ului)IZ?0_Djum]Q&C(cI9l],>c:E#:h6""0Vdi\%&=M8,ThS-;H"eM!VNMN!-)9H$qL:1bnpLR5.5^$SQg;!8\`U%)1*330MSq %9c&cU>nip_q[eMI4jYgpAP!G'RGpj'Rc\kN?$s[5.j`VN$rV?SM4 %K2-n"P$`IkdS5FG3rLu@RaEnn(['NJg[F[40/Lu4R53bc+pj]H-8?bkE?G.ZbFX03h-69S?"AS"T)CCao.LrLTc&TH[36HW.I+:U %Ph?9WU9JeV-G5B/eTrs[^jr`sWqEBi$`!\rp&:Cdlc!9/ReXi]C:tHV]jQ&KZdt&Np4\S3DlqX+%#],UH81Y1U",=8er-6O$gYh. %C:tH(?SShkUVSY^pfMgG4LJK(V-]8;'XuXD=`E5PoMR?o5(D?k08<@Xn@j`RQ7'r0MXY/%:Tf)N&3_P^8sUh*"OJTS9pR0kp?Zoq %L:PSN6uckQb]"+p^R3)QGnS7'[B8(lH*<7TF?SQqEP>U0L22\'Q+XM2%&I:g)W7^i@PE.3/^3a"^#n^f@?&"F0Qo^#R_@]DQ!OsE %ekQE-H^T4Q7;]=*bJ:Vtue %h:!+%E6.;.qYP8s87+$Dh\*9>/!?e5Fq6)o\*L]MZO8k:.iSP([H?'=S[MJ;:;D!.7ceE#>o?q2reX=DTB"kk"n8JbT"f.bshgJ=no %NdG[lSU1.tW-,@*]@fe>2BUBNGF.QA%*&[%mOgr9rEVL!6>)W%G8IoSBq8O=gg/jtoLH8WN07fZP/fYtOeUnic>o!E@4Mn5O\hCn %>:i$3_a.RY`DWI*G2.dOL/=Q`Su(D=/oX";Pb=W-Y,E*hT,_hD$T`u1jN/&gYPa:j6"m=,E4(MU$2j.S3Yi0Mhj= %0:[#01Jf;-^JM]^%#.uK!];\(Jj!58JK"&/Z>XP:CQ!JeQA?"U;;$`l+:$KW"Q@:^Fa %@3j16>[oTuUMQO(k&bWrO=&lJftf2pEVQ/0Z+AmbTqUS\U^m#Jk+P+W[UFRa5NrNW]jMb#[mGCS1uBP7T@ %Hoc%11c3)uBe!nN%aA8L;FVIiU9Z;NdF(F_ojU0t:4m!A=taiGjV$gck:uhnWC!n=9r8;Y=t^*7(T_*YN*e;V?OD:b(PD+5d)tu& %(Ag%!0aYCF%Kcq%S#fj^B9*/NajP2=*tL,j[09Y#nOU+S20_]UM?]2i>*'YKRi_D'B+.uHA# %h8s\GfMq=/'GuQj(nUP7_D$@3'id!t_e9,h.p4RM@DJD?H1AG"cL$7t4Q@IW_J%AIDD)@@2%81*&X7(p>X-2M"gtD;/]]f^Dto9< %DB^Vho*t6\X8;)T9T@TT2:;$9-,OQ^f(@H`[Ul9H]!5*ME6bJL3VtR&$11#H(u#Wo=A)Kt6l:TBX>][FIQKWF[Z%m33gCNIg?$P( %_&mY=KXK0t/1oK#_-/2[.OWip_-3/B:&kkq>MDi#s4DKE/d]`ZFD*@0D@`!")K$Y@l^ckuZ9VoditJo'>qq=E7Up(>+jejFGI#9CAHFGSg(7ra@UjY.NEp3lNh2XUg";#5Z2$qo %$0=$K%&CP'pL1Rj?(b0e=M(@G]-=/Aa"hhs$mKNT6Dl\/)&1u\(%+[-@I,cBaV(9T"tjL+0N5skLTq59$X<$!O0NIM%p"RmbGDe, %?>-YK).>T8f2SF_K,drScM1%Z;An,H?,""1VmI.JQ_L?%pNQiY]B[Mn_qjl5m*DSWb7#f2UkTiJgE,gEnV8&Ef+/Rj$PelOYp$G6 %-bF`p`0a=hCIH]?hGe>.^RI]?KS-XQpL$ej\rd&oR&&G;:K`d`2a'7(-fgV&6fY26a56^t8g[Y#10aE*WP1\c`q`@(.MV %Y"PFmbOY4clFI*6-S&q>FgAgBACqh3W(n+1S8>TEOfFU40+L"eOE@,,Oa+[XB"thZL1KueB\/mUc_tu!':nO9qYIB?oY^jlHDSC. %#+b>iL)dE1ICF-YeQ_Yseo$u=l8\/m,A9e0oUDJ%\M^/8R,H0`A8#Sf=mfUF*m\WR_f""2)=?fV]kRWuQ@0U?fV\&)Z6)c("d+Gb %4-Q?kBt?0)\pb(&:uZ[GGH5.Ea=6#TYg-cJAR\q)1FX#<*-;K64g=f4@eO8QiK]fA,FU[cG:#\Oc?*j-kg!_[*t-Bd'%ND/hN`cF %AC6siYZaf2-;RaFhF44__n[*VKZ':2$r:N%oBY+5"0HUSUk%;\dI&WaVpZg5g-B?I?)q\-r*/"oA8'"#69[\V`QTq#lLuSt$YN$m %ZhY(6V)=aWIeInNnD6W":$t_?YSnCc7]*=ALc;?A&1gNILqF>1)O\f:TfY:4Lr=%=.SXM3(MfLR;*W64RLK+';QGrMCCh2[;QGq" %0f#>.@oag9f/tUd&??'\jqXa4Q"SF`^9g56_F2["N1O&USe5=9iHFdWSlZalXjGJ4Z0)ik:FjA-El>W- %k\5a.)Ek8XH?-Y_&X4S'5'h63=tLt3a%&pcLNWl*B:#"*0!+B6FEWLTm(s/aV6`fg@i+tn:1mY6HID;*G)9r"JojppB:#"*/k(aV %.E2dU-hiN&`l>nfeY7i=.r(m4pm?&I<^+8\ki,BOO.iCZc2@Y@Qrqn6^eDh*U%(a^f_Ci-n\Dm/ort]S`_Z&/YV;D@)nZ(SS6VJ9 %eKR]?c2T:hY-k=r<;oWS"SgWn"?r8!d %(P/Wb!JGG0%,(-6pC"C=M`Vk!dXX]C]=>3+Yp(Bn\19m_(O9kMHVBf8/'tGQ22\JiXfpKt_G0GZ1&nNQP"7/_0,(>*kH@97F7qPT %lMc*(/C\$M'+Q$ICpAl!De#ud"9bR&(DKfW!jE+4MbV-C^3V2T)-g@!i37G1 %J<[h'YH.mS(e/mZ80=(i/fD@sAUlEmoQm%n.]O3PjZAA9?Q#F"MF;Qs'mEmhk#A'jdP2G0FmTZp<0s*9e%jgF7:%CMG;RUJbAm%,NSKA."5q?8F4gSL1p! %%=E8tMaheg^4!:Rpap<=naU1E4#u4MeoliE]D93U!Te5#Vo>RAVBj1QjM`W!gbB#c.GB+5`#&]V)6R7NI;%6c<r2sP_<2m-Zo/D*6jrG6 %Wh,Zk+..7h5fW_UQ8uSDj_qmEo.]!=\uraOk]Imh\^q;C56D+3^R60LSTP"U1$XNU5Xu$@H$]j=I(kXXX(Rh1f?AY9rgm[^>Z4V9 %T&osh%g+fr#pF0i*;[09lmQuO'?NoIs;Mg,oUQ/Reg %C1%j\9QYB5=@GJP-L+msGVu?RdEs9"Ctg(DUA$3n(OQCt^qd]'nVg`Nd %`&%J33[Urd/"U6A=OSg/0jt5mr#OQD"^cg50LsqBT\q?)!XI%*U'eU9lb1M$ZClfQ5SoeXT02Xpm=Xl&.kl1=_>-&S5c;1pf.T%a %\<6!r+&\T&SX;C))[^q5^g6i4V5LV+"0MH546qXX0#HuG!"HILJ+_=]D@um)1'V.mnTFkJTRm)'25d?q`W\Wr\b+V'gCO9bJ9-#6 %IsKrjem3q0[L"/Cp9[NjU^t:n3@"@03J)$(K&sENh\j8R1iL-Mc+m!ga59_Ni;(lDYb>V?_Wq-FLJ8P?h:2ZcS %5;sni^dslLf%u+rS.8FhLU3"tb3:%FFJ,NE%87,4\di.2]/ehB<`#NV"qLn`>!ABWYGK!&)p]?0a9R;\/,N?S5g3?_+Z&:)_2KZkbm='&Y5&9X3W3Jo,K;bIBf2`&u7<7r"`4< %$q_8+P`$W3N?QpphT0\80)XT`(u=+s9N'#%jGZ/aFG'>-AYiWk+5Li6P$234fJ+YY^)5\JEiigM[Oh6#9?HkGJAc#q>WC?"^krIl %\aXeP6qY!L8Oop:L3FqNb/GQL-$s#u>5ZDZ%EN&oa&D4o\UYsS^>?CTQG(+r:KCYoq/"i'/>&A %Cit^!6#/lMh//j.F1$c-e](47]Si.I$n*kPJZig!ECkVM@HV7*UKsGXfDj%+E*`)8ds2boRb!p'A5\C-kVI+65qNRYEBGK*;2YMp %>\o"E>(-j\'=P6@A>'cjJk,rXEA.d30(Dbr=.g>'UVjDa"grRc((IZ2R)N%)GYq,u5R_CI0T2[F67mnV89Im,_BCFEnUFIQ:<(Eu %PCcuN)0^*t$Tb9\qu_<+Z;?JNd@lgs(2@id,?SAbTb[m>9_+BYTG@d=R*J2^W5ZS(mcJ!+W5X%O]5t)CUDE$]g3^%::lBs/b[b2f %eFFtJC2kqcU;fMOXnga^VUs6pK3k-XR0c[:N/q.%SkAbM"&F0u.I2B?&WkH\&0E&L4CXHW9o+j$ %`t"07Y.:.A(:2af$\:;kLMTQil%f?sb;f7+4`5!4Z_aWTLX+1\(EpNg9pdPd %d4Bho$V#NoDI'$k&V5JMSX)@H#PrAmneD %1:kT=Yh"ppA7\m,r!I`pHO^gX@@?7Zgc3jN9]9Vdkkp=Wmh6P(;C%!NcEG$Slt9GuQoqP;`SjlX=u%=E+&/Vj=:@iZ<>>`,I1Zkq %SR4*s0fcBQWe*d/lfDK>X2*hCEVL9qO,77HkV$tX+qVPod.nDu`e6#sFFFDPr<^A^bep[3q3<(''QdaoGKUG?6S<@31T]gMHm&Y: %\j"qHY:p7$Bn#40A5A?cGp7HjbY+'.%!MW]ekj.Z32l%f@B"YJJEiu[troI6k^r70CPC@u]^ %;Sa8?Tid#%<'WGp(9p$43[sH:*(]P">&c%)Kc#$nY"b@]iZ-+]T[OerA0M3#i2/XoVTL)us'FO`38kc?'Fd %N.f*A#nd_H2[?'gBg0o)naaUK6XiS'!)5+Z)%o:OP+k8\;O%K#0iT=,o(ii*&k)qlkeK\%_$\(O'Ue#R]s=sY8/%D4ZCo9i5aht+ %8L@;\;Vs,pkA1Hk+_fW?@3N=mIK#R.'B.K) %"amH$_&$8m@>u8!9[cC!CBV0TG;F"?:SeH#i/<%Pddb[%UOY#d3pm2Z/,?f2?I_S1?N4K-M4i$]!r2=P04)s!( %I*g''W?M[sq4JQ#/WmhMB&g+ZaHj,EOkOI<)d*m9nc1:ECW]BDWs7r;lqCQ]iXL7es4,Bf'R-8h8.j,FqnP89YWt(\)dQ43g*D)A %)KZ#<;DT&3XO%-AXN]l[pUL.aG=Zb)VmU+Ed^8"T7,EP"1IRFR/7([U.mp,24<.306WES17%h)JcOil-7/h+>1.8!k-n\$.qPqR4 %A$J$<& %FV,^+%ESW@:R_p[S=:p_A-?'4(a;D6&nDI'Dcs[j?]L(UG6"%:G$(!TK``=B.U\NA'1Z0=2 %@I-fCr&K5joY6HMm=uE.D*ko2O8WT5oC0*leCmtJR;OZ*P(iWOgun-s]:H-Hlu]OCdl5Vo1&l+)^4D-_4W]'MZ(>;u=gs_X%cbmF %H[oGGB.7ZeEWLt=5Xl8b-FqMe>_MiZ^*XiN*ZUot`d]ddme/I)r4)[Vkdtt%fKhm;YrtF'jeCPc3]gV+TBP7<^4fX3dt*5(K,X*m %3p-X3j6,^=DRC`UPN\$tSc5lT"dSGtB%P)lN+Iq/eUf]btGoX)$WU=FX_&Ln>n$5LK^X\:L.L9_2#:3K^gg7+(c %QF7P1)X.X^amY_r25QSlV+4:Hg%BNO%UCaT\[egcXS+`K;&l41l)E;28cX#OJ*cKQa4j%,S$q)"\po/D]h>5rGHtR]g`o1c*_l![+mg*Vn9[/[3\$HBFE)GHhjN?:0norQ %me9!tG*jW>,1Aa2TJ>?U;efd#59)^omZ/1%qSIh#d)s[c(`3TFnY<8^[Oi!9dp7IBiIC(H[_#?Ig>h<1'K*%lCSC`JS4M0g:(lg8 %q$^5R4sX$uT8SQU`U.eW0u%ZT' %afcN7O'ach-8K4.:]q-0M(ct@U]b$1+>*K:q]CC-<$9_BcIcMXGqV2o_"TQ2]5Vem2E5V;J4QZ;WiKU12Sd!=M%niMA-,,L;!9"f %I,k;qmk9"Qn7\:L>MWZGhDb(-D:VnS'pY64C$FeM"V_fSS8&Zq'FN^)NWFk9U!Q$/T6u0d51/d@&esn`X1?#B+;?ST7g4Ged$6H7 %A9QVuN@_ji>=6Sr9m/(.l\8ZONVQ';m_JE=+qbs6l^/V'Bpl< %n%!u76c#m&[/+C]s+R)rd/SO@XeM81"%9Q-4?D-@$j[S*3m<2TNs03f*7NRY,M?@:K4qBW?a%atp!h7_(f6BmU!qj%QVB3^_ojb7 %`$W>[q.0o[>27lX4jIdoJ&UUHa]q()\:*!6c>CO%n-S!+8Bh8YCq^?SDbn-pcRQ#5U&Hh`XY5pH/TftgMq8cfap+8XnhdpFP8$Ak %-u3$8IO\k%KsISLGo0k&?YK=YPT+g2cRNSmnn)M>W/dG"MV=P.0R:;-.pYBLRJaH7TXjWW-Y%B&=.=,0QPZf2=KX8OY;#2@hlmMf %2#&W'@<:?(RD>$ipTL3kq6Y*9i=c-flL!9u"1mNr1\`U*b7beJ(+T[X.qdA=TA)1*Td_HY'Ul-BS&[oL2$hIM2-BhnFse*n?t"kH %hTS;pPp-C*R0b&7%[W$ejg[eN\%(i\/r.WW3n!D6RJ)TXF1BR%>'MMc3*`>X&c_#!Ur1'u %\,_9lh;@3eT+bg5Qt"YoX=19iL$ikV!Z`mj3koreGs'"8/\EYBMs_cY2FL3\]85Nel!5tGU"Mu,e)=a>U$WS1H>;&62sU8r9E.hg %L(/=qS]hRffWO+!$,#eF]j#oe@Rpou.Ad0nblXRl>QiSZ$"l5a\N(e6;5CE]YhKR?XLP-O'8&&f=t$K-)F-\.I/&(Vn!qT(%J[0% %A]FUiUNnR2qEtbKlOs5RjLjWEq0IKqHQ>BVdG`tlIe5e)lWn"K'=1;cHMuR9Q.6)C6r3jL0j0"3?UcY@*a&H)-qV9HaUSr?uKF\Cp;I#?0qQuhA&6o=nE!Gkb"L? %O%OJtnd1jlV4XeV>"384>B:ONR_3K1=7Pjrlh0]W_&[(]#TU?,=m,7!r;3Nj=2XH+[P;l&4o(-JOOfp$%>^K_YOdo[F/E+_M*X(n*i.baf]WO?(=^%2pAOqk!dbS=8oCXVd$qknnotY1s6>!KNWfJJ %2d](jY^CD:E6Qml"*AVL4V)M&rTSHjk71Zk0Ct+Uj\10)[kPHZKu"io6i"ZZq7>6!]cH&jM"cin_/e[Hie[G[_QL7]qh9@#cqEci %c,SZ;Fi.l=kIZq%d_l6uS:;GO*rGH6&(o"\C:B5IVMY8U7g8$>QhJ^GUK-a>#05<9p:Yk-\bhc)EFtau^E8lk$aGEU9@sYj1-2R4 %HjkS7*_(*H=/]?B"8n#[7E"75S%h%3C)X50cS*Z\O=hTB+$]tG#COOE3h/d#PbO&oUj.5U=PQGl,N/-AEdDRdrTS5:0?0)@U)pbJ %+iNBkRsSj&UJp\KT]dkKlRh8MZ1F*R1[`Wq5B$m&JPR9T'N\]!9CKdX>#tLWh9>+qY*CTj')8??8-NY+N(toZq76,@Rc"KDCTO:L %h5b3j+#eW9AHk,62Q1OGp%'tXenrb1<-k_*dHL_$mk5UcdqFIT\72-(<%UD@a9dl("&DH*h.(@0L]1GEl(.:91U`Z#BkZ`0gR9b' %^Y]Aq?Q&_-;X`s/[GrE+C>IZTAiR`ZQ.Ulor/5D\n`nsnK+O.C:&hg7IYb7n.stHSbUJS %7:l--nMlFL[ti44`8`D#eWS0]'[p3^!)e3Yl??,jL3D53QH:n0U\[0&]O+ %CiVQ@0cehMM%&*1=S40LTl1[j\iNm?M_ERYWSmHdf_W3HRhDAVWmjii"d?WVQc %\$sbqcXbSBlr)7X;K3hZah=i=/$ZFoDN/a.qMZ;L$\,tVrBrD]GloWlQd3<8),GjW<:S:d=HN-M:@&Gc=`.-\ %l5$2E=qjkmD/D(mo9\[J(,r4(?C(XqX-'?'%pDJm^%^FAZTP$!IZ&p->25p>R5Z0RCN5PAMTS2"EKaQY5B8H[`D()5LKu=1`D(*d %CbLc=C>nm70NsC(e5Fd53GjmM/[WC!7E]\5>-JMN8o%9pXch(E+LM4>L!j/[U__6!$)=o<8M,XMf&@p^8k(8J!AX'm7q.WbkZo(0 %_'Teo"UZGV/hq"qK\[]SW=u'F<+3e$4JW`^(1FQc2lU@C"3>(=mr!r/iqpapf#:-X4GQ]1ciHIg,MM;bd7hlFXZFWbn%0aW=Vo1r6Y/G"+Z;2fbnnPLL*pGN]LT5m:k"9AD_^8q %m$),PnIWI^f.F/BY$W-C/m-04i[tl/6MQ6>ID@X%^JQ,OV#6N*-][bdcC_m6K[b=n/:UqOdo\o,Ne64Ca=$ %fDDsk[>_tB\NPdKQHOIfUF?Q/:6kmo=RZ\/pfc")HG>XeCkkNPbO@Bl"STTVW<7I.aV %X":C2dND!OeHY7SeXIKR)BC%`rC%pFo!_E(^F.ksU=_0)3JKeRVKRB8;Y?jbrlM- %Xg31B3#&&a4i;!EsaNt>YbYJ'<\=T)i+;i;L%^sf=p]n5QE,#@U6i;S2iW'6@(`,[?Sa-/roDf/O %p]o`qUBWuN4&X=>qkgneGJ2tP?"d-'lX!r44F)fenT@tu4!&bJ-H9=U2:r@Y>/YE7CU*^7G<[t\Dl:^shGWsRRn[EH-ZZN:4$%re %5J?4*ae:`<%efN2aL#=@]lXn*7P3eU=?,**7T`kV6Hm^rTsJCaW/iT3Rc)Z)U*R9-=&P)1O^+ZX_bCKETP\I %/!(qi+PB>4;(I_frF.OFq]I1-]E5(Hn<;m(mPC:*(_oT($BXU[l_kOhOU)G8ZXe^r,_#h-5,k6>;Uc&L8,tqQ`@1KE\imP"M5qGZ %3f)d=\MtdubPTJ^g,Y%r$#@Is9JjU+\N+?\(W%BoW),:2F]TH](+>FZTJS>H&+5&Oe;Lq4e5ROf*5sfpg$7(L%N)5$-Wm4]]8+KHS;UL@8&#.UdFeVC*]:CCbP1F;DlKR>_=sD]X`h\Jmp+/(mMH4[*\4Tr@F+AJ,(/g4W9",7;3bo$5B9&9:!8-/gJY>s*jq*D`?.J>AGOU*Tq[)(]X5<9B0/*T/IV0T0_MOrbW!mSO[U2Z1K!H %Cu1MuP,i./(!:+>U/]=]gWZ#Mo]&_Lr;AD=qss8.m3k+T:eYIDFpeZ!8Z-,(ReS0g2,HtY+Q+&,%6QjHj@Q>%@PS%*JhA?,E,*]\ %%X$&@Be^pK:C#U_KAAfu%.[+%>qR=Vji=XJ6Y;KYm2$Wgr5V20pKq@SRWMp]W],;TmZ(M[\-kJluTG+(XL`l"*! %(XSpT8m?H1eb*q/h?=:cLm&\^mb7G`(G"6O0tb&Ve!]=q\ouXilWc%kHBSAmoRoZ/;k?V-(#2nX5Zt.%RJ^8QM!o@A8$VbWTmM`n %3@`N85\GHBGTMoff!oga12fPX,/baj`G!&!U!6lFI".[Q %i'dZ*JABHcB,5S960s5J1eG[On[R1%m^6D*g<[qKO?%//@-Zf*CIsIRd(k*L%YO!D7!J-o>53epc'_MTK@`"CeXT*ErI_*3SY+*7 %UZPtGAbTPqC@3=S-E2Mp>)Sm"6>LU$Xi4"LiTDL,\8ma9P?^'sXi4"LU#-JXCN5PAOO,%@CN5PA:(M959L2]W/!aNn18tG@;M7@d %.]K6JP$5"0?C!pXR%tKC:PR;$gnY]\"-15,`?M^kjtH>5L($K?8M)YgH=aImR3[+c)q(*iE:P=aKE)5+gk"G63s^49kj\b %&kZqZP?J;D.DeMgq6ctc>)Sm";H*j(MilLm5i4E39"Kd/Q!0Ea-q7#VIik:AW:2!r^]!$8q=lL_O1?+0l:D/dcNOHYRL=?Z8.;+J %dD-D5/W+Bp)P;^brqJtli3W?a1Ja#TJ^G+JB:7S`_2OZs4praF;]%)@Hkpt`BoJ>p5)\Ra,*W2MjKfO8;@9I4m2@=WU[g-Y>JN/P %&.,M,oG4*q#R"4&H4)Ncli^B`H4/QN;$\e[7jTu7*rO*bZ8AX.NU;@D8=\P]/doU',h-BL^1b#,HLEL^eZbKl,N19%K,7[3$QUc6 %`'el&I.:+o@BXSfe+l1@Uh2.ja+_f@b\!sJPBi^aj)Xj$UGQIT)'M?]Ktnp+!+1lY$_O.i%qcQ/.1-AB,n](Y#JK-mpS2X"6["4f %nAX7H.SrtJbe"#I7986SiWRA%b4$F=W%B^$n*md/\TaWb\4#%I1Y+_%oBYQ'qlad4b %FXa?'>XKmhd*c)jaYe0<%:MtsQ#$/U@^5oT`dB8tj;L)T)J0nlS6SE/eIY[_Z>pBpQ:b$9jVfoO`<;HK=hc7TY$j+NqYI?_.dOr$ %2+b?5::(4O.])5F\e>Qbj;P2=8POt69#@>\>]%4gUG\jSrD!fr`3s%3d2Lq:Od0^L[\G^M<`s^q)X<3Sb0)YaY,R7/jQ%4?d2MfY %+t;-j8Mu084F4/=e?U\q3![J'<5pNUJk!2!\h8PF?$>'.>IdeYZ7\[-j:4*W/aEI>Rac;o8]%1VE'p^^`bl9SiJ.&Q?Y[*EhoR/u %gsBEZ"mSCYBniE76[2qUVAYQ&%+/f=36dPLAZ,a`FU9Vbo&YtClad4bFh*t3r,l9HbISfb1SCmD?s/iLPt%k@&m3`Hp/h+U\ce=A %JKn/sOC;OUTtLus#r:"78(pdI=dRZI(\h:TP]]Pm27L`>kc*]qAR07Q&!+/%bIYnM:1@Lq^p:+mF"1SIZ7^6)ie;hL,3UH>ErsOr %TZ\[TXt)*,X:'40"7!IBfFhOo=7G&MPAuYgX:+_R"7!H#Q?A<,?E:5%?s+<(rV1bA]Vj2!"U137JSmS:?=D'`0$M&WbI%J;Fi!Y^ %:tI"tX@il&lOm=NV$,Cm#qYC/=$NXd941nh95>PACN5PAMTS2"EL1eO.Yule(,r2rIcO=/Mjr3OGMtl%/T+Go-e:R %]#5u\O[q&mAPJ-HJ[OF@MBb6AL(**VY+h(_TX\K)N9;@lcl!4h[CAd[jq[qL;N%Oq'irn>Y"LaV`Eh%Pd43)JMqEUgECMm6<+4"V %/nb7kW9Y'uecg7QNR8A;eckeM5[B_lZ7bA"%B/S*=Or1)ROO2](d?,B6No8L@e_MOGmRlc`:-o[`+b0r(d8<`n)V&4JRr+.?7_W) %MFha&*c(t2.jhq5GB*h<.qVp#[8g705Wn6^"7!H#M?smOkJCM@AR1MN5=/YB^p5S3EO%AtEQbpu8JFIX:-_sKja)s*Efi=6A$46d %&*15IlG4l"=7idNaL.<6^:Xb@>?teupkho!AbM(%`>::oFa:Z=,!$?-iJ$FDa/,hK.-nabKj<4UYcQ#Y7>Z.m!mA0jo,^`[-*XJo8d>]IM/ef'=jmPTfJ"X/Zhc4T %`J-+@fqcaYe0B.S-1qQ"q5[ %0?-l?"ml_G\VY]CQJLf)=+&E8lmDMSNYF&,A: %\09/DJG4uOE'kU^#Wl*c_[U#"7*N$Q?=XVkVPY)QJpn1.5&l,P\'&mbF20^'NEXPaWV6uecgN-J@[@aAR,S""k@`% %/F-3`^q).LAR0l3?aF)@bIZJX1%$1%^_fF$o2C8MD\C@M0Q(#0er9n<)%%n[6AR:nY"M*]3METklELUGlTuta^2m'5igeM@#qYE= %hi\>fiq\/=MccYpOU+#!oJsXk/isqe\un\6=VpT)!HhZLbITC5+P1`B/F.>O,[XiD^p:*sL0%&O([`,tc$'J=.Ku,\U$E=OY:t9* %Q^JB%>cngJX:+umTHadplS:ODM03*VB[t2MNEnK1;*u;Zkdjg(R'H,S(*$Xcqmo(S(*$1`DB`r %S('2l!^^QPDGnYOc4?VV\4J7u>&8R[;G0lTA)fR?/[S]9dotP&(.*E-ZkbU"A\'igBIuDG.lEg*[+9>&Mjr5%di(Rej*=0I727*h %UQJ_TLKtInKha-WW?jPrcgDKZ9oS7d[0d;D`D((Rcs/:J6cciI'6!H'=q`G&Sf#d@C;jrhLe;D:CIbp+/ShejdotOCIai8mjQC+s1-+L*N?s+:0@h_C*%%jAL0Nqr\/;1s@N0Y;E$e"0ON0Y;E$X]5C7S?id %(M)5i+Lkn/>M-^::2n1J\):O0J`)Dgf#?Dob7tSLB)\I7/qIS>5&UKEmKtN2_KRcGY"N/*Q`9;/`C*-ClbY4Rm$KD;=VpMbNQ?-o %Ea84)O5kidIT2U`HQR^3n98]Eo4dQOeDQe/cIV78-jN %[niLq^:;=sX9k1/I"df-Tej\-?cZ'p($p>^=k7/0G^89V)9TN)^H^$Z?RW(Y$i2A@kUusJ>mQ>leTD0Ll[nk(5[B_lZ7[r>Mcjj5 %':P>99$Cb^R*]Zd=V0l0"I=2hc4ij\L/+`l0I*[0L2/a:[9D_=CUm[%fM"dalN42?XB\+?eI\XJ9$0#5;@S2*PEfqY*u=`4@5/As %"t3%o#=`1/md]RkW:eK&Z9i_]+rIq^h&cQ76g+:`BFu/Wj#6%A*5I.@GK,N$#Qm1dem!n?V=`L7ljUA. %bM7fH'4GPM`PMC3_DEe!Bl&H:X5/LgW:*agYnjqI?F1IALh*TprX8\CINR5-_lLE\D/"XBr$Xe`DR?pSOmrtg-qS/2ZCS$=ZPpCC %de,=.@>nt@"Pu8E4#E>,m1E!Eq.MHNFV/&]g;\I`[Fi,(D=!_X-q7a]@+C6Eln\/aq3`lsmfa@U47a3=fEJlM*c%)VA!`qdXBe__ %?&IpRG"FE3\_DT'B9ZllE\kA8KCKhk'K$nIG7nNSRcsV#8[#3-h:UiDLS9l;nVph9h;PV^8MPC^X%uX/nJSsEL//Uri_#Om8;a[q %EhtLu8]o>*4E-&Hi6GrW`34XoT(>NDP/J`5^a4Q)-\M=np\S-ro:Am%/A]2G7YcmjTqIIPPS$?boGi0EJ4!N))eQk9;i&2FH %j`\Q2)S:l7m-=s.M9J*o*q]r`RF>ItGTsoO$3fX7b8o %3VoZ$A#6T'H/qOQ,h]oUkosl2iHFcLP3kmSSn=?:fY5]n`bt^C^&JmXZ2@o)Ya1%'ADC<`Y"fa7S?/Z?e]DuSnlI$'DD*B#KB+.e %EUop73Zplj5!&*UTe7"8Ds=1WPu5d#6>D8Q]q(f85=M/$6QT?,8rEP+:$$@P-%h73+@Y.6(5XL2X;UU/UmEHHMS,?#Iofdocnj_t %eS(]/]QS_/Z4?>@/O)9GYFapZs#&CV^qVLsIsq)"s0p(/e?BGVnOT;dD`nRd3.:;X3?Okd%G-I/mL*:2?; %[6Z%P*)udrqJ[dFkkTK!fe)U&R-6mu8&>5qlsf'I[E@u<`[Y#L<3$G>UTo]A)/>H.GN7dL2NKDsoF%E_Q@qW.dP#iad9FgIrQ9[W %ClJ@0FbUW9iQ3/ST[iS7%8oqj6cpdcd#GV %J_jI>jrlPM?A\-"U$%D2`VVY#>FDT5rp!g&C>%b#rQZ:OSt4r[0[Wq++c`;f(1l=cXWq[RLH$Fq7=%gss-r#WZqFH`95+SR6N5J> %RMu&4oRN0%:[PE_oT/+NJIWmJkjX:KH]D(K4OJ+GEDGuM2N8!S5PK>2l=eJ1*u`8Adg@U3_!>*-mXr&m$Bi3b,6h13dtH`p&h;5$ %;N%!f8=E1;h18(>..;<[@!b7b,)0bS^mVn:#,Q7$r2#\4V'il!Zg1%B6P"Y9=:<^Pe8'IY5jU9*cr7p]./FDSi;IA)!^ZUB^A0_R %$h'OM4Z[HF#k`c?M]YD$oC;Z!j,FQ7OlKiMJo?.ID-7tO;"t;0Nk@VNE#F/\?V<6E8Q8IX+Kqs@"rA7 %c/1Gr?<50A#p9HW$=oELa>]BF.]G$BJJMS;,[]p&E[)TbFcTQOZ0N$3G?Ks4\RcgPGt8LeFUBD7s22750_4Wa"b %!I#Mm-!alK2FEG*I%e,C4FEG*I%PY2EFEG*I%[<&!Gau!-K:!jo8G&549&o)Skgp@!).JHd,"^ulT1-D7FERs2A44?Kd7'5FiJ-,I,.^;X %3cl_W8Oo[Okchs"5WUr36>,]XEi5\]f/?FYM6tF_M=ZiVU3fH0I-kfpNdG[lh;dg51:gB/m1U;dq[8PhD`S!-Q:K&0n1/K*q$co3 %f=[=Co,6cV$o7Foo,!2X!mXu*O>fqU=s26Jon@9Q=N6p+@!"F6r%ICJBKmgaKC7gAR^3PdAo\i:RJ4dkZQMeo1bVB>3l]U`MsgB55s`<-,VUX4N\Psc_am?p^76Q&F2+1(c0+i>UZ&*[>OlVu %4pquL-W*:lAC)"@TlVu>P(^j0m:]S]PEq=f%,G&u0X?cXDeCfn;W@)Nl]Z]d^Sn9.RG:3Ra`)%+>>QY8:1gmf44fuac]46%Vl6?]lpti6n.m80g&7SCV,s8erma/F %*Gm^dJ,d1Opj:4c=ZNG"_(9d0$OsM:B>;,$*ORko"nH)4Tb[m>^b2-.eDajOdfCTn[:nmZ5S9E@?Qu-YcbW^PAG-t1Jm*VEMo_uq %L$#1VXnA)-1msBe;RT*E %'W%K=Er/WXe,iEJQW6T]rd=gGAJ]dN-1oF\9c0[;`_8CVK3Ff"T(f5V>X,o#^MIW9_o8<&P'bXRk<^bn,eMFLW`DD`9)Zlhm6B]X %_VnaZ3R/+P5YKP6b0\J>)'HJ?npI8/rn9Dn(7;DAlt60XC:QAG(t-r[Dg\HrY$TqgAal7>$PJW':WE)R\H'D1Ifk& %CN"fI#n&ZlMi#]_-:%XY.Yu?R-:*0,NLs(50sJMc#_HQ14ibdN-G)9+B3:@(jLFGYBSJD/RY$D^Ckaer_&AIbfJBUie);1qU]bJW %A3Q.(T0h:1mRBpM#I"nouI\b7&,`D"_nl.U?a\O3Zqh]e(m %#p`Y#9h%H_Q9^T:c2=e5ccr]@q%Z=5_m%M`'tgU*T7g]./9H=Ep;TNT/9H=E]dndj/9H>0;4/;f[I8F1DUT+YWAmJqlSJ&N/#?L;j0e")[mcr/*"WLu5'O\FBmi%AI\8[t/n6kdlSVkm-c0T^!5'e)sO=M5VF\/&+'5Ic)'@ %9Hbp8MpO;q!n4Y5Rss:R*71_lL5!?+%nV'k(`#0I17?-R]!0cE;*2?jT>[qKF^`jT%3+$Oa+k^aR=Uo8Z!MhZ\j#M-GHll$W0[Rj %MM5%%rA'g[4!mjVk=$q&+X%SZ/FmX@[9FT5O9G\hpJ(Ft"9DSs+Dg=fTS6l9+rRGsk&_,BT1+03&2r_jXlSLH7Olk>)d]U467Os; %<[^ul+VhN`@^-7HWVCO*pot/4WD)E7EFG-YqGn(f=??-IeWFi*/gn'Uht'-^:1emCb#&qi.fE<)Eb@:;%GkQmcF:M9q^X3LI;nkj"l5W1,pp>XT/+9k%PYt)/mq8VhI0n-?=5mapC.K-Q_ag71;!bA9Mr*71;!b %k*#Lq+pOJASM=HFLk-m>n,3PiF;g>k@\AQek:/kLSAJBeQ8+G-17RkkDq=&AXDK>Oiblan_:DPaS2MduCdYecOurOAX43`@-$1q* %*Mr(J-35$g3dO?o7C9RPcCgfnkBtVaU"=PI$Oat+h)M:0s(!0KnK(`hWH<\E]mud(DUh9)at(]obBlY*n^)WTHpf1Ro$[JSn-.ca %9eGrQ]qG]g&_8Cf#@B[YjdZ*7JM/,;_F[8ai6/[nOk_o5,Due6^AiaiS35`qWRT";f@PAGT;t@&i52WR;33:>E1)+iE5nbiDBb># %q!73\m>$ts/\;sMnhXK?6()e:kLWLFoW6ONHmcfrO7&SEX+-(6]otTNMbXbd3'J.#3I?6N1..DOR1B)7RF)tE+i:o!@8Y>*6-a.< %k2;%tK:L=n9Lr@sSKYl:gJsTPXbInXm-`tlc4R<:7,BaP/t.L2&35ao$:b4=_O/Ar_rF7!pY[I"jQ[ONoq2R$Ni>d7b7Vj0@ZBim %Yo,&mNlYpq+htpUEY%Vu%_CD,('UK7COL'7Poi/]R7)n@iIp"b'UL%R9ln*p%lL> %M6gI/k/C`L5Rt>Hj)0OeOYoU#)KXcVbZSE`kT8EZ6cPZdc;Cre+$411 %;+5,WOcm`.>rYnoBDZe8)g=Nm.VAhEAE`=!2=/6HNJe[Z)[679bXhapKE!]1f(O8lc4kV&LKumHX91.i_o6n:<:dlf9^JuhqcrGG %cg#RZb.1W"?$nm3r*3I>lI=:tcigq!F.C!)prXI3mH58Bk>'3Z'>R\]]Xte0lN4sUE%r1Rj;sZfb\NPdo)kWNKf4R=AKaQYB!KdG %ULt_`<,/+@aO.>UmC^.=Bup/HCYjl3KktD"7n?"-SqRRohPb/0d3h4`ds"V,1.rB+letT@N':Z/7^9=.8h'>qVoJ_T%Z'QNV`Xu'#QK" %"@Gq8SX'k[8oLV=$-fs>[be.#)T3)OV[%3#/)_Sga]Z^Qj$=&l4=Fpb!EmJX8c`]tU[#C+ON'mA@-4#.4!H#J@-:d7;$nD1k$[:l09B'cObH=@(Pu$TDrcb4 %CKlaTMko<`>m7J_/eV&JGHtVX6:*.S9lD;YZA+[^*=/l/?>SN$5&@\MQHqYTqpSRXT\oZfi6(YYr+,kGh,FH*cIs!q@&G?:^)d&8VOZt^[\;[H<>rdR\B.W:.Yc[cCUIo/,/YYf(;QlU1uZMRa]DTRHEG+/e2RKD=O\@eH(?<]tjoXATo/SqJCD6-[AoNKMQ1aYQ5I=D*[X8!g!JF[G9&eDaW1[`Wq5B*2GFY]<%UsaVS %I@)0CYd`?2S8RImflAZqD]0RqS61*>kL,,CEn=+e3*g7-n*iY(C?F,;YP*>Hj^G?Z]gi!KA&>H,:4Q/&kk)X=a4;mQ]7&sX[HtAL %(%(;HVCr,_-D2RUbh$VI=SR,5ZG*jFb@Ko!^H$&Di>Pk;hZILH&7PCP0iCj8jSQK"< %'SF'jG';9$Gf19;@fQ'Kq>9b^s3@=7l?S?fGcJ]@,;ZTl/!,]KNbf/G_H=M25Uri+Z$Q/m^Gk++"rcVs#[J5gpp)#Bq5]OqY)Y6i %Hb9;lr,$i49[/IjhgQISY^?D(5E_RU=`0tuER8"n(fnVI"5"=7bomqab,]njZS!)sZejI\fL[(=ZT#*m5I4JG%:HW7?iU*fKjH-& %*H%92s4i!IRmCHVi[jiV+1BNlQP\#sqcJL6DVgOV*h8gH+$Qkh;ZCGqr!X)U.-0]>J,C^BDpR85:QM]N=tc`*&l)FW(]GDhTU42+ %ZMh#%V9No0q2bJb,4k<2Q^I(Q582/hX^Ya'2;3`HoA,_>rO*g1%1b5$1HnpD %L.#c*Wp&:X&udaR73EmQ9i4,>)i5K9XQdFurgkF`>25nhSh?D#1-D?JB&:F=/T+IEWA00te<84H1JMV8Sj/Iji[2&IQ!:W95\a^D %B,Ibi9kp)463s^49kmD/U'+YXS(+b8P\@E>HF4GgGt9O&@\L.E2lUAbcLQdQ(j;B73uU_,0p,XP`ML@iB_(#XdTYG%)Sm"Z?]t!Xi4"L@7Y9BdTT30Kk=R_Z %%0-c>)6H-e3!"EXBtCG`k4J83EQP0JVe7#692Xr4('gJ^6'u5kJHa>dI:ME3!r4D!&P:#qha1h[VYI6A\rpE-39s&nZS5`X@C3uB %=f+qCR*cPaB:53h?q*ctT4R:>g"?/rHkp$s.#_1dT9W!DG@jm,@5rhHQD6i;mqjE"5NRVeD^"bqdC7"cDrL0%:2n1J[r??q42DYq %hGR<3mEtt,7Lr%G)39;s99as[ZmQpR(](_^lo%(DlMfPP5Z.QWXlqC5]3l*aMHQmZ2X5fBd&o!u7)Vg;7GE %QPN>$,b4=5_VVfd4DkePjfiYEQL"1T1(ot^@-q1pcD,&AU$U:+/LLB^!FK8OJdZl*&siU4_K8DE/P11\LTDFTFnKY9"kk#snIY*p %<]'UB5qfagpq`:tdCZgP?X!3Mg,M??@kpob[A!Zjjm5(h#Aukhcod0E'SZ&CRlt>thKW:)F:T*hDjf@)+2V-n#E=UZ=`1ebh.&cV %<:i&p4C_\6Q#k"DW?Eg9dKWrSn?bHk>Z:e2%9Q3R(V[Y'1,o&2D:3u=]r=;DJKZM<)lfM)+oVN1A@Hj6M5SR\ %XeRdqCBm*Y`';l\+n5XWI.7_\0J8=\44X4D-iO-mH,TC_Ol@HVN?U(W_VC8gB%o8hmCDNl([aVR_Hcj3o&ZiR4?]tf:ip!/c]6&; %^P>\<:CSK;pWf0??+SgiCd&Z)msk(1PQ,fpD!W`2DnF[jp2V?)M\oGa@n-GD=DSUM(Qcl.h1LuXbjFJ3U[KBZhThJ3mA*S5HmP2" %iC`6U%V8spEA5Udqj=qLYbr`sRG/>J.B5=pS%6Bn;Lp@T+!Z59ra]nZ`\r%Dj]+W73c6^^.tWddi7`Oq"G]#/YOa)^3t-uVce>*@!$QO_%oY6mS]cG7T7';Qgd)eiZ`SNFO;:phG@q@Z %?lKrY2i-S2W)'7V!ui!'<@t!%(uF=?="TSt9PkNP`TAfUj";=Z1P*;FUUIG=[t_`*ZNKY+A?^-<8tGtPmpl!)]jHA0g:&0Aj4;Cj %GHlS&R67+3`=UMJ!*2`?"NY5FZBZEL[rK307+1T:9#=*JmZT*$?q&!#Z8r:9U:J2H`C*)*DU`j,3ORTE\da"IrO']E*."!5Y@6V: %)Go33'bl]%8dmfI7r.VdNm*W'1+jk#Rp5A#XD/-o-cB26>MHeJ?J.'>Tfsh:["+/P//]?W]Zl$kAL"Cdc>T2an#P'2;;%Gq)J3o7QjsTJYtd:DHt-aQR!p9$TXpD?4\ri4Z%Be0CR\ %gBScrFc;E,G&Z`3'imE6ldanL^PqqpO-H %ErOoUflNgJU/(*cj^u9s9nbdar'"XP/JPq.c>G`,rIAWAmh\+b7'%]R?eaNI65Kk$j;n+/N$?u %AmkOCSg^"X\Fn17)V?OgH%kIMJ^aCJWua,@1Jgpp6Po[2cib<$T/8;hB!D3(_C+8.B+bpc[H1?W3g9)@p'# %>X4?B.ID$#$-`kegq0dg"3"dTJlacmhaM.h:1omale5JDX`Crt?=ka;?XisMHqA;1`94aGf5G.*!G/C1Ab'bbN*hBg(Q>WD'pIS@ %lLuTrbWsOkdS^18cOBAo,+:Ss%o_@kNDF'W&[t*g&9NuR^8/\:7h]Df&A$a'NK5W'5_J;(,r4H^.UGf`D()ASk:K7`D()5>8C/7+;_!l_MS]#RoNDl>0B9JV..s!ii]XB>)Sm"!XEotXi4"L_=J:3CIKPW;Z=71 %FBuat/T+H:;Nb@&;G0jjefk:CS("u4nab`cC9@]Z5rteW6Ef@T(,r4(p%$ID/T+HZ@A1*=8M*ABTXD:$/Oa6D[Ci]K3$[p,6mX?'UP2Rcgp0G:,,p]pajcqdhjYk %I$Vme#;]OmpagZJ7:ke[o3&M7,_4:"aChV<=2ENH9OpZT@pl`qCUc[o2%m_?PMX.o7-k%X9R9?g7W?>B[jJ)\di?N;7jWUL4AGto %P,5F30X#\DZcaWD"_UL[mNS>W71I1@7Up(>JJi[ja?ngp8>lodoebG-HLN,&IkJ>/,R^6S5RmWG?&:UoR^#C'Qao=M@Cab/Y=E?I %,&pkTXU\gNVMpUV'nrmH,64]IV2)A`'#9hEHI6k-U(i;\s1Y_^I]U-m&&*F$ZQ]X%q4O(\UF6Is\\\K%<&_^=@%t*FSA)nA %.!50RQd!/5["f\7!5,B\B]e`@SI.;onnA;RT*Wf(LjS['k)>m/]##qYC?<-c$/cJLEZ90'P;:9(#:Q6ik>=<&*OQ$$4lZBST] %-XQsR1hGbe3r'](nP`>g+g(Q5*";H9`T6(u3iRj9T,`r.f\^&7LahXFpFbOf)EQ7aTHKD_CZn0%=BTBYUG^Ci9f#1Q5iR?r>f6S9 %D85Gb)N`Gu/(`.;WZ`nEd#$=M<-c$/::,cK(6anskbK,kfhu"V@G6amJ=]/3\VADs"8ad'\V@uD\cDD!@bl,?KMKpDAu`,X#,/m']Z"W7q^%.CRkTBDf25:._u0^tRc %qQ]:r/qIS>@T(Igb.>e,4(;LIjKu(,E0k^d9EgAWf(C[e"Vb"gKq48EA.EDO*0YH(Z`He+Y3Q^&eeL3!-<=7ce(t7P=VnZi3;>,W %Z7bcRK'KoMDDF0\L2lu@f'lr3\0LdD@FU9Vb1*&a#\h8PF>rY3:>h::+XNOKQOm9L\Q?C$o %&#H\D8M0PF"OL>hb.@(H/<&0>-FEh"L!j/[U_\3V6>8#h;Tn/9%]6YD8M+Vu$`18@8M*Aj'H8-Xe:KW".':H_C+3nV9YnfG(:.A, %Mq#'1aE1UD6>G=0f,.%15^]94(,r4hW2tjG4J\:[6>Q+R>5-4nOS2R7!:$+i?j7F&Q7.q*!pB$U`U@QY1# %AMI5->)Sm"o&G-BXi4"LiC3pH`-<>$bK:s%dotO<>mf=l`*(Z&Zdl=U-<\L&i3rj=FU9VbEr.@)b-b]EF[8?@`$<8Ml[fk+`b:4f %ZR29++@]!4T*=R#NR8BVB>F]iQ*$+mBDJ*'IRZt(=dPieeo_9MlN3VT"G/-N]`l+"&I>P,o[]hM2MC#J/F,&1F$sYTprg6V*>=@C %8>lpT(DbfF=k7.6mMKqFm'880/Om/;nYa;eg$)FX>lr3\bVR8_EnT(n)TN"`N/?ZU.dM[J=T\A-_(V>:l_EHX9(oRtEgi.cSW[s] %("^4H[FpVta>1PtDeoVRU'0uIK3n?ssQ'N)eHJfj_s'echR4N;18GAR44e %$E38'=Oo@oIj'[YKp?d0.dmsPb.<*<%B/S*=Or1=96RRK9PC<%Oi2u/bIYKM/1]?!8MpotEeu72Z4[[=F^5'l\ptH\Q##TZ)PZOA %/_A?@21uB<=h09mZ'`;-$^a=b\V+'=QCps17<>H\V-=76RQ'T8d(EBCZqQ4:=?L9Et,\& %]&;k3jhTk=Pp4A^i/K9Fg^osPE"W>$\Q6q[/ne[R'5eYhX:&!u;Srr`IKo/!8e!_tq&-Eg-T0Zj03^F+5\@O"mAq*;DFc;DJpg:s %BniE76ZcmTo2f/9tr(;HqD;$6-q"I=1])a0js941m=FpjK!\ce=ARJ93I %OC:0u`XqWt)._ALE/jb?LUoqmJecdEYAm(Icd`h=A)(\;XZ;a)lZ7\c^&O#b2&jb\RT4;ld`@1%= %h^,5(941m=?O@6X=dO@$Jd#,l.I.%ZD1''UQ0kjo?;b'q^eKQ6#"(koMuBU`XQpL$eqNOsYe3:'AR3Yf*)P65YcJ590]]etJRr+c %NRCR-='Aj3(Ym+5F^5'l\s2-a/qIS>kT1,0[CAd[1ae(->23[pD?Wl[Xi4"L9i;"kZkbU"L">=(>)Sm"_Ttk7E9/@Q-Fn(p>)Sm" %6GFg=Cj\oS92QR?/T+J0`%Q*d"^+F!=FRNrU_ZWrTsPR[WDsER[B0>fE:GY!WS(+1@!!k+@nnUaJ'B=@//Oa6D[CFDk/VXF5r2m7KZS\2X/kDKBW9Y'E-8Z2i/;T,q;:YntI0"Ir!mA1%)2l^Z9fT:AKpC\=p0cQV %Y39G&^`uJP?]jjdT;&P&c6`fq'G>L[&t5!Dq=gY%p-X"Y"RtN*?A]`l23e[s"alG42l+#;JRr-FZO!Mq&m3]gdfhi.MHeYcT$$iu %L!4+6MR\ZL8pDM*,P/nk16cq?DF&;KQb]mZ.iX@Ff-RZ&$f,;YF^5'l]"j^HkRnP0en+910oHKN6F2MLJPg5#Z`FQ5QCtfAJRr,K %UaI\Ecq-+%hj$s>iS)P'Xd8eS>4*.a2Ub"8\eJ.NY+_%oBPFTFj;L(YL9N#Jau0)-Mu=/oYt2keS$*OGJWUd'P=lP1JWUd'7?,9; %Ab8O5/eWIFDsXe'q;oGsn5OH](m]/a-A)M/.L[OM]-P0GS)ob>_e>Jh_lX+ebr>1T.OW.m.Q5hG"$j0h:Kt+%ke*le*/,7$nL#3E\<8BDTT`qDpr#/)=oU %KP@LCL,Q"!<`lDbS`?-/>jOs+UTO2rkU6*$q9e/$hM8MG6">?Hpgq(bP#mX%Z'M+V+i8V/$Zb/O&7Ia@N6L`HY&+_po=W@Vlj?M< %i%oPQC)cVue7/"Ro3UocMI=0^]GKG6$tR([eJ2NZ!gFs^q4dIeeod[q/TD`Ai4=.eWt]%[pg+'`]E4'uArlg*O_j"nNQYl,>o5\Jl"5Ut=U`+jejF4'+Vo97jDV4GcrDR4P7T=Me15Ym[+%f#g?%3LQP@oj1u %PH-%SK&@(NZ\:Oe9\^DQYq&a-RZ#0Vn'k]cNXZBiPHb]-Vng%/]BGFn.r<3Xne"I66Yj"%LdY`SGOY[+gL,gQg^V/:lmdUlX.R.2 %\C:V??'G1@gY.pY@I1:?HQ6gf'OqqScZWO)U_p_VC%H.dL!blcfZb!_Y7T.ke`6>>c,sYaorO=(4[)N*QbNonjBLTFR%H1;$SRiB %Q_cujo;7[u4uXDh"Ya;*h@!F,$M1[Cb'_T^06#O#@(tj;(Z)]k@_VDWqis%bJB?E7CpFA`rQ/mCaf!bcli*rhf]q$c,5Ln3jMbRi %5)p#qab1&%PGoIYj^l!%)W('&0>ilHF?sf*L^ZX3d:HW#s0$T;[XqLWQ)ZZRc?JEs4>YHGYSBcWe_9n+6*2ad %UC1'nKplW%=:)p,_6hf`-t)+f^9Z!8PC.[m/;Yc[qBfagl;$-kc+O&Mb[)&fH!X+L[91Ke1fM3 %ZK7*llpNm*P.\6Rf#_-^&EYi68+3.`04g4e(!q5(d/nO#\-Q1H<9`;\Qdkfu#eCUhRH3)dk60?joKSSpL!qUPF!9[J)pZO_972)W,?1siud_&U'a;HL>CR%lW$9\*^;]I&[_dlsI>=M:Hl@,-B3 %3.S+N2RD^n#qH[P>7;+?&6sXh(rD4?;[hJe"V`lYlI55)%:N1E&N4?%fN::#DgigiaTUG.FSnBFP=\P'V;V[M %kSuBkKQ=@J;9cB3**WcVcX^$pP6i]b3dr34aY]i_qssn-9VuRMiHOK8M2!+n@knp\#RZ%=^PWW^C,4$g,'X1'W,m24b>Ulo$."H, %nH4E49[A2hd@C[^I`"#pl[")=`9,HLjm.^k"Yt01%\?i8RY5D:.9)A9]1*Ygb[5r3,%#F7\%`(BKfUVT.:aNL[iq)Y59XKi&aV/B %19Ep".fHP7HE0.TVI/Oi;<*As\mq<]=cY66!\U^S?N)QVE>fUAMt,n;WQXu$d*sNTV1RdGTE?Z8Nq@>GSW\@Nb6n7EN$O]*5+nHAVMte'SP:5^"#E@JismcUZ!pDYdY7i/N!>U#_LZD)MaOY?[oaK!`?A<[;eb[f %%2(3FrF$*4F=Dq[`Kr'm^b&V/QLd22-dM*^E#329NQjKteOfX`1-ERu]i/C0D*-u4pUdd(d(_]THYpG4(Q2DjP]@RQn"'IHBs`k# %Lnq1LQbO$*OA('6=m?^860Aq+bOP6WLl;-d)iHb_Us!VL4*gYR#R&pcM&Nq?9f6fN(Ad:9T5j<:'g,Q;1BZ8+ih1XWbL*R8/AG:N %g$ddqWp/[>e*`JM\#F&#hVFP5WPI^=UW`mR8HjQEDARd!Ad8B\XJg/j.8teghpf_<[7jHN8jhgRc2ujWd^pr6?Hrll+7cq: %N5aBpi%?N:IJZ`]s'Y<83gl_7C?)\p\%Djsdkqarn@fs7\)E%?_Hu(1]cf&PDB$O>Blrb]gbiOWqNNs,G/MMbq%rQR9H!*:]1Btk %XdRSCmEfS1G7.!Pj:.@FI=8H$R'5B#]URCl%LKT5P_M;Ae4T#*Q6BR5^"\h^5(K7`qnS,NNeO&T;S/ahX.YpG:H/*E7?(AT[W?.b %]'Yb-/8S-g]$hj,3U")21NR//c@J":@oO8<`*ka/*5f#oA*,bRT,LL4Fk"],BjgX=cJ]uV]B3o_Y?q5+/b+MoJpO8Y4'o%(0_1(F %'5bH`m5TiuTC@;8W\<@feQ?0beq>Yr'L^C(]ReOEQUY\;M+&>l->JJt\Eo:$q2U)!*bP>ShJ^@-rQ040PdW\DZ3LN%OT"_gtf&$OFd-NU:Wd:mb %3[f']UHhpp6c7qsUQRcD8n&4H:A&t9hn5sB_,SlXrZgsrq"oE?G1W]@pJCr2)kU\[Nk\WEakQP7[N_t7d`jaj0&_(AcXQS@naSoK %X`ZCPiQiYFdX(:@)UIc(nKET,"4r6!:E8rX0b14<9`ijTh38a<"pe1Z)UG:(9Kc0[a$?OpTZ4=KDsCoSi0hM+EDB2]W,pjZ3mNSu %NiD4?BY\*D)#'S-d<5qT&L#_c!LG01S.h),,6a'J@Zl?,]*+%5@^9KUBdTp$:',&t4Q;luPc2ts_@Yle\mtJFn/FAYSC9==Br.bO %cE$9f@8:;//P2O-i2>!Ek#BF7/2fP.kH)8>r93FRXkk$ff$Ibg>rH!d8ho)cpR&aVW5\9%pFOJ=7pM3@S?mghT1AuLW$?i.W-^/*/?mjqk2lD/`\o7j8;,%"O\I-j& %:))/AOpl6GF+!PjI*q4odG"m0r;b8.2(/m'R*Hu\W;EP_i>"m0bal037Z\/*P/5EKc3>0e/ %LAa`VC/Hn;U796*oEGNMdOHq.Oj0*^HrQ$aS'j0V6!%]$Wl7PD%R[Y2$@Yq"U795C"WNV>0rlP+_M"di9[,=sP='12j)Nu?S&c`J %.kK4[^3B#.ddKkf;TkNO8@GMlV(b@<*$$s"!.j`Y&q:9i#6+f^jD:SmITm:S4.4,'Bl3G%2T0Aq?MU>OQ*_,JJ@[/dLptRr\')?UQ,bBh'VPnM,EN.<,jq(S*Rq$d?pdgRVfohH`&*Y>O0rceqj-?@NlY')Vi, %0\d6Vi-f-Jmk_;\B!_/ZIfEt+Q("/=no4)I4S*T_0HL(I)e!ig7^]R#=FS&$(+PJNVsTt_c9??qI!&AaKJ&P$j)XDeZ(,3W@,TQ %KUL7-(pO'QA!s`!N7]C&a[+Y!rll:^+Uk,^M(4q)a7Ool&I$12R6`/r2kI?ik5`5Is!*s,e85FQ?o-/BrJ0.mUr`Aj&dtKX#:oHlh=-8^-8VoG=/6u_lMJB %or0)(GberZ-1nof[p,cA$?k@C*T%Q4E0^\c>?tE]qAc"CMq.:]A`rT!@1;5pBt_A^ENr5WD^R!.(3'SHVRE!b[d>-mKPoQoXM2W&jVU#+s<,q)">JW]%FsnYVE'Sd_N`)PeVX8T&/Z=WlF]ANRtpNI5c4;5&'%3G,+fBH'#s-@'cl, %ljtlc062$gM6HK2C-b*+kif%+l7otH"$^h7?D>4@L\KYl4s(10UtsP^-7Lk<_lkpVe*I>j@lTrQKuY= %,rpN2#kYb8ZWWk(7$@d%).ci+H(6d#gN05_(]D0(^Q'lU3lp%1nY!Id4!MLQd5pRc38;KnN72ZOfhHK5)IM %e@oY&^^@tjZ^BA""0r,+U+i'jKkh^aAhcuFT9&#-4dgXSr>!OU#ns(GT,HU0=M0Q,^#t:1@Ia%m@'<@Z_rC'e+T3M&@Ia%m,am_t %*/J)j+%ThFTPZa_J!^C&.##irG&$UJ'.i?5ks#sUIk9g`=O:K^TSL#V3"$Z$_Qk-';hod%s51tNhTWmmH4,.pLTICS.I/F\fC's' %9rUAoZrjH)[r5O_IX4Nn,[?VR!<(;j@c09m6II?D,J"mkpQD%:,\WHZ>E/)OLTXgWYFH-Q:1JS"9rUCUMHI"?VGtq6,$:nU.2D'U %'WY6h(-(rh'Wb)_[>u$\d="!S(?$9Ft\[R(k)eV7G^93.N#IgH)LP2(>B4B'j*_3#gS"Fo6 %2s0M#Dqd+tm;[2[l$h)J#sb]KV=+:SIUImpUV?e!JJ%_+Ou5hd[_$AIO(2#7'XoVk8e$'[\QD:'&/!ep_TU %N1tTeaEAto/84Z*)i]Y3&\aJ)N$8Uu#eH_6;7(]&$tp>PfL4rg42*5O;++h+$"nFlg-g!\Bc]akm\)RtMJNqtg`N,B;N16s(r.k] %P&V*F3(Bi0Ca,WM.6Q6K^f8uIUPQc6Jp!%$.&*r&+BOfV.&*r&XSnFcN?YZ&<%m_V$S:tS0$!Y6f@a-9n/b#oQq4Jqbf_ulb/19Ytb1`g]I"B'#;Bfr9b_R1]'phF.Gh`KZ_X7DOFj<>A6n4"0?\ZCAj %es]ai%Hr5DX;eXE)nk^b;Si=Fa>6Pc_g;uEL<,mkrqaU6UIWY+B&J0>4C%89,H5XS_Gp+\V$dngP6Y?Pdn5u"ccjSt`NjNrZomiJ %_/Y'sJHd)V09k$2ddOH6n2+=(#eQh*,&=%cd8n6F&Ae:&YfI_,a;I$pJpTnmYA-YknVCj!,1EkP4ef'9BQ=+O4>P4kcMpT;$_'XS %X/kCHftnZsX:>gsB1+..@+qMHG`/%'15br5lJ$_bCVCbs]rrk:%9UnCL"BT7mp!kL/,hJ*YHdCd\>XV %#NcGT5$],[MPbKO+HJ1c8*"gkhGuEcVls=IICcio]*akb+j1SF&;cTNU^bkK$sKLGe&[8Y(ok5FR-mb"FjZqn%+MO=,e.Y$Peg6B %56kR;*S.X\c!WNWl4e8,+tl4M;B)=QfMT!@^VdY:eMal.]MSG'UP]!AX9O0NT6\QGos0Y$_C9gV)m5EYZGtZjA*CDsYf:.cL=1"4 %FHZjYf]hbr8RU,:)emMDs!7Y\bXi`MY.k_u\TP6Tme;U&]1=]a<)-#^*8'0-G"+4ls#t(+%mDnSBu"^8N8ZYZiUN %Hd1C?3UDe9,Q",Sb+83tS$N#!ln"H'Z,Fi!hkd#"2r&C2Q5b31h:bF14$\hdu`6561eBKBuhnXjC`D6.\L")R'0O\_73Y/7dBPB;HcXZ]OkY0lJ!$%XL[P"6I6o %0*b`ofFpK%"C$19Q&]7qX&jE-L>'():!Q2B<0l((b.+I[:4B5j$Q1<1KGFH+4[sq8TmWr:C)j*I*/1oIQ#IGsAlH'rKfhGkg[WY@ %pGeld%69VNP&H%3TIZAkF[rp%:@J!T>:Qh@9\j,:,>9q)]a'A4;D9+tU8;7T1ho\"\J[,os'jfE&7mAC]KhhY,gP3f;h %*9tQ=N8M0C.p]-=!FTnZg*7lTBj:&:)@,W9Z6-1&IX01NOP2[ck\l+,j"mO%d5Qh@D]lGL0(8h-2a`%61d6VAJI]9Njf>JKLrCYX %.dA1+MU5hZhh9V+";<,.Ojm^`E_^#KWHn!2E!G3FJEq66`Ye^QH0j@G-HkUQQ!nQ;6mGulnUO,c5('<#nI&ckglEc--Htd5E@+-'.dE;8B.>(jc+M,14 %J3G8f!eMgBcr1fi&tF+"a*(OoW %7tmim@G=ZjS6>l\D!pImhsgN>o_KRga6da?H>%&YX6mMh/E(2(::J6kK:^b"F=WZ3:$a:>/nTM7jI5N8=ma1M=EHpt1d9cfrR(e_ %B6LPfN#pD6%B5!b%f"hKAdX;?oe"Rc/c'n+NJV$+_qfLDBQ[.A&%`gb.JN#-+mtl9S]Hm>58SM]pk['k1lc.S_0OJ2m:mGLGuDOgp9D;o %;u5nQRMnEZ!a>E+X:,Gu##`Ik>mr\kmRDspjmM@>cKmn$h1iV0rn>P(#!L1CpTsG/.MP0\iHgS+K`uLo&c*b#g]O,XS]?[cUT#I_F,T@'.Oc_Fuk\t(b'9:%=d$8JjgEb(0/?9Id1ca[Tb]W %-563qr5.^`-HOmg>V7kUh$d0nXh4G2jrL*:COEQt?B1_WpL(2':Su#@S).HZ](/[)J,NQAcAKtip#99&3tg3=T6V`W&hLeH?G-h\ %:L+G/m4ZmfCH3[UX48Iu8KB;F@e"$qHE]IXhh]E>$BXeaD+:rQo0$YgUg3$Q&Wf0CErpg@Rb"0=\_3\N.n&$;;]cBjkY^3`IauT6Xs[n#O=_b %K*AC-F.on48UY:P?aHEQ8c=\Rr>uFD58J@./82d^ZnPV/QOBkI%HXVKSRD'(M$:T'!i1FJP0/5c8M"O'A".ag.Zr(U]BWp$1E;pdR&`*?2`_1)<>btYZ=_3:$PdG%s\cie:d8_N(TUI-acE2)UP-Tr4&o;MN6AdPFgLCb9O'$`XSA>Dq7cE_FUghgib>QpY@ubo!He[MH?OL#-:O9m[SO %QB_hJ['dD#VoaAo$KK[MH?O"kU`Ff&ATqcoi_#o%_L>K(m!_XlX#,jdAdor8.1S[CAp_a4,0$?#d2C %8atMf>oDX.2us^TDe1>:YodXR/Y"?VB5;LV>,WM6\$`_?/X)_H!'NVbC?^0,5.269WTE,s0",6Q]-_:ppD<`?EgcFI`'.c@=(/r! %om(iscT_7JAj$!mb'=kZ?ueeM2.PKl(;BVdNY]=#ePDL;)mQHHS,7k_'g*HfGWc8qB %69mYbi?M8%&pB;%e]qKIQ+`S^'!AhdW_7-o`aZ_[V:8d1+:)4)p1?YTJpr+rn-i,rh3n9AVd"0Qbjo]si>`rgc/XE@67e2Pc/XDE %?gG!DShbUskU]p3PQZlIE2cQbN^AMM+cEN*:IcRHT+YF"+aR4E4-DEbQR#=R3M[Ik0#GRpi3F5D'LNF=%dA\IEG"a;?4S8">4Z@, %5S.;?5N"nGX-Z%p]=^galb;rt4DRNX4lSYh-rbTQSO^2(f!%b#);T[=<"tOWUOB84-uGY5rZ`4ODUroZN-C0%H\Mm0r3JISCDAM3 %eBTbrF5[!J;cING<:Viu]sJ9k^,[)u]lfX+$o<*@]cfZ"MZo6b%4V^1paYl+M'"\tg?r:N%bb^"s41GNm+D#F@Ua1@Rci %c@0UsdAHqN86@J93q'%*Z^o_-hX7HT?Rl5JX(']9ld@u*Ssr4=_=prM7Q\@3`=8*2^00&0rFOh"2&Ktd+V %P.=;?g"hZ=R]`TmQ,^@bPAgL#2K?0+fieSW/WDXa(o(e!+VWDqZfAeZ'"h\'f6,BDA^Z]=NsiRV*4n9p(4.C^;0>A:j-A %gJ!o.NcgpAq[++.Wq;q+liaB:^3/FY3HqZo7*q]l/BWMt^kf\-VFiLZsX_U)HYZZ4\Z,DnhYPKmpW'$mj`-;(f[L %i:OmEn,g+DR9?_@ERrmWfm5lts0A;dTb7JD_-ASEKGs"c'fWN-4LJ!pX#=Q %_%fP9IsDqqqYjNF1LPlqcp(j[diPsf1Knb3(0S#\*i@7XIul&jk.9R;=nEQ.<^8'^c6a%PnD4i8%Wk5kSAj02deS]2@j,(na5=h0 %WjuF3WM?c"UY2Rahc64#VZ4D&iu'D%+8mEY-gOE"<':`F.j2_Z\75p?TN/Z^`4GLlRoYIUk(TY\9qU7_l'%m4QXjR_VXZI!iZ=e) %e,8kM)BSDSlLMKA[4GC`fofZZ`_-gg*=nCWslpAMEQUgJRpQ6,mhB6UP] %pYoWo:O8:H(ME4#AT\o.5Ne<-DS%NN*C_9QkLY@-;Q'")M:T*COlcB7(-J4=AtI`(ls\a=GOk=nFD:f1c\r,TE5(tb69kGD1[Z9Y %\'J(09#tLR"p21]&-SM[)9=Wf(75sfakkN4$>,sb3`R_1<]=W`,^[!DMdZhLSgt=dTGV8`D(Z>@1D"W1:3XA++p#nQ@V6M%ck/,k %&GhSXPqMjnO7'8\cjqIU:6I%W3c8OP;LG(c5V^JJFN3ZO^D%X%9'WCAiMFn+Ip:\@SJc*6d0[Ss2"iPXe3Gb45e+jdqd&-'mD@JW %Afom`$0!`#>[_k9);O%#Ni1?-m6Wi?*#j^X7rn&acu1V8RJfd.FJA2pp&qCUP%D#aHO(K7DGAB)`XH3SiEO %D/0"O<:`STMJC>pf'-6(cdD2*dFS/,WTJb+/IPR2Chn$[>#6T)9jhut[?.O*SA=2tC;Jb\YH>c\C8&,(^TGIlC8(+UDej?^>%Vr[ %LTSO4C=uihP-)]?C>n#H:L!/aKKj>iHt6SgMqcb0\YC=VNo@iOGM[aa/O*2"rkp1%:*8Ab8)glrtn/jagRhTAY- %f=^?VC?a9YO0-B[L/!usj*1?rTK$&QeqH4kL=L7$R8%4h[AbEAlVSml[/@6aN3a-"j/9kL6*%`mo(7n"iE4!RY=m5/"\FlA@(?CC! %3Ei#'^e9_`67^,c14C,0QO4Do\Oe]oar0U--f;<4.`/7?h %mW)63kdouh98u+ikcW4CiGl83HPF_X%XQ%P/JG\Adtc@Apaj*tid_r-O(iiDP43!52ie?YDcW2t>:R*@G`o>e4>'1JRQlk-3sn># %JT"KO(D$'/I\ecA'E[eI"S(U$V^.]7QunhT(Fd'j=T_QmWQj6th!ABu/\'/[f)+%JSYc04>51A;1.6]=sjlaT!;QPG21?46F]Vm#+G2<)C %ME8ol,-rC[Cl0L_#\-uH&(]p"DUQaU9'd,fWnX+kIG`6.))47?1n-SuD)MeN %c1%5_IC!?IBnf\^qIW*q1d_d0D-.V:oS1:AZqbXuj;O2u]$Rc*)VhL0,Zn)7m']EJC#\R\:\D&FM8M1dc:cQi=YmpMKJT %Fhr8F`,u@plbWt=mVuM6_n+2U7Z-LE(tJj)boil">?FtbGql2#/q&IU&BI\]6'%i]`__.dM?"N?KlouX>X^f8lOk&c'o6VM*7fhY %b:Ke(SQ9Z9+^eCg'buflXQpt+!r>Uhn/-87&/#-B_%bJ^7\;Kr\cdb18`[B6JRMi5'H/]7?#G!*7U2:qYc\iU1m$T`)qK]m,n@\J %f'P4q2geDtG?>Zma%12U!lMT''@K%H941kgrON+rU3B]UT&FgQlOk&cV<928`cVRrl]Pdf>aN71/kMqE[CAp_W_"g\;[_HIKX`Xc %@9r_El!nLKRp$GaXi5-li>m/->Dq7cZ6Xm^D(TX(94GfY#;ii]hi\HgcXU]mhN]qMpjf6-,ZE?!gnkk?'ibElFlDN&cdnPR>&#[_ %WFaIdA6XuHe3_[h,r)"3e:Pe43at4BWJ+*IDgJB!1&ddfl1(0F\5Hd0Tk:JeD7_sIJt*^*Xp!`,*MsUPqC%3j4JnE3Mn.SGgnkkT %m..Kj\4nR-;t@?(\4nPWPC7:"m]\==H]X(6_@A&[AH0=Grie"oH+Y+K0k"@\p_^lU!eth@Q/m?]+^nY'8($/?''!W@,aXjm--"8_ %I=98oKskm_HHI/lK)P._kf0k">l,D+M)$>=@o]9:"g$>=>Yl%m16$>=>q2*Z*37gpL]f?(ZV%H"BBr*+j>/iV<,ai(\AJRMiI %9[m>L_n(f+JP^k8k/Te+h`\[8jYTH8b;gg3stZ15N1VF;)V)+ %LbFPUP!k0\@T\uMFYaic,quD.B@j`8FU@C_K_IYRY"N/)QZp3@W3@nO'XPS`?)5t7)nqCqX:'Ib+g+IG=;S"5=i.QJL3;`[%Jh:R %$gWDYEC*os5\XhBF&4_5#*``("4,>1(bi$!G"BL0)NlGX"EFrg@9n->%uG(8;@T<@$]Ae6r]RVlL;l)mUh,7u2&*.2I)EOsHa)K! %2:,8>)VXPh/Kp=kRY+^^'J2t?J\;'-1U_((k-E%.'lJiZ2ObHi")`qBL6(tQYmTa;dkjgTFW %-EIUQrSW,@D-3,MA3A4WP6!$J#55ZB_n'gDq7c6J$o*f-N,P$e@%>>Dq7cP%4o(Mqca5/i@!?Mqc`:W>Zhd(:U8sHf=m=/T+JpY!)qG5+nkYSLV@^(:U8#SU%,E %$3i;oB]d;/_n'6*bh(Ed2mqKQ)mlKnCaRQQf&ATq+OP_"(sc],8MmkV?rQCi;"7+1FV<_[9W]E_4a'b>Nh.g27q&MY-(-j9RA8q; %(_.1J>*;QPN9;q',alO#i\n1qHCo"hELU.qN):5JGt]e4\+nZ\ggOJ$)lbS7W"=,C!i%*A_n$t+J.U+oo,CG*[\hL\64g%Fc=;U=-e%&^ulVn`+%-o[uX/F.[+4^TEAg)s`+8s&*^*`$G %8]_`,6)=9r82$u,-16d[Re_C2c$n=4#sir!b%<^Y,cmeP:uWXS01T+\U$G0lU4e5CiJ\rS\1W=QL#DM5`L!g50(`AHnV+fs\q6iI %Z%R6[l)+IT_B<8mkj"Ak]%HC'@TXEn)nX.5#n6,$W^bnk;MTCg1Id8f&fB1'[3\2H@6eO];p=Hp%0M?-U$!^YXs)=@Qb]gX<*_mV %Mgn@T_Tc1>f?e>sPN;5CL<1=`&9HesiYn7b6TlSO*3S7M=tG%Q`])Q387<:lJ[mdK0Zt]l"*8P!VN-qN#M+ml[Wi"g?k6;>#Nk0! %iVg#8AXJZrc6pNV8L8!rlY]%F15rBB9?:Mm5M1#lV@:?d9Thc/@9A1S@EU>U_I-D$<#LEZfW=3G986jeB'^uQoYB6%0S?=am=D8, %oMnEKI$=heG'en[%;DD+>O(n9HP-Xme?#.oi>0(Z]01>$/[W2d!Y0Bn:SgntG+g]-Y&prC>k'aZGmnj^ %k+d_hBCEYhV"`Odd/jc#@9:r>g(hb<(V(&WjBrd>,$V:f0&Tq@!uZFJ-B&G].r*^:j,G?BPYD@kgc+bU?'=:V>3-t@A9]2';WDD: %+LM-6BUu7S[>Es]q$_Fh'??bV#"/$aD//c!/0)IQbc]i/TfRIJ&;r6p7-j[b!:-m\ %44lDbaIS<6Keh;W4'!ZEOM@a1/kPcNk$eP,oNjL8?6T2R(D%**G_Kq.VrF@ir)>]2\GJj`imB';/HL$n$Bd;&&UVo::Wn^h=Z:=ctNY0k>mJs1!)/!9&A&(4q*k[_iojBYiA %]_sT&WIKJA=9%6G_W.A;?9CG#"[cUZGpr5i%/I5uacP+eG_8oT#n2+6=bKZ\e)pd2jSu2^*]f%gcKBDHaOg>0\Od:r_12]?\QL`L+\edGB_T^X!0mXL]ri5L7@o^'F36`TMQMNoIG#V/<]e;j>].8!")IJ=0PP*QR %YK:;,CeJH1g9'3O,-gmR%UGQ,F=e!-$LAUn>dP'&J4^8O9*PYl5c"\24p-JUH-KK>1%>?TU%i)G^r-0i?`ZR5ZfMh*jg5_ps6YM3 %=6`$A8sGR+?U*FI3Ij1/+r.!6$@c8%gM8eq'rr&PqFf`m=WOB382T"+NC;+BFaAQ%j>Z>j07h=,M[gGaQK=#7jS"ocg!*q'al"i:*Zom?Qa\H.>TG0=rXsN, %rR$1\rmI5Rs/>,:,S#8Q7pg!NWG:j5=PR)DI4TjcR.>RiO+JjpFA=$Ta9>a?7NNY6)CS)2bd]gEN%E2%!#.ahN4P]c@JJB4R4pKS %#7"$V(lZV*?O1D6[amPZh^!'6<$7'fH$s_5X$.8T6!1J-ELJ;WEIW<&mSTOOr(1*7_b$kc:@Dp8&d.+1m@h-dfkZ/E-l=Rm>_0Y!J`X9[:/4Z'R('O0)n(+\c;iG59>tIbC)6#7n3(lDCu#!mUX'HX:"^O&tXU36);gJG'Dj? %*1bc+(LY$-;b/UM(?8m!8TMV6i$:rd0Q>tP`<7uN"QMR(85(^9 %820C6#;pbi6\7$'2FpLq;b/TSF:1!ONmGk.OC5$-6lJ2U+i2+`>#>J7D`,fO&r\i.%YLZWp,.(704)DT@*qn2m]C6>K+6Ah_4M+k %A)S=gpll_5Ed.d!0'Aq>#h@kL;TS3VArI%.$44.&M$u,T9Hh5_=sKNQiuJbkc<(>VO#&&K]+:2W,hSJ$$3co:L'1/pJMc)J@&B#n %@+tmC$"aMN7b)afQsceQ@!KEhM@!l%$.ejj"2k=hZ)9qgU-_8;U87lOrA;(3io6i:6p*NC_SFS/dab,3@] %NQRTn!6u?dKXrKGF"19]G=3PpoNa-nn`YOKQRbM4F'aQ,U.ePG:Cs;JmSG8e+RrR;he"&'ZIhFC-/:S_,U?]#]fD+STtc&fC?V#/ %Vjo)0L+7ml0f=m*Jt?$qYsJ?#tl4c-$>d8`9n$T`52)VkpVSFP/)'*o6=rN\NEBcjmJ9;N:6=APq=n4rE,$b_=Oc]R[b0^=\YI5$aAsb3a!_cQ!f#r&=/E^97^D7-s:XkQTV"S*ci@,5usk?QO:m %NT:N7_q9\YFA`N`!h2V]TlN'V2%'ZVpQdR[56pa`)cq!Lb\]4p%@9OAI=)Kel=nrRn7B/iQtl&4bmalK(]kb_3kZAT@L.37LY&)J %pDfh'/mkus>'.56aHpe4aJ#)oYn0lmWEF=P><&Y%e1B1(>Tp-/aGo:%1fa7*6FE2L"a]-@!KTWl$>!^j+0Pm)5iga&l(SX<`PCmD=2)>\56A4OmnU(*i'JXD6G7AmTWjqq2E)WG<9:Z>iqt %Fg,#k3)g2.PmV2mWMo$VYP_hTO@+"lh9HM0M4f/2"ClcEJhRsL&. %T?fmd8\K:p;\JaASk:[([2A2:7,&6j7D/oRd:=org!dc5]dD&PLeN9r-g$SjV?R0^p.2Jr,E7M.4ESS*\^t;hfD)=UI[.6;YOO[9 %8PKsd]p<2ImWHsCHMtJLQ\g#?akkfgRcN("H.^8'[Vm,'AS,h6nQ][X;QmX&9&'$Nqd.[EeS5V0oot)TNDu&A"#r[jhs1qd %ZOfhHoMg^S=WH&K1g/bJ#d[Zi-B!ig)d:UMT)S=$TDX'VGO!<*CI!ZogKst5-Gj3]p/`700D;\4:stDo^OiVH&;S6Z?U6Qa&;S6Z %?\,,8!2Y:fe'`p/Dg@5<(aO8/P]#XF]c0IJ7c!T-U3GLm/5FLD; %n_UZ2dM]P8(2n\V^4V6>AA`;:peW,()$a)S+d';erX(!Z$ZK4\?fZNO&&6$AVt\.i/Dg@5nAfnrQJjE>:b(g8ZhB)a2j>]B?eA0$ %/i/Y5LW/"T$/!k=REn"q;-N/k4_+j*4h=N?is?LRLNssj!k!oT;R%\Z(d%./3KS2W('F16kD=a?S!hn?2EMs,:=C;ITN/:7283-4 %)UJJr;X#^p"(8)cQ<+6)'fVsuoI('r.W.i^h.)&EMORLpl.Q\8;&r8?3b9Nq'XdIUfH'YqlK,?YBqZ$_IVEqI&md[M2C1YbUZ-5loNhCS;=,0T2'*JSC<@]>*)'U".XIA> %7Ztu4'N*LNYQO?.']#]h9qHT/C_NKu7P]kjGNFiT`C1SL@DZii_ICjruEYu %rd@CtFMYg_OpTQJo"ZAReitrDWu&t%mF(R@borNMV)_,b>i^E`LI23..D\0A,RI96E/8Tp+fIn!lOX(i:%sI(/*n;hX[D08_b9G1 %d5jZHfc7h@E98O&4?T@u9#);aTP+Q(LhIeQbTR;Z&IInIjI3oiFf0<3i+-*sIV!JZLt3_9h^+@SAEM,bmdKYSqkVej3>gak$N:Fb %%#:5mnGr$8>f)qd19J`NU_hf2no]b72m]*Vi#WK46Y$b_YXbKX^V::!;`J5uE2Hd._)rngO3bIjDl]:me(61A7q7H+Z4`gm3*A\m %:bBh_&b5*.NPPt^(@bOW/[fQ*eGW]nEYm\P %-\Ks4Dd\'MgDS*Qr;3"H4nLS%-U[&EX&jf-U($t\gP&B@.gD30bS(RuiUg"ao^!/Ej=W<&E!fB/N'@.$',!ZkLf#gTbNfiS0p53B %'#P_%"4)mD8.9\g./E>:"&(Ip6k%)_@]m+G8.9]1%&RbBBQ[dR,=-*cB`#EK"=eW$1HX2k!#penMtr+GE(@k1);K%HE< %g<lapp/F(n0X"g1V&O1((,]f],f:[>]X"Wq<5qqGFn/`oUFgbC/^7J, %H?XN8o>m3iil:=IU-a6drl0]`Z#5*(Ck]A^gr3TURi>\5^>jGtnWWp-DIG8fS %BGc<:0K:"WE"+uQ%-,?+1884>K43+u%2K?S>m,go(kKLW3f-1bJ0D^f3_jI9]$I;nm[\`E[-.-i!0a5Ib-I"CC>@[1h:Mh\p'hcFkG19D3!P,(SIo^nN*>[I+4,o<1B>=(hGl,]3;\iT\ %kV4[=OA9I;!i8)0;Mf*jI'$X+:Sm^k6GcI&U84$YAf%V9<\>EOQ"]T$3$8m(\'ra$mIdng4'9BHpU!%S^$0pfn(D$>>8Bce1]IXM %^.MT$qf3YI^rX6s_h2Y"JJ&-ZAe8Ue'Cp2nB>dUBJcas0Xr[]RP6DT0sEHN'"cBPrg %@8FF\HHQ4/c[R[Qq%0^PH)F`BFS5WSk-YZSA+Qa*7s$Sc,@TkM1J*Vh4H!3j8bQL,Vm%^IkC,G`>eO72(Oq'1s-Zr_ZXrt*oBI'R %nts`=%K>`J;H@Qn,o*K2PglCi/f%g&Xp8b&M`*',hf`sC-)Qk<]-EI/4[6/BTsGr)-VYsNZhT/k.eLiK&"ucAQM]LPHK[JfA&#Mi %Y.2/n55P7ZIr6G*(#iThc[_[SM(H]5f&5C]/M1gCA@7(4B!dS4lKG^$SN85>Xe439!_d6=/>jS>`kp.#W:/r\o"$fN/8/ZoTV7<]k-<92]BW=W)cD4^ %aZb,d3P[(&Zg7R5H6+M3D5l.MOe-U*E1J6!ak3din0>MgToGDiOLRoXX7)3U;pq+kl5!RSY;0Q0"hKaG1:P9*&sQqS\M\9%Q6]D] %>252@&rT"+:^u9H1L"X8qg$m8jPT]"UC$SCP%IUHa4-8cCb9O'M^^A.Yc/@H@ZJFWP%\Y`DGpp+qn,XM'W.2X>tMK4\4s)>.[-d4 %`GK@P>u?N^`GKASSWH%Df$r2!jo_&U(+i"a[CAp_<*f:R>25tjYWI5L/I#,]SQ(qr8[9u`&[C'VD*oanpks5HBE)>-262KWh!oaki&D(dAE&^jA%E@f.e0kP'#( %`;!JK9kJP6"8H#^m-SK6qcR]QPt5q>@2MS>Qd3D"!j?%6gKUm/#LD.u[C>("a^B&k['u\9R_dnhBQ"bG^YSV9ei3,)!!r\r#e3X, %#:-h>&U'2$e]qKIQ.ScdIu@.ZjefU7fhH[)NSR]q>'JqU+Rlmsc%M6Re6Ua_f7sFH!#:1uKh:5"T:mCdb`Aal_hdAn]6RZ.SPF:; %[^KES:Y@l`kYZGC\a3sk\"iGbUGhY!Y6%-_+^1)I&75q37I3qcg/2P=aWYQqKChM,-!WRN*$[eCpi8nY8Yl,ZYD85LXa.6Q+ElQL %s*tcjNMlYu`L".(]E6D_'!td@C1D">L_=&)kr##\RYn:9\8BgLVl77@W4`!Z8,HIG;;+?Jr'udf/k+A\a:sp6)E?K\S=cN2mhi0, %]\HCH_ar)SpG8_G!,s7e+YJOFd@,Ytf\/*&)&<7DGKEcc:LsF5M"h5-+`RTLR!;6tdF#;R_R)X\ %J$;^h"Tgq#n./mfjrj\PJFO0!>Z#Kd6>lQ'W5j8c&GhD$m^q,Xl`MC93XoFR/;Ee'3-8HSNkYh#)phluf=PJc0&7B0kgIL;k+K8U %rRuq!:&f^)YZg75hG\3%3uKWM%[1)\@0K7^XZ=JX-C],Hhp@9O4Oh&_(=l!hD1$]ADp$i^F#siAU\Dk(*q:7L(&^dr+ERle(!'d]%.$EmTjGU.pp6.c$4rqfPJ6nhg\d*c%J]n#o1`1.W/u9G\4"IQ,<(omY=7u\TQW?H0agl-1UW.Rjo`Vf#I-fSGIc:^HQn4 %C-u:fG[,1F!JX=NbFBuRSi?npPqqYD$k[0q;]scdU %Ma]bk %h^Pg_F`]*O2I,Fj.%,Y=j-rpKBA;`A8U%0ekd1-T%lhD_kXCkpp=cWH@_,iYH<7/:BOSJ0pH;,\-&C/-ZPLKCn?;Di-g=u'2.nVN %rb&4mNC^I(gcF9VrAj^[j>OEa:sJr4/L-b&gXb@B[@g/eC]]f)3H%eQ6mXOtR9I*:cHk)$2RVK.qq>6/VA=9RptAp,VNrM[Mi&r# %bg`AT(ZURGL&E`5>KbjPlJ,:Xc.]JO8@B;CWJ)eGI^U$$W?osE>(KDMcE/-H$_:S;[MH?O'niC'DJJG%R%RP,@_HJ$k&BqQKCrIU %_a.a199L`?/T+M1Oiud&CN5hI(;3MP[CAp_FN45q/T+Jpa=Y-7QFj+R)O1>$[6h.5+L.UI"+gkgLEnQg&u:+W6L,.c*XI5GA[8K$ %:t;IM^Q8#g=Z8iDN1Vu0`kBEi!r5ubirS,#reL\AM_HGhqH;0.kiHK7nZrWGRHS=@n[!1,VMCom`m6u:'!kfgmUo,ZIl)5RK)&Ou %R-CW%_f-+G>c3`)8ZBD*89.UC:`*F4u)7R*Ead@M:QIg<*a`mPX9RGhX]aj:44k6#Tl9-_doZ,4t'bnQCGnu]@M'Vf1[.Z,\+B52+,''\m4iZOK9IVkduKk^3oP\ %VtetndX9gQOlFP-]r:dl\2t%3k4e[1qdHr]"S(S%S*bk?@H,HR]g.F0+MMYG]!W-DlUH)m5,nbe*JL8h2QAA%SS.lAg$B<%*JNGB %&B,H3),oH$.H#oA_+fh@r%j!aZ%GbfWUuTjZ:cL3)dc,:06GW:rUGRXXPM_/qIG:Gfn#hY"N/)QR%@,2,);oL6r>b'%bL+)M1EgMea0((39rN68_GM>XO^YJZ_XZ>XO^Y!St1mE=GX/MOaSj %8;>C8M[AMa->-:Fh6ZV5)HODd](E`,E4CWL=p&rM_r;T'2)`t+!kjk:<4!o)A:Z_*%b@39U6C=2)M?K %R!oC#CM6TTp%eQ*\:u>6"8#5g>XO]iM"`NL\;'oi?-oJpecTE2.YWS!_.7t=E5UqePejsC!&sNWlb\#d2Rm1GYV)mM6\QK=:FLo+ %2oPV&W5_2Y)re8"P!asC=sm8Di.esS?$[To8=H4kbL#k941kgiUOIWf7C`A0)])?)V68hX@plc %G)bf#(tJj9$:8!a^p#G=-bIEA#n6.:o>mXkL.$tDACb\TeAQkGM.'[j;QD%FCMqH[GZ^;7W];N0bFW-TMsEu=_Re)cjU(84UB8ku %Fo?ZcJG`h]OrP&0&Wf1H1H?7.X@n_5EErX`\cPfDR)6FHHP\N5,&gZ9PbB#>n"Os:TW=7ff-PC"@6VMh`UBP7Ic0c.ijo8IFm0nY %,[R1CYV&n7PN'.VL3:>h3$GFt?s&aQ;;)W6,quD.VJ?KX>lqpTnGX9pRYqO=P%4o(Mqc`J]$fKeiXY903f(Fc/T+L&`k1`G[CAp_ %][-%ZCN5hIkUkq8CN5hIH4m9>Xi5-ll$Z1Rf_BuoQ9I1a@r$(R>'Pc\-rZ5]e7+sb$YF->=/W7(j_nn9H(/!#9OV^VRp,$$Td7YL %Qs,YHmgK@Y[I>4g3j&D"GTKeAS"rPcC3e:77EJ`H;h]rCc_CoJHEObP/bDN0,f]GC>'`*?_=I1aPjVHGo0WYZMA3sOf^p#H$0#Q%0n,Fb;K?oe`;!K.`Om0B0n.\q)P+jL %BD8_p8]A-AP,W"\fJ72a4DHdn4`?*Ta[2@#B %&f0%Ua%gi+:bcBaZ[EYpQV5$FHE8oJ>Vf0Gf&[5Qece-m+c%cerPI/`=SI"Q`-)jKqinri8nO[P&%(#.-5m.)?Ol=spPfOs?Ol=S %fs]nZf3Ho:0s4/W=P$6[cGt&6%-u?R4"/#`='-9e@Y+$&CggV4OGj<,GTgCW"60c'_n%+6>aN710&3Mc*nM\lX:)]l8TA#;_n%+] %(tU&fX:*l<%*aM-V4#9QC`"k-bLl1gKkk@"%B%lT@;lZMWZdle6ZfU:EY\`.cie8\Hf;j")OaVmR",I#C\U\>Ypn37=+)63 %%8FQk,_sDt1oZ6+;]-(scuc7[HS@"R+jIY:5M+7E,K;c6br'<Med"WfEMXe,[(;@<%"X!=Xf&WepoOl %(>$pgCH'mu+epo:r=TUlcn%r:,h=Zs)YVC$iFiZ&s+Tb!d("h-K7_[Zd("fW=p(b"d("fWeIZ#72QgJ]YV&MW#KHF9EeSYpHd"XU %941jbg2C3OPtq=D8Z<^@DWI*P?\1JL9=rj\;*I#c-VG]Lu0jPBngLV6`_hldL;eqN_6 %h;c'LL35Kr?>Ef4^eG%&pOi?KbYR>J>aN71/q$Hki>(p:FeS-\&[!E0X:+tB;I#R(YV*V]h_hQ0?s"5:7s9sZ&fB1Gai(\AJRMi1 %YI0Fn`GK@`pV+DE`?!Okej2-*CN5hIHHkngCN5hIP"];"ELU._kJ^f<"uWfIY"in>MqcaEA0u,?5Z8'Y0je.CgXLh'94(n]gXP5O %(S`mr:n?rkCGD8]Ro^&SWJ+AGIp7ice=([B^;P7;;[`;-K!^QCR9ICWGM$)g=,LWV'Yr329%"rQ>"27ra>aNoZ=.Q3$_RorH`dF< %>5F`m%5FHpe2"Cu\#mVdC=/gWn:u.KH:R.TnN0XM\n^5GlEC<<>[Ek$g&rGEErX`]&9R[EjWc8u0Yc %WP<\!7HptS'VYXR&4+t`=T@A6D.8hWMd[H72ZL-]l2FQK)=U+bc@OZ%&:tN7"@I[94Uo;JG/*r%X-r-8Ka+V\Wl[cI^VuMl"Ihp1l&53DiQc2b$ZODdT$ocmigL!h38i%,eBgrFn8>' %_!8g_V09'Nh+:o9eh#6!27Sj&pE%a42.LPe@.,8@;DYVMkL7$qr\@snc!:LlJN6-!V>cfnMc:O\6hK_DVK_"cY25eWfO"<^Tj;)J %XS[GA\N`pjNfKR-O6@h9-M-'V(LiTmZO+;2_7:cA_0MsR/l\WjDpGsi#cX8gp[#e9UF<^a&(7_T?Org?mjA`rr?t+/BBhO+F!"FF %!#%2YqckBV:A\$%B9):BU+;:7gpt^J)A+ak=B2)N7^SaA;g]QFZ3IgXp1-=Bc59o5(mQ.1=$MYp7u&.=%\hl!cEqmoP._U((d0:1 %Uds!gd_'kOY_P.J6,nN2SD;@oku5k3)m;GcA,*Dfqt %\,eBdHeQP\"g&5p!:V[i\3^Kp6$CE1['Rp[Ftc!7>YlJKQWj!X5!XGYp]17joW6*)Ssi8D3QYsZj$=3t27]gDVe_"QqH^_3``JI\ %O=1QP$LXG'+@e9:)/L]3UBb+@DB3O<-$M=6cbXWb]=uap!"?W!T"rYr9Hk7;<;X*+^IgpBIC4YK5$F0U5%F2S7;t?lU-'^(gb;or %#J-,^YPGG=LSJEdEUVaJ!TH^ENPAh7NrDNBhB(D89RKS)'4F!6hYYF'"o"aAmXt,&)P;tHR?uCSO`J3`G[oW&=eA#QM_]sVf9G^B %ObUK)h4>tG:M-DgY'W?,=8!S2^\=E,?GHA]GEIt.[^5;/c`6U)-Tk,+7s$g6S2%51a`s6o:S@)h;Qi;/CWbJ^q&8d;P%7`QNnQNS %D$:(&5Z6IooHcLN0FgD]8^Upe5;!Sm*4g>+.L`l:03o3tIHas6gj=fu:!_nihI: %8JfjF0Zr&LPIgjFE!LJ`0YB-m1qC4pM53%*[c+.a_OmHQ-b]ug\JIh"rRpGu-FMlGlK`K&e]k6:3;-r&O,)Ch,P.Dl[GpWomI'^[ %rsuQd*M,54.[=\D6T%Use)k4h]DJ+-3b?M3ha[O,;B>&i)Mh0/":$KAP`.#I(lQ^6RiqH\afI'?fqd_:OJ.t[&kYkCMo %OhrZQgDjP)OWOg"Hf,-T^Eh\DbM9)h"H;]iO*\6U"2ogol#_b0Q/6Q8XF/He%s-4E_1N1#&9SsKp+=1o^$s:#CJ3Wqf+&E!UQHF3 %U3Cd?R2AV`(@LtN?Gh/W&Ef%PP#r_A0HYr'>,ZKn]d-*n1)SM`Ctfg]mj)ER?4`>:V,f4=KI %[od_^.FZ:?(Pa4l(q"%'RPa]`fXBbbOnYN5_"Vg\U((Y@+Konpesn\Dmu^4@orGmAYB1,RiWoB'X(c]%cnTo4

*B_YjPq&VcE/-rYesDWs85X %pA4rVJ1>B(2t4.ES7%bfQ8D8n,Y?)IYOtMj$=Bog^-Nup.[/sHm)#l9+3UoO&?!uAp$@G(dtbn-L$cL@\`<,ss6=kt\)ZF[h`)ei %J@3G4DCC-,\sZiR)c`S?9L6_P6]9W3UQ0e'Ym>(V,UQf75==&paI-bKd7WNV@8]%khYo\ql#X8)GNhAfk9J,Khcf;\k75E7QG+C[5-ne2N!Z0m>Oi=IRA %]Ba.0?gVAGQiCgo[n96*5'q.IM9*NIpNt'ZQC:#ZORoH3kk:UZ+^.7h4-buA%ASqW)o8[*I,TueD4T^5>9bg_pH@O %_bE]q#;Pp*nbto%Ua*.NOcZ_VnCN\5AYn[qfV?e%Rl91$rd=jV %kF=n@1A(t?>^Xr-N8lMk<0%@M'CbE&O9G4_GZR5q:?LaRd&XR0[hJD.Nub[ElV)*An+St8&N%bpW)o,qYW&8klk`JuPZ`[i>;PQ> %mmQ!g6*=W"!c]@eTED<*Il.&lo9OQX$c.^]4tm+fV"5gs*WoMcEM\nWmB*$G)Y?n7Ze\R?q/RMk/Vc4UP0Io)!^f(s%.kdU*=p_3 %q[m+>;2;AAX#Q>QAc0D10AD[?Nd!kP;RR*/<)4C]pMS2q#rB.C9E+&$2T5_n>i(G\'&*HuGAWuVT")H!BdWfe]]GT?F@FU2Uu1tI %Z`[tXS@OP/IiTLs@eFpk&mIE/N5TWUmbg=u,Oq,0e:2:=;/G"d`F&KX3&kHD#C>!gi2NF-_VhF73a=PMP6#5oZQ8)YaR#sIS^Sot.H2kptqYA+Xp_;7gMrd81?0(QV<_LBjcosS195:6-hVX"" %[gBcMH]cfac]VuKU;)!CVf7@q*O'0bJ]A7Mr]Kml7[%EUie_;\4n)K019uFsI@#O;fNfCi>:h's\$KaC$OVU@#2mB%JCtQ\YXFlG %pOhpPo@#;@]Oe3JD8GSj@R`r'29K*El`s!_PPJXqNZMnV-\h`/FdQ?13&"QlWMOt$+`?g[nY("!q7bRBZj&i$7pJj5*9!!Y3L,nm"aLmYNp30IdG;'*!I9qdB70)a;%Moo %UB2'=T+g>S92X'L\FN--UjICZDn/P^m;-c>\[t2I6hb%[1E@Z2k4+9*-@E5'NQfT%Gm@u'`3el#"Ypq8)^F]_TgHGNm`R=m1XQO; %4_7?!d)`A99__ADk]T(1ot?CL7Us#\]sj#b)N@tCH>Jbrj=pYX':PeAX#E+jIB#U]CEC.u[VKW*l"Mj5>_S:m@QHos3Yk?!M!5I: %qG.*PLiL:5P.bLU`D$&1]N<]&?ePhDmW![P2u.BZiRK_.BG2B=;7GJBYU2=bTl+lEVgVa10#<[`4jW?%@nL]NV_,_`)/;edhCsLu %gOLl(e?l(9Y!=QSh'Je5p%JhuJtq?1U?M)6f7c6$OfcN>UKpucAG--rl41S^2q9?i+V*)KLi&gqelnUVnmF%1Xkq_?1n^]FVJH4$ %Y%:7FA-X[iR]^3+/VPobMlqR4Fc5uH_N\J$nnm$6?A5F--0,YBbANC1&R/1'_ed3=H!M3j2DqVG0'J8qdESS@S)6[#G+mW1l@!cq %m6PNO%*0-"UgAPX8oQldOA+=K."e?#gteg8)IH).N0K@M@3$=<$R?;XO4i6>30*4N*&KoNWV<(Siqm^7qPMEgp"s0u8[j[2pf4QE %?`p)fs(<'U8c"jAgg3bmP4nSl$F^E#aasCC>.;\JB*\(@.,D%d\HaVbRm`K?kUe+kRm`K?qJ'^Vdb:f?Q0-&e6>X/*TBY:,&U;,Tuk5_L^d;X)^k[AXE\WV#%EC/G^B;W7G"H;PDR;PDg->#^cP>!PY:UBJr#Wdp6> %ngd/UCV<`),`AAJ)Nq,%XLONZO>A)4?L'2Bn/GL1^%NOh&ufWhIoWdb+@ua#O!(%ZG5DCcl %W.7XZ8JeEVkY\/';riR^RS)/h!H@jRs-L>&4$76bSZsk".YjIEpIcWeWj=[VFSkP(h[b^+da)+&Pj_p9#HQseme>h^Ag?o:kVNP? %His>`19`gcH4MC*S#uZ-DY<:[(9^6qbOskC,d? %g&Q.Zcc\q(q(X=%i].,_dUKp'O-b55Il;VUgut+j45"K4jk`=>/%U5o#eQ]uh)f&R,?V3cc-O#V)tTbcA1hXLeX"Bj2lck-mm^'E %*,5ST,SK@jpmFNiO75$N[`UgQF6@u6AK-hoc1fNf(n8+fIE82>o)i2)Tm\OBZhT0B@F=mU5"*H5`H&`J27su++8X> %5IYV'*M@o;UN^8p>2.=kU:3o%BY%.pU/?iMQLq..9ca3+Y#@i%A)Y"j`+QsTaP!.u5H-@+>*EQn<8r2C-I#YU_rDW(1h/LT@I];M %Hgo>E*Xql<_D`:2/]598nBD,L/?IT!l*pX-nM@4mY:]Y^%,@`VSrp^1#bY'&#]5uggXa@*rU6OH=`6IKY%5/NZ*Ae9?MHBK0O24g %s&95olNXM2U$2Jm5=@"4h;h6%!A/)^U_/EAhe[VJd!3tl[2,"fPiD4CIV5H'a/e%Nn$?Sm+&soRa]YmFuQU/pWiVZcAn1X`S.3B`&ZS-Z*\L3Ve6_!lHYqU6f0g!mmrii1sJ'ZAd#>GgmVi-Um\GGc/SXnqR0P8 %VV0YHTp%q'8eL0.q]tL+*'@osW&7LtW-?^l,^[#FK&FjlD_44l28*?IOP7X78kPREl;'IHcLoa^49WalU"UBn9$U]GGr!TX9BF\Z %>5hG6$q,hslnlDKdp:T%GN]qcI8gXY9>%P=ki;ekGndu;#1cZ%B?+huDF_pEWGK'K4*n^Ps"Np2EZEIArrB9ME3,qHHQ)t%_4'in %5l@6pGYcVdSWKSFab3%aQH"$Kq9nZhbqHj0WVsT1k(fF6)r377q92L3gsDMAY=732[WJDXd<"uHfCPmKC9iDBJ/u?RH59TIpb@Ef %oBY'JEK.\*^rH#%T=8;@FHMR^""V,,$5"AX46fQ5Cl]VEiSY$e*tPs3h2gb(Kt+GKNpKSuK,q`tFg^B'=3Z;L^p=>@NTo%&8LsS" %l3W*@1'B"Yis@O8``\n<6hVm$n$H_S`n6n;K/T?MCld2pNM13)9;Trkj\$&oEtTGUB4"Zu9+@2-4>!M/,'XY@^"-p50dnaKEmi[/ %p<+NUidK#0`iP-V;!n]p*tPJ-6&o',p#SVZWECY:rBW_uWr8o66XnqM."mX-[tNHr_\EnO;ti:^$.H,0"q%L$HRFmP7FP#pj*;gaFS?Y%nETC+/]eD1b- %SVnBRo4)s`in6h5[$G7"3q?+m/0Fs8W["ZSj!f&)aG85q`JoG/N&Rio(@e5^n3be#RF9b\[o8't+]Y_\@1 %Ot$t]b2([ZD^'4\S4";)C]>&u:1^(UU8fW5>/5M5p%%9E?bXOT%T(Hps9*OTrp06u&@"=abSR/%cM#P^7hD;"-H7K3p[V649<$a*lM(mqO^q-`WU'DP*QbQn#!!J-:nf@7]cZReiY %OOagO`U&gaqd>*do-r)ElYCcgX0ZS]mNCb4[T`M3ipg-"BSE^YIaBp'Qcs'Q4`9[=h/?Jq.;7C@lJCF4^GZIdVi0#p13?)gYKfVG %^PA4+P:EY9f!j:HUV-8#B`@gS(n^g"A[HH]dX:8U,O*s^I1Y$L`VGeh4_ohJ0Tq=8;*jqYBI"=VUGD3Yqq!26(n^:Z2eo0>Q*LQ; %1=t(0]m/k2e:&HN^\puT<$o8?LW:(RW(cCAirlC_;e7dL%2l7!#h49XB0kVHUQaul,s03_Z4B$V %HM0(JFQH4B])ci5JJPAX?Q4D04Rdb+8r4gK@^nDa(2%r-nBOEToKIT9nA=oK\pIjMR1m;15k"_ucFb^p7'T+4qia=4)7'HXqrp#M %A'4#tqP`Pd-XlMVP4)r7H^\h@Uq9JjE5FNm#A.<*%A"]ZWH%Po49'@4?1>Jur3[73f)Tp%'s %Xob03UfM\ZF;94rh_pkTInZn%a7k?[=iFA+A[I!(cOVbfOu=uBW%CRXBQGB6Kk:(%X_Z#WiD1!K]XX]USo2/DZoTTZ@5Aa2?Imh9 %N;CRgQ1:;`J)2+'GngD(P5^9_irR77pA/SV9Ct$B!Bb3nXk>^cJB[VR)F*\.+t`XoWgc[f3^%4"QlC1TE %ZfG[Q-iCO:qr)0p4Sme5rcZOW26T"tbL-H3EnPu[=Tc?5j+`Pj3nu8Z2j,I\%J[7\e!];LBEI"NX=P?`5ss0N,$uTZ,3b$R0kC+I %6[7K([&'<]P%V$(r58d:^M@L>h2u7CpJ#ac'`&p?X!9e#&,l/opjXNPKZV-JKV%&Y=a7:nb\g[8*4ZX&/qgh-TD[-lFLguTeDEWjY:m2@qL\"i)Lc?^fkE.GEOEr.n!C[ulKQF"HYi#rR-(I08*C.Ot8N??JJr$pK %A7jTO)EUOSl)dC`@VP&:MH]_a@7UCSA+sWD(\9V4mfnama2I*YbO/gnp?%>m3F_Mb!TLYn36D=L&-WQo!\Y8+oP)F'PornSTJZG)qW7K'm58;DKfdZ4RKM,mQL6E4./goj(7.L[/ %'D>FrN'Jm=*AS8=3c1SmGPmhV)>:4lJ_Fg+)UKVS!M<5qbmg[aom6,XKn,SK@rBZ@Bl=r+%!G%JXpk(WP8(fS?<]sE?EH2k1KsEq %\#2Z5/mSrVha2#ENsTVGS83%0^P-m5OeTMqc\Z"7MAD?b)%#d1&;6iH7cK*VGp/S\HbG5'CKiat.6]JDmnSd>bQsZo%6A"X%WT>Q %b.Z2>>:dL)>n>N+(N$Nu^$XaU&l5/4]*FbD^@2U=rSUbmYqPW-CqNj]aLRX"j9KKnqF0(H1sGC0j-0b" %:\=&XT2]kj*V@PQI_+6-F9e5#ri!!l^WLhu5Pf%BBt:g1CDac*?E/:G5g%37oZ_0$Z$+pm_JL8.7bC9GH;c+L]In&dqMQfqpDu75 %+^t,:JZDhXZrKG=-AB(FiMfTC:l'B5b&O;%npt`JiG3L=Zp2N!Q9h\8+sbOSGa-=`0l$u.i4J812M;%!-8J54;2X$ %^Wq7]@0ERt>fN&YkdI28%i*@6YJYMRdg`liT-m5\qro"ba%DE'm5`1o,h^"p_'9uRp!]%%af%.T;G4^Nl9cbYdgaBTNsF9jonWa( %bjq2@:QOg&n&p`Q!ENiB8Y6IP7WK-LQJMeiYI;*O(+9PV"'anFT50C-Us&9O3Ji`XP-ZTD?t3^lo6#+mlro1bCG?R?oN`mKa[lVU %U8Lm/P*:]2RJ&'96#mThS1r22%*;'DEZ3FS0h>%`O;!$YEC`hKOAkVX'85El!]d/[?O2gY#ip*o?19!tM*OgGYKqg]I(X4D7Ah+r %Z9TZ_&]eZ[%#%RR>C`5MI7cmQ-T\50VN_0R?l+RY,aN8t8R^#H-"JrC%eP1W;DHZOhiO,Q]ucX,m6Xk/;AgN%PEXI]\+( %XP=W?S%(J94a'ThLi-<4;/K>Uq=;c,6CJXlYnpb[fAhGMUR_ %mA#QLh,@4JhkZ@`N"@Z]NZBLZIPE2&bi6#=naThFI'uX>S/Z-7jb3kV)?qn`]Qb:B)5QAc7u1EE[>@(7Xc\$:ri8*W%FIfWr>$t' %d5L,K%S7ga^.39,Sg9LdjK=ctdo0P1C0K5c_/^RGe,YYL$?HZGo2B;.3a"k,*-(6P3`T:[MqMa$Z/R"RSP?;uICe'@[[=:3"S\;< %Y*%=XZ&bl<G%`/HE"YYiK7?I %4=oZ>^bRs[5Bdq-jVODW8pB'c--IV`n#ph5&p]jp[A^5CrF&,0%ARr;d0/R"O'$qNb?_=ENGPPsotWg[gC5ODdf4[.4O %:(SW+2c/]-0I9q@L@!7_DsM,A4).a&STXR+DG&1@X31sb#iXIGqDNfGkp)C*$*.7U$+09<iQbE7,OQMu@ir*T;JFHr@Qkd1>T/L+.cMb,W_'!d/3Kpf;_>VgJ %GN9ae:`XUeC87is]139#nnqSueV1\N;+Sl>'ReG@$**4UP\qBDSC=19o^pS))U%aKX[8UH9h?dD9p1>6#\mFhb%jYH?^7,AKV!Tc %q3^TF](ZVZ)F`j7O4m3@oV<%N&7A;U)2/XkM";l>Ip[#-Ll/L1/bS[9/ioO]2Ne_#[$s/C7U:5<0'FlZn..LphrnpEM"]Q);I[49 %BMPV$ReSLVCG'%,[rN%`A%2R'HOD0M$pp:oHe^\N`[WdQ0OZbs%l[G?+!FT9XtU&H-\?b2Q7[RBuq]Yd&")bHgs>p/c&Jma@) %.uK2khfjS+B>7G&J^=Nn+B`@GF4[&_mA5u!bW2_=dJ.No`P8Mq2,-)G.i,H6DWBgOJ4H&68AX+.e%]Mbb<(%meZd%Q"M#d1NS8AdU!#GrpQ %C":JKPatL'R4B9b@9[:sbePSZ_E*_SQ8pUU(l.DPL'hE`L$_Y4pkHlW;8P:$HOiKd_gFi!MeRtkjS4H6ZSoL#LF[QQNTaDu.sD3( %ee?3fJ2!KceVllgHpb]7WYpTWq1^0+csTK%@D3me922;5*L]har;!NEKN'/F.+h+AFjAbA:k,>2,q%2aGm'-kTAlj*fJ,$\%.D3Q %9fs1R3;kpl?!ojiV2W#("IVZ)0'GA0F^@r7RV?)km\es2b*FVj8&INH0%Rr]S+QZ1,+C;aJMU9Lm1ceW<$!aZF,!8?hBR&u,G^d4 %XZ=h'qfTqWSm6N` %>-`qHXGL(>Z1)p;`Pu?+rqiM!c%S-^?`X=CH(N\eGZ:m8-o\P]B?-sN[)pkOYiktP9&"#J2;G@AaaH&B)0Q68D-LpU$(#Wh=7fQP %j!e5&K46a6H7gF_S-5]+eroa2)-JT2`ZRtE(9gT)VXh41+B8]m8uL!)=/'#pT$&Od#dcuflKU$+NYh^/.[jK$;9EK5L!'`mr3u_q %u0iQ#&4GCsl0WQ#Na&9u3K)AhI@lR]^1dV*Xk'XE>;c!=GP&tR[6dCrT+?X`.nP!hi)'o,W>D,IDitEi##kmC3_"FlkSW20J %W!_QN;3)go56ftMDtlcq3p$eaM[ZP9B&]eSSQ/)C?2L<5>K4cOQO/CRgk-IRRD@,W$:R#KE#i>tWE9`k.C']7_=&VBMPILtlLFrT %;8j8/Y:&6a<,,]/BO/2fH4DaeE38DafbQQL#+629Q=WtQDV[*gq1ACU)/@g)!.$G\ZU3!p6.LD5+4H/J-q3@P0r,Wc;.;`s\dBDS %a390Fh0l-EAHoKl'?]F*b?"T=#:G`D,KEIU%&q=1OlXg'"thGuop]e>"tUm\f#Pr2(OK+gOp-oia5!6XHBgr2(OK)9f+:P=O%J=6m.\S?2Fu[;/JUY5HJ")B_,+b`0XgIBP`4rE="1M\p_4 %[3$cc0cFg#PF5\1,Fu),k>'/prmDE%m>LeJUlL:^;deAF3+cQ.epqpbS`RAF %Ug$YAHW!"NP%[1^A5B5g:(!LtFmM]mge!;RGM/0=aBILYlq\iDpqp=8fE.,qM_S"[Yl@7HK3>\t"WnJL:P83J6S_3=CCF_a$2;2! %XCfb4:b0FZ8oQc#Ql1\4=OVOj%:=lIf'.SOX/M:_nPK7J!p=Oo$&IdLIpnq4:Z*NOQ,:83k4&@iCIRFBTo'i\+O22O1/Y3_MeL"R %*4pj$W+iHFm7l7KjiVW-`HDW1JE5EmL**q310$[m-O->F_.LD\d.Xo,/bNt->Ks>$[I%h1&L$'*f)+#0p8o[IkmI;G(u5O!7FZ+1 %&0@nWN69%c9#4]&cDWkLVd/eW:17-$Xsnr\=fn][H;,!6"g(Bs7(oH'pe'):,3h$SGCN'[eo%5G8Q7A?Lq6N3,oT7$oj):/s]qVT?Me3qb4q,1>7]jf0Ni2+7pcor95$2+;I3+*0knRNdPoeZ+M*f+_@V8k2n3P_(F8 %\3%F)VGpL4E.k6IH;0OH\^ei%7FZ%/TUZ;A0bo9a8'6Z"Y-i:9OX&sU0HO.9-uu,RLfbPJC,Pil(]28(`N3+:K@#(L?!4;q4]Vmm %7?htqD/CB=>+\?,<'YJg'LLAbNbe@XGFG9.P,"DVf_\rM/r?-p"g(Np"P$5-.uF3?Sup1m#WZ!-94G3L/Xi$EFH.s)j[3B4kE4Ct5`(Mk/dJ_tcGPFB=h\9m[t-FM`DfZe9"XQB>k %!KQpJ@S\ii7I^o=XooO40/=_';2h(:"W%qmG^ %B4FYCn?@_)_!Ckd7c\(l&^jn^RuE0p<"Y8SXL-m:r03L&iOo*:<-E:T);=.YS'';db$mB?qPGueC:VVa@iP$YFDDeI4a%h4n@.u0 %`g#^fc/LET4`SWOTPV8(B3OUMdo$[!IEo4N;l1^9P*n+Sm$-ao6HPZ)Lb]^i6Pi\L6Y8"o;%cgP2akEaQ>sEiDeSn6jVo]"[p3Pc %b4#kL^?P?ABq3>Q0k+=Q!RmMF+UZ*bUBXDU3?uCsC&`+fcg_+7J"Mb'`IMY+S1>$_=&d,(-OcB^]4a5W6+/V[;h*2+^bi&KDN't6 %A\b[hXPdZ\4CD@>:mK_(WWl-e*Y0cO&2di)1dKV+5Y@ZW+9^'Mlu2Yflh3'o.dTnN42$%n7PCps"RI/76#^#Y;T_FIF[GV,_&PPg %GtYhZm>]pJVSeWC3@J+'SY,%Z[9JdhmJ>"MB.jd#OH!W %'K[SR%T4%l?En!UW\a3S[%6M62q?Sh//LkhVGK0mm!/.tdXg0mm!/X-MdJ.u(7-FsZdpm1mOBBiDW!Qqu,j:g1ID %cHEJ]*(k!JYV*tQiN&ta&cUEK1&P7bmGuudW7nV$1$r^W[>eq/-5%>GCKF/_p3gEF_A)-2CKIId-SNlPI8it@?(J,+Vkj6#0HV`u %01k+QB]gS1>fVZZX/]J(47k.ieZK>C,K9.PiPBAAThk&J5d*\6iN&ta$+&$?&AqRL]7QT$S/Au?g6J&mO_NunBiqt[ns7%KiR]'m %;U7'!Mao3lWifVFeA1)\02LWAJg>6QSQ/uj'`Kjr&:HMsE:Q91,7Ua"TYB9:NSTj!KqoO0Xdq2VL(@'*d5mWsC6 %jf^(>^d@.1NcpnoltuhSQ"IRE6b(ZI!K5/:$m!g\@C2&EN)046qjGp2Ho"eRT>m&0dcXRundEXIWV'X2O^HB2sTn$DRhZO#+h=>;.53Mh60k@M,m+^`$*RfL_K %Jj3h7E`:gN\a?3ep0A7_gihiqC/+I_;5&HFmjce#-Q.7h^!e:8Vfj@k$@Ajb0%T>f6;/la.fWM^bu*BCNSFd@d?7ba0WY%gjW=E#p9F*i4`jeLFWd$Tm\M]X06qjY;4$+V_1H8*Hp$"o_F48L)42ON)H3n<38?8ggm:f+5q.:=sS5sa6#k-OJe-;(KPU5NN3Sb!eNh49UUri)LX %AL:$R:?^W%"a9HJZDl$C?M\W#D7bY54Au]c%l[R>lTmCl4uAX,,IpJ?dYHRirudK2&#C%@2(JA_e)chXi2]r:d%$pZX1kjV;ELP( %T/8V?_US_T2H)`%1)@$t4i9q)3mWr;fhdQ[2fQ3u$46VTX-j@N(UB`\6]pfgRU,(_WdsA(9t)69LrKm9%HS6&i7)eX]Z9HiEp[J*M6QsT %MZrb<2@!uU20-U?S0Li5oJ=+4TY$b)pd$+.1V8T[qQSd)9'23i:Npe3QKY11!K6tBQJ %1V99C9AgmH"BQ6/`8rh_og*3tKK^Y&loqD0gYkb'Y7H16rTRWmYZQ\f!E-PM@:UUIi39(@PA2_-'A:$?5>EM%gED,S/Fmt@cnrpd %hiIGIP;Z%hB1*_XC\TjAr'.,[./^dbg'(u37UK_9D^B\/0s#Iea72icjf.irM^c@oB';1+s->rM">*Peh'\kJhi&`oRK %%)Na7b]`@h_'n;O+Mo(,70f$QX5oRj5.e"\[$+oiVqX!nQdD?M&N4"[Y*e@!NT;o^0;eKB*gh&D@N4c]%U02gMhg,j-\TFuAaOJL %(Amht<%,a+Y,mpl*-H=I6]r5sq!CV4bHg'Rk02G*b$p=AFcG\t>pA[V8X"*auWU %Mb2:^g/2@#2/0P"W@3O7U>U:t)tM$]V!94sHa#92Z$=d> %%#:kE/Vtj[]2l4ILIIepP^$C#Z8j?(j?A8E^SMD4S&j'@1jO^7Of'Ft7s/R_4aFf5YmYTue7tVi@iY7[&Tj %VFKY28;X7^b/QLe:IijoJ!lJ1]n)3>aW&I(7%WHbSlQ0+rA==W1l$S&i@1VFP8U@B7@oNuUC?EUSrT%[,)EF+;(D-Y,Yak49B@?n %8(-Jmcf.&M.ji[)QgB_G)Q+=S:=_M::W^-:PHm=OYh@5+$6V"WIuU::abgU,Y`_lInWid:U.j%_5r/8YDafX5iN*E5#&>. %LN@_B'Cs(XhQIPfLlp:XSt8s,V,Sr76rZ%.M``"/nV!o:7pJof`"Q7%2'Pgd1??DF8Nj^a"g26=Ne:E5,b>,jBZ2/k7l'.T@s=Ha %OLI^Z:6sCIZK-IsV^#mfg['qFBFtRgne`gT&:$="+V0B)NQBS2%/D3-5bZ9JOUQMfq(Ppkt$QAOLn=? %noQ-E*qkt]iVnu`O-,S4Of&p]?Cf"JH=Ra7:Id2$\(%cA^aa@q7Bb?aP9DT(AAo`g8!7L[S,]4I+]#BNb!hn^AB;s=9%,CP?S^[s %JlNubF#`"39X7H-D;K&:$="+]#>p+d"/)(2hk!AP=+RaBt>Ff<09Hn%T80m#cO]]k7Wl?%sM00UMma %`-Ej4qS=QkGuATM\a(-W#Dr"_c_NKPcu)c7+@D?R;o;otV19nR*(:Sd:Iijo='>aL7%TF7aW&I(7%TF7amYj`.kC14,Y]=-Z`"F\ %g..@1)P);#%=.J@Om)d"\MlPc_'FKhg0dB"Hki(>4oGMXf!s<-:r]%F\inTQKeAV[24Z6<.H:Qo^o>gNb]XBWTS668);fb>asc:c %9!)=ej$c>Xpb/\O&S5549i+M$^H*"[_!3Fcrd@XI2j13[U#jn7DBr:@,$g_-er=WJApFb"&G656(sF%(XrB`PgM4Mj=D3kb3*BDK %h_r=?:o#V@BBo]<#RE6Q+>>sCQ&nA=VdtIsO*e3DoW_CO@a,!jJK!?H^&'LC^r/^6;JF@tp\isW."PrUqXi2F^q2l:ON9op1,^3C0uP.@`,[IlDmj&9M:UfnAH#^1l`t&j'fKFDjWI)l2FM;'dcRjo#af?^[=[C!fFcY>I8Z %R0b*9oc@uf63AJj)3O&Oki$TPIkNU*N>F3UW1od@0bqtGc;g'j)+n#b6h\4.5D5B3bq0+_B$=Zg2r42CYKDZ>OrTYT6<*rm*FIRH %np!b*MK7=dFkOF%$smDREhhW^A=?Y'*,CMU=48>Tl/'Lt$2Y"TfsmtprD2=KUGE#Z0spRh3F2_B;Ig/Y'3C/Y\)Bj@3lX%`mV+181FmFJ04/YQXM %%g%sa(VDJ^X&FBApGK*KD.,=`h9MOaL8r,UP_3IRl!4/Y(X*Yi$goU8htju2FgE&H06W`FpY.P#:%I&`OYf:cK0=OHUE%O>2$K1t %/XkR[d='e$a2?e6JnrQ@fQ"5;Q,5CHI)jQRnMH[VRDsLD/4ZP(%6K9) %TB3!cZYa,]XdUfM0H7$+*C%_E.ErC64iblh<(ca\duer=c0t.\<-:%4LV9&amrJ=Wa$V\uKF;cpL4!unhJ!@Z&1qONc0.81&t<[ET;?hrt"VB3WkHM@s_4-Z273GTImS\T;h!m/.#^c8M.o'_hfS)NtP/%kU&g]HQ?Dns)2a, %O$;r2K`AN*d^N9E`o!S*4Ft\^PO@Id`r3"^#5cQ8QM,>s82+6VONoVVZ;GFl154QS!KR;S&#Pi,h;_ud[Aj:s?i<.n%p9.J,p<&Fc.8&N` %O=6(akuo3O\F#)A^[O-Wa/M2`q2LDm47NPV^9r!<7H%lak3\Ni! %\sF'>=Sp-!KX=GeD"hP*qg>A&<]gpdipuBP:/lSI/"KVO3mHrJ_3c<>)J>4*$> %dW7"+:459MV4U?@R'b7PZO3`Dp=tJS"CLM2rMT*BCYI?h\.CV8i2j`FZYA0/-B`>5pqf0,092 %\Aa5iQ^bnj-:$4]q1FnJ&4(Kn@]q@F+,tlUjF=t^36i2(/I$RYUL,IJU\0n\jkBCXifqC(X?3!u$&*UXD17Mtgo`7hj$mt[1>K)O %XMmTphY73mM6;c*OD$I$)o%8@;^V63Mdf'*QGiR$FqYcGWn;]+aRc!Hc*pY9)o7!&^L*l\g!iu//;`b=%?Z@Q\q&/Le]ib[[V)9G %IJp%'2h7TGF74C[o!GbSbA0=e#BSNn0b`LDg]tPYr9_C3jKXg;n7/r0-[FrfIOcH9a](k*FJWH0i3(n5;R.#4 %8.(rCkneg^[9BDpk^P-E`3/l"`Xcmc=)2=1^2W%jH/"`tWdZtK\Y=[M4.KKaEt`tVi:t4D`72J[+9'22Kak,-JnbCA5B8$Qjr1uY-q %:\',D=0BIbjN.NmeodYX'VF%td>_ciHbg%I^/F[ecc_&Wh,Y\8&3;RUjBQK*DSg@@)`K58a<1-:d_aY\>760_m7[@he4`Mn/1pDC %Dim,=^DGoA+gdjgLVo/hro1fLP%5;U2t"#8i+.KBa,IX_4StBYp*#I//p1#!g9s#cPHtB#&I:d"1<*hlc$jH5O#ljcb7V?Xr[p%M %H5^%BR[%h>$U=58hUrrdWNX=IO3ckpN7Ppe*%B+Q!:g&5H*YPkR%nb/(0=WC3S4lJAb)Tu-pm!YBW %[]nK47V;HnkNiYY:)D*eYc?`)oFUhCkjut!rp&(SeYb2.M6\fsg>Uh3WsS=KE8"Q@ %Y^teHnZQ'PO$0(Wn@@\b@7pI:l)$?TrHNElcS(;khX*W[(.*M^1RCp.Soc-OiB*p9OMK_;CSKE%O %5N^?H^Ftm(O:+TV,Y$fi/4GE9.Dupu-#f%9DNB]_SlfFk&"\n=h`hkVbbK %#gY$@^bjks#S!9s8YZ6-p+7=-06`_,.:;f_PC0?_0kuB3*n;d.Gr-dXlo5r7-VCQI/Ai+0B\%7,lKR5=9nr[ %.QP+AbU@(=NE+V.fs1[rK\S3"UGe,>f*]$oAgpekj@OKcheqt/f`e#\HhmKP;1nV#V>h4%"5a'&lAOor]CJ*&:Hnd<15$&W/k=C8 %O25K*HT5gMs3I58ln@4N+7oL8s5W(@PI[2*b]a#-0`6tcj1oMhs4H(=J/nE\[(XIunZP@$-K]RS%>KU'o>_Uu8"Q_*j-8uEmrr/( %EHO]`kmdT!#\\jM1u=NCq#6:CHDsqS=H@gk%c3E2*$P;6I9l#@T+P;[m.j82)hi6UQ;&UI^[QN>lig#br%Toosq)=A57C]@8>9)O)d,FV7tm5='7/& %'f>M:-U>[hRCW#+i\;8IZgX30RUqJ2o\0F`XZ?<%Y0hXa/-FJRK>MM12=YKGr7Zck^#nAW*bC5/>rc3W!'6Z8H#B^($nh>H`H&B+Dm %jelp:n;md3pJrT7AV0_iR9R:r[t8Q;F,VV7m99"]A1;tGg_):K%3*dIb(U%qjC>,r]'YC[=pRMiehmCflDFCfj7P0!i4Xl9$jLTL %ggfZ5nDj(PGP*Om/1/NSR\j'ACVNK+\i4+#Nd%1:q^HCZm*Yqc*pm8-');iT1hCOl,O>,.4a^]Jc\a`Oen8GQ(tcYI[d=VAeJX/i %h0Ca@YmQSKqb<(l,Hrek8,KtN[$F=#e_$h5g]@lHE`L:8mV6_>"g>RS>5jJg@m1`]*9njp_,p7gQ?OO(j'M]6Sr#sQ:?d49QRVO; %kn*AG=e!KT\utaOb4NP'DahTIQiO:h%`ToRi=OU2MP61s3Vo)BjZQGN)->7WLJPb(qqi4a3Bm3:I_K.g>\:Bs %1hu[FT'3gPQ='kh/Q4sC67]BU>QSm56`S"LBWr4D%2kM9A4OT,?TbD7F^LBjSmWOFgii %4`(H?F()fsb&.9LVrpIM#-8A?:Tpkt;7JOb=C)8=ZGS@`C(J1!Yt+`A.D_?X0Da#E/h %htO60-/X9Ajg5Zu.f_Ub29Flqcg5IPqk!G$JB] %r9H*9]OkU'NBSo=`987mMfP>=kp`E/h8mbcSlHi-hdU6UmQ<.M1#W%c?7I"FK0OQ^.\9p0`*I@Go=rc3d9/2o)YdT1K?Md9pUsOq %Be4aWBAFd$(`e\%"h(&1EI:-rkUO!o7XOsVL2A>aCegthd"\XLAWJ^-p;o.+FFVd]KO0ponh-*#`f+C:lPTT-@&e_LnJi(a!]1s< %s$fGoQ6j50X&/-(?l"\%I*dXuq(?&roUi0Ti^`h_k@G_^i9cper*ii"LNtM(p?rqO2:_bk=hbaUWXJ4'GM^q(l+22I-f1D[>N'%F %fF0"(cQIs8fd.eV$/^r!EB`L^8Qh30&)^QhkeafoCd86]:\?i6:Fu2m8/rt1-A*ENJ/m3'q8%shIO0pkB+QB-eB4&[[9fp9Y`,K_rH-INeYj%,d^V.h:p>O\V3HW=OpoD/Xc7UZpBk:dPi^]j/%rmH91bb?>>]C!9/>@b$CcO>:F2VQb;c[PDHd^dFQ7269\iP92q'BX#%n`Ve(1Sg`*4YV((E(0(*G1Bg_k[s$l9u4j)Dm76d*sF*+9=8;Z?\VHsj.``$hfH3+Y=e?8T=_onN7%$OeOfP92Y/W8E0 %'#[pDLke5i8<],l3l]+rN:S:b_)3^91ll,'.ppRZ45m"dpg[itTD6hL]Q3((/71I']uF3XS?8`9kmC`Wc=T60V(6fP!Y=IiQ`f83 %Mm\^H?FodO0nBq5o(2b&egh!tHKn.)nB,=,8IiK,ki0_if:`jWJUXJX'#T9qUZ7;]0aP$hMN-$^HZ)3C\)_IU6)kKdiV]e;5,`5b %$X$UI$W6lr0t)'L8ejZ>+#OD^_]ra@8SZb3G=8lJD(o=HjT'*.=Y.i&S&Z^(9Rr5clIUh96M?@$7g'GKKemg0rFL:W4roHZ&RnLp %kF-k#H-)/N;;c[n?9u3)CS]quIrFG2\`AJ-Ic]48B5r?=&?&t4(t#'Wr5#3j$L+&mUhZ6A6kKS[T6L,n$96:r^Smu%8E#B,ptSd: %6b5YOFMFEg0I]LO$ZVu]6>)IP./(J^Za#uhM,7-!5G$3)[Hc22GL5G7V:S!o`S5gh>\9\Los.2CjOXU?$+mgr)kcgnKjq\2U+45" %SU;@l[-cK^L,5^5;>3#Um/F^WOf8qJ2*4\#!$^A1rcT(L_OnIg_!6U=FR%i=-hf@^\NB`*j[eo!QF9nh`l&JjU%criX`4[L2n>Ao %1fD"V0.p>@-KQM-@JK1K_HL-F+snf[$p_6H&sI+rr;rK*I@]n+`G=:#.GFac%h5$F\IWHATFDi0Wn2I24,HJl9P<9Ll'Eenk/cR^ %9n?!YO.D?(j9R:IJE&aPq.XZ;(NCY8P&CLPWC"5'/':PPjOd&OR>PnmiZ>dTK2]ofd/CK6Cno>A"h&K1T5GJEuA"6X5c %+]jam\R%op/U7cl>t1V4-rg>dodT`AVsh6GW0g'hR&O2]sC6)s!L*=KI1Bnnj8?B_-?9q*0D7:^(5nJSF)L.ZR9isLssYmO\QkKf4s[dA$:[:iXd;"\a1uTpiFNnKfq(t.\A/%Z%pJYD+5,-D&uUD[,Fu!G:`G/$LC[? %lr`WQ(nMPgNlBjB@G#Lj0]*4T48?IZLJjau6?N>M+PmmL,%]pkidIAqoE=?CrMW768Lb1K"QR'[\pBBr'8I %I>jDNp*GSpjk+LPdRZZ+p4AKRK7aU2I)ak(XP(kIfm'/+C+,K:9PfZ("jF?L-h:YAm6c?rK<<=T,3e_6a83JSbgiNu#/EZZOh78q\f %k:kJtUOp[>qdn,EA5Or;!o.sY-X"8aEe8lZdh6fHR4*Yn2+?>A+!^*G.I*3T;1oD?ET9DT_,<;a\tmK&c4k[V8:'?)%t2Z0eusZn %]>!'.?`VLAU9`d"9?D3[;WYcK$[jKq>30.WHL>?M9WJM`a2t-9Q5R(UD%)UX$prg1>c6NW42V,O".JViH`rPbs`eJg92Ubg$0aWT6 %77&DW2%SJ)QFh)8eh$f6c/O\@3i@>2fB`i[a&qbAd/D^3nONI-/CXq,'%Z&5'dZ\mFN^GHdca9D?0DPD8G"1c(EGeq,.=U3d?DBt %(I+&%06m*Enf#*G9IA.3_q_=*!Ifd]kp\"`2,DZ!;m`]^.o3X0pU %,,hMf*&n9S`H7NnINS*@M.$((#SOsghMno0+gd29cX:ZJnr3N1L-`5fc.LjC#h*YH"oklGr[d@>$r\'?6nV7/9g7a'\880]!K$JS %T75JGAc5',[.pX!0.PCFX-lo/TnJ-FFP=e=Cg8JBU&O0Flb_iZPg@fu3#7cA3X:0JDj;%7'7q[IQ@)Ne/(QcI29-AnYCKQN)kP^D %-gQ=2,[V_=Sri[^G+UY.>/F\hUF-C1L#[^T#"Kp>s)naAegYtf[_b+GL=q5k)VnlHrlpH&g"\R^mU@(\TZCZ7rJ]E.!a;=nGaaam %@%u04/rgBS`Or#gV#E/hg9hoc^TD&)]-Q+^:)nSK3R!lh8$QrB;mMeV;ZWkY9Z_%n\p=.\1&SY9LF'KHO;85P?ifSfDi4d=(a;II %^D;_pQ=%6>$fWiKAe"#pR2X@DF@H;te\[nu[$..g_.Jj%g]d7u=Z:hnF^qm*]LX_^7kCF.0@HM'hmVUV-%/ELiPdtrJ[Y&7k^?Ch %]*\@nZ($^VU@H(P:$j2c%#:!rp+N%F;a15YI4B[-!9^o@r*O")LQP"VjLKq&+,MdLMu!V+A]*FS?j*O!2Y %oOEPuEO>SJ;I?\tBWtlr-n18iNs.]/iL^nd^&.3G)'<8,Zo]%M%u%I&^;I$INK/]4B:0['*,5='mthBD8l2V"s236e-^3\tXMLt[ %#>2U5T<_Q7ZTVLd#7&:`UnYhBf/Vb:NCK]gopAc)ShM54bJqZE+G8o7e)^b.)<^`98$KRDKI0k %BnaJ?Uh%RMfOKpFG_eWeqsVZ95Aaja[1.#S<@cOY`,#3&ZM9X)_W:b3;(+-lqa="AJ$?9g>H5"j8SO>M^J=aDWmAkFNKE56lsC#[ %_q3ajg=;].Q1e1u78K:LdM5`Ck_ZC!StP)09Wsc0P@6P%!j$el@4gLN>LbYX*jnlZ08qPik2lIj\66C[I_9A0^$$(VK7NOTX %[up=4%=-+ZaV974?])6RrUg,qDZ1dE7K=/+;LfPc:]\']isaA=(Sd;p_:#$me^pid=JH?f`Vol^naXKKQe;F$.Blqim"4HGuL(9fWYqJ?6+]Lhm2[]X^_Jok>k*19&ce>b/n=2CAYlu^JTD^;HS2'YQKUn\V]$I1D9 %c,*$As/)6=T($2J:=cgbYmE(j)ob>e"s@o6>:`mZgo(e-horA4M`$6bp]u7sNko>^/C%I93+Io$-6oh(Ctb$.nB=p@s)>7^XKGfiTB__9esDdf_t\`&H@rj$F],^f#9USpm/8,/N\q,?F=BNrf<]+]T0!d%V0-]E<:**YLWI3W]$ic %3j:6jM4*b=3_-,,=i&q2gG2tXbT][)G<<#"_5Wgliohs)q$?Oj%h5)a[5!',L'8t5gbC4[M(I`p*u:=e.K %B5/-PYS`r(K`f9?UOPiFpjWP;iYU!+N;r-='l220<:`bAb\;j3V'!sGi]!!dQr1q_`V>g?!@at3<_C*;:K#*#M>IJ4HbcCCbpO,r;8PbBWI`O73I,JIuKS6'aPqc %%J,ms$3VpMMcQBKY[j9AO^[U/^_K8Ui<5^bYU2qo)rY&d.A".0[ou;l>j]h[+n8gC$t(ZJLLG?7]2I-tr`i]OJ>P=l+O4gml"(!u %)[mr6N1>;Z@2K#Rk`L"A@0D6$<5C6r/d+S_h/_ZI6MqM'E.uaCJ,EgGQ+MNPf:'B^=At3Q7_p0_e>[!BXLIDEF-d:hh/K'81*Q^W %XR?-F;?>7\Mt:>)?`sKBp`GiaK8kCOD?D6LIgB7+MSc6&VVUNO+aX4X:JPm:"B1Ru$t?]lr+sl(i?n8X63sd!uQ0EO^Du%T74kKnD7u'$]XP^K$ji>33$< %faD_el'?+MAHF(tB)%nn(Cct,DF%P@(h*WKo=/`#kN*E59ULos*6#/6b]tP_FrKkEO$O7<(s6kZs0(?ald9WlaM2E/^KtUa9>\U? %F"bJ1pDf``eWC@"cG89rXjuR[9f(1>7,gsZ>Ygq(dg`bd4sqie-IM6eZ0)$:ThWk^+5eS^mu`)W9R?5nZ9Bal-0ZtO28ui?2mT9B %5N^O[0_W!PVP%/hb>H341r(dEqkP9U6#WfoJt="IK$Ma9(`_24?^EG^ %G"hA_5=r;*6'XZsNAUVQ5iKso<79-hXYkr %/uG,Tdq1-iF>5`d-gR'iP$T*Gr46I&eiSWYb9W3Z)a%#\_u(?-AuO+@O^ma#7nuE9r-&dSU<8N)&L-ZCne-M]C(+4O;AWqm`h^j(rOpd)^].5cKmcQl\Q1YpF9QcVi!Lu,W@,m>bKS+(e@l-,JOa&jS^$i"A87-3<`/la&/ %fJ.dX!_([F,O%#o6:m*OkfF7_6@QmgW@RB2O&N*dZ^Vnp:k\t^fTeejP0MJ`lU7Qq6gceJG?R5K`di8 %-NjplR*fLm.j,4*gI.YEoHn7"B](MSiB5?Qf`5_J:_D4VSdfp:f3_U0pRfo.f+HBB5,uXC/+"Q-AS!mhk?*"%TCF1mjjMSN5Wbjr %Z1tAtUc>%??ST!/SHG'H?-7jt#.&b<:\#5N^87uQHFPSRiB54`@/&,)36qp.+IliNWGFj%gjA#R5:d':^XOdF\I`1'9ZTZ2%q7O& %p!HLq8\ODapg%ulGXnfBL#u6KTBiJ6AcGDEXE9;1pEOZ0A(g60"FA %R+)^Ts*JggoGin'Mo>:Z@mt&5blhf:=t*8C]TW"_Wjt)HYWeua>9HeBc6i)M7F:%Qe@dM);lXn-;*Xt;lB(LZE6#f)[^qk+_Xhi6V1rVaSn3F-JcOk[k"[oWhN@Q@n54uH/'6Dm?%5Cn %ItnC`l+->`o3:rFR#REG^TcG,[tuSA5>0aLX)kG,F@Y:@k0@rGEo5cuO8XY^#,pVDea)18\^k6QIZ^d91/-+8JN(%-:<;%3M)LIs %LYm7C2e?fV>?9E9FUN$?"5hXB\RY2f^?O`rFmh9.IUqELp+:=BZ)=XTbdL_eI1;+gV3 %B\9;u^b)L[m%f=>^1b2mH:[r`-WeVjdB(3SDc%!<.\K<+M%hUZ&t/aj;3AHs6V=%1"4ElWo'RFr+K&Xi>OY55W"Q[]u'X9 %5CD>P3)HXZ(DOdg,G9mG^#0DKW2K"u26 %_5B<-+28[NC[!Ih?'0b-V%_\mJ?S6Ng6R)'n(r.[Xk,'*Q()b>h0Jbu^Y`NbK4SfojB^9gf%0S:gjcXnn*TJU_c;TI]<.P`_p#X! %3kaX"kj\s%glM>rYsta=30iu:)uEsQn60CAC(;1IAR6i>pJOQu:k %NmL/QMKdsZ/OX:+/B]&)C.+[Sa[H[$I7LGei1,SZlb_q"k.]g":&C3=\GH$:1KiP9eVEg')4u'#PBm"*E;9,J^")C`EVNS(WkYs< %jE@g5%V9Eu`RWkXWE<*WX`UX1NOKl`WV^Dc:B<_nb%PUh!PKP""LanFla"I08/L*>/oL+f?.O@?WkU>1\]Z%CZ`l's54.s`a&QM8 %X;tEsD9C7Qgp6[EgiW")V6ZrP^75qRH=c*Z^A"q1%lRDCJ(aI([Z6\Cbj'=9I+s,1oChng#.,r_gG+VL)gnIblk5pTAUK@B5BN^8 %`7"p?"ShACq>QE)WOQT4.)nEV/tT]/)8tH-;`s^JhG/8HiF`5Mdp6a_T6bt#>(rb(5=FPrph+*)AR52kD5&e8rXj&`rH]8(+QK5^ %pYE@*9'L68iY)@UN4XVE3G+/pIW?NdYH%rL5IpO7nKQ40mb7qe`3s'.M/7g4H7"cG+-AejTZ$1%^4Ga%R?oO,!=rO>i9rc;i=u[& %@lb.<4"_$=7*/m_ccr@>Tl)tT=e%)8G$fc+f2?,gj>^LkhoJ',na#^Dd*3B"1U[PWcc8GN$0H4$Hm+hpFuU %O#aB_I*=LYUFe^M$YJoelA6s^82RiJHV,rgiTJU%#_6I"&CX4RRr?X6XD0(5bLMNritF>hqL1KEPl)I(Jpe#Hrq=6BhO67bV0gP' %N7XJc.I7dIG(mQ;oI/V;Yt4JQVH2]!C3@nL %B:0*O_sntg?J)KHnOuK1Pk-!+C#8LshL$Q)E:;*F,0d@06:8H4XI`*8UkHjb#g&dq:\P(-?gN2h=8qp5U*OpgX+0;Ro\e\\&**`m %r^a-inSB+Bm"8q*H9JOm4N1O8.jQE(0&^:R!N& %;D)d25O2I`C[3`hNY7fr8$gQR!]q:oIeY8?^WIJDp4^JtlE6uY@IiNS2CI,5IG2dRac>B,5*NsH)brq0(L"bO4o403NZ5ih`^<9V %biPXuK.4u(klaJAg>Q@GCZCB"%7[R:R:^Rd"ciV.DY)j$]&QTacknu?gHKBapf9!8hV05[iW=:q;.+PZ9AE4=k\h.'HN%)_+M37h %l/=?SR,s+\`[B'`0j\5h,7i]#e\ut-*KegeA8a#U/%aEDr^cN$b<1:HbP99b4E'ia'_1HQ\As7M]?5hRnZTlp77]6G/?WBTap1+. %4j(1dUpsDeGMcgV`HO_Q2-*YM==n%@/[oTpfNB.?L]12(CS"$G^V0:4#9fut%=\?SK'Yp?kH+:O0QfN&:DTIBo$:R91ioA"W%GIf %VF/+:Ao]5^*"2$(9(bto#']>`*c0RXYa)p-6MB1&%6l5s8kuUpeWps%+R&Rm_=lEZnI")&eg#"J15WfKdL5QNj)9Bgn_/Oq=ZsY@ %Ls,D\H'uUtY!C9oQrES$Ms2G-gG2RXT-VV9%%+87_=uBd7Z?<.oX>Q&?O#rbSo5[8])5l^qDQ6f`X1551he*8n+'/H8[3bGG$fj# %QhKO4?$U'Y>aKm<=3_[CXQLGDG4jqk=`.Hmb3:U^9LQa)o#&lhE91S4B+.dMr-cjBD8$!f&R^_:rMX;Quh6J %9mucN=Vss!PP.kkGpNMXl*Y#r'5C-uVp^!2fY>luV$7qS8!is>No_('Tc(J''$A@KJ#R!GkK]InClW?u&a"(^ %(3W/ch,r5$Ra;-04TmP$%Kk`GRm;'2&9)l168p?E7IsH %Irsl4VNl@QA,X$kFR&2.S$qD5Me*V+\H?+*LFak/e6:!O*q#Y.lb3[p'0[Fd8\SFnI4PbEn/m$ERED'B.jJMG\WiK80U-8)bipMPI3CEUoP`Z(Vl^LX8*e)q8XkrHb<((A`TL@]2f+$kNkJre92u(anp57'KAV %'6n#n+$-u&AE7%Y7G='P[?pA;l\:s158,5CB/B03'Jj!j2K*^7h&YNYOuoG+RVfd?#Ip[9&-1AG;p$OJRJ!1h>d's'jF %-Z#'9MtorWn^a$Q\`EI=bSf@>De,%J?phT#`#B@E@c5'.!?XU&4j"4g3AM9&MpN]2o8.8EOPUIlZ&jgC)/mQ"0qlFr2_#M+j7([2 %7`4"JUJQr*)RTacj0+HsJ%k=.1L\[Dj2am0Li@&-jL?P^2AdXO %>]]*q/d8se?g+fl0"O@c!aH#[?5C*tiS*nIaj>_E'S#Z^.M]J-9k"?&ENW %:Np_p3H1Qa7OB$,O][E!'[\pkgB'_ta=N^.k=hE=LDAQ5B3k>&3K,/%29EO;e!N3QVHS(mXLqlV>k4h/\L/'dm"OP3*O'g4HNQNg4+:cIpNep+,iQnPG08E`I. %J0nGDKAp/Z1gK(#cY)u0!?reH%kV`Up9?jqKIHGHqu")TP3=T=fl]MOl"+5cY*e@!NT;o^0;eL!FZ5p<\S0jk*4CZOI.=GQo`VPA %m?ekC0dcm2bpa;BTHj3fQHNN8EbXTO)tNfKXkOoOQC0+thFJ+?H++#UbP!TBGjIKQG)^;L(ggi"^)m%J=o@4cDXB#Mb)5SNsV;V-G(Zms"oLq3%Yc^+P,nGgU0^Y81[/38O'NTQ+dfb?WV*oH)rr'f]nr;D&c:H!*?*o;K\KT[`= %LWTRS<3BuZ9&sD[c)egNIBdk1R-Hd1o>B+_osrV.0"+5"'SrC0K)W?Oj,/M1EF$"l %mdt:W=l^6keV6fhKu3L7fH17B4m!EGFE'V`7-?L)%P=@tGdd)QG%K&MXr9<4\.)RFjR-Lm:^3UBk6=Bd[?6:S-W %_1YkDn/%05WL_CY+d*[EDYZYU*eV).)C6K2f'Gjc\G9>cB%9lf1;DR1h3,F+Zp^fh0$IQ[=fYF-s*?=!(,]&oGTOQg\,]A8Q_44nbJ!ppmr4K"ER6krGY.;(1s^fU5l %DZu9_HQF@nepHIu$]@.V1iA.s6be-Dp6ft#YSJt'U\I?A3M!gm+]\i93XK8ZQOq2]:U)'!q#*O+]TH"/Jj/l39'#LiqVoe.k*i0` %ZZOr/_0iMB?T1Xfhi\JGq%LZ^9m(gSHi@P.31^jSQj86C=[%.E^9T %2C.!`YgKIm#e'N&MMNDU-pJTC?$+hRL`q[TbXthXl$M3)C9GcaQ"T]7R(H1B`NUq(5%dT[02V\%mJK5HlsW[`KVS++U`0>4!lp!/ %)*T"MA@cS%&$PQ/!cJKc7_>,`.@0k6$1AWR]LI`"]A."SR4N,.Kb0P$ST\EJ&?o)moUA+A'H1/gRX42ceZ8r*9cpM`"hp-35UPH,gG'B!O3D"h?F1HY8M%O5gb&)u4p,IA),%j_pOC %5F18@gV-NThR%/-C`?@[dMIJdYNIs>\%Cg'EC^k`XRQ5/YMcWd4c)+%IC.ijS=sfAag6b/Z/$,cbRA*[9X@ZBAudQ0*MutVMeR>A %cO=Zr18`_R4>Y2cmP)nS]1b"&QB8.EJC/QWRE#P:0KHeK2O=tnfl'1nDPtTBbLKc2:P9E#`+*6h%Id"Bi6S40>4N_QFc@LkaQJ&a %5p>&\4V(d1\9^%"%4qE_qR5>k>WTWfo?ZbFXF@OrIPLs'HlaLAfS]R9rXHh+JMZS_,e4JS>\==W5&V#6[eIY;aB`in`CI$flpLZ)'d"7>`! %=_%O]?EZ]H02elk`^3O\'Nq3joPSKI24Rgi@Kb'A!bVr(,E!SBi69UrDah/S_\n'EO0%.dLGMg[8H^l]^_qc-]usIfB8EG-JT+^1 %33u#V'!fjdcG1CR">m^*)-%OLBK1XXDl<(,Q,+>'8\^J5:51P/ZRj3l@lQgi%Ze8sE]A\OSddr[$_5'4apgV2$_/BkEZNNj!b^FD %Rt*sE3$Vt9Ijs!>#\RJ+fB8RB$>KO7B6:.fS5BH&%-AcRB2l^8?(R3#E!@2(^GX;Q_3m?Pqk:#N,9L2>BUk3gcEr$_Cm\N;\#M6b %=jODHRJ_h22`"UCVc7;jGB)iCCK$d$M3UNMKg?AP^/`#TLm#XCu);@fGH558.%]@ZM&C %?I@^Z3g!X,MWWef!$YJ#72[`CWO,&]nU'=t[eS)%GphG_@^LbI08:/d#cg(OlIGu$73*BUPiMh#jC7H.#M*7r!gZbh"uk*D!;2L< %GC)UmK/gi/E!?Whm5Xc$c^CoDVcTtEmohOkZ%VGBBcl%rL)1\he>0PZL,+]cKQW=:pbn"k %h+%I"U_(q'"?2*A'!\l%cMX@odrY?XFZJE<;nhag[3shpp*\P=fREE['l9-!U5L,8On@P-Q?+0Bq0o.k@+Q9@$V.,DX6 %j@CC\H=kZNb_V3qT)qfd`?)@G[?@&mk=F@>VUI(4#K*$a6]h0 %I;gjQCBlN2-oeoC$\WJ4@@!$DPb`d7F.-o5@UTQb&`VBc=9,KL"!ji2_/euA?.RK_.Y43/`">*^3ksp(JN;BXGBciOO'0D.0HC'( %*_KD`4/(K.qR0KrYPM7aaJi,J_`HuC`-^UnT2'EbB5H#]M2-@.qsY$hN6bE%Fi=H_gU8m0A#&OpMHI?S-X"ob-@".31.qjD: %8+uL]XuZ3m&*lf?D3 %erl&$fB(f&Tf49],u7q#ae:Zk0&!VsjNnju0g1-?/bCCVA1cJWEp-67Q!1HYjNniCcW5n[e42L8F?+L=9g*ei2.3ie9g*e9-5nH* %)n9R`RtZ=W8]4ap6-l>c/n,ETQ3;"XQeSQX"43[F%YAX>A90MZ76.'L!N,^`(A2;RSc.5ob!#+X)Tjd`Tf059'U %?OWqBcZ!2gdrn1Z+2H62JX?$R,.r"eVrpN1p$cpW^\r_Uh>#qAk@^SN$30'YBk7[Mr>qtUU!J!HJ-Xaq%X[550Z4m+$6^(qbsA$/ %%sLD$WJ`PBA"bC;^nWLf7q^l3jVB%>Imodk9lZ6]+Mo`<[RY$J4if]p[Y:&*&$.eBia>pOl/%fs9Pt*Gh2;`%M+TWga[@LN:\)JK %f3a4qC!?1P8qL/A>BPRQZ*bs:V_TnnO%]>1AXU9L[)LUs7WQ)R5V!@AhJXS[Em9A$:1bK)DMi=9"6Oq7OChSM=dJ %Q\+)f#Z**s4Z.\dP6of9$?))Q-XjMmq>G^'o&^EKN:@'81/EW]*N&,h<44(<[9M;sjs/cdRcYS^WHtQo>KF?Q;VV$S`="tUP081) %R/6B>5.Y\JkGc%3=#^-Z?+=`V76BCSf)IKt1/c>%[Aub5mQc&5)^R@;Bg:;'7!>l#SdPEt'MV(D-n# %#[0/oa`f7d8f/WbW6pUT]b0D#YSh^F*\Ca=/Nn3@,+l']]rBKSl%\)@CKl$HRhM %<^T/*js=gl9f3XG'GQW6X0%,.*/H>:[FS09/+jaTiI2\Z.*,[dMCg[f0es_3K3;t!"Z[,=Z3N)l--=u^K&$3Z^/@<-Kg2PPI=gI0+q4^d %l[_d]=@5BWjbU-&1t>EaCH:+K^M':6+P1XePn@jj'TUb";5Ks/pBtN3SCDX[nW4f=JnYkRnp-YHHFr8jFCR!H`])VE)akHGp]f@; %"GJgMq#'4/d^k1>0;E]m[FV`Bl$H_'HDPc_UlEs5_(;L-X[qb=h=QkeZjO1C%;%W.lU+k-k?[cEB"]h*M/Om0a+>b;UhR)c]iVHr %97i2`^'E1R;Lp)S%-H)%;(/F54]Nf-+H+/K8h01T;l,)tE0l!9f7+ur4_7Y)][TYl+Qd(`d(rK&d#g>B$:@_M,Ym2n]@L0O)EB(s %!QfbcVLL-44$r6O/<#PAoh+P]Ns&NF&fmgR7`q]TYMCkuG3,L:ip %I>sc>hqO2Ieb<#-1_>]sXOQHC@5NZoJsMi<5e:!ol/,DgL4=u?Aq-A+'P<_E!7ifUd094d1#:2!N:P9$1WE[f`;**D6<*MI2U[DE %AR+dpek6OSAD.e0.ClUO0*?5)(I\=m'e:HCRS@P+-mB%=$KSi>H,X'FZ`aRd'+IJIkf!nl2jGuDWJ=\i];kN'X0)NDaj$s`4b37ir4\^*`n"t9c+=_7??&1OZRgEj10k:>! %4G1%uA-(H8][@\gA%-;Mb"_k-jh?OfB$Wrue"?aAl/+eBRq%DCb'edKpQ\?;E;!GpAO,0jZ:o80IWF6I`Tla;_S0KOh/"U[*NGBA %2s:+=&od&DMDpUiJq`EWESq_Qlu=GP.]&T`u&?Ej-k'%Y%eklkcX>HQZ9ZEpW.EK*cO*SCZCnm4Zq %\Y%2F\m&EiH-FcCLG=dO5/,KWi[!nW;(,0URCGsLe6tu!nM5*[c_BRu/]qC[nMtWGcU!OPc%+'tXL2*E#!9=pN:An@fGMid0ba9` %)i-,rN:AoKL_%lR78Y6[VolMrQ7"$AS?>3lbtm`.rpEek7*,:akrF6!lSOs*[d`okDd %5+CkYr"T_QnKE'Lq%t26$CV"tRa,"=HaL^1 %(Yg_+2S,NI"=D_J]Wn53\Bge4Ju`H)T5&VI$="Im)t5=b!u!g(,J^dGL"4c7rMITVB(A2!+;6*+hrt0_r":,Vf#8+"1@'fhf/O2[ %W8['h-`>_4L6>N?h(mS(Whue*"KMstD*=gI[6$[0jJ6sl[:UQQ+r?AW"u;QAD?l@)VAhWY)4`8ueF)8]T>77$b+g3=7:aj*CV;\5 %+1!Mb@_oh7HOI35/(%>qeeb+h_--"V?8-%l$99XXB/&X<907hno]eEAM+Ps&(2[^9&q]B>Gklqm8`&(&PX)mbRbLD-fK-!/kEUZa %n['SF-Hb;K;iI=D,KND_V"R^h8*AtH?WPmh=Yid%./?rk'rk, %WZdYW@$^HQ1fq;IKgI>,0$Nt9WJ@L#*F,eIh0&.VdD"GTn1c!g61EVf@lI[iW0[Jgpi^X(r8MprLAp;$AtaBXoht5kdp^C]*0`$N %b8iS1148J[VmGn]AQr%T'lI<(-E^fER/V.q($Hu7ja/$Id(iX.6p':`*1O0k_T2g2"&c2_W0-b2L.K'd5ZNEKElEYuO*=Yo%Wrb6 %:OLZr=,F^s*+su7]h\ZI]>nYj"&Bj>]HpWfT*ClF$@$$@eW'hT6sT!^Y3n_nUl/0PJZF-[)F5-rRY?oc\LF0ImK>W:Tp_j'TkUhE %k/TC%F;QIkg+5XdD:H/EY?=E?AHkugnu1M8W^[X>bkm//`G7BdhVglWUPT8;%LZ'QUPTJ&VApXPUoL*n&>*QtE;N-=/J6l[9KK"4 %3a@)a8b`#$RY&Yu[cLl60>D*d890-H!Y.Eltp$[7hWo3m/R0b^T\' %d%eU)]^,[cA;(H-;p&WYq2\?G=!;p@X,kJ5'L#X@*dhnJ*hZb>Lp>QAq+^e88DF%E,CJK[Z3E>?"+m02je&>5OP<-S=,X+ug<3Z\ %/f8t:`sP#<:Z7AJ_CN-BI3W&EnG7"7-R_fi`_5!F:8Kl^H*IM/.NQgEeQZ1DB^^X=o;o6eYLObl1]HuN[E6WI60)'bI(J67u3>C.)XRGU] %\!:gjiutFj92'7K-067])=%IL1dAh.)oZs1YFGoeO7e7FT+X8"ed^B70#X&$j1jq%C##F8PELc'U`Eqp@j<)t%`u[%(%9DSscYdmM.V:8O+f9.*>TYBkKTV_(o9`%@NA=gD8];PQ^c %@87jb/([-W*cioO.>W05,2%rQhhGgRF$m5p\Mb/\"FPssb$BZIZQpnIdV5AOV'%"A(1pX3:5pH'kuXf;IO5uhQU-oF-Nrs>gA)Kp %ZBk&k6pl?60PatA;:?nq/NttX:[-5(MU/`aK?$cp3eYfbHJLl#>2uqr@Mk*o)+LjB#Yf)^-DI:fKLYk`b$$'ud;]^4W.#g0H\:F; %jH6mj?p8/UP1&WZRV>om7iLVOSrNDIUB@CO*PXl+h#!Jf]bsPNYpRCed9^aGX+,=8@'#Lf3ScXi(f?0;H>[9[fee%2E=e%*[qi]U %[N%_Kh6Ss5lZ$CChUATP-Ki)SR>e@Kn(E51V"a8p/':1<[SVOM;Z)%2SbHIUb1FY:+;]SI'EK?`8FKig\#jNu2Jh+Lp]&O-oT4`o %biG#_GQ'TE4^0.mA?qe0ch]gWpghc5Aj^kd(6n%Wd0OGIKoX%;0B#m62*6NH?c&L4N!k?o7DcInk':B.gDf0`CdJWL[T7DdC:jSmd'01KKlTndgO3Qf"I.=]"gIR?GTpk %"*E^j^Pu:U!7%t2&92Y%PE):$`7Hpi2_-P*K?dc.5-TpXo]J,+Jdg/ng(f]e3E.@RWb+]EJtnD?/[9!V^M%SC:iR1'QXkQHmPp(Y %I_5FRAEUO2^&QogQaU5pYQ7iHAb:$6RK*`:Hjk\4TE84$U(q,,lS]]=cJ%"U#R_)LJMg_#Nqic.E,osjSfaVD&$<,q&Hr?`j)TI^La@BEW*P3$+irYX*YHgkUg?>.?Si_@?-C'R$ODi.0Kf-;^kS' %7DK.jm\rUJa%&'d(W9N+M#Qg/52JVKQH.`caN%M@m`I3`I1C0=YgcicS01Ik`ES/mPcX:><7#iInkJrX!%i/L2*Ni5m1U_3q-oce %ZBAGY1LFjmZ(CA5NH-Ua()%rJA[GD`/W4?C\:F"F]FqE^:1nT`J$]OE`N3fC7,MTYZlce><:tHTlEC.o%'(NtUeuIkh<=d7NKdVC %+si8GXIJp97"`#S?Jm'>CVT!I=tM+K]/?r4eFS\[-hLJD^E@silQU)<8>!oMpc_,c4d//IY#q%M>Dj!W`U*I5i&+>N239$FNi7^%fX%d[A-s<*<]h'J4'?.BmD;Q,6oL.kRn`Un_i0m8O %?SK(24Lh8#Ub3KiF!"XK]Da&r>Vi8*JjW"`3:P.R&T_nCQX7Bc.Q0*YpKW%+r"F-@9';r`WfmfL#Q=8Rjll#\THtFO!"'oM9/*"= %`*H72Q=)rY#h=V^U&Inm.P_As@+s'BlKJHpkXp_ui*Xg;V\"@_e"3We#ZR/k%7))5]l^kCmI:d=:8[uAQJc,i[%BL9c*V]/e,KHG %4o.tkcLQW2!7<16RK)It!0Q.$SWMtX!*q!0+UC@&oS1n92$KWqo&`0J#s^f;c$uPS-#jZME/bJ$+,c`l"X$QL-(;fB(P"T(e0J8% %_fU*#H'Y;^QmQ[M`eS-X%?=gTl5"p8oZ;@@3kK`HSpl1l2/AnE1X=@ %9!l5q88h5kgK7l5dE0\"I'^/c"Y4F)h)U+B1gYIJ.kT[#.nCu&jP3bj/(TXXM#-YC`-XU(J7H:R][BoC[*Xl;b>+9n1H!pLHIjZ/ %W8b+plPK2`4j!Q,-fF%$-)h]n0>Cr_YB,N#'%7 %'V)X)iAj+oX+Pa;.l_NVbkA`Fl_W>;"C6nX\:K[*7sUjE2`soii#Tf!.==/.KE6.;=klP#"$2NVFr>TkZXfDjJ:CL!/k5a\I[)%U %G6%>!M982EHPZN*?Ee63)f,[QBN'b23o1KF^T>(O %\][%NSK3\PDS]]*3?!1Y+<"NCPc->WP.1#[Np(XKFMIUYnnsPnX-Ab+HeY02j[E>Whe1E15q.U0>Bug" %4EsnICZTh"o"],.ho\:o!&K6?n+Q6cj`rcT0\Mi)Q+,20AD_9cc\n.%WFtSd9R"W4)tAM8rJ28qnNu?9rK&e*Sq;d3T$1mMrkM.- %OuT6Dph'mMcUu26!WO\O@!-dn$-Z+W"cR106p>;dr`K*Dn8*5N+i@mo6r`!Ab!\\bIeqn/&BX:W94&7kWi)bDf5/q/hR4JN&QoF5GVX%:AcR9/!bHF %I.jOQ01"b!J8@n;n]*ERLRDF9'7VS)IY(*dH_I)+djKme"a14sl,4[e]V"I4Tqf.k9?gRD4V3Ih0"%?QjNOrN9[YG$70g"_c0F#LUSA1$$d,RqhX2O:`3dnd^CS8BX %Sr1T`&)m=VG=;WpTBn-aXG?F!c34e"N!'i>0;5*lYlVdb63]\Zp&MP17h@h68JKbFJP`'Ggi=)'b6utc%i&r$=Z_#'# %>@Of_:<*hXD2Cn$d)_oT/MYmUm3IFB[a[.>$egbjoY=pf/s#2s4&LcO2iM]"Q!R(/EW8d86--+bEfoRJ%s"KO4H%qtX')*STSH=3lK2M(dWo13]\%"BcrTYCbe`Xh^6HpJ;glbcUmZS1/tr'],!2rhtW %X0I>5YNj*!j(BjfQ0m2O2cq`s4!Z`'OEEsUjZaFL%m'6]carh(q>o=Tem];7=gUq@c)UA_]q"FrRY,B*;5_nbN%6:LT>]!SI,cpN %\mdeo[)'/HZck=L(SC1a]3aj":>:iS]:+;+kbDLcJ$^Pde%>J(6!gV3O'jJ'h:])UOBel,F4e0U;!qO&]/o]F:-N$'4]\0KTG?9` %TCsT9]"NEHjYV\l`iQES`i+]^#,qO$=Y5>:d@]2SmXX:o.a(rHi9/ErpLZ6dNRpe9R'EY0du%@,^?M!3`+'g %R-Wc+::$mN/ZuSu-2?iq06Q%>UKbBCkIr<*0:gXSdQlQpDLD)ETnJ(T,@IW\<'mRd_*c,:p4Y_Er1QHlda&$7a2-urI3[/R'FmUF %_Ls=ue[>\W@D_+cs@L.>jVe-=f'rBGsfVoK/ %0[AFh3,IEZUjbHe0[HP\>jU]`FE9-N?XX0aoXNV_S:Z4bFjl=@Jn6$o(Q'@os(7#_#[9]JFR8>foqkVKcK-T%B=5-M$JcK4O;Kqr %D9S'2H&]&%,J"m+FQJ*!>)1ah&[j7eNMfhRiUt&B_Bu%Qe3Qe=pQ/S8aPd^h=N;hEfE.);5m9n9`"m`3.;*TRFok"$9^;kXG64csBOeh(@rB/g9Fg8LdaO_eL`=J%i]rYH,'?'g_lb" %VA?p.C\0QH[^q/`kGE[aD2dJ.c/DC',N&,Th\YD?p?_M3Uj9;Q]Rt\1Fg#ji=0BoZnfdk?oj`)okDOY$]&%>]CnJ18j7@$>@Ip6l %(4g=OcqCY_rCA94r+pfg-e8)9U66Rpp&*^JOtr0`m8G_bPm#+n!l*ut]=ZCnVP!3.oP^7KC7O'<6CiRG^=3+9kpQ+sapY)=L?LXg %DTeTln5-ihY+[66eSU"#k`!TXaP;F\`/k4rE"`F\SY6NWfk5TI)LTD+Y!ATN*.3o=e[U%s8W(:F<\8r"2/+BfNQuLpdgC`Q7D'+1 %hp-Mh_[;#KlKIusJ[/0u4^bgU<0![YZG*5)\">GFL=W$?*l4r$%3M(3+?GI1/iLIOE0F=)'!+qnAn5#--!54n@CTtqHYNb92ELb6 %d*bkF7loQR.pr$8gZSu,:.d\6f0F622[^+N+6]C*L^&g:Lu?R*&WcLRecFH=U%Q:&brAV^.L!#2l6C,SqDV8THXej %DVBSa'-A"gaL#K*[>D:n@nlC4:M"4a<7&IIVWl,u7ckl=DGTa,Ub[^2/;Bd`8/p+UEbG@C#e^eVhQ/k'_5,P`'`*U.*@)oL)F,@% %l)h:!FmZmm%7b:?6bL8=5GF(P:hf89mA;5Dj1`s#Y1D$*Hef>,`@`>DFJ:r+9(]JNOqMP3Z4`.uDqT#&2JK&9ZV>ETMDTr9fd>!h %82KY'Rg)6U?PZiSn[_?&WXdhnL;`?/9EmjM"Aduf,c:4#_.Run5f>bZl5'/Nmu_kSl6EUK](?Y=:TlpTDm*Y9:L$c%MM*TLK;#m' %B?9'fKT6e8c]H+WW-T.LI"kTQ6cWjJ3:=k8L+FrE9K=?g)7$a\"d.;IaPnsCG9rs/OMtde]*WY\V2*BYct2uce,,TW&E`bTa26us %S'ITDW\,."C8=!M\G&Ye&qS@_\BFC#a1?=\hc1ogW=c$-O=CUW)Bd`L--$^&h@Iq2c4\ %POd?sM>f+p60(C*oQSY5o"gKP')c*j8;hI2-2MZq9pZb;.FGo.##Ad9X*1jL6>'f;"80@O@DU?\NW'6=6"\$iA?DOUmB^6]KCph, %UR^cLP7k.&:g#6e6/?t5E"&1W]6'4RhdRK.#3Fmha2B_[kC_(lWQhp)1@-&S(>E90Q8;&N5.F!V="_IuOGr6-r1*^!DMY+R#WsZNl>K)$I_`E2bQ91C/LKYei(<1C/LKkUFN/bTHmtQr=*;WrqV-$^lPqdsV:."p$EqWVH8Xc(/]#9+!J%@k&1=2Rtm^Xd5Y,%%,HV4ni*A %)$I_`Ug@2d)$I_`p4Ol_!18?#pXtWG"MbFJ/K'ZgMjBdmnclTbX.u!9.D9Y?PXYTK0YCqYj893-c3ON$?sai(CIMT@7TJi"fo[-T %P>h>W(d0VVS3QR=H%1kTQiZYe0f"CDLi1!:]K9jP1MXVQo4+X(iFkYXA-RUJJaOI9pn+II1&Cc0i.%=j#2T0Xa:*[.%2c+(a:*ZL %(@Jjg5\<,E"7$/;=)Ymnp]LQb#hi>F!6;U,`6-gV^rgn_`7CDNOgU,"(qtEUX<5u*pg41:%WTK-UZ'Q2Jf"ha_pRHfHd2Rm4+Ih>0siU#fLNYfiTBM8sd0cG(BNP<(0 %/csH*fA&G6DJp\`'F%$Z:g(#11sh$CfH=8oakSThmO;b\0cH'U(B-o3(_)72(;s$')NKgels,6pd;ZJ%0_'ZX7`3X1'#[U#)W&(5 %4>@b7p(gh?L`9T4KaHDg!Y9ZDN!?9q;NnGb+l'cqruYCi=kG("UJNA0sUcWtbVG@,1Y%#*@lA %,!,)B'RqW?:7'>:GHX7#XX&%cG! %.CfKlOSZ*$_EW]kJfb#U&-#I.5X5b#5D4)qndj,nnKf82c6Kt=Fl7l]CDP02eH)M7gFSfDHtmHIl01E@bbCLIWg7'0at0"7We:5lY\);,.d-YZ'U/V3ui" %98T^A2L;'(=\Ose0]_'+OP94Y3M5kuDI?!\$AX'*qL5d>K^`&Ufc'dR6"GM!h-4_;Ra2?MM>P@;d76n(#h8dBkT^m6SmG-($?JH[ %q?!k_!l`1qDjK&TeW(pHaX]XcfkQAo)c"NIf5ImKn"/C.ILZ*1p0>>XpY;u"5g4)T\)1U1]qcJGFe6!GVkF4-6NT4]_MX'Gih.A#2&]5]FmerD`XlnBqe/Sfo1K)Kb]?fhcDrm[: %H%,M9I*42+EV$8nrI+[rmS2$%XliD-Y+F@tcf8[anbdD1ZMcitXmG0odC8BH]$Z!9R<=+NfBBA*(ZI?!CopI_jVmi$[#q\kG#Gs5 %XH4ct-r>Mk!1:-W'u1mDTeG"C`pe#&c$q`%RS^S#^) %*Pi?#eeFm"!=._rB]OlL8Ca@!A2sDs*7nUXS.ZTV/\,uNJC95`51l%^f0BkrFUIRaeds*W@m*iYh.0BH5Af.oo%:P %.E^>q5FqS1'%Ic(FSetj&nu3Q@)W6Ff1f.p,A=?-L*J:dEO9ZH)D?&PZ9q;K)eKIY(m9WAH2[g,hEpPSABuE2_5gu%3,lp<,jMk/:&"-jWn\[0$'dlpAsK*RqQ(LPo];'fNJm4.APD)S[R5C8%@SoF++5-Bl`TAV_8h'c5r=lrA&iq]D&07?W6fF)U)D=h,Y[3VS-8aI^J* %Et9-"$U`"&4&*Lh=r9TGghFVHpc6bcDpCMI@ps@CbYAgpgq!'GSmV>V6tq>tS+*c4YMiGblQhjO'`,`` %9.=Hr"jGqZ;MnUJ$)/cC]#U;&kVteKP>[?+.XPXfNAK8UZ6u72-:+H"bH`s5/uQZ?Jp%eg08gcE%.0o=2T]ZSYF[5$5sl[I;DZf0 %!EB4;#GA2$"uoQX;Vc/h+4hmrS&49`@?8MDN(XF]8pe)BrH<\Y=Nq:cJ_m:Aanj3PP%Y'* %!nW`;"'JH[;iG5j*68a\WfaB5"'K^+()!qoog"hS5K;5i='KHiCSc.?ni&JNit^_8%kr%M)X6P<]MlYX=<]Zi-)?q.=b/96<$Pfk+qrSHR+F4Me %"[&O6=Hqqg>pP>'q`QXT'pWA\=e?'9>DTE.VE%2`'`kQSY]E56XpBic!(OH@3JYF!Nakr?flnBoi]%^MSJScOW:+YMMJhP@lS+K< %aP/b.r;ISiZ_,Dt35#F<:=k!CF&6M0C0jQ.gG#l5D6a]4l!!YJ2U_<>I-6J!*Lm!E/jY2WJ3#\%>f%F3Tol+OBF3<7#m?Tf6;&I" %U;J9TOk$k)1+?I[$8$h3A=H#'(N.=kTL-P>-qbdUG7dYn.=J:B?=Q@LIgJ!L$9a[f9,<+s#\-4_OC#P+W7$^jZ]53O^:'ob3X2I= %?eVc4'Dj(1gZ>(H%pih22M,m#%kh=^Vcjd:h*OMh+BA^Z?Zl[D>n3II$Oq1$Fuc3Po<;HpgZ;feQ"E94QsC17f`FS`;`00rY/2C# %*4&pGT19A\QlnPA!f:?Gfe02o`YY,B=R:'QqIu(#NnH$4L]iGmB"OQs^[Gs*A%'RSZbP-Ha)%)@B13URk*YOV0Is`]0ZS!r6],fe %@IF$)p/@t%Mof"p^T#`H;l:VZY/%,$Io;m++o+FeN77jI>P_2So;%rUc-n]!e1iVbRP-)#N_r9:J3L-8Mt<(]&lVH[-5V>m9r\HidH$ %<_G%TZ+l7Gm"=r:,YN1H+IO]\&1Io!'S00o7$GQ?;m:2>_%&ZYT",Fm"c2/HqXJ*=e)ma9OESm.G/^#ZX1(dl3lX3BDqQXr]\ %[:V;TBHG+mBDO`f@gKA\^%5O3Q*CbD=a37Ab]E3t&LUl=T]VkRh;X)-EDhZRmNn!:`+qH"T/I<:ha^Wi7O:lN!e,Jck6bZ@i4")--"=*Zdlfg[ %6,Xbr7EhGhRh2`Y;0tm;iOMkY-aFoA?I,f'7*NbsC9k2o9'a`gY44efYI/Use9ZH;M:c*6IOB`uB83b@4:]BRs0hT`oH>)qY^r^u %9WuJ7S7W4^BcV\q)=I$?43`d*Xic/X1GptB`+d4hG+cT:kVVo&RJiQKf8bGB^EJsc_Woq^8,G09@1qM8KuO)#l^+jNhkjAWV#>>s %Ig;A%$Gc["9+3U\d'T9jhrC0BC,am/?+':=G>V4\:f3\/8]@_38>MjWA6L+hL@@TS@Coh>Ip,J)jBcFNOjTkoRQtSQO!XSC6u#V: %FgQhPTG#g]fVi+9(MP\8jX=rl]haa*['O"jh=gT/;EJ4=TYL3JH/U]fj*@1'$`3*M<()H8B.mS>rKGUc:bF9=Ep50R\q-q/+:@8X %Q$'$m8\1e%>a2)NQ)&2!+P`-%YE/f'_I(ub?M/=/XV?7:QIEaZX7Uf1/^dKnV8&j5JK@Col4Mj4#:djiLopbM8CO5C4'mYL.S.uN %5Td"Jd$-T+%s(X`^=nc\@Ut.UFQI]:VZZ\:\tTaHl$=`A!n>je8_6N1?'qJ3P,&IgF6Vj$-Ym";dos;H2>a8%E/e#k34Z(c4r@,D,4lIVu+oP?7Z#UPDh'U%pabMe.%Yu"[4^O+##:IPQ4Hd2G]q_:n$k#:CO)o/`8hU %=MSaAcYWT*\B>O"ba&F=9,5R:I_joSL@,k,?oCfQ)=Ad@!jd1KbV[T[+#'1^cV+m1K%W9JbT*mI"jH]=>rtU/;q'm-T)-);RnXZ+ %&M,c,0m@8<=2D()'<""QXB!HjH!b5?A+%Y#A/:g:%%lqr]#GMTba?!uE522@B?7Y?Mm1YC'Df+!Uqa#"ATp:hsS_[@W)d&B24s;q7KoTU*_D@\X0c:!T3tYJ4ifG!#Uu!E!-.A!!(i?X9\fA %<75Pji!'/mr"&kjAa1m\0!nXAGI@<,-K_D[hOYplT1:hl(l9WChB;^f&,b=[8F65#4gLBd\Ve>JgE2R1c,4lR[bb8@D^Y%HCER-C %![[0!qNZ%ScU4D@14QNDLgHW?eh1EEn.0LS$j$>bUlee7"RmD2ipA#h/B$-s(+K#m=*f8[4e]3CV(gb);RHkC3p(msT/p`R(4L"3 %]k]-%'CkI(4[lGmNA\_H%L9a]n%GdIVA=Z,D5)[*[29k5kF1M)3YVT%=PE"Crr@9f^+YfbHnNuKI+7<5$ %@_e[[oj%m,adOLu;Ukp.LZ/l\"+6l9@\oV$Eh^''u9cj,> %M6q]SOF[Ng^X$E\aPT[I.Tju:eSX_f4scD)njmJrYGUjNOYM(Pm?ft-5J.b)W4%X*e@+.+/CX]Q6[q].#uYRk2;('i8`TfQ%'Oj1 %fNJ2Bd(g5]YD\SOVL8XNIN?b[(-4+=)%)b(TL:l24`t:3gJqY::`sKJl.hl$eYNfDY%?>qZUO&k78'UOU0%YcFT#+ASP-'UH=clj %0)B[q$5.k21PeoaPafE/d"h0QS`(,\Qp="Wj)$e#[q?MHB_c#Y`2hqNMB(@mD5)/m087,G?33I7liQs&;AT9oUlT>BY$AhcD+JUD %7agqs'7=`f='dhj8J#&p=nG6IPOQ?5C3)#K4AH>M]-uL"Ms@A)(J)D %.4XuLZgui!93Y"NY@d1,XYS[sD9t:1YXmp4JmcEoif&HuHph%)gHJ/;\#lsH"Y*WZ7)@G`;8D^&RaU$T;i3R@<_Y.V&^QGLW75Hk %Lj3h0K(#lppHC='Rm%)nS1:5l\Zr6dX)V(j`qPf(?qWQ`]NkWRg57.SdG[\X8_ehjZIkjVZN%piejXL,F!c\a1H" %RuM1\5aGTdb#QCR9[lAgB`'?fo$"&Gfjp %#"/Oi+_WSj&IB+mLYf#$SW4$f<+6PC4K@rMV/AADFGnbZh"P@BV6g"q)JG_;`^cZOF[KmuK1CNOEe(dMnnM1i`hD6J3rQo;2?$GN %9;jjgm+H9qXGH7(mu.=bZeGZP-*1gV\K"p&8(qFY,j>2'L[21k!+eHlJlf1Oa1*\WNW&F8[[ENX)WSMLFG!iXI@+3s3Bp)F6&+7> %_mBp"pr%`dg316logfa%lG(Vf?+l"/HFE]op8Kd:/otFU=^jYS%G=n1IhC]nrG[+sWqVYb??\Lg=uYUZ`a`r(Z,2/^l\9/%q^J^* %f%57hD"C0fUig00\!^r`'8X"\U6mpXe8J,ZKJCA;!fHba>-I0'Ld5%5%`.3;cU/mSD@VY#T0P5_4SZkm15H^-^rH]G")5E1*6aV^ %Xj^8-m%ToG!\^kZ4I+YX'tPnUcVqAK;aK:+U3Wc)H*%](n*E[frks1"4$L_IPrVNR7BDN@o)7#$;sA[SpOfL'BsnlWaF<3u/'9jK %G5H<rcOsK^1mpFiNSZr3/4I[n?JNki!$0e1-LX)4\+1j6&JnohG5".PH!uc<[_>Y]eaKTA*2` %WW*L?B";gV/Q"Bp),s26Et^o[_cD"0c%70l/KebdhekVBft$NPmshfCrVjB`pEil:0\i*NofS:MThhTZO&U^K!`;#G:F$isAKoNN %ZqhaBK\L2M3G.V`G_[b#5;=tlN!qcn\EsP_:8;:nASTg6F#pFQ2QaDTigW\iD7muPGSdu>5^o(d`$(]&IuE&Z>;E&(8r9H-q+\3R#Y`tgUcgT;?V/pNlWqZ4kJp78 %H894'T%\V"PVtR'rGECMOc-1q:0&(2R=uSg[CQd+YT3N5A#d#Lilgu-.lHMGk0<3T9`99=EZQu[46af:B?&eBP*BSDE<*Gp*Cm#A %5$O-ALi0mVIH?NULHT`,7sZknQEg(bWj?LV.Co!\ha7Ek=&=tJ,lkOLY11BcSch2_WtL,oELAR&@^L2?`LY^KP(,AT3-hA*&!m$RB@H<5^^heV6#]7M#/QQpP=?(q-A+:F:.G6KHF//Fo3]7LBUS-9b:G9r'@NI$oI'g+"70H)V?H>6V& %qErQeIL-%MiTO!%bo[!V__H!3[.t7e)NJM^_kF)C2/+"bHm.Z&l%j/!lLZI#Pbm&#S3!VU4cs$URf"9;N*W#B2b+no:%MOj[np`h %=\ZPmRae\4b\AnsRaM_MK*8NXJR.S8p84D!j\?//I"cSD %T+(mKE<0-F(&cPX-Qcb!PQ7unO#O^f2uD5=6sMJ1h!'m+QF_VfB(53kgb:J\L>3(&1,AV.(dnWr3kDT@C"O[VcfCC`)q %Z0&+ZlOU_"@06-`4^?`Y9"j8W/gb8)47'DN7*GNkXRWp%kJqgAk@];Q=rLa)#Ioj%:=(Eg2@1:>r!Z,*j\*s>j(G5tE(K:1_rG),1FOdoadH4QG %&BtuA!@DLnRZ*M]A?f;NF:re*N>uYd71Yqu5=JB"SO(dciG9+LhPj.?VT3Kb8TtAgW!a8Z_ocVDZd4sA>"Jh$UK0F'1)c] %1P+03RfN6H)18tl.flk5:,iN0k^"]/jOef>l]of'VH/,4arn7XcPgPNT`q@EagUKo!FBVdh-'q;L,@k"(B,.9#6YV3@H]Fr8%GoF %4&C[-+\b;M>C\3!M)'_pV+oO`K6s"D\077%; %a6sJ]:-Yr+_pU!U$3&d;XhW1U:@S"L+XPEdS7%k.p[hTi]'1-Pg.%;jlU:uIc_%%+T.S;/Hd?r8BQNaVMH3CBol,lhDtTf'9?jWe %='Lkt1R"2^R@X%8Pk"Xq9sM;u;c-RI^U=e=49h^s4ptkiKQ1TFNSl.c1d:>FDbNU#mdW,sXo$,pb';[Xj$O?bQ-T0umA5rW4Bj_M %"jqV=>b-pl5Db5EZSE4'/,IS_BBmI,f3I@^f5XLaJ!\RZd73/iPDgc*omM:)f16HeqaQT3'l/nqBAjB7,]5nGSluM'j+T@tAl$RR %^Ta`7&tE97fJa]7i<#8?CnRUTUgXbTH"Knc4NjJ^Gue[Sa87GHO#Kt#KN+:JZhlfcOX@:B]F]oV4HUOoHOj2VWhXoL %)hLq_#pM[kat1u6\l]fEb:M'qhpPf-E>3*i8ZWn"R_#7bP,7IfdY^8Dg$Dbo.7/5s-+^FKKR,\:CFaYD_"+F"3)@cYW8%,\Z27gZ %%sYJFdokO!Tu+NM#KV,C>]?oCM(9+Rbu&*s[kRCrbj.][`Y[kdP%MItpaQ3(_05&P'B4dDA/U'6J1]"U%YH?&-(%H`qTOl`tSat#K3a:&GDXs\ImWL+$CuqY"?EbJupD`bBpKdSa %.D*e;]a`Fp]iH-f>m?ku`AB]dQ`%U.nK*j4Pqqc&c+Q*M2l2YQ3-M4TH;ib6i7jfClV0ZPN1`7DR3?Y'FT)Xk:7("6l228::]^]4 %]%5tDC=N'n.UE^#2F/TgD1OP`>)jc_XcCUd^);Somf7e %/>&KtZGXeI+o1Jp*;FK#G,EFmh3F]0ltlK_U&"%KQ^n\^cd$XcWGL=.I!2C1:([APG1N0e0'!f95!(j>JHVe%U)\-p>iB=dI%WIZaNG#Zpd*'-=LmV"RD40sj?3[2H2fpOHSn;r=bZSOZpJf(**cE-H)>\fop44@c=q(7#BG'D9i %s%NplSJ[OX5,EpN-.KtNZIR6OTjUJK2*9mO>_)!1W(=E%PnGGi*!X9RCFi^9SC&,\'a]YHE-_RVBLoYC-ejq7&e6.Q^i:/?&e:ZJ %%-m1A$j#0JHVMhZ-*!=YD)QqfBF34u[p)J3e'HF:2)).prYCkpeL=Ln+m=FTCl)uBB+U\"lNi_LN`p`f!-_;XG+67DC=k/AqKU!H %\q]TY?U4Gu(t;%=_JdU-(Rr[Km-q6Ica-$cEC@:r_0]=(`:@)->ZOlD\\c0)F?0B@^QCg+l=WUZMQ=n4AZsQM+7I06=Xe5&Y[n@A %@YP?]iTOserKKj1W6C0'#*<['YW+HU3-0.E1[CRQ9.C#\rW=822d1/c=`dlm_R`K$2%^(]D=dh?27L5U*\JNsCAf@A43QmMqT8$V %Dcj*f>4VT,7GmDmhgG9[QC7_"BW#BZ)S;H:\Z'g,D"0M5?lqY#B7>!p?eaet#PNJ&OaYThfoZg$fEYAS2M'Nd5]!ci\\hht!-s`D %';'u,i5jsdM1'nTrW'L6[-Rm>009%S4SF@"XRnRk#PN^73HN^EI+\b'\f`i)5osB#p[ma1pe:Nq9>?r3Iq!.Nk&.5FVI"*Ig6/g^ %CWs@uMi8qn"+nT6)/I$i#I%jJn"3q_FD]o/PT_l*TL:/o77LGLq\2i%Z:2bGaF_Br&e>Y9kttu\Dt6u?_OSPU:OJTAN7G6=(abmBDe2#8;c8BjJ)+8j#D?bI7,D1d_`=:WV^)9=s.;n9.pBFWu4,Q]d %Ws#)1I2@neAp"S_ID/aB,TFlSZIEV?@Fp_der)c5cVtZ$r/:ETV/O!l5h>R9Bk\pic\24KcK4>tIL3fi>A0ZoeSf:iqG.FdIY.om %eagp&Y6,4b5ED!No#^Xr:\On/kKN\:,0.q%\[c1plG9G;F(me%=ZtG&?2puII3)NclhNDtj0Tk#4_p=RF2\W3K27Gt=1pPQ6`!U7 %c"9j_Xcg#[bs#'i"=g*_9)"5!2f>m28B(42n[%DdNHp(InlA9Gr2soN#TI,oqJnTIPY@s.Y."6XqXIGbi_-^^Go(p)1DZUN+>V!= %W][c&VrNr)BH9#k;)JFMbh+_*QdUqiX/[.dYAIJ":i5T\KGL7l(2FiUq4dDZa5*i&;O"0ulc)fN!8Z.i:&T111s2l$oW\*76gk+W %n:.5X9Jt)T$Ee8.;W94TnH9umr_&uE5*JYP?o%t^5n;8D+rrMfc#B%kR+C>Anu%+1?b@q%XtL9a,jj^dqf;Qs]qr,Kln:#*@g7@8 %)`'0$k0]XVfU0KjZ?pAA@q,`A'n7dBELD-oRF.qDlM/ZH(u3MmP;31%A9,SVE[ut-EoQ*aEtAU$<*S+l8+bp0=a1IJ#a)a6-!E6E=j:88=ZIHt;eeU?@',%-NKP)$9A, %AN/')d^81^T#(@l&ZP%;W+u>H/NkIK]okga#4+>RSP5aC3=2E9;RQ7`8c&>IkQ=hAF*U:^CB(A?*[:V(I@Ddpr"kiLc85L>a$3)_ %T#5lHdQ^7jSqAP]eiu[nSm.TU9+rTS&*T7I5!tSJ^F17\5#\3;FAn4U%nDNp&Ua3glrjXd"X3 %6/(O+M-&"95Nl6jP#q/ZG?85l.@r+[UEq09:g;$Z?B.*,kEeB=6V;h5hTKr:N1&Da@;2QjcPFU+K$lV1oVM(DD1lHPEXHD%)H+>A %cM5TnTd.,h:Cnu@s%I:B;?4EFMEJu[e&cd0rd<2$3FB_);')-'Eg;h %bK3'.9gPH4NlUI.6PAkX"i_R;WHDs %qFaq*hPHj0V&!CkOK)YI25WLj;D>lS*Mgi9Jj;+@*5$Gqf4666JN!`5f?%:0;f::o?";CLLRs)?E:6OR>%)*p%ljeZ&D];O]I=+i %O,nfp^d:>[j!k2.+M]?_cU$KkA2LKA-ddp7P/0#7&(-@I"[V&1?-IP%TcaX/s2:=WTTWNL*!G+4"Lqh$3=*8H#T?KqJ:Pm26%Dai %N.;p]THHM>&.?aON.QT*M[Kc@2[*V%ELICA6.M5q%K^PUJfqXE&/J+ShNfBc'SQ9XC]VU<&-YAE)K9^.GZ,0$>\Yf("JE6$bt:M< %h>0+D.0p\I'N6*o?P_!g8jOm3g-,r6E@6OaARH!H:_6=s**XN*^P`b9;ODo+!9`olki43faJJ.]"Jd/*B4RTd^mfp@R`!<<6#^+< %kk]6$'EgPu1<2[gm`@F:#abfYa$JWX5mYP3TVN^g^G*Oa\\1_VOK*B+=W/L/fB5Jp#X3(VY"e)gpa %@]@\C0oMT_^e>!YiC.oNFp`hbfqi^#GZ,/-95T]A&D&?:7r]IOiD;*kW$r">UH$:[TVio'd@\L74F96+MRu[rTMD*A+r4+IU/.lHHTh?Rm.'m"&DrkHKtKVL#%%1$mb3p#nuUTkXIM1UhH&7)gSNbEGAZhkWBQHl"e1N' %Bq'9M+(mR(bl4$GK-KiegDlmk58Y=SqWV0B[P'T)?aXlJlMQ+uL?MNV2PY5fVkl,Z<3S(&RD)YP[eauld_.)7?5i^HH2=(C3%kg'o!m:@8qOklSi&Eo`;W?j>+dCF7C.6!"B)#\^[7"*KkWP9g="!8[U>'F?q[pSp=0P0gOZ]';iM&O]Sq %+&nJ:FAhW9VD&4#Z:!5\bj57(950pObFZSjfs1*#N7#J5RS$OCQJgp=g0>73.p4k/n*0/5$KkQVTF,hI?\W_n?R0r`UkNLMKuUH$[;"?&:'0 %/bS*ZGR.t'ZOme$:*[<(V]%3`,p#$PhB$ug#Bd^7@t/cT)Dc]i7if!)eX1pdYs;/J=qT0_t>gD4bAb-?cUU`qfXZE2EZGAX^Ya@#2ZC-n/=Ld!c"CXh;/6lR4/QCtd %KaW9;]VJ184cG8&c@Jh3Yq7NkU2q'dPqE(X7$Q+'(T2k`9:*\s:o'"T^P!LXWhqS*-s^X7n8Q96iNIna?/0XN64"H^g@DqI%67[X %a?@Ta0)G%e01WRYDT5l6p_W64oDCc7%8'n4H:dP22$84]'-DQ(6\Qd %^0H`Jh0%sXdeYE<;HY7QE`KX`kniL@cZ[E=DgK4j$s2Ii"9QaY>t*!1rFuf)MS=#Nc!Og<8!c^Xa6sK0mFaW2Q*/`qs'oK\n'u:Y]XtM)"UJGDQ\(Fl8EZQXgb/aHb4h(OI#2! %8_o]-\C.RIPGd#?s*<&I8=Hm.4QkiE2\QXPjFrcBal#:>^j2WLF#%J38C5"GdQ&2TP(VqOP0V2-kC2@%:sq?AHmK$C$RM@-JJm>& %H(h$T1?aS=O;CMM-R4EuH(h$T15=sA:gPR7S.)ul)=g,-:]XXt+`)&X&%;k?mD=S4KYcgtT]q;ROh#=W".ID_<8c>:qbH[^50^F*kii' %n#q%Jm63C^Y9)X%?,Ka-8??kl+m@RobQp.T[7A8,c*P344DV2.\dhoAkZs_sB#F4&&ukh&41hWE*fMTsp7KOXM`\-<`aRkL`H]C: %N45XibdON%TC?n?l)>@p(S%kV9@R2t$Kfl`p#n#CY+1qKVaJLoU;F&6VO.V#!arD$k.? %-f(c'Au+juh@d(W_^N!/UAa5Rc\u,#hS[jFf+b14[/B!@%taV*`W.1VQY@B>demU&U/4!CJA=C(LOa^6M1@Pf!gj!lPNP-M\V:d( %8./uaAPT&3q>04l:52t]5,33+P %TYJ>i7EAi3RI#%('HqsgVG9>r_h<*#:EHOj*0?ZH+.]'c\m@_tDf(]a-ldeaV9D<'S`G*]md',2o[B!b^\ %mF#.g%HWC3"OQK=a[o %0K5"?2qT2[b@bJ!lr97gf4TkR-:`\\&4://3>tkMN]T^pRil0>GK?Fp]I!kY==",nX%npGaImFa^E5),HNBt2';ujcj>fRMDbrAV %q`]9tHpHL;XjK4+M%?O(3f.ChYUlGbfX7RjN<)<#Tlf23@u%/'BdUKGS_H7)TBO"K`s[cS#X@m7sDYHqhGFQ\B@?U3h=fJq)$Z7%Jkb6f!Oklb^,d<"[(@sV^CS7a6oc"4V'.LWFMf6c*qt2!GMLoN*MYmQfj#Wese3I0lY>]69J:Y!XAYh4'\NqAY8-lT>KE6d/`40<16F>b>g$Qg_ %UVHVJ@+l-b?cctH,d8Aj:.Q]6U9"6sGpWtoq]W!9_JP.gL)BX%fNVfG(I`+rC"($pTPeo017/)>CN%=1KsMNop6P!N'bhg@)U,J]eeXmMr\A[jIIF!oXhJJfA?,K+*k?b'3g""S(?R%a?,rfBL)#Q6/DpdShh/C*B]If %EZ>#*7Eih7+e7a?#P&A9#pD\Q"`UHGpZ;V+^H9J+Fda$rH#sYBE0T??jP?C3oW]P-0%U-o5"*rbfe-qmV@5qg\K$0Z/-%nP$RB:+ %Zr>B?cmR3bm;]sq*Gq.dV8m^(oqXl@Bln)m5#[t;BQn-tA?lPHTcT]c)`"?82ctRgkDMB#eHZn"5$jGZ/+WAf.'M-\j3&FPh:()D %`ZK8?>=F8OWTV<,9oa'+ZSXtPcF0!(!Y9ZHf4\=_AuF*YU.VPKXc7#U%i5b-06'+n)($C+\#o/Q%g*>ncFM'a7cu(&49T)m/0c2; %2ZNsmn.>!Vn.=5eW0&LF_aE)T@q"=>YVah@DkZ,5E+_ZP6cMK$dA0LhKnkEhfRKU56f:!IeX#1R+YXm&&@p^B.d1:t)S+fMLd*U@ %49WBo@"LI>49YUf;@kqnDX(WtkkKF3>:2*G_I,cbMMK!T*7!IP'+^eu-&%;5i1?:rXV%\cGUReBgsj.t9UL&1S)+Yb%tQB.Fla,G %%tW[NHC`7d%ro.B=/+U07qc>fMO?DR+GPi1^i0RC"4%PinX<$DcSH\Xbt<_m!L %hE0Z5kjH(P]Q`G$1D]GMm^Vjd>C=)->0"dZd!0p+O:jM-GN!i99Kijp#RJP!8!dI#e9_FaO0fe01usQ6oZ>s41e34g9OefOQ;>nq %8VASJnp5*]OQ+_Zs'/c]VjU3M6C7,bb)A])8Q^f;qDW3^b^03?=pAWD*o;>58A4&k\::DJBlk']bdl@GU3!OjV74`j`UpD0\S]'& %TJc:?&T4-dZg-S9]'?`U0!OcP'6TaGGMpS(9lQ(h`%)!"Vc*ro;Nkuq,^PFX<$AnP`aN79`LDKIa,58Mj+K\eeo(C/g/4XlGkJ/=4@ %0eKQb4*+++6H^MEhEfI33%]d4Hfrq)kNfhQRB^5mhGjfA8@T+kKY,ud6Q3M!42"'ln*[*^;r7I&e^B:o/fbi(!mX`T.6:smiAOKn %VW]i`,fb0[2arMI5+SQ$Y*J5JB2FTZSYpL,FFqS\T#sdT3U#.T4h&toerH5o;g7/&1u3doT#sdTq=%g_KG90B>kEmKBt=OI:$8_D %"HcR14[,?29i"Fe9VhoaVfKLM:J?L8D[.kMgnq'X8RW\3<5V[MEe[3\S*a!!bKs"Yi(8g2:/e.&U-.Vi %P["6k@u4dlm7fiXA?^LbQ:)5=e((i%_arU#pc%DE*@%#IqW0q1KjNA098S,DNot&R/e?@P5?[D4TV7Z;X6ssP]lePLG4&pF)g$*$ %.CG)*d`h`jaO_6N%aoe28@YdN8W`6rK[*l\Tt42n[lYYKkN1OdTbB.oV71?7,m$&\?B#WX0`nopTef#d`sClae4JTdG`:s,55]Tf %=Ae!2!]K7-=&Rs2>*jlN2Eeh2=^)(ITHY5FJu9IY!#7B+*D`Q:%8[WJ"cYOVhucp]j&>1.q\%][nCn,oTA\"Mhl_#k]EmrT*AU]F %]+@7!cmp1(*],b#A.f4f&E!@;ek]6[2IF4V.io5orM=BnIWUK,Rr[DMSX7Xe7qnX`2E*hrNh'`d_shSBW;_apM)ffAlJPLB_,%hM %"@CH5`/;;dS&5AihOB+QStP0Im%rm_(3brQ``*ie!T>IL"K-F9g:o#+mLmJ-H>]SuL+/T7JG^.l/UeYj`k,)C`3_\b`7Gim#3_q0 %6['iH[n>U>5=qmm^rP$01:W>S$rZ"Fd)fJ,/4b'1'UT6gDU0n&=0T'"Ql@1!%:X]>39oRtSiTilHtp>?<0),6QTM0YZ;?S>ZXI[! %>c9dn[,em^5IFr]KE`4g/+`/A)Hb?i8e[IjHl?*68($K8?uB@4o>GKYE"AL%brp?\iB[Wp\H>nM):R"#o1_,(\i]-%o8%;)_n"<`,J#=llh#.5\#I1ik$[\jWTV31NlV5tPKVn.*/]))`rPF,a!c$JjL/:-mc/PgG$ %WHoRSOpu[UAt!J=Aj)mmkB#=Y&@GIRNl((snr'(P5T4NIG!"G+Gs*pVQ:A>l@KY=u+3'aRJkmpO*Sjl#p6R_V$,r-gr];d)G"BfK %T9j/c('_\tu>M@,ki<+gJdD%ZH#n=M#415!=-f33c=?VCE[^GIDpZ_cba\U$d.D@\2]=Sk( %FD?;C,Dka`,P7Vu3@]+UWQ=AY8f:C0gj]$tA^n2d6o"qROfQQuC%jZ.;UkW[fb1Y0[K[Ic^+o0&M9-X2%5g>L2;,Wq.k4!_7s,hq7V@jK1P=Q_ZFsOK0SR?r[fam_!:R= %a*TO;@'a. %J)rW#?.Y$3+`)LN&bV^VoQ'n@FmV+= %X(MA,H"j.Q808_+dT_d9rQ9'?:]hpcC"$o^?<1GEjJ)H2HMLT+%deR'Ka%3ah]aoDNuR;t[%Nu`;(nbAXP#Kp#ehlZpF^OR$qa`,nOWNq=fNE4f %+C$uYc5kD_V)6>qXn8jm,(fr2JNrsk<0Z/#K6[gBeSRfKHpp*Q'F;GiB*$[O29lYBkLl5"cT]YX-F^u'>0!",G%?RM>UT,0fm.u?2A^XoTB8R`d?kfUrGF`%^5o:&7).c9QGhJ/EE<<$=d3%ncg-Kg]"h9m]!eiRCY\T?$+k>(_D5o4:VQO)OdA?-VBBhfi&oFX$IASXF %@aqBgoU3;S\KA!-%P'TM?U?X)@7>rPId0mc,oEh)P\G%s/S>JC8olDqJ'eDCh==$#Br[hkNe6Y@ulF[!,0gs`A(mG6BInh;=OBG/mE!^KEjZIqH=()%L,-jGG4EPu %BleWhQ://nl1+.VesgM6+,q5AL!J'()-T-'p4"Ii.JMTKFmPcPV0CX>LmB)CnO`PM;(.F`>0dm9*pV5BIb$#+QR'!5MW]/3b]hl& %g:kmTDSOM!dgso3L"Ss%q_4W3;0*@.kX6,pU#p!^GRFtU@qD-dU7@&)SLXW0+#ko9-kQA9[ssB0,%rso3PI2&\25jD..&o_Zd%FD %1K#@n$Q8F_nXr/B1EZg_%gBhB!/FQ+LM0R5L"uiRH_:%ukCnNW<-3)=n^)CW %M@So^DC>cd70b=O%o)5jkZiHMgcuI_U-iRcMl-)IF93gakHF(l.uf=]o2g$1_=GrpreaG^3KAf=.QYXCj.Y`8'cf9FH"]6g70hX- %*h(A]d:'49#>OBbk[6o#F&^a?9)A-1PCD350AXTQI:u.;[[LiDbf<'Cb%!>gTnZta"9tn%in6$XTh6l'G'-S0*9NbO)2>:KcEgp[ %]:p9!mBH0QSIK(PW!:8KU[!I&Cm`uL"Q(hm(T(ILH-_5i@G45>%6[oL>YI69J_):do$)KdPC>'sE6#=QeJB"__O2uhUKmFDZ`3-. %[=XW&Q5!+g4-D5JMUAGfEAXn[q3-[QjG3b$DZ4t,_-MnI;?ON%#SFLEpKIEZ,:uR6UC6U?99(;SRCTKS::UZh`sth1DEB_dHeD@ %ELG="h*]&@`$H^5@aUh%N`MOoP.8_Q(Hms4N$L$>g9.\t_ardm:ttNS-1<+^ke2W&%_V>I8R-UUeU?ftE'NPbQlRiELt[m?Yn3). %Y)GA(FZ^.W't>T13BkD\SN.Zn&sla>0r^rP8R,j;(O@_e8R)i"OC1iC$;(Jt9B,dq:]YhfEW&no;6m>Q>8!8On?B2(.>`t6#YL5t %7EOkjP'HJHN]R@br[T-VIJ\;TjQjWs?g;R*2sod+DbG:MnML+:NB\Dihqn$mRD\?V]e!en9i5UIOZ"iH]5Qp0Ka,lZdqtRR %qk6feUGQ!#LD&ElRZ#Z^pN.qa0`@7`e:+PR%X+uEb<$Z.[5#;N-aJptcO(6bs4BYs8=UD=U?3[R^kbfQ7,ZodF%kBr+r(YD+:_9? %O-'JUKAdA=D$`JG&c0gHOT:1S&;MZi<'\BP3(-:pH1r_RrQ;IZbkU[g17247,#bMN!93r31HhY6>`-!`Q=:&GoN %-Z>cOUZpfqXUpHG1oOBZT2YKP2+o#O!(EL/g*hcN1r?&.D,<%C@,N!egBa:l48dZZKSu;9fVt^ %G[*rS_]oY[P!]c_RCXf+Qpr!(#QRS?>Rfl/HQgSSa41CBh.RA+NN6(9c#GV:P#V:i1od>nYL>RV$"OoT1WUVO=#3Whm>iM=`FROo %ro2^J)UeNHW[c'G[=Kn3:ibURl\)V5F'V[_B[rs-/e6imL^i9qs(dO?hYIq]eoQ9ooMrfL3k,IJ206!@&(PPI'9jW!R.kSZ\r>QoR!45V.b-i\5[uOI#"uo$CjK$pZZ2 %k$QtjU0dat>#ojmO%-S_7`+HU7"80`_ZI[4_Pn@7q't5+f.*Vd=B)u>i9XscT]SE?h-mf)2lE8aqs%(P4ri^oca?_Tll.\\Dn4K9oW9[s)n/WU?h2I2*Vlq/TA;p;G,O,A %;aE3nl'R82Dk)E:8C'\GdS:(HLrXKS'Ce?B3:p])id!7N.Unp0M3u";rCJGLC%`[JG![r6U5F,$`;pJZ&"fKJ@-mHG8/DXK0LY/W %Ko8DYjsXNrFtHd93;CkR%p-@#'5QBg@7_7^`Z;=+_8WD!)qUq0f"utb9'J[-.Ek98d("$<)reXr(oh[4ShHd0(G&h8ClY1:KnQga %hMVbWK/[LsL2Rs"[./(d0BEXB[>nF2Vt@_!Dq6S-JLkmHVYe_iWRm$!]cHq21f=LaHRW9b92SG?<^#?Mh2Gm4d3:O2R3W+]>9:+"&"[5Gb8!bS/ %:=*;&9P\W,FTXc7^=3HJFb@#:FFA6/2QDKeT`hG9co4!NhPkGgW#J@7EBn[,Y/O(_@okVI8B[%WeIB_Iqro%`l3j %`LWp<_)#,VN!t#TKC0OjOs#0_#!BR?XVm.Y)4^BdhOWuR-Um"FFA>ifppTe"e\\B6eojM=j9>%7gWfXJ4YS'e,P9u%8FLuArUP=Q/dbb^Z`c\p3F %rJTB)q/.Y=0:b=oAl&6qgp![2Q>5[&3;[lggWLsn@U!Fl#.,4W$\tC+"4%d@!Mb2*7<"5`$lB-f0+p\=&H$OQl9AYjE4e^QWKqZU`DK57+sZ@ND7jQ^HBuh7M4lVSJ@OC@nG0s&!rA(q\H)^_^:k/0J9+]*:k4'CkpT4J+9C/_lXWVT5X:81<,6qA+Q/KZ8-<`? %8cNKhAPAu>s"a$kV+;7fWr!a;OQca3Yl<5@)H %`6Ydcj#36^^CE?c6oirQIG2HQ_/W:!ZWm8ABcgS/"]dj:g1PeKC*.gL#?F&1g;dnkc!m#C&0*_G$sh2*%OrUB@-FhmjG$#d]DM.8 %Blb&NdT<-$3>'`Q/W$Yc/e-0%o9P!7<[g/o %-Y][nV34\a*AboamgumZMRM/TMSmZBmJ9eI"`8J+j>c(U_,`;&?(.-F[TM_,F[%b%!NJ[OM9DGh1Kc+rnC]KR68#VKk;E;8QZEl_ %Y?m=IQX^,/QT$tOE%`WYijG/dU-qf6/*IoKLeu>+WHk[2RC'-'6b^8m>CU#Q[@ukPF1-AA %n7[kr*7'dMV5DEbMiE+rkYK05QuDCLnh!ltg,q.2bUPOtK,pss1TT;qN5rSuD[nN#g'2bt*ta&7%m`91?:9HO,U%@BR;I/0put:: %i+'CJl==8V*BOctjc.a:_o^QiIj57^1Isr8f2g$N[_%n]7\c*[$WUQ4 %&9-F060hX_&9.PE!S';3#WTOTZ)9N+#WTDDp6rLUL*#6hY[6Ij?CWl,g;=R_Gi"1117l)YFJ=e6=>)JK?*K%U,&sJO1TqQh/QQ&? %DbBb8Qm+$Wqs7"CSN^KFl+(!"V$Gj@]Bah9mmH>f$iSJV>^C0HVu`<5a5Monq-lr,8c=9ZqGCEWoCgiL*c_1(0Zu9@ZV+l+phR#^ %G9ZtePhITE:?o%4U%7XDd)UJfd!U#3j-nE+kn!^6DWj\>A@o+.h#oGpT:P5P'1DkA:@>I[>MIZa.im62*ef+Y*spQ2p6)VWVR9ht %'EZ]9$r/i]'EV1lj>fb^;$`K@"=FV/,74HlGs#I?*)Qu,ddqu4`;-)<5`9p'&3-Bqn0c4e=ND#,T^Ihp3%T_QKj_b-F55%oRc24' %3HZYB@3ODNJGl`LLP:]/HD4iA^/@%]*X5"U#b:_prj"fX^P"KrA7X;H3\5s?F-]DVE/'(Nb!jXCY_Ii_-j33C`=u9OchX:H.]=VZ.Kh.&HsYU1ATT>RiS&0Jl5fnHh7s30;Y*3kGbPasO6CaL %<:bIQ&CBm1\):2$!6@4IJjM`Q"[bTg.1-*%I)-JR85TY](N/b'B0mb$-AJTU"HFl5oN/\5#d,S/`:gB3,ahG77@%,:-1%)#(OqI; %Z%^6)&CiR8/;9AN(XkA9L#> %U_sWM50bkO;*A]LYUeV%-_C"s!6XV[Z!)))kKE*n2mt@uljp[]p`o57F5&YR]1h,4/LWT>sC//EbSkH3d=- %j_eF^Q7f=#Nn$+(,4o3Y(oq*:_NBl/r,]MilshnmqbR`lr=Ht`*&_h'$tZN[0iS6).>4rEa&%cKJ*GhR`Ur]"g(d(!gNKQ'cSV,p %WTq]LKRd;']=Yd<^,D:A>:eP#8)g2Cs3]W@,**polaa=h_ckc%mf/G1mT9ROe93<+m7)TsqhUmm"8g2fklu#g)0K#3(f3A&<6N;b4W3b+;#mVqHSS+d/*O]]?("(Q %@I4H$%bQsW6ioW]'`El)aKsLi.uKqBag[!3BYJR?qIL%@j&,.,kpKrDjo%pWRC[t@ii6p5#@gamkR>*E]dM^cJp)H_A9^=4@IA9*(euV0:9R9 %5Td"J!!tcC3N6@mm6S>0#X5Lq9Te)OT+5H8;":QV/K/#1\[?+09]87LC=3k,3:;CiWpT!)]1&L?,mB/ %keq1a)5;!^1\g]1-V"gm$B':USeGMqMR2PjX)*t'gR5qnYUn=$Z %I:@jc1\;>:OI&?s1IGMKUY:lWB#]=0L*X*sA7gSQ,R=3VZnjN1'/Nh4MH`$`h0jtN/Lb=Ekj*8Z0uUI)ju+rHcT^I7%/n*Q&9MW! %B';[BTjB0[B':USFJ98ibRFHg$sI))o1iP$/Z&`(OXW=6@:5tf]Ke+nH,3%iGsWt2%1C3GTNg7$rLs(>0Rd.9r-U,8%8qo7L8G["GZF1Vg9#^JH!pr! %f^D(GI>4>&r1\k'+JG;mT:u#=a#$n@M%XjZB+Bg/K?ZlV?J9atd5RK;S4"G4h&PjQ//ctX"qjY3PSL489_AoerP#rqL"a&1TG+,qeMn'2R\TonZ-QT1I%N%UMSTLYk3^G$, %=1C?V8:>TOluXF!*@[Qu<>YSn;>8OY]B84EmE\KZ9Lpp$2=0si'p"6:8pQNTg?Z1`IS4>*l#f&)`+c#/ehZd\34:%(CBs&6hL/(+ %]!R!0o6"4_;^8E-Kl>Ab]fpq^^ZNc#TtA`lhpHc=IU2_D&Rh&K_UY%D5:^/ %;m;,9OS\Wl`dr7gTPg'^kCTV761:hBhR\-$>j0iTJEhY]2g+40##kh\\uGQ\`.7-'G\Z^q;ZNg"HLK?(G[`p\5jo_-4iZWt'1@!-"' %*e0-jHhUuM<7"8^Rk8+>hEe:m?Ua%QLZ"$5U.'p"g"L %\%Z;BhYfQ+@\(E_8F5I>bVmPd-X9U"Mk/@3qltEJ1TKh+FpA(?08Mj>OfQ#8)p$NomccuaZ@Qs%J@_R[7>pe%gq)\7XiJTU %*pcJ*:mu2EjS>QdS)$A:rf/r!':70SRi=t]Gj=W/&X6#>Ys4h %F2]q3eY:#"6A60YW]L)gFR061IAWU&T^2n]IAUZ/U;tuIZ;Pp1n>4dnVB>4]7AWk!%e*4@WYF_e-+\/#@J2,^;=+4?H>lsVT\0'Y %f)lDL#K=uD[S";rY@OjV@"?_mMPB"Ni0>tSJTR6DX\F5U(=h>PAbVfE`rrk./$i" %[h.(DS9`mj)L(MR.E@U5pk]-n?IC'$kk5_bTB+Z#5n8>rUBRLnhNi-`99/D#ZI$:CNo>W('$!qV#gq6.o/C(Gso.%WDmrB,J*[_jW#a7?Q,pddFJD`dp"sAk!*1@^lld-4Z,BfM4Ym; %c&J[5ds:d%h;!fOU7h0(K%9%I.Z6h/.?i8^+c'eB>rlij?mA9o\>.)t.Qh:h%9X7::Ut$Zp-.NDVl,$9!4T>YG)1m*3RH/mC%=3 %$o9)L5cl2s6*a$M):o\fHLDf"auKC1REWkB/]W'-pK)KZGC/)ba@bQoFWsV-jH@DkKT&Um`$PEmKqngJHpF//k@hWQZBGW^iQ"sko"p856qcG?/OOS<0NHBbQ"h-B]>/XUFb]SE-2oB%^u">/R-U@t,d %CN'$_Us:r.DIP"PRT.1aa01;TB.98T?"+u>*[C4*%_XQc7).Fs!:24/1*68EYYT %mVD!hTk@;\1j_hNC]"A&>PbF[-.![&YGiG>8CR;c4BKN8Lbt.d>o?9Xd[Uq;D"/>";t>`])Sq4.j^B=H.mP?PW_[07OW]:*=ag!9AC0r#08lu] %)Pi$VTS,?@eWCKk_pMlJ05Dc=#M(Qo,rIsF0+1?(9&\6on!A`@jh,"[\:.S/miohM%lLu:P;k4#?dZSp[bO>u0j0\YZca>:^FX^!dg)hMPmfdoR)-rdPmk1OM#pYjqIMB]@u9[,J%mPs.](lK$WF45Xc6VJpg:a!@i]r'KCnr#,hf$J@97m`U.fW!#7eI$L:<6!@i]rPd/KO@t9FZ5,D(5Hj-ICbMuOR %4\--WHC4PCc*ae)/JBC1q@%#ob]!.RcTTo%8r`p%JrccW55,&BFUgoKSI76f5g-"n;A(tYMuX[G,;BO$r@Ol %1fKPf0](L?ZL-8=8=QfIHj$AR6lKZ'q[644Lc!D,J;QUfEBHO;$Eggl*t'5Q0!kYZ;tO'ko'#?jDmLVPYd+g,!lAGt9"_>5IIXe[ %/3YrjS3i7>>Y.79.MXO@`.$+;:=0.?I5M-m5QSPd:KII=&hh,r.4+6WL)b-(UDY>\k$*rY>Hl.q@%J\3-!jKO1)KJ9DSt06Ome^d$Hn@og)) %#lN0,:_(R]qK;PGdJUPsh=tEd@rK]k0D].c_\:_CdYA9[>0=k0d^QG<:FhlafZ'41ZTugN-],W/khi:++tbmIONt+c'+*C'nY%N^,3fq_m!F>N %#3_e,:V]gXAtLk4!nKAXT1/*C'13kG!3634/Rb!1VT_W,Y6oHUfU08>a^>J33+NXn_"R6!0@_/"eg&GlokpK>cPAkBBP?-CQg,%C %/b>gdZ^9D:I%0\k>Z05l2.A6L[pB'g9$,>DkM)56DDBm9#;?#HEt!)$blh.gG1cVf5e&TmE+XcV!g*Hi_uTc!2.oF1E*lWHGE`77_OU].Nc#UH#VrP?S&VB%GZJ6F`>Jm)=)Cl,,uS:NHL+#f!3Mq3%1LiVm,JHf!3-i69DUri7E0VAT1S2+s6)P %"7l=='7CRbm;C4)$.a:_HA>X?7M=$sU3WI,4,s2M9M!L<48&DYA%U2$pPgcl"3F%-]M[,dEIHW.k;B0K0G3QWq!!$63dT` %n,NUh1^T#_%(]Z'Dk7k*oS.8Cjl3'F<&kdC3q+8\kQqS1n[:N`*'`*E %MWc/Dhre3;8r*ODcJ^eoQ)cF3;'`65=`F#<]MNh6@;!k>J(^EB>okD'6$YRPUs\]rYb$A9kD+[j218_ZYDKU[9,L1KnRAed\1<7& %7R3d]5J'qj@o)^ZL+4JbqmZ"Je:SW+%tgj:f;=CU9l,XG4eWu.Kh>fX)cRGWUBs5&aJ&-fEGPo)fQjQ,,**2dkP(C_L(#A%*$7]\ %P9i-*nU]1D=\>%qrto/RPPII?=OiX9hi@;dH)kAZPV@*im3:G+%?mWAM;nnXQqHRcr73'o@Bq86\2"c".fWl6;L=on:-#\A<44YX %Q?<-hrt5Gj>@00()fchI0Nka`3g52p@BrF0cDks=e1b#tR+0XilP_+n_k5rkWF8t#shUn\Bq[PLR2h>N.od.]>-UfR;eOKH"boKjIdi%i'!BV=:4g3DAE,%"rcHMclK<:G.cUpO%R@i^PB0&cSJMMBA,Wr\k\Mf)!Vj01NG"I-1HcdB-/VZ;f9j2.bf-T5gFI*0X-18@WWZ^8Ed`,ge`HR?jT`2M.Rc %beh<@Oc %Tc8+Gak-m5VDGI&:LCk-].X-e._#3^S*:@J_3,TM%6[I!31^,.i%U_d+Q4*:[fPR&A3.W5Rn^IfB=*"@-.YE;phl#D#BH9Y4Pdff %+sg:NnBOrRrLNm,,@l"8R-j.,#5@YUAW7Q77WV&Ij%LFBlJkU)i)BQBV-d#LYd`:P,-0l?&iALX@>t!mo8O#5.mNTN?7;X9$33>83fP;98$)?6>k$$l,"rpE)k8;0if;hK'-%>G2^-lEWac5)"Xe@F[t_A9Ls@pK&3O8hBhR_[C;bUk %3/_]HdD/M\Ru>OHS2%Z:\15aAY>\SB_['nZq">JJeYJ-_A_#E*aK$Y!]V08f#HsS\nHOthA<]%D?(/_4NO!We.mcT7TYWXHAOWW5 %7l8"YoGO>G(t!<8mg'B=LkarH,;_T!<7,I9DhNk<7Wn\EF"L;_?)("M(\:k+lJ,sg8@k`[5$$*C(0bp_;'hbYqQ!HsNae[0`=(kO %@uVt`,ot20QfDuBnPu?qA6\cX]"u,$!MXWp3:5:[&?TjUP==r^qA?Z8;8YWMO6"^XKQoH?l$]-"AU_039GC %e&h>3q:T9B+^\!gDUGY60DJ>B`\u2hi+[/:Ci"`qB*oo\)R&%nlXbQ_ZD61^'i"Qh?#*4'hHrunC1465]GV2Q5PI"8Hrjn`\8SP7 %$u6tfVlP<]:EoDf]+1U$dd^B2Tc"B[n)e4.[2?t`^1[,l:2<_N/:8;oP]a:4g<+<+X7E(e=38%"iLX=^RXLjkWT\ptK@NBjL]`Q! %j*8g:Q_lLbXkQtAD"X4cG`jQpVP67_D=-MS@g!)6P!"GKoJ]D#RDZ!)VL:cHcQ'OfJ`G$QVD/Wro5F0V7;Q`MUW`QoZP9M1`1#$h %mf[=_X!V.^@KdkfA&"7YV*1Hu^DS>JLuYm"#D?.pXDF/^65XmJ]dJ@NE^5,Gi?;m=_eCXWJ7,OBh307>]-o]+C6+J@!0,8NMnZkE(AaUgWKl>;G_!M^FN6j+ %>+.k1`(p,I)`+S7am_%n9re?l\aLsq'r3A=2pb@74b(AAVgV@=?tjRoW?FUS8lH>L#[D*j3W(Zp=Th&eNmMFQDo)ET'&A%5W^:WO %e$*Fm:$o#rUr@3i8A3S0Iu6e[ah(*%*Hkis-,T-DV:!udN]XGu5c]'UF19&j14"hkTJ'L4h*$\g]P:?a)ns47k#IVBLsVUJ#HuiL %X+$X#64kah6QY]Os.><5SQ>]]j,U,!DCMdcYBAVPUK-&1mRVWRUpOmSo>Lg8RZpjtnU>`5UpOn/7/"j*r\G^o7(d84m/ucB %n*5[-qf':!cP#VDhO+9pUB)%tW_!:EkkX4j=&"Pd#dCql0Xu)dXsKI8Oj;H9?W/g[=uECF^%86qC"5Ibo?OB`*C/?(?\j!Xe@Z/b %]P:>J27g^#i)PuhWp-H#,f"Rb=uACu\/VQ=j8JJI8]bl6)tUnH-Da]e/`q[e9hMHEoY#S/s0qMa>c@rC+eB(b=ipC(=\)MH?ts8P\cpX^J? %f>I,om6.eE_#p9Fl>$*SSdQ@nqX_-4G?ROf/m.p<6[+7eJLLGQa@dJ5Q([*=DXc$aUlB#-X/d2`ZtJ47,Fqrd%AZ"9RdK>)dePFCLtRfkDA3`Y %ib[f;lAtBlSmYbX(Y&sUP65U\d?f%?kQf\YUOVC`l3tfkW2gk>?*J&'6#0-K_6'c-3QhWpA"(.-9"`**2//;iQQ9*,`'gCAb>81^ %8%jZB1D!C-a)jG2UTdUV5-#m!C$FAIfH?Fn6kKqF2JDdU>*58-I\1,QmHr2I?uuWM`1tAsn-=P&5Pdq5#ah>i'TLM-?09OKF+G)G %&UoIVct8ku6j)V>F\),RE=EI>,6o3nD"IWBq]Urc=0r(C.=6J9Qjj2ZC3OPQbkG8%X51>:R,#Q/>j]h=L4)_\1&"#;G"5V#F"n&C %[Cc/CVU]kNl;I?gS*a,Bj6cSW1OXG5+83aijk[dq,;$!^T?r)K$2V?b4o2k*mp%H4q+(mo-\pHg[I^`qDK-tcHG?L#V1m9l4^[fm %_QSB_YJI't!l$qG`o6^GFbl&riC?h_?&4Q`p^rH\9ncQ8T:EqR56j7qS(j"Y`Rf+=3K@1Ppa>ZoS]#Mj:\`Xp`LZRH+MQ:+`d=e_ %0:POg9QRtFH-?DgbUc+qVW\if[#@8=jfV;*m!=7JDC4t\HeU"*?e(8qHeZT-2-*#qgLF$F-^A`U@Li*>alV:gf^mObogj"&QZL?g %gr_gAWO!p3B92599MDaJZ>F9XpuWL\5]N7?"K2Uc;s50)Gbb88;g.F8<"b=B)uJkt*7JrQ".$(GWK; %]QnsrH0B-;kfr^oc8f?PSf_Sdm#Wdgk#MCKrUp_@4>#6hYR+0rJe[HeVb(ed*2=45H\RE4G%+3D[Hf2c0d_)0DM>*7Vq?\.kLf8Z %%25:KZntok&L[*X')l>Ia)[:nXMA?l-"F_%r%J!4B`e=63.?aBn>?TjVr6Ntjg?)CXo@-O91H,_N#P"?cOGuLkIk2-/fp@`Cm_-X %NLIlo51%6?`@e,If4$!#!2-'M?-mLFqUKIZ)XZtd^d"/"UMjkBm^dEWDUso4.McI*FVAoYkF#Zf-DVnOEkl@^1!K&\upo,bWFi_59fQs]-3*HM:F_JH1bG)LU*3H[[-jZQ&- %qJ(cF=]6^7QLjTn@8!/q;l;@gCs@OcF#Iq)0O'6_S+V&u*OFi&%(X`1FF;CCg+:##fcPWE6nS='&aHD41$bLK=\ %,>K`MSGNK*0rIe!kp>(G%%U^V1CtSW_(),]HQ/$+mb"11)+dFi(;d'n'SFSZR@\jirA:sW4$R.dX.RC4R#62Zoas-k.SjTkD:ePB[*YSZR>R9!CNLf%K=9T`f^7A=]iO)I)B]<&-D)f>^iK0bfN4 %S2We)9`-6!E"[JSR?Trji?XG-gQH.`:?$NU%QFMK)u)&,r+mG0CuP-:!5$p7g-jk394"_NXG(5'[KYoIKo;p31^N>tKaW4@"=mc^ %E5=]MN20)f^%SgMokq[t7/W$iPqI-lA['V%i)L%Z]&:OVOBNC`Ed\a[FH_$9+gNGi!RjEi8 %kQ0!c]Ge8TOZ^CQXb["`31dn;Zc+*_<(6gK/1s\CLseh?(.i5_$S)tUN71=Dej5]L#*VO)O10>][dQC>W*>!kd*76Zne^rKk[q^8Lq]9<]J,>8m3*5[).78 %Tqmr^74\.A*(jBPEVh/tcPQPqHfP1goQWjRi[(?.`cG?,JF$?HaiN1PlpWHrmZn]?p_C/m,XIBo[_>$_(ri;-4#CQXHWt(+u8CfLcslYRFj! %OiM#qL1Oa%_kQ/>4Y63>VdG8?14OBD65>jW(m^Sn`X1Z\*lBbUA:uopj"W+&nPjKGO("HeURO=>:DK23/-7K@J#]`3_BL+_bBOH= %-tu!,\;\J4%.KHPi\I^*g1XPKC1V#;:m=!lKCfO/jc)GTK/m#oE>agG)2$P0,VJ*qQ8sej_D6o3o+;9JoG"'WbBOH=E4dJL,E0os %'66C/4[a/H1(I_17Du9;!5:n?i9LENR&tb3UntUNdFDV%NV,`9(Y#8M6[5dlF+aFJVK?nOrI%gS%\>:?G'[LJj3'M!@H']Z!&_qU"/G$/iE5B %/1XEAdK%((=*hA!W+Cand*9.M__oIH6@A[tf.tse]3mq6k@9UcDUVaj]hNO_BjE.'bdh%ZspZ-#61K-\R %aXc)Y*a80qE96:i7YP+-SRtJ`j,B5b3"qK"faO_.#"C_Dh`tS>Ljro/Hr_1-CS,'V^Ur+;;gU"t;b-5fWOX`pV[f %H[Ufr2u%P7QDBJ3S.,6q#a7#9S0C#L."pS[GsIXY;*"-A2*N(&13a=q]Z/!%:57f.C4)c48pjSc,X_"+>ttT%2AA#4*_Um"Q=kK& %%p;K'UB5F,5LGg^3f56t/R<,O`Q'D+l:_AtW3gTQbM:7,84s!@Ei,2+`j5[D_#Oh;JfD'SAn\Os1#5t@c,sERq`A1Vb!\:g1;Y@PVJlEAHIT#q3S0P3, %0mk+a&tdoM.j_C\`"K4$eMReHGs#T)h)108UlX[lj=u(\rgkEb24.Lj*G]9%RU%eM.mouYOW#<.:E@ZHhAl%]4EAZmY=JmSpj-@@ %A@,6-UO'rnsVGP3BX/IrQBN#cP'![9lp1]Bj'T$h[<>FEl#c:m+t&:eBZ3.pNC:dDA`HsmItL5/sLZ6mH7QQQ=RG]a-N=+LFAnX>fNPl%/)9*@Pd=^1QJAF1OBDNr%5Ns4GIET+,1slj"W+&/^'oVj"_[n1-c#= %Ls(#Ob?2&4bMk8u__Sa>N]\rSEB9la@>Nr!*iCfuUIYu`nJIRslmM\qQH=lUPH@4IcYdEuOh$$Mm6Q7,h-o6nPsEu6qS\-Ka_!GM %>0sS"oX,ZDQ0kX@J5OQN0snlIAjJ9rK'.3G$Irt=*VGG-hG-Z(eFCW>4l^cOmPA_RENGd`FqZR+;qT,!bfYgT[@;]?3t1-eR,%lR %>qa>/m.DSr3hf/Z#S2]k#jF8rsZdP,MVJC7!,nKBB0/I:E1>L[)plH^."f4?Sh8pr;CqKGW]9hG![YJ!#oatiLM@L*i1^-hEhS? %G@6Pgl:d_2VJu/ZUQo!U5c$W)Ukf`<>3j=Hq>S/Ya[Os/\eGgEqm+lLe;4oU,G4)0iKejQCrX-7B]*US[:IYW0MZ6,X_3;.7MkN5 %R.>X.Fen?\Do$Z$%6^U2QUpB11HGB>=[m'(r\cq%g*)k^)eOFlBr!pR]n?S&G5WZMHFg@54Q[,h8D$qbd;hFY%3H2h`MY@\%Ys%$ %V#;c.Cl>s`gdN73802)Wrd%%nLj.g>8hB/%4M#VfS'pNeZ%W,%H8G)sh^tOgh:NLt2`H$Sg8t]c[#ARl+^7CsiZkPm;>g@+L0b!- %0?'n'9H$Jeioh>f3Tg#[Hc(8CJ(K_1O1t2V1).mn/YWgF^gi;Y!b.93Y_]HJ-B9Go+m[1=G_D#os0XOkhkCV&j`BfkahG*0Y]Jp2$EH".b12[*YC'K_prUI'd2VQ8qigsE %Z1O,2-YBjO=1oFB,;F:F(d])\Vp*_HgdNXOIeZ;#ePtT%qs+17A4P8^#=;TZt,-4e.2oC4GF#YoH1ol"*Ad);[ %Y0DH:R&o@lhpU%>h^=Q^mp1]!a'7)LAipdBRk%1,Z7`OD@8T4l55Q\+kSt=S+,1A!-+e`2b*N07-0siMHZjh:ls"'AY!C<5`>8.S %a&?"R(\b@)iSWNL%=87S&n?oF5Xun82`MR#iPOVHY2n!_McU^\m>0pC'c*Ell_kB%@6q;`PE)DTH:(Ofr!a,)jYj4:( %r%1gYHT>F,pBKgK"Xg*7K_ofaSo*.4X3Bh+=XoF!DIQ?(Mg'bpHQT77?=IA4MTkM/Ig%!KHj:g>0oc%N/onUk9omhW";3f,\f?as#m<2Wja@mi?d,hB,-7"kVb^m')%p+D?G*_:.4e;7 %&%`0a>G>(YInN4'n#IUOZBc7\c:aZ90=+34g^<6k^8Jai8\tER0r5`d1sLb;H%,#C%3CA2Vl,F)55B%ab8[d)fIZCKOgNUh9FfH_ %53YV#:+HcYlg\9nIA!KuEn3;4*Jn.NqKe6H"B)9HmjNC'd0Z$gaOS:U7d0$ecnW6&%q&Qo$GCV))bK0dkVHG^2MJ0`W%FRG"rAelpSSWfe[2tao\eTC5: %%\LiO1nD7Q_bPO_Ra,3d!JP,Oe"oCi];H@.VK5g\*,dbdobc8%*&+.;Ko)\5H^hU@1\=fQLn__E4&sb'-cfN8Y3O5Td2D;eU.(6r %V%sJs-C>i\.uM@'&*&>;BeN[#3f#du.J]3L"Cb,O(ZB`?[1Z)-X2_kak %o_FoGHIK2,88X@$/fS89E*lgK>Lt6ZkJs\SfTdaloqoDDh"bYjd?[fXn+IDJA+YZGP7?3@hN"m^\@LFKG(u(EJ4dT(X#JjK:K\c) %V;>T`mAW:bU>@`eVlb7IAsZ;n0S+Okl$@O&De//#n0RaVpGB`s3KDG3*i6JcH2VcN(.+4.PT%J3JDioR(^5`e5eC60!HEpuNP^`W %khUq;.H?&:Djf6q"c"OeY=dhN2PZbrO5%Y*EORrg=1\/So8fH\EHP(Pg4;tEjnHQ0SSg=A@jN.6ig;]*h:=4jD%U_CSo;B55$'a==P]jF'h"YNO#5'VCGn3 %YC-\Pkr^itlELkNFAP'6o*6V'nV!@krU_7p[NV;$^Q1P]d]#-<1%0MrP\s^*4p6*qDc#tIcrK=&g`bYD9J2$f=ruTcY@L1nZ83ZA %*iokkZ@9NPo8RT46V\Qj>&H\_:/k5fNabAi]82b*5%gP2P"9k?J#(0%+Gl?<6TSD>XKIB>)h,u*>gl7%WaIo3+1Fh$c;R0uXF2rA %`RWWrP1JGM88Hm&Y4-Mi?Ee^&76A$a).*,`OEa>scis":.9QeCeG.\_8rZHUk=;ZmprP)-D&0Ydm_PRMhK6<*Uho>k)eD!HZeY3" %3>TQCbp(c4,Ls4NiD?HuVR8]9nMQd1en;5L&"k>e1=S'k72Zje=JDgg`'"n_=JDfc.b8#_WX>9Q!/_C?;,rVm_nVlsC%aHtM38Z$ %SGoHrVtSim^??WN_rLUBdr.e)B:AO6A_m-=>8gk+l,:`eDecpX/^.\@Ha&mWZoVt[P&"^smlgSZkFo7=>C6 %4tlD8_YfsTkVEmLQ*go10*2U):Xd`-m`E>REc8"K<*ib'm.Ic@(!P=,NGsdnl\.;\ %&sg!^rF3g@5*\rd;#fn\Aa..U_LN3o&DlV92BdQqqqo?Wh_h\8\QABf`efu';DV"J`:;ci.+c87<\^OJP %56jpC8d':QQ"#O6od(#2T9NI&d^Q]HhVKE%9.t(WKfAb?pJK1/L9K7\dgCH\57muc(h]P?"e&Nf,l[I)*Q;](\Q0[is6Ea?d2\r1CUaW=n=fn6cu.TH(7)Vp?N'*\dlo: %?"G=Y9KV.;?1hC&NLsGQ+J$^-:,[@`OCt^s!;i)*gCcD*5BigGop+E2jQHCXTKK2MUp0G.g*j^36L/"!GG1#n %`'+%T\m<(Y@6]$/_mQ+cCF/lOWFZ3*(fH*\;jPg0rpd]#Uu_JrcQF48KqH88VsJ=>h2*&U,qnsj:_mo*>+S`c_3jnr]IDr)n4p7Jm:5TGe#HJ^GKN+&Em65^J*6]=1diL5Of%c-3t[1N8/k]g6>duAYn3?l)EL4MI^3PY+g:"mI5\do35*<$6'OQ8 %hW>^>Qan^V:6j'c;F-X`W[ogC^?T9a&0,Q(lO_ZX"2P;6G(OqfQI8Nu+?4&&"3ioF`!Z-An)NP3TJtZ?%j4\Fab]?\I9S=r*q-=I %IaHu`P'RV8q8%QQ3"\UNDq-6'YPCKQI6_GNdeqI@:V^s#lHKi\UU[#ni<,W*/Y#:&3%ST^F5M6"1pPKJR5QhkcVuXc"05&LA3j^2 %rt&2!neUL4ci]`E5(hC>gUEC!/aX:lfP(VGK8D:7Sj\_p`g]/5BkB)j1!_;UVKf48Oj!-VA$6o3@mmP\8uc%`@$&68.AW+RnY.S$ %:W+6](h-tu`5g!4j+H[h34*m5!%hdTN,['85$F_f;]\Nf4F4?;Vjk.pVSUcs$XD` %H1+>"bs$C-De5UqSlCF#pnja':4gsOg)K#H(%#NP;JJpJ[hN?Fb;MENN %4MRn@S;mhug+($C[NUH&r&_WNj#b#iKH..)a-)n>(e'Zf(I(&)Wc=C9fGj\:N5R1c!md.W-igJ3?D*MMSKV?U'o<'UPJ#A%(br`4aPatqf:VWQ9e[p@FURY@6rSp)k=.*-@1;SH,P#K %J'VWH2a/JU;_6"Qn+i1qfTL0-P^m=t22)MS@*(>k2rIi\^>umVNX+Brc3D8:lJdT,jSMdo'[a6kfQDT:PCqF(34lP`$LGtm[LO/# %8skG?eaKV79CXXtek7>\uqCc[V[7U%^W['WSI/qoWtER!rte`Xl1Tb##FLV0sK>3,URW6!oDW!Da3_rYFS&gr]u'VO8*r %g]nY$oWSLgZNonu%us'h^kXXD4kP>p8L@fQF"bdbLUhA-=N^$uTprUJ"[?=>Z%leVS=+#72*k_-+gI1dYYJLuDQoE_(;H^&'dB_Z %ZXWHFq^fb]Q0pF-PP9TEGKNqMOHV0/Ann)Hl)9l8NC//2GA)-X'T?L7]2P5*Xu$Fh[QE9)m4nk949I@`F("jaG+rJ*cU#knR-4gN %ZepF@&8)Lf'-6(e#\uNqZ@EO@]O9E+?r=HEQp3S,!C.fM,_T./&A.P%3+Il;jU9S8$#D2:FPX?2/U"Q/4%G4biNbHR=b!n@_4em3h?J@niM_1 %1r#X1j:*UcA!cqln1^tTUf$)Y+"JOWNSQJRE1rJH]DN`HVkW:`g$ZR":+gD87C`^JiaMD@Lj*j%uOsoF]g0IQRp*7Lpg7fq![%&,dk>RLm\W5U1Vo^a#>t-r2Q[fA;=r1qN/K1D?'mLeaFakLp>h %a>^\oii2b:0U=@j4c6qTBq',m#\)m>\V$J,_gD@hD_"k/c,hHh?W-W`c1@(+Obadm$8Q3'"R %4`_UHla#Gpk1&(ba#7tdSiOm+iMO0Zfr"14f,eK*_k;)8ft@bPrP@:X&dms^,'o+uI#n;bo[EL#dK.D;*V=gAjD(C>`Mm3!qGt^( %qJ#]8kZ^+[kfSGP^%HerNq]ld:-)C,F=ji7QD=@HpLFd9R%eR1Ar>Mu2Kd=D=Jnb%Dn.u65aQhH/1$r?<)ZBGmq>%c]h.^"2mmJp %3S'H:laOu+98XKH!?6(0:G98*/%N[b2"m*)T_63('cWk!E)-c35#EuDqt6pEmM<&JNuR7NFdd?Y+*Z(E2cgbQT)r27?L;Q;3'4Y> %"FTSa,R)J2(f&i=bUF>S6@Q:^K'l\&V@WN>r1<<5Qn_PKWkn*@eq*KH%sYWW1q6lWPnIf]m2].[l?_/n2TB0oiu4\*4$](c+u$&h:m9:CX8u9>A;t=NT30&*`InP/sl][K1L@!]@F4; %lm?Rm,#-8O0UoH&M)>-ikq[+E%`P6p;(,b9G3m!Z*jHG@jbsIMTjoV2p7E_'BA'QrXD&I-ePkBM?rSN?;@T_/P8P*,/_!<;]8=o2 %``drRBo8]1RV2->]c,Ns]A(6t1!]h*o8>WXaQHNDDmV`,FT_@mAqMO4h%2[9kWW/m)uF?NFYr%$4&QrK'\p)5ae[qbUr?$W6Ur__0+1f'Em,Z38!,S1Ob4Uqe&%IZ6k6i[XsYS+L`B;W>[Egs\HUYPd'DsAe6qWEPV+\tH#q`Pn7((Wt6=a2D2r!O(^?gH7abm@>8K!Ag:7"Spi(;q6JWk!uK1SSV##;mt %N7p%^+7oM$hY:l`P*hR4^4T5]n]#9q:Oag34Q,.]V7ARYi"LR:-rZ];K24K#"F&%^Jkm:[&,aPc#+qW2i^'6R-S8mCB^c=hBQ1]6 %DFjA?bU3+s[>IiC,%R)?"#27uKIeYK@:>6#G$9]4.4+c%R5qIrOjM=MB5_'_@*;0.+Wn>X1-7o4f:2t %X'a>T$#Z]7>*V %2H't`Ck'sk[u1J&5e/#g0CqiuW#:XZDP./6Wf:o:E0!L=#t$7pFG0CFnbmpKndXIZ*mL4lG('aq.rs7RPO%V&l]^@&-f:Pl+4"P) %WgO:,-eh=+r6AgeE\kKiZ(aD"Ws_;3V[E[BZD@U/An>u*cRJ[]ip4,/*60R8@o\]][8T5kIO`);nEr,NR>I4$!Q"K:5:s<]h\2\U %Y*n1NB(Ps\dehd9Fl@!>h&mGK?;+N@D"Pp^EPiJ2Y/-:s0tKC`iYjA9+7P#[E!;U+)$!\9dQ>7t5;-k1GHBc=B]q %W`+-6[fu\hT?-BHh\[db2Qtt@!R?k0TCcJF9>Y%OBnr;0?l/Q74BKAg^NGGPIT?Zks#-`jK&_@H\hW]_/3L+?g6P0%C9WWnE'.o6 %K3d9QN^_lee6mK8EdSE0n12bLFbf-QfZtWb"<;jZ=pu(BDq`o8B+=soP/9LO^m3pb9h(\e/5l<:P0gE4-6:9kUe!Ts+LUa$NL#=" %X7P8qei'Ss>'V^W+#s,WjR?j85q5HDK1_b`gIaajjn?d\<7n.XIjaAll`5)O[=jo2c"ZTmkk %Sf.mCl4s3Vct@?tH6(j=pu>,!(91]GD4tlhH0fUSCWKRe*:qQF/HQnO;F0QliQKT6l00';bj`)`S"f9_fW)!_C@+E/q3jWO3[(EK&mWmc,Y>4E1/-=#Td]"/l+(Fj%9$ %/YNZ4E\72e,]*^9]tVHl&DRWP4#is7.Z$cH5A%"u+P'R3-)p-;4 %X(uFt5'h:*Q+9i=r8ul152[B$o?''Qj^8KhiKOFMl/n7@j-8SKGH[N4Vjr'r.^N3g^sAj'f=O@4OMDUF-!=l]T>jol-gbaCeC^5%_S8E50t"@\HK*f7lDLnPj-Oture//-]lY\#?5ena[c4+/8gCKaY)HL*k0c\25mJiE9`D<4 %U^IqjBJo3#>mfe8Pj>U=3PpH2+Jm7gen&oK6Gg0ROtNL7;PtLrN<>FuNh)5)V2J,="H?=i2bF<(?-I.g5tREAdK8@pQ"/j=K=sH- %Y8eLZ*;9'9Gieq6oZQo.AtG%I7K1."76cBBai)BAlRkk:P&=%*ABE+GLQ2a"IuVf(Q]rEYYGN0"f4DqQ8*k&5Elo8+dI-[8b2_WL %>B%_j`bSt7)ZU1K,'D$WX77KYXhL?HlFbQYY1:![%^.LNe[>6sb/%&AfE^cr.As8fS@rqG::^4DpV"uP\]N[sakar;A6BCWgO*dj %NcS2Ur5IL]d>0:&`\9ocIWeiJ %T:E1nE;O"Ni_k"47p7nN)[dVW'c_WS9+=^k$Ts"K^t7a*6K4[t;]n-CZ9bjM,*(RQS,"R$.fhu]a/R2B5f&R;!1@-KrZFPm5Ur^2\un-CWH?QTH_^a$>hemfEX!fu@Y %`S3b=0(:i\_1!6pF[$X%@p+lgWV`)1d#I=-JH#//Z[`F^3*-J5Bi8mN>/U+X8X"`6+CFB(,Y\Uu;"e9sF9.1;*F0f-2N$at.nQ0D %>eol98CGJjX\efe2bOK1JA&\O=WD'd@,KE%u0E]q+-lL<\ %!+s%:^2X@9*(3G=#-KY4QJd;`*]@)2+*YCtuprbT]R;5#pSZj_3FNkcbFbStkPE %,ucg4b0^nfXL1'Lih2)CS\hPt[89!TL)c1bq@[VR1!:Mc7&6L9.4SbYGC+-A`e0bD'_s.q.q%VPF)C!2#6SY`\ZeJ8#Qcj&.?CA4 %9f%rWrY*Na^#*Pj05LHm&((*mM]&UPN@jN"a[V3H>gkqG5l5]&Wg_]"K"RCR=^eFHd'M0#C-i.-8?UI\k1+0DkZsu?cnF.X+[C5b %0,H!Q8?87B->'J*%%(>oQ7s,iReRSW?qe,rhSE#_[l;@tk[lGkTmeB&q"D?1Ar\Hq)17HiJJ_2mAtZoe'?#E90EZMl1<6Jk?^;fc %1JcX!^e#2mAanO(+&87I/2QH:qnPc:KOs:?7Qte>"CW1fL8U7a&LA+K-l9SA>Q`$hTG( %E<\NO>0iV#j".BD!A'6eibsbc0l:p#EI8m2!8knE04>`paTuAW7\lV3HH-od_/i)L%2:Q790/Q52Gb'd%-_SO?TJ$7D!>bZ;AVQ[ %4jr$)__OJ8VMNE?%*NVf18S`CbBOH=fJt*!B %(k/k3MHAp";"S-A%oJfZpq,GQVjB(E3.V#l$uJ3,fl*d#`Ns=GlZs()`L=XZ>+S/]^"/h7`aSJ?,2Z?@:P9XL;F7E"H10@S5M,9e %"Ha]p)$8tD5nto1qtJi %Cu!l\?]=SC6Y_AP7n=D3i+7!"Y9?cQ]/DZ5i1aSk;hVli@#KK/[,&-+1PmqW^Z(n#2&H2ms*@s(qMgf[R06H[Aq)K!KJZ(e,?g4! %]>M8`d]i]o7CLdYnlkbScuE\*:Z"_*Gs(H'[H6o';\D8j"A+GB9o?U@g_%b?3M$Q*n-laKX*-qHG^bD80^O^Hs4XPf!.,MPh_Me9 %A.Oc(s3)cq@]^Q-@M9<@)h8Umi+*NZ7HJjZ"(tNZEaDp8;Xl/n1cmoh^Uctr?O;edX_f2]-h58Y)P)RSR,$l7d/eGaMQIBIEKIhR %FJI"/h;c2e9DbM0f>?ibTsrq%9=L7].VgK>bBtcgYG<=_%A*ZUlg[.fm,6>YIn88K4/dV/4O@%@7*Zj`n359CAj7OuC*&[m*W[dC"3f'+3 %m'ON$/9,brN0EJ4)3(:XqbIV@jRX;d`q#UR,AhOEIn]?S"h.MT)Xr#S>Ad,a@10=?"V2>q/M_95+P!4Lpb0!(r3kQb+JJ7taPfir %7fQH#ApQkmfcp.+i*=kRY?ffH)Cm=?/8`8q2%H-#H#^a3Mkdg)p'07Vl=m7Le9&^oh.>uUd8AMA=R:,f5$,!t'iqQHgP>(QTAlZo %Mjtlsq0"EjC;9G%:d'+8rBN/("q*itS3UdhtkW\ueI;%Gp0=>_Ji:KX947U?_N54%ZVbCA!W3ni3<%+3LKl4BeK_]?`f<<'Y&A[d5j34kr;mc\aU/fu;7-h'5^[D+`@G9+lHN\#G#0[Y %U$Rl2_PF^.-pQq7#AgZ`s'@a1npJ*_XZ0j7s4X!MPcFg>T1Wh0tT4n=g)gHCi:CK+AJE$R_.@o^RgI$R]f[ %$)o2_qh,_h=gW9#Q=/[9K'?!.kd?=GoM5d13++>C;a)1HoTRRE'H,fn/N8!9&*-bU^X6D[)Q4Q[\E#7]X`V9;LWk&!Q9gShnB_!* %7AQ"F>ujLdeeWK;h\?g.l#8;/V5:GFNL67QN>OqmWi/Yk]KU2/Z@i.fB>MR.5->D%bAUd-s3 %">+^POD8^PI-5.n/*1RiSN!hXCES>k&lc'!DBMpuE]!s`3"Q0@kB0$TAKZ[06icno5)F.5%&=jb8A23<`hds_g"-%(%&B9:cbA8f %ZeLeGhNr!%ccSZ`e$f>BI4aQp%.]Yd(B?QJ"/tt%PktN7."HVN$aL>GPCoh.[/^D*4c/OjI4\JtoSj#OmqYcUk^!Q0hUeK4+C?#M %VA2;SGd!0V]rqTB#ktS(l?t8*6LaY"64;8ZlGkRpr]%D=mhWnnR8/5+S=_rU2Y1K'2CY0(pRfg9:=6VX2Z-2AbOQ\QK@Kd(H9W)? %NV&t-5TLS>_fPhl-60V(!OM"lKRhL#6eBs&4;]'H_RBs&4:r']3gW*3CSU %iD-lrLuMWMW;-(jMa48u@]]?*s$hn7eo"U1ZDGN!OQY*30qPOgE;WCYM_7gr6rJF#drnh+'e`Krp[;%aLLt4WW.pd^H5gcraHdu`@0#kiA*iZ#X=*0f;a$A+a.lr]Q %VK3/i8Ct1O?Vu4M24_@R_fpP6Ra,3di^5[o.^,NP)'sleH29qZD %%sNIu_M:bWJ/cWVHlu=3^m`s&Z7X7f\q%>19N?b:L-YbGjT*6BC_!$iCq6'Zb^ONefM1PMRJe-cqLU`,oj^R.JOf5^Q^8nOjdos+ %5o1^TM1jHX3l20CqKD$L3g2#.n+p]lJp4h@=tI8k>bk\oA@:4/rU@"8)KdVPFHnem(?1#5/;Y7S+$V8Y"h&6-+/FASctZeq2`k`[ %H<"L5+ot/GTq]2c'8niNAYf2fn+Gsdn[O7;j*Ul:1u%8q>1aiQY%ueGm^n&p[%]J&Md?b!`!IPBmR(%(5` %\677oi(U+/l_Hl_EDe5*/Cp;Q.iEtXSC)H$:/T&,RSDX]^?oCRcZG!e)$Fe%=@c#/'O %;mYC/d.QB#33gu63]Jgrq,nPf>qQ,e_g(qAO\akn:!oh]C_O->^TK9fCZeV,b^Pi3@r^*P@J8Sb`bQ,a)Ski1Z6Yj^'kBq"#p"FO %bN)Jd7fA59f/&FsYY,E9A.hIUXaW.H357(!7^nh'oEATFOnRPP>,#6bBn*eEG`'K9cK\H_YU?GHYnY5a?baSEjQ$0UqY#BGIj(pB %Frg>gI(_c.L9haeU*@30hiH6o8ob/"h!am[R%/_IGD.[%NRbS3(jfUr26=6j=ufmG\:WHM\skgSY:38giV(_8]$5?2!1apE:EqeO %XiaT(8o[[srKP)n?9IAOa"]iO$c$4a)94/G`Q;RjO#CToT,6&'pA6#*ghe#2merfec*p_e9KsiY`&dpV]A]Lu#74f)+bi3%5j5IT %r>a^SeA*)@P;mj?Zur[,MbR?VR_gQrJFk=nOXWP$/[R7j^,_c.nCnQLNQu&Dpan=\lUg&D,rm1RI`lN[k613RecG($48_YZC@Q[8 %LKW5MG)+h'fE4!Omo=qS96#=Z"uYY`]]M`1Qf.Yr3rOD#D_Uasha?+(MY8lgo%JB"Hn)^Xn`G(k^n6pf-@l]Rk3iDgIUi6t&jk2i %mfKq*p7%95LiHdFGe]]uQQ=eE-\-&YI*nl6&f8bE(6&R^O7O);Sq\90ct]s4:oPCY,.m(Y2X8<7/]cY8(A6)Pk!e+a4kP:tC&0ic %V:#G7VWmA8=^1%5qIX)OOYh=3XuFalqkK5'Q5=oA.fc^;fSOH,pqglHo[?R%1+W,[Xg4@94>2-9dO`6>p67hrTPpRMOJHM$2Kj;3 %_(j@@h5X^sQ;_UQ%8$-<^Tc*I\ZAMGg\M.1[::-qBcW9k)9g6mU\!i#Armb(@L5iR4dXetW.11ZIS?*)aEB1iQF;S4PS4RCR+HPH %2NPC[UbR=f3*,+]5';6A]@Z(fo./O+LMip8DR1LAj`8D=0TDljN1SE+TTaj^UK]hBcq-^a8-ZD%g.jF"kmX0Q;Ke5NZg^Y:YHB]E %5LUM69-U.iq3fOPf9S88*;\n.p5]g5nGGsmaLDS+V_a>^)uD[-O40MBNfUD>g#I/Y;J?hfar[H:\f\pGT.(WF21>WcphWlWYbZEa %*a*`\/-86i>ZROU@kQAP5G?:*=j`daT^mN./RK1/ObJ[;u"H[1d!uR4OB@(1d!uR4@Ka)Y@aX=#A9l*tI,6sf;WK*QM8 %,6\+>aGV#@!X]"UaVmLLh'/O8OErK1b-=1nb_'kihmIfFabf %cq;CdL;4@S@*"1/@0k@2K]B!;KlEj!2h[*-Nd$."0LR(']EO$4L4;Qpdd6@@*$n)uSGoH:W:nrn^??WN_rLUBdr,N@J.4l7@)c7B %k`_>mGoU$;qLuGtalD"\?2G,:U&t&2"iuC-5.:=bPJB\tUgkpfJgE'iqMtdY5=u"W\QAJ+%:^p=1i4(6Tk2ha;6GU[MG@Bf1%]E\ %efc`of@L8Sa>U69euVl7mneo(g_/T/@X+=AhA;]Lru[h7r=RGR4%64,p#=B]5BpY6R@2'US+@0_/1SBXKfmc*<65eZ:KMB(7,Y[r %9,)Zm'/^.<,d$l=>IUt*Dh;_=1IDSpVD`cL_MqePXOi/TmT"jI'iG0a`15Xj6h:5?0#1in+#lUXVG^t7]i.d-FTeGrp %cG-m1B8sHVCc0=bkKf9_'TnOqZK?tu/dj<],,L(HRNi0H,?;o!dAMfU6#V!dg^ED,$M:c[VT!4FneZ>L!qHcbk6C)aogT+2_tR[l %lE,tT8iL3G]bNa_W&N[4*#++I>@BJU"@LVuKu!5e-5A,uitm3MJceZ]l%R1k*pXXF-siZX[Z!0<=\2&-UM%4g42&fdDp8Pk"@r&M %mro\F5PO-:oHsm+r_nQ-3I#fVC*;:?f)-/tk/WmZ'kUG:K:L@+u^Y*@3A4ok(gg*>4jt)8!R"5D'hI"Jqnn %dke#?Tc-n:O?T%/g`:L$CAPaT2!*+_Wp(DOpj/X0<7;@i'Q+F%V4(jIUGAiX-;I45VIrkD:#?YLC3i?,a4!teko&$od1TH"M5te2S %B,iFNIQC*o5@)#@.FnH/rF2U&dke"4>"qYhVIrlGh3+3U:!KWV`+_h92*I]QI26Qi28-s;G2U(.m>tMqi*#<@Dhj?MNSPV>P\U&_ %N,_!M8u\\c+M\YYQ;UFAPJOnO8kLu>9ZAn^o$L7u5*LOZ$n\=P01jiATHM#[#q`!BhG0q1/*SJ4oQE!t]9\=P9lDE>GX>#F!PS36 %mEn\+XtEr]2ZE)SE)0g$+L&;<=aJq)%Y?W$g":9j"S;R\%K^E-)92t[?:2D(@UUWOB?<4/H2?p:?\Wbq-6jc*l2e4um:#$f.qjqmW&-aR@rS?TGc_.qb9-mQ'^rQN(] %7ZsZjjc8.Uk$GW_3jk4?&6/(r5$1%G3s:Fko3](=>Id[uUt'&K3Ou_J]U*kWT60-t(d/=T(OJRT:4&^\JTk6^^/?/>"h#"WGTnpG %)`Xj&R.'nlH9'4beo6Cu:7jWF^eT%Ih2&Z.)>g"5f=:sP^0><2cL %$k`d(jP[sl0ZHWi5T_4SO[ct#4T7TT>pHL=O&2IQ@7j`AjJQ5\p$C1%G1_BAea$f$4^4O1L*a %.(r<]*(f[^XFD=fdH<0"e+`7^VIQcA[D!q-A%4#ck`#oY+A!ZKQ.3g^n*%g>P.B*pZkTZ^?S<_!cc(=/5fQt[KYD5:L %jXV8HG*KG+EaHnHj2#;*)P'$Wd,.rDU=FFr"OM[9Z$g[p!5IXL9bZYkBed=+I$gPl6di[hd^C0]%HXj5LU:n'VeeKimFWG#]>Qp= %q_jjlRX6!)Z&I`Ao^0.+bOuQnOk\$]h@@mk2VMHmX`h-C]7-2mguSsbP;hrTQS[n:]^Tla]?Q)"AuEeUlc'#cm?VKJ"3Q44LM/*k %3nY!s-^h\4SPdt[9KGRC7ufd>3E:\caF`Y^`lismJ]@4j"Dl7#V:7=eD-@j@+k/>%NgdtLjRQ.n]'r9C,8r)qMAT>6E;ti_&Ile, %LG\41Fl*7-GU.18R:n;f1`+P]#-I_'9-`[o47l[S.Fn(>)686&SN#X!kss0lJ'l0=L=PSg %Y+;7kf,Y"G&@X29@p!C%%s2e2lT*0 %UZ1?4BM+6p[%oDu5BIu'`;MWl^Q?+NU*J;cj1(%)b23:MVBOsq*Fl1*_JoeE=qfmf^RNju!8Jkq)Vn'\o"r`NUDYR>2dIJ'iNiZ4Ke\$g>*:7UfREloqh`UP-+0n3bI;X3NrD\"Am0NQ$uG(dgf6iTDns3r<,N&*Sa1G=5!j:UA2f %jenb&mZcUuCGdd\.N#em0agH&1Y5'P>"`heC=C@+JYe86\Ddlqq,K#t;fXB*[/;0ASi494O/;0X=7%O!G@A*^\&,';H6?fX: %c>gL%/_%A!<@UJq.QKN%HX1/!(;^Hs\IoDg#S!B^5f5ojFXh]%^p&nL0bd_l#Y0TQiX7LmUcVS.$k)$mOM\U80J'$&P\e3'Vm)8` %0s"&KP$G/fdU6F@4[%=2/7ApTP+YbM*a07Q`,o5>Oh;>V.gF %QeV(7DBg#N9d4@NjC#3OoZM[brU9"Yr_r(XG<3cLYGF[3b9#GI85+As([gf<3F!+F8A1>:NH\m@/bA^udbL'ul1T-,'+`)AFl3m' %<[+qMr5egOm9U\jlDVgiN5W_8"EI:V^s#)Ou/8p%*dW\X31a]VJ_R=M,t#!3gdDA@uj6pf5"HH;:%4#Yn`4i03,:&d>rZ)$"%5nte,p %gs2Qe\_])K*rCB@gO7G`imdE!KhU]7m)j[6a=Y5A,Q7Dr1YKJ!k<1O1(\hN&Y3F(+e?#k=`AV(S1tIjZeS#J %+^"n)Q,BC!nA8n@!Y^Va@27!X"U;k6ci"UG?4WV\$a9?^k[/NX[5[XR%mHO!1]qu=V,?2ZhZib(F\[2l[l1!&hY04\<=*nc>.A_C %M@+51).*!u'-Q'K4^S2-*>I:4]siRMEq/S+E,Y>.e,iD6d]o+U:huLc\#Qoicrq[#)i@DM#GHBOI5f)/M!q&$_+GbN$_:+9\A$;Z %Tie+r$\*UBg0-KUKjqOc(\"mQn3^8#rbD$l0o+`f?)`:Li\1%UY,\&[B!W7u5Amm7U#lV4Y>`-cTAdduo;j.n<$"hg=sYm<>3JKQ %kY,mn>ds`p_R;U:*L&#!EnE:+C[Y@1\;spCc87E#BW,P]kpcL>\a!%nnl^Hf3?)%[%l7<$*5crQngjetjb`QE@A%. %f7K4rZbVl:>RNYqbQ;"/E@m1u$Z'\Y9#LU)pKn*914D/`mo&.^^@q:?MiOpSf-\LMq;&/F`Ud6DK+d2p1:[`6WjuDfk7< %H2<E24@et$k4]49abZbeM$/W=C-)$+kdBA#^hd.>Y?bfuT!u0X)mRE9s %2^0q0m,H'+-/WM,5bqnEDt'l*m'$YSpYl$3R0_@'5Ns?(OUh)A)R(LCh`m1(d9pRB1#r3ec`BW,dNdhu963"S68s&AgG"(FqmYJT %EC=p[2W-RS4H7WINbC4)[5Jh*?";4k;tOoV-(7m3cM!Zq=9Bs'`]F;Wh[d*$fUT/RWjETR69lbWQ55A\Us;]2`P?q)2j>)E`L.uQ %S,GLjJM21V!keWoJbB5SqM,d<>3j=Hfsa>`/HDgT*_8P53P=sJKF\bg]Tam'.Iqq/a(F8QnWo<@c+s&^lkOY-"(1]%$oX-EqHsDc %,Ef[f9s2O_>iI'\WWCa9i>>'Q+#fAb=6^.\rPa)TT7QqtNIN6:f!f&^qjg\L]k=#OmUGpS=B$;bC.n(>H0)R-Z&n8-DrmhMb>8p; %?O#5p9&fX1Z4nl`@AqdQk,"2fON7A8hWnCuq=*p32Z"QB-k0J(*N?SpFprjj5l1AW.`TEuKNpYZ%UeHE-hP^)UX8[$J0;CAcPp?*I\BHGT$&S[7d`C8gX`_lcBlBC-<8poOpGOF=4M%ck7?bPNP=8CLUEqc*B6cKWMUtN4!XHWU %p54$s#H;A!=0tU(V[@AOZKR4LCg%;>PI0*Z4'V8>\pE7sk^^'uk_AXi:ikW\WF0gK;AJB>gDFY-1&Wg6`AY;O?T+_"A2!3>:d\#hoTPWjGoifE;'0bK!\!33WN1B+i94BN7pi`'j?DF^7YTg[_UDn7I>FI! %>NfUih%pm!#.C+uY?TZBp\'J&Sg2>9n&)/u.9E.VMYb4$Iq,*RGl4tFgYm'nnaT,+4;Qsm?-s9L!Hn^S!/b:a"KNeK!>NS54o/78 %>t7ODp?1/#:Nl@MEP/aMZp]O[$D[jCRQ)#n"[DaJ+]3Uh;%2&?IX$V;)eC$2`47.CK2pr6FoV0i/j+qj(S2"e.oT>E!>c.SaKf5. %cgc:MW@g8SmB[XU?D#`?[JZo]I*[QEF:q4Va:7:Z$%&.B=nPi41B%A9r3KO\2$M!rK[>:kbA&b5A1nCA,7438b+M2Vmou:c)"R7A %c=;_FG09dZg:[9;>:/_1C`IktN8`atp6_O\28J+,)[ek+@oQ\F@IW'Hor)kFSdIr$-&Nf1_!UH[(^>"RN>W32h(\+d5rtLE; %pX#].ZCGKc\EA*7Q`2'f.HjAZQ`7U;<-KG_%l.-Wh8`2:hk-_$8#pWicSj6bGPPZsr;64rWh:*5i_QPnlhAs.[E4FP15KgQCX'uW %q^]6u0!pDKYZ=KT%-QIg;e0iJJ;p/.q+hKaQ/(e3])(Ue,VoD5lYts1X8:2%LZ3OL!J!gcR$-NNot2om/AMMe6C^hM>\`bP?6-/[ %L9^((QeKh>_]o$D]CrL29$No+faW$RIjr20B,rB$3#-gaI;'HOk1/!/H5cE;kuMk[bC`3s)T=D*-T32'2 %2%/VrYFbepGp>3&]6S'P`AaZ=q]iGVG<(1)llAe"O3rG(_b`>G9n_(Vek.VqQOGcW3L%`;f=idFVQJV*Bb'V(!f$Cajs=c2nCTdT %164RLp`4s`ADCVV1bEJ2J$:*hCND4c2p/"=$s)C]c*E7.flN:u.Vn3BG9&*"^Vt[+hm1`q(A0O.GiA!iKsO_sh:ol:ckl-Rl1R;? %77p=VJG'r2j8.0<&d/ccZFR-DTUB#Jc("$(^ghnR!`uZ_YD"@j/-a@Uc"t`)U;l+gcI#k^VYa\!;i,BqK)+& %lJaOo/"N]\aGS#Q>D\]sBFY)Q;9'Uca-2Q6]bca'4$SW[BGL_u;/.)jPBOoTWWuiMhs^s)&^Ok6)No/'.J/GmS3jA4KfA9J#$NMR %/35EKL?JPk,K(['@R4ggXVqtAVQATN&s<&Ck"0TVqPd'C;=YYQ-YPt>-5:'E(gbVm.R7&mVWR'dlH[$)sW?PoQD/@e'Jk, %/4.J2NU7Ljp?"?kmd6_:l)QB-lX,'l-m4(3K<*F5'TbSUEW2_`Xs1!N\iY:0!==@.po,Op<-H- %^oAtNHRq>@bDFn(qGltfs!a4P;qt2Ul2IKq%GbH+Umjm5L7Vj2dVZO6HaXT*L3,#(FRpp9PZ/R+FRpp9^i)dfh)l$'Ne`(kX\efe %2bbFN4:&F:P?c5^qF;[agk=GRbYbm$'),A2VS>t0iJ(R)R&1k*_X12_N,^uGPb['DW2Wi*0-IrIj*5l'+MDaC]/^k-gN@>cdVl+( %o>+D"&8lt.V@"9*k?lmim^6bg<4H@$N9@&q;W6c!VaN#ibe"4h9l%q+gD"EAjdthR1YQ-EBe9=c#6J/7)/6JL[E[WaA,9@C,,kOe %BG+CEI`BH"^D+75s0!Be'7F8ck0p1`:iBQ!gdURo&%Afi'.:]@/5gDq!rBIr.6,CIfL9b;Ie)n%)u_tE@K^n(Bc4a\B;Gq,1'2N> %8IkdE:97Q`Amo_554a11RadMard.NXHK1KL>;r%9Q5]94Ub(S1k"ejc]p*`'IQQnJE#7L-qU4ToGfN9'g>sMahV@MfWsf[\oL0/$ %]4Z,76:9]BFE[uL3t)4@TY#CS;Of<9JTrL"fZf/_Cjb+NQZ]WSDJ;\7h/)>)3HUZB$`DnGM*-,eX0<1ZNj9/Na4L\[7p1V-5!*39 %.-iunBNCb(-?=8c$dZ]8;:^:CJsiiaP][tl:tReN3qQPl$+iL/kU>b]]aG`eVZ\1--?Ar>_,]-UhC/=j%R%d5$+lD2UTDr!jnoBG %e$j!8lRXJ[J&74OQH.HB%Q>:S_Ck7\fJtPr3L7P-;:Zk*.iOd6jk7efKr-ss_Tl$0JZ"j&Yk+>$ni;hRe1Yp\malk2 %LK55XK\]nam;=5A+#g2dItNg.8Or-#SYN8be12bPB9@>rV#4H:F"!&m&U*1>UsJ&>,[`Z5/nacj8(.1'.6%hN.fC%ZYB[Ns+XdE= %CnaEq0lNa"];dp:7GRUR2(?]JATbQfCg:\OU520/GS_.M8pA8U!(#2l25pH`;Hf27QJ>ZDO %W(uhe0rqd37h\&+;q^@D;*PuW%;mc,a*BBBhC&\JOraiUi(Yg?V,<']jfhtp_mT*,V>?YdNp3` %G<;lkrPN[pJpZb^,O\@Yjf"l0?`.A]k,lrogREY[K*+6^,hV(":?Ueh1W %gnU3^1$l`18+0RXK;TE7lH9"](^qM_$u11\dm2c`e-$PMoH$icO?^Ja9&*c34UQS/If86QE\GjS:Tgjl5h(1o([7-IpYEPG?:-U2 %C5bTCPP7eV#[5i>lWU+XJGO`n'cKSk-M\e<@@ijgd(]W4p`cr3?S8nVCkZ61FSV2kYk3p*nK.:MSFLTaLLr$@:eon>DM+U4CHFo+mkp+tV3nqBU)gP\"Q1VEYPPZ@E/7k_P;AX-h@ %A^6B;(?hpu %Q%"]'^rERUGSc]2]mT"fDo:16kMS84UYY+g'*TDh6eGfV\FYeo[YQrkh?FVa/S$W+-bk&!#BCE@+`+!"#-5K]7F'WV\+=i:4mZ2' %2qW,2mJdgsaYoo8(OG7iC2$U+@uj40>#M`In6&bKf))cfXm!_#hY>Q4ceF`na#nsVC--FrE)ujKR&\)fO'fiTS1ehII''ThQQR_/ %E8l-@Y9uDO4P#5HgkF9R*"0E1cKu]'lO8?MORK@^Q1ZGXa84p=nbqocHu-`-f^\EVMUQ?+9=h`TYhX04WI!lj9H)<.5*JnZhp53Q %hIqW?lNMbR"'kO8J^n*L3G\&k?cPanMK;e<2>lCGQg_S,m0`,@YC]r"o.o(G]-Csrg-\[5a0g/XaB:W!E"HqpIf?p'qgs6_GQf!T %5:j7$Y*$%o:U8;hO.=aHP)Xj=C#l?rUr4WFads^?p5>Hkd];r.`,:^D>&gn,]QB1(eah.L*4]_CXHo3%Pa$J`c>%Xha-\>>,A4Es %oJ+ckhoJqP0E$,ChD91Qb=hljL#.ru>$h%VX)+]T=Y8Ne'F2?^jK-odq)e+1OgA4tqP8s4fh_Y1YkRa)[)2KqSCR2Y`uIGO8B!=t %6nrJsrfOP$*d2lrpPk]Nr-lDI^@]qCOUm`o\&dZ8Sgo(Wc>%XhB-6ndOgA4tqWQD_2f_sB9>C8/?Nm#)[P\IB8?lLaN.o?Zm> %qi@uO*P[a"U: %gZLh.qr4++(kBF&/s#IM$M,s!R=9S`qWHQ$\V\t([slfXJ,9"_a0M,GPPf;_qt(tLFMIgq.sJ.%s/!6p]_9q42nlflrI_R4?2<(_ %YPrM6meu<%`QbP<_QNjuqPX?&Hhu2eY<;UA_\Y*2IdX3opFiCjZ,sQ=V2'!'&F>*qOn.5&c[WV(gZI*Phu*3Hk?R`$HNus$?ba5D %l#X&A!R(GpLXZgA;ASHLSR:d-fACl:o1-,H="cZX=<_mJ"+ZhYZB7TpHkht.`J[ZE %2d_5V*a^1!H1?Tf&1Dnorqbt'oIY"t?i,k-J+p.u?p?g(=+>SrXZ*/iWu!CQNs(dC`n/=T+]f?GIIT+>WkJSt3WH4?W4BQiF^>qr0H`ci)spj2GI'Q0#6NY31r"^%^ZIndUur!L$:Xr-Me;fEZ)E^CHgk %HM6n[%kg)]4`pMjWt0+)"7gEk]s9W\0"B4[rR^rA5lhA,$Ks:\?MWf;=9!@7k:]'rXA$\#03ihf>N!r%#(E0JnojteIpINrhAb\V %ob6\JJ)C.uc*,ZW]B:e72tL[cI47NPRgTGPI;AkpZE+kNgb"o>.idhn4",kM''&qWPg-M@0eD2L`i'T5WFr`VB8Pmsk8)_Spj. %Y9?*@pAXCPY=626n_fJ;@7U5'NPWqI^]*'$ms]TYeUKdZCKb*@kh7\NhYI*'S_)bDV<(7+B7K^P`@Lu"rR3*"+eS/$`n!R\^4+*4 %*aRM_q!GuIkq"46YQ*hBWI/W5@<1Z0l4`pFh9B0C:^PY9<=cb']c1$+^%14Pq(1C9p;/^$G-7ouS;sDS@6?7D.Nu^L-g.bnkj"O"S2Erq.U8k8UmZrq-aXEVEpO)<(N9@3?_)@t\3- %?%-bi`f53t*e/V1_n>JrbYoR9%(o=:nDrq4N#3JFHSkM9o< %IGoXeqWhM_mPGaUUDr\%Yk?VH^MJ`DI> %9@2h@pVRMT)Z0>5U6-iL4S7UKb2l/JRe^k@&X+ubLJ]C?%*Vd %T`"9YHMHXAJ),D3Pn1#]qOA`H($m#\\Bj$Gp?cd"?N:ilU$d,oqcA:CpAP"r]lW:"hqn/-UG"CGJ,@YOq;8B*$Sorqki'e0TDeE( %UX=JhhEUO6i2%rrgj&6^@_C%%X["_Qiem5Hq3;mPIt%?oX5Eq5qrtcLE7"H;Hmn4KkICumr%eXe2_Y/q,lR;ToTu'IAmu"f%l5\c %@LgW2o7,S`>eP'c/"^(qTB#SC?Cm2V^MfWh'fOf.6JT.ls+aC!r',[:IrP;4]cZ_CFmd*M5X,2;Y=H?;!H[SlO$DO4^\R;IJ,Jo. %3$8/Z_Z0,?/tK(&7Ocs$5c:T1AC#=+1D4_fOi\K!Nt"LEF`")Fm"/V=96Pr_YAf_<6;dIL"F&]t>8,+$UWtn\=S:]C<_A!<(5h %IK'3:?[Y)/rrGXbmrR3__7@s`Q_TXp0u9HrG>@?f"iISS_mC8R!b/6O'.gQ+LKSj>QO]>k-<-Lbq9;-Rr:/855?S\6c#n$b+-UmIWJUrPC-JCHX8=JG$STi'-Lgi)<]UVn@fTM.8L! %,G0tiltu!ID)GpIF^).]>G>V3j3G(S4lp0%SJ=N]:7W2-pq[4bnU+JT#-!Sikb^\S)m"#h:u4MX/M/M9AMEO>Sh`5h$G2APUBQSC %)P^YhdcMgK[<9dOSF&lOr9iS\GGd6l`#WMsY[5]fUP+U]%Nt4C4n/V^%YHV$JNF%5#:l<,0&/`";W)I_5@mirt %D3VHtE7#*j`XDqGRX[hbeLS*p5l(/,^V7U[ %(\nZa!l5b0qAjuI%EVhC=U3"(GS(1\#2kn])Q6]H$GS(M-VA;)QIX94._3,]eJj.XRXl>YYao>ZT)h=_&M$rW=pf^p'3D,Yj %kq[AA221RNQkVeZ&l+6K9B5%\@ImWe7ug)q(EHqX9ph\S"5T;ch&7OoA)-!r`9eH'&>XM)Gh_Ff.>1bc"[: %^e719"80c*a@ijZo?s6d-FnkNM:%rP[Ol2Jlo[aHr;oRl$T-99@sgV'$H8-)=&bcbN$GPBg?<98i>R[P@!i%**$h^1GuT/8GWPnP %<%#U35VsIFNWUk\,'`kmYA6&4M\\4uB]+\_+rlnC80A<`^a#a1CdMm82EH7AHiaO0qGGai6>G/#>5=%OYbI(P1`A>"4s:*r8f:UI %-KJk4TFEA>#@J4HF[l.OT:GDK!U(AiQihO0+bR8+/41nKU&3n>H;NlTj]Figgn?"c4LVXD)N..>(\E=!VJ(NH+%95(#Sd>Yg%'"i&>&rdZea24r6gfEMn,%`9Ydl^[OP4tAfo7`\6/EA->c]<6K!-M>etK?gU/=In?kCg[#%FVbhh^*;8a'Hk9??$-/oLcD?@h6$*! %g?@$OVc/Be8!'/S>+/1TTWX5a)Tn]f.Y;2L>]&%0EHBTgKTLi:8sE)4\;E!(d5nkB#p>T?.9Y%mZ[p/h=W!\7/]KG+ZhrRs9G7X. %A:#)_nQfeTU$t7<7;$aQ(3@ktZ[i5&if_22%ssT-k6uG/>al4(305P=&<]#4RhH:s]aBIgm$.0iXZj)s9.$Vu4\-O2:[1?3apW^= %bC-Zl"(1Z>Bi]E+C>bnJO>P$9OLE!75[fXOP(CUR1W&O-(Hr!3'`f-[8,&BTUBBFX`NFoN/3!8CLd9Y0HV'Bpd_iY-7b2OQ`@G3#tibAk'Z& %89b5D1PTY(Uf%9F!%C$7,DLAK,A:;5/dHH#NPc#(&kRf6jlksq'qE<8HMLkZTYeZ@<5)FYfs4Zt/bIpN$P`Np*d)8e/hDfbR`%Gc %8SVbq709La.%Fmk_bh-@XW.X!/[SC+_S^UXUbHIp2CQngmQicC>+^`l+R_4IE@4Jl.5EJ4RS&CuBT\XX7UM:V[^XZ0;Y3ROYd7W5 %f^End1LT!L65?@<-%VJHKl<"_V_^T3`nN+%\J19YN\!mBSoJJ\F_-P^J$k0=Fn'Ulq\!.p"B# %UP7a2:u_NrAqc151P_Kk+GP&B+eVafBkTip.hm=rac`ihd<:&K9t`lQ(65smDRY*kgH>,X]q+8XckAkdQo?CK+d$-@;k`D> %@tfehc+/Nd>$>%jm;*`C^S?Ob_S#iDhTe3aGIhdoHU3+A)=;Z7 %P*U`"ASAZ2MGYkkc"of!op/g2\$EZ,0CWT.0!uVUteXPK#c4JR*j6NZN8r7Xsbnu'GdLF$+ %EB9$ZL?&U,Ks%ofTV,u6l;ZQ4.[sR/X+_eh$%62>Tqi`_T)@k#2PE7WQPT.FfE;[U$5I;6U%$4^3E*6jr^CY=AgWbb"sn$RABAeRe+ %@8s!_+Z=m=157-AYmI'8K+$)#]W_]K[]kTX$ccck]1&C+()E;8+GkYi2M!J??;,9]:4c3uOQ;?lfFdhL;6FLD\R]+\>Er!A5o@8s %*bD8fKLQ1kHL5YOrfA)^"MaS2EJH;3?C225-[3qnFbk&3S`N&j_-&k0EKh2^5j'h(Rth?jfKcFk"P<4!Vofo/3a=bMC=WAt#_[sf %S.KJO+U.7Ebo2NqKCJNGMQm@l[]kKU$cdYEGnt2`*XbVB2e(8oC[f1L[&tdo)*k#;X;A>-%3@>nXc9?+""RTc6_f3riX\e>_.2i1 %MEb2L>7^q&__?np3[ad*c\b/U&b=@dgrig %-43.^O/(os:$=dMbR-_/WM"'DDtLl4?G)?Ef\S#u,R)[+#%slS %*a"Fhp8;;R%mf/3(dlp$0(`VM&2jTEA*GRKlC4ju0YL'_PSjKBLJ^tiK;n47ftp31/qN\H%lB>eUE %$JKtLfXA5c*f%bYW+c0Aj'ZQpEO:%FEM0_'/.HtD)=0QpCc]S?i1ht1j:9tmeM%?aIiOFhO]^o]%ef,PE>8%e-lF*!-lR&&VXVtZ %4+!*SnZif[CXbT2@f^_N\=6)6-hZ[)K22A'd*$p+-[b`ND[eM6iM[b_H*o8"_B.&M/>o"gmJKT:n>G0W,(\Ii4n&PUF?D'aq7pR7Flnuh8=M;=0 %IMQ2gml(0KA?NbtUUSr-%Kegd/ShQ"!j^R];Sp543cma;I&gk'K%o87V7%4H7hd%(p^.B#5QEi8"Qm#s4]Y;fjsghAWL39$Kp %gjN>;f>7aeE]];h=.C=s(hC:64crAh(_RUO3BUs`%]kqt^#F:iI&YY2i1r!50XA4_eb'[*)>#?*p-;r(V0.5]`VQYg[E8c#Bf>CN %ILl-goPKHB_a22eC"00dmB=AR1ra`_;H7UO$nNBL6*m*^M00YCIIV#b[7UGV+%f>U"\63B:R`/ck$C1?L>E_93TH %d:hL+:3!mQ`U1(9Y\##6WgZLM%FaE7l%KQU8Jn:=-@qkAK;b@#GgXAQ)YHm_7qaa).r/_8,P5[2@&-j/i=W/67eM&!SEd!a`W2L) %F@#dfY\Abrglk7p%ck,1O3k`Q(k]3T&JX"\\;J?`OKjF9]a:ijH?ls/i15+GFQ;;UX-nVF@QO]3:?^dc$q[=OH&P;pbr=kr*b,g_ %fut^F/K@]S3:$_dX[aY.:=`Z:>;I-":PDI"OJG8RO)kU9%30t_24Iub$_(fdE)LKRUP`hpAi6'>YQsQo&*#q">3CR2oi\PV1.#<9 %NOp^13*Y[O"Xe$Y1]Mm5KN4\/X&-L5d1kA]Ahda;@gJoW'3rd.f%bAK-RKnER]sNg&mBUC,=[)J>QT[;4Tm6>6;%Wt@E'R;dD@.I %%3/<1fPU!2CL-H_cY-ZMYL1qE'Ys'GR"Y-AYYp:G8YEhPo%M\hJs@o]U=$bJ0aS2XWD*937Vg@d6+7Sa@1oF0MX6Zn.je+_a@ijZ %mq*2rPnVtPij4,Xou#-/=$H_oKMq_+-[4Q]IIe+A)-u."S"K'PNdL<&gT&VWg'an.UO0F5*::!pd%27oYk8'o?BhE)#gb=%9sV0? %[;apUmAC\49e/2S:^.t##eA;>H\T*]<%)KR-f%Goa8ZEh!>HCqq2hY %ljPaT3:7Xs]3iabCjGd/08S8)W(=8BrJJ6!R(>S4g#JWitj]E34BdiN)cL(b[7Mt&K>2Hf?N %JREn,l:)X70?qLbg]U:;A\i&L$+i:5&@D&@K;HCtG;ss9emfK*(%0pKM]D,-2n*12L[n=O*kcM@&q^2hmn#5&8dq/?r(Pb??qt,M;8Pre %-HKpdbj:]F*?$K1-1m3!7W9G1(P&%o:!":#[p7=MJ_12jgpIn'*g/._ZoAkc.&DNbs#]r>NVZRTYj;!@l %.1g9)Z?_.f:79m,%Fp]c_jA;<=kOC?[OBk:=u[f?)+.;_d>J5U[t*B!20tKcgsHGp-Qe\pl1#kLe>jX5L`*q2a##bSPq?BDG40s; %^"n"ODF=+=pU((oYU^[]<\s2uSa#Y^LT^D"6Q)q9/[WnC#@9YXc?Am:.G*R8B##)jC17VQo[5IQra]+uTF`_4aMJi^^j![NTCBc< %=M_in)RYXI)r+k-H3B1TORZTo@h,0]!$.n:'eKLK`5MY3je/o=.r`:_6id(hX2b[$Q;+V4bgaBY],+]c%_J` %raTfI">c8ugsSM.?-S,[fd*"]C`(&2`-\u1L1,]rpnFM]*1[VhLn(;,PD'SN.d4U&0k+IpE8jpsA#a6uFds)uWY@:\ZXP.f[Ns[I %S-gc)E[1uqEFL.uUtlb5/k$X&hQD?+Hrq=$@tI^.(c1ZX+D(l:_khM$=]q@3+-%Sa3'Y&t6$Mj-%,*=^R.4U>G2^>rP1o4>+/W@R %-^bLG+9t(+)'$Y%;-5MY1AjuJ`L2qprY.aU)CY!9JBh#q0Q[P/5uA2)S7B.L8"!G> %jE`jq\!)(*.:Y7d.0g`7&++;GKi-`,]:]L@0no4!Mf]3d,,SVl%(dNM*eZIpamq %O7K.;K8f?==@o,4Z7HI*b0kMmjjVYB(A!2hhbqPKdbl7-YKn$^R*t!FB:m]%CgC!m\H4XJS!BR(TY!RemL]Jf0&*-!8]g0LI#in8 %]s5>qmds]8<4Q6"A%H?KAB,JCU5qW7[r2ks1uS`.IDZl-V?dXK;u%2knfIrE*0d1JA9>d\l&To-9rn,Q_t>'/1T[,tPD9Fp.tEWj %`l>NA0WTZ0d8#j%M.*48Ic4f@V'%QKpob]'P4tdhM@_3eWeM6b= %8,!Y%6]MF)LJ\:VqMl`<0s-Fmo!Fi0MPlW,B)U2IgsP=Ol4fUkO0j<:lrP"m<[r`G)47o)Z,9cQMO#F-&T&5Tp5C>e=4*D/oe_%8 %D_uNiZ6MjJr-b&"o=5=e#*N-E)>RW>NEK!H4qj[^F,N"@_^1;(-7gk#F*4)hL$l-eg!T5aAE4NhEi/5/M-P3Cu!$P %'`I)n/B56eB=-FI4cbn,54*n6Mh"8:bU'8hFOgXBEmPN^?TD(eab\-`;In/dB'@`2-SmCA&#hB'`Q!Gs^[V8OW:u48:7K66\:$ho %%3\P]OQa,"*I6@k&ePT&'=d!Dlm&mai(($JD6u.he"ZW&]0-7_KFQ^bB=DhY(lYRLM83e4AAI2DiXBBf-?h_^a9##Sj_&-R"_^"j %XVNs7MFS%'j!kNDniF?GU?u<]]g`>B[gn3G!gV2mDE+Xd2u$e@0$,]P;:`VYkPcmT[V&pC'f98&OO9lE0K!$pER=J`$?QA=#8l>J %O/V;KI@Srq8G7gYM'N]7@>MB"fV)>2<4kXdi_]FW4aT$UNW=AFUBX@SHKZBOD@0.B&5%*3&b!7a.\]DC5q@8P&O9ZX,tJEG!_KoX %3Wt?+!qdu4'/hg[THTu5;HZH4\7:9pG+V1R.dV\*+K7^9!g,bVV#kf@CT9Ji-oFk&,.uL'3OL"(iQojo."d\c5eD.Udc2D\$fGLr %4lcnlL=4Han2IqTlIV^2_:?r'NY4Oq`b/])VGIm4eQCFG:+6i1H9s#V<"*Y>lk,VndPRpo'$T#")tBF+N1P\]Hd7aN!d_6;Ob*-/ %BS(hGfr`:=$]uE'1@Bs4TNjSqN0Men,O0Cd.F2ZrZuZUlPdU#(\^/UX5PJ$AGBAh\Zj2Tu8SaF^RY/Q,9>lbMYB*e10RIkUZjMgg %cT(TNDJK/fU9S1IPFH6"i>A)R%P.H\F)!\8!c@')i7*!P]e_H6X\;E1Er\\34GK&`C`i+H:#?26F^o1+i %Ehf$YC6XmT\O1=NP]MGCHH)q8IiB8O8j6!Q*LjbB0H'T((aXg9\+gReURdA!0JGZ*R)3AjU;V.a*cc!P %$p?jnYP%F97h+Vo:!)0=MUspE+W34rZEh\&g1]G5N1sM9h)#FabU?(iFp9a(18AL`RJE&sDklWWU*=\R&Tib_$qi26g*U`LAeP>e %noeV'd8H3s6lYh!:)6]aq*R!S5nt)RZU[@-M52Xj^VXL(8cuUFoRr^nC=pl]=5Z!j'e*M)%u*!2F3\.4d`."^%Oj %<]b/6"W5c+cr'H:'OZnM)DLHE!Xp?!E9,!c>liMiD%BNt=p%eM#liHt63Ge0aeD]\f7:,uF:[,/"4fGs0rYE0J/(VL!M@b_=+E0r %Q8&YP/&7M^fM_FqmL$2,ERY%Q],&O/]c?.ki@CPZ][Yo_Qc&kg+(AW$smD_K=2"gKU27oLRTcKO."&(i''nniWLbMAjPB %4`"C`-<;-TT#ZJdA526N@A[/cp='9okSp6NSGr$,'@oleM8M^UC:o8M16bX9ej:>;2XkrO@F-tJ4XV-;@q\:\%I+dnm(0iO6!'4AFggZ$ocq3dn,!N0]6%[96#DfW %oE/eRL6sFR?&gDY'EW=SZ%Ee=nDfE0<'$95jE70goVNcA?d\0C>;Spj)eer.aM=.)($DR/,cX9-6HZhW:e5jt3RKH2[*\uh,\dab4n+l:;O-)[jAJ_6[/H1+ %7qG/\_NLuWNb)5E)Y\COb"ANiZ;O]hT5&-.++`Pd#HZ@;nb=-V*@-LKVPPDiY %4khQ8W5bcL-CPau=R%2\T@GFKe0jl@8*0B[$rHCu$8U.$Gme&6'o;U@"mtq*;GPPBR.V/Y4-0_:J*SPsFJ/M:dcDpB+QW\7dl$cN %hW:\X+@0.fQjeUGkut6LneNocI,^t+4e2fe(hJWr5B.Fn@(0s@/?ol[$`b3iGo)_BiNN.6+PcW>%j[$1!DU:[M3l!1<_`%Je?maFuRWQ %8jGZd#rg'fR10*#0[)M;HCqAM1[rX<>@E$!N:R)$'Ot`q_[L-C(I"3R(hObBD+;!gatVk?Kb'69,+T0!%XF^kTf1.T/YZap!DG9j %1]]7!;k%Bh[aFp3!2^VuqWM6aR:[Fpb`m4B]4Jti"iSFVg+q\RlL#^uKi)oP=N7;OHc-[hbroMRU[IO_><"KaM.N3g]1Zu!eD)@9EU)sEZ%Z+tQe90SHb733:<&7ciGKNRF&Qctg0>tTO$:gVMB:$.Ur %c9!+ZliYU[&(D("BhdaKBC!JZ6?tkPW;!jU'0#)On'd$tjeY+0hf.WB,r(gU:R7&*;>mIV?CjPD5t9u7-r^-" %ra[(]EI+-QG@HRa-O/[@=7oOBo/P$1TdM^Heuq+$7bW[2\'inGi6khDC`(5,es-#JFJY%NgAO'S8Sbr%i[df6;]]cF1cFI;(JeO> %b47AIN>DLg4q:'Y7N*5u-&j`>%-:V%8dfM.(d8GV?R(Pi&a!J8CntmCYqa*:/rbjTNANQ?j5JG=8@>#.`X$du1cA5hdb$gG#>8PO %S@X%cS&2.m8X+;]hJ$d5Ve.8QcDeFRZ!j06fL-UTm[qLREU%!HAXrUrUp4@P %MN`)<87PT'5t84].ud8uh,Cl]Jr+^#b99@kriuu3Y1:H$=!D56&-Vtp,N8HpL4DC(>TSt:!P<< %T?tJn[..uH,P2Zf7uW4ZisR[`Lk21PGD*M\T49:dre*Jf'[hk;HIs^"2$XHVB[d$([07r-7-dt:$;aA %b/GVD9V+cKR2DZo4.R2O-PqtWE.K'DD9CAYS^%UbPY4S'Qp;1o9u\Frhb+ojlr?ZbPl-Xp:;0lY)1=O\bkSp8n6JG1@%gHR@Q60#]K\RBb4g#P7UmY_t1@k/E)FGuuU2u'UY@kNRrhW6/DBji]2 %9F@HJ7!T0-$mdB\"mk6nYU!Or_s=,'`+s`EpiSJ!j2T^dp!rdNhkRp^2Xmhi-ro^Wl?%I((YUAg?R[<=ZeEI5Jo7Mn1%[(gEECL; %VR.kTHlU5n.h*IF4ut0,TA6B4'4X*_C5K:OgTq,%FX-c6r:a%@?hlF+nPS#Y2?7O/2-'e/$Obu;TP$#3LWU4K4?a*h.&?db<%!`D9gBXIr@84^XP-Z$#$`ZnA2k4PSMpLum:#i#(Jn5ZX%ti7-caUJGf6 %*9[AI.HG;N(mrnYh]PE.A!q3njn7["im;1%g:Es%e!Sa@@:`^o0[1eW0[DZLm(IVLFhof0_#(cTq7ruKq+%(,\pQPOm&OhEV[Q7" %ii%]+'.8S_jY,WsEPcIB=@s>iLFj]_W3Fcq9bHoa$1D&u(0/kq3CTIBRNf&#r#8RmgY[EW90=GUHu0^hf;?n_2WGHFXHk2s0NKlk %3jpjKj%I;;Bk^1tH,9qdj@`F-+tLc"EGBLZZVPLR$A%,._pH%QKe/N-cX`.k9qc$t@&A*YBc+jUVF&a"Z53%b(V7\SVU3;^AGO0C %`N@HMWMMT\@FUOh;q?%&5tVI(kTW'0MF*eg/nV2ZMl^HdG17^jgRM^)F[[(R;UMJLC(OlR>Kb,t`[\:899tX\/T-"08Zco*(&>^G %?s8pk'_uhuU0+VB7)F2bM:D'VL,%ne[f;f`=(B^NHneZCg%VZ %k#l4(k1S#_Z!*Jf&F5M.\!.Zk++7&Qd\)BNW[+1+Z`EVT,%M)IXC3)bC&#QIg0g1pB8p9.--a+$1h^n.Ke)m>gcmHNG+I%i`PmZO %jY3E_%AA;r.r]g)EB6[GZuRl^F(KOD;kE7MD$bTG2Y5Ec\V9I;\&;Xqqf=WIQ2(&8kaCR!^*;e-^c3lSf#UJTaB6Di=inlIWC=IF %Xg$g %8cFQFMd)g%H:sG^::2nebtF8r/=Z0dcW3]&fci(_o0h`;@2N4;$;D2U>0IYO)/ZcSA1&Ek?CB>X\Fs73GpokX"KQ[dA,+oT>*e*=_L`%mUG<,osOQZZmHA8m?.`AA9JWBi/ %i:^WenJ.c0_%38UZjEGf+C]@"36HIf7NI6ED@QW&,#$#eFaSoon:_$7(W.;J"Rubi!!mn.-$h0gLhSSZKZ$E,kj(l)lBEi(KJCJP %m+8##ic.QsD5XTd0SK5Z;rINT8oE4b7i>gL8,MjA8kah43l[3J3uX_,8W%+0KnpP[e=fI5 %%YP4\"2>*Q2?P7oOCLo?7QnUJaIPTs>IDcKo2'8B@1h3?s#N9!j=cpE;Tr"+d1&Tc'6noR]AY?K;:`UmMpeW0)!E]K.%q^q8,1e&5r:HVH*S[;^rKlOP3P!Y^0609BF2@!KHfd?-Vf %)ib!O!Y&8)Y01!^UTB153QoY%e5<*Q:OAF(Z1/q;tg2W(G509inX=VL;.= %/1p!coMJm`;Qk)gWj8Rra1]l6iC!aN8?^(T/Hl@Q6KoB&%GeG^kCRS2.ZM^M4u^gk=oBXt=+ol(#h)>=Y;XdT %'IM*-#D'G).73L8TH28].gsiFprj^P/c;.@YCJ6d=^lCG!o:n]U7DD'%S6^*h,Gd.B+bmbRXj0Y'.ifT2L=<*W,A9#>-;kK6Dl;H %,DAA">(C9H.pYtXqWs]NQ&kcp>^acu$9&G[!(4FN)6K5/`4D%jH!,\6aQbEup(b> %;q[!f85$"V0ICA<%4ANH2.'fTCe+$\M!e(L4eOJOX@K>FKUu"*1Pm!je.uE1.+DjeYO\uQY;TQD&\b87ZJ!S!.V>a2>C;Ao2Q?k%6ckPq.`nfo@6kLIj_t17UqY>2WLiHP_7WJWsgR2PVpej\+sc(hjQ.2b#$A4'rWF2R.F=< %o$V:^UWXB0)8(iXR05R@;n./O!fU?8JXM$N@&,4(cQiQT\eOr^[UflhO$-t-P2J_R?;cH*k"-El1*e%W:(MHE8NiO+)bN!t*DA[b %'D1Kt#VkNTFsdJ2U)lZ1+\"!LSEsm\KO#j%k^R;t%?,m"`4.+ZCta=TH\V6GrbRJiO%GAf[.?"i8YEaZWlVIBodG@<>,*I%k:bej+=dl=h+a5Z&YVBRg3@dGtZu@XoYk<%S=Ce"fll,.t6IUT]^; %gHq54#eRFSFti9bBn,dH"8)brWF/=F7\>:E!$pM1t,B:*=Omo;dlUVG4qDsd+ %=]SH^2Pq^-Ul-BANMWtAUekA68Rok'P!Y30(H%N83g.@*ogrZ83g.?!HECnjpXYH@[V-u_E"jLj"k95#G/%&kWOK[#^Z_4)W.pe>1;!R@;(h.8t:IQXq(4@AkbsXd\=r(2RVT %M[)t:_l&Hm8S&s7Ua@N!+L\*nJQ.+Q2+bB6RY1b&$*-W7A()mL.Ep9eP]MF4H0V,m`6/oRWR8S^W(B$X!*2,/PYcgt %=,BNWD05GfdVe[%P#L#C,2Q6s!qJ*SRS^.7)13SI_d5&\WK\r;dT5bMQ&_XBaA/M6/VFHQ?bo9K$R&"XRq"%Wd;:`I:(W5R.b'=d %6Rt##K^urMMH\7s1\:rf&tFSb)fVC5ZM+to%od#Ke45)*u(Hi)DH4oE;lUa.q-b1cu7RbF4%nD/Yr;dY04X(>eS2qqrQMBAi;##SZ8dZqR %0_P)3NP5Q62.;^O3^^C&&K&E4o7@H/NR=X.!t97*;:edZTH]-UY$+52"5?%`9qepMQMMXmkNe;m@nMY`T7'TJF^[k,EPOuef$[N2 %=rO=!ht`5Co_bds)gn;P6,In=1HcC'CK"YeD&A^SP-pZi*;bat)glLAPa#1)QRlKB>28uBdp!c=`[Bf*ZaHdZZo3H6(b<8C\2RPM1#RGMA) %&p?m$V64UV#UneAXBL:L0^posN"]5j7TP\%imcu=B:mZ\cR:#F)M[CN.?q*]GbL(DD$h:n,r<4bCVqj72AMZmP-pZi]MM)32MEol %P5H8s(:V$To[]m9#ei2*c"g6+A!ujR)>Vu#3lXd(H<8[P@;Kd11sI:]1!b*%FX72^BeM;D*^@LJp%/&J5IL;jhaI+=mLfqB6kbZI:NH-,V/V8]R?5,e^g$"L@u'q//M'1On=R4qZ7PK=Xp3K^qZ %1_l7AL7rl:=bD":1L7)J-IYCiZ@#>[EU0r,DeUtTW0X;Ie'_dD %>G$=A9=%\fUkT&Kl\kJIc),RG5r)54+K`SgU2Rc`?uhK_.&1u:<+@7#+c[RjOG8fVTEI<$3jde@$b[7i$V)j?'ef$QU3OY.n[g]] %qVnQ?`n2`Q`k2O"[@RPE`HTUp,sIar'e%`jI2JW^ZRBc"0%MAJ8g5:+cCGm]T,SbN"BdiD4^#Q!S0L8Z>0,FAnk6GZ18@b?JYT %V1nIS&l-;7RE)3TpF:9bP+P'%mmU6FUV-5N&-E@oF$_#Sp^CWm0['c(YKV[N.g(t`j5I#hTS\sMQ:7(g%qer %"!rR20l0[\gl^_:#r4Cb%o-NY2_n;uAgB)#64ukH=2?]bPe=cR',S[[fHV9Ro6As*oNEi:$J-e7>)_c%5;1$_(s;YYBq^Nhja))o %Cs9+FajIkAt;E_4:@[VGiEpg(GoAGhHnMDB(g;9%9k$Z1!Dh_EG.cG:?$n[meK`Ci"OQ[Xhk>*_L\BFMZa,FeV="F5&=FD&"U %VtUl4<_+aJ`40J)*_758$'@Vm?tr[)l9$A&SeKcR@EN[_mTPnr`"WK]*d.7<4^tp&F:a)r2AiR6jK=1ql>`LfHmd_"?-A1q,2J$Q %`$Ko8.DHLa8@m(rl9l9LKa**FS@6.e9gg%3(t.8Ue('-ZG!(&++X'n39P7(`"V.jmU'7BobEblekMR^4o]3>),sKY1O,Z0J])$6B %0[\f$'7g-$0T_WgU8/O$V[!qXoU%el_g9c.Q?B&Qp"c=)3ONJ %Jo\"j>%j\-Kt5[`ES[^`b/)b=;&CdK=d0<>#+Og[Q)!kmUq=c(n)KKZ#P4`@.L1<>dTbf]IT0S6."5-N;`U.GGT&6B)Ja\a=Raa@ %:^8HFMQk1..-*6:;4'\H;r29B0btAXN!ULYIQ(q;poG#g">Rkd<8Ri`\jK9aNZFhuMB9$'7LsD%ciD&:'Lk$sGBXH[0+E55$G9(I %QrPH2)#>$`/G'=)*q56]@>,/t*RB9nHAngoTgp-@flZT.@$F^I+\35WN+%SuJh[KCF=9Di*;_I+9Q`+9G[_TZR%4dL %1sn*X@$HG<;Pc4cU8=_-U/SF!lHi?+eJK5sFn?iDGb5a"D[=>tV\nLI,D@24R2.89H0Emjnr=NNq`8m*KCEsq"UM>jFLnM&=p(9;W(N`TL3Xd-g;Fi(a65qL.oEb[3'F`l2TZp6Yo6).lF9A`>B&r0Q68A2% %M5F8'65qL.lkKm,M,ClH#rM7/K=aLe04k9X?=Ys:^.T>D6.q5Fe1n]KL/N&7LR#5dM%6WM"[HP9jA#lKs %UYLj^2Xh^BA"Z6C`*;g93UY>4Mu4'n@u[[?"3!_[/"t=q1CA0j.n]p,3(;IKPMU'5kY%%%J.*f:/Jrf\`E6S:5+>fjE^/Pf0sV4> %G!8ZFGm+="^lBg=OW(0miVYEDC>]EI[8I+]4pl(7r*auN[,?(P`N,CV4)(i)!%<%mGZMH)X>boB:1`EY@ %hZVNJ$RnC,L=L0M\ahMh?SiTe:L>6NP=IO:>:dI,YmpnEK;p0Q*K1O??1nRe_#gVI#[VP"o^8u&rjIYL9s%ML8ekgZ(/DHaH//k!ar)]u%l&B*--83YBr]V\d[5f6t60;8UUaZE7.+Ob8u %"oH&)Ga@QZQK$L2kuj$;=>`NN.Io,ZRAe>5BVYGtd&Aar.g`d*:6pDj>,5`d65s2^6U1)if)@G3IL7j;'X6noNeB"md;fYAik@j= %Y0'LKFK9s+Oe\`kF&;'E85#ZH#n\LI@%o>BRFKGaBVT?sC#/GG6Zj-gc0j>KV4.mcSG?h6.H31WB[,(^bL9J=/5WeopcD'sY[c#d %S+oMdW?o(\>&ku>68:ugr6/AYUK_38`0e1lQ73K53Qf:tQg#hNkoR<6]>JB>j^Eb/+Z>(RO$;SkoTSB`=e %3iIkZVl.VgI!W5TCl);J;J:\,AeRh"(lS'?jD6919Fl$.TFJk-nu$#][\O2o(_N3JlGhPjJQM?c. %@ZUIp-u]8a)O/1Sl]XD^^UC6=Ij6:0NNIqTM8.?6-SEV1(YdEB<]J+XEkOb/Rpa1Dfh5K\,9nM+_"(J/(Y'hMR[9!(<_37GnB'J%/;\C;m\7)'$j!7'[l:m@??hS$FX":?`-H`^Oe%]R`-0(bqMk:,fN-h3kN-]#t>g3YV %8UP@(r]<^%pe'?GUSD2Q,ZHi_^e#+Hgi*gHNp5k&od3e@:JN@%ZA2O_i>r6%$KRB0Co#:fBZ>;=-0^%W=HY9M-\KNmFIr48,a4A^>-h`O^K>n.+-Ys>.% %gLpT\PB^=tg7a:`Nh_fP0bY"?7+X`1!cD/F",&(+U=l0`iG6uV)i9Db>RFOh>)/1.N"YLO]BOMC2+G_h`@;V,MecQ515?5%p\Tmk %Z5+4T,$d'gQ?V_F\cWof'LO=>3%+hBM@9tHOAJ[>;]ZsYCn-D]&n[4l+)`(js%^]=hW#,4;\3RTiklSf2aL,$4qkN,:lMuC+nmlp %$Z38XO>Mb1!QgJN2H@:hTi2]e>>PM>"!i6jpSMpOjb$]Bu7VRo^^*n86$:JZ97 %`[>4^>8bJ7)KAL31DaR6OYn@>!1mpBg+-pHemf&0(Wd1VZN*>P;i7o?SksB$QjV&:3G5N6[@&W?b/uL5g1]GEfIK.M'O0qSN2WDo %fkWl6,:tLSdC&>koQ27qfRgg4WtY7pU#rNg""J3Y=&tLSf<+n!/,fn0.nC:orbBgCDMu7bP]9UP66"bCY7r@!Mn_$SiicCY8)%$X %L@Wbg-eKe9oS`oUTIjE/'\39X\rIAkJ3\Y%Koph27A#,PnL>`EA"XjL=7Lt(,I$rp'MdqLG0=bd>("[aO0>r*n24pFZlUXF'nn6Z %Ce>^0[(npX4hu%liraGfn^>Y#Kf0r]CV_&1;ik]#Ru#KSG%_T60@;mUk[;$J.6`@#[p9%[6^h`P)s!N/0;kbprHa^gTI<\T7__Ut %$gF_rV37sD@MsCVd1#M!6kDJ:+Nh\F5n1Xh=?Pf%ip_::ohXib35J/%]2]44 %eZm.K"TZ?R?7nsPcbU0D-l=BC)X`Jr/j2V)R0?'s1FC>576rq<-nVgRd_[%SRe:QhrWobr3DX/m'B?)d@H&9:W(*;X2UQXSPO^1:MB?XdT7^=6iT<:hL*>PaMH/UaUk>Vdi][*b08;I9g(`FXcO?]#72rF_RoUhb%2F^83GBeP__Nb'4qBToErj9?t#r-&,IcP#j5XM4mF9Qb8D/Tak.j*/`?FH0MIaH!t.PU[h=4 %-&3C,<*jld9-/5OW4Xg$aaoU#/a`9"l4VrZC/)0R9O2[`!M6ZbcKZ$+9bS4GQ)dOff.JL*^""D>P.ON492V%Go)kKtHO+c9UN/]D %$WiZ7aP<^j*(!s%(^*I1>$H#40pC4+GAYH3=S8W*0QkJ<27?)%l)cR`fGH4i01B/e!>?;3EiECc98Co+OhTbk8b/?\W0TL0D0M+e@_=E.2qfZLGZW_LENI_q8_/jcR_Uc/'C!j'*7KNU %,R*\DG*I<0b*(M.X+a:iNbbAFGE'FjaTcoY&YF*!/73u,&r9B<&Eub3!-qA8_]Ck,.?$$Cl6W<(p)$]6S"Lnn3L-F'mir/gUPV,8 %A'k"4sXL`OHXJ[Q-4I'$3bnPP"[,R-!t00[;#?2HE49,sJS6'"LSmQgM92%7(&1!`tB%fJ(j5](gH8LX\=7i4]hNf>]HKC1.p %$fja-2FtXT10pZ1e*pkZ0,A`2LZnjo>#kGU%M!lJDN0mkE@uigBpRk"iA0e.KtYoi49Ya[cU4-a:-dPKB)cT@R`?83cCQtZoMLYDlj4.%rjjPn %_@BIBK&0b/$-%iQS]YFmGdWT,@lA$bV?6=N8RRuj#+#RGeXI\^^cSqK/%K@o5Pi9r3-sQ/K>("sc0c=&L.NrqPS2qg%-MFA%+n"_J+"ASAl(s'i^Xj)Ll!.m(bKC,?1W1%9,oosEG#'1Z,=tU]N_(6bg)75X^eh+T$MaE %,QCs[S6E@@`h>LD-CQ5W'=4>;\:F=kTZn!VKV'g&C?Tg>Lcq@0J'OasTsR:Za4SLE_*jntB40UCSen?g-022;H!c6RPFm"'@pXB# %N0Z`)0WYEkU>h?oV)/j[N']n5Y2uKLoqPHrq1d$66n-5Q;2B77`G7&lU+j)0S63b+-rqmW;;5*3:?Q6\:N@-Z'CB[m';P=``"?*O %L`(#[+CaKV9Eo3c5m]0b6GbPPQE+Q^4mJ.9cYf)V4UFoHX"r@:E`Jtt7>TZtGrcXpa]03?8\$=7%451gMSfQI<\@$GgN?;Ij=ntr %+utFBXNp[k\6"oPPt>4Gq-]N+9C[#%GKBngIck=[>cA%tANPjQb\W'@;'bHL6^aXP1scA,>7\3EH_%9oI[EiD32tVZ#UiMbAS]]f'"TmYKi]S_[TYXO.nUoA'pF(SG+.FZ--GgP`i^ll?4u,RCBQ9iZ>s+Ih6)*HAi*ir&qF\d %H494l,&ir+DFuHa\q_lbSLsC*Oqphgk&n:C6`o,0Kjkai[k&&RH4.P<1@B>I'-]>.n1EQi9"p^$0ZgdD*%(NfJm%a%Y'`RcL<7/` %g)Nla/X+0_MjIfs+Ip:1bc5m?i+FesMKi-,Rhg^M>8AlS.g!9`:6rjl(c>.S:b7Nk"?u,!g9*=c]!LM&>1-m?UA)aYDRVFn8no`l %M#Q,%QE]ACaSLW,:ceqsC0@Re_XWK>HrlSo_Da(p.:EChAR?-j(h`Q];C[T+>8<2pmq1$EdT(6^dCP]7_!am'#?]X%6-;M&BnH(6 %0=lna`.#YF2Y=rJ&g,lT2*2Hn->I,?_aU\$H'kP<9l %_#D!aA2Lg-h?_bf^-J.h<@5\aC(i.`f@h-Q9,P*m)&qU,0Er5t'c)m8'heK`]&)(a?rt?nhT;1:XtpWYQ"%H=4CaL!S3h0EmNG_:`W@O%+4TC]a7^[5!$_JPZ$[H@.q6?pmEj.,q,cY^ %RUGG[KbF1K"62S)hW*RN0nr!<&IpT?B6;&L>eLI7lMR]Lh#-l+==WEMS'quTQJE>Ya)GZmkVkoUVQA=s;g)"2A^'k5_$pKT[@jrOZ(TTbUTB$3XCKh6_08c* %&-Kg.$o=9DP?8[*h*t'9Kg+p[c.F;\Y&kVDMj_9qo2#q'-Y!Ls!)k-oOZ*j76@=l\_$pL;L.*(V>kk:E'4fW@_P6&=C67b4n-+3P %Pkt!=qC@1;%ZZ!7+E,;t;sb?$.W_>Y0[-[1A>gE?a\c!/pk5-.S/$.`;!Zs0d\\kJ"F9s$Mb(e>S6,Di@8*.YcbKVe9f+oLY6UpP %9YiUjEu5-""))LQjX/&`0Dk<`ppBX4MsTDSHkmg;IHM8N8(-/6JB?D3Ue\-3TUsH]L1(o/5UAab.lY:B4!,8QJM)91JWYPWJ3cZ' %]+D<'B5kaRLMqbH7D:2#Rind2n1gf+YN0u"5((<<;_#RVP]pq/K44@U.grlG@!SrqW].alrS\s3gb<)7O4N$SC;nXZ^[(-QEdm\4 %4f@e7Zgjo]>[c&Hj-*\42NPCl$X5^#:WsI"k<35*os/A%eDn7Ee7MZ7_ZgpHr"Kp/MbP)M!`H#T7Ot`XL!UN<,6%]s1t?*(`$U3S %&W+!D7b7uBc*RmB,q"&jf7A:tILnJ(TKrab#YS>-*MYAEBr?JT0$:S+=@6&>^KJc:C:UDK/XmSaJVcGs/92?'h?;T]dLs`Cmi\QL %/*5Pm?;tQ.6*^HM)"F.Kk(.-mJCcjEH"PJi`Yd_hQ(-^?1]W$35TG`_U]HF02W@.SQNf4d(k8OA"tK3R+*AEomg0t %%i16uNhq%8XMi6Q`L,3sn&G-Z'2f9a3Q;TbKK5$C'5_PFeSSaFH$bLcj"ZQ-^!U7N)1r2Ugb#$D(Qe1E;SjiSE"p$%8ppgiWN %,#82.Uetggo,D(!)@Xj+kI5tX.SKF]\:/n!BHljgpIIB4X\Mg_;'Sa^14:MCa:Z=VU!jjB=peBbKr4-0Y_0'VC-P9QE@AVQ/")*d %bV3!7BS(#2*d(kWk&Ir:B\e;4,LFTlFgQ0SAXm.>d*H>]"l(dCN?i5`F6sa_.R.Gp7XEue6G$no$:[q1G)&7Q(mZJ#)[<$%jZU^@ %V0Wece[(,B>:W/u6\\6K.s,GEDHLBU\7$Mc08bn&@F^hiX1leGdNCmTNC+=']=TJkPf^qtNt[SEk'Fo>XQIZ"YaXi'n"&0>hI^O" %IQqEeG2jE60,0TiF4^l-gn<^!"E#'4Z5U\Mh6?0=OB%o2S&@!tkfs`5P0]4t"ZbtX"E#&Ig4G4Nfr*OUN)a1Bhe*V_f8@^RSeLH0lH@h./!fL0UoCKk8mS8BM1PI2.V4!R1&RCr8la>E5W4h&H4sOF]s;(0m;>>GFm"2l %_A$s+)5B)GBaU%ME(Pk7kMfC=eOK;"U/G2nkCi@I5R9Eg9(*uPeH %TMrWuD%'F2X#IkP$%+UQ35u@.T]?VLM\m0I_db4C^^UAj4,\+@EqLd#W\>.u=ESDW2;:I-dFs:Y+)jh_[Pj@PlOq7*X)Ju@2N3AhIs`.g=Gd/X %a>X2/TkDoFi+hENZu0O;\Ef:??He[47jse.\YeU[f2N*fbGVh"CaMgJ-FeAJ%j/&RNcX`0)09'pdesS,1CJe"DlLf0lgL#1HKH*n %Ed'@SQ/P17CaRRLPS.YoN6,mh)pfd5^eFt:"+)p=p/8R1k3DQ/]'G!pk3Po#g9n*#E3r;to;`Q:C5T\mR9o5f*3co(*]s'V)WL!2 %81BP_E+EM)^g.[9ihh;'8<->G9K83dVU7^X=7'"mf3==3T>]3FY&(ehLs&.6KA)[6YL %(R1KqC87q=b$#lmV`)d8]!(Ha8MWif1aDEd%&WDl9Uh=8\MEr5pCN6`iXp)KEt*]+@:rjQ(n29qV#hSX0?lu29CL';FS??-q@!B> %f85MCg'^#h$Ie^kN'a7K/m7`^V<;7K$+tQt>g"P(FL"7h$BT-NR5HKY&O8l+NOL:R-ZDVrRo&^5i#E.9<2kaNYd03`1g2jcT,>mt %3PTlK0uF#UK!*aZ"I7YUj%bD)i/j0'XgV[P&p&eS=`XmMP];OL"/j'`,^H(l!(t6WjG8@iK@5P5'!-(BpN`*qm\fS(=dLaSB.hTd %B1B9QATm,IR/D`2>]DBIEHOPYX2mC.$U\=PS)@I&Z)*^,PY4O\imVA^-6rk1nIjtpfE;Z*>+4-]-7!3jTIX*h-@"4\-<_u@Ptde1 %Fn-S(X!jegEDXY&[*_7VLp*_o-ZDT`(9-F0g;4U^F%4!g1.KZ)iM7:o-E/6%,\Ih>@Sl,n%`0Vdj.,bJ/h9Cg`lC`Y;0QRcXeuU) %W=rp#,J"D\YYrJB0Uu!RQqK:m*-&4P"BN2BY%/6H'ds$#N.S]XJ\]iq!j`=TC%M]d$8"AV@HhMr!D;]$I1S92?tC4NBXD_X]@0p, %]mHi^`@r!8Y#(eQ?AV3O:P;T\*s[Q=!@pWJ5uTVflG4;@/'AbuUP4n@'R$huO3l_l_N+104JF[XWBTXRiXn"(?8.C^)/%TAkHiA/ %GQ0`H]lid-^[mSti2\N[kW49J/f>?;NWI-:MV`rP;Z&/^Uj*;/[F"0nJ^aq"<(I,Ei&Fnp+\+tPCE<_(*Z>q^6'A^EIuiFp.S3E= %3K!`)lH!>`-\MYs(k()13>81%j\?LA&*V$!?M"?'LeaS=kb_@pHT"uRqY]>@cp8&W)gM,p/Y+$!(9_\^`aMidKur(pXT_3t`2.>uSQ=78-G.R7J8n*rkj:AmlTUF*0Y,UspC,\Zq9m-q5IlND<6;Xlm,H#b&./46[P-q4j %Osk]b!K+FJ-&nb[!(PQgKNY?E`%6XO9!p)c$)'WP;EsDUEb\LU(!o"4b,IK<$H@Y@&lI:717$F!l3Fm,&[OqWL8EVL"@"R(?0VXU %6A4tbi\S$!\Z)lhm4_9`$8[?,1R1q7[h28SbK$_pP'_le30u.bTR=\Td1d#Ha%\A8;%%fu9,]Ys]O4pPC/^#>L`udEXF,3F\pt)c %C;Z?5[7;<:mEt5&l*LZ?dfr<5_"su)ekd2\3,35V\&r[D29=mC+?-c,pN%qX+tE?gBSknb %':228KJUilB-"INV\f`bMk=$DG)IA)Jq%-T7%E^5r9n+cJWG@d"9e7C8-maQ:IM/X2ArLQ`IoL:?VO-jrRJi>lL.#6;Z4!+KrV=( %.B3/YU,(8+93/Ld0-i*Jr^tV%k'en%8`sM>GtI1@21]J6F$*;JblF0BE9kt('2&m,CXM4\'p?\_mI4EViRd\b-`>;*T7,g=rgPt^ %0EMBUMt]]/;@lgAJ1(b4TY!iXk_8jEWh$QhP!MkiV\\fZ*EkrNn_n/T4VaDV:W+sV?m.ZF,7?RX4bP/]HQkS*,rp&k4G;+O'2EcX %ohc?oa:;YCHR?$Cd61XNW@S:@:l2aB$IL"jgSl8U[Y-[5Woc^):leRa<\hI6AMaWGOfTsijq'"-E+Tf>0JuTOM;f()bq:(uW"h4^ %c9uUWU\@<5i)Ef*3&?f?bmYh;1W'j9RA!#b,)5J!@M?"'kF'u@D^7i*9PWQlTPnbG20!YLUkZ[0A![Kr>XSG?69PSn8'.F2og@O2 %V''0_O?P^fR:f?V+SPm&q]hktnH.1$PdB-8Otp^0?b'C>Weu0Cc$Y9R_gZJKtDT>I"Uia-)/>2d+.f.>rMGV-p/OPSCO* %X]DP.%UdI`@/W6)pfb@ra`V4kXnKb\Y<+6hLPMiET;+Ob+54W>]386nT6^fu00Xn8TcRS'eTL:&-8WY9hgd4s+niJ?q %I@ZJCDH[Jhj>p_c3BZZ7<5"RIG5E8J%N_oB,_6)1*8N/VN-uhSR"A?p*VL_pQnHHaOUNohoB'@A&n(se0;>4m(rJ&%^f&TUTj-c5MVpc1,Gu&$/?*-b6MHjRd)ZD'7:M43n"_C\PJu3bIjspq&Dk?3;pe=GJ^^(D;3-q2='uRW*M;_nMA0'i %$,+O0]VV797M[:P=YGIWN)2gh%ciOWKV0$2b,Q%o)Li0-;2Sg<&Pr4P=q*TFNrZ)?2?`P,QUl?=POS&fP-FZbmqoa+%.1bscuqs/ %JZ[PO+C3SHhaQ'a0Vaqm`:9tbdM %$)eKC;FLnGaeGmQ%]h&G3d81X=*5_cOdo'O0+gR`/V3;[WZ`3'0M:mBT'O-O_6) %?G8b2(MW1M11]^@.oC1BY_*3CFpe>auNLW#i^/s(""X+b&tRa?h<2,U)jaC*tJ0ffT$ %ekse(^RE6K2IK(C5241/>"9Lp/1u^rca2ip^M1,q9!9R6g^=ur@8Wf$@V6DI&Fhel#UZG/X81YPN+5#]-)Ot0!fGpF8F0oljhEi/ecS(mTF6k>h8&[*$d#QR`(HLPG`@c2XNf%,HZA`'G=u[k@BO-#XHt5/>mARN`%bbn`g`jeo %W49e\[%h(G]P(^hNJHA>>+2n[\I:I3CHBV//ZO^!c+KhY%AG$+-rf9 %]7Y0_'"d17\4)7e_78S<`W6o[ %nI%6A@teIaQ;*?3J9oA06l0e0,cF4'YhFlJ&&YC>JGcb@r %oW9Cgil**MAu'?2bYK'9O;.&)FS=+]Tk+%^GY6#;CJ?7bGdcUc3+Q*i<>b?GbX$ %Fi:@H+U'SnhZAm_e$mtOm=Ha@m>;(r[f@`i4^KAbU8bTB1P(VTXA>djB2X7gB]]S[.O*5n.T!-;%[_B!n*m;XK]4h=i%^Z,PLCoV %p_56Qb0!gA4t7f$`)6CgYLT:/#\]+X`Xat/V?]qNV9ot_cF,Ah(KAGa=V[f=S-=qHe?iMNZJn92BUa&/UXQ)?Qp_8#ROZA$6P!.O %T"i5.naWA_d,&2e"p^-I#`'QR?RE&,P!fWXJ8[B,h+=^HoUo!fM9P2Ecg;0KMCe^Z6FsR<5',\$&qTC)%d's(t$lm0d938 %OgM+L=UG7^p*%G2&;snZfapL?p5_k$LrLCP_LrJqkYm2E8F=lc&dm7:Q8)SljP2S6^SlMl&K*jVEN+U=o&b):jLfV[L %i[ff`Lc_2n1]p1'-p39F;!OiIZP6;'e#(A0LE4R^E>Z]kfu=&A>1.5NFsMGmoq;0Ikm(4,:llR/P_Q"!ruZ=^Z7=+ZF:4g=ORJ:% %l>0RRm[*)((/Yb['GMMs"acfk+og\BeD$'Ye^(iHZjjQA$A^28g-MI_Qt=juY^4=mu)2c$ZuZ+o>REKIuqF %PW/ImI7jCu]=gi&[bZD/NOlfpV1"65IEVO%s#ceLq,VU+**$aOos9$fa1&+eLV&oa9\!>i8AV67g&P1&E.op4L-p`692(b.dmLFK %j##P&>\'+.`]^TA2!'Oa?!+I5U%0+QIR_TpL\Hs1^.M@g-XSm(/Vb/3lC9*GUp`nc#(/t%D5i?/#9@2fC$$7>.>sV#?EqcS[Q-j: %1%,>ihUo@-!!K;0p^rK5+Prdhp@SPVb!'GQ>b#l2S?3KPXoI1H,Hb#8DVNR/TZEWO\6+r9K]b6Q:X_ %lln\.nB/VF\(o>8.@"rlEfOgT7EuKk[Y5%DOE1OacD*#Dl^T1toJs&3?>m=9*,u,dNNq%D3Ca5Nc[]n#qXR#e4_9GegZZJ?`?FD8 %C]@%R&X]BP]#B==FK=B'8OmkE8U;!)7iG[h8!7t)BLbiO1:0EB[i$\ZB?2c-HI@paXJiF>XA!B=2![^-/5JHuFi$eL8apI8i`X.V^gea %RYoC*\2IPXpa04^U6Hn6M\NauM^2egmNP4_U:[A%*76o+WSlJORU$nV:(Kp:&`#e]?.)*'0LYYsU`@cF,Ul6*(JSYS[Yrr(A/!!^ %N_H%LEZl;bg`"Nc]A63>)_F<#AUmbYb@u99i$HR:KoTb)ltTS$(ol;N>kk %C(7^!%#K505td(X.7^nAmNoD7KZRfrV!",qE2C]%T<%NZ.7[jK0EZ6?]fkIJ8$>s=8A^Go9m/OM1$&ZuZs#O<(Q#AtLj6u)F'?JP %<$!N3#P'OL;p(L,USF`_*/UM$ro,Uq1Xu?$5.tPJd=hbSKb%r#B*W:o1kFn4R_L]d7hf1+e0<&eCK,OEf.]_hZc0+_aEtc99brn2 %j>LNlks@408AYs5(:pT/`MA5=aWc2*&?eYbU:ET'Nnf@>,[ZAiMOncT;hZ^$W+&Z@SZ"k$*)T\/P(/ue'tSSYrX.34?Y(##K`taS %'m[*QEf;L-k7u..F'lYLuO;cD!-[Y%9IR=qOE"O;7[?6(6WRr2ImuQ %68Vh9\e31&WiTZf8I`.<$VB*Hfg8SdSA>u@G!uC_%W%gWW!WpDG%!,Y)`u%Tq-:@iU`c*X,cul7$\^'::c6JEh/![QF^ZH87Pn=? %ZBPAd_0gU=hkuIdErrB)gp/?`?3I/L,3jri:VT>WXJ5#6t*VhG)_rdj9WlF*up@h.6V(XLk1%a9^0sJ5%bVc %/ZAsZaZIqN"r&@d%P'r3'L)_$r6%AB6B9>c-,N7!q96.U_VV=B]X;=G38=;AJYMQsf'(;>Y;?[m8V1+J6Qa]],f(a %rKj[`g$a&9mIfji0C?*ul!W4(\^SOA^[s$TI*`[1fc+a+5Rf?5!^_#9(>B\CT]Ue&%3']fC(A<"q9SDQ@aZ"**3t)`7S6 %*sSc+Kgn>]XLIFGNH60lutOTB#!)k %2#H)="mli1P\.YaWK@&Z\'jVe4-hi&03q5Whs4P$leCf5g/kQ._6e-$Vi-smkpph(bTb97aSCs*O6fs2r!9f)-ZuneQRd$o]Gu.h %Th:d9bIj>e6L.H*0+YV%;^":WT@@gsdLUD>dZ=/A"+Ekj%gObZ%p+sm7$AT:!&+3Q]fbZeD.M!:G=!*Dq'lVNm3>bUG21NmQ?H.a %"79XnMRFGkReR!_>'N7X8Z"+&,tXt-:.^V.P>dWNp,T23lEhWTZ83O#&msrh3UK>8SmLoJon0+^Tq-ljaSJ2$)k=#>=[.LjhFI82 %OS,B8I84Rf='c6Umt&kkTa$d-"&Y*u4I*cP<7VS60$3qjPAZb?Z8\&M+"/#QhM*3>7ka_/*WK\L9)3WcB2aa9_)(:ZO6OsmQpn7qM0&$WRUk25QIcSi7i55jc %I*Sr71gs)QdEs,r#KH3M__Zb@@?.?+h@k>@LPKkmbkL'P/;nRko7S33lWg,uP?`-TquL*9FhTZ32=A$Jm81q92)/+hMM\=.ld.Fd %8beulVNUF9:I8\O>aqc:I?U^>9u7Fs5lr\'TUr8qkb+O8A*BR;h8dl,P6rr1T?fRae`f8>rs6-1IsS,TTmqBoO.h&LZB(]3-8f&_ %61K#bLSM,HZPsW\Xrd1i/*?QeqC#"CC!9W)Dh6bPe5nka=$Nl?c?@p-9O1Um%TDoKRk`A^_hL8q2Wlf_`uEC-^(XL7o.u*Co%Y:P %Z9FL8k4\$&eT,NKbQ5'LLMQ,Z,e""91n0g_*Ypi=cqJgf_j-sRHEO25jn>nj_q^CsF*i$$C/K[qk-,HdP&tlkmD06[c/N1%*&2JO %W_!YD&lkkU)&@;e2ZM4SCi&#YR6<)*Uu?Y?*bfR`(CpgZ;L@WUJe"Uf9CV4e$"!S#:N&sFO3S4bLI_+1$=bhfL2XkFG5,'gG0f9D %a['rmgkHdo'8In>alT5<6'YI20WF#'E[[RC]5)G4BPro:*k1)48]@C6U$)!ne=_^,2,#L0'/c^n*^U;cXi>[%d$9Nq=6ST/0t7<0\Ig67LeJN$=lj`&"s3Lfceif=CVCeHinOi"30\7P.O)$K?E"i(N*';2\\3Lg`;7kFBRRW=Ug]M*'S!j>El`ePCqra\.(Gh %jpb#pP.O)fK.\\@0WF#3ll\kR'K\i(N>'r1rYBX%a>KH %X5c,)+IP,E4%QLabmpbT@Y[MaQa4M)[W%SolHnl?\N4WG%[(NnZ\.?(d-RFK$9Lpr\.q)%q?o_#OuD>'@Si=?="ic.%,<[>OFT"K %i'UcC0BDDs+(DC>jm"OfipH#uWrm:6:XOnO/&raYXbJWPFl5G[BrOK7)De.(i_Zm@n#O%[c?m;"*eXKJ0[sG$3O?J)Z47:TC3tYZ %D/O0HFl4Y_u9Q+t(08kp7Qe-S!kTe]f`$+X*Mm)ct(`-`Z;7k485K2/9,a&`X7P227H#^KUs0T?Z(:L?)FF0ah*`@LO8Y %)X99A5f,1m@L8/O9@Jqu$bf^O)&Dpe)^WbkH>o1-OPcRf,uW6IlBh8[I=?9q(lqJ(!\-H^#?DDgb56hsFEIhsL(eD:ItH/F?Bk %m9A_Fpm()(kY%Z)k1-P/UFTr):gXAbR/J`+CJSqI:]'qcAf=r1_jaYF[s=UI25/nKY'Rfc0S?QJjST#N\4q]S1ak@R.$3R,0i$iX %Z+n\r4p%fha--*m.]on#L&DMSra[i$'UBRRdH<%FMqRGI`X3p0\miV3-\:SmX\]8$+c-.9tT:p\EB!ZK2r)GZ(kr6/*m.Z2Kn4Y1LCn,kDc'LFoeCD0Mil2u@'6XsEn %/;X.?gDi>WkZT2f6lRVFECZSAY6D$cDoTe6*@*$[b1qq3d;6tr>IUk0g*AEHT&3J$*mBa>Z@\Z%7q&H_ab[qn@'TR6^#`((,TrOr %Hd0q;brS=3&'Del;ck"(Q%ur8b]RE@Cq6H`#p7=`'_okYBB.ZpXFX6k';3*1m&h62#R7lb@f5fUrmlI8l8&_'mkr16^Y_@5h&GC,PI`cqI(L<(QcK>'eT=n$\n.;FqIj)NaA[YPs0O@4jJh?ST@4_HPt=7s;OA<[763ZoWN`eg6@qNM,Ys+`QfP,"&RH-r'8J[b-D@asBuj6# %Ma"$Rh!=A$4;G$i[]Vhb`>L\DQD#/3nXpR$LKA!453'$m]HB3OmplDoO["JC0^?6[8V:g@u %QVH[JJ]<(r)(&AuJ/g-L()UfoHtol2p9@D14pAq'IsfcgZP5V3q]l%^'X\nl=/i%EII87hiDdlih/7gS1 %k(#6#9t()f?\se>;AJPt0aomqLah'renr1NIA@sBB%@LtYTun#K7imoJtZGj(U0WOT4%sXecoN?ZD6"i/?[5!23Y>bLTQuOl_-rI %po)su'CuSH+6c9eHhR2JJYfM&_8EJ$W"BO'DbE!YA7*-1q\36K@Z&e^$lCddR[G6W-eOkZIU/5Wo2=o7#]AdKdWuT@*sjq-L1.rg %(i[9")Ja8d@-ckp;KmX/Q&1`9>Bq>e^.*murH<]+!G4fSNVZc!-)1k=h-]6pR^d,P%/jakr2Tp5>.-@>.2("V3U2P,N48`;T] %mOm$SU(;Ml"\_@KEd%1#K`V`*2c^/]!#g*8@-TuaWhb`n`;EM2pq-YgFS9A:p(:R*Bi_I8?lX4npRqbKqm.-=U1qH4)W8LfH/Jj+ %<-Vh\Ij\R,`d(Z4f;a\$iZd$d1O,TpX^&P%:4%;)=gW<"X3ehuYZ`!;B)@f#H,7<`PHH!*]O9^k^_jD1CY,5@J23aK]:!*5$p63? %+RY'&]XnU%?niHl#0+.`2aES^_\HpbOFoE8".7>V?jBtTh.\UUPj>l_@U`2WOJ_lPNr'5tf"fHat?)[XAc$pdR0,R@CN %0uTlB>>^'k,B0!NV?ltf.dE[%+UM/ZG5^]g"&VVdFD9:j[7'Pk4;cuBFa`,93^ON(HOSa("&X<$!N>%uO9UCPPkc$K9bb@1:B\Ba %]FTNP:_OoQC3&G\/jV4;Jb-gD6NuWC2g8@TEs01rl4n%'P`>q*"%[E;QFPRO%NV"rMaVe5e9@O%nICjdWbI\WT#5,d5",+9*?Q]Ltes$0E;L[#jAF[JGfa'hD.J:bn5P& %bR>d6@l*e3`XlGY>9Z;*rJ2"fp7H"Pqc:jX^Ycr47M8$!C3EE+^rtUV6'8Y_\a6>JckQ7*Qgdm*<+mUGWRV4Q]0WusB$?"cSdHKu %:rup%=NMqB[We\h*&.MIh?d/uVAS.N!^j(5!r5@[m1!hb_.-ip78FBD:^@_5O-b#e6Ya^O[GMn3_&73qVjYE*La=fi:a\[rhsbOf %..CFJL.6-Td?9qE#(HW-pGuAO?!(J?2CQ$8&[U(#&'`1j>0=[G$JbnF2ps+]>Q(-<+oeE8.26Y*-A]$BffqL`#"u.$TZ!2Xr]U-8 %In;[^FUAQGF:2cpgG,r&Rqil"n!jL6mWK+W][K0NnP0ld_&I`l"<6fO'55&5;6]Rc=7L&'Q*]E+]['lfm66@cD)\k3ski">Ld-=@$&N(qVF]jOpB.^;F6_\1nVX!ZgE %'fEP!iiqBRiY5^aX&,R<"e5%q"I7^[#ZJRS/;o+d/!i]@),:L7QULprDC$6WF\sgfS=*`cUl6\A>e\20StVsuH^Z,f?T^lP9NhCl %5[rdkNp.s-_?j"JI%7fb:VZr=]HSS(g673C*%(ChWoWd-pf7_dlY/*gE3>9cVX!/hX,^B-UK2)IfV2Co7:-8kJ2S9Djl_;0htV#T %q*fQec*%N#f+W#q_MhllTl"A5di*,sH4.m_H/=HfS13C)B.bdhMh(h)?m!Ej9B*2GSlZN^YmdYJs6F$GEfAPS24c"?SbL@2=F/>n/,\hdqU>hhc?8 %U'^G=N@QuJ0'OQe@7<8*(#))h)QA))j2Mo&46dl5YMeCMqAa0ooJCb-mC%+pk/0N*fA5<97ghb(iU_9_cgcer-$cZ1 %i\*ci5kMs2!M::KCK_0ub'XPRq3UVMZN,XLFa5[3EDVsqCq;5p^q8h$TLBIL/$"[g?!_:nL"N>e0U'_G,&AUg=,'JHT4hUKkjf^2 %d)9=ef&[3_[B*sRej55:"5(_0?!_=/.)Bu72jG"]\hu4W;p\L1\[dTC>eG&[-R[gYaukHYH`CM2XagVZ`[tUuk39/Ye7B-qf#C8u %m'4@[g%OhOaumoW?_])mZh[/D!#cOG5%H\^^.RN&h#ml&tJolZ]B\i`c0K.8>*0JU>*)reDsD3=!qEY*NQD:kQ*lSL\Z4AXFY %0&#Pu@XfbO&:'l0LJ9IH#!GN5ipd3$%UZ#V\u\BQd_g+aG!&j9h8OK)*^ksbh7H,k'rW&5k^J,NX:0SEV5G1t<-l$I#gq:=NY%JI %-4*sY=CP=KV)31tMS#q]#+Fa*^&-/Ef@UNpd8bJp:[#)N'U'GQ`=uVHVO9b-F(]HGY$Ec463k5$/QAP]\s>"8$bGB/K'oe@)u-.C %nclg)W+#s2_]7LY(Vc@@9#Q#X?Yj2bqp7cug'r/O`HhVlW3V:5-8f%#(FP-P]3'!EM_eL[/h;#uWSpm"d:I4u %?$,>d.a1nrdcE_Q!.OKDT4JgOT%&#).MFq%ht6Rh7#DZ.o> %dY;lZTdp^4"AUe&!+j'pP&OQ*&tYI[*A%Y[8=7:VlY+sXn2W5;R>.qL]N$c9qh#]W4N6jk8F_fFV>sB)>'RXh5#[2.K.%d/TYJ<" %iQX90.$pUIUE+)BO,C4ZGq,:A&B9u,jHh_0rIfMGe\\tN(30\CS:[CJ(bo6;)=K;t+5uO\(a*CA$FL#?6bpbdKYT&n"HtCk9_hAY %cje&m+%#?bi9dVENN!U4'O*"j\nU]%K:"pn"],[m9#!Lj'dJOE*3(,p=PD#F\l>VqE1.C8kqLM(GekEPhL6m0]kfXS_orZ8$@?>4 %;JXJL,'@ZO-[NZ_KHX]Ng-5d7tcMmAJNP@!\>5dX?K7,8.a:]ZN6)qH]M4F:k6? %\`h!M)SQJ'=.1RDJ5)D,JblR[]NMg()Ie_05s-bE%r!I/gCY[>QYMF_rL'JdJ(&TUkSOfeV=PF/B)g_l)rQus#Y&_?O*$i\:lHAq*TH_GbI %5*NdbT[1gr\70>VS_<.6I;[&caDRB7dd$r.26])lX/#HOguSr5OF,u4TZlG>&r[=SsZ7%]>qnG21eK@:db %rm/ib[D",H9'7"(Zb<8e&B!PK'p1F5/mJuSFTF^s@7fMhm?ro++t<>XR9qKf$muDgj6NUkWdrG2N9oXP\cS"+^i"jVO@e?W"YF"F %#bZV@`1P*t+I&&8GN2mVgdEUtF9&KoC_>2:ROdgCpbE*\27c+>8C+^]9s4_R^gq]IE:AL1:s(u"2;IKiFoe9eGY>?M:(%=2r/V&k %EI>/RX@iO67U)0NpV_1T@;Gch(<"[3QtMmBJt)RA'nj/B6n>4J8#+9)B2]?Oc.Ksd6Rr;Pb9.AtTH5DR+On:sQ^)PGX5Qq_@JHA@ %oVdGijl4)q\Z@*1!\+MM.hn/2h&mL2"0*hqP7WNT/4\@r;3b)4.`Ei+?f3p/*T^F"X0'T)_s3j+VqE`q)U*%lJoNoAQ*V;?% %o^HFMP=I1[UA;#ggnu7$T:O.a[=/#a^1s5=ghkrup,Q%AW.$E=bW"^>48f<3qS?9QC>sser;H\Rq3N71rb$8@eb[)fZeFUkn43,' %*P@A\0Z$L:1i64D%rsJ^-l%[pNJ*Xd?GL0%AMfbRM-tO]IP=5"poJA[%sIGWh+nge`oQW./.DA@C1aksO:&u5*K@VPT/6(#`Gp_O %%rX@\Pt2eBHlY=:58[&4b[P"*@]66'8MBX#[_V`]M.Xk4J_7L83;Z8,":te3(&OY6s&[NCY,RJ\#`*B[%RNt9_GT2eWje$,kd10oW:h:A99PV'P %:P]3NnV#?\S\PrNG!uC_%W%gWW!WpDQ7\CQc/#p&F&D^H[LeFkAda;B?;NN'dJ[nORq\meE_s)206??!6C9eE4i,-P%FFT`16oh3f6BtP]0ra,4A0D:B9bsJ_4+f(`mE5G:3fo&1TIMMVG@^4e!,s\b>-/aNYO$7lDD5Jr<,+K6 %*R%s8ZRt>RF)WpB0$qKt3/j-G-3+'j@-k-[%7FV@'(B/f^p:,h$Q01s%"gaIQ[I*&Dl1mf(:R^#TKV4e/Oit(D+9HciV]0! %](pl\Latm/_##B^\od<-IhA,`k?O@l/$rV4"KK>?e+.0-m\gYWC,l?86pj\JfpBhm8J_Z,X/,gfCtu%dGTB+L9^Udbd[5^&!hS3Z %`Z(\/iUmXr%H@^M+qSJsr%>k]f3iD6b#&FRAH60;=0kI,AUBp!6:-HA"s@MP%DkfZsbY]2f#"R %&W.qgK[Jm[ge*Nl+DcD6]&f&ai6XH*j&5YH=OeD-JsSt8lCE.&-(W6Q'uL<.GA@l(2-rcWQr-)[NEmIA@\#W,!0?$eB'hChEkm&P %N#<8\&-g>IXi#D*L+%;&`17QVD:[Vu!b:`u-\\sj`b.cP,^>'t)pT2PrXes_m?Li*8^Ro)-';pA33d*m#rQ,;KZ^`A+7V#Kq<%[/ %n,j_bm.^Ag17rfR2uGa%d`co^'!gE`9:GZoDaO.&r(46Pm89>N?D"Nkn+A/Kp0[Z]B#!*,[-l]9>MA;qk?ZdH\^S=;5P#95J,C^m9pn\#?W4g>rd@Mo90R"N(CM5S %aT>!,)P_JY^bJf1en*2edQAe^Xi$q17[iQ!geI)RK>XaKI2MU9^#\e@pf7GYV.9u@?56-t7t%-c$0Dl-X02)S$=0BEKZWt`-MF") %D[ZsO]shG"2tjQ'BaqOt]qTER5e.'e\^pVs%VgFP2N4h?Y),=s(jO5T7Y\u'WU8Wc"smb5365I3Apmm+UZrep@oT"odFGqZ`JqGD %?,rl_+lH'aLf,S"+el?'C5`R4[m;dMi)49aqj[i`YdDg@%#[sr#&.QP[Bq[@p=CErS>3*9GA/9QrTV>o6.tJ.`Po!L9,mQP6D8-+ %+Y(JrTSo-PHOp$%OhR`N)qF:RYSHcUVG>XIcRs(aZd17@e.^(cj(i4/mW4KTC2'I.(Bpu*(m--0^(FeKmMlfslE6N)E,>j5cQ_i. %_FE?I!\W`19pI^1:R;6iXf#E,kW"%T,A?C])6?R0?eN+'+0/A1.)**e]HTs1b%N)..!*VYaLJA$c`s/udnt`n8,^a;A?;%r[^Z>$]-=c-0d!/->&9q9tRT@X_m%RJD\WG_M+(7ejBqJf80Y*P>R+ %e9-R*VMB<>%PgLkk)3]r7d0%QisXM`mhA_JU-OXi`n6i(:#Uht+_&Ceh^Q1*I\<[+NrVZbUFIeP;"ekpZ2*(tIG`QL3APZ8N3Vu) %kS:^.(Pr%(14'+H1VoY_gi;#A@KMZDhLu8(GGploA;cj>aVGU+.,!Tc\3OS[M@5Yb;3?D^gs#4,n+ %o:+F:PUo\<6^K+UL)`T\W6%>9M4,D`=[`ga)D3:j=ARMPM_%_hK?+[D6Ok:ieDqaX6qn0&XH:>qL0Kdmkkc&SLdLS6E_r#OG;&/N %%]XrW[%Lch_hYbTai\%3gh\OFCiPUhd:A-+)t,R>k\$V!K*$$&DW],RM'b4=/s$oJ"3["9"Z.20,/ri[YAt-YXYIZT?o5WY+mfH* %1[D[;&q/E.0"C3P90EdM"1083&F+\Hrrt$[l@uRV@F\AUYeSRH_48aFZ"-1TLE1/`QU8/9ok0J27igH1`FLm$cp$(JUU?$uMjbEu %.Y`ctQeAt#)$1"A+;t\c+^r#\i%QVcW[=Zi!5L-8CRQuj9[>-b;n-B83=bMSi^Z?\pf1conB@f(EHDCti&et7Vt&%,u*Nf$e>OLPbh@b^@S %g[G@tk7ZEjqC'J*^6O'^6jcj?$lbW6l@O5jMkS'iV3O7$+$=k\R!>"R5l8S+OV"DcX]N2\jnbe)8:;]%fO1VF#OZ-sXb%E9PC= %3Z(uf^4;QNq-`=@1o_&"\I^Ob>US.qgY>Vc?'M(^['l[@TN_To'_;@]]ro;hJ#ln3@[\DKsdr)P6q)#ZNc=\=r#XTNmHmYP&/8:@? %os2nX%C^Ys?-[(u`B0hd;U^nX!bs`&+3.H`[7$-i%'$dRd<`OXpd)Ir(_6*r?=DKgn#GR"SKl9?h)e6T\%[2I6/U%J9tN?kU'pg8 %1IdTO:CRq6oVk\37J/@&\%TUsE(D1KgfPDg,1AWl:S_` %#B]KZqqf6\8_!(:P!1`.'l_8GFOT?N3N.c1A.C)X4uM/DZb9>%KPIVrfCZ&&;hh]=jitt;ICb1: %?.2/HQ)?]7A::J17+J1skhZ6trqRPMH2-lR,.Lde9ClSWW)S3#j0j8-gAudli5eTA7.9XV+?&7s4!!7/T]^ScIVJN5iJ0M?EpdGU %c#S^(p^<9,;9'(@*7+aC+-\6=FTk]?m/P+-4VIcLbOG$CH';FHYM76_:poe.-b %@`.C<5TnI=,2dMB@GW"KJ]`?IG4Y/hl/Jo3DZ7L@&cl'%hYR@I$=]"0,%fhfQ&e6bNjsZf!I\*sZbbY!m#)6^RK9 %;-VpOC:H$b/tX(rr>0]j<)I&L_QkN=5i1,O>UnI%d&VNE_Lln`VT@]DDg2uQL6CeX\3no2BHYl %]`dP5;?R4:XFTVGku?b0Pn+NWo:UOXXFFN[]`"PXVb='kldCOjXi&KQ6i;Z`5#8Hp"BthZ@[+sO98LI$]7a=C+,E77_?nA4$LT6u %hj!F+71(5K8"P5AP]LElLF9;t'TFg9KQf,QCWI_rW3V:.-8f&M'BS#M@/`Lc77tMkMC2epD6ignU'Wk6JpnY@,/X-HET@BSW$pZ] %qGn#51#AkI4>;Erjl)_*V_Ed'Y'n$1jM2>^5$u=XK!&[@pbT&22j:@B)8_j7#W7VFJUp$?$k?TPSI(PJ%,4DbnM`*ArX4o!^sEt@ %!RE?TF#W(_&iYM*;M-9\*k;JD%8p.[_n5l4`"5,)ZQ+i1^uLI=#?n@iDiG(r5-t;?"?s-=Zs])/DkqYEPn[PlR,<`:$;be$@:08_ %T-(#NlUdf%4feb^"1=?]9iFKW\SLG;\MA5l#Cda7i+00YS2D>>K]/Y:fGILgGQ#[-L@(jjhqV2JUD[0KNc]fO`anME<3R,_@VO+6 %FC;5!q!@@_#-+K'_8Q7D2Y]S0]-DahXlk4P9aCHkY;tHp%X^0qP0LM'`//eg)N'KVVKhh_iU@?7VU^m=c2>ADHV"0#N#GkF>h %jEo?T;/,HBFR\8YB!OBuXi5ZL+BkeajAQ-6NH!EXTL\*,MN4##_#-Rh^=:iR+4.-EAU;S8@+tAEGf&W@WpX/cl+B@!^CtqS,l')5 %.)FoWK?GMU$1\d+0>UKiD-St:E4$u\+.F3P"=FDYo&GeE*'Q9I84Rf<?P5+6b&J*/>)+"E>VYo'c^FI.hWnMYeJ`,\*Th05J[XWfWY?;Gd/Rdd&*Bo;YQ&VL1J(RdjP[NV?Xs>Tb.#nO[m0E! %?8$&5N0DJ$%?X3cQNlWfh9NM]S;M2h %`N-m=bQWMZ@cRV;9^E->=4!j7iU_?1nrQ\I@?.?+>'U$R2H11$#G-emXmf[9`S<_m(`f1Yh:!QUeDa,PZHBI%[iM&#\9R,CF*D_L %-,CImq7uUV:tG58KeAdSg(N+U6I/0d.5W-oo2-J=46J3Y0.pYfI0jE(cnf,LHNm_.r;SPE_o2K4cM?TTUn-6t-]>Ik;IV8hCaXYF^#PTdLn>Y*Hr8c30(\t[Dgm_. %h)SPVGWR!:hmnVaG`em54r979'D+;X5W9t0I1A-Y;5rO/YeE8J^-?W_)[bn`ac(kX*;g!.J]%F]&'Z-G?.UJib",rIkQY %.CRQ&>aK]Qc3@cXDuq0Gb!6H9]jfEX(9T0dJN7a"S5lJp&/3OVdL+O$%u55Mc:O%MF2ZCe:e0N['5!$;%()HS/Dbi8Z$ZXV-reTG %<%nLM;oN8SHQH2>kW$_'i!P5GnSunL5$WY5U,]i;/"A12k;R@6.]^'g;T#>nIV4FdUB;eX'rhP",Q2LI'VXW#cnp=$ar"3Q=[JD> %*:[on08>!'RAjmG#TEich46kDWcmLp'flsqDkQ6J%PFR_pG8`@bpqo+/)*nk:=4?U*b+3O54.,/',FEa;fFZQP[D,EZ^mIs@L0X4 %IiDFEZtgUM:9]f?1+#LfPTU-`&DiC"B9M9aE?T%e\;0TM'H#R$ccf'5[=U4/XMN4-$s8K+Ohr %naM-E#;7ZmP(J*P"Wu0^raXrH23E?+=)P4$oRhY6.BaaOF@n.`?R(BMKu>A"R3Sd3"L@j7-pR1L_pT98-"6r<-Bo3$)b(>YkBK,& %UW\]k_TX[<5D4&\(CV$;-.>>Q099:RQD2]nrM;5t1GS%7:#l.%0n)<49WIl+Dd\Eo4NI4o]__\8*olE<3BX1,a&"Ush1hlgd%&\8 %bhKL&((Za=Z-E9,(r*8;!DR18.gJoG*4`^)1sHuWLVBp!5,[Pp'T0@%iKZN\Hj@lPq&gL=.hFcN^M8PH6eVSi3P^qZGf4HmE'pM5J0b(`?"Ci.hnF!"eRU:>J4*?Ri7<6ElHafZ'JW7"pSJb %M1GWRi&6g$732>\_']ud"&Ou]0RP=l8N/teWuJ>Dl\":pqjK)FL71,oa!V@FC<^[JE)IH=KY[i,TN_kl`]g6F\(C$(i_LPhKUmqR %TtK2&'1Y%hqUB2PH]FN.UkUn0C=m!f>]LhG"=BKoRhFm71hVah/LpD760D(/PF@JGXNrtpoqJVVp!WH]LP %1kB_7;Pm#fS-C7gN]m]Ti&lNe\P6#'C>!k*"+_m4[LI7=)=",rE\+2hLmGci;kiU7Ikhalp):` %;DH/&q5oIiH5-0b7%>S2BIk^,0m)FaU/86Jh_41Y'WQ_aYb9kc`J;@naTfoQ_e/Z=5!M'`gR#PTC][@.1"D!:@i5H%6T+RF_LR0' %*$_RPFoDt&DlqJU4RQU4N8lF/MO"N#c=+qF0Dh9jY^?u>:uZTC=&M+`Y,'=3G;P(LSI>lE3`l4m\CiMs[K#6^qA4`2gugd:#KJWZ %-(Y.qr?.dZT$$%UWZuic;0B\OC2##\4C5nUoI6/HVVi/=>8l3s+_m."t"S+2/ih47q&+kE0[<\IsGFjS5UHT,HC5O.*hrW)@@b`"8lgp %Xptb#/tS8(Or?I&n[e(.oL:9c'#W6p^4uF6p]?p,JCRClsL@)&ZdodGZZPSk)-I1,i6-P7$E69A;`H3auJZiIO"tkX'ZeD%sj2C[=aQ2A][3U?6XjWD#+kWYLm(s#s_hH!\0JmDr#'$S.9IGQoJnIYe;epGQ< %:5jkJhXSP\;O,T[i,@l8l?.)mL.V_m*nF$^;'nIt""MBL0#qM>,c]C#:62&2-Iq4F@(=RP;t]suq2Gjr]S"cQkD$s^!bIW*9,+%n %nji2d,D>n$Y,f4<6Pm?e9E=?/c>]YW=pD"oHuh]C@m/#=ieW_D!m8@RTqJ't.QZ*qO,N3bqSS %nGE](#2+NN^9i;-[F7;o?g^_(=n%uis6+2afhNTs+#/Ir[[>c=m2ZP4[Md&3$GLFAie>k<3NmWJ"WK?@LW*L?2OQa.ffTm``T@bU %4)[us]d%t/0)a;VO^ifU*&`X#jqmLPIA8[P):!^%cB8-@ilq3/iB^j[rXNh:U,qhQ$q&_24oSmJ59:&#l2SP,i32Bs83GgH0IXcN/ke4DsmqR!Y>/V,/asTGk#r)oV9K921&VH6D,EYVB<>$Bd?t\0 %4e:,BiT;2_>Ya/26g5Fo)W>MNb5o]IHJHKY=g:;shVPRm]uenkmq]Y6 %?j7Lm`3=gY2Y_CUYcsl:'>l%h[2^/]H[MiA;Hfb]l(^iQ5KaLW887"3O9PU(2749B6(`ufK?&lcEWP;;+0Vn<"Ch-1lt(q)"mr3B %K?%Yu@RD-6_.-km7HrW6R),P$QIc#')1[M.,bn4S^4^2(NRl6 %KcDEsgkm)a$]j68(e_rdj-G.qQu-:q3U"VN],,Q7#ATmOln#`TTPMYXQ@%[03P8q+>>#G<'0bCj9Ssek-Qe=m.-B7):3R`r]mRHPn9o=eaZsj89(S@QcZ@aX-fO7[qQ0^3ZYZT!W0n@GXi`,9+?p7\_nMan^Cm(hPb6Ia_*[]=XtK0n."$`B_]gp1&+2a %b!Je"GTis<%[1eJ$eV6nXW)O/-NC:ra,q0;=iCc4)Qr.T\#cNdGp0*\80k.\]RYjki:khBnNq6`O\1QW0jsje^tTid(j&nhL.Mi` %U5"V@\LT.\'fFoH[u%'Y4b4POjiZHg3jOBQT.2GVQgF2b7f+:r0jbQDiSUeg>FGP]cO=L0AMP:A=5LdWBI]D<&p6qF<+:l*2(XZ> %nKqWt-&*2'i:-_Jo'$M#N_Kb^!JgM*NY?U_YWc1NL]/!'kp;"<2>#F.nmW`1Wes!<'qB6er'15Sh_mFiYV=nO+'=0=Q;0N"a8%aP %=<;P>c9NEK"2E=8C7BV$GaN&4MY8=&no>Xi0p@'t@fBOuRtZ[[%4bRKJ"s8uGaI2fcp-a6#$kS\\;]T5rQ/U*;;c:`f^O8WI0d"/ %=1mf&0k53*+pJE@*!%[uFfWt-%(&;W)Ve@\/0n:7o-Pj),.]5?C]`%%egWW&./[#R,l\j>(Yinhk+"&[Q2WCFe,0gC6;,i>T2K4$ %?.i'EJdRhZeuTPA$1^tLk87B^-M6C!DL78sX:mF7CLuHdoDl5&Qc+ef$/8dhDE0&gWg-H=Xb!^T4gDId@kM]'>ba3H[ur(Zb6BCk$[c[jF!R-/t95QC,#'$:(?ptoGjOT4GBSi`'hmr]jc^>G'7q8AQ2iEnX0 %B#!)k2#FrrL!1(;P\.\bWK@&Z\'jVe4-n-?YA8Egs4Y"?qq^\:^&QmuVL92+>tk,BG<;5g[uOf1c>(/Fr%J*Es/?+7gs-bpJ(sAj %r'0\#r`AmTs8R#+RJo;Gqg\M;s6'Dtrr)j!r;ZUX)EZE`PDPq6=3Lc?\ub%ZD'%=N'(n)C?Z)OA,nn"\rN3@BW/7i4Gqtq6`\!`V %@t!gpBtQ[tD*$L25,T-c17eF?8oJlAh9&R-nf-24!6'O[_&Xj)^$c'ZKVq*-^3D>OW:O9rY)0Qs,@[eS&G/C.$&'`F:BXBb.+aA@ %V\S"Q,>,n*J\4ar%,-)$Z(\U8Y#8'mN(A8blpRTRhJT@_qWNpX(*V'I9f&o)$g^2ALC'oRdIL?33NM(E0,LJa2!KRJ"3fj8`M7c& %(q^[1.J,h3Q196EU(q?+oK]*k#\3[8)u!8\c9H*ug>>l^Xf03A6#h!DcE)WjM,k,+E8YgU53APs6D0^haJT_=1#:uZm-m0 %Edg:RUX0qh'hT!3N`V2S:Uu+Z+%FCREYp4nk#WnjnNY+@YW#A^'B>AY^HT,BJgkF;%sr!"D>GeXm0(&Gr&*W#4e@bmHHa3tHS!ULUXCn@M>VdgOP[%UcjDL/ZI`OJrF[2Z`/^\Xf %M>a8C,&h82PTctcE=V9!rXj6H#6d5n_.*W(5Pu(Ol;8Q)?Rmbl_q79Dp=K"6riHT(0W-E36YY=urs635IkomH7gJ:iKBOc^Xn;Ta %\B.#U:V)$&p=FK7/-G3&FO:%-:LI;Dp?a:;?G+?FQNh(U`;'O:6Q:.RU6!.V&DO&l5S<$s#qIul'^T`p`oB"Ea--+X;iSB*5]k^% %Mj><88R-!+0L3;.8P$9!j%VMOJ3K)l0b-KaUWX\b9IV5>(d,2.UG2JW5J['>!Q;Y2mIW_(L!j!PTI?icW;R!P9Jm9[r;$uZ?9teI %rrCJ]/_k4O1BDq5dV<2=npY2'RVhVh]TgUEOY]g^X0#nnog:8h;hkG/%7G%^@?urZZ%99qN0oO,9m59B@; %ZPASr3(_TVf.rfSlB_[tS&/3%j^V<.543'1;=`jdg&&D!nL\`u5dhe[?90[Xoskb^Ea/YmP9a %]^RVAP+MLoDXF=+M'#K>8;?PMO2gKsGq0\;\#Hn)X$/u;.fOBJL?U;Dl.l/+qci581O%7)]af\=GIe3iI<-;[i-0(6)=M_gc$lk^ %+S4F7UKR&,+(W%=JMc\`/u2Y=Fs:kuhmnk]^=SLSf=ok%Zk$QR1MPb(DKdl7XT*[R'#'AuRRQ7P5;bHAZ0qoMa7lsudaS-ig:P$) %O?@pQOo/F2(mc^b.,%M1[?o6-LI*<)&E+k[$GNIi-r7tWP_?>Cau3*PH?C.W>M82HL?15K]a#L$+EQhi`nSVW5E16skl_*5Cm71o %nnmjk`!I/\"*er(+_hVt)kDnJ&1E&1:u;n^F$jYk:DNPgS`Oor_>7D's8:JM\Oc_ies>?k.t+qdiXZOk_ohI#_o\V%&a:[CR4mh5 %.kgknZYV@3p2))r"fId]IS=V+d36%(kGe-'9PEr$<,22+R1Ol>>"qS1U!hPm6l1'h?`VUSE":Ug`^CWu:sRIbbPF^9YN[]d%9ElM %_WS!PM\9<7`nI:gmtiYXHF5Fm10*O+[Ool1Vm1(gFX]k,Cn"&qh>C'l-L%=jS.eSMTMP4kLMHLCTElGRJ0WW\>RO]ZV`GN+O&m&bL %OOP)8/lYtB(R#bT72M-`6ICKZ6u`96kh6aP#WgCfUq+jK"^Ob;iFfLUDef3?HuDaM$V_G#l9`sR65;5R)Wp7$\d4M=j)63\cu^GQ %0Q+cEP0-,_Kd=R_I%e^j?VG4EPV5cI4\IO=bnlNOj#2;4P?DS1OCT2s/u5FTMg,&&ObI>3ct(Of;k1Z=;RpiI*?:J62,=r&F=gG0 %jlnI2pKT:\$;"^#R6m'DBVnV)iWN9!*8SpT^R@&PdUQsfORsC!@1#SDTp\6q@q_adAVDQ[2-e6;5I^u9;0iYq'TsNt2G>:9/MpHu %H43L_WiY3;8I`-Q$V<1Ka[2.jSA>u@G/XH5NdRO(W(IHo-!u$\?2VaLkVX55b3*!/f4;s9GJ1L@6O$m*j7AWGit(?S_kJdrk0J8u %(4&F*3/'s\]Ii5Rcu8mi?/2q5I7Lo:.ZShmG#-MjbGUV1OKTRCDU]W6X,?0j3:(4Kdi*+i^V^.0\*07li%JkJ=(gQ:R5UcS:r!]Z %('og>((5d-H$8Ci1sQX#MB*(:]LB,d'uJ1G7-"6nADL*)*Ym)c.gjS?2LAWg+_HpVQk+SbMeD?V-P6?P.H^>G(alFr8;tJ$+sXUQ %ZJ"eO%&12G[n0^!21XY^Hj!GuNsPD[;'4@ue5l),;<\Pr`4Y3P35#+D0bu"kM:8\@bsJeB,^K6@AVR2k)h^.mTs;L![i8N/;^@;J %L=A`r/5FjkAlZ_L%?Bj\"7+=96fg78\)n*$nFCB]^%6.gSYK7@?l#YCDq693ge-!Q+ZuOuCkUL]2k2[s)=sgOU:GsNc8Yld0[)&e %n$^RK8'Gl>gD:nDLArk"TZPG:V-:F5$RXF;X:>'D_d8VPmG*kobsO>\VdT"dM/41SR1Au\Kq"7H\pp4%23s#h@$ktDZ[MY(IjpP& %mQMQ'f7B%Z!>e)r'.<@*J*BFkrD#l2XS9:=1-a\jRf-Q:K'#QC9!dFB;E"Ec:?Bb"41EY^G<2&`mWZ:/p-J%g0("#@l!ELZq1Ugj %pcEM9SG`c(AFeoRh55I4o#D8dRJYCDV6`'CpR>-$01ifMQeNg%09bUCc.]Hp1uFPk3f.`5Xh@E&HeIShL5WB]J.k-BL98e2A$/M[ %_07]d+`#,]],=Vs%DH+&V'0UZ?d@m#R'i\*I82<&f2j5#4$l8b9=.(;%d+4k6J*GqLB:QmNR?;mNP6U0f27\F6I3aoI_AbVqfW$ %V.]-3#)Xl[j5f%qdZbd2oTUADhlLUXeWY&rF@b*$(Y4=%V!OJ#b5OP8#@CtVifLHU]ZBduAV],)'Fg;,XF;G"EmVkcIeLRsW#c42u^SQ'QFb(9=j=L(&%L[H9NfCVnc\Y2)UEd$XfP,',0LYaPk[Y)H[UY=g$4*1]6\u(**l%\W" %T!Uk/OC[b**AjbRg)g+U!prEZ4)2WLQb70u>/RgQdWRq12HqZmncatqijSe^9[K6FFrIhuR)Ks!)"1;$P48Q)#\/ka;(2B_Il:GR %PkRmTI5@P'CW[K.R+ncX@]WIBk-f'Zlf:1HIErT]bQ474[V(KT04L7@p[(iVF`,s/"4jnNB4(24j\;@-OG<4I+_6)taLq^!f%b]n"B,c?VRqA/2OnFSVPUQnR$NDJ_%:;^Wgk6i#+g4Ci\O+HQN-RQIHCqhke`0q$22ulE\=p0d)*BB`\Z:2\ %[gK8P<6V)ZA5N33unIE;T#WH68Ej8Y#*e/:>cIb]CPq.*OnFVGNdH^?-u3FHlSS+,bp,A$WU6K@T(%=A8uVk-qWWra?oHCgk@;*3Y'CLP0QF9KdnQOnSWh,VNB"=RONQ'NAHAW.T`3K^k!h3 %o2K.P/u8l`4AVXK*1jD^SVO'K8_g"R6D98J<"3nj5>D&,2p1]5*h"E$S]>S\6BZ>%RZMV4RO2!:Tnu>EQYo"c=uHm['9^T"/i4`> %3&FE%/e?2?\uZI^UkW).L#g2!9He[=cCbME]5moY*QURT:mG)FG@^509Jno(=ImXq9sAb@/rrp$,IX7YkTn1[d0AUY7ja\p[Tmt2/u34;40-_2o9eQ(GQ9! %B\"6BjS=t=X^M#d!0IRr,k"1Cp=Bl1(,DS^%jA$?m3rhI"L0PiXCGe3kiRkkJkTd8nV_qFR+$dM^Y/2EO[/i@KGE)H7W.o8gGH?# %2k^oA2jBbRITUJsl)j1]I,Dn]VB)F!`t@m1?\3lKC%c:upP-.dFA33RgX",]Zsk6hVm2ne@3,;Op^8b6+=os1dI>$]GC+(e1k]9W %7'l$P,b[E0DTXrp@uO:i+;S86=<"Pc/EV6SfNQNEe+Z@CppXJ6d?elp@.'!J'5*M+P=RA(S5jO3QReIl$G8EP*b38:da95%80?0E-]!jP+N6ZS<$!$B8qbsfo9_A1(`;Moe/*5-iO5^RF<=*&&D]h`?/8"# %Q\]O7A.?rR;!;c98l#YcLPd>jd6g?[WfcjiIq^YMs7odXBJP]T4=:m]P)4:&81&on-DY8*GseI%Z@>XsK'+$)[bH!eRPP9R9:R@C %d;qO3p1^+/%J^+9G4)j6Cj6RSGA8Ui@9tGAP%eXV">WYD[o=QhXL+l<).o_/$EhX+?pBE)Y"g8uFHAhUo[&m1AE]\X8n@.ZSkZn>J@C@6YQ1+*6-3D%%*0[!E)n__7[ %&#(A_Q?4_9YccB]'ZTt\8>5;[8>EP[>M6aK^egN2KTX,K*s*TXadCUZ/n#G4/mGjr00V$tgWB,Yh&EQNiCtBMa,O?.rLCTaMcen= %WD6A'9mB1:g;cX`pn7@nTt(\tKANdXirEFYc*&GJ-5c42$Dr]jTB%t.=5Ih5.g;;rm&c*qn\W.W=\\54<@PQQOV3fj.\)f"Dqh6h.bP!O\+7Gk?S$LQ>=mshJ+kDr& %WhAICJ^j*>I7ETAEYa>,/%f0&mG4dq"ja[c8EH/*'3"7[TWK^96E&@.pQOVdq25LSomH4htti(KO;?>i0m#Q.0"hsF:0 %rGJ5op'87QS,L\38o+9@cdI,WVf-:eDRXh(TAshh1B5R"-5%aLnm_W"+qa]H&rD&4,>s_Tn@=kF]8QoiF"J2g9oV;B&5_V9OcH94 %4G8a$q,iQaEia1GV6/s&Aq-:$,'FaP]^kF,IZmFeJG,^"GTDVljBE%upFkId=[XHOY%!PGD`hnsGT*d5@7D]YoR^;iX"77/GeUcZ %3N_8cM+#c[4E1?9&3i,\lK*g)d4?cX>)DZ62e"+9SQ3CI7m=tn_Z%lm#\ %]hJtKP2BnF9I`%j>!kq$dY6V4)^_42R73p+$[!F+_=Tf\6p0TQ:GqnjMhn$-.lhns&82^#Y6uF&EuL1lb2e>2+l4U1Cs+n/'D#GM %3-mUq(lO5'ma;t93d=+,&J&6g_eeR\jH13rW3Yh;M23dd>HLO?cFY\b>sdOTSDO<$=VC %6'q.q2p2kjR*Y)S,mcsr:\7=(RO8dtPb?6ui,5.='1Hn'GK@Q54a4tqLn^gH(l4pL%N1'hPuU4,WSpID.%f,HCQaG]7+&>rgkR;d %oH+02o^j:/:In>O'CYY(@Yp\56aO^sbMs"ok]L[E0+T$N65la0X!Y$HLnD5dDa'n:.AA3cckOm6KP66>TWiu&T7X[(@WE=W$[G)D %MWf=QmR%RLmDhI(4`AD,&ZVq,Le/&BXsH7:KWRfc1/LBb*-*-Yk_VM.Np*H0#*)Mk'hM)6\.q[/'HEPfH5;PtBL43#Y$X>4+:;hT %0!/=U*Dq2F6C_kjY>-'H?5MlS,nBH!2hAgc@]@`&Pcd&=aIgh]L,62b(qg>n_E;T1>Y^51de:3k@A9@2W9qKq$2DqcNDTrYL,73BJ!EEEfDPL#nFj%dMGPh,19/1::g1Q2h,u$OH@rFMIsXmMWp3 %O9fp-c3s]I5aMe5OYKho&dDU((h8>O=E6-6f!Vr4"2=L7/BHrVqj %[]`G.U)F&bg!#34Adp0dQeS*kZ-eA]ZBb%dI3i@Wb>g-TVO]9L!->kl%*U7MN]>LH_GG5NUb9WH?^8PCcWj\l,EL='TAnh-7`X)qPEeXV %!7,)q\ppC*3L0o.@#6*SrgnS]^D3S*ocf(XpEO3t^lslY`0\-p?[IuK^Y>A;qn4&)bRaK5B#!*$T`#J;dd21)Q=dnd\%LCDl!9bV %?N8G[s)&@r7aGrodltq1?=s2A?^]&h4sk*LSdGh7A1!Zf7Z6o2pQG226;sA<.\4G-"tF-eRIX/YqST^TZuL+,qH_6[(,$N-R%&i:$8;P]kd#tqgEr1R!g,qlpH_b(eG,Mb93*f.,uip;;ThF9=>uV"X %]&gGoi\VAnPVBS#U*>T=,^2YELdm>[BZ.>NmYEV-&V`6..N0M4]lKP%da'(6W/qS(MQi3[OV#4\i6++%75T`q2$Hi!nm&&[AV(k(V`D)710!ln$CK(`ak5oq3$4Z1Yp93+F_7gOSo2M6M;'onq)AW9Ubc`GLF]Z3u"tbi)6$BDPohp %#M_qXhs4C5q/4gTB)e]KC%co097-QJ*DH>WG.X.8XmU?fo5FU!*;>pSigU4:b_Jks#A3IBB'EbdPL@p$KeAdc7p#J#nR6ml:[rUq %T19,2/sBX=oCGNW[uhqi%qF_j(jHMWr6nN[Z.$9d3-V>4'_T>BgX0XCi8oilN3S`nTU7L_0igai-YH>R2UX$6(TOQeI(idT.6orD %$$&?61b^pK$-k.d2o3!5pmC>kDA#e&Q#%EN:3tUV["bW&,0nU=/c5r]rVRB_b_bQ"o>?fS0AG\59gN5JS9q321ur@GEU"],o0gR* %jZ&!d'2aWNV\Ru;D-tV<#]'OVar!A(7&0s1Yu48Pj@%M]Jt.YhBU>8^a2lDJ>f!3mj@#6Ql80aFY_fMZ[9_Xq+8uRP]SX?]jE6M?peX^R4YIOhag>#F %)X;$Nc\\T5V32KhcUoQ">as*bI$`2s8PV\05mgoG6Tq9>mNBW.W-_'U,3g4qYMdh=EqT#=X35Q.l4-_UOq*Y>L:W.d:.3o(OqU]: %d%l8/H`2<-4^.g9lE&.77aHeYAQ7reLb3"NaHleJYRf2u17>!n!\,_AmMje=M<3p@l^Q(J_ %Zm=5'4`pp,;!e5&Q`Kq3]\DmoQfL*-aST_d*71G@g&CMZ*D2>V8Ib2YI;]5Y8F+DlGI(gd$1=h#Rn=+!0Nq'R9Jo3GNW/<#[U%(HL %9RoQ<]+2tQcPtL*_S!e9Km8#V8$D>`Qqfk<`#FbR9FpHZV2!u`<-[o`)HtLu%qQ4Er,Z&ZSQ%>j'on?@S],,rc+dX=%_>GQ"4sM] %FQGIqL1ZF+1tD/%)P="`Vb.=XPWgRh/@3=<+o,[J6/JdInk!e]GR9j6RN54,S#/JK7]m`=A(M/nBb8KB.*/H5:u'_^2s#=L/,-C2ft+gkZuT8T_YA-ANFH"Cd>05RsfmE5T&QoV#*UclB-)@_M])mGeJ-JK@"nNop:Z+<$J %`X/3gsQ %*2k#i<#Xk"5CjbQjiZHg3jOBQT.2GV@WqP"[`CBbIU7OH@0`/Y57.b6'K]iMQ%%L/;HP.G0mj(HZbt+T>`7580:&B+XaqLu$]jMP %]b*>:LDR.l0X='Sjl)3B,fdI'-f]f@#W?dcKk?+/iJ$7L_gU/;2@%N79P5rJfB^ %2<.%q=EDpOJr[D*Xr>^TZ %,13/_#i)Q6EDSOWdGC,VlqlbE@Zet.UgABdn?eS#Tf>Ft6Fg$joJ*IiI=Q*&tPNPcK5_UhY#289OoAm=j'<#S6Ad]#(SpGS:kjk'B/\sIe>m4T73bt^6!7d@\K?p6r%#O`NdIaKj(cM)n^"<'_dMdGaHmphG4 %#0^"g`)us]%Ng9=;C)r?!1I#5+D%1O$L[Qn'dCFch`/.#i+O@8UG/QbAjop_+lHd/!7.gq"#%.%^`#:ZG.X;WHZl9CQp1_O4LUu._!>d`Hf2SpR#+2Ws!Ui9o[S8f5kc]EMaQ<&Nb"qaDZ9tkPcanL48lsWq$nb6\n^genkVNU-7 %0S2J'$<.*XS]E0a]nSPICM<9#=S?-q6,mUrT"`e!"W. %laa!fCF5sq3M'O?\LBb]\RBLsC_K5IPLFaQ9=7._/+(\,YE,9fnBn9$+$nNN:\'5$Hp\//;b@lf./B1?Y^XI]IF"nkSZd).P?@4;K.ER6PrnF&/lW>CT>[d[;r?b`lo2>#%Knts*/k*:6gmP4?q1Ip?nCN?)-&Q< %;5rNtW3?-"0u9S0N%XXge"@uQkgcq(U'$@!o9.45<"a4=I2FhoQnFJ@Aj3+M>T*4":Q>_s,p=T:VsUQO8_DFkHWG6=0fbWnE'0a@ %$)sV`qbWQ;R.ZKW*[Wc".dBY`GnEu^@Fl%$^5eeZ-&d(3F6*#$TV5s-%Y)k=lI(7oV%6'"kN,RWq:qoV;#k@F&ETSI$\^'B:c6JE %rI".9;8T%Ze9iFn_V=R6-j)>6Lpg.OKe=m'0ra,(^.9VA$&c5go7^icDo3As)lW!f["Xr$Uo7a\GPbU,KkLiO=`ge')-e>M/*Gg+ %OXW[gW!a!EQ7:8.K[\i.Gj;-=8e\.k6F;E7.28dA6.IYZG;D\AP7DJ]g/'SZW"![_'VZ>l9He.Uqko_OR@YX %116UCb*'Hkh.?,ZcTeR5-W<' %'np(0ffmbD%l'ROL=+'%4WCj[UY4!.F*i/MS=G;@M#pNKhI60++qs#KmmCebH2WHD^%:`?M+K#isc+-K&ao0 %V0r1f_BYm\("THHd!%$4M=;HRXbf0mgI"YHis;^Y[%RZ7K.mepVFDJ*);AK!DE)fE[VQtqFe[6ei,*Cm`e'Oi$gO:4.nKs`0:9^- %esj'uAoL>Q,7ZCP5J)n[Dci1QN;6Ebd9K"b[%Z;`_P$Yu4jp1cN7mTH2ad'EXfK6#[&6e,ESpBMg4m!Y?[9_nP-,g/Egq?!>(-U' %9.$qn[%<5@c$HQ,+nGeRUtP3Z,\2A>Pr/BocD9.^ %Fsh5%h`6p5^=/pcGJDJ'[#\Xf>A7I.:<,-i^985;dMEVM"iu?mThB!F5,U"H6N\^jUb8R=?_X$D_=+j$u6M=JNu2W= %K+uc0P/*"05maO+,so\'f/G#do+`Do4t_1$7Nl:qqjc5VYF"!tO=h@Y?RT=o64,aZ+h-EX\\(XIN59%JD-@1dbtf[FP/i(XQCF'' %]nX-++bqZ_aeS8JKeDd;d6S8ek`SHl$3BTN:.3("a%;U`%c]sDQ#SRYiDL\,r#FOAP<4!f1%*@0j; %%MBeWmNE0/l5gQaV!apJ%2X69kE):s8k@c,K!+>^&MiW(&ga@A,*>4W/t1:/E>O$N-iPl\cH/]"pu2)G2+gCbbD^1%QZ2i/nEG#0 %5gp=Y>RMEYI5or`8KJP=).%h_pBW25D_6r2[8LQlVT52', %bbH/`UOsPl_W&D$pi:rF+&Jrqb941]X$OoQLTKuH_YB?]%b]716^:'`=CGM<9US@1,W@Qo>bQsNJTue=S5sT?$sGVNAm*WF0[Y89 %cE/F&a:5en>=HX>V)_WATS;HMqDtVtCP'jO_q4(YL0I*>M5IMOPRPn$#$k\.:XML<&uaM.2AKt7VHZZ@eO&QL$Its`7kBGW&^0.g %Lh4sbC9eE$UF$A&.U#Y+bgHB"nZ*8FU4q*-+^2tAOG,)#2-G_N;Nlea.qCB6i)6j?3FH!cOGYSW$$d>mkX%b`'dA=\>bR#^VBth\Eu%V?rAIC77tt+p:o`*8O=&r`?;`'d9BM#n]M\L*f=.W+eSOOI@Lq %=eU[D"]s-j/Aops3_2[Q,(mN99o+O$o7X%b2,EGA655V%DT*YC'tTV\r:2pprOI.CMHWl@L$0O7 %=X[7sJuW7>mO*p"c,V+[850koK"MOqLk\cjKr?+O=fAVm(6](X-&[u9EJXs!ObIHkmm7d6@+8^1&kG_4\u_"4UkW*9Kh)M-=bn'f %%'i^;/,-6oJLjb.4F:f0ss1";%it&(3k]ZhC:r&Qo&a$+kfuFD[#sGi&t%a`@jM.6pSt60;=oD;+i5r@QsCA %ckoGXhMq(%Qr];$GXH;t!SpH"IL^=/?(leTj>m.\,U %B"m#nOSs'`Z;<:\XejZgaWWgk!qS16C.s%n_"\lW_j=1ZH)cP)$Q/9luQ@J]j@lJ,)aG;Wbid\ %OW>GFOaTW)Y&k=?,>=))0%+XBl\\5N^X&\KZ/?3E:6(sq)K)U3e9rUr8)6ZB?/8"C&ujX5eW79Z!o@ObLn[b-'[]>6OeU!uOYWop %;GEte*9)EL'8`V^FDNsN,!.i!,%44WcE<+&)c1;hp)=-2i54.nK*h:fg$p4Z'.si\('Igp:/r3HUBMQZQ*V1Cd^?'p1j"F[bB< %7?\WBm\9/l`F#biB0LG!qU*!rI@MLM(ZLRD(VC%EKG2L*O$rLDGXDb9"S %Sr><>@BUh%9-fY+7[r4iq[7.0mt(Irj'.YX)H+q_UR&KY %dA,\,esTrC6ah`8nJXq`@20eh1m1bSQ-j:=jO!!@L\-sd-Iq#Z4f"`PpM?0PHHLeAG]U"q,$REu+/FtS-g5Kl!?%(>DAA5`KnV3# %';]Zug;FJm+c#^+^p@8/VL#%l[Xhe4O[BVTWb?_QTM5';W2,Pbu3'is._;.NLX&7&G#rrPc=$kc!.(YL[ %+H!=T*/HqH0-RP`?o1:GbU*>#G.$OMC.3IDoE>p%&mB=;^S)%'"r2Mp#U`,7Y,OijGSZ&%!&"sY(O@t724gt48oQBC,dA-g*OCZ.HDXCg?$92U*+0*duTs8&1$Y#K?r/01"*brF)$1`%4&HJ[Y?2L<=:C5"ZrMTtrW(r1F;$P)#<2GAZ^k)umV37-#Yo4(kG&-@:&MA;6l) %MS)GiA=Q2>noaOs8'?fP8:An5m`dmtATR*j,0&,g@af"dNK>&+R#a]j>]CPg[h+(kqIH>'"\Q?]P#c*E)m0`\CCCfB0=q6=RRf_: %j!)N(6%')3IT`+,(ru)#k+sSZ[EcQ/cZ>7GRPIom\]-+SZVhH+RX9$W@9bjXi25lp`N@EfPV;#N0NY*P]eo_lb,1$2=Bt,Eh3+L? %[<$K86b-HtQI=iqV>94+`d3%_7\0!_T5-9HnDdj[=)6YIUi&@JmI4M<@-eL1f%XK-0:m:q]lZq.#eHg:8pf!b"nSRpEBMEmM,5Z( %Q:*K7PlkBLa"U&Fis!"T=2ZS(=IEl(VS;o'-.CP8;XYaWe5RSJ28Q!`791GD6,]_Y>Xi %&MF*@NJ,Ic[ZVm5d`nR%hn>S"q,_A\V>Ta5L!.5?;^pgPD_%[^mZ"'-hn?FfPeV0Y.HU;A04jqPDD5YqmG26oRbYTuN7[nXq2i8/ %m$+Bab6mTA/j:*G0H8m'Q3Y_Qd3LkNo.`j^hWdOM/5FbpuaRi>Y_g."R#9p6N9#DDA;/=)L\$<(DcoIcI'I`p=F!G_[722bnddi %QA2e7#6i)c5+(D>qXgLLYSI05_P+Ilh(tTi)&s1+)Z=("^ZD-`_"T`7Jh57,?_kQ")\Pl^]n)M)]=KT>"g&BFNF%$FdI-'8=jThJJh,68T`#5M$1e7fJ\/=jQSSP>$sHu+6#eu'ad0MJe$F^#sO %i4tX-GRJq42Rm&;*rk5kk\T9-tQ"qAZ(6cH5Mpdf'hmM#Q29LH-WjVB4Nb>KS\^+14jEC&sq$rXVeM/aEMS7@B2A'tLLC/Hl6"4j,R %0.PBf,;1epB;CkDK]qSVerlhn(dV?Z;@BK`TJ[koPoC9eP[!)O/Ic7m0nUX8EJZB@)$2=H3u8Fr<2:5hFLCC8.p#4d7O(I-Bj?%V %$'&YWKa5J]).St4)G/Y[/0Wm)!3paT/g2V[mYkBe+.a5K'().2Eo_@.:c<1Xd2"(8K-sT)gs/H_DigLS4?2$r=rb`b3;\Om,19'@ %jfFjJ,OKlYZ9B;.f;clGH=X*I#AW`YM2jRm2B=O!JY.s>J>*m9b&4#BLO/XZh/@KVKlQeuEJH,Lr-Zem?J[pR_*1tGF4grdBtdHR %GcJZ=f8tHKEk=rlB]hX0<8*VY86U9QWC`7Ih.MbKZ4l=G02Xg<67!n5j^D^>"KDUp92:^A45:0;%+X@64/%o]?JslI=\/Kc98MMjlSQ4Ngl71lA2@Mh0,-9qLD72Ole0UQ+)#G9Wh6PG[r6[TPD+EajH/G`IBL*CQ(O3ZDJ1+jGB; %.j;EZnr0Cud`_t$Z/MN@6_H=jaQlU-FQH2he)\oFK;)YWgifq^;LoFnM<42=p*Nft;JX[?7h$o\)80-:T%8Cq_,$8m&!5'^11C?f %G0j]^.jm=o/IQaW7053A2:_1(!4;YjFCIG>SaIea1E]#E:@0k!Oi_SR2D\\uIhM'_n[,b.7&8d>A_s.ON1>U!$BEgP7IS[E"%!Z! %BlF(.6ue#QN&WI9GuK=VOnk>H,E_AbBD/0ufg(u>)TboV&hcR,WTijdJV.M%U!XP8Oj;'r9H\s*%Q0PB4-*aA,B0ZN\B!NrdMSJi %Bf`C0]Khnen&aO^LQsE!]1eKFGYW?.$u'([':GR-m&\agLl?'=Z@r8+AjT4K@[iJsA'gcKrp.ej3SXeE7Tq)-4H%*U*i&e@qI/:+ %hp^52`^RZa4*]es)*3$IG4;\ZJ%PT*pQnp5h59F#="0Q8dF#4cS*X4eY<]6>=tASa@h>oYRC!jrPimAK_(Z2KSuK7[=%P@a-^[GO %IRCVEg*3tbLm':<^alc%?5b0DCO$Z-L-29i`(cWec3fFk5?6Q,-O\sqj;%.kmB^>=(jHI2Ioc%Wo%ZS<9Q!\oX5Gkrd2L9fg2?!1 %XfQo8eRr?"'WURPfJTHbE?]7'a.U2al?d\EDm"pE4nS(tn8SlNjR/*MI7E/h/[`IHC#L7@'k-F:5i_[^Y5)rC8!_WhXP^N>&DtL1 %nG-r0A;",%Z(d]A_CalSmJ1W-`([IbU\klc#<$M_].G"jp$DM(D@:!*A)hF?gVSO>j5_,T\Ljbj@[t_f><$ljNS(&OD./V?j*SMt %_VrRmZ\A*WJFp`lMtqf0LEgpmrE9(7G(h"mcL`@r^BO;(*"B=5_Il!EIl?(I.Y+Tj2*+(kn^Vq>YqK_MIF6^ %_BDWE=T-6\JIZ'F1YHj.&-M49hpjh*d.&G71O$7l\NoGACrCbS>Sk[&:?"(eF5^f8(sE`^\St1ECNJXH<]q6Oi9JSKNT\/%Z%nb3 %5&?euC;n*U`IHN&(H1;;3)/2ZRd7i<15PGPF,-ZN+8[\a7s?G4M5?auk--ScK9`O8+-d^-`_,3VWL)q=)_'Z$/nn6;"h$I60@19"?8$qm$G8[*K;d^D %i_,"5IT2uY90"Y5.B^H6CF5s4jZIiXs"mLc]_JRDej*NI2U?Ki'KE"&^WTZ>d1">MKX>J_m7FDqoO=WQ8< %O1*.R,D-PUVg0'`b[3f-kt^j$Rh`Sf4OD4&iM;s`@(O57)];FG\O-Bd %*0dhMB?f_0j*_V`HjmICLXA&aj!O^&XeWIA9PWA8MHi%D!=gET%h(GK$+N*ti'E!;>[6b&_*JkZK"^rUJbK9+jsDJ83'_a"0B+:8 %auBNR6e5Ke*F13q_oNX"FK\!<4aeHMZ2t;G#NbdR+udYY@#cpGMSK@kp1cWb:WMVAZVW$l99Q9s,:Sur2l*4>>i&qJH+*T2@j0dA")3[f`7X'YLS)NI;jEj;^Wsph#5`efJt.(cMK&s#>#c@?PlrV8K\1FIEnhG\Rd@MSQ2Ck,l=jgFUa?4F((Vb_tBc[$DDc'g-.` %QhZ2c/j9DbnPcpM,U3:N,3Oa.7R.'`&`Br0lE]"8A$?dLW\jI>$,(V3'Q(i\LW8&/QF&sC6j%=hptRpo(O=23?Hg@!Pi/*l]F)rN %#LbaU\$(?aO;DRqNn`1$g%'kjrf-:-j&rGipVXFZNGle.G)Idf[.1%G3%?pj`CoZ]k-)7g6Z=].HLsDV9I&=6ZWGI57U3ac3o^\> %9>5SpCO*,E`*.i-qa+F;S63cjc#'5?1;ju_Q$:AA@L?G>V_XW2G,MShh(EQI`cSL:6O$,?'If>6-J`Kfk9Y@YInf?A2H$kd#-5mX %a`jOb5j&DXJLFEt!]qiS$c;p\6X1mSW0(Nm!j>=\@Mp`UiIqsr&6uB''[):d3BJ[U6&."KN>0Qt7ge*BMIhT;h[M$#_:=uLMIe%: %X%9K(nO8*T`=b^kVjKEX6]0Qq8?iR`W'3Y-A^H')cq(DM"WnF-QD*LllW-Q]%'FbRUf`1KY=Po*C8=u-S5lZC;@Tg3YmacJ2QU"p %WEBrd<]UQ'qN^Nl#es^'=g9_72Oj*;d*%C`/(:\%+0 %?f%%_]0QcSp2gsm4Y&GDCV=7_kbNFPPns8P-?e8N3oE'f2j'[P<*.nhp^fRIY\r^31jc"-0,98mJqV8D:.5BNTXmtg`J8.EF*k(+mC<\aYTrpBh4Age?'P*Cdr3S0Vq(0[YCsJM=(&ck=2j@[T&Y=5 %0`07]2B4auJ8=Hkfn,@TCIj/5#A\_Pi'E"0"S`sYnKHPC?g*"5c_dJ+l$p-g'(9)VQ=k+i-FD]b(S-<[k?#5GqA@+aa%miAH.0RR %]YO[eGa`"r77Nq"Y$Df]-F=if?9[$/kfBpfhIu/I2.)tmbqN_kbDi.eRgVn#o5[1>9+75TPJUXJ8/sd9J!+>cGD+f;>WE08D2K-I %K`]BQ>W>$\bIGr&PBdKd`FioF4UHCt*UN9JH$EKl^RT%RkM$-UY`Wf>A2A8s1dT+)+pV"@W=JP"8[+MpBuc_7?;\DsMs%b)H-,ee %IKk5X0J7U[-a'8a*&=*q'GV<.`K_LL-U9;3gHdsjmJ4r:rFMnVcAg!kTpRY1R1rY_j=>IqQ8EJqfLLWuK]LkpQGO!!@hA+`[a+46 %_[gt[^Ah^ %AI9_PrivateDataEnd \ No newline at end of file diff --git a/doc/img/ecore-pos-map.png b/doc/img/ecore-pos-map.png new file mode 100644 index 0000000000000000000000000000000000000000..0093e8ca69f2951804b349a3909d95d4a512e5d0 GIT binary patch literal 17267 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 literal 0 HcmV?d00001 diff --git a/doc/img/ecore_con-client-server-example.eps b/doc/img/ecore_con-client-server-example.eps new file mode 100644 index 0000000..2a5b6eb --- /dev/null +++ b/doc/img/ecore_con-client-server-example.eps @@ -0,0 +1,566 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.10.2 (http://cairographics.org) +%%CreationDate: Wed Jul 13 18:29:06 2011 +%%Pages: 1 +%%BoundingBox: 0 -1 546 666 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%EndComments +%%BeginProlog +/cairo_eps_state save def +/dict_count countdictstack def +/op_count count 1 sub def +userdict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/pdfmark where { pop globaldict /?pdfmark /exec load put } + { globaldict begin /?pdfmark /pop load def /pdfmark + /cleartomark load def end } ifelse +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +%%EndProlog +11 dict begin +/FontType 42 def +/FontName /DejaVuSans def +/PaintType 0 def +/FontMatrix [ 1 0 0 1 0 0 ] def +/FontBBox [ 0 0 0 0 ] def +/Encoding 256 array def +0 1 255 { Encoding exch /.notdef put } for +Encoding 1 /uni0053 put +Encoding 2 /uni0065 put +Encoding 3 /uni0072 put +Encoding 4 /uni0076 put +Encoding 5 /uni0043 put +Encoding 6 /uni006C put +Encoding 7 /uni0069 put +Encoding 8 /uni006E put +Encoding 9 /uni0074 put +Encoding 10 /uni0063 put +Encoding 11 /uni0073 put +Encoding 12 /uni0020 put +Encoding 13 /uni0045 put +Encoding 14 /uni004F put +Encoding 15 /uni0052 put +Encoding 16 /uni005F put +Encoding 17 /uni004E put +Encoding 18 /uni0056 put +Encoding 19 /uni0054 put +Encoding 20 /uni004C put +Encoding 21 /uni0049 put +Encoding 22 /uni0041 put +Encoding 23 /uni0044 put +Encoding 24 /uni006F put +Encoding 25 /uni0064 put +Encoding 26 /uni0028 put +Encoding 27 /uni0029 put +Encoding 28 /uni006D put +Encoding 29 /uni0075 put +Encoding 30 /uni0061 put +Encoding 31 /uni002D put +Encoding 32 /uni003E put +Encoding 33 /uni0067 put +Encoding 34 /uni0071 put +Encoding 35 /uni0062 put +Encoding 36 /uni0079 put +Encoding 37 /uni0068 put +Encoding 38 /uni006B put +Encoding 39 /uni003A put +/CharStrings 40 dict dup begin +/.notdef 0 def +/uni0053 1 def +/uni0065 2 def +/uni0072 3 def +/uni0076 4 def +/uni0043 5 def +/uni006C 6 def +/uni0069 7 def +/uni006E 8 def +/uni0074 9 def +/uni0063 10 def +/uni0073 11 def +/uni0020 12 def +/uni0045 13 def +/uni004F 14 def +/uni0052 15 def +/uni005F 16 def +/uni004E 17 def +/uni0056 18 def +/uni0054 19 def +/uni004C 20 def +/uni0049 21 def +/uni0041 22 def +/uni0044 23 def +/uni006F 24 def +/uni0064 25 def +/uni0028 26 def +/uni0029 27 def +/uni006D 28 def +/uni0075 29 def +/uni0061 30 def +/uni002D 31 def +/uni003E 32 def +/uni0067 33 def +/uni0071 34 def +/uni0062 35 def +/uni0079 36 def +/uni0068 37 def +/uni006B 38 def +/uni003A 39 def +end readonly def +/sfnts [ +<00010000000a008000030020636d617001caf26c0000191c0000008e6376742000691d390000 +19ac000001fe6670676d7134766a00001bac000000ab676c7966c667f237000000ac00001870 +68656164f5a8919600001c5800000036686865610cb8067900001c9000000024686d7478b7d2 +14dd00001cb4000000a06c6f63610001e44000001d54000000a46d6178700495067100001df8 +00000020707265703b07f10000001e180000056800020066fe96046605a400030007001a400c +04fb0006fb0108057f0204002fc4d4ec310010d4ecd4ec301311211125211121660400fc7303 +1bfce5fe96070ef8f272062900010087ffe304a205f00027007e403c0d0c020e0b021e1f1e08 +0902070a021f1f1e420a0b1e1f0415010015a11494189511049500942591118c281e0a0b1f1b +0700221b190e2d071914222810dcc4ecfcece4111239393939310010e4f4e4ec10eef6ee10c6 +111739304b535807100eed11173907100eed1117395922b20f2901015db61f292f294f29035d +01152e012322061514161f011e0115140421222627351e013332363534262f012e0135342433 +3216044873cc5fa5b377a67ae2d7feddfee76aef807bec72adbc879a7be2ca0117f569da05a4 +c53736807663651f192bd9b6d9e0302fd04546887e6e7c1f182dc0abc6e4260000020071ffe3 +047f047b0014001b00704024001501098608880515a90105b90c01bb18b912b80c8c1c1b1502 +081508004b02120f451c10fcecf4ecc4111239310010e4f4ece410ee10ee10f4ee1112393040 +293f1d701da01dd01df01d053f003f013f023f153f1b052c072f082f092c0a6f006f016f026f +156f1b095d71015d0115211e0133323637150e01232000111000333200072e0123220607047f +fcb20ccdb76ac76263d06bfef4fec70129fce20107b802a5889ab90e025e5abec73434ae2a2c +0138010a01130143feddc497b4ae9e00000100ba0000034a047b001100304014060b0700110b +03870eb809bc070a06080008461210fcc4ec3231002fe4f4ecc4d4cc11123930b450139f1302 +015d012e012322061511231133153e0133321617034a1f492c9ca7b9b93aba85132e1c03b412 +11cbbefdb20460ae6663050500000001003d0000047f0460000600fb40270311040504021101 +0205050402110302060006011100000642020300bf0506050302010504000710d44bb00a5458 +b90000004038594bb014544bb015545b58b90000ffc03859c4173931002fec3239304b535807 +1005ed071008ed071008ed071005ed592201408e48026a027b027f02860280029102a4020806 +00060109030904150015011a031a0426002601290329042008350035013a033a043008460046 +0149034904460548064008560056015903590450086600660169036904670568066008750074 +017b037b0475057a068500850189038904890586069600960197029a03980498059706a805a7 +06b008c008df08ff083e5d005d133309013301233dc3015e015ec3fe5cfa0460fc5403acfba0 +000000010073ffe3052705f000190036401a0da10eae0a951101a100ae04951791118c1a0719 +0d003014101a10fcec32ec310010e4f4ecf4ec10eef6ee30b40f1b1f1b02015d01152e012320 +0011100021323637150e01232000111000213216052766e782ff00fef00110010082e7666aed +84feadfe7a0186015386ed0562d55f5efec7fed8fed9fec75e5fd34848019f01670168019f47 +0000000100c100000179061400030022b7009702010800460410fcec31002fec30400d100540 +05500560057005f00506015d13331123c1b8b80614f9ec00000200c100000179061400030007 +002b400e06be04b100bc020501080400460810fc3cec3231002fe4fcec30400b100940095009 +6009700905015d1333112311331523c1b8b8b8b80460fba00614e900000100ba00000464047b +001300364019030900030e0106870e11b80cbc0a010208004e0d09080b461410fcec32f4ec31 +002f3ce4f4c4ec1112173930b46015cf1502015d0111231134262322061511231133153e0133 +32160464b87c7c95acb9b942b375c1c602a4fd5c029e9f9ebea4fd870460ae6564ef00010037 +000002f2059e0013003840190e05080f03a9001101bc08870a0b08090204000810120e461410 +fc3cc4fc3cc432393931002fecf43cc4ec3211393930b2af1501015d01112115211114163b01 +152322263511233533110177017bfe854b73bdbdd5a28787059efec28ffda0894e9a9fd20260 +8f013e00000000010071ffe303e7047b0019003f401b00860188040e860d880ab91104b917b8 +118c1a07120d004814451a10fce432ec310010e4f4ec10fef4ee10f5ee30400b0f1b101b801b +901ba01b05015d01152e0123220615141633323637150e0123220011100021321603e74e9d50 +b3c6c6b3509d4e4da55dfdfed6012d010655a20435ac2b2be3cdcde32b2baa2424013e010e01 +12013a2300000001006fffe303c7047b002700e7403c0d0c020e0b531f1e080902070a531f1f +1e420a0b1e1f041500860189041486158918b91104b925b8118c281e0a0b1f1b0700521b080e +07081422452810fcc4ecd4ece4111239393939310010e4f4ec10fef5ee10f5ee121739304b53 +5807100eed111739070eed1117395922b2002701015d406d1c0a1c0b1c0c2e092c0a2c0b2c0c +3b093b0a3b0b3b0c0b200020012402280a280b2a132f142f152a16281e281f29202921242786 +0a860b860c860d12000000010202060a060b030c030d030e030f03100319031a031b031c041d +09272f293f295f297f2980299029a029f029185d005d7101152e012322061514161f011e0115 +140623222627351e013332363534262f012e01353436333216038b4ea85a898962943fc4a5f7 +d85ac36c66c661828c65ab40ab98e0ce66b4043fae282854544049210e2a99899cb62323be35 +3559514b50250f2495829eac1e000000000100c90000048b05d5000b002e4015069504029500 +81089504ad0a05010907031c00040c10fcec32d4c4c431002fececf4ec10ee30b21f0d01015d +132115211121152111211521c903b0fd1a02c7fd3902f8fc3e05d5aafe46aafde3aa00000002 +0073ffe305d905f0000b00170023401306951200950c91128c1809190f33031915101810fcec +fcec310010e4f4ec10ee300122001110003332001110002720001110002120001110000327dc +fefd0103dcdc0101feffdc013a0178fe88fec6fec5fe870179054cfeb8fee5fee6feb8014801 +1a011b0148a4fe5bfe9efe9ffe5b01a40162016201a50000000200c90000055405d50013001c +00b14035090807030a061103040305110404034206040015030415950914950d810b04050603 +1109001c160e050a191904113f140a1c0c041d10fcec32fcc4ec1117391139393931002f3cf4 +ecd4ec123912391239304b5358071005ed071005ed1117395922b2401e01015d40427a130105 +0005010502060307041500150114021603170425002501250226032706260726082609201e36 +01360246014602680575047505771388068807980698071f5d005d011e01171323032e012b01 +112311212016151406011133323635342623038d417b3ecdd9bf4a8b78dcca01c80100fc83fd +89fe9295959202bc16907efe68017f9662fd8905d5d6d88dba024ffdee87838385000001ffec +fe1d0414feac0003000fb500a90100020410c4c43100d4ec30011521350414fbd8feac8f8f00 +0000000100c90000053305d500090079401e071101020102110607064207020300af08050601 +07021c0436071c00040a10fcecfcec11393931002f3cec323939304b5358071004ed071004ed +5922b21f0b01015d40303602380748024707690266078002070601090615011a064601490657 +01580665016906790685018a0695019a069f0b105d005d13210111331121011123c901100296 +c4fef0fd6ac405d5fb1f04e1fa2b04e1fb1f000100100000056805d5000600b7402704110506 +050311020306060503110403000100021101010042030401af0006040302000505010710d4c4 +173931002fec3239304b5358071005ed071008ed071008ed071005ed5922b2500801015d4062 +00032a03470447055a037d038303070600070208040906150114021a041a052a002601260229 +042905250620083800330133023c043c05370648004501450249044905470659005606660269 +0469057a0076017602790479057506800898009706295d005d21013309013301024afdc6d301 +d901dad2fdc705d5fb1704e9fa2b0001fffa000004e905d50007004a400e0602950081040140 +031c0040050810d4e4fce431002ff4ec3230014bb00a5458bd00080040000100080008ffc038 +11373859401300091f00100110021f071009400970099f09095d03211521112311210604effd +eecbfdee05d5aafad5052b00000100c90000046a05d500050025400c0295008104011c033a00 +040610fcecec31002fe4ec304009300750078003800404015d133311211521c9ca02d7fc5f05 +d5fad5aa000100c90000019305d50003002eb700af02011c00040410fc4bb0105458b9000000 +403859ec31002fec3001400d30054005500560058f059f05065d13331123c9caca05d5fa2b00 +000200100000056805d50002000a00c2404100110100040504021105050401110a030a001102 +0003030a0711050406110505040911030a08110a030a42000307950103810905090807060403 +02010009050a0b10d4c4173931002f3ce4d4ec1239304b5358071005ed0705ed071005ed0705 +ed071008ed071005ed071005ed071008ed5922b2200c01015d40420f010f020f070f080f0058 +00760070008c000907010802060309041601190256015802500c67016802780176027c037204 +7707780887018802800c980299039604175d005d090121013301230321032302bcfeee0225fe +7be50239d288fd5f88d5050efd1903aefa2b017ffe810000000200c9000005b005d500080011 +002e4015009509810195100802100a0005190d32001c09041210fcecf4ec113939393931002f +ecf4ec30b2601301015d0111332000111000212521200011100029010193f40135011ffee1fe +cbfe42019f01b20196fe68fe50fe61052ffb770118012e012c0117a6fe97fe80fe7efe960000 +00020071ffe30475047b000b0017004a401306b91200b90cb8128c1809120f51031215451810 +fcecf4ec310010e4f4ec10ee3040233f197b007b067f077f087f097f0a7f0b7b0c7f0d7f0e7f +0f7f107f117b12a019f01911015d012206151416333236353426273200111000232200111000 +027394acab9593acac93f00112feeef0f1feef011103dfe7c9c9e7e8c8c7e99cfec8feecfeed +fec70139011301140138000000020071ffe3045a06140010001c003840191ab9000e14b90508 +8c0eb801970317040008024711120b451d10fcecf4ec323231002fece4f4c4ec10c4ee30b660 +1e801ea01e03015d0111331123350e0123220211100033321601141633323635342623220603 +a2b8b83ab17ccbff00ffcb7cb1fdc7a79292a8a89292a703b6025ef9eca86461014401080108 +014461fe15cbe7e7cbcbe7e7000100b0fef2027b0612000d0037400f069800970e0d07000312 +0600130a0e10dc4bb0135458b9000affc038594bb00f5458b9000a00403859e432ec11393931 +0010fcec300106021514121723260235341237027b86828385a0969594970612e6fe3ee7e7fe +3be5eb01c6e0df01c4ec000100a4fef2026f0612000d001f400f079800970e0701000b120413 +08000e10dc3cf4ec113939310010fcec301333161215140207233612353402a4a096959596a0 +8583830612ecfe3cdfe0fe3aebe501c5e7e701c20000000100ba0000071d047b0022005a4026 +061209180f00061d07150c871d2003b81bbc19100700110f0808065011080f501c18081a4623 +10fcec32fcfcfcec11123931002f3c3ce4f43cc4ec32111217393040133024502470249024a0 +24a024bf24df24ff2409015d013e013332161511231134262322061511231134262322061511 +231133153e01333216042945c082afbeb972758fa6b972778da6b9b93fb0797aab03897c76f5 +e2fd5c029ea19cbea4fd87029ea29bbfa3fd870460ae67627c000000000200aeffe30458047b +00130014003b401c030900030e0106870e118c0a01bc14b80c0d0908140b4e020800461510fc +ecf439ec3231002fe4e432f4c4ec1112173930b46f15c01502015d1311331114163332363511 +331123350e0123222601aeb87c7c95adb8b843b175c1c801cf01ba02a6fd619f9fbea4027bfb +a0ac6663f003a8000002007bffe3042d047b000a002500bc4027191f0b17090e00a91706b90e +1120861fba1cb923b8118c170c001703180d09080b1f030814452610fcecccd4ec3232113939 +31002fc4e4f4fcf4ec10c6ee10ee11391139123930406e301d301e301f3020302130223f2740 +1d401e401f402040214022501d501e501f50205021502250277027851d871e871f8720872185 +229027a027f0271e301e301f30203021401e401f40204021501e501f50205021601e601f6020 +6021701e701f70207021801e801f80208021185d015d0122061514163332363d01371123350e +01232226353436332135342623220607353e0133321602bedfac816f99b9b8b83fbc88accbfd +fb0102a79760b65465be5af3f00233667b6273d9b4294cfd81aa6661c1a2bdc0127f8b2e2eaa +2727fc000001006401df027f028300030011b6009c020401000410dccc310010d4ec30132115 +2164021bfde50283a400000100d9005e05db04a60006004f402b069c0006030403059c040403 +009c010201069c05060202014206050302000504a801a7070602240400230710fc3cec393100 +10f4ec1739304b5358071008ed071004ed071004ed071008ed592213350115013501d90502fa +fe040603f0b6fe2fa6fe2fb6016d000000020071fe56045a047b000b0028004a4023190c1d09 +12861316b90f03b92623b827bc09b90fbd1a1d261900080c4706121220452910fcc4ecf4ec32 +3231002fc4e4ece4f4c4ec10fed5ee1112393930b6602a802aa02a03015d0134262322061514 +1633323617100221222627351e013332363d010e0123220211101233321617353303a2a59594 +a5a59495a5b8fefefa61ac51519e52b5b439b27ccefcfcce7cb239b8023dc8dcdcc8c7dcdceb +fee2fee91d1eb32c2abdbf5b6362013a01030104013a6263aa0000020071fe56045a047b000b +001c003e401b03b90c0f09b91815b80f8c1bbd19bc1d180c06081a47001212451d10fcecf4ec +3232310010e4e4e4f4c4ec10c6ee304009601e801ea01ee01e04015d01141633323635342623 +2206010e012322021110003332161735331123012fa79292a8a89292a702733ab17ccbff00ff +cb7cb13ab8b8022fcbe7e7cbcbe7e7fdae646101440108010801446164aaf9f60000000200ba +ffe304a40614000b001c0038401903b90c0f09b918158c0fb81b971900121247180c06081a46 +1d10fcec3232f4ec31002fece4f4c4ec10c6ee30b6601e801ea01e03015d0134262322061514 +16333236013e01333200111002232226271523113303e5a79292a7a79292a7fd8e3ab17bcc00 +ffffcc7bb13ab9b9022fcbe7e7cbcbe7e702526461febcfef8fef8febc6164a806140001003d +fe56047f0460000f018b40430708020911000f0a110b0a00000f0e110f000f0d110c0d00000f +0d110e0d0a0b0a0c110b0b0a420d0b0910000b058703bd0e0bbc100e0d0c0a09060300080f04 +0f0b1010d44bb00a544bb008545b58b9000b004038594bb0145458b9000bffc03859c4c41117 +39310010e432f4ec113911391239304b5358071005ed071008ed071008ed071005ed071008ed +0705ed173259220140f0060005080609030d160a170d100d230d350d490a4f0a4e0d5a095a0a +6a0a870d800d930d120a000a09060b050c0b0e0b0f1701150210041005170a140b140c1a0e1a +0f2700240124022004200529082809250a240b240c270d2a0e2a0f2011370035013502300430 +05380a360b360c380d390e390f30114100400140024003400440054006400740084209450a47 +0d490e490f40115400510151025503500450055606550756085709570a550b550c590e590f50 +1166016602680a690e690f60117b08780e780f89008a09850b850c890d890e890f9909950b95 +0c9a0e9a0fa40ba40cab0eab0fb011cf11df11ff11655d005d050e012b01353332363f010133 +09013302934e947c936c4c543321fe3bc3015e015ec368c87a9a488654044efc94036c000000 +000100ba000004640614001300344019030900030e0106870e11b80c970a010208004e0d0908 +0b461410fcec32f4ec31002f3cecf4c4ec1112173930b2601501015d01112311342623220615 +11231133113e013332160464b87c7c95acb9b942b375c1c602a4fd5c029e9f9ebea4fd870614 +fd9e6564ef00000100ba0000049c0614000a00bc402908110506050711060605031104050402 +11050504420805020303bc009709060501040608010800460b10fcec32d4c4113931002f3cec +e41739304b5358071004ed071005ed071005ed071004ed5922b2100c01015d405f04020a0816 +02270229052b0856026602670873027705820289058e08930296059708a3021209050906020b +030a072803270428052b062b07400c6803600c8903850489058d068f079a039707aa03a705b6 +07c507d607f703f003f704f0041a5d71005d1333110133090123011123bab90225ebfdae026b +f0fdc7b90614fc6901e3fdf4fdac0223fddd000200f0000001c3042300030007001c400e0683 +04a60083020501030400180810fc3cec3231002fecf4ec303733152311331523f0d3d3d3d3fe +fe0423fe00000000000200030000000000140001000000000034000400200000000400040001 +0000f027ffff0000f000ffff10000001000000000006005a0000000000280000000100020003 +000400050006000700080009000a000b000c000d000e000f0010001100120013001400150016 +001700180019001a001b001c001d001e001f0020002100220023002400250026002700000135 +00b800cb00cb00c100aa009c01a600b800660000007100cb00a002b20085007500b800c301cb +0189022d00cb00a600f000d300aa008700cb03aa0400014a003300cb000000d9050200f40154 +00b4009c01390114013907060400044e04b4045204b804e704cd0037047304cd046004730133 +03a2055605a60556053903c5021200c9001f00b801df007300ba03e9033303bc0444040e00df +03cd03aa00e503aa0404000000cb008f00a4007b00b80014016f007f027b0252008f00c705cd +009a009a006f00cb00cd019e01d300f000ba018300d5009803040248009e01d500c100cb00f6 +00830354027f00000333026600d300c700a400cd008f009a0073040005d5010a00fe022b00a4 +00b4009c00000062009c0000001d032d05d505d505d505f0007f007b005400a406b806140723 +01d300b800cb00a601c301ec069300a000d3035c037103db0185042304a80448008f01390114 +01390360008f05d5019a0614072306660179046004600460047b009c00000277046001aa00e9 +04600762007b00c5007f027b000000b4025205cd006600bc00660077061000cd013b01850389 +008f007b0000001d00cd074a042f009c009c0000077d006f0000006f0335006a006f007b00ae +00b2002d0396008f027b00f600830354063705f6008f009c04e10266008f018d02f600cd0344 +0029006604ee00730000140000960000b707060504030201002c2010b002254964b040515820 +c859212d2cb002254964b040515820c859212d2c20100720b00050b00d7920b8ffff5058041b +0559b0051cb0032508b0042523e120b00050b00d7920b8ffff5058041b0559b0051cb0032508 +e12d2c4b505820b0fd454459212d2cb002254560442d2c4b5358b00225b0022545445921212d +2c45442d2cb00225b0022549b00525b005254960b0206368208a108a233a8a10653a2d000001 +0000000251eb321e59865f0f3cf5001f080000000000c896fa5500000000c896fa55f7d6fcae +0d72095500000008000000010000000000010000076dfe1d00000de2f7d6fa510d7200010000 +000000000000000000000000002804cd00660514008704ec0071034a00ba04bc003d05960073 +023900c1023900c1051200ba0323003704660071042b006f028b0000050e00c9064c0073058f +00c90400ffec05fc00c90579001004e3fffa047500c9025c00c905790010062900c904e50071 +05140071031f00b0031f00a407cb00ba051200ae04e7007b02e3006406b400d9051400710514 +0071051400ba04bc003d051200ba04a200ba02b200f000000000000000440000013c00000210 +00000280000003a40000043c00000478000004c800000540000005bc00000654000007b40000 +07b400000814000008a0000009b4000009e000000a8800000b6800000bd800000c1c00000c64 +00000d6000000de000000e8400000f1c00000f8c00000fe4000010a80000112c000012580000 +1284000012fc000013c400001464000014fc000016c800001740000018300000187000010000 +00280354002b0068000c000200100099000800000415021600080004b8028040fffbfe03fa14 +03f92503f83203f79603f60e03f5fe03f4fe03f32503f20e03f19603f02503ef8a4105effe03 +ee9603ed9603ecfa03ebfa03eafe03e93a03e84203e7fe03e63203e5e45305e59603e48a4105 +e45303e3e22f05e3fa03e22f03e1fe03e0fe03df3203de1403dd9603dcfe03db1203da7d03d9 +bb03d8fe03d68a4105d67d03d5d44705d57d03d44703d3d21b05d3fe03d21b03d1fe03d0fe03 +cffe03cefe03cd9603cccb1e05ccfe03cb1e03ca3203c9fe03c6851105c61c03c51603c4fe03 +c3fe03c2fe03c1fe03c0fe03bffe03befe03bdfe03bcfe03bbfe03ba1103b9862505b9fe03b8 +b7bb05b8fe03b7b65d05b7bb03b78004b6b52505b65d40ff03b64004b52503b4fe03b39603b2 +fe03b1fe03b0fe03affe03ae6403ad0e03acab2505ac6403abaa1205ab2503aa1203a98a4105 +a9fa03a8fe03a7fe03a6fe03a51203a4fe03a3a20e05a33203a20e03a16403a08a4105a09603 +9ffe039e9d0c059efe039d0c039c9b19059c64039b9a10059b19039a1003990a0398fe039796 +0d0597fe03960d03958a410595960394930e05942803930e0392fa039190bb0591fe03908f5d +0590bb039080048f8e25058f5d038f40048e25038dfe038c8b2e058cfe038b2e038a8625058a +410389880b05891403880b03878625058764038685110586250385110384fe038382110583fe +0382110381fe0380fe037ffe0340ff7e7d7d057efe037d7d037c64037b5415057b25037afe03 +79fe03780e03770c03760a0375fe0374fa0373fa0372fa0371fa0370fe036ffe036efe036c21 +036bfe036a1142056a530369fe03687d036711420566fe0365fe0364fe0363fe0362fe03613a +0360fa035e0c035dfe035bfe035afe0359580a0559fa03580a035716190557320356fe035554 +150555420354150353011005531803521403514a130551fe03500b034ffe034e4d10054efe03 +4d10034cfe034b4a13054bfe034a4910054a1303491d0d05491003480d0347fe034696034596 +0344fe0343022d0543fa0342bb03414b0340fe033ffe033e3d12053e14033d3c0f053d12033c +3b0d053c40ff0f033b0d033afe0339fe033837140538fa033736100537140336350b05361003 +350b03341e03330d0332310b0532fe03310b03302f0b05300d032f0b032e2d09052e10032d09 +032c32032b2a25052b64032a2912052a25032912032827250528410327250326250b05260f03 +250b0324fe0323fe03220f03210110052112032064031ffa031e1d0d051e64031d0d031c1142 +051cfe031bfa031a42031911420519fe031864031716190517fe031601100516190315fe0314 +fe0313fe031211420512fe0311022d05114203107d030f64030efe030d0c16050dfe030c0110 +050c16030bfe030a100309fe0308022d0508fe030714030664030401100504fe03401503022d +0503fe0302011005022d0301100300fe0301b80164858d012b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b00 +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b1d00> +] def +/f-0-0 currentdict end definefont pop +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 0 -1 546 666 +%%EndPageSetup +q 0 -1 546 667 rectclip q +0 665.925 546 -666 re W n +0 g +0.663875 w +0 J +0 j +[] 0.0 d +4 M q 1 0 0 -1 0 665.924988 cm +0.332 0.91 92.867 57.141 re S Q +BT +16 0 0 16 20.902991 631.872559 Tm +/f-0-0 1 Tf +<010203040203>Tj +ET +q 1 0 0 -1 0 665.924988 cm +452.164 0.34 92.867 57.141 re S Q +BT +16 0 0 16 472.736133 632.443994 Tm +/f-0-0 1 Tf +<050607020809>Tj +ET +1.029478 w +[ 4.117912 4.117912] 0 d +q 1 0 0 -1 0 665.924988 cm +41.453 63.719 m 41.453 665.922 l S Q +[ 4.117912 4.117912] 0 d +q 1 0 0 -1 0 665.924988 cm +500.469 61.043 m 500.469 663.246 l S Q +BT +12.8 0 0 12.8 47.919678 528.919275 Tm +/f-0-0 1 Tf +[<03>21<020a>-1<020704020b0c>-1<0d>-1<05>-1<0e0f0d>-1<1005>-1<0e11100d>-1<12 +0d>-1<11131005>-1<14150d>-1<1113101617>1<17>]TJ +ET +BT +12.8 0 0 12.8 44.687207 414.165955 Tm +/f-0-0 1 Tf +[<020a>-1<18>1<03>20<02100a>-1<18>1<08>-1<100a>-1<0607>1<0208>-1<09>-1<10 +0b0208>-1<191a>-1<1b>]TJ +ET +BT +12.8 0 0 12.8 46.65733 249.188416 Tm +/f-0-0 1 Tf +[<03>21<020a>-1<020704020b0c>-1<0d>-1<05>-1<0e0f0d>-1<1005>-1<0e11100d>-1<12 +0d>-1<11131005>-1<14150d>-1<11131017>18<16>78<13>78<16>]TJ +ET +BT +9.6 0 0 9.6 205.503491 441.642078 Tm +/f-0-0 1 Tf +[<0a>-1<18>1<1c>-1<1d>-1<08>-1<07>1<0a>-1<1e>-1<090718>1<08>-1<0c>-1<0b +0203>-1<040203>-1<0c>-1<1f200c>-1<0a>-1<06>1<070208>-1<09>]TJ +ET +0.8 w +[] 0.0 d +q 1 0 0 -1 0 665.924988 cm +43.879 280.043 m 493.195 280.043 l S Q +485.195 385.882 m 481.996 382.683 l 493.195 385.882 l 481.996 389.081 l +h +485.195 385.882 m f* +0.8 w +q -1 0 0 1 0 665.924988 cm +-485.195 -280.043 m -481.996 -283.242 l -493.195 -280.043 l -481.996 +-276.844 l h +-485.195 -280.043 m S Q +0.701961 g +0.8 w +[ 1.6 3.2] 0 d +q 1 0 0 -1 0 665.924988 cm +44.688 81.246 451.738 75.961 re S Q +0 g +BT +9.6 0 0 9.6 205.503491 590.33656 Tm +/f-0-0 1 Tf +[<0a>-1<06>1<070208>-1<090c>-1<0a>-1<18>1<08>-1<08>-1<020a>-1<09>-1<07>1<08>-1<21 +0c>-1<18>1<08>-1<0c>-1<0b0203>-1<040203>]TJ +ET +BT +9.6 0 0 9.6 207.119751 293.639929 Tm +/f-0-0 1 Tf +[<0a>-1<18>1<1c>-1<1d>-1<08>-1<07>1<0a>-1<1e>-1<090718>1<08>-1<0c>-1<0a>-1<06>1<07 +0208>-1<090c>-1<1f200c>-1<0b0203>-1<040203>]TJ +ET +0.800568 w +[] 0.0 d +q 1 0 0 -1 0 665.924988 cm +494.324 441.785 m 44.367 441.785 l S Q +52.375 224.14 m 55.574 227.343 l 44.367 224.14 l 55.574 220.941 l h +52.375 224.14 m f* +0.800568 w +q 1 -0.000000000000000122 -0.000000000000000122 -1 0 665.924988 cm +52.375 441.785 m 55.574 438.582 l 44.367 441.785 l 55.574 444.984 l h +52.375 441.785 m S Q +BT +12.8 0 0 12.8 46.506689 86.755847 Tm +/f-0-0 1 Tf +[<03>21<020a>-1<020704020b0c>-1<0d>-1<05>-1<0e0f0d>-1<1005>-1<0e11100d>-1<12 +0d>-1<11131005>-1<14150d>-1<111310170d>-1<14>]TJ +ET +0.701961 g +0.8 w +[ 1.6 3.2] 0 d +q 1 0 0 -1 0 665.924988 cm +44.281 227.516 451.742 75.965 re S Q +[ 1.6 3.2] 0 d +q 1 0 0 -1 0 665.924988 cm +43.477 375.402 451.738 75.961 re S Q +[ 1.6 3.2] 0 d +q 1 0 0 -1 0 665.924988 cm +43.477 531.371 451.738 75.961 re S Q +0 g +BT +9.6 0 0 9.6 233.439209 138.249939 Tm +/f-0-0 1 Tf +[<0a>-1<06>1<070208>-1<090c>-1<1907>1<0b>-1<0a>-1<18>1<08>-1<08>-1<020a>-1<09>-1<07>1<18 +08>]TJ +ET +0.8 g +BT +12.8 0 0 12.8 319.679053 553.059363 Tm +/f-0-0 1 Tf +[<0a>-1<06>1<070208>-1<090c>-1<03>21<02221d>-1<020b>-1<090b>-1<0c0a>-1<18 +08>-1<08>-1<020a>-1<090718>1<08>]TJ +ET +BT +12.8 0 0 12.8 267.129076 396.28368 Tm +/f-0-0 1 Tf +[<0a>-1<06>1<070208>-1<090c>-1<03>21<020a>-1<020704020b0c>-1<191e09>-1<1e +0c>-1<0b0208>-1<09>-1<0c23240c>-1<0b0203>-1<040203>]TJ +ET +BT +12.8 0 0 12.8 293.462207 265.367908 Tm +/f-0-0 1 Tf +[<0a>-1<06>1<070208>-1<090c>-1<0b0208>-1<190b>-1<0c191e>-1<091e>-1<0c09>-1<18>1<0c>-1<09 +25>-1<020c>-1<0b0203>-1<040203>]TJ +ET +BT +12.8 0 0 12.8 308.687842 103.743494 Tm +/f-0-0 1 Tf +[<0a>-1<06>1<070208>-1<090c>-1<0a>-1<06>1<180b020b>-1<0c09>-1<25>-1<02 +0c0a>-1<1808>-1<08>-1<020a>-1<090718>1<08>]TJ +ET +0 g +BT +12.8 0 0 12.8 47.719445 513.461366 Tm +/f-0-0 1 Tf +[<0a>-1<1e0606>1<231e>-1<0a>-1<26>-1<0c0a>-1<1e>-1<06>1<06021927>-1<0c +101e>-1<19191a1b>]TJ +ET +BT +12.8 0 0 12.8 46.103198 232.2349 Tm +/f-0-0 1 Tf +[<0a>-1<1e0606>1<231e>-1<0a>-1<26>-1<0c0a>-1<1e>-1<06>1<06021927>-1<0c +10191e>-1<091e>-1<1a1b>]TJ +ET +BT +12.8 0 0 12.8 46.911322 69.80238 Tm +/f-0-0 1 Tf +[<0a>-1<1e0606>1<231e>-1<0a>-1<26>-1<0c0a>-1<1e>-1<06>1<06021927>-1<0c +101902061a1b>]TJ +ET +Q Q +showpage +%%Trailer +count op_count sub {pop} repeat +countdictstack dict_count sub {end} repeat +cairo_eps_state restore +%%EOF diff --git a/doc/img/ecore_con-client-server-example.png b/doc/img/ecore_con-client-server-example.png new file mode 100644 index 0000000000000000000000000000000000000000..aef949dc211ac2f89d6b393d0ab06adb0fd4a587 GIT binary patch literal 60234 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 literal 0 HcmV?d00001 diff --git a/doc/img/ecore_con-client-server-example2.eps b/doc/img/ecore_con-client-server-example2.eps new file mode 100644 index 0000000..ef3cf7f --- /dev/null +++ b/doc/img/ecore_con-client-server-example2.eps @@ -0,0 +1,580 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.10.2 (http://cairographics.org) +%%CreationDate: Wed Jul 13 18:29:14 2011 +%%Pages: 1 +%%BoundingBox: 0 -1 546 666 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%EndComments +%%BeginProlog +/cairo_eps_state save def +/dict_count countdictstack def +/op_count count 1 sub def +userdict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/pdfmark where { pop globaldict /?pdfmark /exec load put } + { globaldict begin /?pdfmark /pop load def /pdfmark + /cleartomark load def end } ifelse +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +%%EndProlog +11 dict begin +/FontType 42 def +/FontName /DejaVuSans def +/PaintType 0 def +/FontMatrix [ 1 0 0 1 0 0 ] def +/FontBBox [ 0 0 0 0 ] def +/Encoding 256 array def +0 1 255 { Encoding exch /.notdef put } for +Encoding 1 /uni0053 put +Encoding 2 /uni0065 put +Encoding 3 /uni0072 put +Encoding 4 /uni0076 put +Encoding 5 /uni0043 put +Encoding 6 /uni006C put +Encoding 7 /uni0069 put +Encoding 8 /uni006E put +Encoding 9 /uni0074 put +Encoding 10 /uni0063 put +Encoding 11 /uni006F put +Encoding 12 /uni005F put +Encoding 13 /uni0073 put +Encoding 14 /uni0028 put +Encoding 15 /uni0029 put +Encoding 16 /uni0020 put +Encoding 17 /uni0045 put +Encoding 18 /uni004F put +Encoding 19 /uni0052 put +Encoding 20 /uni004E put +Encoding 21 /uni0056 put +Encoding 22 /uni0054 put +Encoding 23 /uni0041 put +Encoding 24 /uni0044 put +Encoding 25 /uni0064 put +Encoding 26 /uni006D put +Encoding 27 /uni0075 put +Encoding 28 /uni0061 put +Encoding 29 /uni002D put +Encoding 30 /uni003E put +Encoding 31 /uni0067 put +Encoding 32 /uni004C put +Encoding 33 /uni0070 put +Encoding 34 /uni0068 put +Encoding 35 /uni0062 put +Encoding 36 /uni0079 put +Encoding 37 /uni0022 put +Encoding 38 /uni006B put +Encoding 39 /uni003A put +/CharStrings 40 dict dup begin +/.notdef 0 def +/uni0053 1 def +/uni0065 2 def +/uni0072 3 def +/uni0076 4 def +/uni0043 5 def +/uni006C 6 def +/uni0069 7 def +/uni006E 8 def +/uni0074 9 def +/uni0063 10 def +/uni006F 11 def +/uni005F 12 def +/uni0073 13 def +/uni0028 14 def +/uni0029 15 def +/uni0020 16 def +/uni0045 17 def +/uni004F 18 def +/uni0052 19 def +/uni004E 20 def +/uni0056 21 def +/uni0054 22 def +/uni0041 23 def +/uni0044 24 def +/uni0064 25 def +/uni006D 26 def +/uni0075 27 def +/uni0061 28 def +/uni002D 29 def +/uni003E 30 def +/uni0067 31 def +/uni004C 32 def +/uni0070 33 def +/uni0068 34 def +/uni0062 35 def +/uni0079 36 def +/uni0022 37 def +/uni006B 38 def +/uni003A 39 def +end readonly def +/sfnts [ +<00010000000a008000030020636d617001caf26c000019400000008e6376742000691d390000 +19d0000001fe6670676d7134766a00001bd0000000ab676c7966041fef2f000000ac00001894 +68656164f5a8919600001c7c00000036686865610cb8067900001cb400000024686d7478b924 +152200001cd8000000a06c6f63610001e70400001d78000000a46d6178700495067100001e1c +00000020707265703b07f10000001e3c0000056800020066fe96046605a400030007001a400c +04fb0006fb0108057f0204002fc4d4ec310010d4ecd4ec301311211125211121660400fc7303 +1bfce5fe96070ef8f272062900010087ffe304a205f00027007e403c0d0c020e0b021e1f1e08 +0902070a021f1f1e420a0b1e1f0415010015a11494189511049500942591118c281e0a0b1f1b +0700221b190e2d071914222810dcc4ecfcece4111239393939310010e4f4e4ec10eef6ee10c6 +111739304b535807100eed11173907100eed1117395922b20f2901015db61f292f294f29035d +01152e012322061514161f011e0115140421222627351e013332363534262f012e0135342433 +3216044873cc5fa5b377a67ae2d7feddfee76aef807bec72adbc879a7be2ca0117f569da05a4 +c53736807663651f192bd9b6d9e0302fd04546887e6e7c1f182dc0abc6e4260000020071ffe3 +047f047b0014001b00704024001501098608880515a90105b90c01bb18b912b80c8c1c1b1502 +081508004b02120f451c10fcecf4ecc4111239310010e4f4ece410ee10ee10f4ee1112393040 +293f1d701da01dd01df01d053f003f013f023f153f1b052c072f082f092c0a6f006f016f026f +156f1b095d71015d0115211e0133323637150e01232000111000333200072e0123220607047f +fcb20ccdb76ac76263d06bfef4fec70129fce20107b802a5889ab90e025e5abec73434ae2a2c +0138010a01130143feddc497b4ae9e00000100ba0000034a047b001100304014060b0700110b +03870eb809bc070a06080008461210fcc4ec3231002fe4f4ecc4d4cc11123930b450139f1302 +015d012e012322061511231133153e0133321617034a1f492c9ca7b9b93aba85132e1c03b412 +11cbbefdb20460ae6663050500000001003d0000047f0460000600fb40270311040504021101 +0205050402110302060006011100000642020300bf0506050302010504000710d44bb00a5458 +b90000004038594bb014544bb015545b58b90000ffc03859c4173931002fec3239304b535807 +1005ed071008ed071008ed071005ed592201408e48026a027b027f02860280029102a4020806 +00060109030904150015011a031a0426002601290329042008350035013a033a043008460046 +0149034904460548064008560056015903590450086600660169036904670568066008750074 +017b037b0475057a068500850189038904890586069600960197029a03980498059706a805a7 +06b008c008df08ff083e5d005d133309013301233dc3015e015ec3fe5cfa0460fc5403acfba0 +000000010073ffe3052705f000190036401a0da10eae0a951101a100ae04951791118c1a0719 +0d003014101a10fcec32ec310010e4f4ecf4ec10eef6ee30b40f1b1f1b02015d01152e012320 +0011100021323637150e01232000111000213216052766e782ff00fef00110010082e7666aed +84feadfe7a0186015386ed0562d55f5efec7fed8fed9fec75e5fd34848019f01670168019f47 +0000000100c100000179061400030022b7009702010800460410fcec31002fec30400d100540 +05500560057005f00506015d13331123c1b8b80614f9ec00000200c100000179061400030007 +002b400e06be04b100bc020501080400460810fc3cec3231002fe4fcec30400b100940095009 +6009700905015d1333112311331523c1b8b8b8b80460fba00614e900000100ba00000464047b +001300364019030900030e0106870e11b80cbc0a010208004e0d09080b461410fcec32f4ec31 +002f3ce4f4c4ec1112173930b46015cf1502015d0111231134262322061511231133153e0133 +32160464b87c7c95acb9b942b375c1c602a4fd5c029e9f9ebea4fd870460ae6564ef00010037 +000002f2059e0013003840190e05080f03a9001101bc08870a0b08090204000810120e461410 +fc3cc4fc3cc432393931002fecf43cc4ec3211393930b2af1501015d01112115211114163b01 +152322263511233533110177017bfe854b73bdbdd5a28787059efec28ffda0894e9a9fd20260 +8f013e00000000010071ffe303e7047b0019003f401b00860188040e860d880ab91104b917b8 +118c1a07120d004814451a10fce432ec310010e4f4ec10fef4ee10f5ee30400b0f1b101b801b +901ba01b05015d01152e0123220615141633323637150e0123220011100021321603e74e9d50 +b3c6c6b3509d4e4da55dfdfed6012d010655a20435ac2b2be3cdcde32b2baa2424013e010e01 +12013a23000000020071ffe30475047b000b0017004a401306b91200b90cb8128c1809120f51 +031215451810fcecf4ec310010e4f4ec10ee3040233f197b007b067f077f087f097f0a7f0b7b +0c7f0d7f0e7f0f7f107f117b12a019f01911015d012206151416333236353426273200111000 +232200111000027394acab9593acac93f00112feeef0f1feef011103dfe7c9c9e7e8c8c7e99c +fec8feecfeedfec7013901130114013800000001ffecfe1d0414feac0003000fb500a9010002 +0410c4c43100d4ec30011521350414fbd8feac8f8f0000000001006fffe303c7047b002700e7 +403c0d0c020e0b531f1e080902070a531f1f1e420a0b1e1f041500860189041486158918b911 +04b925b8118c281e0a0b1f1b0700521b080e07081422452810fcc4ecd4ece411123939393931 +0010e4f4ec10fef5ee10f5ee121739304b535807100eed111739070eed1117395922b2002701 +015d406d1c0a1c0b1c0c2e092c0a2c0b2c0c3b093b0a3b0b3b0c0b200020012402280a280b2a +132f142f152a16281e281f292029212427860a860b860c860d12000000010202060a060b030c +030d030e030f03100319031a031b031c041d09272f293f295f297f2980299029a029f029185d +005d7101152e012322061514161f011e0115140623222627351e013332363534262f012e0135 +3436333216038b4ea85a898962943fc4a5f7d85ac36c66c661828c65ab40ab98e0ce66b4043f +ae282854544049210e2a99899cb62323be353559514b50250f2495829eac1e000000000100b0 +fef2027b0612000d0037400f069800970e0d070003120600130a0e10dc4bb0135458b9000aff +c038594bb00f5458b9000a00403859e432ec113939310010fcec300106021514121723260235 +341237027b86828385a0969594970612e6fe3ee7e7fe3be5eb01c6e0df01c4ec000100a4fef2 +026f0612000d001f400f079800970e0701000b12041308000e10dc3cf4ec113939310010fcec +301333161215140207233612353402a4a096959596a08583830612ecfe3cdfe0fe3aebe501c5 +e7e701c20000000100c90000048b05d5000b002e401506950402950081089504ad0a05010907 +031c00040c10fcec32d4c4c431002fececf4ec10ee30b21f0d01015d13211521112115211121 +1521c903b0fd1a02c7fd3902f8fc3e05d5aafe46aafde3aa000000020073ffe305d905f0000b +00170023401306951200950c91128c1809190f33031915101810fcecfcec310010e4f4ec10ee +300122001110003332001110002720001110002120001110000327dcfefd0103dcdc0101feff +dc013a0178fe88fec6fec5fe870179054cfeb8fee5fee6feb80148011a011b0148a4fe5bfe9e +fe9ffe5b01a40162016201a50000000200c90000055405d50013001c00b14035090807030a06 +1103040305110404034206040015030415950914950d810b040506031109001c160e050a1919 +04113f140a1c0c041d10fcec32fcc4ec1117391139393931002f3cf4ecd4ec12391239123930 +4b5358071005ed071005ed1117395922b2401e01015d40427a13010500050105020603070415 +00150114021603170425002501250226032706260726082609201e3601360246014602680575 +047505771388068807980698071f5d005d011e01171323032e012b0111231121201615140601 +1133323635342623038d417b3ecdd9bf4a8b78dcca01c80100fc83fd89fe9295959202bc1690 +7efe68017f9662fd8905d5d6d88dba024ffdee8783838500000100c90000053305d500090079 +401e071101020102110607064207020300af0805060107021c0436071c00040a10fcecfcec11 +393931002f3cec323939304b5358071004ed071004ed5922b21f0b01015d4030360238074802 +4707690266078002070601090615011a06460149065701580665016906790685018a0695019a +069f0b105d005d13210111331121011123c901100296c4fef0fd6ac405d5fb1f04e1fa2b04e1 +fb1f000100100000056805d5000600b740270411050605031102030606050311040300010002 +1101010042030401af0006040302000505010710d4c4173931002fec3239304b5358071005ed +071008ed071008ed071005ed5922b2500801015d406200032a03470447055a037d0383030706 +00070208040906150114021a041a052a002601260229042905250620083800330133023c043c +053706480045014502490449054706590056066602690469057a007601760279047905750680 +0898009706295d005d21013309013301024afdc6d301d901dad2fdc705d5fb1704e9fa2b0001 +fffa000004e905d50007004a400e0602950081040140031c0040050810d4e4fce431002ff4ec +3230014bb00a5458bd00080040000100080008ffc03811373859401300091f00100110021f07 +1009400970099f09095d03211521112311210604effdeecbfdee05d5aafad5052b0000020010 +0000056805d50002000a00c2404100110100040504021105050401110a030a0011020003030a +0711050406110505040911030a08110a030a4200030795010381090509080706040302010009 +050a0b10d4c4173931002f3ce4d4ec1239304b5358071005ed0705ed071005ed0705ed071008 +ed071005ed071005ed071008ed5922b2200c01015d40420f010f020f070f080f005800760070 +008c000907010802060309041601190256015802500c67016802780176027c03720477077808 +87018802800c980299039604175d005d090121013301230321032302bcfeee0225fe7be50239 +d288fd5f88d5050efd1903aefa2b017ffe810000000200c9000005b005d500080011002e4015 +009509810195100802100a0005190d32001c09041210fcecf4ec113939393931002fecf4ec30 +b2601301015d0111332000111000212521200011100029010193f40135011ffee1fecbfe4201 +9f01b20196fe68fe50fe61052ffb770118012e012c0117a6fe97fe80fe7efe96000000020071 +ffe3045a06140010001c003840191ab9000e14b905088c0eb801970317040008024711120b45 +1d10fcecf4ec323231002fece4f4c4ec10c4ee30b6601e801ea01e03015d0111331123350e01 +23220211100033321601141633323635342623220603a2b8b83ab17ccbff00ffcb7cb1fdc7a7 +9292a8a89292a703b6025ef9eca86461014401080108014461fe15cbe7e7cbcbe7e7000100ba +0000071d047b0022005a4026061209180f00061d07150c871d2003b81bbc19100700110f0808 +065011080f501c18081a462310fcec32fcfcfcec11123931002f3c3ce4f43cc4ec3211121739 +3040133024502470249024a024a024bf24df24ff2409015d013e013332161511231134262322 +061511231134262322061511231133153e01333216042945c082afbeb972758fa6b972778da6 +b9b93fb0797aab03897c76f5e2fd5c029ea19cbea4fd87029ea29bbfa3fd870460ae67627c00 +0000000200aeffe30458047b00130014003b401c030900030e0106870e118c0a01bc14b80c0d +0908140b4e020800461510fcecf439ec3231002fe4e432f4c4ec1112173930b46f15c0150201 +5d1311331114163332363511331123350e0123222601aeb87c7c95adb8b843b175c1c801cf01 +ba02a6fd619f9fbea4027bfba0ac6663f003a8000002007bffe3042d047b000a002500bc4027 +191f0b17090e00a91706b90e1120861fba1cb923b8118c170c001703180d09080b1f03081445 +2610fcecccd4ec323211393931002fc4e4f4fcf4ec10c6ee10ee11391139123930406e301d30 +1e301f3020302130223f27401d401e401f402040214022501d501e501f502050215022502770 +27851d871e871f8720872185229027a027f0271e301e301f30203021401e401f40204021501e +501f50205021601e601f60206021701e701f70207021801e801f80208021185d015d01220615 +14163332363d01371123350e01232226353436332135342623220607353e0133321602bedfac +816f99b9b8b83fbc88accbfdfb0102a79760b65465be5af3f00233667b6273d9b4294cfd81aa +6661c1a2bdc0127f8b2e2eaa2727fc000001006401df027f028300030011b6009c0204010004 +10dccc310010d4ec301321152164021bfde50283a400000100d9005e05db04a60006004f402b +069c0006030403059c040403009c010201069c05060202014206050302000504a801a7070602 +240400230710fc3cec39310010f4ec1739304b5358071008ed071004ed071004ed071008ed59 +2213350115013501d90502fafe040603f0b6fe2fa6fe2fb6016d000000020071fe56045a047b +000b0028004a4023190c1d0912861316b90f03b92623b827bc09b90fbd1a1d261900080c4706 +121220452910fcc4ecf4ec323231002fc4e4ece4f4c4ec10fed5ee1112393930b6602a802aa0 +2a03015d01342623220615141633323617100221222627351e013332363d010e012322021110 +1233321617353303a2a59594a5a59495a5b8fefefa61ac51519e52b5b439b27ccefcfcce7cb2 +39b8023dc8dcdcc8c7dcdcebfee2fee91d1eb32c2abdbf5b6362013a01030104013a6263aa00 +000100c90000046a05d500050025400c0295008104011c033a00040610fcecec31002fe4ec30 +4009300750078003800404015d133311211521c9ca02d7fc5f05d5fad5aa000200bafe5604a4 +047b0010001c003e401b1ab9000e14b90508b80e8c01bd03bc1d11120b471704000802461d10 +fcec3232f4ec310010e4e4e4f4c4ec10c4ee304009601e801ea01ee01e04015d251123113315 +3e013332001110022322260134262322061514163332360173b9b93ab17bcc00ffffcc7bb102 +38a79292a7a79292a7a8fdae060aaa6461febcfef8fef8febc6101ebcbe7e7cbcbe7e7000000 +000100ba000004640614001300344019030900030e0106870e11b80c970a010208004e0d0908 +0b461410fcec32f4ec31002f3cecf4c4ec1112173930b2601501015d01112311342623220615 +11231133113e013332160464b87c7c95acb9b942b375c1c602a4fd5c029e9f9ebea4fd870614 +fd9e6564ef00000200baffe304a40614000b001c0038401903b90c0f09b918158c0fb81b9719 +00121247180c06081a461d10fcec3232f4ec31002fece4f4c4ec10c6ee30b6601e801ea01e03 +015d013426232206151416333236013e01333200111002232226271523113303e5a79292a7a7 +9292a7fd8e3ab17bcc00ffffcc7bb13ab9b9022fcbe7e7cbcbe7e702526461febcfef8fef8fe +bc6164a806140001003dfe56047f0460000f018b40430708020911000f0a110b0a00000f0e11 +0f000f0d110c0d00000f0d110e0d0a0b0a0c110b0b0a420d0b0910000b058703bd0e0bbc100e +0d0c0a09060300080f040f0b1010d44bb00a544bb008545b58b9000b004038594bb0145458b9 +000bffc03859c4c4111739310010e432f4ec113911391239304b5358071005ed071008ed0710 +08ed071005ed071008ed0705ed173259220140f0060005080609030d160a170d100d230d350d +490a4f0a4e0d5a095a0a6a0a870d800d930d120a000a09060b050c0b0e0b0f17011502100410 +05170a140b140c1a0e1a0f2700240124022004200529082809250a240b240c270d2a0e2a0f20 +1137003501350230043005380a360b360c380d390e390f301141004001400240034004400540 +06400740084209450a470d490e490f4011540051015102550350045005560655075608570957 +0a550b550c590e590f501166016602680a690e690f60117b08780e780f89008a09850b850c89 +0d890e890f9909950b950c9a0e9a0fa40ba40cab0eab0fb011cf11df11ff11655d005d050e01 +2b01353332363f01013309013302934e947c936c4c543321fe3bc3015e015ec368c87a9a4886 +54044efc94036c000000000200c503aa02e905d5000300070042400f05018404008108040506 +000502040810fc4bb012544bb013545b58b90002ffc03859fcdcec310010f43cec323001400f +30094009500960097009a009bf09075d0111231121112311016faa0224aa05d5fdd5022bfdd5 +022b0000000100ba0000049c0614000a00bc4029081105060507110606050311040504021105 +0504420805020303bc009709060501040608010800460b10fcec32d4c4113931002f3cece417 +39304b5358071004ed071005ed071005ed071004ed5922b2100c01015d405f04020a08160227 +0229052b0856026602670873027705820289058e08930296059708a3021209050906020b030a +072803270428052b062b07400c6803600c8903850489058d068f079a039707aa03a705b607c5 +07d607f703f003f704f0041a5d71005d1333110133090123011123bab90225ebfdae026bf0fd +c7b90614fc6901e3fdf4fdac0223fddd000200f0000001c3042300030007001c400e068304a6 +0083020501030400180810fc3cec3231002fecf4ec303733152311331523f0d3d3d3d3fefe04 +23fe000000000002000300000000001400010000000000340004002000000004000400010000 +f027ffff0000f000ffff10000001000000000006005a00000000002800000001000200030004 +00050006000700080009000a000b000c000d000e000f00100011001200130014001500160017 +00180019001a001b001c001d001e001f002000210022002300240025002600270000013500b8 +00cb00cb00c100aa009c01a600b800660000007100cb00a002b20085007500b800c301cb0189 +022d00cb00a600f000d300aa008700cb03aa0400014a003300cb000000d9050200f4015400b4 +009c01390114013907060400044e04b4045204b804e704cd0037047304cd04600473013303a2 +055605a60556053903c5021200c9001f00b801df007300ba03e9033303bc0444040e00df03cd +03aa00e503aa0404000000cb008f00a4007b00b80014016f007f027b0252008f00c705cd009a +009a006f00cb00cd019e01d300f000ba018300d5009803040248009e01d500c100cb00f60083 +0354027f00000333026600d300c700a400cd008f009a0073040005d5010a00fe022b00a400b4 +009c00000062009c0000001d032d05d505d505d505f0007f007b005400a406b80614072301d3 +00b800cb00a601c301ec069300a000d3035c037103db0185042304a80448008f013901140139 +0360008f05d5019a0614072306660179046004600460047b009c00000277046001aa00e90460 +0762007b00c5007f027b000000b4025205cd006600bc00660077061000cd013b01850389008f +007b0000001d00cd074a042f009c009c0000077d006f0000006f0335006a006f007b00ae00b2 +002d0396008f027b00f600830354063705f6008f009c04e10266008f018d02f600cd03440029 +006604ee00730000140000960000b707060504030201002c2010b002254964b040515820c859 +212d2cb002254964b040515820c859212d2c20100720b00050b00d7920b8ffff5058041b0559 +b0051cb0032508b0042523e120b00050b00d7920b8ffff5058041b0559b0051cb0032508e12d +2c4b505820b0fd454459212d2cb002254560442d2c4b5358b00225b0022545445921212d2c45 +442d2cb00225b0022549b00525b005254960b0206368208a108a233a8a10653a2d0000010000 +000251ebb40a581c5f0f3cf5001f080000000000c896fa5500000000c896fa55f7d6fcae0d72 +095500000008000000010000000000010000076dfe1d00000de2f7d6fa510d72000100000000 +00000000000000000000002804cd00660514008704ec0071034a00ba04bc003d059600730239 +00c1023900c1051200ba032300370466007104e500710400ffec042b006f031f00b0031f00a4 +028b0000050e00c9064c0073058f00c905fc00c90579001004e3fffa05790010062900c90514 +007107cb00ba051200ae04e7007b02e3006406b400d905140071047500c9051400ba051200ba +051400ba04bc003d03ae00c504a200ba02b200f000000000000000440000013c000002100000 +0280000003a40000043c00000478000004c800000540000005bc00000654000006f800000724 +00000884000008f40000094c0000094c000009ac00000a3800000b4c00000bf400000cd40000 +0d4400000e4000000ec000000f580000101c000010a0000011cc000011f80000127000001338 +0000137c0000141c000014940000152c000016f8000017640000185400001894000100000028 +0354002b0068000c000200100099000800000415021600080004b8028040fffbfe03fa1403f9 +2503f83203f79603f60e03f5fe03f4fe03f32503f20e03f19603f02503ef8a4105effe03ee96 +03ed9603ecfa03ebfa03eafe03e93a03e84203e7fe03e63203e5e45305e59603e48a4105e453 +03e3e22f05e3fa03e22f03e1fe03e0fe03df3203de1403dd9603dcfe03db1203da7d03d9bb03 +d8fe03d68a4105d67d03d5d44705d57d03d44703d3d21b05d3fe03d21b03d1fe03d0fe03cffe +03cefe03cd9603cccb1e05ccfe03cb1e03ca3203c9fe03c6851105c61c03c51603c4fe03c3fe +03c2fe03c1fe03c0fe03bffe03befe03bdfe03bcfe03bbfe03ba1103b9862505b9fe03b8b7bb +05b8fe03b7b65d05b7bb03b78004b6b52505b65d40ff03b64004b52503b4fe03b39603b2fe03 +b1fe03b0fe03affe03ae6403ad0e03acab2505ac6403abaa1205ab2503aa1203a98a4105a9fa +03a8fe03a7fe03a6fe03a51203a4fe03a3a20e05a33203a20e03a16403a08a4105a096039ffe +039e9d0c059efe039d0c039c9b19059c64039b9a10059b19039a1003990a0398fe0397960d05 +97fe03960d03958a410595960394930e05942803930e0392fa039190bb0591fe03908f5d0590 +bb039080048f8e25058f5d038f40048e25038dfe038c8b2e058cfe038b2e038a8625058a4103 +89880b05891403880b03878625058764038685110586250385110384fe038382110583fe0382 +110381fe0380fe037ffe0340ff7e7d7d057efe037d7d037c64037b5415057b25037afe0379fe +03780e03770c03760a0375fe0374fa0373fa0372fa0371fa0370fe036ffe036efe036c21036b +fe036a1142056a530369fe03687d036711420566fe0365fe0364fe0363fe0362fe03613a0360 +fa035e0c035dfe035bfe035afe0359580a0559fa03580a035716190557320356fe0355541505 +55420354150353011005531803521403514a130551fe03500b034ffe034e4d10054efe034d10 +034cfe034b4a13054bfe034a4910054a1303491d0d05491003480d0347fe0346960345960344 +fe0343022d0543fa0342bb03414b0340fe033ffe033e3d12053e14033d3c0f053d12033c3b0d +053c40ff0f033b0d033afe0339fe033837140538fa033736100537140336350b05361003350b +03341e03330d0332310b0532fe03310b03302f0b05300d032f0b032e2d09052e10032d09032c +32032b2a25052b64032a2912052a25032912032827250528410327250326250b05260f03250b +0324fe0323fe03220f03210110052112032064031ffa031e1d0d051e64031d0d031c1142051c +fe031bfa031a42031911420519fe031864031716190517fe031601100516190315fe0314fe03 +13fe031211420512fe0311022d05114203107d030f64030efe030d0c16050dfe030c0110050c +16030bfe030a100309fe0308022d0508fe030714030664030401100504fe03401503022d0503 +fe0302011005022d0301100300fe0301b80164858d012b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b002b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b1d00> +] def +/f-0-0 currentdict end definefont pop +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 0 -1 546 666 +%%EndPageSetup +q 0 -1 546 667 rectclip q +0 665.925 546 -666 re W n +0 g +0.663875 w +0 J +0 j +[] 0.0 d +4 M q 1 0 0 -1 0 665.924988 cm +0.332 0.91 92.867 57.141 re S Q +BT +16 0 0 16 20.902991 631.872559 Tm +/f-0-0 1 Tf +<010203040203>Tj +ET +q 1 0 0 -1 0 665.924988 cm +452.164 0.34 92.867 57.141 re S Q +BT +16 0 0 16 472.736133 632.443994 Tm +/f-0-0 1 Tf +<050607020809>Tj +ET +1.029478 w +[ 4.117912 4.117912] 0 d +q 1 0 0 -1 0 665.924988 cm +41.453 63.719 m 41.453 665.922 l S Q +[ 4.117912 4.117912] 0 d +q 1 0 0 -1 0 665.924988 cm +500.469 61.043 m 500.469 663.246 l S Q +BT +12.8 0 0 12.8 312.98374 563.66853 Tm +/f-0-0 1 Tf +[<020a>-1<0b>1<03>20<020c0a>-1<0b>1<08>-1<0c0d>-1<0203>-1<040203>-1<0c +0a>-1<0b>1<08>-1<08>-1<020a>-1<09>-1<0e0f>]TJ +ET +BT +12.8 0 0 12.8 216.362964 532.03114 Tm +/f-0-0 1 Tf +[<03>21<020a>-1<020704020d10>-1<11>-1<05>-1<121311>-1<0c05>-1<12140c11>-1<15 +11>-1<14160c0111>-1<13>54<1511>-1<130c1718>1<18>]TJ +ET +BT +12.8 0 0 12.8 215.566675 409.19657 Tm +/f-0-0 1 Tf +[<03>21<020a>-1<020704020d10>-1<11>-1<05>-1<121311>-1<0c05>-1<12140c11>-1<15 +11>-1<14160c0111>-1<13>54<1511>-1<130c18>18<17>79<16>77<17>]TJ +ET +BT +12.8 0 0 12.8 334.803003 271.936462 Tm +/f-0-0 1 Tf +[<020a>-1<0b>1<03>20<020c0a>-1<0b>1<08>-1<0c0d>-1<0203>-1<040203>-1<0c +0d0208>-1<190e>-1<0f>]TJ +ET +BT +9.6 0 0 9.6 205.503491 441.642078 Tm +/f-0-0 1 Tf +[<0a>-1<0b>1<1a>-1<1b>-1<08>-1<07>1<0a>-1<1c>-1<09070b>1<08>-1<10>-1<0d +0203>-1<040203>-1<10>-1<1d1e10>-1<0a>-1<06>1<070208>-1<09>]TJ +ET +0.8 w +[] 0.0 d +q 1 0 0 -1 0 665.924988 cm +43.879 280.043 m 493.195 280.043 l S Q +485.195 385.882 m 481.996 382.683 l 493.195 385.882 l 481.996 389.081 l +h +485.195 385.882 m f* +0.8 w +q -1 0 0 1 0 665.924988 cm +-485.195 -280.043 m -481.996 -283.242 l -493.195 -280.043 l -481.996 +-276.844 l h +-485.195 -280.043 m S Q +0.701961 g +0.8 w +[ 1.6 3.2] 0 d +q 1 0 0 -1 0 665.924988 cm +44.688 81.246 451.738 75.961 re S Q +0 g +BT +9.6 0 0 9.6 205.503491 590.33656 Tm +/f-0-0 1 Tf +[<0a>-1<06>1<070208>-1<0910>-1<0a>-1<0b>1<08>-1<08>-1<020a>-1<09>-1<07>1<08>-1<1f +10>-1<0b>1<08>-1<10>-1<0d0203>-1<040203>]TJ +ET +BT +9.6 0 0 9.6 207.119751 293.639929 Tm +/f-0-0 1 Tf +[<0a>-1<0b>1<1a>-1<1b>-1<08>-1<07>1<0a>-1<1c>-1<09070b>1<08>-1<10>-1<0a>-1<06>1<07 +0208>-1<0910>-1<1d1e10>-1<0d0203>-1<040203>]TJ +ET +0.800568 w +[] 0.0 d +q 1 0 0 -1 0 665.924988 cm +494.324 428.855 m 44.367 428.855 l S Q +52.375 237.07 m 55.574 240.273 l 44.367 237.07 l 55.574 233.87 l h +52.375 237.07 m f* +0.800568 w +q 1 -0.000000000000000122 -0.000000000000000122 -1 0 665.924988 cm +52.375 428.855 m 55.574 425.652 l 44.367 428.855 l 55.574 432.055 l h +52.375 428.855 m S Q +BT +12.8 0 0 12.8 345.308594 116.777039 Tm +/f-0-0 1 Tf +[<020a>-1<0b>1<03>20<020c0a>-1<0b>1<08>-1<0c0d>-1<0203>-1<040203>-1<0c +190206>1<0e>-1<0f>]TJ +ET +BT +12.8 0 0 12.8 215.416064 85.139587 Tm +/f-0-0 1 Tf +[<03>21<020a>-1<020704020d10>-1<11>-1<05>-1<121311>-1<0c05>-1<12140c11>-1<15 +11>-1<14160c0111>-1<13>54<1511>-1<130c1811>-1<20>]TJ +ET +0.701961 g +0.8 w +[ 1.6 3.2] 0 d +q 1 0 0 -1 0 665.924988 cm +44.281 227.516 451.742 75.965 re S Q +[ 1.6 3.2] 0 d +q 1 0 0 -1 0 665.924988 cm +43.477 375.402 451.738 75.961 re S Q +[ 1.6 3.2] 0 d +q 1 0 0 -1 0 665.924988 cm +43.477 531.371 451.738 75.961 re S Q +0 g +BT +9.6 0 0 9.6 233.439209 138.249939 Tm +/f-0-0 1 Tf +[<0a>-1<06>1<070208>-1<0910>-1<1907>1<0d>-1<0a>-1<0b>1<08>-1<08>-1<020a>-1<09>-1<07>1<0b +08>]TJ +ET +0.8 g +BT +12.8 0 0 12.8 46.878833 549.018738 Tm +/f-0-0 1 Tf +[<0d0203>-1<040203>-1<10>-1<03>21<020a>-1<020704020d10>-1<1c08>-1<1910>-1<1c +0a>-1<0a>-1<022109>-1<1009>-1<22>-1<02100a>-1<0b08>-1<08>-1<020a>-1<09 +070b>1<08>]TJ +ET +BT +12.8 0 0 12.8 45.262585 422.951697 Tm +/f-0-0 1 Tf +[<0d0203>-1<040203>-1<10>-1<0d0208>-1<190d>-1<10191c>-1<091c>-1<1009>-1<0b>1<10>-1<09 +22>-1<0210>-1<0a>-1<06>1<070208>-1<09>]TJ +ET +BT +12.8 0 0 12.8 45.262588 246.781092 Tm +/f-0-0 1 Tf +[<0d0203>-1<040203>-1<10>-1<03>21<020a>-1<020704020d10>-1<191c09>-1<1c +10>-1<0d0208>-1<09>-1<10232410>-1<0a>-1<06>1<070208>-1<09>]TJ +ET +BT +12.8 0 0 12.8 45.262585 101.319128 Tm +/f-0-0 1 Tf +[<0d0203>-1<040203>-1<10>-1<03>21<020a>-1<020704020d10>-1<25>-1<0a>-1<0b>1<08>-1<08>-1<02 +0a>-1<09>-1<07>1<0b08>-1<100a>-1<060b>1<0d>-1<021925>]TJ +ET +0 g +BT +12.8 0 0 12.8 347.920971 516.693861 Tm +/f-0-0 1 Tf +[<0a>-1<1c0606>1<231c>-1<0a>-1<26>-1<100a>-1<1c>-1<06>1<06021927>-1<10 +0c1c>-1<19190e0f>]TJ +ET +BT +12.8 0 0 12.8 345.595336 393.859315 Tm +/f-0-0 1 Tf +[<0a>-1<1c0606>1<231c>-1<0a>-1<26>-1<100a>-1<1c>-1<06>1<06021927>-1<10 +0c191c>-1<091c>-1<0e0f>]TJ +ET +BT +12.8 0 0 12.8 348.430322 64.95365 Tm +/f-0-0 1 Tf +[<0a>-1<1c0606>1<231c>-1<0a>-1<26>-1<100a>-1<1c>-1<06>1<06021927>-1<10 +0c1902060e0f>]TJ +ET +Q Q +showpage +%%Trailer +count op_count sub {pop} repeat +countdictstack dict_count sub {end} repeat +cairo_eps_state restore +%%EOF diff --git a/doc/img/ecore_con-client-server-example2.png b/doc/img/ecore_con-client-server-example2.png new file mode 100644 index 0000000000000000000000000000000000000000..d72ee56b2245ace0a564f2d7f386f794fd17168e GIT binary patch literal 67464 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

&XeBV75&k>epsAyc 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 uJ$o(PIi(r=Yyb7+G-dwY# +] def +/f-0-0 currentdict end definefont pop +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 0 -1 546 666 +%%EndPageSetup +q 0 -1 546 667 rectclip q +0 665.925 546 -666 re W n +0 g +0.663875 w +0 J +0 j +[] 0.0 d +4 M q 1 0 0 -1 0 665.924988 cm +0.332 0.91 92.867 57.141 re S Q +BT +16 0 0 16 20.902991 631.872559 Tm +/f-0-0 1 Tf +<010203040203>Tj +ET +q 1 0 0 -1 0 665.924988 cm +452.164 0.34 92.867 57.141 re S Q +BT +16 0 0 16 472.736133 632.443994 Tm +/f-0-0 1 Tf +<050607020809>Tj +ET +1.029478 w +[ 4.117912 4.117912] 0 d +q 1 0 0 -1 0 665.924988 cm +41.453 63.719 m 41.453 665.922 l S Q +[ 4.117912 4.117912] 0 d +q 1 0 0 -1 0 665.924988 cm +500.469 61.043 m 500.469 663.246 l S Q +BT +12.8 0 0 12.8 312.98374 563.66853 Tm +/f-0-0 1 Tf +[<020a>-1<0b>1<03>20<020c0a>-1<0b>1<08>-1<0c0d>-1<0203>-1<040203>-1<0c +0a>-1<0b>1<08>-1<08>-1<020a>-1<09>-1<0e0f>]TJ +ET +BT +12.8 0 0 12.8 47.919678 540.232996 Tm +/f-0-0 1 Tf +[<03>21<020a>-1<020704020d10>-1<11>-1<05>-1<121311>-1<0c05>-1<12140c11>-1<15 +11>-1<14160c05>-1<171811>-1<14160c191a>1<1a>]TJ +ET +BT +12.8 0 0 12.8 216.362964 515.060583 Tm +/f-0-0 1 Tf +[<03>21<020a>-1<020704020d10>-1<11>-1<05>-1<121311>-1<0c05>-1<12140c11>-1<15 +11>-1<14160c0111>-1<13>54<1511>-1<130c191a>1<1a>]TJ +ET +BT +12.8 0 0 12.8 44.687207 414.165955 Tm +/f-0-0 1 Tf +[<020a>-1<0b>1<03>20<020c0a>-1<0b>1<08>-1<0c0a>-1<0607>1<0208>-1<09>-1<0c +0d0208>-1<1b0e>-1<0f>]TJ +ET +BT +12.8 0 0 12.8 215.566675 397.882874 Tm +/f-0-0 1 Tf +[<03>21<020a>-1<020704020d10>-1<11>-1<05>-1<121311>-1<0c05>-1<12140c11>-1<15 +11>-1<14160c0111>-1<13>54<1511>-1<130c1a>18<19>79<16>77<19>]TJ +ET +BT +12.8 0 0 12.8 334.803003 271.936462 Tm +/f-0-0 1 Tf +[<020a>-1<0b>1<03>20<020c0a>-1<0b>1<08>-1<0c0d>-1<0203>-1<040203>-1<0c +0d0208>-1<1b0e>-1<0f>]TJ +ET +BT +12.8 0 0 12.8 46.65733 249.188416 Tm +/f-0-0 1 Tf +[<03>21<020a>-1<020704020d10>-1<11>-1<05>-1<121311>-1<0c05>-1<12140c11>-1<15 +11>-1<14160c05>-1<171811>-1<14160c1a>18<19>78<16>78<19>]TJ +ET +BT +9.6 0 0 9.6 205.503491 441.642078 Tm +/f-0-0 1 Tf +[<0a>-1<0b>1<1c>-1<1d>-1<08>-1<07>1<0a>-1<1e>-1<09070b>1<08>-1<10>-1<0d +0203>-1<040203>-1<10>-1<1f2010>-1<0a>-1<06>1<070208>-1<09>]TJ +ET +0.8 w +[] 0.0 d +q 1 0 0 -1 0 665.924988 cm +43.879 280.043 m 493.195 280.043 l S Q +485.195 385.882 m 481.996 382.683 l 493.195 385.882 l 481.996 389.081 l +h +485.195 385.882 m f* +0.8 w +q -1 0 0 1 0 665.924988 cm +-485.195 -280.043 m -481.996 -283.242 l -493.195 -280.043 l -481.996 +-276.844 l h +-485.195 -280.043 m S Q +0.701961 g +0.8 w +[ 1.6 3.2] 0 d +q 1 0 0 -1 0 665.924988 cm +44.688 81.246 451.738 75.961 re S Q +0 g +BT +9.6 0 0 9.6 205.503491 590.33656 Tm +/f-0-0 1 Tf +[<0a>-1<06>1<070208>-1<0910>-1<0a>-1<0b>1<08>-1<08>-1<020a>-1<09>-1<07>1<08>-1<21 +10>-1<0b>1<08>-1<10>-1<0d0203>-1<040203>]TJ +ET +BT +9.6 0 0 9.6 207.119751 293.639929 Tm +/f-0-0 1 Tf +[<0a>-1<0b>1<1c>-1<1d>-1<08>-1<07>1<0a>-1<1e>-1<09070b>1<08>-1<10>-1<0a>-1<06>1<07 +0208>-1<0910>-1<1f2010>-1<0d0203>-1<040203>]TJ +ET +0.800568 w +[] 0.0 d +q 1 0 0 -1 0 665.924988 cm +494.324 428.855 m 44.367 428.855 l S Q +52.375 237.07 m 55.574 240.273 l 44.367 237.07 l 55.574 233.87 l h +52.375 237.07 m f* +0.800568 w +q 1 -0.000000000000000122 -0.000000000000000122 -1 0 665.924988 cm +52.375 428.855 m 55.574 425.652 l 44.367 428.855 l 55.574 432.055 l h +52.375 428.855 m S Q +BT +12.8 0 0 12.8 345.308594 116.777039 Tm +/f-0-0 1 Tf +[<020a>-1<0b>1<03>20<020c0a>-1<0b>1<08>-1<0c0d>-1<0203>-1<040203>-1<0c +1b0206>1<0e>-1<0f>]TJ +ET +BT +12.8 0 0 12.8 46.506689 96.453308 Tm +/f-0-0 1 Tf +[<03>21<020a>-1<020704020d10>-1<11>-1<05>-1<121311>-1<0c05>-1<12140c11>-1<15 +11>-1<14160c05>-1<171811>-1<14160c1a11>-1<17>]TJ +ET +BT +12.8 0 0 12.8 215.416064 79.482751 Tm +/f-0-0 1 Tf +[<03>21<020a>-1<020704020d10>-1<11>-1<05>-1<121311>-1<0c05>-1<12140c11>-1<15 +11>-1<14160c0111>-1<13>54<1511>-1<130c1a11>-1<17>]TJ +ET +0.701961 g +0.8 w +[ 1.6 3.2] 0 d +q 1 0 0 -1 0 665.924988 cm +44.281 227.516 451.742 75.965 re S Q +[ 1.6 3.2] 0 d +q 1 0 0 -1 0 665.924988 cm +43.477 375.402 451.738 75.961 re S Q +[ 1.6 3.2] 0 d +q 1 0 0 -1 0 665.924988 cm +43.477 531.371 451.738 75.961 re S Q +0 g +BT +9.6 0 0 9.6 233.439209 138.249939 Tm +/f-0-0 1 Tf +[<0a>-1<06>1<070208>-1<0910>-1<1b07>1<0d>-1<0a>-1<0b>1<08>-1<08>-1<020a>-1<09>-1<07>1<0b +08>]TJ +ET +Q Q +showpage +%%Trailer +count op_count sub {pop} repeat +countdictstack dict_count sub {end} repeat +cairo_eps_state restore +%%EOF diff --git a/doc/img/ecore_con-client-server.png b/doc/img/ecore_con-client-server.png new file mode 100644 index 0000000000000000000000000000000000000000..c435b54f718a94a7c36faf1a7c27ec72c27d0784 GIT binary patch literal 58250 zcmd?QXH-*L8#NjddbQ9IPyq`aLX(b)5~|XrBM=B3L3#2q2&k ziUEbtiwL2H9%^pXbKdd&y5H|RE+Y)c%Ff!)+I#Kw%xBKI{<&v(mxYm+5dZ+NKy+>! z0|3A>004BCo|e+Gt-#hv`9tl06JknF`3a|YenxrE;H&e%pK|=j?_a8$*Rp~sjXVL` zmH{R{(10MvM=pS%pdd+@w}-!zqpypk&m-5YbyZ#f;35EWTgx;!do?F0<3i`R_~|@q zM&W<5(SYbLUo)7mpoRIWzMi`=Nv`)n9n1>Cf=6 zFCV=NE&n#LIyFTw3>z!m5BY`9SP7gCw=fE>DVwuWtC<%Yo+c^LcZed!&orc1Du z(3O9~vAfOe@$bLI46*Wm!n(LL{G^TdPq=3S+}j;k{)Ve8|9^}23iFSD2WE1f_WwKG zUVn*l5!oF`?GuHCK+r$*D*JoncFh5r#`ZIOU_J{U+rQ%m14d@!MYGypc*`{L{5>pUVwWj zTGS|2-!Ik-r%QTz1Rx=i5wA=0_@gc}{29~I>VP8~x!s zuPl1Q&(%&__%R(PwK^DG>279>17f(rS)vKEp--sGkm^zce5C;BUNO@4KEVOPq$dg) zyMQzP6uM6NicrmOub=(kpP?`UKK}*l>B$p%f&u@+Kb>N+DDvf-}9w zy4ph30lf}*e>h`lba<-NKLR8zDMToEpVuuHCa5WR{l z&RG!Vmmmnu@Xz$JziM#16ZimP58MVt4EZg1xfxu2$apXDHM}|+Unx%qS&pT5#h`5AXgE@~dS2v& zpW73PzgjdOof9n&PlkUtIk=^1Vi3#v=lKPrc?bFH3%)Rn(1rpdh=bAOOE7~O1x*Yd zL+=o%dOQP#P@YK3U#|(qDpvu$v$fbDOg?Jc7t))74|ZVpz3dyjO#ZB|B30XwG4?c+ zyDYI_0D;n&6I-0B4Agv1)xc*-r39+yCQ;k}6C~=}grb7(g{}{3NAtml;MOL1*Lv3w zeg}&Q>AwAsOp%V2{V5xX)51oeyPyFo|AP5M>MN)%)%1BId27%H5N*cy_n9QPJ zd2C9DD5UD|O!#hwT`ka`JgC2a5Cj?FctXz%NRvSiBp)->&#x|$GT&SQ^U-8qgK0S2 z0jne#eqm>0kVc33#`;@LY?CTb-6A=nu#*7CtyNGNb+!YP4v8Ov?zJFoS&l_NJ`Qj5 z^9Mx9qBXMcv9K_jdRh|as0h#d2R}MY?%UY65D`#N9KZ*-l7W{fCSNrn8-b!;%UMLT z=25L=;S->HFOicEj_{0suJ(D8T&t)`(9tNnC9jf(M;TC9Wx>9_8GWbi!`1YJ@4`Nq zHCWJxSNH3j-s@S3f%)ign6XXm}@tCgp!2QDS>eGlo^k=*~YuJOL8mKiMq9a)M- z^otT^j=OG4`P_fM;7{YiRxog5-1^%ql(!VCG@1+`LtYf7btEsael|MhN2K+9j@{`V z(#)1Be&2wM#tR$xK&PQS(|w((&<5^A*GU$|lq5MJqTVrtko(f}z<}MFgL??DT{!SI zOGL2n@A~XSbU(DIqMTef!kf<1TI<(chqRcjO0h5PrhBzRjba|qX(V0<8c6R=YJMf< zKE`%Y1fRph9WPZVI+ojRJ2CVtvofu5)=rhYA|=xIx~H}qlqv6X=I4h9YXexRH z!Hw5{vvjWdo8h8vB8-MGZ@RBA}clie`ze;vvm?hJ-JQN$)WndMb3c!)n1+AQOxU z+6YO*?v0q%;<=Jfnv8;@=UX!tQHu9ekw3YBk+j(O?kV%IyS{&>4NDv{=MuqiMqjmg zxC^G6!R9*k(kY&BS<$V1x zHrL>h8ZqU8R3@J4An=h_|Fc$`d==tr9Csb(~|g81#Q`JMjBqThbpsQoNVj@1~_%bQBic^)^t?2kDt4;+wcmhY3r_R!4`c z71g)#2B`X}{RU1Iy2rE%oC_;>9xmIz*^#=9O#lB=M3eu2$6tlTb-=$sWbKPM!mzaN zoK}+z9URLHu?GnbKX{XWlF^5S{%)qsBk6*q8U>lyiF+CNW?3`^QvL;p)Exg@ef|G} z_#8yFam9$hiaG&)180W6*fJyZ;D&VJlx~3BtmFTHC5tNsDH-Foc7F){J<3gxx8H&0 zl+n}HN8~U1irKsL@Lz;nXlF<>Ra|$D|9?Q))&T{I1MG7r`8(L#3>-m{|xarY(Hj$Oo~Wc zfnA48ialGS4u7rUT@heYr;nFIK=r2=)8!%xE9eHfmc)uHQG}AEVQ@$Ym&E(5*8FL2 z#35?KUpMnckbY&&Iy`eeBBxFdDVcvskWK^wi%)t!Kmp*G^F7;vc^{ z9>seEfHX7xY=mTL;fy5+eAI2i7g$r4%WvQP1KR;QR$Re+^-M}!^-VELO`5F%SR2GT z)g6E$P)gTI{A)RjstCb-CU8aq5?|CP0XKlFMUTVZQ39nWvDcrgzlpn191ex-7e;PS z+aYR#mCFQ)cA2lD&TwBRF@ZS0bc+<%x2>{KQ&RxoFLhnr-V*bTXVvSR!YcGku4d2=J{#-4*UjVx7EBIFOdU zKyq1jZO|V-A<|_LaHs!Zu40~Iu0d3sO+&8kk~w{?k}9;$1o&ag-Y7WS$+u|UeI`*` z3a?shjYZW2++rNYp9e34nIjyfVh%8JFf#SbkDZ7J415}OA_5-(ud&gbT51=G zM1R0sK~`5AUY)=5Lq9mUod%;;?7ca>u`zTij;Yg}u8F!#l&{hpBlG({KAhrHqz*DX zQuBMa&jusQ%{V%|s+lf7Cetc5ru8i;14!a%@)hriU0@?D5Y z`t=lN%x1VXG1>KgM@^@gz)FgE}xx?hHx5QblesQ8?n zPqX?J>$}4xAle~y_S9)f0SJ^CF1SlKli!ks1RP}*mr({|hKsaI2Oay;Sd z=`fy5tG^po8eo?WjC8<-&EnG58!pl}N^Z`&O$Il3e6JQ!}zxXQx(WE6uol&QO03;mvDvbNgMm115$P z(oqXo&)X7o8TfsK9gVsII(d8dyw{KCFWYXN72O09uR@ypR*!%YBOq^`qm}utO>T%k zE-<${p=KPrif2^zqMb0lH-ZZ;kpYgXqg#~)UfuibQNLNIyk0;fNdCgOWhR5JBi?&` zOJtJqm@#jPOdH&Zt?<_N?|?@KFLjHg{Su3Ijed+>-SGM*Lm$(Vfj`~-;i!A&H$#wt z&qBljM|70A5{qnlu&;b(2Zi9E;tZa~N_KHsuo%6liUXZQ zXJJ=U<#OMNu(-Z;{a_vkqyRF(U}iQg5@W`_{CP!$AzgoZfNT|`dc^cHyCZCN=q4sP z_^{d~8r0{RjS`AB5s^p^u)2`wb8^2{$K5mEbw^3R@MvHq&J1to+iy zVpu#KSE*pnm6+GJ0@lKXV(jV_H&s+?&x4!nab3mJPvOzfK!4?c0Gv#3XZ=3AY9Tml znV{#OQ#c(f;*}8Qn~qUS-$ymliIg*}zN~y1#bRGZ>nkj9wTV&SAyM+R{JNnl?m97E zXJ{F^mx?m;-S`zeK@8(0U5m0q96KU%yPb43Xw2o&BPP4C`paG?R7z)7klKPb9>gqaEsd{!B4J#>|H zvwmP}jRM3{zJ2D&>e9rOVG_$fZd}iUkUEP-HK1j3Jbou)~J#}KK zx*ddva@p}8;X#`h5_<#Vwv3DAL{p{CF5I7D=;6YqCjLX|^VUIj!?B>+>7?iU!cI{mY+8a|}JBU6H}CEaVgx z7QQhsFlZXSpZ6DZImo)zYg<4AO)A{1u0;3*|3N-&rgu$DhH#|IV*|_Oy(xuf)yhKl zfRg2Zk=z;T)w8<9g5i z3#Wcxa$oCru6Nz*Ujrbq!sYmC=f59G%Mbd}iusQBmrGm9mO{Ed?~ z|7IHe9XxRbg=2pw#$6Uhb)Et?{zmI8OU-@f%Je7Xq?w{u;YAjosyk_vm6j3-|NECK+1wRAbDLAs`vhuZXUsLRjoF z&u~M)b%jEZBfYVFm#@WHaf+7zh*SN+$^inkRKL1ehQ+yN_Ifb7bPAM-G&wvhXI&9& z@uvm&ITO*e*><{M5uuAgJr=X39D}?Ki)?`$+4I89eH}ocM5phRX*}^#SCH5hr zB6a5#N>Rl23T(NK z;EI0X^&w$;p_;fN#1tYxdrw`*i9a)dbk8^$#qr2%HLb_hX#d+0p+)K9)jDt9`A>-c z*E@}<5n=wkPdN|p-U!yz9m~d%yw^2B(WlKKIj>JS)zf#XQQ(DDrd6sP!;>j7LKk+n z2^56HtKb#-R>fwPP3`}=6hJj!^X&J%hcP(3L`E?GnM?Wn6fR7}m)}>p>bmbaX(?Z7 zIBFf!jFH7m6G@*MaDHmhdBPH`sw|&gExuZ1J?7!Q1cM_JbWd0S=G2j~Mx_F@pRN?M z5%rbVr!l?tj=q&B7VPSj6|E3VW`<#=L+({#bOC$;EE@(Q)7d0-eG>MSBZ3{~_5D`> zXg~yfJDLDLf%6GV_{f)erpaCPr6W2k3%-L#YLZ`K%P5?mC-2cp{jFb@ARb8kJ4lU2 zWQ2mQlPWNn%YM-RJ<0^TdZfSK1Sl1GAS^+xN)!HEB}|=ak0$qZO$;(Yzgr^Kz9=WU z34SZu!kX7(+3A{hN={rJnJ2krn@Uh8Q=KpfQex$1Ipz#D#f3umeBIqIIYi7DItUZF z9PZADLpG3j1Bf^4vGOD!oGKe`-ysCAgtxj5H_=8N49a7QF=@rkH~LoVQBiCZNa;8e zJkyCfs`R}(lT3Zo?~ z;fwOK3dh~w;Sv4|Q8bajUy!4ts|}A!YaZY5rtizRp2bF%(GW8Uv~~B$n%E=*x~Q0b z_2khCcy(rYcO`sBiVp9$Cv~4pKkr{!{?9bg7-<{f~tQ`S!1YJb|j7&_oNKTOz;o^C~Ug zOQjEdf3D!umGhXzpyMg^Pnf$qFXM#0XzJxxlv+4{SNv62oq*{3qojW{%1+=TqVkBs zn~PNH*WO2F{i0m~L-)KYJY^=vEq3NTF`o5Tt9Y4aO!|B*lCF2>MJhq)p!34biBcI~ zWiQuhC`WMe!34Eo+VoWD{>Pgi;Qq$v~Ir!rh?X+jlvEcGs^(F}0p<&p5Kq zT!L@>{Hgx#Kpx0u^0jxjXH|+-pN*a8tp?D)XyXJhWt_@iins5*o4!PJ${oHsDduO};(T971liBgdKP?eZSK@wWK|V*x=^LJHFwHe zkG*oGgsl2q(Bw@b^3j^vauKiDM)K#Y!8X3RTkM^*%0ag)EqPDz@mOYhm zU|OhVuc==97W^KgIT1USuCJsS`aYO*^p5deJY6CcSZA#2IhNkRMSkFJ;|*dOGGZjU zQQ{Je!1+^v?uX8c1<_3jfkxSgisJ&)k;;Qhudhc{-;7A_J4e9^rN|R3HZEmfuK+h{ zT+Cj1gMxb8_|j*@aw}6z5yN+J*eyBzMd!%ZM!*&-@06NM6yfLfBMe}`MfJI zNys)8*X-uokNO^`3~XBU<~YXd9|u(twJAI4<}V4p4rVhz3IQLOW~Q6t0?nH*t!H~( zgGM2R%U?>lg(e3E#-O$j=^!V<2Fcajt1;cI=|wGU-9hK+l=u*}+|0B5mAzBr?Z zJbKlng!2Z+REcKIN}axYx+8vc5ITb{>0X;yKBo>`y(>b_)jjHius@?ZIP^iIIvR2) zCZO=hQ)TJiKifo4(1`AsFhQXd^?iZxxkq7W+E?l%0by>qKX7wv$I%7J<;S;TgfN%j zYlAAVCejIL%7BQLL?f}`yJ>LBLMuU8ZN&(WPq9_2}NcO&V!bs?#BdfRVMglPc2eXRzn|g9aH5M)6FK z#j7)eHh5J?WE1aWJTUK-!o(TbiF=c>SL0P?jd6h(k{4aSEO_x1*!y6mMbaxZ{ zI#kC8uFcf(AZLRmztv6{`On0y)axG!Qh{V;JwO}I%dH?*?8j}cnckQ^DPV5jYC4+w zCs_Of?Qw=!mda$*dD#f^6RF!Kcf22{a#-$NXr>P6{gRDX|FDU1Z3y#Gtoxu&Upn>s~7Re*Lvmr=u2mdv>$5ECx$zZZGHt$8b;w*VzQR zsSgUrXCTWjq;B#i2k?xvUrHTAa%ISW+zio*kP64XqtME#*4I@XPf@+;m?j08S~)2d zrk3E<7pS0k>}3iWFz``@H_>VAlCj2rUVw^_OZO7i_S?B|5pelsWA+2-h9vVXo&DLH^;(CK30_9A@i}rxd>eA>mY>n#Tc|=IN25C91QZ(Up$2tF z&9eOX@-K*Xy@^u@9;-R%^VFApI8A-(2zC8fT`uWZr4Vi<_7{_;UknjYbk|zFleJ@D z#Q*$w%}&hx>_Hbcvt-yvUdJkZ`QVm47+qBOS~-Uo++>IAs1M>%MLC$M%Aqb(Y6Crx zV7hLBBvk+*w1;)izkLD=oJYP#1 zogV#tx%@6CxanNfB&@>;x|XDU@x9^wGhS2PREMhQsiq3m8v6@jq^)6(~eP7oQ8Ib7c`OcOGV0<_?!p$DClY9a~&&?oFoBf(&znZ z(Javg(Ff5%n_(2r6)TJ3#iUXQj;Dd{xUGmHxPmpTHu{O1NY5*!O%QlV2kTBVATALuEKxD;K1#$m?>DcGIgDUa9 z@-GAMQKS5CS3?aG^v69u-)mKn=3Tdf{vcq{h;?GNAsNH+`97w*VXY;5bpq1|Ipv>` zoUr82+OxoZ=?B8|ufJUCmlyli!Iw14udHNoc7%lNl8Y*>WH(T?zuy!71)?`G4w`(gnS`#FN! z-IVkFVxJ&p)ZOIkEmUBI9Nj9hA;*Ke*OGoRTS|=lDl0xtBwSb+=V3dxT$^%toDc&H zfac*z7=BC^;gbf#j=>{35w$}L*oqGX`b!^gLI~x`8M(yMuobaIHK;PO-e2qus0yh_ z7%-l+XxM74*|M`$^Jn={adG=r)8DG{Y{P1x%)|SEZ*0!G@g!717xE* z<}2ncW~i9-&;jglSI@3dxXG(zC2JXd>;`2LX=tJNFrxi{0`Ib2Z-9^9b2woWAsAl= z$jnIECJB;xX}6i0cu!QFZj@oP7u!GZ#rqYRI89%cx&pO1RAp4EDsP0!pc_g|?dgvN zMmaQmLTG2%K9Xi=@&ROR_n>CR#)!meA@VI;Q+?5+ZQijwYREQlf1d5OSO$I@ z*{B`;MpH0<@ZA_=t~}bz{E%*)Oa&7Kd(kFiTmwGEjtAK(a-v2Eeu}z;NUPX9{`fhX z6tGJ5z=;Ec?aIL0)u(?@Z6@o@d@lQt>0C+m3Z#%)qg~LCEebGdSG!+YH^jZQ8f~;j z{`P2yVx>qx^3&S@FTz|L6lbu%zu`lBN?mpx)@>u`5j@AwjdbrFbG??P>Io ztnBuDZfDd?Zbu8nB%}7V<37|rKO7ywe8KR;BGCsUCEl4`poCtGj*Z?R2H16ooNVlR zBGN#)Gz#rS)f!YksK>+<*Y-#?bKg^`v7R<}eh{y3UhZ#KOB}BobPdYC+JM;(bPiLs zdu%BZjm@a-bfPmVzZgoj9wEj%^pzAqv>z{V6KgnQc@sC_zaXM&zWw&A+mSM*`1kpG zYtj+bnqv=C%*3x~%l>+~p`*sg{W4ztf;!F71S=c5fjaL^#;Y`P5lQ?%bw7V zO^=ga^S$%bZ9l=(WR`*I8>u7Na?C7T=Ux{*6{ljFk0W$J_s$>txQCuW7CS)bW~Yk5 z(baUj&vqhgd&M~sa<+vhCcd{Ea<^*St+;oDtJu6h8B)lAqyV+5QdAohN~n*lzw5VO zGtHzVn1~)1e@AY^Tt`&Mp$b`bK-i7$g z2^5D`#Ny5h)Mq+e1#$7dTIm_#;F=Eo(|Z*Uu*fH8GRXbbYG^ z00`UM$aahspH66^3fo~Ff{S=BOxxzQbi@?(4as2+2> zMY+9+q%?YiINI`2c-OGAiE6~k+a(Mk(XH&wl%1DAC5JBZt@QZ#y}g4dxbPV4(lo~; z*prKWoQy5LaU#{#oWh4Xv4B5-C!p_?aFj7uXimqJ2k|;dP52(ych&xCQ~UIt^u(r2 zXwU@5hKK~%b*S|mW#Yebj4heuZwGKVzsTUT=dfk^_>y3fnOKZ%APw(MyRTOAa#V7_ zkr6aDOvjDkf_jc|o@H(i?3Pnu$EbYJoc~Mv0a9>}w@*|Pq^hm~4?1&-8LH1gz?%h<~0w~Yp zMqt8{qZ*yjdzE@xJR8NjWrIi5w{1CkL(z2VUbPNZ;?)fv$GiDOkxt3eAR@=! z_Y69F;>ed7?VwkDFsvS0887m=P#|89`B(Jc;( zkxV=_Bz?~0MQf*%370c2qo-QY^Xd#=CRp_2E=$YXIt}mob%3fEfepGhAbL2`qvHUB z4E>n-7(p|78}|wNV>R9occI=d=x&AkCuHjMvR^sHlt|INH_iIj`g9PA&2eUfLeXm? z5)>L{QEUNujztW zaA*OC^81so3v%I|Cud6R_Z5;kz1N>>kXmdnR+pmQxxbv}hYx6eGIpAtBwlFt8NOsl zF(Li3i7ATrbmNs2&WBU-nOQKaQN{@cbXiqJq!$|6zX_S~PfPdP=)S-)2K(9(BBQ?B zD6tNU;8R5Prp)t)nYoe6J)NL?&yoB-P`&xw%IO~g3Rb_!M8f){7=!RTmWd|C=$_oX z4!_C(b@fN*u&b|xx9>ujYRqSOmDu)UEL86zWo%z+U`%<3+DPtu+oB&`py!FES{`#u z`N}WZJye-VPgP}3jY*GTMz7kP>QsJea}&Z@It3#c)%FmfU+qPuJ7v&5n=iS>hqhkc zw8m3M)vKH_5=oofGkPr1g1Q)DVbs-JeUJi89py9n=W(Q73!Cx^unF!y<`Sm!pi`WK8=;<9c7HL`goQ%I z*1N6-L!#1(SVirpU4$oN?2{ic77W2{g>!7|0QDN-% zw+!@%Xh+pf2vx4_TnP{<3;wuglZh`4ex{YxZ4Bz3LDSdijFnsfXRQ|)5a|ZOCw#wI zTIo`KZ*C8fcsbwaD{y-5pOZ1^TB}k1L?N|q?0TO!>DJG9xu|EWxy%Oy5eejJo?0|H zLcj~!r&QB>`f41Ut&F8tFQ%sxH;(^ zT#w-*@uk|e6sb=F(G$ChjfAku9!ip9XS<%E8T#%XB8-;XJimL2 zFv@_rOtZ^0J4-uHac(7(fO#KKb*xlm$GI%Hz~`ZB5lo&_?FZLe2_+@UuzqI6 z9c6Sp>te$@l0}%{IdxLIC?qz+21)mW9cvWM8v;Xrj;ZsLD)I*&%Qn_hibC!2bdFaI z^55-^-$d%9DzGf&{_OE-TuxVsw42~oP|fqYFSvo2`ux4CbvFb_iu)+&zmIdl>_FD@ zMdyP>zM6&(nH9{hfB9k?+uitUcU(qDBR@Y;x?P z#cbR*(=UdV7h`##L@gU;^4V|-+faU(Rzodagp>~pOGF_z6?ZNgQvc%5Ojfz#49Q0(5~lBkB_MQv+y9A$EEX3$9GaH9a)qmPoNzH0FM$Y#lY$q|PhjRNrQ>P<`1jh6 z?dAB^PY)v}=p&WK?K2%M%i3ot9@lx~rn=j8>zjv7Wt2QKL9s|a0{PC9HnZ)3Ke`0n z1nN?>giY*Ek0Q&L)Qe@O9z?qk!#+sgdWypP#gZuXj16u~Kl}a>RU+v0J#P9|=Ev)< z0PaMMlvbb47Z)g2Lgj2pkAJsi=&$LF0Z60R!rR`6cw$`p8Dbxc7JZ~} z6J0LmR*{!5nZYmJT^&qj4mq8bcjVtc&d(OCJvTknn69axkPX?jxN09?^qwgu|HU^7 zLn24?qbSage43USX;pcVj&Ve7=uhtQ_E8|IW@ zY%#Zin*sSJ8XsAgLzL4EGPuit*p$<5($TY`5I*zie7u}U&6%=keQj8=I!pDSw0my z9D9eEVU#yY!VUQ!`z3Vd0g(6Us+iHGe^uf^X*r6%S4=1U=GcmGN5ro0uevXtdYN#4 zruLEYz?}lI&;M1QX3 zbI^_T8$neMF^)}uzxQ2&6^X97)Wy1A*nWuc{#=xz0c=U#NkWwhKkof9X;M(x#?#=4 z+)BjB^Gd>+Ut&cNc4?;EY1fL=Q6nNbse9ym1shjoyS>s&!^9?gTa&Mj_?$;X=8QE} z+&qzb

>ha{87?xyfuskZkuS2?7;_oK};Ff{mAW2o3qlltBaUS6ur&DMn_595iMY zLd6hHfe!56`imiD$J)kHGl32gGxnGdg!)sAIi{IJMpqwqVk#(pyF9p5^!I2dxV?_m zG*%tEBhN*==6h)nWGOgGHEM&Cg(@f)ZFA2I19S2!{3e8Bot3H}%lpAIw;UK8z%$;z zolo(?QJlU2-v_+iMVJA2D_})$41=A*2FTD!i}{wJqO$OH6vCvqMIOuW2@%k@oq>!H zjmj9+!_6@IaE>u?GpT0pxzgPMxpIC{M;@r_Et3Hd*DSmTvXNkH8+3fk)<3)pI(;1w zdD-NYTjJvW%yiD!iI}g3H&+?`>JycZJ(UW1EK$#tit~%lA~(RGW_aw-DI-Q|)1x^F zIZ3gyH370fikvld@>SP-O~&#B1j(})iyQb#@N}3+!+i9}X8dS5989FcpD-PkJZ+BV zftQO&xIs65E{7FH8qwu;R*qaIO>Z?LyyVuP7SAR))jSpYnbX>0lqmSpB^oB{0^~HzD!DMuLf*6m zF5TBEyebXID2Uz3W3c31vekwP9N!IYbD#hEB?>TM8av^DfqRJ#`(z!o7$DTjG`)Fd z=w`NT4va7~4b>ecDq+8R?gIB~Iu4E_+@tCkcdda#g&Tar_<6>khqH0ICKboviPwTm z$2Tm3)QK>$-4jMq5R>fq6}39?_gRA6Y|LL%nxD2leP7VB(Z)3#PHlrMRgvDk5!B}A zQP9Xg?i&%P-@R@YyXud*CI4lTK0HIrT4C4UYi#2mzReK}xB0*s+kERWjY1sBzk3bw z(|jPcHFG_woh&9%(;)3#vysTR+RgsOGwpElZNB%2X;5Ir@!gqr-~knEwGuS6utK>& zksZX@j=Fw+e^%+Lk4{-*wUnhV;|awGRBI}lP+2FSHTYiV&>VLk(cjVhNQfAeSAAt4=vWN4UOb z;N_8%t%avqA)0-wAr9B7Vo?RwON|%Q<&DgW6^U()#8MAy+GL%C%%S?l=p5=D37Lj+%(5#cYtiMI^a}d9ks(f_wsxvpW=j? zUjAZ;UA-}L9v1|a{xFT{jpWIb)Xmo4I;o!?no6i87CSYjNW6T^-Lf0@_E?+8J{ zs1|3th8|%=Npb{V$cb$CDZdi0(z(1VSsWx5Z}yZ1&b)SY`V6kTo?N#2+MdL2>G04; zr8Wmp65EJ0AjI=0g&Ug)Bqc5j`uX(vA?N!$)NYl|n51man|%0)N+w9a-o%u9p4sni z9#X6uz9)-G2d-ne!$Q0vdA&7*6KRC)H|9$dO(Oi~UjV>!L#<|z5#Nv*J8)@$dha3> zAJgcxDIKrz{k^q3^u6@D0EKcp@9mj79DaX7b0!iTCS);{>3@TrQs=zk@4}s9o15wY z|Mctf|9Ej4-L6z3IgF^`7069$9+3Qe%O()}&&KnC9%eB&_m-HJQpvgG?%6bWkSFd8 zk`vOs9v2qZduOE`(^w9ps}~S7(ThrSiJQ+ogzks_&f}({YNI`;e6gWT!Q){aMIOIR z>K{6Pm?_}qxUaB)mR^PRu7CMz7#{{1fE-bV|2V1?cY4TfWbKpQGh%S0S8&1tmKB0q zKkBxn`;>wgd`WhbN=jA%<<+j_>`hah;^VfrwQ!|w)*4?|v-cEB-!yM2C6--AJ0ot0 zn(Unym=C5_?+lfaX5ByC`NFSJ{k*@guw87a$^}6-V5!~~!JjYvg3WS1O}c)>%$?bi z2iH)=rtgjOp1TK|D0TkXV=_Sp?ddVuZdw=%FV)S;a{jsAHt*~>XL=F}YrS<7h}(=M zk`}8CrDpv~&K_TsCVvtRgBv=<7s%L zgSk<>G2}NNr7yAX*w%o51|b_Z%?|CR|N1E!M~ynOgSH$Gc*AHE>g;&$B-#@U#wcNl5Wz-|0w8Kl* zmqoqE7s##}P8H?VLGF+VlITNjUj(Y5Z&e6_o?}vb)&Hd|jxTlPIvT-4_FIlN>T3oZ z(c~M zCmJtpO?+27NDr%3LySC;V(H~}F4DwX~@9_)1L^dXG1x68jOhLTdqgL(!*#swL0l1qy;1$G$0_HYZ8$j?TAY)! zFFp}C@AT`JVP2j&EG%+DrQT0#a;-k-{W&u2X>^#hQTr{1MlfL|bFrJuUfJCw%%oUgalXu3DtdR~d5wk@=63(ZIQ z)LrS2%j%qeG~+x$ugDaMs%h~sAE_p8#P(6@^xh^_Cl4zlWOLAZp3RMn zy)DoeKfr!M%XYrx>DDynONsIMqg+<<^r(33O$xaj)lIHckh8rM_gL!6i63K3{>g`l zNIX+eEz--lYAt=ax2rqGY%KD;;qUk%`U5l&i7bC!lz-!VUf{&rv44t_lIn|=MkE-n810=8W?o?C_#B8)OENNpxe9xK zkxJ;Et5x&?34+G2Cl8<*69Ifzq=L`3wr!v(*wT+y;JLAkk-N&H8@UM-%B!qj(@(if z!4XFn29?UOzr9$ecM_I`g-t7{!Z=_ca2sE6eT6=q9aoHr?^*sKkytqdsCA~({`=X5}RLYdF z9TraYqY|Dv?jg=`cz7-`eu}}q@1z9DAz_zw;T7hVo$}8GMKex)uU7-NKj8#UG8Rc{ ztd`ad;+N`^G*ogQIMR;gI=HZQ3q6i2NJ*$&RUNMCpnrt9xBG5X0KcW**WhE4q=S=iS& zvrCP#92ag>bTylcfqb&?G?ZPqC=9u?H0=wEl%k= zaKycP686T3VlSi<=6}&WCn-X>a-~Jd;mkVnNRK5nnlIRBj)%MY!CB7I{B3`zdGgh7 zSjprXXyIXZ!b21sd-)aT- zQbk`LX=TZMv}~y4_lqsHii)?CUhvTAL$~`jJmH^lcbEJ(IGsrfZ$f z47nZsRP5!v2-pJ_dJH_iz(TwJC1pB6W5!#%_YV03qDAbQMvax_D`c}2A^i9$TetQ0 zXL9mI7)|(_;b@NA6~)ftE1}lF+a8er?Fs$ukWn{@^Gq*`}C19MYRn=LP0I4AYY#e z7zsP@qJ9xAzTI8(#YJP{o_OVtW{$i-+5vN4!3J$^sDe2TQXd`A6vFz&^Mv%XO$DgP z%-Y4}`Kjx+55@br9jLD#N9HAZfIY5z4GFB2Idik4}+2eSk~{4vm}xuzzN%V zH=6164yAGj!+pXpeSd}`wbXw>tVGM9rZXeoRe_;SnGi{)|2cU zz8)PWwAeN8y8){0v10?PJiviq%%Fp)y>*rTS0%^uq(!}@W@>uwi}Z1l+P9z6UlU#C zfH7WXG-l^$(%^f4{~opYGe%MRXKydkyGcIVnYvw4GYEV#buLtT_Ta>?UnKc!bJnDD zkn6_k{z>TM$a?k-|6j-kMf_s!4gV_!et}}e`@61Qr*QiR>V?lTt`JI5j;v}4KHiIu zaOtUm-D)2U@Y*OTO})VuMP?lTgjj&vHnM#~F3^GuJ)28W2zbtSv&$B|-Q-Y;J~vk-|mPf9_3v~qf|ouD6|6xR{J z+p-TJaCZk7tyLtUb{E$Pe z;g!jIK{CEpw^c_Ak$MnCCof&)D7K{jBdW801kX9XH1_)fq2^M#lsyty?6NMd0u=&v z4N39H8IEKY``hZCkN2z?_f+U*D@*fZ{DSrMW_1pl35=K`_Ib4IZo1NSZyxM~C=zdZ`Sy(7n`oyvNN z#Z0+$PKnlb?f;?cI|G`^x^@YnhzJ-_P^tt1QX>P>iv=M80Y#-rQ-%_HFQJbDQKW?q z0+t}sQF@PvqO@pe(jy2lAiad1d!jS%o$q_^<&Wl+eb!!Q?|oKzp0!U5X~4P$FhL-q z4CqwspN^)=Hz~oP&Ylvtgk|7F-{wV+@00-e`Tc~3I`Mwr_R*zFd{^FA=E9x^*qg&9 zbg~6PtOj3aW@Tk@h#`j=$U~aTXE^Q6d+D8;cR}ZkR`AfJ?x|t|uCcJb+L2L`aQFP< z)5;!JgYp|C%MrA_J#b(Gzw*+FNH%WqpT{(m1AcxTE(~#2%F#2*JpV19Tl`w)^x7rK zd^O;N^wC-Eyz_V4cjN+t-_Onfr@U4luyHE_rwpu?)*f}WsorgW&@FK-v-0!T*Y@q{U|P=B;-UIpl7Pie$}++F4&2Ho3&59m#9CXQ-T zy67i>Fk*kP{pn-=Kkr^pPyh-`c>mLaU@TK8IH-R9?C%D)k!JLkm2km`NT3Ca46NTH zvEPmK#FWYdX2QS3D6wvrLPa3&mCzZn?Qpo=dH(dgiWq&!^|;^?*cKY_5ha}M^q;%2`F;-c2Ci5NhWu6uGtw4Y zZ9V9HOi`kgerCc|*{=V;MA1aPC`owts|h_oGo(a(>p!Br@LhYG~3r6^B}XZ{%> zjl+z`?px&l-zFa1CUS`_UiTNEcXCMEC8LsY49tJ)Kf@$3nBL!#*NI@l|J2UX|I&`o z&`i|Wf4!&dSo)mG@|Q%i8jKdqtFUBq|I*gdrib0cf4wGtq^s$_l|qP`DE|A+>j@Ut z`~gV9FP8vbD*BIF=_AJbzedaf{^oyPuW=*&wknab1kGQndG{BN3o-ii-=YZG#r~Hl z;mEx5Zb1E|;&hb^gINDFbJWCtxAQ(C3VEAV{&Og0oPHf3NGn~C@pr#x;O~wq@Dp9A zIBBFbBm8Q|_hNf_x-1Q5O+rJMppH+)7Me&k8zL6`dFeGaow6Jto2+O_yb(PML@jSP zTyyjnLES*In*w7Bm{2Z`HA*a}<&`-QKxqfPy(a60FD7`8=-DrLMqhv@4u%P8)GcQE zH?T)~n*KeGD^e6M6LZAMWKlY(i8l?QhbB8GuydcZ&E!%E(x_`iOQBdE$uwCxRNnqx zJC^6;Sox%QhhUVG{#asqbt^8~V75fx(u{aH`VBL{hK9jpEzIlKSN?o9sj;I`Iv{>{ zb$!_$-CrVtN*0*Vo$suM>Za3@%hIYDD{LN5s11GkZw8E1M9r-?O%TujL`MB}#3TlkMTH8F76` zAPp`EjM*~`*jg5GY-^b?*ebJ|ob1QAa@>n=1%nIZQ3^Y$B2a&(-U1*HDS?+*<*

WM3jb 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 z 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

GUk?#YKNeAZkGosbKI@!hgZ=<*f\Tc(YoTY!!EKK3%rJX+MZ4#siVh+eqoDI/5=79MpIuOGA$p^Qf %'F.`?Mb,Y1`Qih$dGjX*1[):S2'(g\"L'2pf'WGP/E6.HXF^MgS&Yh8b]!rq6,Ctm+(-)E(Dc;tdW3/h;P(f*HasWhX %kT`ZOWdEpLT&l3&r7QOpf@PK8$0hF?`K_^pVFBSO8Y+r`l!F6qPD8Ki:HIT.0r'^oo**IE[",Rqc,umEquqiHf*;'e)>?q-j4!;g %Zo\2oXH$]QcO460.P:Kj29o3s>$g\kcMZCtNo,GB=3%LO?W2K)cLiGu[Gq&?F2cGFQgC6.m`ep,53:?YjjlTVeii-GI9I>VEpK<; %lb<;3Vqek]gq'C7R_S8ARO:sW&qq]1GS5^#F6df[G`*%%@0PLg0!sOfBa\Q(?(&*bc!&i3_Ap`#U#"8j\5"Kfm[)^kQhsiT+ %E(6 %"4]VEo2pSMQd,G-7/..VRGj9qn5h7u_diL=gI6k'P!2q@,[(E#5s#"-asYDd@8TMQb-I#8F\gG[K]oh?(\Qj`=ZKG4YNV`m7+Vf; %S5AOC_dq)V^G<7/4B'L-.c^>0nN\iUY_9!_,?`ORN_Ep#,t?$J.Bl.eql,m\/J.07o1Xr!/\HE]7XP8RhmNeba(*$fL+]C%)"CO` %paJ]1'I/'a&O46jT45`71#f)JnP_:..5:NB$;[Dc,RWEE,Q9?K`Ko#s:p8p3I1cJ(#e`+4h\i]/0>cT]Z+)*sh$i8'1A/OYMrRJu %5L7i[5.YL0^=$c2d%oRhcu0p=\`d+^e4&cFc]X;uo!,i>(M/4F_op"s._JG+,slJkGl1=T/dktu*gHoC+)qi`kd'-BJa>/&c>EBY %]oRkgiXF0tB!^-kAN=d6$sp'%],nf/X5ttREo=cU_eJkn\.R9Emco'=]gS8@T34p:*STW**IdiB]n?#g`VHi]B7KBeto(HZ>]Wbjb4]*!s/W8ua-0esD]u!2c %pb_c?Y)eH,Fa'&EZ`W!D?lE&r_WM9Dr7H$DL^$+anA=[^*q5U`Fb).Qqp-&^B)ioEk3hu.piRZ[rfAg\n!,qj/V/Q=Z^%(TH\#^2K+h#l2<`>VPgbr#'q*%auNCi`FU/H+(J1N*-/Y:K$l.Im:K1nrXGVX5Eeh=ddqs\=-IgBJsB4 %:Z8:ie[NPOI10NY]U83YnlT7=ag%n-F?/tc=dH8"^>aBa_=>#aQt7SML=OhorF08D2JZ/LCK3E2=ZgIYD!GXb.qg5e5ED9X>0A[) %;FkSBQ*e[Xp:Rp&lWA#+:Y"'CXN&iP$V`0-.mI'Mb>m:X?>g2s@5q/,X5C"$]^Ah(]QL%Df!$R;jU6#J]5PmCi&Z2M(-KKs;I'4l %/WmaHpk?7n$A#@pM'5[R\0W"PPnAtg-u"A+PhR%9'b`_:\o0AEkAo'k"Rm5a$?Q!,&,:AnPG7AgdbDFCd.>s46faG%Nd.KQ1n_-5 %FZ;RmDu.R]e'Hj#rT"a\@u*=VQb,PkRT/L,PC1VbRV>7,!a-9B->'j@Pd5@!i;!#AXo+angOI_Ac'p^*O65oN[$W6W"3?ch[_@7f %l:Y#Rp$U4MAh&-QiK7)=T8`&6;/%VI*)q,nTNB*j7AM"t+F/'sQI/#B)@YlhONU.W/2mmI_m'VCjpWoHO/?)U7oM"oi:?%,-Kajq %&D&@sic-S,$%6:InVbK#pSliBde,os$(&>hl_IGT[Mek^S537tn+1n>X;2llDpX.[G$;5`FY7rE3Y*)<$ %.<,sg3ok?HQZNNe?GTk1o%bhUR/IZH8=DJT"ifX*^g\oTu %qs[J;]fj)VpR'o'Hn(WGGVTMHm^-9;>Ho:=g(DBde(ks,SZHk5HTZ=Uk]_HTK>X&P?(^E=n2\$=g[8n[V.o!Mi/AtDn6cQ'7\[j5 %VBI!@):eWf]6&pP/B(oe\1U's!d&f7@f]5cm[7m2UA@CuUN>'Oj:%f)7R9j'#b)D>29o=VBsSSI!nk%7cpqT=lOpNBd.l8h)E'VS %0a`EE`p[P6_^CL@k[)8P-c[5^eU2i]c %rlB@V]"*07>]OcI-F8Dsm&9"1LA4M";#Li9iP3Kq(sgY:&r4([Tn9En2-46;`P5[I9Hi][8j5>fbG.CG>HN>eCu;$P;`pp@!W'de %_tHnl%gFlE$+P)TNbC6DM#'5S3-"\;m,7D$:s6A"%nh^6+7.:3c2P)Jk]=JO>sS=bpc9\+F(b#DkOBn&b2WDRb3VZ.f4QS>J'Y4e %ch[8NIsj;R'Xut,Wg4LbRWsEZ/^a7L0H\?S"KcukGh),L+._ku62)+`icl^B'Yefi>i,H<7<:;IP*WL25:?,l';%K>n+j<]9CYdWYU7U[q>S<0=QKNFSsc_o+/qO!@E*k,j-k,a%[YJ90p@P:&`nj\otqGi/ter2-HYO%/a4d9ut% %KO:&=?CUSu$ge>ICYAME/1Sb#Zh_<%n#sPg86Gm7f3mhh=M.bri>.bn_!@mF)XqG7@tFXQp<$l:HO"2YFo/8>5iIFq1#m#t7ogW!uq1>uL8J3J^UdFqe#jU@[63P,J+@;GW*XN60T_g1r:6EE,YF038d*hAp7bEGghLh"c=ZQYhMgG(V'p %i=T?)7t+4)h4r,4E7NrF5:39MX05fW\Vd"]Y'=hU#Ys3FId)KsaC/'\Cmf:K %bV\i-->?TCQ7Od`bl.,Kt24A8XHm5 %g!c*DGdL.>iq+Kf;&U3Q8t)^n<"]u0BpY`3QY1"uP<9l.rnm`Pp;ukhNe]'LU\r[&4Le).D]`[1lf%I#kC$mB=/.p+e\9p2`d@LI %S\Is\pr[6?kD;>\F=lN4;*7mr1o'-C"PeboRQ9ssDu\?uarE(DMUb`Lo0U4b5Bd,!QjqEk]XP?`5Pbd-OM<"*PHQXrGQd!G?9.^A %6K.)as1"bEZsrF#MTtEZ+7VeNFe-\7<5MCj*aEuCMTr+$m&=OmYA?GJjJFQu]QX$TgVJJL*^!eU9eQ3KI^e0Y/Zpq@c2CIihKpgZ %$fjuTUXYdHq(>aI=UqB>aNR<CC6G[Z&&SC=,PTbSrh2OCXTEk&gB&`>e.Thi>?;5/J+r`"\6&hWlm"$apPGJ:^"uL[g$=D=*I=b>6nM %pN^u.4aIdtn;6JpNa>NUZ"JE+h8c\"qi$I"L*P655Gu6dUX/FC!Tm0@p%U=*p5;EJ37G3U)jRhbH_jM8W,&=q@Bck[o`a_&_&(t< %rqN&Mkg0d2F6ED_hn"7s%7b;A5Jb&!?[;8>]%dUtIJ@?XRpPL#lCC$tM#TOsM!K_Y\qOlVQbj %r2RXJT_kd0,g+O%/:\ePcGXX%enFYd=>tjUAeE1Q#kJgMZ,E,Y2(-! %+1S8>_+nbUSY%$BE?]`NLfqg%4frR&F:%G-.j/1cbh!BojP&R.>$;SRp-MFANZsnsfe8fh@YabDpZ;IZR%LtCio>66D_LlLE[:8: %2dRIaY3DS;;<.JWs/mDg,cWFD4fS0_ErPlU(=t3$B^cm4lYsEdHo_*UQ+KTQ8T?ucC0a[q0bPN\lc't9FoJ=D"*rXJo",idiRgB_ %U%XUqao+>Fm50#g/tO,gcdll]]Rp$p/-kAlT4T]lY+HcF7`$D7Y.4SBfIgiSH'5P("*hol-/nHt)ilWk<> %aG1>H&EnnHQ3gm89Xf`Fh&FBcSo7-m9f>O*AqJMc:PsS3ZfC;qNi+s#T'kri]!LG]cAiR+_>b8VO6miKh:_=?B?,Mu38`1R%8W_f %,RR>An/&^gq$X3XY3Q1;aa8LpRfVp?q:)i6T/sT)mCjoZEDOp[>o,rRlPu@%O\"M^FfZ(cVUDOYCUWXr5EjJjA6b=l`-E%QAPl]M %$m[I`63bk'#/4\EkWR5)Y^e%JM`ngHQTuL]-j+=jZU-1YUA5e#/eldt+>m@]Ha.J,^9Q,spggNL\'.\4V]PV,R-#h3b(&#;pq<2F %OL#IiaB\L.B#:I/&@RE"T9F5uar=a5rKS;tLk6uH4FDMS9W@h4)K2/lWHq>tTB\VjI[>sPAMFpeL..L#C6LWVg2MIQ`Sq5gc0f8@ %Lg?IiWDJh_[Q#i_NdTj:0&qXm&a9#PkdP&3FdQWOM^s_ON%:;tCOcgdR,AKW_'G>KEr6\(hkhla<^LND8gok$KmqZEcbE+DiR-ZO %HAH2n&llMlUaZ,<9*P7'NZg8OgTjK6s-gXe?EH30&n,qAB8^Y:E9UbuAK8RWA;aKPbIEqo5n_BCV8acE`)(!RQ8LcH9]F=; %,hfrc#39*rbmouk'.DH[;t^a&Ekm_T:^>[Ujh4h\^LjBjQ[8Ouo\m&q!(Sm*BB[7Rc.1e%p8[!K^0_n>=VfatQeOZh,B[+\J6A2n %SQFu\nfhFUSM@N%]K\@RGOVRs&U4N=Bs.iAFQjB4%Rh7[H9G %eKWGq'G_LqK+:Lj;2%oWLmh@Cc#X"n[T2#'orq>_B/4&1ldtaF%\*qUcpHQC+I0lt#$?-ctH-UPu^XH=7k7.I9IjaIB#OEomM=g`Ech,Q`$:"N> %!;r1iI.l=$J,CDKfh6qsr?'t$29n8g'>.u(!OhjU!iGEM5CsDSp[l#Rd4hp67$d+XUc'U'?8b5%ecR6hU;CLe$NnuPPnIniZ`jB- %#/:.FD=_j-SV%HCR:$'cht0Y>D*%f]f:Hn8+m91+5L*C$!*8n5A@Yb;K#1DI%rI>bf8mc?h<.;tl$)>S@+>B#"iX'j;-4.fWRY_Q %r\9eSqtp^`rJo=%msC)FGb/+K_OrfIm23ooH&YP56Ec[6LIFLH&GW@P&2seD9_neT_d80Jn-SFdndR!B %JsQ1"mK1\rZbPC;@--`^]VK^R3At]o-I\);]>B;q5I8M)o!n00)Q]Q(_D>7k7^mujKHXm0L3gS"YId:oIPDdC0MhU$H"BlHU6Puu %?B3&d.k?a']0J:Voh=U:7R`X`P9&c80ppQ3COD[Nn7uX96Q,3Sg;M&#,01@ANLE$dYp4ui6S%CfF1W<;9SW\Oqop3$4K0o$]%i&SX#b/ %ElE^kpc/]L*/s&HhWio3bYu9rVmNUD#]EdhS78E:!I9XE//%m'T8!GPQXGi2D>@2ol--oq^]!Zi-cKTcO?!5S(sdBps53k"n,],7 %dE^743'Gc#CaAiLC#;#:'=T+a'el=qZ0DdP_RsrYR1Unu7_(Wh"0u?!X%-QR(,pjj:^^.a.cKbbZ:oE[a+ojX+@2>$2+fn@&C\&!b7NTbWOG;1&JlTL%ps7S(jJ@Tu(LIDC#?Tn2 %SXut3VorMr2H5dr6jPhSA2h#`9+#bL?7\YOn5SOqfe%(ej>kQ"!X_"-)[H2BFarf"V)rg1P%]P8&0l?<3f]LqL["&f@fS7D12_>-3R3Lh6HZ;>RG/FAG4F?\;R0Z+ul8Ag9=@K:qp;[hAf[d"j!\%$=;4&kMt.jI=[OlC)rN/;gY.mD$spOG)bt3e3G3ej_GL61:!lB@?tTOq"W.O-R1_36d1E+P>QeiC11qquS'luMA'9NL %SEDkhKRm]'*1oLr-1+f'fk7qt`ieo([\O14SeMIJWkbKboo;K1E)cC4NSFaM^JI=Y5h.Vf&<<^+!=DKVT0T]?cjHd)9%0/lW/?0[ %mu),c;.[31dkjcKZ9dA$NSfLe`Ae1.+laGBk9($;:3]'$k=RK?^ta0F1/.6q$ZOCf$ErVp$irnp%KRt*)&^fD29G$%'GM96c_S5h %DH@C@8Z5ADXEZ7u$Sn3lH0fe!4:2g&C6F.8KI.*\Q%<%ZTKR%>F&W+ %ZnP/9.6FC]0UW7nSLqWZK+PiPNkqq:#e=H4Mic:T*T/W.e:8j4qab>`Do#A23Y7r'W,2R?LDNo,\[M`S$c_8'[m^Lqi#F-p@d$*4 %YYLs6*0n,9kGiU)3!:h4U6uZ.!(.c>Bfb:uAfu1i^XRAn,<1W;pF0ju5[[jN+@&._J74rV!KkH%B4ggAYSM.;0%5?kL,M_NKJ.?rZ6C]>^+o5X1NZ\O=dYP]i59VfuX&&79BJ#nrJi4sHo.YHoD+3VGRN]Qq%ffP1nu7jA %"=d]Cf2TNS[jmb=/Zr1]^e$'b;2'r/*7E8W_P!W9+IVRY>[o2abi<12;?S;kdb?30[UA?@D%[QDo#f#"7hH+Z(uB!C9@1e3G_:mT %Y4jfB(#@+Z!!\N,234!0(gJba(<`sTgH&rq&&MMS^Tr`%[-8$:>FJRU9$,Ksgm"P7@D`Tf7('re$U>9=5I.D+H'[!UU2I(?/sE#+ %>8`\jgMIZ_UTQBbUE,6$eLZn=9d?tVBiM@`JMgfRnIMt/X&4/#X&bc2@195?=Yn0MJW:a`?+rXrmu\6A-fc&9A#NGFJ4__@gni:8L*.L0FD %en.B/[%4*dJ?e4;S5nSP^hMAV8$!M7dMYs$^dG1tB1U-ZJ--X;('N,)!7%?D_6Y^t<_dTaf+oWC@%\ %i;c2]_3?Mg#3VeNK9e4reuVV;A!MkSU@/2172sK_S:l,hZrChcXS1T.Z)I_'1RA(]Ai0W\()T$=-Ie*1`>sM,Vf=T-M):W\2<'1] %:_\JJiW+q$>1,2fYt@/9&-V:k,D&L6T>e;`"=@qs)?I>N*>Fc)!2c`o"GhB>QF8-&FfPf1W!^)0g&50lM'iOC4l-.i$^Bn %lBWhb;:kGc`4u[A)A*DJ1$6E$9T1fp?jO%U\CmT_ZRk\VXs1iA#B`$8a_BuWQ%n9E50L#DhV\HMU+IMm"P.D&eYR!r?_'5D$5\8d %a)`'BYmOPUoIBWLPap]riZ?.,/#R]D8+Q1nPZlRD]dl@Z;TTV9)F^jn> %VFsNI?,OHk'5np\ljI`DaWRNK7rZiu`uJWMJO_C?YIbZC&N3djCuSlVT]rJ4;d4bqlR4*'<"PG(-$Uuo&>WdY.^/.!8+]S[H!:qo#JE(:46!DqTp^JH,a=a+(M"P%=U,0hCP[u9LrTZ^;%`Afm:ZnD0=e[%+cuU<2Z&Vhd%<95s(mJ&`#\s_2W%tD>%fkU+XimuG&A;8L;c/IR_#c^P16F[\Z^<*.W*._e7EJL;;>?)g6c4R&@$&Gq0/O.H\2R7b#GaT;R:KBfNVZ %+[Em_r$4'$@;IG#STmY0oPuanU+5IMQNQa,1o@D8246ajQoInD5M"4u5P/^_rF1[UX0WF8C_`hT;8/:E+?.c]ol+2#\,@A$R[HZl %`k[#I2.C4)o,S3cfRUn:5=QnN'e$09[LSL:a$>Um:)rP-"9iC6(+l5/3rjU]TV4b/E,K/_iDuE^_53'6CXTI/7s'n"c6`%<$'XUN %JZ^>Cjqot[6ss;,8RrO;DR';1XbKliN@')d!&[;uIZ4tu#/[;Z'3,EUrhKo(.7\7mUNmej%Q<+9%g#V\['*(q1Ff#H';\d8%L$6!FKW/f;/,@Sn@P=!3>o;TkfNONItW %@(#1uHFs)9/<";M-&aB^!Z(H;1N.L]0F!MIkiCRY9$`>D$_NjHeg0Uqs.ba_u>]=Vl;'8">M(<2Y3gVtYW %QtLutc52PBmX\56>:UXSN!L\Sl>ql7[94nIhKlQqC;i]VZlLR*3O_">^I1os6pP.:3p0ugiKu0.YsPM"2ggs_MJ4UgSWh(R&Z@EkZ-O6fB!&%XQ$"'Z %gOktT(sP=t>F[.$!5RUE+CQurcPjgWFMp/aKPd4CLoJ\T1Y`rYMRO?90L/Ia\P*uj6=:.''iL"u%&p1Z3(A7eJrF/Be1+1j.BA!j %^(LJtH="8iMEoG9M$%jO5b^:Q]7UM;X%j@iprijV9=o7"N4*)KdGH4Rh>uHI7jnPAL#5U3VbpcB!.j.0M!ujF5'(GSH7iU]Sog1' %nMV?P3O\R:etA^dMqleERVp,;nrRIY)"qJ9TeQ9@&taW %>m@#@6(ijUo7hdDG-a,\^aZ81*Go'eE4)o?i-5mY2;8b4cK4`;Gp?TKq/m$fWlC.u%tlE,3X*mZeV.?'c4H@JOK]Tpc*9"93-=dg$a!,Cn7Q.Q.Le4LqVg#TmO5_tlTZr:/d-;YTQK;W?Va8.":A!q66[mI;cIJ6I3`bP=&"b@i42+bPqKZj %#V<8-18uKo5l6jaaq-OG:1NCq('1bI79*-l9mP7Q[FtHKW.)m*X(=Po7E8/GEfbEI7Xemi7Iq`P&:GnEgIfk9TrHi^-;HB/0$82h %EMC:dmQnLog4e4%b(RoMdi##;$0S:C\C',cX&,-[Q_P#=>pb'W[6eQ=j9 %c=\f:C)cYeM`J6`cZlUp/]CIZ2oLZ3A%^qQ]p1C\)FkEWH%ED(,NY&?63p8NTpI_Z&V2rF`^(F2M@iJ2q'@Kl]Z=5F=#Dm\dUAUA %0_5+I`J!$&c-F8$BIa0BY-nn0*\*f7$tWh7<$@o-+@+`k6TL-i+m;9_0hM2nUpI_uU5)lnWdHBl_?`h6NNsCOq-.udD2urT6dX&^ %:]thH]']^eDWt#):';iJZ3;:k8!hqq]F5HMgRrOuM4`7p/?2K27aPBo[H\C\>^CL'^Ct$A_d]`@!J!\HhGR1![o=oK_O`]8Bi<7p %$/_PGUL,Z)OThX5<1Ih5rrHVZ0?&].Cb!M\r@_0ML#umH"r6TF7lk?f5$#e^ObtN!e.cfSLhXJjT0mBrp<-HY\dX:LB!S %V<*k1aVY$s7pSC0Y^t=e>E)rcUdIE-,,tHaXRTDO6#.Jl@ %-)-*AQ"bf[T5?IhA(-N`OjHnBWo'!D:cm#^(i2Qm3&?Q&_(\[)0&?O>1E0bDPD3?N+^ME#JTH8P;)N,_;dC+>b>OqJT4N7VUPpG8j$":"P#eU<8;6())Y.8neVLSf`Ei\(A&m1,R-K3^\j@r4(* %BO@XY"(Ip]fiMKQ@WJMEO+?3rX^JaaNK*1YY(eNJF&3!&,W8dr$k^]5LU&3pD'_]QqlQBsT?MJ"(*&Ih=MNd/baBg%):G/o@5J4lg`PQ\=@8m7](X83. %EG,@HrFg&(-gG4\os\_fI$[]sdYOS]b=@kK"28,a)QF=./T&'EZd#8S+A"lh$<*KiQ%CEoMR%$na>1FZbXpQIf#SjiX]Ih$In0$?rVaf4aPrJZ//2>8NA_-5:\Z+s00n3DKI#Df;7,24uZT",5c9U3+QLo/d0\]_XU%Z$IHfc3:E^jHs %ZpelU4se!b2A#fM[mo":tXtCcV-Xc%J>!?0tfRTu@."AQdHW3Wt40:F8dKf`^5D-c&cWU'7EL2J,*[ %7VFAt9%%^A2*Ilb.CKMPX.CZ3lt&VYRMsY:CKe!jc=.?aP*M.([#-'Sr#"XKC;eeKKeNs0fS(1rHH;,Z@NAfM\4dg@5ltQt8fV(O %?jYDg[Jmn2-DAZlOcHCJ!I3m0J@b3@>l4lCV.t08RB.Tk5uYi\B3qirl8ch_>=UJeUeI8=oeU)u*/,`WW5J!N^b\g`1!-I]TUmf0 %HsB![M@>'-<5OAu/D5jq"(;=dVS^IRUa(J_`NY;$C27Gbaeok]d)fi?O^5.B`_8QUr0;b0`&M,$m9a_3U+)jBG!&K^H&m! %I4jG+ah4V=6k;-=QImVg]?N1c,+Q6AbEeX4!7DM%^i&`$_PL1n>j^^c#"gL`2#!1L<^"'gEDuoB;]N/%VhU/j6]PciMYS>s_(otE %b$3"t<,6GfH8E&)u)M1e3&PncWM":PY%8SXpf:a9`&4sl+0'GDJZGT(GF4QE*oUjCIL/T>A[ %.Gcao]G0LmaH:!J;nt:*m?].`;92h55-]mGP+=su0_SN,`KX"==EW(*pB8G(M!Sau&0/DH'kLj\%6k/K7o!m.bsAU?,?sHGBfTD; %M/;ZGiuM#h)i?2^cY24DaTb'WDau`b8$Q;C#<-ak='a4PH$H\>4QiM6Ll)t4Y+i>V)=AqLb"(03I7Cip?"ha9_gUfIVb"7UOYL)& %&l)M7LrX=%!MXI#ii[YX_QU,n8"&()=(;IQdg^mAOEqNB1mG^P%YEgnkd_VR8q/I$lFQUhp@&YR$XWK6&8tJSqOSA_9ScO^D/gMI %Rl&k[,e#d8e3&i]sL'N:J0'(a/6/u;s%^sS0Jhg?m'+g<@55.nVko(5tF_)oQV4) %Rnetd$,chn[(aV^])ZWK3c"-T9[?(eS/V'ZZJ.6ggLV%^mNntYZ6RKt$KrM$1UQbo5d4%I::[Bmr-]V\QMuV`-cJaUXO$+_J=^2, %SEJ#0P'"OL)?qu%'PE%jI_KVZM\lg&PAT+W;!g8*pn.je@m@#Wpp^F4/'A6pi2O"-h0F+k523=b4bt*T=bb=Ii$**$kkfZI5%8A^ %VJThm*ltliG6BDh+9d@T6s$X'_QD4G#iZ1/oGCIJK7:6DcWeM'7-ph87a(^hrO<@"Tr?tISSgbjRq6_2g"rNg?'DG,RdFCM'e,"& %G/bSsZBHEn!hXN"Rg,"!h4E#n48",ugA2*)7!^fXnYBdIfg0?9chP_fClATWhO`-jB\`[tmN`Ph4I:+cp_Jbl()i8S_I0p:V&s7Y %I)ppO9].!c9n6nI.M4Wi%qEgecg4UBl:`f_a7i^R<1 %A$@N.*4)fkP*Cs&E?o`Y\76;bfWJ=e=7mH]f$V94cql:EiLrD,iN4^^3Eh4]g8X6Td.eC=<2gAgC+Y:&+9\[sNi@/_D')>eq@?JJNF#?-*3,q@h?!7R-NfTqXK`f83<^6nb8SJF)3?Kok9lMP;Pd;om*CWVlNKX'S_:@D?>m]n[Hnr %&lcaoR]0pFlUD+K#:s"hdL7Fb')VR!i3nAC$o4H)qa6qW[fq,gWG:i3u\f7.=@TqJ(PTrG`JOqZPIm %nu+P;o-Lo,**.?&mr'BJeU+"q$NT0t.=C/s:1[*uh_dhPI>bQK,V$+V7a,heP\7#%Lk[HdVa;*udB5!N%#lb4eTYKS[6Vlnb+4[r %Qh?Hl*,Nj(MCDWQRkss%0>tr!1\n.oe%(&g!jo8=,#M#:h0[&Q=>dSZCg2=MA!gFJ0@_BM2Q\lhAa6S@MmNu;'M[\Gr`-PLO`Uu& %Xd,&?'7PmV(TMF'jeHdASWk??;TBFsKV2:,r^M:7Ek$`OpMf+bNOfX\5WSFhj_J&`>"#9:ND9';?>gGnPZcqUZ;#6 %Ai^t?UFD$In1d#b:;CQjpJo&U=5_.pN6iPhe40.MffkuTda8D4:4i+tA1b@#)3Yh,U)d8>'FN?G!t0B\'B[)]$`nIi.q`1qFI_SD\*Oa@K\qZnE1PuY`5`0[\<<7eHg)?Rr>PhHgV5:"';sL5`k(hsbU>/@M%+J.8B+qM94oJIe!BUmd9nP="iFFHFU_8qt&LE!VFS6YKec7HiNfirJtU+r9gJP2n/\9 %[o@5@Vr(bXlKnPh-NEJ\-@bshbq1mN^YjTH6f6fo"lboS,l'Qf6FFbJ<(;o^'C"^-193;S[@2<*-#1;NLBCeYO"oW== %'ZGYr^q3]J^CsF6:\$t[gHqTbZ9[\_npMN@"cmKg09FcI.nU-L$KT#Z@X["fX,_>G!?=5/at`&sr\!e559s&[oJ!TMWE03dA#@.ig,U:s-=$.8Z[X=/be/HbVVm %/J!NHBuCq?=C+!H\gA-#`VIX_YRO()V_;*Y,oMTaQfT*/_;l?TA-C\i^_g4^OHEM"`R$4BdO$G0Ouhr`7'&)7@*oV>-$^F>V$"m' %Q*gr/>^UC>Zo/C<0>=VTAZ_'Zg\+B&X;_?LCV^UUWmot-7_7:aNNnm(8XL.J8=8`Z#J:WLffsc"Q(h2WjCV[3nWtn7,SBkLQTKm(k&F8*EDE4e6%PVf/>/R.#JbAY&%(%%3#8(TR^F?9%ZbA-oNcj5K %bcD!:TX,E(.RBTo\E_lWS9,:.8dQ:h'P==t_He[>9NH`"2*C!#Ec5gBKo9Z![0)*a*?55U"gB<(OYbOR'F7O'X44_h]jD98L'PTO %N59Spi&&]+-Uo\8*C[hA,Hb8=Wj0EUf,+lZWZ[:g*I"so9204L-0W>k-i:u=F.n5Ci %,q0!!<5pDqY&3Wo_n+e-1DVO3+=UUL,pt?E6Bf/m`(<&f;6Q?=t&)dPJa&OR0TcEM@o\IMgq(h.c,itV:6k9TX%W=Fl*rj %A(9*bX<'nH-isQ^M*2SX769/JM'G99b$?=E[I)f882hM"k2Mh*Qb.eC;kRNO,qgj<)atQB$lI?.:NgN6kbUj8f;pC8"%UV(7ptFd %h]/bA%JgrnkFM\(r@!&faLB,/hJlk1m6IA\7`W<-fAWt=h-tO10MHbm[.]g"YD.)8!9A!)q_kp>rqf6KKZJB8"KX36)6C:Zoind_ %,\%68=n1NXL3G-rH9%bK-[-?a*#_h#,nM^`F7-uan1E`[#EQ.mqG]f,B^_gl>ke2:k@Ad'kN#DOf*`MK %K>1_&74o;ME3_IX,'s$CG&qHIi"A&1G:W/n)n/dZPHF8Q\Z`.YUB6;0IK/36XdXk#Z$'Mq*j#ML::sh>705KKbYb#u7UX`W[]WsX %l]qdOWkR:p`,^O!GpA0%G:RVlT;5h%?;4mC8WBsBEfju>e:'tY^Mf$F1cLK$6fd#"FpCg55e92eUs3C"bKh\8#?FCgD0q<`ekPU/ %jXO.Lb:%e6mDumS3+1N6bA%(g=iY!Y_Oe$0k((V.1/D?/G18nM*btuf"j1*SpI]32CXJ?OScSpJJkiF`g\^*:DKp+M=-8)'(8'"1 %7hbfTW%4#W"^jr?k50I %3%9'JTW/'Y].L#K>2,\T'0OhUA-2COL%^Db%dBcJ.!YjsW6A7N?/+3fLNUjm;gF98E!U1a@njhP'f]<3S-o7q>LofJWi-_*.?M/r %=[$=t[DeAo'NSEa)Eg*7`J;g."le;&]3NO/@SA8@Icdu;hXn6jAXARGiPUnh#YQGi)(W/M1[)I;*Jnf(V3 %4&@>%`[Vf5UPrBR>-V\_WGrUX:`6=`]!f:Z%dSiS-hA*Na)L;^`hkG.s)%uMSAW5BBM$/q96Lr^(0/3XW9d5egpS6$)E(\4-kr', %$Q)OYbrV/J(!l0`2$F%\"A5e3g\^*:DKp+UIh?0g9g^m>>i]c)euLVUIT=qoka_gH<#ndsQ]mGjCYQb(uXBCl"CXUXQ %ScSpB!i:(f[eIsR?1Hj[/gJLO+$Q5AoD`\1G.$FaKdP/R(02,lZ`?PGn0Lqo^1E9YDGYL!I9th"?o_0EOY.u2IU@W&TIa>WD1/;j %l\5En32-?j%Ji,b*((*Aquc'-KPOWtOaPp25#K %)\/C\Feh.j+u+NrK6"F&B8ZO>[>jJSiNWVJn3Ikfj?L$i""jDT"!>>\8[jBr_S %lNe!!CmCcG^+Esn.U*?t#7:WlTS'@SH,keH/Y'*/-kN'BudQkX\)d;U9.C@>%6m7 %C$rXu:q`?lj2?fp#1W)L:u>>X(N"N&js.+P"SW&E,*G#FF[h9l$6C10S]*oO+`'Vrb+faV':UuD9j>.bDMbb'Qda[(;QFMg[C3Rg %!+G_MVmX##ST6,[$t*`<;m+n_^l.75q'lp;`He[YS0Q'#.@oAVmb/1cj)j?)^o'F9d4 %FD>+9hCjY,_h2n$iXk9X23*=>KC2c:G?"ef=O:=q].*oBh)RKgZ?;,:XkI60J.Pda4-0bFXsu9L*GljqV)%r:$]s97[(<]Z!Zd`DQr2hF-.Yqgfq&6G.W:SUf=(Fs@GUG26r"`X %&&QB1.9EPfEtsT0$V>R^F4Oh(Ja8>W<7`NYT^l-#/(YOm"*E^#O`hRkhK4T>UXf?`3.p(;kJ&Z8jfHnqg@e9%XR#kXb(ZVF<18gb %'mRDrJMS,$@!Yc"h)Ms;&c5$D>WP],)n:d0Dd3"Dm1O1>$3c;P_6Mn;d]j"g5/:#<5io.Hle;&]3NO/@SB-DZ8iLH^pJbtf-'ZQe %1:]F/0"ht/V/'D7e7%.;8^G5aQGp.;*(g_]a69<_X6ifee<&YuIKe3H#JYk58mU3.-\lj#rGQo;=Ol^CdS\)t't>>$Va;!/*rV!9e_45BAG\UO=hCjY,`Ih+bE)a!Al,ZTjgnhK4WJmeVMs\g_Ts%p]`oUA*QJo9S>Wf^%BUa'd-BRL8:9C\Q2L!C!Y]c]6i#GikUb/j3>kW)- %JH-QRVq/9CrGl"!4SX(1%WB4PK*5#VPr*L=XP<_rYtF@sBX?P;,%WJCaM"TW)9TG-_R*fZ@I6=R5R0cp>%ku%%@o#?JC)W\HX_Wj %TQ[@\h/M:O:0d!EKS`Ldh6"KGe\Y"^M!pG5i!.18`n:BX[;q)\\"31/ZpWPUW?2oJi7RMDkX^>3i9(@WTWtqBg@ei5X;_Y>b([`b %Su&Co1Dsg?-s$X0[COrPY?d6Ro@Q)t)(YCI>tZ^o*7lT#O?Tg` %bf*;E>cIHWpDXk:ih._'#?8u@Be&#+.PnLJed`B$'S1kj-Flsd/<%\^e)[Fqi3Hcm>m %)IWlna7]B@VV>"88?G"Ps1SJuZg(Rq9A`O_\`s%6gbp-W/m=+1a)O#O3cMLle#toRUTD!Hs2IO/]DK9NC)u@:@9gJ)N9:GkDgQkl!=?FkfSX3`thfjY%FCkK$l`.Bl %C@->.*55GA5K@OIJ$B\[]EVct3,SrEAJ%4)#+[]i\^`JTo@ne]/NH?gC\aQ:ebV\E`*g %%bDlX@VHrb5h;X\HUUnCp[crKD*btuf"j1*Sa*sjb`u=RO;F^`)Pda8#DqR56:i7+h.ea?i"L38j %;,12>....sHD?;9XnnmWGZRL\+Q[A[Fhbt#ihc$"Y&JPlEc\cYj5O+-;4TGQf@bX[5fVC.P'FBGmukT!met6I["t-kC4fDQNOoY0 %l$\:T0E%dD>kIS80O'tJ.Vl"q`NnlIMn-ajJQD'RK-OaPZc!c.@GFV/!0t/gX_Z\gjfiWIE%2Y50=S2B;3^U![fIEWIEUCu*NE5E %,!)C$B%:_[18c1a#LS<$i1%_c-Lm0LV,(mRp9+hMpaHog[_4$uiMP3SnBCCm\#@hm`hK'X!pir?\P@L;X2h#?6%(^C.7pR^dnM$% %4(BSM2-(55$C%Fqme3*eC,\Y-$3[;dUoCH%)$V+OqR(-)Ygd/TQJR0/9VDgZ5\9E6NjPAQVGN>]",-eF %d)#_D/&@,-brMpT&>6;;CteaR)V,?.:?J431=A-:V&S3l^o9!R=AQ1?GEU)Y%PdC((-!Q%q5PTn(AkDSB\Ph %5_.!_-.]Ks]iCjI%\3/Bh/\l;)=q_JD0ecgZ(ofn#tE?CU^%\AW;Hs=Y+)l5.Z7a.^c?Q:FspA->pD@:F %JWH@u4(T:qO#_fAqRGh*&h42@bQt8L/C6''Hs]ia8Jjj&[B*Olg(8F`YK>e>]m>P[FB)B5ql1q<=eKqj/7pY([ %Oi;lum?A=TWd75feLE'UYQ!$<,/#0nRe.eAhmVaFPTFTFqMHg6ghWfIXM)c6UVKrAER_S.]jD98L'OV;=9g'576=O^'j2Ndf1no) %J"hXE[E;*6HLL-n,"k8M=LIdJ7#&#MI6EnW2mfr4MW*n:#)6oZ/M4#SRee=ikW6:MW*oe(D$WX@Rd(SV"Pc`"#@\h2'" %>p8Sh?\-1IH`\!;Zr^7I"S`0Z?\-1IX]UHJg8h55!dk.e8$$L\]@E$]3,eqC %&X?8%$A2B1`IWB."SoC^X%@.HokKIC4/m'pm,#.hr=R:!267h^/$LS?@/"?hk,RghBgmRQQ+]fWU2BA%@GUG2A1f)>0q+S?_X!n4MQ.>eR&h:9 %;?hQp*Mttm6$LFtbEu6I*Qel!ngb)]%$Si4imdf0rp(!Af9K+gZ?OB`>k\,,eQ7jbBK'*sop#\_l_Io9bXp)J).U!oN4nV7=8/[7 %VcXtdHZ0JMXXf1W.]R_#>kJh-X_Z\geZj";nEh8:Sm7I0nTsjC&%+GI7-LR24F4UaFD?tkj0&5N%VRN\^7;V86l&.]Qn&9!XrICo8qFDJrb6K"U@-e?M'-X1mT0<[Yjr[>HH* %!`sfh;sW02IQ=JK*h:B("3`W;*=8j^ih9O("f^&M<3)sL4f_.uIB<8PE^B)mhA5:['grk6%b@\aGc9.anMmYFMZ:Dk^>`jLD0r0# %eoh!gk.V#3^fCmIX1mT0<[S(8X]^WiWMkDsdi71LobHOT90+u^(?SQE1K&t8"'tR7&%4MJ*ii:?nJ&Lu/"Tqr[eIsRh=0?%mMfQb %qDu=daq?2#;NP/3k,m67_4J'9Y(p%b5q)+n/6\("mG^rgT\7*jC3h49_naMPo%5p"_L,)]kNnFi.?\1gA>,Y:RN:b?=\hX7&]q0EQk@ %SP),TQmQOoI8F\uSAArB_nq;%=s"ggMdPe37Z/iZ!htT?3arnBHaa^RL'&fEgi.qAC*0Liik]kp9N>Z)pIo!PP\X%r&2\cX5j_bm %/\tcJikfN2`/:r)?1!n'QqhcTZ,XL?FUI,K.8sstD0pIIeeJ]jk.r3XZY&r8m?Ju"Wh^b6$RWm-3^bJB*g\BKC2M_6(U8!_44%`G %/AYR?AVkN;1%4#Og+,foHct9DNcEVJImHg^m&"'_%T4Q7pCMO7:;-'+hUQF#9qWQf%6>2.OVYb73auBiAT`[35;Rl9FdW&b_1lc?Zqr,`qD:5^@7l&LIPZ9`9HQ[/uL0EkP>M'^n,p=0#g&ntB.m7"_V"C5C[OZ1r?1*u,ZF\pZ=dF0@Ad=o" %KN$,Rf]?H(_3-,KAfFo*&'CdO/+YCJ%ObOc#^.'=_KM3AZ1#&TFh(S"E6XQoG?XU;oFpG/YOn%Gg9t#3?J"PZ;[ICMMSr,)A^Fr9KjB`_?CcYY/':*L3*iToOX6"L> %&5SelQ?_TFd8YE3@22B-i0ksgn$D.Tl%e_JYOjXVCR,[)Wg8Uj;?L'Q"tK:;WGG?"hkICSpQP*bY65"9X=\Jub_AH=)QNd*9@Li^Gf\Y&.BEfB^R#4IPgGBC&$jX=77tE1'0.A1O`@BL8iF\)lU:TPRBGQ0:hE+M(Qtj%^Pp9>E<7]aj`6k?;X` %76R%="(cPCgsEHGMlj[qm(eh,DD2AEWN9k:Q4_>,Z3\t):.AjR!c7#cRXbRX:1EYf[Rt)6Y1Eko'Mg0FsLjgGY(%AnQ?P%ga7]B*Sf-Ws[9?DAcOXtKWd_X!k) %b8#*0]IZ4UAl+'3(7@TZ#0O?*$fdoY/h[V!JV<$,D'?]%Qp']A"*SrmH>q-%de?pdXn4F5o!7noD/Hn-[9cr/i/(u'kdbDrCL3;J %>Vi>:I&e&%#>`7k>`c$G2(o@(6Xaa-UhqZ!NLZF/g&\gu/3UKi;<`FmCb,Ge>$dMDY-hiMW7L(q#!A%3#!J$(;(a6CRR76j.lsf$ %D$:^+E(8*r!dbKQ`!Y)(EAcKD%r@Y:H>(QtdW\mdXn3:jEjPD%D/Hmr[9cpXi2Hi=QpZ$0HX:d"N*sr*K(EhNpW5)pCC<"AXla5H %I7R5@Rb"pH@nNQK!EaELo\c0,V=1hS>NoeIj_!aigY-i:C;$e<_%VZEcuZ3a;DgDV#d/5^#'CE]_Ne]CN&;^c^l<$X[ZDV5R(0_3 %%9+"Jo\c06V=1a&?KoN!ZF'7FD/HmB[9cqds7nDiF=IT.\h#EX\>*QRV_LgP/5)/'F]hlJCuQ^5$f3jf2FFYMY\%V6_3M"cH``]; %qAFBX>5Hp\[b\MuYH*$><&,FK.S>pF2+pRQY5)%9_HL1lfaS'"Q^j;6W**;c]N!M)Y,tZVDnU>0/ka@nk&^lWY;PoD5D(R]90_1^ %G$(p>]"/,B-,U"0q';o(IQ/Jhu)_=^e;5g@`/Q`;gE?/*6qO1AUeTU88?.-FOn4!!a2VZbD<"OZ5F]:7N?-,$JJ^fG&]l,)mQpXH+\ %56l=l7"iIiGW>dddN0*qLR/o*k6+9Vq-;_V)2Q^_-ra(p41:+i;KeG4f+,kX3-n*Q7QD$-49;ob0;1)f-F'D0$\sZS6Qf.J(IFX' %@a`h9ZJ[S5g&_)-XmXh]\MGosP^MC";,M;kVAZOmOq((?-0#t]_($J69&p_BGF5H*"!Th>O\O6q1"JAG`I,Ude/ns4>gZGU4%H:Q`k(F=V& %eE&L?)$e`%4?*oAfrM8L9F#R56M!f5L_eWin1Ce?I%`^FCn)c:c'1-&f0hi7Ti<-?mSPYde3r2JqDu\8KM.:V %%6sq4,7!-eQkHi7bPT.LE4#VKNfab2MNE>\jWDr1^UnfAGk:1[pB@,FT&!WPci`d,5@7dr[G^u;K(es5$%.!kh>((NLNe7I&cSL> %rTWYJonVFs?^,HbrO2]-W6B2[q5<7;?b\gX*s_@Xk9%Fjqt7]W0Ppb?IR9r5A.'+>;4h!VjhTh'rLp$Cu^8s2k+tWH@CQj %Cg=g$fuHl)1GH2CHgt*@?%79LIX?AWrbX1]Ls>pJIW7:+EXn(9Hqe55@]hn#roNeGjBluZd^OXM'Rl_Q`moH`o'u)@2eW0b;gD=u %8C=7/*8GPSeFbt'hh^XErk8[NZoR$Mmk9&2?XJ;o3Bd8Wc,l%(T:^!J:006-e((lNYOeg,?ICNUo*Y*(F(@#?-%8G,`BoPprD.`?_./] %qugUe8#GKS^Da*N_o\g;+4!`c%duTWD.Hm1T>paG3;NMg+QXJ>T7N0_^BRH)oocd"%pa\[nF>l=Sr.-MUjTAJRoC9[J*Sm@5DSA2b^"X\gA2Zc!;nN'W'3P0(*mIR(lJ)0F2G\bejgOpH(FM!Il8p;urTX1@a7$2bY.r^b't8tiIhN*%LXFJ- %G^sX"6Z4(UCI(p?JaDAfu!F?AZ^FOC/j2no8c+BS=H0VSmC1O %l/]l*+r-FlV5qj1UTKh5e=QTE\+6:8Ib_G.r+QAI-1/,Qa)*J@gu3Wn1ZlD-8rt9R[/AC$%t>NQeXYC#[5WTAYd_;)J+MI)Su\:l %$2VlV)Re`BI@03do&9N+@[;5Z`E&SmLR[VQ):QW,0MWW3i"WA%@Ho3V5Fq_bH1ME0\imTlLX)jWbB(=c %=7Illc'b8M.@m&Z %])6Z2]0a9*Y3daEo-[W&QZM>/T)-'0_Nm8G(Z/:pRT\3/8c$&VQ?\GjEjgHQ=8)GM!L:`n\%peh)mnM^-/5*mC*qK[=Yh&Rl6!hHJ(3_i>9ak.WWdOPP#3QudV_p?(hJ,K,POD`q1pqMl+k %D2$U_5E7`7Bf6TKV,Q-f"C?.3\X%YnqL*k9bQBr2mE[_BqA9C;E]LMP&2P(,"fb5u6goe&":#k\3=Y$[UMfo[K?j^3NMo$>9dAC3QR`6OkEL_YqBpaTIG%IZc]aSlhn#2B+(i0?+(!t^CfV5JE7aCOWU&rAqH^P$Id6>Y,k9,X^WY6, %T=Wj%m()5rCbCLV';XtTP)I#\ZLI#SpA<%>gDTq.09:RPfZ8@eg]Rb8j>B[ob0tMreEQ>V)2U,`aF5:!\-pXd&;#5CE5_,K'Q453]Tcf_SZ4=!.D6]_pGMj"4LETA.cd<>"u.AfT%; %#;C^:u7Lh`lg*Q^\dLD?'0)j(8aa]piI_*4n[T.eYddY4/;qSa?Z]"Ct4@Mclo[U;g %?_*teEXXqc[2^I+,#RWmn^%bOlePUMI/NO$ZllZD2rR;5R(p*X$I>Z1-\jZgF0YS\.gUj8fCcb*s&^]E6e9f%fZJ=g\r0"$Z03e] %[Z]Iu?*L2XF;M%"5S_;5]3'.kMsb'%>qERFEN\%@jLl/]`PjtarXKdr(Y-]Mbi*?'Rt0UmG4tfi)7FD5CgM1$I2OZ%n1$>>ND-ZncQhQL0\uGlE\- %;Td4P^afln-;r!6rVak8l^sIM(jE,sP##\6d*+-jXEj+i\ %0)EiGqft0oiE5?0T(-0,D8-M9q[r#dVO6ji3JZcqp$][./99+ga[+X\?Z!H/hk/0a:T<_f? %E-$&GHZJZ>lgl".\b+FL]o]s8GU97`krJ=_F5LF)_Ml$D]`cs82'Il?%c.3bc<$3;Y;g:760t+)\57B.O$e^%_YP484XofUS9-p3HqF^OCmY^R`;#9.H0cMcirO4HY)4 %#'jH/U!s85;C7W@d?sk1e'5@o0$7bY-+2DG3GMc0^c.GBiKp&U@F6.!(I[/6+46TYCq1Y8N"p0.(X\20Dm'[K,Gj;Q'puT8HG2h# %^4'F,2_dodU-FEU/=PAebB[AfmUiYg*E(suD:%>r'%;J>r?=$L1=IF'D4S&=a@t>3Gq:`"'@2&jR5Qi0Mp/P<1=P"J3a/>VD3^PJ %B*Hp2WG1s5(85Hc*rR9>/OIo11qfitiST=81hRP-/i;t]h%cDkc$apBVuM0nrVjEuP8W"mOd^GeC3h+mi9*P?DX6D3)\Mh6jbY;C %I[a)BCEr86gj?4CEPK,1FNGB(70r+p7H#/a8EPDMHZ=*&_\[Y&])M6\o_eFGs-f^6qKVo/XI@\hm,d7AB9`JQg@m@@qE+::ILk%G %LL/'GgU#_cidlA<[T<(q&X0L@mIl0]&H]K+A7&"X].KCb\(TKgA`C/k=jLBhf"^=WV1H?E4dj4]%?7i90mmk/f2l'tH%sO(rSYX2 %p!`YV!f&G=G4Y]]/53OUC&8]Ren0E(O.U;RS=H1q]Qn#Q>uLH4]6Q&QV6p.1B=J7@D>@h4"6.WI/1nWk*7gT/`r8G!i+@.$:2rJ4 %ZMMNjpk-n!fC/_;j7UsU6e9f%=?)V#@sJ-9ARS[VL8CN[f8OBdOCNQi(:olC6eJ(5;5C5OKDclt8G8+(!tZbU@%P=-J*u %qA#kkA(U0)RJ0X(gH"r=ns&cF\$&7'G2J3[Z=ROUqhBi,DdF-uh\L=+A!>2,W^H&k$pgHWIo^03<%q7Q-Q>q5LGQ1_0%VRTC_uhXGK3t/B!'R9p]X[`* %9,%na=GpPC;u,Nq9?XNc>FFbl&p'H+kp>,OEs+bfJrfR)n5CNM%jgWhXms]\0o)?8-4h\>> %pXf#;++EfVm^lL@jbNk75X4YH]g(o_^]0q[HOoNDp23*>Wt'0qHW`j]@/Sk-_T[ROg/fDIm"&'k %!D":l(G#ZpN;ta>6!:sHMI3uJUp6aZ#h_1RkmrA%!J'S\)BBD,%YE5fJ2rnOl2,F]9Z"7;5hVs5l8&OB4PEUC;8F4(NW9 %+_QEmIo-,J5k.+O^tW4H:=J^s^nkSPA[!5:.[NF'_LfufWInUDoLii:_XL,=f\gJ>FPsQ`"S@OYV'd>j'Jk7+b;Y:sQ:n"UNoWoK %:aUcZ\kh0L3s-U0`maLh/M6L[$TLWi\ZPB6[Q4.=AZ_e)9>FAAPi8r!@,j@c8kS3bQ5u_l7I.3q5-QA,#>/3f5uqQfdBjB-p7'6' %HusM>&_m=E8/e.Qhgq*&TcLp"X(,36NB2#cKhbqD]bHo_Wb,\IF9'p")Y.iV[2"hi$b5@J9P8&r\92!1/2`af/5oYJ$!:6d''HqNL^mkY2 %,;At!n5J4B&/i9*fnfaoiLF`D_lF%U^h"U,We*fN9mG-5Ug&EB]ccO4Xe9\;#+Z"+%jNN/3rfne"+a/l]S3`2aB#-6WK)T]WQT)& %8[(BT-j0&rWk96?,R,Y7J2H.2+a4@2028u[GjfDu;]\uZ>Mo*RJ1A(nYU7L.[2GER"$AGX9/-ToKj^e$/mo^*)n3lgQ8!X?9EUMX %`TbC3Eh0T2PI?3b8Um,33hssli6)JfasAK0N/erX]hRUdm%U'+]CL$iBr,BdCKdkr9aQ+N+u?e'YX:$=Sd=a\d,SUc5K58#cL]^( %TMI&Y$`u!tYXtEAiXB+q=$c*"M/N %I1BpIB'D,0i??>YXFkcG3^M(5d5+HM&C,*J*9W)Y@R0e:6"r4i#b3HOE#gB)Z1*!!#hb=B.!'J?Bkp55@#dd2)_#PF^:+PJ8L!jC %lps0W>Z8bGo6'A\\K"-qY""nCGiQq6RM'r%-)CP];h4b%>TU0]Y3eCB._of?_o$O>0X)kAVpuG,#0)DVn4.)ghNPqpiI-T,A=rAR %\I#$2mqBb(iFNK4edX5q$oqbfn;RFYlSq4Y9\?^^*VnBJ9P/^G4Zci>EmM8TZR7B5B6""XGSN]&(iTdU[;jKBFZ`pUJ]C7XjMT=W %&=M,`[N1L%do.#(n>"U11k:Ar);e2,0J'A#6juE/',cF!\VMI]\5]h"$9=A>oE(0%'&"i&HE'=fQ568L"H(,P:CCPkek'_RE-JZY %i&cC3q!C05jZi[W#fj^Z`t\lcn+XQ.3I-+'<[;8Dno+45lP6^2rgTIe[PTX=0\Wf?\dJs,r9g,n/P5a'^AL;&<;:Q22_gSgffQio %pRr"EGZa%Xs!XW-JP,%Wa"di]eoLXf\T>"]T&g2Wrb'Ckji[d_[WJBp8C.Q#ZSIMiT(M=NC+f'nq)SRm9JG0M>rIfN]Ie>t\([(\ %M8GTP@q`d&WEA-&F@]*`R:7Vk,en;UQAB=%02XX^J:qO%=c/Xb:q/X80m*k<%_k %N;O-HpgBoD_Z'ibnVFkiI"cC#EeTel2c*o=&2?-:_D?fK4GZF*=U9CO?3krN.&CRLCl68g)7nmbR$XKj %;ffac5g9ht\P-E/AH`bf&.'@TD_)4\_R.pW1Xgc"K!KI>''2(A"GOc1oTP-M$]T\%1P%3_0[u(4mk6JJf7]o=2j%^mJh1cnGg^+* %OqM@$E_(cG]+)&eGa_1[RGY%-%`#q&kdp;+7t?nl7j%puB%5i`c$,G\9Lqm.l3$!)H<5#6'E2O01WTC:C):5(=RSF&=J5]jpu%]R %9f0S)L\RSV&U>IM)dXVLq8-Iif1Rb3-sC.69qF1HWQ-.^VK4la(TdAX'Ed)5Bbt82YI?*LO %Z@%^X;VJ!A;alW`R<>d'DA?VfjQ-s:q<\`j%NSYj\n+m;8]50`r`@;k+I,$7@d.ES6;Qk>%I5V3@67*EdYD]H+N&dfoQNmD*]lfuhZ.;]T(+sTIOWFAQ\ETi6Y2C,Ges:o#]rDlObHg2o#GJ#CBs!5X@u^d#HgZgMW)dAs7aRN;16/42!RKTO1D"OC@XUKEm;gh;(B[I+s:BloT!507<&3?'`SRLIhlQc:Crsee5l5!6D)CuiM]:Wl[>qC/B'/t %>SVsW7E]m@YO3\=Kp7G`dFuHOH4_RcR_',:]1R>$-S:0R!E_m?'qN!@%9ASG-qQ0L<>X/0e2Jt %]fTZ]b7f)NKZ>9q)eUXX8GqmQ%7o]U4<%(p-QWOS/=;@#!AGXQqabKM353'MOAmP&Q!gMue9UdoF:>Kl6\A5+=>-]^ucS13SS>4*JF@8.GM&DAXPYbl#?5f3h4D[g^EaOT]aOc7Mh6Uu8JKXTmE %C;Oqe:>8hY.EJ`2AWJ`hgPq\sfQor=Niefj*G1ABn_h*P,'ggH5*#gIDc;GojV[?.Z.BN?34?c+CtqRi3X'(jiol6O8R$I5*SmgC %DBuL[M>$#?^13ki*DmoCfDmm[pYjqXr8ZTt:lG:up[>uUYCEnQci:Zc+Rc84cpN[e\&jI$$Bsq9"A\lHB1W@^S^WHm^B39u[Plg3 %/H`*e&!Ea-+q0EI7P%R#'P+hS/ST67($Q'^dD4\8m%^j&%i3E5;?X>n)1XWOMG!E/$Hu#K5@rMDLVaeN8N\%$7ok9E8"tnrofOg# %Zb.4ZL0(X]P`(ahj`jd"8AmhD?on*tK@u)i?l,KZ=<VTiaiD%u>4S^2:`8Ca,Fb'[WE`1JG\hdp@ %lI)c(D&-8N/#!%(%H2<6od+3;.WSJnX@"QM$]J@]om=s_.]$o`CNQ$D<@msMPaORL=gU`377'_kPn&HY8>N4u4H\V@V&'ZS>4(j7m,XggM:+[Vh]Uk,>nMMh++u1-]kBRPq)bBI#ds$2!&m'H80mb-iOh%=[I3Le!VB*p %HXG<("f&RI)2P:&_'ihL?srY`?q6-XD8Df@g)@!pQo'X2jjo&Zj&?FF_([iP-[%>E27)<(@ZiLO/CoXK6@/e=/>C@3UT4E(S5A$+ %@NZ,AeZ>6q6V)Ec`(b2nnu`I&&86l;/t#B %1Y79"lDlQMTfT[b\pAlf9tD!PnM7oSLB8'#a$,7Omka:*5]% %lu_4=sSD=H55J0%S+;<=_7/7"$\c>Lk+'H'1n'0#baMo!).0S %A6EUZTiElB=8IV!3/ML_UNO,;@u>UX<@kU(jg6sEcna'jIansj:`Fr6?:@d=k^39pX-_IQumsY-5jN"U?9D&2_cdM*:o'\XrHCI]tYg;_8 %NZR\.R7Ct?p>dBHVpBbDQ+arfS6UJdp6f7Yi8C:\lgm9?RN-9WM6/<]B(2s2bZ?tO.4eVQ!c9(5Zs6.+7,VQU\S-$BE?n[,ZU257 %<_pA7!q4]M;:LdK9J/))8-/uB-h+_d)ZmL'1N2(n%oKP<:48K3+gK3SkmUY>h(%hnUD+JT%[L<8r,9ZOH'kkFGRBYrJb*$g.sh:$>Ong8Fq/J,5U2q7\3Lg2O9nm_l1T!fB\f96[ %gn;4rFPW[`C`V?V67_@ClVLCZR%02g?K,,%5UM%8ONK0Z"&:g1!_99Km:(#O!8Xa+ejuqM>hD3!=2_n)odgJj2<Y;Vl6q2_: %8VJ7d@)K(Q+lfjJ]N>U_g!#LGRP:$B&[CgG's&tn:I*-=-arODL;b,TGkDDUQ.U:;Vtt'lBN68,J\TtpMf=CGA(:n>8#18Mk;M6* %_#$[Z5rRe/)-.Xog@K$fLA$"b"M>Z.o5Vo$mqOi_>bGTnLjS!eK-XkqS)-'LZU1\Y9>B#;Sf$7baglqQ(&*)<70)A>O%0Zj1-@Q([bqS)BjrC>7PhG<]K,PH/*&WT[Ll4#oE1h!JTPOcgLt2/H)EC/M1K+^R9?RKN>a':MsD+aD"l!#W:2j74>2J=*ZO0+'[. %PG^KDaG'D<7(V+UN[-&J%]+\Sn1.#m5hqB;HJjKpWGLtoH2p1"o#bP7+Jka!I(4L<;Houq(Y+FlV^J(aYeU$?\,A[nP8Ko,:0FLZ %,HM7mT5<>DnU]<:)ppt-l4J&W\^Hj;3NgmRXCDV9F#abkr4U4uqJ$hPUX %H0+UolQTG.@S(Jf-cLG9I>>;Je/SUL#2,Sg:t_!/(2++:3T?@?#UuJ63c"1/+TE"D04*sa,nu@`Q>u&(=\sVa7t4`#>qd] %4&5Mp9HF*lfOr&)no"S8HfQ;3&Bi"lbOKK.I[d,-F\9;Q\QKo"lIkH]cEl_!-VF%UnOV^A`sG*QI<(Jg+]VNj %nmYZi?2l@K8@1i_BVSRn/I3d.V"V?Cb1.=8Nuf3Ke:I'ein-l1nF:$(MRF(MWN*,Y`P@'?)O!sb%>Gm5*eGTmHlu'$if'D`#]#8/ %(_FeK4E^qSQZb-%&O`a8jp7Abm^Jcg"2#$<"83*m#8)f8XF#Ua[GhfL]8?FoQr3aO`unZlrQ59,PgH=oT6NLp,^UL^=O/$_:V[4W %f$cb_f96o=*$&7:^jsmBQjaG=ek.oQ1lNI@=qP<6N)NS&H+E';02MdL#D/\*[Xu[7R)DP=@L)\V %!&noo:.U&#BRYEl85)"uc7(9s&k'@'i@2kC5b_?q0>XfQ(kKV.?jp(W,GZqP6?tA4BF*"`aD#f^bB8 %DhhBqSg37'JJ`oF'N7F2Y9c\XonAPLRB.i'hQiF9Z#]VRqX2`]?D8^-:@=mu`Koj#R8Cnf.Gb)"YfdYjafah2K5jL!`+9nga>RVH %Hbd7&#Cm[Z&-Fr!-4ikSSYSd&9)SXL9ju8H>C(rHdq?MF8]4@uYGB)!1mp0drU@MCH))'FcEsJs@&c.4:MC=f-CftrR4:#BaFn]s %XMJ(`"9u5P-g]'HJUlaic3^TfFp$nEbt+102&bjF*DjdjL=#3;\]^Z!MUC#^M&VV.kBY`jGE]9p@HBVJg %)=R`,E7SuB+_MB4Bn5g^+[ITFe^OkeA_P0O58*/8a!O$N551+4IO%\_O%k'KhTtP$4jADnoXW:r,fpVu-Ebr2aaI,I8poJ;TDM/a %`ugfJkXaq7j)Q5A:YEeM5!!-[n`\auU(_utm\ALPqV4Su$2NDfO,fU=5khJ\fU&C).7ngrXpX,+bGA_b?ntRff_N=[d69\SY"9]eSeL)B/8D8Aa+DI1MB7GUj@ZO%jkG,`:DJ-+jt2m7/M94_!7*UD)K*Z#9'6KXYj;n#Hb5 %CBonpG^IATh$5=?4aK$e*h)S![dMNLDl]WrH0@CRiN:>^d0X`&miRhap?5e373A,j15oYkYG^C]Nh+&g)4VG0j %,88oTM,sAU$#bm]$&Nn3_V6;4lTR;em?/o,acs#?8m!hp/=@-j]D0RR1er1PRtojKMe/G0KAEgg;(K)3lu0']jq#-6m"c! %VmEHQ"'/@U)@Ca)^7GKeY:1VEEV2"$!NkE)5TR`k;]_g^Kn!/I8QH#be$bJQN^gkc$Zlo<^6SQQOD]"lF@"Q'b#]#g\oXhW8KrR? %KZ$IflpM.l9D46sYQ-!A]k/@>5]b(UOMQ`#:.^;P20^'k3Ud"q7g;H.&..Dk"Vq*L87t^,">TU4=(&k>\?f5.-7>t)&1[k2oI9D$ %eccQKp*iU;67l7W_`;i.+-R._,a35k-PP6Y"#"*^F8+mJ(nmlEKp6/fIZ'_a)]p882k"@St:J;UcojS)Q#=HTc22/3oKqj#,i"Z %,-'EGT76LQL0LJWVit_d!l`N$6M;pH(#O-e1^PorjtM2`J;MD'!+7D.-R:?sV6;n_anAKH?DXT_;'6Baq@q/tfq9!1J$YNo^jbt?2>&b#p9)9([J,6%jj00spJH=4,n;_V/-ee@eG.FB:6SCHW2P\YKH7/XT%bglasC8=&iC,1)H8&.OP[)T:8Be"XG,l&de>V23#'sGb_9.46j?3ii9E[o[7p-Ab-E`W:#`4H,;h*IA]1f-fl>a();ZE>$Kj<5+LH\>\IdO^ate!h7)EM[B0C`fe)Ugu"nP,;]?EX*%IAnR!SuME0M7Be[mJ4b-[<.=$Zo4E[6s;J:rC!-GU6Dkc$A9N^5h+#dZN@ %ra&:NJOgQE&&b@GWXHa%]ndf-P.<>(^HcS_5)X>d'G%Zmog]P-#S'cLcrh'O/uY]6g0iMHj's*o24:hZ?*eQbF*g$^]>qLf?+1dA %K'%m;-Ap_mJ0;ES;NHVcRaFGTh`rYKcE>Yi6=?tCQ7X8kX,,0YiRrVmclkCp.sAcCNs&E3+P:bh@/s1P0Q9AbPg)s[pG*pn\ICnl %&"Qq0#+nCr/O&Y;`3*sBYe#uAA+:.2PJQ@LiiS@ZLmW@[=I'Y&!2KTbORUmnKAhg.j65@!U\(%ob==u.n3GTt+BfSId9"Z`&\'EU %=!h7RE561f\uAi$)WX=r\'M=Y7,;=QEq`@kc5Y!1KBi.TTV6r#r85L`i:Upr$[K*=e %U`&B3'F1V+0Sa0OgRd":6NiOaS8A[BjQN'.e9WP+Y %(53se_9nU31PE1bcfXh8EjKMe!kkt#8j;DX7AMH5Z>SR`IP(fPbg+Bn&O]/,(/;O1-6Dr&ok4F9cG6U %;fL$>9bP$`gQ],n.5?I"@R(q]JKo(Fk&aY5i)+\CJ7/Hh"bNM7))oU_joCi;HFD6YG\YX[il.;8lf"DJ[a"&_^$AQ]phdi"cQ@]7 %nV=I*+n#%g5,#A%K5\TJ#CN,:*a+#?%R(]%Q7`6IdYuKe\10]c:=hl046.t\U9pV\%+Z#/FP2,rZQ^'MJ?LRbMIL3dKgKqd$9LP, %Vh-5V"Qbs9]21%e%"j,*R4:qQ`2MQ[RuCi)*&Kcs)Nh#Pi-W!J4'kS[)h*G,[Ld:p%I"RtF+,g5;j)6#iaN5A*SF+E&[\:` %Nt'pV*o1@GYnJj6fY[p].[eIL#C*bVO+LfgN"GjP`'/+(XPaAknS:@C[J'6iuJO)ibBOp?B'keT:LGL(;'?k+K %]l0*&@jjh_AXlk)KjZP**k[Po]OZNTeD*=k)6KDM"VE`:0QGkj>a.V*m5.$ %p0gCVCrP2FEEk^i>d^\WluSGTHN&$VJc^Dif)*CTd7ebW'DpEdaGrDo.l1S@UMWWC^%k\=/0UgR*JN"]h\YI$;;C#Y`tl[H&5A9 %GU0&7,iDRboEa7HP87_eF_I-/JX0bPlhZ:OcJt/fq$7$u#NgO2,hP8(aQ/0Ah=*UOc`<"aC1%/u`dsdJ1?Ise7 %'i_"-Pa\"rd[1bU1.JM^;1F+\,\F$9?%HH4P),d6XlkZ96a$Q]N8MG,9Vp?L74YE''j$O*P(@N8S*aQYDK!j=Y5VHIJWI9!-d_5K %5QAeBS9orND#?gpXMM?(gi5&&/JhDciq %OCsddV]5_/Q:Ou2eDFgN;nn$Vq\cI)p-!,m3YL\tDY&Od6#F!0/\N*M,0?ZfT&JsnZ`?6Gj"4Q+iR7Ao3]5:rk$#kuV'T-:?f;g8 %9>:A!,_DiH!RFign'qoj"kd[8V9K*kOfR6*;+fUd=1DHl\I^1"XPIus".lHmkGVbCK7)k]6h%p9e-4BmL8rG07h&9.\8'--Y>BDS!nrNHn"r.ke8=G@F6N`f^9#)"QBAm&M_S2XD48HE=@I`*aWa %9h`pn5&f!Y-3fn8'%DB`LMVMZOpBoPp]^1R-oSU7ot^[ %EQ=>#=J8+b^47c&_r:!Fmg^aH]:0#V"_u#poj<5B.HL3e0%eB&%d/k'n[*blXabdWP9Dfr&XYXNq!E<:Ua-LhDn;;c76W6>l+K#lt;-j`?<7#n>OAbMMmnRihpDrQ'Fk-8JJc(ogq&ZX2,%4Lf;F9"B\:/oT %pc`umfDFbT(3B8qhJ^.]1>UK)HbVa,r:9LPe)fJiDc%qL*l0u1dfV]1>Z(1eA]q9[Ip1*#qpcln^5-<60nWDMjW4KW0YNXeFO!_E %d"\nSKi<`Y0hL>g--.cmRL>B5m+]40R>[I.oO=\*"uB[2?A<[>K*Tq_R^D`W*@)",H(KeU0o\ea1Ca`M"sLT2g9*:+**Y9$6Y+:CY[7Rc'csPaGL*toMMP92<gM+B[u**FQ-6/U"&2m^1W;(;&$H]+\]XTJRQrA\&T/.d5ZU %&Sf52m^2ih9,aEF91GT83pVc$^dOSbha0@2a:\+GgXGH'LCYL%),3o8-7'X+:PFj83EF82f,LJc^[J5q-HYF.R%>dP1c.KqTTq5Z %hqn`H9M`td@32%h\6Vd(Ms4r<1`&`)0g.+cV]@HS6%WF#R,shITT>QCZK-HlcBQJL@TSF%!e6iL6o&cQqrDcfo!QW!C]up^aO\+YZ!+R5.*phI.U#:fjla%@C %d-`^W@t`ukTiaO,$3bblS;1?,/;qSND=*dQLQ(\^s&]C^XdGDAZF,M,Zg3;m%-]]K?JUNWD@etNCL.6Ofk%XAo-Z?+'7?u;n/SaL %02*)Tg\H'N0=&A;$S8U!+q#s-^`j0QJ1P*%kS'hS@eRGq_&Mhi9R@$3q>ROT[GXoZ!;aMXTYpF!5o*Rjfo*rS:6rFs*l("p%A*i! %=kdT4""T"!?-kJ?qOI*V"Q.C22L,;)*)0c*)ii]s!tVJYKD'+D>dG.ne?"OJ-.bEfaeNu5!NZ+5'?5?0c+Q4^,E21Y#O]3EL;eg- %^scTZC\N^[K3SHAYuuYaPD0`r?k%@C#G,!0Ad6H+9#V&^op"IO %KDOA3ET$QaqPk[/rOou$S6UJdp&r2[6#crt,RmmqFb$1h!-0QUq2O#&?Jl;[7#8D]O"ZCkGgIdJA:&PACq<9+2!&SO-m9PkXq!NI@`M#HZoKVGDuiT_pamI0ipQ@P))kQ(P8rjV9,@ %J$eHUUpa^s@JS9T%j*Sc(1f'RQr4Q,S-AA(8F('=6W45jOt\O)kQW.F#:(UIb[^,I+>-&R\dO/0RlCTfc8RdXN[\AI$)(ZBkL0Ep %19DRmg_Z$*;Hn@,s44;Y(C!XNk%MQh>t*Y:*V(OC5?*E^K'^7_"ZWuRqP %265nT4&G@um/73l?f-^:Z=0^[g$G.DGj.Mr`/^(s-HOUK,#uU<0(urPo1k1]@r^-em]h-9:a6lI\bj-qWn1&mWo/X;%s[l*!Drk+ %]^#\DI>/f_"^>r>W0'B"7Agr':9V)VEsV,W^%umG7"_8L@3Si&a)]j#Z"=$8Aa(rE27I/pqC_"*qg$NRp6!RaH!9@1:^g")a&V0# %4OF_Z#Z=ho.9Y1%.n_0"K7tq:hYR/Jqp"6Vsm>; %.MqL\.>!pI8Gs$57Me`:fa]57.mbl<4WEG6>V&/'2gu_UQFrak)Ehot_oI]E-%A<)oYfN_G:W<:Dlf*Fp70:)\ltp9DMG&5PmuBp %c<+uh-A_,;K2q^2h-`tTE')\tJ/f"50B=eFlC7W:G^p:VnJ.q8&>!e*9iffZ&^Bp7mRN=Z]D'3)28$54el5kE?iWc@3`',=f`B`; %>p1XfP4[sdKJbtbnW<77XHA]+BE1:b29ia.-NtiXUi9t3(3rIY`lCC/d5BpJG%>S,?:ndWhNf+Wo"\`-. %-k1V-'/r]JC>bWtQ'6rl9,.t64-O`tcT/;Jfig2Boit=%q@l]^XhGX=lVfM8YT/s/mAA15UNb1f$./3.[-so:h;snLEVaR+e7g.h %f]Th0JE`lh\.^!("N]]^Dd%[;Mb^fkHe4c!KQ+,ge78D$Z+K+\.C-bAd^<_J.7DI:,1$BA>b)SD!Bi+T$p(%$6\SoZ#T)af7`h'] %MBIo_6e]m%Lu0$JY_ZA0C^]AeZC?!-8gNNJ*h3KO`2df!W'p>6fD9@3RLT'-bTi@1*O[#Rl5@^1!3lVS$K\NZ %GLmV3oFZ@Z_hHjVr;b0!;!We'-j??VVWGiRiAi?edW[A6ef$el]TtW2tVN1H1MO=U9Ah#&J-nPXIC(g^8$Ob5..^[f`o/pVu885@LXf5LpY]0!na2oZBaC#_%m0&1j %@jYiqHBjNAhls`;"J8igbC^dimr01..K(Zh@kEYfm@L>fapHeEnN$f>ltXee3q*$#"c&GhX%E%u\2a9u6OZ`\o[=BF4!;"pb-b%4Ap %U75,9ooib9d8MMa#tCB#&al@I,lU29%IRG6SW?%u#[]jE%4]:;>+2P.)6t@gP/[V`6&L^>9PMKf4G]gpFed?%/$9/8C.:kXcRTPA %/]%8:JO'_0W@Q\A)%9+t8ceWH,LW[beZdU(O]'$d+7"OU*pVmHUD5,>d=!s[$LHBK]"=lJCb+#l#])dT+,H[5QFe9gBDKYa.D8DH %IXu;==e?VLJKn;?'H8E*e %@R]8fM2$fsB`Y6&!XT6Ud_\8Yj>iGlCO1LBhna.SYhr=g26sc`JTU%9K?<2ZXXT3o8fWYJjjApc8NbUD:cAS@fRT0Ye4cP!Un^LA %GZk,/MN'm">-6kR2fRG[+(QqPF-,m#\6O1mjqks(d)scP5eRpU_I_/HbKO/#GEAU\"C^516,#aiZ*G[(mYGFCrM)0?NhDo#F3M:k %QS/BMH@#iV1s>YjnMG92^\>rAPT_$SeH_'".L%=GKMZjUF#H %W17At3_T`LO3W"$bMn.NFUGhb1NQ6s`0)Xu!!E7SD!F1AaFo6GN^Jj>/kP.YH#s)8`^1_aeGOH+bA$blim;Cl%E!DJ2Ug5k %^SI.VT;$N,8ZK?;So,?[\c.ZUbHiWZVk90DF+Aqr>Z;arfR5B?b=a!T[T\L;nIc'O@)/+(ar-GQE'G1gJg/jl1R@gQGgPMg&&o6R %LJ]W$JOt[fT9eqo\RHo9[//KP_4bWQZn!>,>7Vac5_BO:HJNg][ck6I`*<,bprOg<&4O>&%=1-';ef,W`I8o9n%n>$`cY+:IT0T- %Ep<^.U_ML&en.%Q?;j-Rr4GeXCX0D]Pu`lKJ]bT!c>l"r\Zn*Opg=57h`=0"*K4 %P3VUB+]kokS&=^O'u!\q3s.5YA\p)3;]RI@o.Sh:lUE\BK#8:e-K!=5+7K#&l6B1nC2]40DW1n'fmaJ,>6^VOWcu+56.B( %49uO@jTH!V6##=6Uf.AsFM2VjS(tH:D;W9C^mS464Z2.OC'X0==SqI:19C7aAIiD+SjO\l;Pfod>7jD.QKg99,)EDs]E=L$r^XFu %IUR8b*N,T$IX`Y12Ru.8_:8k1Zkt5O$ZmK8K*9HF)A"Tu!@t6gY0f_GSK(P&+`/#V4BZiP._Fh"m4_d^e6+V9h;P,Q!uRFmBD;6T %@K3DHG8PfW9eFBJV6O16-pGbLOq&G8+2!0:M7-`%4l(^NqY267[bGXCRbmFf2[t(dYR[IUCFMIt$br$l3R0!WN%r,#];4 %Af]`E*Ho5sENT1HroW;M@2n&C>nt$9'2PA:Po\Bd* %!d\r$HqqA,]U)a:=(b?\,$30.qmP=$>Hb)S0Se(jG;kuAW*;O*5X3CJgH%]/]*6J+%HgVm-ZC7u+k/!nMQmLjTd.oJC6#YZQ?>lo %]%\Uu$>%FkQmbmmc>h8h&L0"%fjHr?l+7P_Q&V`5C0u*TFaSasDNUjN2f3?q3aGngkFN!YKrst5.`B*C9^>I&*9D+IhOTqmU7DA=5:j*K=5snj1?7DGb?9;Q_oM5pd2$CGc]qJM(2.a'P[2B6Hc9cQdFD^?TqHd7si,d5]'bLPb1FTd: %s&,aE!tF@O8/u]&eSCOh"1kLe1[s#%L"r'L<0QCo4&40.GNLb5X)IBe,%##slb_t(:NM.8B_sd^Ah)S9=D_#Vgqj]5: %F-"+(\;'&/;Xt4AdjWZLlESj[Af<)fk1HsAmWOp1W2JPa;CEt/\F?la6<47,:pX>VE[#(im%eKqU*sNT%7h/2-X*4W&stb?L#jKR %Wg`tj7AV>pmFq8lXh@JRi3N_[\V&99l/5oZVFJ`oG'k-g>esQ@GSZ$dH^>_')NP#;!_RFgTGC!Z(sF2C`.EFU-d![i6c?f,L+k8/U3$tS=Bgk;68mn]ZB%J'9ZTK3;>.qb %6Nmqb4.m]*2!,#h(f6LRlT58f*:p*$'<&^qGPu'a[f's;dks5Vfe3JE>>3$3k@'r9%[>LZkCOoK)Vg$,_^IAB %n2)Cb-2O'H#NYUf/ks>6$,9L,k>^(o/b^*a%-4[EZBHT=kF=j-<7k[e>W7J`:0fZSiL"PP!h!#&r/OPPX&P# %SiW#^_g,mXY@]Ko"J/<+p)n$Xn]FiY59J5o7OKa]"icW=Q=AW#0T25c!4l\\"*KL&n?bIo$5I0hAl:=6Fd0Br)_!h?sss*UhGE2^D9F[_,h1pKun!0B;NFp!&4GKZ3=nGid,S?JA(+d`MJ/JX7M0YA,IcD %\0.j0.bJ]Z(!WGn\12#]HO-Hp:ubT*E!eoSjpVV]Xe=-=T&N!M=No?EM:QR'TnLMd7(?snN6tAETrW0Z2OW:33PRnSRb,OX/1o\'DO %@\1u(qa(>;-nqL>O!g,mgaOI32Q+I![.M9kH\s,c%)YC)g"F:6!m5Gank>0&-BWA@OpI(0LAKYhQiSo#[fXXHGtQT)Pp')@"EZ76 %_+%U=P^ndc#Y^CR$ZQU>"e,U!jTSL%V.BlZ8+8LN"-K/uj5hm$`rDe&"Wl^>Bf\di$J!rp-lZXK:..8W!h1l#+#8\;L>YLPRgT:c %abI@qX;.@4\]"cX:FNLS#g`le>uCf,a5kg!YJDiWUYE,/R$Cg++:SS^jEpB:fe3Tj_1Q^`d""SJ<':bBJ[!^-=Slem!f>hhV#3<% %^oU[-&kI#2PPJH'[,HPXK7^*9E*'Fs2Zf!s4UWaf=9g+?f1&2K<;jYnMNU6TePsRX!/uKh<70)3ZjdUF7rjJ6H-&7+^S"IM$a:Re %5p_u;1,roNJRM_Mo^k]@J)UL0=Y>KW\:1&bAI+)\&8,ABP=EfQ\4i.k`0u?)BPjfF7q)s]6[4-_3r4dZ8u:Ta9h0oJH+j!K'm:#g %#(_QXOq&(er$?OJ[HrMN5aBu_&NR`R[T6TI==4Gcmg3cdBIi5FgfZdm8)kd(7U!=]i(X9o:*]RW#'B>q68Y*c>7X#;j?3]N!&0mp %L^>4/n,^%W,nRH!VjgG\L_tsgXUHqQ"Vkb$9bc0X1b%c;<9MG?^,E]1,sq1V"`RTG5JcojiTMgTaUAeGB`@0'>d+N<%:PqA0FC3W %ofE8c#B;r;.QPFS1ZqEVfb$#8UkE0VT8eHj4-t!>_$1%03(>%]^sP@K#1B/2QQ$L`.1MhU1c[sT:H`c)MNWDUUV!0cf.")`<*)*#*gIEU+]aUO %RWD:I&cDs9Lb>)@[3^=D/\kd[3B\9s-K,:3d0$r#Xr3dn:=lt=(![OY7fqo"\,G`Og9!0?DG4W:(PL>eZWfi()LIX@Q"q+!,N2`BT"!6\qa*@^$a?l %"/?tC$(W6X(lhq?m9K7^XZKf"QWM*jc'pKa#%c+Kd=FmbEs8gqNi(_VaKni*`NgpQd^=EC%`ek$7_C&L+rVFL8-X+KK9)BZcZrr9 %P%`m_MCd%4)^W!(h[QI=7`h`8JTYAfMY9W3IiN%'KEq[``H;2kK+Q[_@gd4lKcP\&@@`AblsNOZ&"F@1PmmSY'LC_P?1&X=J$rCT %#L*M=VbF5s[Cm28#^-G!5,8?%P/O[$QG*cLYF:X&-:]'$7fptL1ES=>ZpmT"Uq1[N=)^n/kpFRZp%mD %g&kub!#7$HN/G+L4M]/;#Fn`\h7=+_LSkGMl*B!1dc/Q@/m/_f).Ujtasqg'YB/8Wp!Udn!0J539MtGAc?(fN\0;KGZbW+$8q1'F:/(<:C[F17%]#nrs;.\!!i^6k(l`0aor-2.au\5=2/,rnj"pC#$SM9 %O615Bf>P@,O&Qd5$l49ljM/PVJ3BPJBcA2J5L`Us)kMln=\M7d?lq]R1f/tg$9=C^%>e*#YCUedX\C'/Y5LDU5nL\L %'?&=-li^imJAaShQqPfqT\qPCm"..2i@RCg%]XbMBO(E`E7L@,1n*uZ'!Gom)guRfTgB1LAuNnt7DG0_$5D@q$s3`j %eeH\Q]C\1P%L:lfo]/J\a[cO`1_Lb/:Fcqs*COBt?PX-%/Kg,686Q@WYkAYRN$9QIB,HC`#-&Q`b_@:+9+]n`+WU2&.H;5?,Crc5 %$ru/22Ur8ROuH#:`usm\_s1Bn,A&-TBdQT0!+J$Ffn#ZX,\q\([SN_J\/ps&6oJ@>C?4LI)iH/b)3?*'^f` %%X#NN13CUM>j0Pt'\?PULR-;\-Oq0FlU-I"m*HpSlCgTA!MMl,?0KY>#>YsnUq#iir$#&s>"4qo5%ONbS]_=a$m3p`_M9&^m4[+S':MM#=gaU:qWH"qXZ1iZ/=JU-]W60Ru^Uf`=JuUi/^&;3X.,,CkSKRLK9cBjC]NQbe.9!$X>K5%t!o86cRH %HNT'JL")4abC'CZ^4t[8Fl.3>;7o,D.*W_)^&XndbBj>I2U$CP+PMDI,)KfZ>6..WEs%4p8=:>\jH]e?-%KY8+M%Xibmtp@n0EP* %F&5XS5bp/*$;CSXe7SssiAHu*&F%LM+B%M,Lt)8$,0J.l-\*VK%j7$7Z.g?c'Pd\Gig:XcGO#6UdHQ4??JM"j68X'B5t#F(&.rk' %(dnK@A(K9F7AM5e."q8#@N\O:+%S6a*(,SB*_-i+JTpJo8T[`ROeb^"i^b7HV*t2O,0at[8>>UaO[O2+,`tsi,)P)3MmH^t-7h%UW[9%"_d#[h9Q$:;I6NcZ>Q3*m_SRYD5*S(M$\nkj]Us&3e^9qmJeo]UHGlhH=&TFU& %YC3=jXr1Ss+u\pq]=-Oq>,SD_!(XdF6iZaRa8bqp&B[HZ"'*KAp>Z2922Fhn!$c@]W'sd$L_u@"]/B"hV#(u4K3!C@]qkXd]W3N9N:!FsS9MRIVA9GUVl^)Vh %'U9/:Nckp]#&p+%?Z:K]YU@3#h5[OLp"@I3l1Y:'qntd3c\:3W4>]aV#\pZ4pjrZgaA8l^'a6u*lRq:1K$2J+C1Z!;V:tGbDpUj% %O4)HL;cEkhK&9qGki0mj>0r'=TQd1;""H^)i!f:I,[AcL%RIFP=;$C2XQ/lE(mrC[9LUlt8J9MR=g7s_=m-0_gA1lE9Rrq*7054QC,#=,YfI1$BP]`*le8Y,*+C+W8;C+'-FlpCA>WEQbZe!=\[g %=4^N#7DMPIOo37@i\:OZMU\SU*'D/O/`r,@r&t0^X[\t7qnA-jb*6AdJ.#6ehjJL&;U(u9`*!M$L3fdr'g#8"%+81Tr@ %@OC4?]M7&.@b_29M8*j?qeoG;@XDTp-ee?-U!sRdh4_php3EY9HP_//q^gtKj %03FBc+5PHl@Lq6q8$^_2)0A0=h&dA[EQP;9,B6N0IOmI@30$Er*eRd?'_<5XOH,^u13A`lKVGlm,8>OF_MYa!.N3(_;n6_jRfaRK %QYu$EQB.$S-?32D_4Y&HGnr;jQJ;k"(UHd %;6Q]7a_Hs&nGB/V@kW)r]a4:W-;N+mNr(_*bcB#kb$HID8CO'epk846O@IS(C1UcR9ASVDK4R1Lnk+i!XB2UEdJDU6Q>g"YE]_p-"*`i=&df\Pk0pmo`ti[)"J?\baP4Q %+?jH"Wl1_H#9R0JP8)Rp71X&S=`gp3i21Fj7,?[CWS)/R)'7erXdRIW=OWe)#*@6*i7^LO($$#V-kuk/:c/EK6)uqZo>$0SL_T:K %c\-1&%.'L__@VaLkmUfH,+qDRg\g`g*JV,-mC?9>d>l,l'=9U#MuWcV8>9I7OH1f/K5aj %5f"8%2E\i]>&\IE=V#FV!2TuUQZ*)TR,3$P_c?h/Ild/W*9d6gHbfo],o"UYPrB%`@M]HGGEPNg0h %$(r,RNm&_oO%L,g_Ji#>Ia9F"A[#+TAHP/i.&gk\!Q_=*10L&T3KBL>.@bRYRt;*\?#jKR4_=`+?idsh0XAQ4m'b[`8Wqq+!]9Y/ %QJBg=J[C3KO[[1j(R*nPRs]UE$6BJ`aUtSem`,=qGi67J'hF8s,[#"_-nN?oIMp!JYVeDe:.)*X_;N_)mM^KJ.U.esr]`'nU$EP- %%*r;p$L9p1c),UN7JK53f&>kg7m3A(.N$1"'Z%lKGi(%+f?Ba`[t3!>4"HBV7aTUi8(AXJBej=N=>1Jab<G4Krs-a.$(N*86)#P'tHdJT#qam[/D39o1! %*72k?Z]Q?Pid_sh1)k*HLSGfDo8#[CB+FbB)4ZJg)s=+`S,p\#\$Pg)^hs8\PN/SJ#fZ3+\Hh!J*-P/QPIN"1BuM[khT9Ic4K0Dh,40*X1N_32rsL:Ti'JrCdceunQ_3J$!/#ZW@,j=&"*G"R %9FYZE#F#<[UCt8Ja@$NaS^SHj$#8D^XKl@D]]@u99c<]#r+Lpkjs3h%j&*Rt&('E[XNlD#?P*T2p`LJ_1AGhWUCnK^C_[:bnAqNl %"sL6&R!o&@atG"mJG@;'`(2Gu,[IVF$.pQ.(+1%XMKCHN3ruMGc>*,?K74j?<7VMm%1E/>nDB_TJ)GV33%>!"i@]I"bQ2KWmA&QO %VKhuY[M#a?,T`49V^ukN)Q7EW_&jA^#V<`kOg"!*=FcM(a@I@H/\,T3>p1OLULPo9lr7kJ`dL1("J]qm4)"h#WFRgT:E?N,g]U06 %_CbK/]qt3hBWs0e4GgKHOt]`Q>b>O>>[^lFk8j29lLu#SD.I20lh`fe!?%2mXFMJL0Bc+rE/mE^W"mV)\q@;b&;q'5H,5m:+]H!" %6-Ldti*8E$)\9JUaGE#EJjII%QQY`)A2IN^Bi#KIROpua;K8*pNd3U*9TN?R&uX(!6e7:p*QQdQ5pHTHABbk2q@*Q'!'-W,SKk`6 %m\:F7HY+"T'2qR:;?A0cIG5BIG!L-hJ8VnW"a`th1'fe.P07jr#u6Uu._Z7[S-SYGT8NV$-;Lb.3+ECCOGetE(1Nl-I85;Y3F?2t %;7r%6\N.i@D_3Ic$'Wi]7!S]4!:f)1'@/PbA-\Vlb^F?XC;Q\I3bWPJ,n]% %4G5arjt:1>p5*Ji+i4TpJRH?MK;?>t[,t;+c;>IcSNtIC5_\;_4a,>mRA3+*[&=$r*F^derY=`Rc0CgC]S=Eu,$&kP"Yb5&&^[d8 %NRkbu"oOI!Oj_"aocu;rnF<5qYM)*JNK)Wj$.e2f9]Oi2SnWaK,Pj/M4KrmfE*IYV#@p6[aB5g_cIM %AqCPf0=V9Ef2taiqAD8BGmm8ei?1G;'SnYn`+XpI7^M#0.4')K%Ji)'f]r9_1,HHj>$8QaJYF0HDj<^406qR*\09G]%IjY._LMb( %-jM1HfMmsJBI19;#j@ca?GHc0Z,#mDG[6E#P3!/73+EQ"mgFstXAl]HLtdS^.M,mrmSdN:'U]b'Tc6h%$i0'F,^Ck(;"X//;'G%^ %iiMmAEr'b;W//euodGSIn*eI_c0n$m[XUO;[d<<#jf9Gs[WRtoYa0OpC_R@Gj0SX_fmE2,oPp^Wpq6^rJ_l:mf_!NPTnZN;9IJ=, %fQ269pg*bIaTVc)R!c5QbN#pAZXCtOdELf11QocIKpJYkVfI/&a16D]^l(Lmjr'cIjBh08LER2cOLp7+'3Z*i]rPJF^BXn%hFf>D %4qOI-Q=<@IMZQh5C5V %SqX@""kh(=ETN2YVJbjh&:XQI@)RC;jT)dgFCZaqp4kTdUN[q`N\BFJTDT!->a5EV!eJk+8amN.$;'T>^W\,A3*?k7lT:2YRMOV7 %SOkF@N$5bHF_2BZ[dn@("6V^DG4m)^l516VA#T5lg%I_q8c#WZ+P5YYj[7a'T-S^4*?4u0SYg;m'`IM0gt,Bkm^XE83d132s"cti %hc]LSG;(4,h3+i.:#!aq+QMT"9$uu!c>8<$[38FW6Nm/;B$'Yk!eckK8!8dd-U7Wk0(adB!qV\`iEY&.L;+B1Il%;ZXV:2J!J*%, %0HoY3+bt"g#)=M5-Yec;0m!DN,c#%*UQbc@[o]0o#IsM.9C1j]4f<2d)4%f-O5H1NX>C!XB6aQ#KZ$&@_X#eJX%4,l'2"`bS44s6 %`4DUaq^E-=r]*Fq?Db6t?B2,Eb:W?+#0V.C*=:h4W9Kq];Y2`Mi)N^l.IM&ia$pE&[7RmYEoh!Jj3E8sS*>oF.Bjc%M$kjr0i&AkLMBi0n@HJ**31Q7&i'$L6_X1G0W<#1\I+*k:#I`6khXm_p;.XI2oYd2kMW\I0OY %K(FkqN_MbY5Q#LMi@XV`Vh=I]+*$sfOO?%'M9!M>7PThnL@0Kmmf^0_ %ou/!MXn=nKK:S$LkF+TRm^H,CQ!#i*&I[TfiJ;V]^8L.3VO>D4#*cljc3A[>p3OFAJN.AMoBL,+1#VYK;h2'%KX?0c@XFN?LdZ-s %m&mcE;>V\&FaDgYOcXj=j./ogcjc4B&m\gH?"PTILIRd1ah;n=8NL.m2KKE4aFq=/no;8_(;\ddj*!XOS\lqTte %_bP4$+i$H.aU&jb'DeP$KM:^r>DUN`br<"\6\B!R::j:G;VJ-0i %q,+O>J**7&5m%69=KBB2\NKe:_i&j9\"3B\$t*6\dHQ(Id2;d_Q:W:]QS=g1OiMAaPJ/k\Ulh,uJ.CL)^m\md4kG4rb(Y+)^56(^ %U"55Ab\qo#78G@E3u^`&JbFK]&H[Aee6'F:+EH^h[m$r40+YaB"e`Ac'>%SK[nFfX,+"*,onl^IB@rd!=Ak()C3Y$r(E#`h+7i33 %jnlj_iGf$M0YUPf4BH\.!32iIn,,SADoR1"uLGOcr!/# %%37P,oM2npmn4ajV`OU&#CQi>*>Si)U6fGY3$]E"+FE@7h$IrFO\Z76Ur#9%0$2-gjoFY3mlh0>6k?cc.-L17WUGU %X3k1s)*63q2-9DD5]N5"Bdg-X\;&u]MJFVhNfGsipJ2WVe'K4BK5_::2$heV>Qu2T%37Q\t+F8A7Z)(q$o[)r@X`AJ@]:g?BXF*.?UWmVPpEGlCWDgKs3fBd7jDB3E7LI_+t`Pl<$h6G1Ac$Gf&#-c([lk?`F %nI4,IkkNl!:+.HP#NCb-\&K>&*pnS9"WP#H7kq>#=k[77Ts;7h$IrFM*-as-!U-%93@% %TW5-3BqVJWWYTVikU;4Hg=tF?FO\Z76UqS+jjj,/bG!r\ %TNm,HZuQTb_DMVN+C'P<3HVo7Y48t\oL\&Lp5VlW`AJ@]:g?A-3HWbWS>N!TL5m05C?R($NnP\[L5m05C?VUiUDu=X)EMWsW1fu@ %NZ't$TVJrBUnOQ_?uUFOUdMB]uCgUP=dI3m+.kG#1Il7h$IrFO\Z7%NVt/@r(;,Tqd@&)EOIb,9>-?7h$IrFO\Z76Us.Y]QVBH %:J`;t*_#qi+:U8ha8h&%!pFl..#8@,;<#??f'\[o,6o-ECFH?Z\;'#6kc"G`JVK1'3bmlWTq`Sg#-YtTF9!QD0n5&j;*bhC^^("5 %LC.HLjVPH,P@E:>s4["F^IOu#cqjTCgrBhH9.X)SYo]\%$/TU.BIEPBCIB\m9130Q=_/3Ge>'aoH8+ArdoZ\ %W2LAj?OU?YZ__c(I]dj-;UFDK*cH6PB?C/T=HC7LU2ZQSW?+MA1egQX!i161O;W(ocMW6#6]Sp'h1PJYi'NS!s-jV;5@rYGI@/44 %0Gj,nI"Pk(iN\IC#ADfSp\XQ4K,*pLZ. %Rf,T>oL-J:Jm1&t$3oWY5::RJD>nrdDu%&;![5=IjTtcp3TC'"PeMaMb^Qh_?J0D3C#1\sQiA=2Wub>ELUACcU%dngQt1DsjXn+X %J61Urf;gq?>0g4_O,(?;)M*04B,78uDM1ilhH.t'rNus'7\LBTC"Ipcp@O..oX_1h\4pH+a6@D!ih'.T2[+!tpnuTt66S)u%-inb %&KYWJ;u5Wi-p0iT+gfpLGa8]prnoM`LF8]a$b/1;4\QGEKr21%kn`J&4bX[+q1f#2*BO0/(n:knU!W>9\G0n:G=Hg6(aLO;mR5N' %#cD4Pb,L#C1ptsD![XdA#_V.G!qB]pXn/;dLR$8El,o@2*'+LgP5RJ`Dn6isO.0^U^prN_gDA.tn.hC4Q"k9J@DJ&-S6ULdNBKi4o]qo5S2h#F3U-\q.j5QjV9kRYJ=YA82!3r5"!iUX=OoP\Ra;9Z8;/d#@e27;OMrtQd^Z4oTFPCiLXO!fa9DJ:t`(*-s3nVXS)<5taY/ %JJcK/*KfPg5arE=Qj?qV#D<]qTO:1[Z2?-VoBROQ&$)u*&AT!GAB@.HX*Fih"F!#G"kntb%^/D*OuhDMI]I#b6eW3s*Ac.Cn[/rlm%V% %^%JdGf[3`l>YPtVHTE@frUVM4f[Xoc*k=/7j'4Bn=OHLJ!H+?)'STp6UhV'C"'1KoER#8c.k^FEa),Ku"LMAfG.?qH0+8+p";65e %'bHJ!$BR+85lm'f+TDgS/ra6LY_j8B"b'32E("Cs94;-lMkGC^$"))j_nQcR"De,oJfd9@KUkq)q>m>nI#K2PFo$Y:9HYlTM&,k: %bkYK#G]@[q!V4mlJNOQ2/ccSNMMmOGY)e_\>2\c>"&GUYIpBE=E:rXi1E-(#dn$kV@5?Qj.iq?&/=_LP+Y&-,gCBp*>LO6dgLF,/s&B&-GAZ*3^[@JI%[50B*_] %i8JAnINUWHJgGC;)05HCBg`0F9d6\ATi'mmg583p*=0_5eKTL5g-\^8`%aOhpX;Ym\24ZS#SM+7j;ES/T"$cL7j*G^"n`E-q"c,o %$>Co!a:(L9a5J6*aEcg1-N&*BFKeT3UKLBLMgiOshI3ff\dYOLhf&sXk`2lX=IF#Md\Y;`a&'b2VkXo*kN>&_Q3j'5=s=HZY$9&- %"NS#VXl#KDo`C2NK@I^1]??'nA8$1Xs7fj&.F%J)5.;.^;LCL%rdk+E/@r)"O,*po+C$o %/XQmh!]0W-_93j48h+spmIAbn=V(4!?pY`Ca65)C52j+;N4qkA$fLcWC?9n-*6I&rkjACU/lpo=LY;(I=b"3H:61%)SCRQk8GiI9 %8ZT[L[MZ;8p8Esi(-oA;s6P3lN4?KClY?=r)oHP<%R&Si"d2&eqATNZcaAJY[gMM'b`ZnaF0[t*p(*G6C:tOb&BnSm/:=Bc1."Y. %?TYFiCc)?Si[VqPN2&8ah4m8@+.oq5&#oRF-%TEfKW=RgR/UQj`pg0Hoq+(g_nW1BlEKM[Csd3HKDfu&?N.?'p?1+;Gg!nIAE`X# %'N8e-J,6eX]_makq)?OGmJ&nq@rM8]:P8%D2Ya1[0uuq=Ui;hnBqWoe8g%*s=(qE],-\(5rF\#Va',[,M/W1@%`q)u62K;sITJ=q %huE8@:]V3D2O+6A6Bf01.,ro@V.'#J+OaW5oX`&f5dmV'<9MU*%9u*6]%22R%Rqml.eGCgq7nfbeLW7A4(\abTO6e*oS\*aLA[Km %)XEPCL0(<=J.1rG-]9-2_s[A:L)oOalc#=Cj8-LBO*DX'=i>\L.H3T*Qo&:$^`Bh^L2'Npne[FJq %n0VnJ8^a(MlVZ#Sc4_K %T-?6D*^ed<_r6H'/Puu*dA?5B]fWdC/7q"FdXoJnS!fVT,ePH*aG^k38[>9jmWWGDrTA5EUu*jF_#JSdgb5%I8Vfj#>)Yp<#ihJn %>f@GCFVMCUD$69'RFQ6"[O#s6(-Wd"JC\C2@!:I25\7kL1L"s&c;fZP/*d5BJ/XNXPr<?U2l(Wji/7Up=I'=fF;*6'hmXAPE$\lOU68])o7l#keV5+e_gd%K>hX/e-^9Xs+36j %!M\8=,GX$*G$mZ-P7%&20eXlA8+U7G[pLZhX6>LE.!'A%fT)YBn^@k0f%;ctB'UsPOZ97ATB+AqM*7E$Bg3MI8AA=M"K.locm[LM %FP&i!'G,RE[k:@(WD$1D1_aPj(M6Sq9W?$.;f9&?3h33J8#h_u)6UBOqkIe)6f.4#_#'6ei#[Kj*V;phHO.INksK440O&IpPl]K= %=U=2-CV27,UshUZ/$>:T@<'P1Pns,DF`C\A5*;Z0&GGr)m*H-BE5?A';hqr-^E*20BsZ&p3VS+ZWP9#"j[!0bmC8FpnSE1\T:Ik< %>k`HHA;BX,9*F=C6qrH31";U:f2Q:&"2+)=2-sX(`_*6IXu&QWW6_^&$_g#uq[f(Fj0")q`CDC\4>cVNijVh4KM)`NRFp&?u3Q/&**lk=PGIZ;0j0e*sAC\Bd6GNeMZb:/j>;&5ekakhJWFU=I[J]L5bH`Ko)Sq26 %bK4HkKm&+A$J(mkS=uI?%dc6jY=t'!ZJ4F8NQZ#B2%s6cG,sEi@-JE#Lr&ZV\T5`RL23sC>o>@nn'#Mm"KrVFE=d5S^EptuG^&f< %D0bf8UHWW=+Scr@hs@Jc>5c^>s,D!=GCnIR+!?T*mfPrXUY0C+_2:/;,T0P@Z4,#p]#s-KX`E(DE8:+r*#-^/UE\gIGB&Gi(%AauK-A^_-EGOIJL0qir5!-'NYYl5ZbW9d?j)eW %'b>`4PSoK`8HpNrlI`4pJa!KLT-daIpqN25PSj]8esjL03!hIp?5P_<0\i^dlVF+a4EEMaZX4.EdekOOLss)`CcGVqWp;hK@&4o0 %a9LOC$$\GP)U:CtmM5l:U6P&N%t^qZAdA;g1u/S6XY3_T=kHukK!_c-?Fu*Pud&SP,&528qm5+A\H$JU;b:5e7$==A-J!ej9F0W9lV!?jCagu!oMLT)2h"rP0MLl+j[UGVs\IHkWW6oNB3PZkK6@/9b`b+nH/2/]`Stp=mC %H$iGFbX%!KRG<.3 %]ikrDm!:[D-\]+K5,[^)Z@;\JV,Oq&$.qDMo`CJ`=1^M[Ld98OlbuO'(hM04JUQt"6@$#Nkin-c%:;_\YdHFn)P<"%i`*ZP\ %OQOCF'81sK+%CR_KOokUYKX'3om!FEF=M,",sg\AB6G$PpCV`a)6Z_#h?[,4LTEesVO."QFA$#,B!$=R %KI&9$jpqFRT\o2k-@o7-!#=jO@pQB/as0I8.RLV\/87[7ZS,u%AV!Z9D4..IEeDYr[Qq1Copf!].l\-(m"JGGGm+&BIo.q[e!VPJfjBl1bBe,SU*m6ejDMR3W9W@WTf;Mjn/Y"2O2AeF1UNs1(>(,dnp$n*A2&o+.?ri;2 %p/fIS_9:9`ScX;f1G"o8dug5/UsK3WLCglDs(=Arl*nlTd(G_\H=a)Y4sn5(d-9b^/\K-;m14:cSp'\i+1?tXpq&tU*Kg;K^"70f %4KJcY52n7.0u;8-^c*jj*d&m*@$4$VIn,k_(Oa`&Yiu.fI6'(sScX\c"%?Mq"0=Lbo'QRD_A^DXID#3"`E"9faMmMH[I;#s@_LJQU#rMa %"6?c@#i6/(Vr/J[25J48mkcg0SM!KMR$Fo69]H&h=V?h5MCnW`9.r;^PaVn-C9j*W(5%/H85k<5KnC.n_3!K.lD<"BiAhr,1VR$9 %'Zi'F2O8*;X/64A\MkAX8'GB6(Rg2"/[5].En.W`K!je?1hY'72LkYpLV_pDa;>=\S'bWJQ]*su0MomBr]'fdoO8pUCnlf=%qZT+ %D("T9A-"kr)W6Z2Qqo"tH,Pbd$L\34SaMgHI'D;NfBgPN=Fsm)k\H%a7df3d)V;Lt1'ke$"8"GgClfV*_/=q5UWHpBEst5m@dn/; %B?Ao@8N6G2KT1r8]OcOfJktf]piJDWgU;P".q1>snMWO7nA0aP]=IQirISAui)`_J,Q;80*uOJp'M&hb5)[.LZ%N*i<+(!]T1b6W %Ys50'C,=-.gR']3c0UX#Z?#+R;a*u?g&B]/EnQ\@!4'%WZ[Hoi2)DZU/=H(#llhK7@?NYZ'##l11/*NuOfT05o4o3?khs]Mrig:a %CkABRZO,1U4MMG1K.#cM0&nQM+$'f-Mc:+MpFt`pkFB;+(F=:M/.df_#j(E!7i0"ji,T,4doPmfbO_.Keej.qWP*pG`TD_U)Hf_5 %dCK^KDtdR#T6bs#-C_n7CF\X+q&qtGn)UP4b/EJJXEFL&bbsSO'iMi=E'^YN0^eg#o*?@Z@,)K2-_. %.th3]C'@C\h$n%![Z\8#8Fq<"`ui$@WGHOmG:_!3BN5Be>OKEZ4duk(3X`WKMgGJ.hU1#CEA!L^hg`q"jg!!)0447)'5jh4ijM\, %p+c;*=ai8gJL3Te.8Qo4ROJ`)2Ou/%81_j3,%0ZaZu8#QPO+ru]B5e>S0#[>$1qJ*-X1r8e,E %C,LI?;GNR.+<18YO&m!"@hK-T,S)k?#GfALB\;[.HDf.hO,ZC_>>hr?Ec-F9'?>Lj_tHqTM/ %UhOI"OS]:*&?nVs#0LfJ)//r=2$=RmdLaRs$\n/'TkB/i#!bP1R.ZS"`8d\_iNG5Z1%BFqfF4")-+*O3`nJMFNhNA8An\&LY2tiT2kAd:g(hXA0^s]US)E7=s&bNB84]!J8M`%!*rk#/O %1$_&m4>!R@_TCu6.:=H-VVmWjR\CmdYpn)uHnf4#9/TYAL#l!na*Gm.Ir"gRmE_0?oPAR#9\n(8BO^68CDooN9@G7crmY(EX(HZm %g00[RZa"[42V[$OM:pG&:X*";r+QWX*gYs8g\[]i16bY@giAq'B,oB%u=Vf$+`VH+V2G+5=JSZcd\I %L<)QUZWO;)pD&U%DgShKpWUcHm?0(po\LLqUp+j^P+OY0Q>/GBYdA(^_X_Nu4^!)hq3P[f3MS-tmiQ\qAis1!%7A-R[EXI9X4Or< %=T,T]@L^rZ=)292[-K9o4OklbX&&>P[;C',X=oQ\ho]=_^ND:=]NSC)8$@((EBMsVgII=L1\*]^r11"B(261nCoR!ZD_'CB6X0L@ %IV4"tff-@rITj.=WFqQ7=Xh)>G4WWm^cu$cB!?X&TdMo:U;HWVB5hM0js!Up.R6FLHe#FUhqj`OI9>3&m#)QIflsF$d:#\-"qG"o %$k!!Wgig)hA,s0B7Vn#S.4eQEB^Qr4_K8\]K,/]m]1E< %IXcK#*0[O`#d3&jOb0k,b'[T,f=a8PE'76o=;PK&>$R]MT\$S-2JJ`$D1=L@gdJ;imuD_FYO:a82fmRT>Eerp>:86Z%l3HWp?.JX %j/P9:GV!j$LCSZoT&fk%USkaAY0%2I'rI(oY!AOH9P_m!T-tlf>m7OA/$719QTPQ^uV`JY&;*;PKY9&Dib!9"o?1i7=.I9_=;l-&!++<;nU1ZNq4*Q8&,AdkMdqMJ5_,k[\#+c,:pi8H1b3;UU;*k,T5iknX(=d<2hPpLk^7`2,cW8cqk,7F)A!dAt/DhsB %d@E6OVhaWm8T0C2[o@.(_.]OH$'s$hJ++a*\I[!.M9h9_Q68N4W*Bk0XIW(aOe"s/+!WS/n%kqam$p3t_Vq$4!&3^k++>8*2rRn$ %QI/hZk42t%nYbuh81%j$7bX8J,r0j!fciK^H]2EW;]qN"J'Oe]l(Al)Jo?\5fD+GPk.,h6a5YC<,BhC,#I4#`\K'@g!bC)W0=11N %VVdBjQ^u+jqb%Z;5JEP&XEP^]H@?[FB=iAq9r3Vt2J/D` %7H^;B:h.76PrBPLlD='Ke:o!RFI'<.hFXT.6m\FBm<5>u\=`5#bYS+EL9B?N1SpPlS*<+3PF9Zc[?^Dfj0NPOk]C>Wh@.Nmbdi,H %fcEAe\VP/Bb2&-@&%R.+\'5l/N`\L'$23pYa$&W4hmElmq(J(e/RY8m\r`nto>8s5)_Wb5Mb2=P0#rlALZ>`9n2a)V5=9_)jOb.? %V>/-m.^e!ZDJ@fB`QRu/la@d[l#k,k`MjL?1_ZRT;8crpQ#@( %rV\MJQDo/1\O\=$_hd$IEUU&YA`pK_0kF&Oin`A'rk@^c)M[[)h[&Aq`^VOj\*,B&Z&.B4kYhl&'dJ]oT4ANLEBi+M8fYPNm'S9?4?:%Vt"M7Cs@Dm3`7QEcLR?mN#s*JJemAk4-!sGW'^7M %WTLKVSgO'oi7[d3VOo[#L]2AhPmG)@R+_6\4K[DP[,'^6b;/C^]].tRo3fB!h0gh>?]'I4s;oqL.iiFaZ7I`Vi;QL!Mu0YIagF0)"1i]0thEGtHLibe@1toHVV,^#']Nl@%7:D[qBn %]8k/lBPm:k_7El^L6R&U3G]*XG.?nO3_')]()YS30<*>C*GLPU_Ui1#H[OP.kMl\*+UPG6WO8hrPPKB=R$*G/A6S^Z44D0=AS;!$ %7qC1q#f"YcpD"6fIT#i)n[%oN>(1?9`Rm:`>n#ne9Tkuc5<$e1RV`0Dc[1&H1d3MOb=&_F>kWtYBk=W+CoaWHIp3A0=D[B%]t8Ed %5X)?KrHNEO?o?E1hKo4SXBgRDcLM_JL^1X8MitCsnG;\]e/,C*h7@5HHM6thrW=5IcD"M5c&\L^Se>!ROT_Q[n>1Ga#\k!Z$.FXEjNbr2gY'0_s5&ZHULTi#NjRM6[*7+=G9JV5C7aEYD, %a]V]1iA9\YcK$NbqB`o"I!/Hf(QTMG9U.2kh/;M8;l4sqj#93"4r:XtSL$)38psiOAi_cG4,qk$A392G.!I.X([`WEo3=3dhKkNk %N8(Yag%3+dc@U_7qfo=31ZRmJ%5XiYn2N;]V5NqnIO'paCM&)u^(O9S9Q>.SbM.,WdT_?"ehc,7-Lp;oqMq??\=,U0'68B[u' %Vjg5[#.C?Y%N1`V-%'-+Uc?G[[N-JKg,>ZI8Sf68V0rd!04'Xk4ml0^6._IY#bEQ47(O3m4_END!(bTp`E11rVpjt'/(tlT %L5EXDMo`n>(,2C@jYT8g]Maei@g1s.:X'oELH!K'Y_(h>;`3TFU=PjNotnRP.!VMBW1YIu$e@6PrTLRJ";D&GK+1*[+h42njJZS\I4:E %@L_g1)rTA8GEt@Ve%Q\t=33oukk9C4EC>#(*IaSW`pGmp3>@5QoZIVZKF6RZn %LuIIp0UEh5T+Q=jkTHL$:pJ%CD/*,QcEbeT`D1[)=TB85=scJCN'LI(-sDPF`o4u23ObpR#2k\lQerYWTo^ea^H[iOUps]ke$JG# %JnXCoXV21CZ#CO[A/)I)_+\`-TQsOCZ-l9:k]HA"E/XpD/JVoIpHDh/>9B]#D\f\B3!*SoJP*AOlUdi"/i'tRYjnNq6sWpg9bbVp %lX&H^3@bhn!]o4oZ@ht>1 %%qt*Gmgd5L%0L#+C':D5TRV!Kf06i35OpXoVk(V[k1Oj`82$Me3&$F;KsKi`pKJ %gXUs'[4#HiW2nOfr1nsh1T*Ibl20[jU"[H^]n[kI241_'_q[oFq/dn`5K/21j"YB"&)Z>`HhpLM#""g>B=O8k)Z6%UTU81ZU9@Os %68[WV(j]BP+:YNN3)[ks-V"D(R3qJ'ZH9s1;1Qcm3P:Fc]1Tn/pBN`a0S0JK0U5S+ji4#CX;Elo1iie>`"$:3NGEQ$4di91M^ZHpaY6/O %KTA^[*HRE.4H&X!FNWq20^g8&F/7@]_.lhW.#FbDZf@VnC.uE."gpj=U1O+Hq>HP/J^EL*`:8hmK#3#Z`moZCRnFi6"/o %8N7lM$;RoQBff_E0JVM&(Z9mNP10mNJV9kiU21tEF1`u7;fq)sP"UsZEs^q/`rg@U"@6Z,Y"KV&osi'A9_n,"0C:(Y5"[_7XbUG& %='T?C'qbI"mNRu'=Z/TEd<$@k0eo.jcNq9"q%-0j,lrc%6?7hBI;uQ;DV6\SKDkTP(>s/Qn1H[5b-&>p0a#r^##Xi>OK73Q+F8(u&59&#=_%o>LW&R0D[df)t$#M8sVVFjM8k+!=C\g!WgNF4rR2a25KlNobAIMp-b*HZOs1 %(uUc\#PA-25Nn=g_8V$6BCicU8f1Dt.]dX8c4:S]?b7K\BQCEFR;h[CX_uWpmC7Qm".lu;J3_d0OCB$S%6H^LTrM\K;HO\DU8h&;h-briUQhPlZ^ON[;)u$I00&mcU %2\*jA[USlVhlgOTEdr/OO\aRKLmL-K97$GH#eT*lpNOHZ\mD$qD`K\Y\j0q9+!9W](p:7<;KF$o38>&]!jM05\\OjO\VJU^3NRCS %N)->>TC/,*PjYAHGN3PMmQ/RYcp=-r7*?P!H@CC]%nSWLDg.l5qbA*OD&R= %mi/p3Lcj>&P!q,MYV8Pdqtas2rP1OJ%`/T)pQcp&2[,7ucDM$e3_O.K>E>%#"rCLPL"Rt&VK2BndM9aEo+rXMUc$WqO'5UtYCmKI %HRHUlF,p)@P03u7#Zpr7lTD)D,0Q=7X[m&BWq&>BncX8q;l+o^gDkOdfauP"[4,U'Q0+D;Jan"D?gCk7pCp1)o!FC(do#Q9b&b`^ %Qdm1Z(o+phOgh8aVQ)bju2OG;IbR(3nPH0--C'#$7iJg3-^Hame<#gLqX-Ge %FsR0e@ES3)W(JAkKX+@(4!aLt*@^=,i6pt$-,H")<%KLU_9:fmO)YeQTNnNt:@?NVb^ %nQ=QDjiQ3-+ih\V]O**##83b\Ke2,.;MuhZ#50g%U#P%bF!@mriTESggHiN'Q?9@9Ft,C:9u=eVs6I>>M^O.2?>R1ELmf^G)$Wkg %Ju0Y[\A)X4E36B1$BlUVR2)FoM:gbN'hk&i2;)dn^WUOA+_%2@"E5pPD?n*;6]TpJ4IL%6ktlF6npdI$ %@#ug2YmGLT$qup+Ss?o>L1_V:CNo4/M.h;.#`kjb0WPV=;/1"'Pu@Toj$P!`k-q<..3I[m;6bK*?n_-24\.fCC[&L,&o6\?9B_Tb %R(oF'U^/WI",S]Q1u.76ch1SLr/;.4S]8hH_p!';E_H-X!,$J*o!S;SJA3'0YpV&B]5P=n+ut!iR1)gImS15c^"UV32LYWYO/#9u9YL33F--uc %^o'PML%b#!FN]nDJq"/bW5n4cm0,DRk2Be>)ebH^cf^[0T(Lc9%pAe_#gn#pC@!:#H_0Wk7WhNI=3J\B;%P/b++Xp_V/0V_GIm8:_[R7^F7hV'e9Z._2!?K[gg2[.&@^BLDGM$;UL %N/U)U%_i0;Poc_GPqGAX&\3_PGY$c=CeX-&2oBX\?I">%8k-8CGVd/TMe&m')0=IT5oD&LV(q`oM3JX,c'L+7&,lb*njl4f3mstW %PHFccEUHX)Co4_4D1UG6/HLV7.ecfJKTm^3=ub4=&uuKm-@'_A0h!e'p'n>+Fhr-q?/,5.bq^A0@qt868fY3GA!6'9mf!N+H7%=S %59VAAG@r.S%V>PJPZVmRJWRKg06h"1T:`4P.;.IT7Oe@$"Yq*[BhNJee7<8(!X/1.(TGa,H6Q9-2KkLOh4B8RTLEbU.(N`O-oB*7 %X@7cgF(l/Znak\H+rA)d@4Z146G%:d)pWZc+U:YF$HK"A%P,9UUF5Ya*t&?N#4:o.YJ8D3oS=g#0iHe#J!$0tCm:*u5Fgo,*%]b? %'f^srHY.*MR&F;9(X'KF]Y:.IAj,kkBOgA(_`_'/mK^9tog1]?,R=\R9[[jcX[Dknfp<-0[l\hN!!IC4jsdQX4;fs:;YM[tMY;u6 %KqXn6_[g#EGQZmabt!Kb265H/iNj\h>SRUVpKcC79@u`$j39Oj9b\(GKZ'Mn>][b<%>+T7q>ZX+fpm5JC9pq]6;mp?c %lgCW8^/#?a_r<3[(@]"U1E`stQa;q@5E2+>[`&XMkP*4+_FS\C-qIZD%_kaU!s%c2R4,L@\-&GN*J!AEiQ8gFhYjej:ZL!$6;=(/N2J'!g8nl.PkCT?"iInG5[kbqG\$/%_)%Vn"uF&^GpfMmDC.K[d7C? %lih/.Z5k.FV+C%1h$K^47ASDXY#!jH0qFBtA=Bj@?16\`b9DKHPu"Qt[Q\rIUR(/iSk[Yhl2q$>92)70)#mGOh#Qt`2.t*:EeU?W %(4cVQdHo,B>c*%YkJb`:*VA/TG`(FA\DsbFNE3"QG8RMPO&ij(F<]0)m$$fnr=6-Y+ipm9*[\EmNcGBe3%C^e)+d6-%k2g)Cu^rO %Ue?5c^U6W-"C_?al9d9*Al18?UJNe*$@iW,Oh:m6W,l#3ZPkU]d,^;m]GBE5Ro=QXApC_7q;QE)^+u)/ZU4(C?qC_ %eH(cuk1Y[]V@-IaQS1B-3h1hYJc6it(n93BX8ZYQ56KM.b)][=bJn&jlsje[9_`eVN3A=b7PZX-<\ruHj5sUfoNk+59>4#-h"KKs %(>i2^5PC:"=EPC(VS*$.gl>@WfaW,J$1Aa(`C1qoF$VM2*ATpAR`KDt&(ug3?fjr=+q*1Me$jg/'lEb[?aE %8T\c#1Y3Vel:fL.ZSEY>\bDpK2dte3I&mu4)qhY#a6k.+HTo=[@ATFWd5IBHFbnn#DP\6rVb:ZR9!1JAZsBp`2.aDP2X2S=+bH

c0UjGa@b$_Sr)_FaMhVc[9(sm$*s(o+q-sUBWfl`@WY+'P3cSA$+d0INoGJb&t;' %\Z6d*:'4EV@scMDFfMbJPrRW*;.:_2eu^[Yo:$dZMi(c;=>!TK.!/(LbU_6V6_+9O4rp^(\VK:dpFZ29o7j1Y0>4i+43\Rt[To^k %$PG/`&oW8mDK0bTW^e9UeOW6'8KIt#CX+mf3(;k6?2V$V!V/r?$%Vc^+Vbpda,R4Rr0 %26G@WKB:o2*Oo$#1KJ!,9A2jYqH6k"4-TQ%n+>:C58!A?]g'Mp2u>MZM3uM0q\$jtZj2AW7aF+IN7LslnIV?lb]>hnb3KG1cm`P# %kJLP#B0#3Wlnj>pS_]BTVo>iYifh&ob')KrfZ97O;(m=+j\^rS'KU[8@'+X.;81M"@n'/&b7d9?UmCkk#b20N`M,/BNo0Gjd@*&m\9KF@pjT-dDX]Icif[PE(huj*7OW:=L_$Mq\WdMb1rm_*4CJ,j[@:dO?=9q'CPT %jZDjO]=,`S:3UobPEE`AG37>kFdm]sMoSZXB"&:j"7.jambWgB@AHcu$j[51MX0mE07.(0HN]&jNW5UA1o*.%/g#:PAm)"GJt8c6 %8'3/KCVbHuj@Q6l\d3\<;gc(5LA+*O`qAPjc+3BWo1g=4<-YY@emZP0cOG9T&NoX[r@(eBYj@XHSc\-#=;C7%-A0j6k2VoXkD2;h %(b1?V$[cmU_3:dre^XAiGaGQL_f(EVFd=0/Cjmeh%o/Oa:%<+aYeCM[moE\o4$o1!bl*!-*)V*pAfUFN$?q++CE`PYjmJ.G?_K94 %4h,)jGWNj(i=joUrDIF-GdilVbur#t3m4:pmkZBKIsfFm@u>Ip/3V^gGkZ8\h\63MakWM4Lf?b3l/b#Dmj[&rZ=u].-[-jLZ]k`F %r(6GC_5cCm.,D9LXMm,ria%Y&-`d3.ir'L0B>g)'-4PX]&QZC\-t(_qZR8?rClb+AGI8CE49"KO2gTMRrK2:NV0Dn+-D0S?A1m7h %VVt+IDL+'T_fnHo@ld7F<%reCB>J#1Zu>i+k_pTea`cG0Ld2=8N;9dgqeC,If%^(sCG.T!EbMYGO'pos;fI@NdsQhP9PGC"n&)TM %rp&.R:N^&so4ILhqrL!PrnK5:\lhe3k>69E6'HO+mB]q&du2P_i[945Ct(e\oX.(dB6%,5RJc% %&,-<,5[q%;r/Roe@ONJ4`g?`$'ue;HM002-#O-_e=!]Sc2I.[g;Sa0]SWlet,kg"m71;S"fD0/$8PElYUC_*Q>,&?!_H2RWKl;8G %f%fg,7_[=nLj;u_VR)dWkbrP5!XN^rWEFL5#LdoYTtk;m>&@H"k\U!H<\Uj4kKo^"iHL@@g7DY<_^Ca=o"c$@"3QuCmE-9u>W17, %n^6Y#i6)k]m9/:Cf^V)-S4tZ]"f24\'=do?GDgrW!O4])0BqsVWuEKk#2<0_2;`jm(^s3R9t3n^E=kG5_/B,mQjg1Y)uFRU:N)X\ %TV+n*2!>)&U&77u7&*cj6mF3 %pjNV:__(d.G81Qsb@b3Q$bF2Ge*Q1Y!l'5)XN)RA?6?.<:00P)T8rTiSh6_B?5k?k__Y@'.55BjkU\rt#`o$djd>)Z@;]+6`2Sn[ %'4JMjMQiHE61K@"TM>O$]k1ZLe%&J%B8Yes6)n5NcI?KeS)%W7"bpJe4.eOAYp!-T==iYHKZqJP7\"tb*:/\m+nk+J8X %<cW/f_*Jot_hoYd(6]uSqc$_Cgjjm!k0S"&/9=f2.1F/m8h-#Sli73&tM`aa9BXMVB468`g-,^mN0r#pA?Mi@G"R/I\7%WB\`KBF: %(YLTo;\?>7-*J/4IS18=Q?/&Fgd[ZY(8.UKbb+=^[)dHo-=dHk`gs_$G!3`*>h+<"5llSB>Rs)<&`=Oo5lmSRr>T_; %gn-#&:hPp^#P.k1(]RD(B*B0&-BYRYE`7QXUn3==rp4)bh@qd9;``CVQr+$XF"27kp&*p7Im#R.8`AI:.ci<5r$u/nBDL[4q6BF2 %SrMSOKZ:c?$(f\Y^2K92;IC,J9$VVhnq7 %EkKTE'SIR9-g@5=$P92ImAJB2]!+IJa+^&rUn#cj9hOP;^`C+NnWh)2JslJs18T9Hh0p5;KE3:LCZ8/mOTH\\8SqGBq9$l/?i9$I %ZD2P85g4Q'MU\KPqQi`LFkTik;k<#O[*%\k?XM[(DQ0RjbjHF.>ECku34X:>]VTMo>[U<,FE)s"j;5<#h)3_J6l`#L8So#"m)5U$`'5`I-!"ZJ#pF0ec+r-:c8J8Nn?3\^gaYo?d3"d\#Ze?[$]-7CXG %_@\39i270'qC4bWhDG.[8=u'Nm_DDqCB!g-e[*K0#qTIVa %BV]^)?(SS0/Y=sOVQf>!6tpV8Ge1tjf!(32%g(%*E)cqm&>;-$;j!rmOZoD?M9PBchO^rV>3CZNrL&VG9(3,EdhSJXm" %@Lqb:VD*^$-E]=bhq?1g%_h2]'g#d]3tmNs%MhsTLq7=M*p=W7qdEju(YjAim_eT0m9m.LHAVr/j!]R$E)f1Cq5SLXKMNG)P9/Ij%4G4-$(F %^[csV^H%)1f4!ackBq%Tos\TE?/2crD%6T(8os3N=inp^6gZU*BkR=W_(rP>Gh1!P@UE,_*LY1sI1)G'rDg7>IaMT\d;.!I+`jBE %CWGboKPtKrkLt.P1O=mXjs:u>JnnI@Sam9=l'/CU3ZN8ik9T%Tk`[m:E^)6' %9REVIhI$Au)sR#l3"%5Yji`ZkYLiG2aYAQc&l6Z1LH\^La6cjd.W^ir;O^[S_u@A*HQVOq %N]eNlF2hjB2>]0()PTuL(5^2JW;W44l(MqbV#EG@-k\V'Jo=M44ck9GK'1))ri@ %+:f*;Y@$jCqU^Pbc'/RLi4GARf-Id6hD_$*&2UteW/#/W]J"J.8IW<;VCc;9B%S^c<[!r.9Ycd>)(lGar&G[!Y#P\rt+[/PVN!m?ccB+(?[QQq2OOML=DaMeKAV]Qfnee[T&op+56 %R6h/?;TE\i'>qN8X6%9d%`2Ap$=kpRIcA&,2%n?0L&T$/?Fm2 %8=l_]4Y1Xa\Z.'r193KuVE%agH?o/g1ErdG=00RpCOEE:&(5XolbLp&lTbb6mrFmT&n %L#dM"T.SX/>/tjH&sYsJ11&h@X>RsC-8d$]>g+QYF/;VDB.NI$X@0>eD4!Op4oBK&Wko,@09s?9>:VQCXQjMnWmjgB=b"-=pO#F- %f.=IRG,jiZ"Sg8KY=ZAqJ4b0>2rnF'q\V`dkrG`)Vb[YTj#FdnNDBm2'W.'*P?7\Mc>ZFbThs!R;ECnT*/$3E2[bDehPg%@Ku3tl %.S$^sgG2s/TqN\2Vn38mU3$!-=?:SHe,[So.VSPccr'K,JZIRr8&)@9niE>BRHeM=W481iY$Cb?/RPM/dTKtTg/6-p@K#/eCB.up %pP#0V4+$[u.=Sh;pGD#tXa*u@m%7W6XELDJo3CY:`%nsrJu+CHJ%:=02?5^3@SY5tW[e]GR4?@%ku70N<9GojmIE=A,j/Q8M=&Gg %+pG5C&E_%!K9*^uV+"5/*&]:=DcM-V$]YBDT=k@uAkc!2QrfG4"K5;=H2[,tJ2t$FMc]4NJ)hSu$(^BD>Kd"@N?DQ]/"Zcn^]/Nbeo;nm:#pP:,E/`cd(jQhRo+CCINQ))s<8o%kue$WtY.Sn[.#Kpg2067b(h4=cmjtcm3'rQqs;t]VG.f](=h.,U6kL%7m %Q?G4KS#36,b[:@Kko+FV@)^JG*nV30\hIE.W(fO"`o!8gVgcC.Fn,$gkmC(CiH/("bG0Nt^@aC)+nss6?%&]H>Xi"B%Vn"ap7T2! %p'-m;W]1Ee5#-h9WaU%8f*XT--[QW5f_B:CpmWMIcf=))Qd2V"\2nbT`j`Zop1/RKg,N/Hr)4?j%en;B,ncO?frO,.4Y/KTIiX>;Mp>hfT;[Af3C:LJ!m%$TL#^nLrfrAq%m!4HMt7cWj_$!dbpas)7`cd %I'SP[Ak>3k)Q^TlpQMGi-P=Yu/%I9u#2bXkICh?24KnZ=8qX=\U&DU"_&#&\Keldp>T.u&lU^bWI]t[(,h>iJI=pXDB.*,]UFW!W %9[2f3[0m?+T05i %P$cH/[L6]+bpsZ_]!lCi,0O=Rc$$OV%/5D(^:R-?@6\8gRssK_,]@%V(E$2eYmhH+T#U?Y4?nQ/j!S/"`g+^S%eucXWIP%PXaGPn %6)RacQ\2Ro%eKV3$?AA;E3fp9EPUeICjPtO0)2"9jlH\1\q#Zf]&nU@-"RG(o;%-5F?'#tV#B$s?HUU4o9O-P^V`+mS+AH+fAu&Z %N.:&VP['OHV#JU(obVKHk.G`LBQ.Zc9N_s/0LC(>;"F=79<,\rSjE20Q8ur>\^R7V>#K'o*BILA;1[F7h;>4>^/i/KZ^(43Rc#9e %X?W]lQ4r2YQ1`b0Jo@Zjs)qDH*-:>6dZ7E4?]:1uX=F#-b50:]_<7:]W%(oP-5c_KY3N#p2N]OemF(*r@(D_6S`QcMJsCfPpLgOY %j_BD/IdQm]We0>IK%9hRmk%PUEm,^,ntT4$E](\'(]2=S?o_+Mq`e=#/4U&<*<+?c@(D`a9+q,.SD`qHct!;5Jf5PKQ8HJd?M(\N:DGd#"j^L[a?1*`ZE`mc,ihFri'hFm %`#X1,@amb$$YfV%)T3HhZQDXha`O+FQp@;bTGpJM+[@e8C7eJS)#lsfSA@KWX:5M3pUe(iq#B1[aB@e8C7Q#&b(N8&L1 %@Y`,h]@]6TGd2J[C3Hk-DD>.okYcJ/*#Go=6H4L`rGK6pT=[>%o` %c1u-8]6GZ%>!L=(ed("$=W^@ung],DH5pM/Q_,g?g)O\)T(V5*b)Wlg.2j2fD`mP3Ce8pmjWD&sk/at83Q_ha?GW+NP\4b10:"A1 %Nj<)IOGu6B5P=kR4LSGrh9DZ^[h,0*MsEJG!e)k%B/W1>>j!QbH-I=@,HgV>1_^%poBOF4/["\e5/3f3cq:II3V8tEY4I8$Ooa0[ %4o^3?f6M[J%Ye6OL$kee\]u_Ykg[,f;l6lek@.(hB8_4d-FqF&3P;`/cI6`lYM0l\H1<-IaZDolYHXQ\H1<-9$ft5;-$q7 %l^SPC>j#hF&s$!]>j$B+0,q(c->._G\^&Y@=c0\a^ic5(SLM-[s55qBFY>VmFZ+bHV8.5F2VpD8A&WS^%N$!BZ-qVm:RT=ZFKI-8 %S_(/,WGnE+9]u(oh`BBBU9CLeY4Hb2^:6h1_fbs=[:[I%T&-G,V'C%dkLEiN/["]0l"mT4[)@*q`(F6PK=piJqZ3[\=E0muXZg$nZY=i:93gXoJ$pIE;r]o7REc!e %=A)o^'fA3EY4M9\QYYDnc?5^f)"JA!^h[9$CB!Y<]Etce266PBC\^H4k1-QqKhgM@Gg39Rk+KY.%]j1uIoAD^LtB:U"EC`QIkf,^ %?Hm4C_FZT$CL58#?@j.Tc"gWKB3FK9CkC9O\cF"T9b_ish_&dIX4]OdgPdr\(Q',Q6W.?_L\=6(+=I&\F9@*R:DeH6Wj=HTtr3EMq1j#Y#Dqq%? %Y(%c7@_E>6_otHcN(B]p]"!IXNe5*YeM-5+:D/YK&5BBj(QeSIc]aKF]Gf"'r_a[LEEW6#mHp,8b %7fEuBCUVpjoZOO74)*,;d*W\(oaANQGr1\T%Puu%Fl5`!rf+2nhnou;\[LIP2Pm^-ntVl'3?f1h4(aPB=Fi4hCGVZdHh%KJd/a_q?H_(Fpft*mX@mY`'Scl^225_jQNW^cE!=UQ:C.Xt4oZ06q@uf[19-1R^jo`SqL< %$CQiLH9bkfmF9X,-MN4a=P\CD=YtHF.oUa5FL[4]7%k]O'V*[WE):hYi_m208 %Xt+nWO=Y;ajh9f>i*N?a,iU+%LW5`mUK\/Y-/'AYAPn?Dl>V/ajL.?($AR=]ZmP*&R_jsu\ %oDRXi"o"HkWrQW4foLgKcbSA``Jg0Ce'T<^P\(:q_i#uj6>9a882g"BAtsQ]IT_`l`[>@`N5T.2h;DjilV4n5<0>)-pU@3RNm/c' %T`Gpgg(8]4IEOe?n2D73N@k'fM]VNC_sVZtUHX%!l!`2:7'2,[GlD,&bkoDZQ%$8QA34fKV,fK4OcfEF.H.s<.45CpH,4UP.](gk %N5W=:8)tB)@!4?ifg;=$%MJC31CZHUc`OEa"=_AK`)_LVf`.#SqfQWO5pKIFJ2Fjp*@OCRm1anB=/* %A"qPbI%IB]X?3Y%J,U9c]NWQN77oA,WPY%N]Y<)SG(8eoW3`.>F(W/;=fU8/ChaV4PSm4=P=2H/qS:D5E]YWl%TT,2h' %b&`_rBdcjNL#"V,,3C_nF6:;+,QTR]nXWTVEe6A90K`9;rH=g:#3qW)LOn'oRZc,d&+1""()H/T]O=jpqM2KTS?[8.c-O6l$9gD; %Jlct](T--Al\ZArpDPGPN2!!(X#=C00&hc*DktPBCqUb8L,.'@N-c@9Rht3'6d/;IO>+iD>iN[_Hc$dY423;!/9HuX_X)rbnofRN %]1I\@gi$HDls.^K?%@4>UUngX,;E`@2Wk0dJVL0ZS2u+a@>B,`lh_X4PgH!0YE3UdkG]QC3h1_,A7OLLS-agj+7\k\jM*f\r(2n.WBkU[/?`^M@=iq6MG=f/LrHgLX#@F-uD\ %::?B_%V4pVMfmP(qpL[UHKmO=n#Cb]eD&Sm?E^6mn#sM'4^R-XE4Agm9]mGbQ1)WLg'MbjUTd^S8^iG0(N2D`fjmY28+rc#3'G!$ %h/WB"\9C&seoj/MrGF!Q\sEMUoLg`s9[k]tVo+9;?IS=&?Fp`eq0`!+jmu9c$=>cLL#>\.'WWh"1?oDFg>hQ@s6E45nYa@b);f\N %lgnceq]gUA9RZEnTeeA%44s&mf:C_9heZWkq,UdIkM+F=LMn8[:L7C82=C/)cVrir6hoj2oqQZnIIfk_Y8EOmr%GI&o8n?J(#M0J %@8F)keQ>%_G5Zclj*/*fNh(r^8&]WKX&*io4h,ZZ@pIQrpXjU'pLEVpkPdeBqIBE)X87LMSpo&gWPe!903fUT.0mT.lR,IJn!.,] %5.f#LD1J8?`!U@3o\7"S4"j\+.65qL6$1!Rh;iX7,YbH)0s3'Qb40n)MB=L!45'8>^/dUP7??[0"5N-$u %lKE)g)ZZk?]Aaq46ah,!%EG-8KJA\!$")Mmd)3(4MR/H"=$.GJd2? %W=8F?0k\1d].WI_!duA@(>:po[u]=laaR?@Gg@bF>\j7eo&DsHn5\'l9HMJmURAlRUn=ij!B'*;aF!ShOo4%oko]"lH#Ok>B+l$H %`8M2sT"KA6]ZJ/H]L+!08At*Ohc2[[m(19#a"IQ#K/EL2bc>k]LIp-@PFf^p#Dpjkf2n&@p+#X43XTJkhh5M;:M8I@V'FU>CqSoD %Fh#qaf8C;^pFu%fo.IHGG]T]DW&d/G)$O?[eo'3\?26=$FUPB]bcg_-=#G"O&SErOO6sDDf7A&Cj"Yj4n\*#_c-%Q;hp]Lo;'86,9Qr73eH*7 %`5WTHL:j9t139]RT9_ZM>5-u%#"e:I-2ZC*]CC*[CV=t=V!K3$j3p&:+tAYF.W=hCcMpc=r9nU`qN!S,]DZm-R/RkVC]&PS2t[oW %mI.N3mP]1[o2f244bnnXHpagHp4YV$pu[\m?2]"Jq7'=\`N4F_G7I\`+C75[HK1Wah!g%3Gk'fL"S^g.Sc2IHGNA`qY4i1)C7fRU %[-ld]H0s]h4R`"J"-L:l`@n>49SW$H!p'$+7pZr#[(<466^%-7)O6)Q3[^Qps1IL^p00NidqW5M59pb&Rj_QCns\e6kBDMa %cfF*Z=q=b-iU4a9'F)r4\CTFV\Q4M&]\5dLGN%f@`T)kB()0[0eOfK-,O\Kpb2jKomHbmgW/4.'Ysa)+E69OiQNOaWBLse`hqScJ %WG>fKhEEEOm.h#op$W6n#+dFhZ\e"+GI]&RISCTUpO"`&4T$AdOZU&*Z[UpS17P29S6Qj)cc=FgorF.&jo=P0>Ig%u0%Fu^kA9Q. %i#Sj-p_%lD;Vk6S*P&7.ZMEXbo+E5p:f[BgYNbR0+=2KIQ,2pQZUFiR(rNcZB+fblG*)@poa=a\5n(Xdj_?CoJXqV?qQ61GE$eT1sS\aP+Tq!a%Th\1$.pL^daI!pF7P>\;m1)CeJMs'K9.K9`8Rgp79FMJdIc*pI+4ZO5G]-28@g91AG %SGK((s7p>gf:\p]ch!R65O^Z+P'\%-=_5s.]Mc=:^10hba,p4l/tMEDB.$cYn:()(lI14V9#4)TF2)'R;W,O7?S3oIo/3i\rlc6F %_3E_/Q&_'Q3Z2\qT?*=]]]o0/iN7P.Qu$"lB':VdiZ+AZADrWa&"#kT+Be>S[X==hhM=3 %OWduX0b9lf5B:rip%*"t\`k(%-0!t^JU0D*WojS=[iK_6VQop[3^$Ias2qRc'FX759n[S6'rqU"cu5B<%PGR$.m7ULF' %gcPGf%sIIPXCN!>1e+k7`n5db?Rh*AXs3ZLpuA;)`tIJF)6r^@KQG'".:0%0XtM8H.RbFsW"<4q[utcRIW.E]dn]n9')MPgRiHm) %E^n,[jmVp"L[)"V^8m(Lj72otikNP-';JLf6+H]F]UZJH,iI7VU[WK`GC7ftnqF_4&#Z&2S3?[jg"RMT"Bo*Nu'?f %B@4K>@!g,i';)\ZaY'BTL,5o?_#'F#-$gNQ2g0_2^5^T7D+n42fSr@L2*7lh_._6k(d=/gUm]Vth4X8V2KK>(D?KOKfpm)noN_WmIT?=Y4QbD#@qXm# %U"Y2>=*EY'TlI."s5lOR-(k+-WS6C_DJo1)U$*CW:NdS\>$q6t"0BM%C\I4[r'@6N_-\_.^6s5$VRX&JHd$^6,]4R8U!eABI@X=n %&U@HgX8_B6_pZpE(-r;YaiPp%(NQYp;DZ1-.F_Ac7Z5PsfsNng)MUa&g'QS#lTN&X4ST'R2u(J;+'07-mtZ.gkbl/,aZ`^R:ZYfA %i=E$@,*R6h:E9Z>-mqX*Q/>RkqT7utbSs&IL<$kXX?:ans'Q`!Q;>gF?C=T\Pk!"Eeq0fJ:2A]K>[h[J?sSe6e,F-1qIZf2S#S%t %'!K^SUZYu\(immCQI1uRCB)s7N;)qs^Opd!LblS3H91[J:B(4QQZFo%.L]KITi0"JJ$.`#Hp1DjrLTbE*aZlUc*-BeY^lcM*07mr %N"dGr9%F15c`cR)A,+!$Idm395jmagKMU=TO,XN7P/**]dXNAJ:Ht`D"hA:4/G.CiG\oLpce&,2:cX!pdh0(o^;?5s!s-+hPiH[D %%<[&M06URsd5ULXjkFq]2+h*7Np_7>:%^riWf+ur#h<0jL[9sG.$8;Wj77'8>]tEi>s-Zq2%>%ol]H,GX6I:pCN3sQiG5GYG9Q*4 %k&<%XLq.)a+cK\I+Et1)s&4dGX'r@ZNe'nn+USl,_(JQ@"q?ZB+Ma(b`j7-Y;Gi;:oNOZl/Pj%)dYEL(=EC3@Wae\<>QTD %`9MS$Zbrl%Lt2#LSgSFt&I[U7-ctb7/uk=d_F@=spP!K>SGkBtU(i0R]^:f2%1X&86Y51DmVqJ#*Ja2-H` %l26S'E(/)J7Q:.E7m32gFZgg+Lt.cCZ]fV"j4j>kFY_uD"]go4T(%B\oU+tQ2DBVo)+ct*cge%S';UM3Hf5d_7"]q4=<0&e1RE%# %fOrRcV\8bW._$3u^h`C_:JXXQ%J43FVtD9:S=6p+g6<'opuFGGRj;'X=K0Y_1%k8-j?Uui\U,H%j"p-3jic8ghpXdh"CD:lP_Z$` %*a[>[WI(@PO-Kc,Z\Ud"QMTZPhq)6RZq0[+]]'69+rM.FtS-'b62'8@(pF?"R?1r,IIp>kinS4*]KBO'<$h9A/DVG'@ %f_oUL7N'0,^/#g-*314BrJ4i+*>_r94B@%G?1\m1P,Z$8>.%g=ZDq-,<@_&/bj*aoP:MN5lOQ3DZ#q@l&-@,G\CnQTe#?QLjUs[1 %Ap*G3`?i$67Wn%(>af'Z=HlGZpqD,V;@XeL`6lAF95Ur--5A),\omj3nQT,GX`Gn(8dc6lbIO+Dk]8cC&KIDNh!k(?^=65r-Jq.> %+m,)!&M&jX6EE1ATX58Ob!$V_ENtlo'44uupOR!XW9Og9hJ)$)XE`+@'oA&AZ^dC"4\Z=>]\W:1%2"na[;DgLcXB^R) %o"5+W:fBdDU2qHf]$H8\NI&h!9_PQ+j&mHdFK#C]7lDs!-b2TLLb-CI"H15L=U%9m1+chS19``dqtVu1/D(`APB@JKfut$e]Y(E[ %4YR/ZHj]`8PJedU0t.SO2jsM/YW.&8Rj$qiqihitj.Q_^X)KJ?S4*bAZ)"*[!ftljp=8<;C59u[?Z!NXAhY02crJD"i=,G1$bP\G %k:$Jed3pAWdWJ_!$T#j0uhWAO[Li7r:jni]9&pAAGGW2?GGRq+)\OPRoVF7nY=JVf_^QkH+0BS:J*2ZmGT29e&jFB%d"Z9LPn_S1"Sto:n4E3 %8hc'fo`oRKQh=Bg.)@4+:k7\#Qtn!a]]D'AQ=SFt2Q*9"j+Ri'@o8]1Hg,WLF2XPu%_E]bSLAm%MA)gt+LkGAXC=+7NeN-(c`H\,]QmQ56R:/.RD_JcFbV1&g3K7o[Qju:GKGEd-;[C_dVJ0M6F2`A8lX5P5 %?k=tAdtGWH)5cG7L`/.mWnLhg8R>4j^HQBEIVI,92kRnj?T]'J-LXMO=7B,#,6%r?n(,DodI"0CL,Bm %h3g^56Jn8.MeYD^DkdTHMBW>?pa]]"!iV^9@k."G+j0j'RDhM:/]5%8/BrlNZ,O+Y %@guFm`Tn-?>o#l:*a]V0OV,Y.XKN %n;tiQ.hK]-ejQ7:F[p02NcG0*?.JLn^VuQ&dY*T(fIi%H#i=sin/c+^.F[cY9@JQR,%-BS-r^Ci8Y,_c?[@&0),1e<%$o-HeiUB> %`O7uEZ'ZkSja7uhq*?EqoKc+5L.3-T'=Mr\VTS^@^@Zl<(&^5E'.33A)b"-_?[F&DfWRPYVq&la^;r%+F4hsnjb$Z2)$N&NF/U"h %K&(/Fl[^UXb_b%KEk[eEfNJF4e0=BQmc6s%^O<%k:rJ2L3cVHFYgdZsh.!YkER66B?+hRVmakAX/r;MW+L6!k'QC:s6aWi*d3SJ^ %aW]P+isS1-I]m\LFL+[]m#=j[3@a<8n4X\Y?obJLg/17F4`WsA"Z!NJLA`\#k?hT4Q8*\caDkdi@DqJUDaXjhDc2-[6;52\Fesr^ %o6sk`n+[9#L&.tp?iS%:74H(3U/J,]o)8>f*ao-S6'"u)=R99dCa[D+d?EOI[VF8l4bbpfEM&KjZ?K7VU`UZ*lq,8*?"\7cLY&\n %fN(V+Y:m5;@]Pis_5hV#_tFpA)3>-5.j`o7'&OMjBt1*h(A>hJ"GN%ek%r&! %V+SiGk0$(9,H;uq.t)Zu7iZ>3EiV.dIsn0cs"s%_Me^h8'7HX>R_pF3j5,3X+;CMi)\1?jXDaT75/(AAWSF_!"0^>(1NYC$Vok>5 %=j:OeD4<7ZBSR`9#KtWjC"%;]OX=I32JjKc\_DFa^O=2#!pRb=#l8kC`O:*-ggC<" %KipVp9bU@r1$^3g`f&BR3Tr"&)+l0J_fki+JmU,9U3BFhf0ZLWN2DGgar+^CcoAk8dF6e4Cro %EAAmWdfdSsZ[QAP-4g@*Wh3B.0.`og*8_Dui1[EgGa>N;L-%6V?5XF62iJQ*B`e!=/,dC8#A_&;Qe]\t>kC#].A>,B3EeIeZJA/V\X/hJdKEORCo(MKa33UI^G/2tEM=ihK<.m_Nq.-d*=3YPHsBPZ5;MBM"RKW7AI(hqJ9[dSMmhhZa;CZ;Mmb$.3+`fBHTq*+ %[>YI/GVK:RMmKq`fEltNR7b;!kDEH'(M6RLJb3M\^`)@WQ,'sg!A?n`V-p]@g@IPYmU/ZH''DA"fTqC9m=g)!%[J9,5pqKk %;3R.hGfRr5&+tXD>D>^K1*4A#O3H18M_)b6TmbCD#iS0V5lcH]"<1D[Z.4I2c`UZb>eqIG`GkCJMX'Zi!FL/.%&*&:qU0W(>ffs" %J1Lf*5#W=#nhHk+_GZ+r_F?I$&J>H$U]nN78pHZ(RhDa+B7Iu2=qBtLkZn\npa)Po`#59)8\CY%`s[hUi*='a>W40 %]:AWUo75oem1]hk&amWie#:H&fr@aNa?naX!p*<9a7h_M4Dn#!6-k:C[eJ7Z]q6u&AA;%X\j[&`7!'f7HE[e'Kl$3*VVY*758:,F %*qDYa,`mHlU6e8"06@DLbLH\Zg\Zi5pQL@cF_XKa)_,f(XU$D<(h^!j;I`((=a.>+X"AS@0c"MSsqNUu9,o9$#5i=l+b+B.a,_P85q.a9/Z&P`?b.4=i>aZSJPgh=.je+UGH%XE`@_L%Bo %%daVsDcO$'Z2@a81"O;/\+`82&6ERJP"`gF*Smmd-nGK3)eJrLLtj0/U?]:cb1$pPJk]bnE2LQQY_d`9cRbFj2N_Pf4%^GqLpj0J %(NH9NE?R;@VH--n(D70n9],B^ltRl&M_U'HHjo^'[NmK2$kCmhLr^8us3:ohQ\ON9Mq>^e>0T\(E\Y.Xj_;-db=;%hTfLJmSbn4^ %G>E2^#nrfGr8NjuheZgj>c`*7O5\ZI>EP?IM@5*LtOhHInN:/Cfef[cl(X%a^>E1pV"S5$:W6@#MQJD@^(Pm>L5Kjb/M7^ %)J$][p!DXa;pfHo0ij`GeCq#J3^=C-,H2rsPJ@,JVkP_VeNZn69M\)1YL,rjPngl3H<r&U#-1Gbufa'a/n&K?gaJ:S;fm"0XWRJ5fCprbCe%Abm@60kjK)@jG&:>P\ %TZ&E.D(hB\HeGbn6Dr7&n`>E[$Em'"61N@0WBl=,AOFM]#+#/!2IU=HaOdl7V'T`rGTk3r2sT#W1,b\NDdA6EU<5+(oQE;hP=U%uV[_b;,-R@:724dqf %>);/bq0M$Ice)4P_-.\3Hu.%qOcg%/2a?i#UC"&.+W6bE^4t0N$ah8U)Ifb3F3O0 %"!%oI,[VdR?rb4DPHU\?@l=psKc`+>-9eI<>(bI8=S2(#$?Q#hU2J*j9&O):&YD6_m#bFF`2Ce/F++H(O^"B[&O"3M,!K9?JfnMZ %&YJJU(b_s;imW9L:92WcA,<>p=Zj\V(sUYB(Ls`^ak*Ji_iu]_-!i.bCKMAt!Y?qJXEgM,Z^@r2:cD(-L/8VHeO81\]MQ`%?V98J %)7qCb`kKRCak%ApX\Dfr^sEH`c8VkTUtV=7\qq\A(% %pWqK*#eKH<"i]*DB`di5AW4-1:?'9G=KGrp@`4s2H<).(F.1bXW(5f0aN&8_5Ha0dIEV$C>@'LemQb'19,d/T^/6Y@bf8X!:&Me2 %1)\#ZWAZIO`,6JH`o_d2WIfDK%?E\&BsH25d,`e,2saf5P'kbq/P6Zdf$Irj-6W$86BeOkMhNuRr%!aQMUn&"(-7)>MCK07GW.s# %ah8qdgRS$*Eo$s_*6N>HrI#-s`,UI'V'WT8=YcTri([g!>WQ"(`l=jUie?t$cS;%?:f+=1h`fQ,W%*QM'p4]>kC6;WYm#<41dPK& %AnAV/1`G?beQIo>jn\ln'&Of*@bgI_Qfh!X*Laq@YsJ^8"bJ$](2PXnm<[H-I0Yq9446q?,p93V-gY>p*qbc[goP4NQp1*L %gEULVnZjE7+;SkdhVfR_h-2ud"CH=/kT#1G['hEY=O74C'@;TB-#q1E&MQARhE5,'U^;()BM#n=F<$?.'SIs?JYsg9eaoh!pQ'=6m4<_(`n]eUmRR>@2(7naIIb7hk40E`D<0nk??;3W'F6Nk(Ok"41O^T]#(I5r3" %-#p&G(V1h>EOZ7km+:/caGAeQn9Eje\/bB_*1]a-NZ[QAP-EO5<=H42@8(KlRm*bO=jK@cZFL)_gb>AQ-DTo)$XA0F=Q49=4 %K!IGag,)*=IMVlM<78=hrpCpN#pitb>Wo&3ajl?46Qo[-SY!k5/49LjXGtHQCXu,>c`f$LeD@@^_`VQIW@RiQr0ICi9M8_8@Zg %Rc[80q;ig5[[IsV26G.o%-lE43_gCgSWb7)('^es=75[gRb%2^[)B34F'afr[W#N$:&o"Ss%##m;Dd8:=-V/2O5(,F`XWd`*rEH: %(Ais@FT1HB0c&"]C#XICb>,+/#)D78b1dP6i/1o^+ZZ3u#mi09)R5BK\@]l>JMP(;mNpk#X %*'#E&E(jeX&MVQU&37fD;A$0_=c;l9>Dn#h(4d"HoWplgnuRill!!p+-Zkf0Kgoaa('-cSK$NsD>h!aJ.JW!+7sbf*gc)+G%a*Sl %e`q3,JK:BY)Z(>s$ZG=Kc@!@GfOkQXfUQ/_3+#I]$X1?+:7m/3&n40NGK#EQd7FYEVfiO+0m\hMX[QWrYm\De+:qKK%>"08Nl*a8 %1ICRkfia!BHC.1(E2=<5UdY*b-j!'=JYW)_HZeTU4bpSOQf01\Kt[`m3-Z@'2rF)2b-q59m_n_i2qonqu'`5Hg!s %+%l>nTLHXm'QudT0]3F8[0X\NiaB*s#*DM#rU;4#,o',[Ku*bWK-FNXJ1e&.!oPnrh]h;2oY66g_\:[+"KVEVU/p6-_'85@^=iV( %'+ia1"ArQB&St1"TY$PXir9eQ$#D2F/SPfQ,"gGIq9o.?_#U(BefnM!7GsA?:"(B`p%O;frUpj[KdX+4#\[rbFL.AKDKsi67A$/9 %fE>">=0r73F/otTguOl<&Tf')`)b8g(4q0O5ud/FGSqFo3K*jSG-qUIY7]7\P;@'5@(l>jD_>"$\tcB/TB(Ga/PC!K]T+EacJA-s %ZMK\',t!Nc.=q+E)ta\P"6S-9NLTUP`ZM?>FNNpsH[MJi5h1jJ.6F*CF:[&Af`W0hWb.EE)nA`I;pJc^*gVSYT.R8M2L%"q+54pKo]6>6!A %./]gnF!CM'2pu4*[7*V7:I6%4;Q(sVfIc=tpD,)hI$5B0>abtF,<&*5$b9j^ep!csJ!Rl12cRh#s*TFt=1U+i/3;`aVC)FUV&+cn %]:MH.#=W[BhB356bB__Sh^iG&fXc#@lGC5,&9>H.qBMbPG[5k)0jg#QoqK"=Y%)NAc,u/W(4/3j9?Q5_6up:R+:Rpo/9I>?%)kg3 %Uul;@Gs]W.GKhD&?klerV0)P=BU=kq3mT&#\:_#9m4)C8o;2>6rW>^gV#qlmKOgn,`s-8H(#.9&4M2Vu1aM9H:@qh;0IR.*mJ=;/ %f>#U0K\.T7Kg=F"(+NpuCa8=M,43M4hb3Bcp'KA+ZsMQ"1A;FaKHeOiYf!]1:g@+`d4&Q?1?+mIFAiZ&GB>F4M'N`KZo_-Y %>F48Z3JaSMc]i;,Pl+A$nTfr5@--bU0'2asCd[EL6'gp7[lr>-?V"-`n1r),fKOf>a[,=,QW#VsjhdK3pK4'%);1Qo\n!FS#LZaW %hOhg";fs`$O$A%iJc7\6rBt=\K3U,ZMJ`%#'T#fN2j-+jZVQlKMNna,ht^'eEPi %)Y,VQNADfcFfMmf?'P'i* %rV0@seMg)e\!W$*.Q#m[Tn11.6'-LX%pNWi\9&#OY=&u,^lM>3!]jR5(ZKa"!Td3RLMJm((HRg#`Pu,f``jA7T7hP#2)is\`)#aQ %31\atbl75bNp-@lW+JDO%k2>-,osWEGP"j&FC@ljZZ3^4r:]&AW'JBsKf._-4H_!P$qhhbYBZ`D6Z*n(RH_);F\NeCLF_.g1p@pq3(Y8[UVf)N*-c9kQE6r!M`2`_G%Dddut6#m-.iu=WmNK+*<)9b,kctKSt)J2.9c56.%&.Eqhau!"0do]S&T_H=-R\/D=:dWt@ %F6Me6H)6C8Z'gh]4V*i)RQ8'/]5D.>[jb'5GYt(F3=QacW1lrdu8*P@iEZFW@`eg %4G&Ql=$XHSfQ8"tg%]`'j*^mN;h_4o$pRu"[/<]/(gt*Ydk]$SW547U$IYXU6\c98BG46Bebl"``d+n*1tmA?rt>U1WLlq %NimY@W%0m&W"Tf;ZY1!#ERh^eYDjLY9GA[!FR/o=Hr]51e$gF%i3]7.Uj][/X]G.0(sf@TEq`[>6S2HnlC2D[#Rs.?G6l+e8R(8JN[\L&VEBff8RAqj1#+gXP`7$i>c(MT7Uhah?`n\YIV%VXI,X %CaXNfF1]nf)^EfeQL&*4ND%C]A6!d'>T%>&Bu2)/mWROEL_#U,`VG1)jt/(d?XiWtN,q8chnjOf:4hKs>`@?)Q^Z&-Zas:,F@'2#C4$:1d^nPI&l\36(qG59<.0o[dSg#n#I5nbT_LGcc3FV)aD'&KS#:YMnZ.i!0_RAPBL,m %n"+Ar^oaX=ApK[1kO''^\bHni%b">f>GG;3;,E3%-&.NOafLOXA:0BZ)9l?.;Hk&TnbO5Y`J#qdYO)J"G_%h5lnf*E0+qV:]nL\J %VPH]p'P#DoS!+0ePH0[X=fhI#[WpVE"Fd#24Fso8_Gf.lS?,*bB*(GhjW(#kmQ_d;(J[O"L2 %=^MPCZI@XO_7HTg]9@ALMWK(kL/c0>3POY7RD`#P)Cn/5eB82i_7a[-eT(85p=JY_)+OFS6;87iXs;o6hsYMA;T"8M&2_SHGl^E2"I!9XCOfVYg36L]8rMS;qCO$O?j]n8e;06QQMN>pb5 %DVSI<+qHOo$&c4%_Vnt%UbWAd<&eEbUb[APVC,H2##J-#)@_Udo;s.DPBtc,Y-:b^'N$e+()cPC+3j;ORleqQ>F<_O%MrVbD"=d> %-SmX"-6L,3#ub@#.;o(dFa4G6gi1fq>.UTdN\F%T$YB:Tt'^sCkQ3oXs %mO\@CVFk?_7q]".U/"+gZhTHLKeJBoF:&A"k]UV/=$$f(++L>2_rIelk^.+QG%^=]3suITTr.AYekX'L/H0[&dC@5T.]PfoP_+Y% %nLX:.b>d1Xikt182XN%^#UO^=Jq^W&l9%"V4gIO/JH %e.TD?$^!]0CL`M]MVH3]gL#so%192#R0'(rGSWu(:uAVc(]pC%:_:YeZ_SftH)gJF&,A%-m4&Y4P*5XqpVucDTYnao=)+22;'1OX %YE\-Dgg\]dFYP4P>"3OjcBmPmlqaerf[s3FrWJq#T983@hWEO6 %[apEemT8g+L#:>X>s^q_5kOnspWBKOh=WcHTG-'P.*#^e!Y2kZR.11dk %72@P`AfsglG'j]h_OiVd[No8pq.3L_ZGX(nqUAIi[oSK.eR1Sch*"2jHp8E*2g[lN#c8kUOs\73`f_U[-GRp/SfA-FI;e&ca%'^2 %4p@U>dOVOS-Q=LqgN\0?GlHSdZt_$TNX,q&(A/YP<%>6.U;BCUd)YbTd.f=?"=qf.e4hq+F_r]Xg.k,la7BZr%?bn@.-R@P=B'YH %$u2V)^JDm-fLF\a$B+$M+uFRf;,^nuDRPA4BgP!**n53sk?7;4R\ZoLYW:-K*VaL;^__`Wf[B4'8PVl%,jcT:5h-3n*iZLTe?[u% %^DI=75f^p2,YUB+n\US;9PR__P?6sSa(2IJqcOrKGb&Fu/uk=deQ1)Q\r%hfKm1nentl*X"0?'lFNihe/g`1,>YnO&3O@Lt1DGHh %#bk7g0,9-k$&d=Y.#UZD>kKhY7jY^4i%8*cUQVEIqL'.QW&%7Q&sXUXO7Fb>Mp!`TA[1N1C+_A`Q"=baof4+h7]_u2b*KrL9\q%% %3\H/(O4i`=lEZh3=bIl1&\jUBG7qg4&FNWtq.[2Me6gla(AkqJC@Rb3GjAZ$#0P5\N?P_*sVW %;>pHZKg)\Q:'o[k&=YQeM@%%\n\N2E#s>nQp?Tr^>?Gtn;%;?^n5UW&.%Q+4h=\H!rq??bbi6GBEW0F#9q)@+\9he>9j>niATMfF %Y$n!h*^"']Guu[1V1-@[l,5$3%^LSS`Rsg.ek`=uqi!5po;5-d39M(_,3o-,h!hh>VMIsQ3t&AuZQpsgNs\o(X-f#mB>LCMR*h@. %PUgS-KWY%sTV"t[o[P`D`%en"EahNR3WjV"(8u;6hdhJ^87+/TVT26nFPnUR<$sjSjoMjL9hN`XFc_r-!\'PH(7R_2@Hip5rrl+t>2X9,e^Ms6YK;?/9_[&@F]k[CAhr>XLRc+5.S,F#IREJ9d9E(@ZL;IW:K %Q:3Yeg:WGt/B1^+atgl[1('K3_*qj%mc@AdQq8Mm;1kfqKJH#(poB6-nkbI\gR5F&V^Wr[p/lf3XElIbF5T %VsVGSs+OI"5tO^d9m]1OpT7YmcX:ER9A9gnV7$htR\Up0=5iJg-UujKIhbTCs%+/%F]KUd_[+9hps$8a[Peg_D5].qGgDfi]Q<@J %B3WV&JNl']/JtMAr0Ilg05U`]8N%s[c8PdYMZgC',A8`fT`\MAp91LAU=XH)*mo=\@lDcBNe2La/([3k7<<#\26$Eha`W"5C!ek* %jufC,.Y]!Qj^3,Rd-\.b1Bq\P5[(q$p7*VhbB_]q.ZWo4:!nT?%S1pba9nK\734D;W3+a\?-TN$Pa2;`=)Ut0=VB2iUcBi?dOPG> %=,PA,-eG$i+^WfY*KVl<92UJDE0lCfaTbbI_mLOA.)6cF(#``N%q1ZB*K"TFKS#8G)5C4!,[M<,EKB9:$nXpW9h=JI[1:gJ9e&(u %\RE(C'(\H(+2?.^*t+7e]"]t,eY4i-;].Gje`*BkWJoPObS>9!RcD$PKR;?)$UNaG5cS!RGD0!^cc.GFHebEs-0RWagjVnKOLo+"9jl]AO]HDE(Lu+aXdbDK4MmIZ7q\CXZeR5O9olRAb>O)>9A0S'M8+JROi=bP?59[$rWE\+$r[H7G(-mE*dsX! %apABlAo@aM`Tgn6W\p+uD#Y>"BM*N`esl2L:GhW:h1+FuEd]keZY\#A8a)6VA)IN?6jVHB@=en[]-C,-)SU(q+`K/+r7H %PaKtlA^u9D^;mH@lR@/2cfrnrdUUqD4Ic3<+Q311-j56q-J[t14utjH=K.RZfdB?."JNudluN3BP#[Q/G^T,(=s(B^St+H9r][WQ %.(60EnVO<#eK6#O:VBn%)&5[[&AjV&-aV(r!_aV?h\#N,@'AkT2:kI)52Bl.1:V# %#i;Z+BUg`rTAd8,*(7m_:/L_kE5RU9hN#ehK0g@,=GbQM>kYE46c[LQ/9au(gY-mm*em`=0D#.;SHBfo\7Pmm-^FsYP:P#SmWu&4ah0([DJgbB#6X1=k:eC]s5gcJ+g74q0I?q81=d%u!L(mnf4GjT.oq[9! %9?^G_hR7_gP\LH-+iU.]LqS//L9%$Gk$+E$'?54n1c,l!hjDU-`O9kTOBm2\qs\b7#u'8nb#fUZ[U`>Ihq(Cc)1-CW3aQ-d)]>>W %E9PA4WGNTNp'A:Z0V*f#EPAc?cqS2#c;3d_Mna4C&`EPOAm3][CIC!l_XOSdZK.P+<]o$?iW4.F"gn%U$AHSIk`Q#)os&eoSRaL%pKJaK/UZ$.`9HJF_s72nYna!>"-hDPVtTHYf5VS]o.^L\K;Q36\V %+'FqT%^O&fJigQ(B4,$1Z;KL5UU;YPqH/UqR%%At<6HJ_QbM*<(^d0]*bs@`fptH+om$e%,[]idD(W/tU7pKQg-nSN=)0edJ>>=F %-s4j=A9W(((cN29r\(@A$>T+:IWohBXR8lPKR1]KK9a+5$gmhF@.#AdQO %,RTHD_Oca*4r`*sb-9[amHV3?SP9glCj__YEA<>CJr8V))r]>(_Oc`CS;eU7KDQuI.IM@!1,?1b_OcajlR2Ts2`/S^6#SqIQR6Op %qCR'FG9_$?6''$#W:o1URO5aoE&4jUS1%5g[P>-104rW8Y)B9)a2>pu2nZfM"[,cBN2?p&aDAuQ,Y^7'N60hOj2LjO(@Gc4+U*7A %[6R""\3C.)J#^EcoNi']g/-PSL(a,0YDBo!X?u%iU9D:pJ\4k+r'u-(Q:!&P+tp]ZN9H;II#t>RaG1VqmeZf@8.T%AkheBRMleLj %>6b&J' %+jh+jV'WUCs)r'75O2fX`_LL5N6Bi_j2KsE"LY([rTW9N+1pehF;DEKfTn;>kIp5\90i`i"q`?pU'-7uj;_u6&W*RV78m#NUbZC` %C`5S@Id?d]N5\AWJ@s3O/8dFR2Wm>cojJVG!DB!=+X1`_O>bF[?(PYM+`):"HKqA9pqD,Rk_;GnP-Nsqp+qkZf%V/`$TebQje:oo %d+*\SX`;BNH&0]E7%aGerB?ZGU%u#9(0c)\L#$d:r\#rI/TT],/t?#t+2'O6Tr4h=a`l(*W(H.uJq\!lR5gp:oCXJWOG/V3oP%6I %Q<]TVEBZhm]C1sETr*`OncT-UbG[_6T,*$2e9/S#i81=92]?n;i!!hTb,AGS7VT"V^(q+$7)o05_m/u)]7]WUgcBc.oX&-+`(\E; %8n'm0'1B7kLPs>51SXG%!N/`Nm`='@hln>O*['BK6`e`N\f_VP%al$mnZ'29sBLrs.J/:83.iAsgb)[E%#O@Pq %:n7R=pgbV'PDE7#@;I#"=FF;->ScSW"U"t:Cjbesn]?nj?I5H0)8q9gBmZ$T*lY@C:Ym]f)&BrACEAatPcq%Q`"]pm\M)7e$#Ju= %p=^OW"A=nUn/2$&G,G[>d)@f(qe34hU_CIr=[+XsSY59&<$Kd(hU8c!VLdP04]>$HA4!pkj<-^6RA/(ap8d4`>/l`s(RF2]`Z3[1 %Pd+RTfHkdd0cKZIf6]i)opdL(H!#"mZ*cYOdI)PHmcm+t]Ml[]XInt%T6!?Nq4*d,B;\8.GO>+:CD6ST`uM$iGEN1MLW.]7(n^@q %5GYMG]@`p4+r)[-6],$39L&'MV%jd>CtrQ'bWmok255`+oAs6Lg7F:Bf?%\AP'MRJgN!#KcFhGdc$X'HI*?h"Gj_^V85#B"J&8EO %5qI2Md!r7k#I0\X%%*(\K$^K%Ua:53R">48RE*ktV0oUb<6"+K:^eN-A9W'uL5[(.(J4\\DiQj8p*Wu65o/:HCZAU,S9n1Bcalq( %l:0^R#Qo@l\Y((8&c2'WlW#bZe?Y*GaNPndS8DP%GX9n]"oK=>J@ESHV!-\ba.Tb`3J:HZ;W,_bJ0t6B^4Dr#;SW-&:[aWTrU@Mpkg\]_]]O\*=%2d/39>o %fo4E41/c-u9q3Sl0q(\#TP$F!&G0:2:uJf#W>eHTHm(=0I-KU)I$/`J0Xf5oS0Tkuc(Q(0bBBe?Ie%*ap'a9/Y,SWCWEWr0c73G/ %)aN)8<0iKmc7@3MK>ft,(Pdr-'fI;%!@.8f(VPHJkjFVa\Ab=s/3EQj9UcBp4-=Yofi5&0(Rim %2"#ECSq$'NrY_@UKLJ4Dkp'>1MkL56[4Ip?Yi5m`mGXa:11Ll6d8qA$h5pCfcqU%oHs(^>PJ4?`(HR1\JhIig"X`La&228['kY,, %BL$K"Z.@Ep;14W*=tV%W?cbm\7+fkaG33s\Z)u;\f$8XU(/':smOVI`(,O[4Mo*>S %1>81\&N&)U.C!/A.:H>'TrGP"KPiqec(JY&$9EJqU2`aNN8#NLWkjtIpOC'(c((4')(N,`aIH,npfhY9j(+Yb$/:8*J;Cj.s9rq_7XU/EuL5YVhKPo9afk2(M;+2--FAb(AH-0`PXtr[U %Q%,75a#YISakLXYK*sKE_aP$#k#Yu$d]4eQkS(O/)>O"Xm>+;!&XQ0\R\nOcb2K)NF`4.VZH7b8d2gfMmMTO+UlR4qiFN;VD)BbN %*N!GE2#4k)PCk3pW1ks(o(M'M`8G6XmU4FK(h%BY_JD=Y[^G^6kg(+XIElFEY3T48!GPr"qPo`^*@$[ub2HfWN+?n%8>D1hF8gmG %Zm]151G?1+OTVPW]F*'LP2&XbAoM[X_*+Qkkngp>Nro"Aq7PR>c/<3Yi0MD%&RUXE;f>hF&=JAPAg<^HS&&sM]tc;J`RaLe/Es\g %Mj_j+2M7KfYQ7-Xr"+XidTirZ[@t%0%5hp@*a"j]Ci(Tog/&=r"eh;O!LC7C>QG_1?HJg>o;Y5iB]mKI??LYK*tn+G4A8Q/'1sc'jIHoGZ511m)b+O %lL1LQUGP>gg17\J&>7$.7<=/UqT;[G_mLZ\AScOM>-n)l$jmaK(s[uPm_q,c83BIS$;_rT69J1?L4soX;k,=>G,7,KG"VE&c%X+h %DGi7LbKC/C(Ec8pO8.-j-"qK+Pn.7[=KF&QfqA(CW!(Q7N5N;J#]/f)GgEB:Mo"EcN0&6s?2HjEN^(,G@E]P(e!'eE!> %@BqVIrK.uO#qo6`@D`s(^WF)SYgUSuS`b?j[[f*T#08H6akIS+7BI>#'7C]E6:A$kiA#NQ,`9;BHTC/d7\RM/]li]LG)I*:)\&_9 %P5Fq:FNu#WSrIZ42D0(UNKb\9H-LO3qO>c;]?j%A<$Gsi4+I3/k:ap)=#+kQ,DiH*o4^U.-M`*CCbpdSb7sXUHK[@be0H^lY\"MU %CO-P[9N8.<'i>I-g4lLmdj9ld[Z!cP9IP(&\cE?u%'+G[/HrPkqf8*L7MYK0m>A&8XI1 %k%5TV"hWRt(:&$%n]_Eb;/+/>kA>YHXlIFqarIQEKLKGp(nEY>\8`:onQfhp7TlGVik^J8L(pk2#h3;@49C8QO1KOeC;KASK&YC %B3X]A@N#&H/jLgaO/DM5LMP9?OS8U5m$93EW79j=qs(_\7/r9FKM(,B&.6YiFElBNWN46YGH`N+-g*.AbLfSq&@Q.$ %ELAPr5:IusfLSAGZkEXuJ.C.?E=rtiqJ=43QMICfPY?\.n2@O"+LWFNuVJ*:6Js[2HRT#]k^=PaF.1`$2KOU\0'1)[89F\UQN_+Ku(Lj %?+Wi"=pU!9?5C-Fnh21DK_Js"GMYgFcpupeKOFBU[]%27#,:0X_AGk>KRm[/DRQXGilg,pG17N$fNG#DZR@0>26=*;g;IXu#(;1mYc@Qi'&K5Plm4Xesg*Z6L_?SkY[WeiRmokO"n[[%8IXG/(Yg4lQSlm%= %`tc7R?reM8f1**#I:beFbec.?##;$l08JUp+pG\3"Df+RD_Y8b1C)dqo\\d<7/>r'8h8.8&Mf'oV5$'^KegDP3(nr-R %'Y<7"`9o2UEbDYdO7$f:/74DF6)1US2P-NISmV-Y<-;.qSX^gf3_`anNBHehQ_dp9(PA3VbnP/a@gRf4*ucG[)$6MQ(A1\Dc>QUl %%rJ0RM%8>gG/Es@`MR8`DA6,K5"WU_gdWNW&8^2B%L`0XK$p&U3D@p@7n"i(@W<`<_JIa@l(^=@I>k"+,BrdE77q)S5<6&XCaX%k %=Y(@D'a4`$/*$6g=f9QMg'L-("j%Jh(V;kL3KoA\JZZht8Y=&teK'o.kO+8/%;]mY0RK\$_MN#Pk6Q6##sCWW=nF,dj'EY3eJbot %eqaJ*$obi#a[GW%oNfEI1KaWf<)pfdJZ#=Hhg1"63G<"m?S>@5`(l\9;:(0+[1f-VE&4p9?H#R3>gPND2lWSXqn1u,KL<^Rf[_1N %W^0Sn#WFt02df/Tk-nlSHu,e8&I6`5sM/nc7X_rHg:?9C*M %4#c:I4PcRBFlLnHOJ]W'e76]tON]-pCd'G-Xq$BQ6Nt!?Cng:\* %7[d:KN/s+&@hh\h;<'$9r"uE0he+9,*"rXrp._4IRfH`sr;[Hs>qM`Z4*3>Vm,A43EWnMC*$/]C&C3CsTadQ*S %k0Al_L8fiWX3XB?Ga^=B?6:C$i0@rY$s[The!(Fe]f)%0CUAEs)l7-ZV+/g.Pq*mB;kpe!n6bf%(4s)D)=9_46G(%YU+#-]5>'14 %eo.$\++O?Qb+`(#*8@(%J([bF:CE*;5r0l;LE@DhU9YUhE&GOVniq/\FT.1;G&B.YI5FJ#S\\<2#i8,f9F3/dIHf,+7\XAH+3?f@ %a;-*9&eq*)'"T]F)8[RG+o!7@;Y`&PIGQPKEk>MmCk3GXIE3Po^DZWM%N8K'$``]<<0"TVa#-`m\6:-45HiMZVNr7cQPJNkFX5(> %+f%dVR`()Y!:Ohi$Yp;9`3c$Z3#8bNBbaaN7M`CCp?+VoHa9=U?>WT`ig[RnDp[&jn>0;d_q0M'bGrTL)%/;d>:YWX4aAAE1ds9C %P7W=!OV1t_"L11:KQsYuW9refaaI5[Er0TKfOdn:'n',mM4 %mY])E<5^\2"9452pe49c$H5A'$)&!e$bYn_1HW?U+?MfP+L-Qq+'eb!VR,f(H,7MlD\pb"4YM%EJkP^P6rSdo`.MaXd[-AmitE#2 %&q-2$\\*H2ZLQcP)X:od"U4O>hGf)uX'cfra%979PTMZU7'Y^@$#5i-=?qP4NQQX`jkTlV2cik3q:='8oU!4+QZlXLRl($[@6H:A %@#(S&/aSEl'qt-V.1uh+'H7[4,4$jt;D't3b7B_UM2e#&8gOgV2&"iijY/0mMZ+jQQ(/G]<$P=q'2GZtaq%W`$s?W*@#*_X$B8[h %:rbF2='sVQc1)rk=&0;B@pr:S:.>Gg-b'u(a/%>l&SiBZnJBSbRhN?B'rGG*4,/c$dGh#R2ZkN2b3BC"ehE26aCqg[tpMg %CCk>[KBVkE#9D-ZfTn8t8Ge93=k//Td.I-e@;?E/ef[;5=X_tO'p\5HiZWP>.e(Kq79S+QU[HQ`@;?FZclhn:C=Xh$.G^69N%GGe %,EbEF;.sLc:R17O-t,fV#:X\!9^M\AH]6'_I']T\b@+@jF[nGhPHNAm:hW[d %Z*gn4me+ek/keR-fg*CsZZ0bjWBi2\h=\ZgL^igAK^kn5ajfg*I$.&!:iGdX\'!_ef4-d6VMsI))a*pE:@*19T@&=#qcV;?ZY4C\ %aaLZ-gX&:q.*#fF)C[TfKEOsqq8k,`rhrBE]5rtTr0Q$NB:ImBu8NC$+S%US$fADRDD;PN;h`fQ\`9^FpFYD<:*;hnn@S@8rQ;:%b*[o;)`OpT_\<=]g %W8N&b_i$jLKp-dt.[r*2ShJ[XiM'3]#@YpZ<)Stq2b`CTA!IE@4h*ZITLX$(:C>HZGH9(:APW8^i'C^NkWJStGP>>V'Y+"@:A.AS %#cP*HPIW!Ip>SZZ<38`0.=!W?ji2Z#aW*&rfpcUAnSZJ2A8_S-"A>/04<<8IAFIfn`!nB'M@^<;cluh7aSTeC]l2V$%%BD":'[@b %ZU_GPJfqAKlueau#uN:#1]hW&mE9@=-*]R*RKM)hq/R;>4LQ0t[a1-!5dfh&%=e#EE)+oea+\r-7-?+8%TLW<'0E5@)8KHcT-\@O %/86/)lOrik7i-d6$\%+s$F1LQWYc+UrG$d-><*%Mgri-X*3o(2LF[B[MW@Hq/,!,o(=/-d.'uMO\d?)=JcbD;SP]MQlESZu[XFH` %bmO]KR,cB[2q%&h:_,i=&098U@G:(1/aBq\"Zpaf)4lQT3XVd[)f/Cq=6,%HHP0k_Rjj)cNln=LTp)q2P.#k+1m)?H%f;N2k3cj< %'F:.jMf,%Yj;AY18G5"dAF_oqoq1_g&KU5>+_QF*d#,`gTDOp[>.-4V/m_:WJ\\)K@)7-YO):_NKCHR#?RJ_M-@3RQeYS(:ZPCKZM,EH=J9`,S#^?)V:pQ;jI:.hYXH9p %U3naCm6M?I;0gZ@/?B'=oed\(Qh(lM3e6JWL#'mPa4RijU>hd"uqVXRoDWJoIFS*#7GVK0Yc\mX"MD2>bX %SLYh@dF!Fp1iJPOY9#-#$,tqeSi0jY)l9tpPhJ&E/HTWTjQXcZCKVUQ`Y>7-"/W+(lU>]93@Kc%otIbYGP[Xc9@BHK195!<3(n_L %Va^)e#kGA:Y;'LHea6`rDb#CgJf\GRTtRH>VcV&jWFp^!n\RWNTpUSOktQ]4aCVnj\u#kH1M[g[3#<8s99#d\*=3(_(UimX$Ti>d %[HtE`_m$)*pp,*?`bZfl]j"`@1\WAi>'@"%_pGQX\i/'\:7S$1_)NjiLDLQbP,W8+T35"A17uD0L.SNjh5eY6@B4$>&3GtA20=J+ %LeVbaY-:!GmI=P800<<6oBXGJoNjNd:YVB"9?5$@U@W4,CTA_$^5^bdVH-9S;:+IO\&f:>#\U<5R9jNj(V4pP'/f$e"CKlc)`U^& %SQP,;Yp**8RjN"JJ*^J(6L%h)]`Kef"f.>++?^$&W.H5GV$j#<`-21*lN&7LVjClY$b6s^p(P^%QNd=s[%s-^L1H<0qjk4KZ(\,$U#8f_O_^,tqf:AsXlV-X %F*W^\I@6:o*Vp,5A$rJKfQGb`HS+"`#:_i6-)Fn)"hnHDden_Ibo)G\FH4Vd4(Rm=,)\1"Q7ur3`>k&.:;3@N1$rG*/ZT-m^?9s=HffI%CX:&O<"RE49$qeh5C)4Aa %RX<\Sf,!kbe,j(9EB+Xt/:P6DiFY)?afN?X %Pd/(GFi%8r6r*.T%X0dgTC(RF]OuUTIo=)g2Xb[$b_*Kp:Mm%>\#WYJ/D'"&d4]dRNdY^aPs,M:i>?Ub?Wkk$i>tQ>VRcN7bl-oZi6G^p!:\:-FtWW*k>Et[js`uFX^'<`I&/]:6p9PpZ]dd),]GCR1:L2p)@:qB)XR)Mb8fWi@@U/AYI2AJDI+R %$aj].DhBT$a]e#D(7cH"\iDpn/@g0\?NDZHQVQBYe5p/5@T/:J@;SFhhDf2GPd`V76G?nj`V%H>TXcf+Qc7hu[4nHfI_!]dKga"3Ff$AJR-%H(/KrBY[9 %83YmlGg[EYGLk@OnCn_&rdGiOCb25qc-anLs2;m2KD_JM6db'6<$qsg&E1`u\aR`.5V^N3([7'@U\sg+F-Rb',]NMD^?7ZGgS0C31)p_qZ";5.c^cfXK8-*ZnQ[+B'r5Pe %#JCJm`'g#p$]L;T:IH,8Y_,!U/d %fC)9>Zqn*t-]5#Z_[JZhee_gP,V'miagrMbDRS=kRZ4YQC>/t'_]":4iln^1huQ&^(iubt8f0qM(HV.5NFI%qFVn4T=PIDo15S,n %V'XgGBnaA3D9VbD+sbg,-+Hc.ITK1:<_IIPEh=.nna60pQjC5o.!ijhFt>L\=_\q/Wn;hVP*ZNe$jVo+J]$F!otUELs%Dqs2P*X# %XICee^h)0YXG]cKl6eJ1S;6np>+EEc_gkr_NAEP>gR$%$<%s&@j>)=Y4SX_OS4tA'H[k@,,?NBVA#!"$"MRhjh`boDe&'q=q=l(I+@jFWFb;h-(0V!cH18bqrRorO:Aj'bO.r>SH`bCPP %.:0XmWLUig$G2`!5ee\X=+894C?p$lp3rK#:+rs[h) %mMoqG."+fXX/ruS2aXaBq4qBMW0!H %fEEUg$lYoLZE#:R60"Js314$i%+.&hm(td9eWPBkQ8D+lK^0d$Ufk2*Os).Z/.>hDi3^KEjlRfjfX8gQl_u&rDidK"\;=[d1n0VDX?4WnWOh3S@(e.,j7:',')`K5X57m:o3,C.UQAk%1lh/9hHQMfH/s5iguo %?ak]s(+3#`Hc/,/OX5:KlG1TBJdBS.8d1e4(no\\#9AoXp3_Si5JHJ64[)` %0Yh3pOqLeKS>Zf#!/!&>fI9ZK*e(p]3I=W_D,)E8#;:7K8O)!se>u\[E!$WG.&c96$86S1Un=S3nMV\qE,s]s,^`e*-'&\.W]VVp %EcOiSH$YTAbST#iP@Lo`1f>=Jb#gFgob-L%6R*OH^l^kHM/%NmWqgZ]e+Ei?0o#N'NDrp&Rq25*=CaIuR=IFbgWVTU %Y3l_#2f`pt05:D %P.G`[Ft>M./@B*_1@"0_.jDcF]1.unEfl!G1@)(QdMqn7/\2YVC,K!W25>2rX.?]MRp\4o@qHH8dD,&24@Vt>bZtRcQ.3C-oN/)QM.O(WN+!9YN$Z9+?6+&HZp_%g@o*jY/IJU"Cd %LN,4hAX9C$R&lOq($&8#2`fK0`?n-'_cYK#>t]:'88bU!.jc0Y1rk'6XHZ6GkX=E"`3P&qZKtb""[d++nug8`MtMK%ge,.G-upb5 %mt*#$C'>5/3_O@ZJU"#)%OXmVbl-S8NDn%EM!sdUe\moq'O*AKF?qgFM3*E9]/L.lW+gG" %Lh7i07A"DY2JS`21qRAL2R-nJXi+Y)52ocKm[[tAg0HB+c!lXRVH%+DBR(Qk::#l0r"meb3`b!?E\2J+?[cJ`Mq0+us%uAR]bX6o"e9,7_`ij`,g+"g\J9/u%;t2ac)#&uLtC-% %l[Ch_A&A\[BE\G$Jm6L0f[VN2W*.=QZ1mb=f"22RPiY[`MuP4`i+]>@HElsNKGQ::.1R2db*!^^*rIAR5nr$3=(Io]C8.F'0/<4G %UbJ,FSBAYd5#641c[t"98L%ttl_FUpnSQS&ADQ3&Aca'neQo2ZqfH$nLil&'BrWa#CErAoSMpD32;+E)#EBW-EV2XapMd@-lE#!* %ZVt[7e*S7QI_4Ij)hM)*arBm[gaSa,RQ"4H_KN7aSF]uBi^!nHJ42K'P2c`b5fR&i+ehCM_aJ[M;]]uBi^ %!i$.'c.h-TcP`)r2d),lGV`T!\/>A\2CB7f!"Z=Oe`Q7u:19%)gVtE,Dg_dY8t3.EB=OB:(\ik#pkk,qB/^e.5FRQa&E/)j(Csc/ %O2pU%ToWQ5/-^;XJg1^pl([N:E&O#G4Z>!"/6e*BOfo"oUcbHTJr(;)p`caGBcb17(! %-ZZGD4-OgQ7G"g*7]QU90"Eb]6_qZCW.3*@r93`LdpZo]\$i(->"B%g^b#^/jg7OCe\ %pUO&M@sJluLPi!53'50>;WFJDVLn1,PIK.>p/ioF5k(/X:t3TID?,Y1-^=TeA/?V#%i^U7!#>8%UY %=>u_.0tCgZ9-tN^qnR+Y1;%kgStC#s$Tj*/MW0is@[%<$ph``_*CC(EfXjnRCi>KGKO41HW,QD@h9<$3kbgLsY27NXK]AT_\a&>l %F$O9lq8_Q$G'h9qUX/8tq;><1,^Jp^;h<3XTGE+QLpogJbGS/&G^Yg`#eV5/fCL@9puX^uDf[6>hSod7^!`]>j/(.q>AamuH"t-bK<_^1'^t\X;9XkG-VdMNj=OQSLN!:$83W\68$S#bn(tC>`W2F0N %Z]GD293k&XS;mbmOuY#$fV6LpjTPAjmo)uC)gbqX78H8d_0-.UQ6V,oJ76bWm\8X>8dP-"$.dB!]-,\HA>K\aApJf(-+0W":+/_L %5m4fnI?KUsEcCiG/)8tXK9,7rg*tVOC/GaP$>m'o78P^<#?p.kCg- %lAndG($&8+R4F/fi[]q;R\U_iPZD&tAD"s70c0Bl:KpuIOWL=6LZd7['deeojp=161]UY4BeC$[_U[5_YOhK("%J %k2^u;a1D(dekKr[#i'SbKj6kQSh)PiHLYO9(EWhcahtutU^JZ2AJ)#N:;a^j%8c"oZDh@;4P,Q`VZ(QfVN\4'cs.GKO(E>\E;+(k %@kgMu<-KlT[$F2+A!rX6,eBYER_63!k[mSZ<"l^Yg,#ub3:31;Kra&!J_b.YT:IP>)deb:cOZ5liHk]^ %.@PfAp+a80l2>%]hLso;%_tP.1>0htVdgt6[UI*STGtl`oP4:nXQs4%M4RDl`Ju-blG6o,18gM9+FN'f%T'&N[peaPO6=M%7Lq;B %]FEl*q)=n3O6PcG_2*qCB8Uc;6[jR^;2J"o&!FqkaMs)P7Dd;ZNN6D/\&Xclr"4HJ%3JZ4QHR!KXNA9hP#OQm+nD?B01di8*Qr6( %DFOtGOVFBpZ6)LQT"u3Iq\'Yd69Vte'FpNZlK(gY+gCn@![;H!]u\#>5(ufm7tjmb7Gtg44Ik,`'3mtLktBC?$t"*B/c)s:IH`g, %S:(195R8QC#0[R+IkY:1!)I>&/8A;RgB7?G,uhKld2r'(?E@"?A,pD=GU1d;qF47$^4gJ"6G2Hj1M'_aZHe#,q@]oGJ5.]t)=fof %d\'8j\c[E,Og-195-oY1oJZ=oLbZ"J^I?@"cYO0PnX. %n/5\;he.j&MRIJR5Ts[7I0H*6_[+SV?o%anV%F2lndllM!p=6&7Q@sI'XbsE^Q="*`!Fi:>[>#`_Uhup[Zq.&\[mrVo7"UWNIEUQ %b=an+oe3PcM!sUb#`-fi61M]4R,1JiD-7(B%@7kT=Lpk&aRWehN7Re^QplPgf@oL_"AluZk**I&*6h:#B&G3($3Q9#EZ#W\XDO.[ %$6o,BS\Po^kq3V;]94]$I.@)[n]U<0[%HPUH)tGfEa;MHrpjs-V\J>BiCg"08qe=\m!T6??ZNku0[@O4"j.aU?Z5%6dhlrY-IW"< %)Q234e]g^D\SnKc:+dOm]GOYS#.h:;7lIqt4L^OnZ7s`+)T73I/8IpkZH^#ea%E7Lk#cg"D!><%5ddKf?1\cR>o7@,B?^P)ak,u* %l/X<#YhgBbVQiS6jI[As=G1ACfR!E]oC-TZ[LC*VAKFCdY7&97eeReIC!Nd>-6tC8-NeZr=RSF(/=XNF&s$a\'MXc^A0U'A5JM@D\PMh:K]QU.2cHj^[(MU?b1\sE*fb(pWnDRoV6O%$DDf@Q8R3U-++?b4#l/h_AW %cl;ehU2+-]`MDt"s3SqkE";>fip4Q>8MX/sjWW/hJCM+2Q/O(i+*k)>&!LkMF>kHBZ5VWhkJ93!Y]+7WW!QDAph#3Za#mJLiFs[j %DarCL@.e+hT:S2Rmka5KT\^hU_[rHtLI=)K(`pj1nLYBA/)96PnlU?"i`hJaK$f:W;co![nMtl!]r^M\Z2?X?XY#M)9^S+F$I.$- %m'Qdh6tK4[K[&rudlD'$\(8b&M:k\R``dk6Z&Q"pIqFSqb;h,?#rp%t$Wm8dNblc^;(.d%!CiBCO]smB_U(@e/e=-bkB@COhWgktTP#`m(@8YdaIuNAuM7SoR9YX"G,Bi"`K' %1W.b6\aZ5YraW1'VD'mFSa>Kd4h$NklI-=u?A+D-ilHB.-k.+W2']qo,"h,nbl(J[%1dr:k3MDiPGl`Q`(NUma/IOVC^B7b"2&/+ %79.-.?H4!$^5Bt1 %0he8P>lTfED2)cZiX,5tT0;_N)\E-MVrC0b/CUj_":2r:)5_i/:_oIK^b=4"HV_jMC>;Yt*gq?]hL,aJ,;VgFmDA4';N66q3T)lp %3NWc=0l/[9D!CMR%#NBj9>6Bhq<= %;J2o3@0o/HZdIV&C=:]q\R`fjLSlR8=#X.X)F"1fj1b1p7h+!eO8G5u]lGl/"0T=3+b'dX',dlq_3;9a+aBr:a>U*T9rUgbTM'DY %3]ZB]`FoCL;$F_7.nSh;M!=@9=#m*t4X=!oEC]s4]S87n*X3@6'fX&iXL< %10HQ=*1U8Q\;@3DUkMgl]46&$_X9rX#?]SV8Hr"6NCs-M$#HoCDQ&`5b?W<4ede!e,Tc!u"rhd*T7,@>$o]Y8JW=nKcYN_,`@[JAe`-VdObc\O,&K''\6d9J31=jjP`>@KFuVgO='XaH:lprWmu%*I5/T:ku#iM %0fcZd1>._+eeR(<\8f^/_\l@aI^,O2(IPI#'\5rX`5ou)59,6]N1/1pdA\iMrF4TOnPdY4]^>,M78Y@]7n,``#>4M7RgqD90Tc;? %K4sdEbcN8T?n#p1gbti!i-$TL/=U)\L/l)A1(si,$VH;!8rr7J)l?c/oQ'K^r0X`.0t3`"Ji/!%[RM#g2aW@uAU'@g:U,37?ndk!f*O]&Sbh^`1=CC^Z8F\VUo%5)NPPXS]iHj,Fuj^+c,IN<0\l3/h@'%T/.WH$G!Z4@T\MrP-p< %9%CUWZN)*BeqpZV5sN2sPC7R*21be1Q8H,3`Hi`1%J`S72ATGt/m^)nMr;o2B`LM.@C'%S(p&S8l$+rB9(MPmV+a[lO7X\=L60K4 %.Ed>hI&SS4IASa"@!'OS_F;7Sh^Dk93oIQncBO(Y]FZbN32n`Y`nc'q"0B,gLb3rKne\JlkAZTn;mUrCOChrY@=BuUP>,$]LOVW4 %Ai#rE\>(n$4E!&(d@IA]E;&l9F8pLR,QbG[?)aIqM)gEI9G^1A:Namf:8fM%@aWpa$YSg*M<0$+"#_1l?k8DJc!*N0Um@skU@+.6RuI"%qH76tTBl$I83r96K: %477N%(CU-hjLX3p:'Z]:OnmZDq>$r[i01#[4?nVA.fTM,8a,7?c[fO*VNS]K@*TF*>"FuAU(ia@3/^0,9 %%dmUV4Splgl6\$pm)oTJo34*-+gYrap'%O=50DYFE<)it,Fn7$qbfMo>L6C[?94`o=9gH)J'P`:[eHCd"2<_TW_ %AN'4#&D2+g)q">;/-:ct>sSa',2T0>q`?T8ImD[(NinIo"VqfV&r/ZG,A*s3D]JO]NGilkXnQ\$hkpW`;S=2hp*DIMausOW32^e,rS*pFkFXl9KHrbcL]%cX$]]bbN3p3Z&="3\Sb\BIN2) %&t5nde$#Ol8%Rqdni"FO<7A%pJsl9A+1@1:Yl'hZ%*!@Wk?7P3;h_a9'qUn>K^*VX99j$@0SW_S,gZ>-I]N?Ddp(6Gb5#h-OPh:>&Par=PH7]AF/4_O\!`ZNT4"X892`b\gue<% %YB9o2UrPYfr#rQTHVn=3]AVug.Gf5fTpqkU+6.c:ZfL"f4WBM0?`MEopMmM%?"L;`D6Qh3L4F+1*1Nt\YL]o%rO>&k#52c3qkDh/ %l*X9`=o2/5E$?r_fLZI?BM/Xk)nl$t@4\Jsh/^KW.Z^iCm-qa9$Y,V%-T+YJ988DNF0WtU43H*=]+^sgAQ3bA^K;l#KeoBZ\(Wmj %a]ggqO[;#U9-p\l"S%3+SD9HkrkOJdQ)flVXKgu,dA6grB%XMQiK6_VS+`dCPAQU^+K:nT_bi-`V@"eb)0`GQ"^,]J0/Pru\J1uV %^Zi-;3DD4Afd'7h`h*=bCFG+8VkKtNA_Ce'q_Y-%[^\!V7ScC*G24+rHHIL8\,DIuh;Ksr1?kYm)5`\H'?9rL7J'.CUp4fr7!FQ` %-]F:K7(7WK2q85do$@'YQA@%SMg*ZQiZ#(rnK68Q"JgT1f:\CqD!G18bdIirBG.I-[F5o0"+Gp$V$rLl)[:qL']hm#QJ_^#UZ7Ghg](-EeW\j074^:,g69b$' %U?Xf]RJ($UHM.(GV8&/uqnJp=JIYlV4hS:b^`:=@S3u6)JFkHpBDm8g9?dIO5c/*iMHe]$Q8Pa9E/ok\)>TW?a;4j/"nFOa=[0#8 %:+'qM7'.enEU2\&-7cd>FV;)WoiNf'>I1+=Li`4a1n93=9l$U;-W>q--[l)kEE[AJjD>fnJ54nrF\X-j/O*".Q*>"LW7O5t[8*Y' %:+L4Q==4_c;Mn[kPp^:bXeYMX;M8t&"o0:i8Ii$c.g4d8hKAe_4,+MS-gXM]U+3G%3l,_h:-&RYn6k,nHtb0oa$*]CLFT=XlmIDc %`7!j@Z^)#-Z;obWO_8Z^R.5TTdjeF)#N^M^LcLMlo(%eq)$2I*VL-CV"9G>l&FRXol%GrG4#14Odj_P2)'+d %6T8Gg&Wm#/jlF`,4UPCl';[.4Yn2oD9u#ue0AD8eRPNOiNhYlK>u0DjgDmkE5Tb_b8QW9Q==<2'I%:^SFKZ_9?GF4:-4cEC(Ku+$ %_F-oQ_@B\5ko;dC]?+F"jHMiV!FIKdbb2,S+kXE8`(RPqfl$AI;3Sbdh-mB@90*i5_rVoi?g()SXf&&(PrK@V7b0W8:Hc1jG>aUO %#7SlA9SB;RE[W<&(Dq'?"[P-9CWkNg&3qMJ[OoO4T`@ %g1dRg>2\B1-FsdIm6*uQ](YU]Z24Ef.Po96.!`%'RB!WjSYh91ROYWOCjCuGmKZO2r;lEfM38o+&S:_QUX-,QQ@`pG3"T29AY>0- %s$/M56Z6"s9UFKlSUXs0VUs)On?K*Y;oO_e6P0%:654I-JA\&He:+Xkr_'9/F1$reagNrJ %=PaH>@omkoBe9"jC?!tcCWqhWi=/lB#R4Ejq5Vs[t3a+IUe6Z>C-CS4p:6SkW0=E;B?Vg4K[%9A_I/Ra`cEEID %Q.of?#UV@\O6SYR64f.*0Z%lXGZ_5F4S4nN#K4sla(%uJn=I+AX?0dGiF&hd?`8q]d11tcrR9$PlkKi8qj_5eK,`6"g6T)(b.i[XV.]2ePCj$1B*B##%SE@[IK.hH!CAm/p(c'/L^,18VgRJ9ND";(ZFV\JRL!q,GGk(+k@)q'Q/o3K0 %3:o@U]Lh2"D`Xb92be`ZYc'Y4.F)@9V]`3'&*&0MJ]Y1"Rm4\c1f>2,=3T=]StkD,_K!8GT&]TLuW&'%i`?ei/UWR^cYDcTV. %1nngOeX=A\:53mSiE1t0pl8m3-r$b6)!9N8JsKjEL7`:D@:%a(&',uhE_^\eW7``Te!@Jbb+#Jsj\s:lC7SUOk'g!iQ^k<4kC0dk %O:!ooRc>u.DfjCtr`]!]%@23HA]2[*if!(Q="dgS3B?-D\IoMEBJ+>[`]ScGVKRD9bI_Y1_Igtaq"u(B-YiU43*006c8b''0*]6^ %0XNZSgL];%ahT!fEUH=n5dTB=S9$_n(,b-(aQ6T:;otc@3]F=e_!;6O*ZTTp_>]c75r.."mkXBGK]UX5!&&Rm %!I2=C_W)%j`+pd&"$E?dUfuIop:jEVm1U.,r!SM450ifg>rC&$SAPb,XYj2dT+(qL-7e2Ta)A7H7Q0))JML(/0]!(bS*cmM1mTYFfMEh4cEH/'=lo?,bZe;"RC>3P %^S)3*/V@c)5(CUZObaK0I&T-B[QN@_Ri:qL?0@t[SWBac0AF]0;QTbH%h6&tc'%QdFKK8COUR\DjrtH@0jW>m<;c1F"rnq#mYu:n]T'A+:?>ZE&ORRsH/F`,d_#FR\TZR"((0sRcLgAX((),BLQ:I'YPb\s*6=;Ce %YTRCh#bgq^d)f=+@$A&$b25rLlI`-D2YCfFk+p1]_!3%OBaA.Qd`YZd63s\pPYSZ-&jg9h@bc@O$ijkJ!.dMK(n-*hRcUFqEAcgn %;AiF4X`D-!A',83\nO1AfHleph9#X>lOI"SRe9kIF1f^;inGICEF)C(`BbUE*#sP.EWE:.&6??SrV0(_;e7o9<8!'I:R!7cYpO;1 %dS5k'IlK7;_+R:h1m:'OWIJFsj2M\Om(UiHO-5^NH/MmhW")dd)h!P,:GMb#-Vit=Dld[!2@#4pYLfj*9J4Q#=!-F-s8E421Zubl %-9"VYF]\HS.YjB2@4bBOG_jsK#MQIXBhcQ)[TOV98<^VV1HE(tWT+QYQmukm@N:)NK<]"$ONZ!4`8h2nXRtXH:8V!Prd@E1,U\?f %D6gF7:p;81!^'@\`M%-2S+[7gYV1#]@$%2/:8bSsm"MVR'`acZG^[VFY=Lj[`ZWJEX>g#iLW#O7*J4b?ihF6D5McJrD\a)F_i$[: %h<9K%FiV*JJ9Ts[h=aNu(GBeXh@dEo5R>f)0F&4t^\r/MUphVZRgJJVM"*i(VIM8.Ij1edZYo=cX4*0Aagb\ohAj!7;.2$!3@k8M %)frZ%&1nEc)^:rja($INGW;(X@q(Ds5ei]SJQ`o,)EW4aOkD(]k*n7m3I()]0$Pim!]E6q"2cuu$j %j3p=&@sI#I=^EZf#Cc3uSE/b>-OKP&L)n'h(ig=E5;DVLkS:"@(In#,-=0Qu[p7fDHC4&!:gd5X[YfO]L=.5bE0N<@DH`?'e$>D_ %"s+nUiT(Un!5J:@"`ng2`78`Vh^B/#uaEIRo]@,gqH$M&pq@"5"^!B@'09&,L20$bf;N4%1Z*f`qSpqfFJ!=KF]Xq=^XN,tEY@lX=K?8sRj1:bV[5#56 %C.sjINQEo?gp&ifOhTGYcX(qPtBY? %8;tWO,eSqc,c26(Ua%o1]2+F2\%%?[T'3]+\cMmD"tU0gC,,rnkD5RsA)5t.LUmH+a*\Dg]`=WYa(=YiZT@c(DU]]'R^+b@5M7c,U);2'kEEQ\IM\DW$LC8@FumpC9;+f7 %#$m.`V]2n.@Fr@uN82"d'l`LF?qmfIiClM$JBs-HV$VTPO4AC[+d24q'>LZ1hFpu+poSEtJ-bkN<@2Q6LuVLK4neoh,,fKp=]bXH %eq-(4l`+_D_6mt5,gd>&^cYr_4N1iiD4O_Y)aK23;-Gqti[]gZVM+R5eA[@TBYS)[7l]t?aPFPe]%L]i-Hs'gC1R"M`Eh&`@b+_g %h45[@_8Tq\fGN)"c+7]Vs'aK)]PO%bOV'%Ui=nu8!7<<%$PmHX1@.ZWa=4="<1B0k+cMY!iB1k=nt(.KJ9;_0frl1+ %Y7RnQ;=U\27cO`WFLZ$S,)a4a034$N::$0N?MjhfA#nOH/WU7nYT0H_rF/7g;0.V_!Q1`Bl]J-4/qR5As,DK4s!\C$0I\tT:PI0Y %3eVom@5c(37l[.moHu?`7OeGY:68cB5>?4q+sIo8M&]tdl`NFO^5#H;Z'7QSX0U:o4Z7S49(@*'@Qkqn55HhHSt:!4)*X_(R3e&l(EWL%bZb]tlViT)3\\Ppu2:eba!&3D&nMa^eCK@qC3&?T0`aD1,e %''jl"*1N*naVXfrs/TYlti[WT@@('W@0EEfQ)I %A=_/DqYP%DIm=gq6[4#Xjqpm77HS@`cq`'H+AM`YF)4@sff"L#29YR\kp@olF%hNIWgZjDa5eOcP3JEF@Z5=$-g!DDJ3^9jcS)*p %DjZq;^65?R?:03YgWZ1%4*(hn2p"_,Qd\0nE+hLZAf^%'k1(@E/`2nVH(,G.H(3KN+oS6RX5m5?\`D/?7eEW0WO3o99[H7%0uGaO3p9`STPHKTg50/L?g$ZT?E=RA^88"IC$ROCH(q]ED(EeV*TDCV;D4p$+i:aq@gD6tnebb'u,r/\R%4DD3"N %;:9*h8WRK.M\juJgm;VBe6"0%N(;qC^3m4#L2I8`a[Bj<)kR=Y]N@t*d70AZo\-Od.sl/=]N?QuiDLX2!+k,]'Jk67K9KTG=q3P`0J?^pP[>2Bm(`V3.WoQ %j-43pCgX4/K71j4]^>)=Zq[M)mL*;%$Uh".d^Eh9tWnb\J?*#0la%_f73(Lt>XA;C?ot>8)&q"""VGE%D %DqPAB'EcOGMRi^QQVB:A;4YHIEOFsl!2QK2`28]7=>?-k&E@?#8aE=20`0QVArdj1bIXLkHt#Ls/%$ %!g03C,]6^GpsMfD1@eU"4l++t7p#MDXWo,V"5=hj@f)dT;o7AC%$#k>jSKT!UApo>)o.B*]W\f*E$h]m9[6t(_df:(rl?@[s.q=e %5L6pQ?%I,_*+Y@AMd;[o:NY8T\.h!t4hS:bR/?V*Q]>kObE,01B\uM?L<*iO)pc^JoT4d!_/"V5EIGJ8V]M@<+Q/P>4(RlfaF\Jt %U8R$e_.-i-\5io+LNT=KO_n**'!716;L:9M,A+%knh-0*V!sPN-\4 %J+LHOlXeHb\9QcI*WB:@#g8&Kh:_#h3=_>#'WqpmLD.>LS>.0+oOaHhA'NuUoD-@/\ah9%]l>K"_oT5E4*G\dS9u!s[%X43j?_kr %[cu0kg8S_7,aRYc.=.3@#]I'\q"W%u=rHJH!RiKLO"$.@OOkI*#)Q&\XRC>VccSB]h-e>2ZaQ:W2$_rqc?d6D0W@MGGpe&`^&&?fZ.Co\8k(lai$E\Z+!!SrV6dM8=6%+o''THW'k>j`6#lp>=h3F"B_[#DM66o]Zlmn4_ROIl\Ld %m*Ce8kniZSKi`8$&>JT9)h6ST&/h^!En5,X)]F^WK*D7KE%$AI:Ec]^1?]$_T4+3>0^nS%=I-/LqqBlTnOFUFIII.l %1;!8X^(HUp!*&4o4Gq<"kQJ&/s)LH9R!_l9>PH@r>;UOYqqTm#n$BE^Eb!I8-(W,R4k4Opnq#KAUaHYaT@lT<0###=mg_"C%l)2_ %A&'I)1)HQi^+WNr:6%;:P6EI'I`=af;KF>W>?:`(c5sRVp&.e7n^:bOQ='Nkf3ELHDuK6"&$JaBrM;+#gb2sCqqBB+]K?d)Jh_=5T6CPHj%al'skljn$ep4I!9:_@F`WEn9@-QOY[Y3;dE?&^T>6S\`qT5./_Y>q#SgTCjlGJ*Zlo4*T@N\ar^4>'a3Za.A_9P90Y^E"u,Y)ak %,B9@BU.7P>]\PW*3Z\TOIuT6;n<&em4FAPkeThf&Q!8IEnr^(Lf$t:BDd#b/$e?c;eg"Uibo.,#fd"Ta4)3u))Ej8413k-S@D4i< %J+Ll*/U/[T6W3uoo%SN#i=T-=Ns,3rcuiOi8=HqkrD9Jq[gjd8)7iQLeg^Gopn?fkQVL\NgW@J?5"kgmgrDI0$YL\h@%M/W%e4Do %C2d)d:S!VPaY/"deN,)SM8P+4*-n\$`\,"K7.+gei&*YN8;qYRO'VUYg;b!#l"f7j;`UCrX=G4RQP_>\r01,%_0aZTRJC%WV$tP; %]VtO?W$,fEXnS4cbBbP06`>7d/ZR@U(C7rX\$+N+WhS:;qbm2@;6G7,r7F^'o'8F]h?S9)6bWHpV-_JmpUa)2:FA3K?+B?qV12[Th8[\?[U#E6Y/H/^TgKCeUj"?.NWMKW(q489+R:<._hTM %Nmq,l2Vd2dL[*6qnk`V,;=3_4_S4W[H=I=qXN-nCGCQ/N,lh+4aY#bVgo#F[SXQk+kr\@j@qFnuie:=CIJKR/,[XmofdZ9b@^,TD %RAIK?j-t?HeS71"Oco-"osV@%:bc\[XLZhURB5k(WEaK6a'RT9/H8h[/1if1msAfAS"LfahXCYBdDlM'cDJiJ#s'a/=T3^9mW\-`DM[ib#[\6^OiaaN`6=:aZW=1db$VtecRmZ:. %?FQtV7r!AEQQ@X->n)+H>?,Ig>[M>J8%W^'TmHR*4&RlLKj+DPmJ\k6eZ'R@RuPY0Ll4O;r(3af.`da@l5H$R<2lnL]s4WXh46], %ZR>S?VRYnf_>Z(\W=SGjm?F"L(8&ZYaX)`-9tIph)H;[kajZ$FD)A2YgAO_VeOiY8S^(Ll2&^75W]?7tGGG4AO@,<,W9_"/[@H-! %pXc]M=.d[r^I?GoA>K\an45]=b?T&U\),Z'X7YA+[h;tcW$KU0.ln0jh!UW4<">1:UmbSUMgXa*PJ#G>1*=THVfP@CB(t3BIX^g\ %C-K:I'2aa5hoJ18C!@Zt743@BUq4WB%'.>CkkPjN$mahAE5@)c7(A/!4cGW&/pn%p8;L.Odl-dM86; %\u.?,G?oPhZBbDNTg!3=n6%n+-0n>ig[HLj[W>QiO-&$=#QNa)n)ccQO#V3Us\K`sFpdiGY:B5;HrZup)Ml'<'*M'18UL!"sl$&GtAPCZo %pRbDN#&AM.j,lYU2Q-8k.7Q_nqFR6>'C]k:;S]=#8HmjO74ae-(O5"9KLkq2'9CWn&rL"(0eO!Ap6tq>a1os$p%,5OpoiAL&$(r[ %kHi10'g9[IG[bA-'0^t:3T-Jn/4uu5r&D$+N(#k1?KYs-f7ggi]F(9.nO9TaB%JX`^:[JdU]5ON'?XYO?LaCG%="[$10r]h@fN;% %WJ[<,QSJ@bG;#f9gbU]CYhkKq$W6ZV*Ok9Fb_5'J-h%+B)nrV0s)5tnJ4GX:ouc1X5B>I>L3;Ph6Zme5n?aJg%fhCMpeFhLc]:PS %#i:=5G;9$)D!),Jb%Iq4_&2=YU2%ABI"gVGWlnPW__+@Jju6gNmpQWGC%"WbUUPSWc[?YHQRCliq(sRFQtp??'72]14ri-aNAWVk %Q:LAdcPPV?)jR"sj\u!S4`NI\6$PQB1=FE7i5I1NE)Ndi,6*<%F)F:5S38oi^;X#[2.9)FH`cs+ht_9nhC$m='<\[IS?TK+RJOn7 %O,n=imZX78esI,dYp>[6>p!#oIsL?HulL,2f,k %18YL/'>f@@?9*K3Gb"VprE&SnC1)l&L?bYB=71=`K3fYASVl/O'gEW*g*\ZEfak'O50XI4rZhk)WJAE$oe%W)IB!PA%#L_#8m!k& %EBd/dU87cQ?B]0h.?`^J=q;dui@9=#pKdDPI%lcGC:e*7lfTI.?@QS4aR"slA5*?G.<$;L2W7JdDtP$BakMWWn_uK&Q:P_UU\b_V %'']%j:I=./irh!M,;p;kGN)bHcr#LScr98(]=SAHK],*Zp/*tW;S5WnF)ZoSlkDXGfpAOef/98?O1t'j:T`C;*4@.aZY^$0NtU<$ %=#cJmF/@toRoRM,/O9.N8B`aE-Qg"!+69cC5&KbZn@nDl]d34L^giHHdWVD`E<^pikXIp!A8QAOF.;67"C.`KRhst&a/GkHFllp8 %LRX(^G/\as]NlTlZOY-)i0ZPF]Y&8?6\iTE)OL$a#sCUL^,HFHWr;#n6ELo*5B)m#O2[2*BZ;-#d(0B2WkuJQA9['V,\69K2^],s %'XY5ps(8Ej_5c0]>hQ,a0Rfg[F:hWBpoCqKL3uc=e)\".+*]cQ-hCsp:#T*Pfee^ugZAu=-Z\Dm3-$r:@_(DonQimu?&W#7oNC7u %`_l8VF)\A+QZfq*3k\>G+!$]eb'ja^aB_Vu<':e-Q>\":LFa^!hn8#$:,PsDbo+>gWC*7.goG$+@ek9,`jUiT %dBQ!kh:qa5Ohi?q@^r:d;osVu%fb %]^KLo-0/*=?:G%lR\srglBaX[X_4Wu1#&u:]qi&kN9,a.bD"X(-2._@Y]"F.UJ!`@5r):e8p,'hFuq2.%ZXIhi#KaD>+Q]U_B3!$JG'_5YI?1'R1?jlf$)/M2g%*BD=4QU]rB_H %HlX;UkI.j?H3ZImro>cLA5AA+:A4=d>j[7nP5l\]>9\9D[lK=.q" %(/+\_WR[WNkjsmO4o^@9HciqG>JspJoE#6Ter&o&EV=937Ab]YF`TV4lbtA6*Ja=*a79l/Ah,?]crtta,VQDe[SYHnoR.T=L?,Ml %@th/1k!t3,QWh"R)*!Pb&m4),VL1O %S=&FI+?[tiU/+G`Ys>hihU(:uUD3J?>W9$m9$Pj-\k?Nm5'sh2;e)RqJs+e%H[JQ(rnbRrGD5^C:99dR@ZZ>!=Y,399!ob]iHP&F %fRinloL(*h0KjFuC7T-KSna1M#YOY.Qe=(FiRSlD2NHsuIdfj6eY(F])YTpl'()c\Fl;4r'$U;E`O@8Rd5iBD-;->RjGtA*9=Bc< %FrpH^*K3tCidoU7ik?r<,Yoh'-9bfW[+u.mo1/_$a;.S,h2Vp3rbbnGCq#/0+$TP9>sr/_WUeeu1Z@S_:bia2tp)I1bhgXUe_6Z.<7"Q@!eo %ob][j+4.bg6SSR&-=+&E=nfabS*]cdq)s[qn6^jt\JjVq(G-%l:34>pZH^3[N46K+(ZkbAPcL8K4O#5=r^:_oG;g?CFLCb\=7bn$79.,.UqolVEdme`b8<_/V.^FS.Zjp*T1h%$ %]+s@bCGuB2OaW$e+r7GRDi>?4=sNL?Bn>YTT1=Ir,TC]N+@L7\O&8]:2D5A(!d*1;V\@hm5.akgiU %iL.-+U?uFbP-OsO]-0\G?30%72=Bd;X[P0pHS6a)A%HgGKc-0l(]99lL>1J\O %4*\u_p/JXB66!`f0>RLE@h\ %&hbJO0[,r!ab00O9he-24pgVtMJ\`Ae<<+:P'!)5Rd@uC[peV`baKPIJE4jAQ_kg7AS/ie5o*?'p_lLQAS@9e`a+L!f5S%V>.@4T %^chg)-ED]ZCFS2i3e^(c$_6_u(d(bMe@HkUj,+jId__\'4o+*0=qOB]Bs"MI<>u%L#!"M1ASWVBq2b=^c/\e*mm:BpfN=SYOS %FoBdKo8tE`]Coj-8uCH0jWdImUP)!IZCYW@lP]eWQ+*=YUV%nc\&Y?qG+U;$fg"H&aXgo+=)qZ\09a=X?r*nqW_USH9,&5W-@`VE %>S6aoK'!lcMsZ]k>m/%NBL3*ukpG+V8R?dk:&sEJ*!;@DKs?u"`=u:/X./o!C,#HD8"_HN1&X4;"iJ'%*pQtpqo"1B%*eX5;0NQI %,*QlDEJuXt.(9t$4]W(ZI!du5_r($TS;uDB%E!pXD3SHG!F]YM[XqqSk@9jF_;fhdX20UdPu,L]0l;N9m]sX<."HBrSoPCT<\i+p %u-^WAt1F$l*aLNZ"G3J#G7!H$F"WC7b`@9K0rg+j[*dG\FX-P03R:$S"kKgna*r?UTm0[dMDf+M.Gm+9d?;L2BtnTui:c %,?R6P5E)t3&7^r.it,rt7koRd %,Wa-u+jMm]j_OV06fp*b3j@M2!gGDh-D`4T[?]:CBX/+XPLi`FECb<=0M;RRp'RqnM:)_jimTY$mJW];rJ=K@p,7MO^0X1_WL`hh,;j@Nurq+*I]&,B`^@Wuhj]n=O@_3N;Tdpmg)epu@7$6^+Po,FgJO %TX!0T%N5r=Kl@cZnA#i1>htgc=XPq\PHQc.J7cd!2D$FF!#q-.(K&K7/?T,8hgFFXcdU1l@aM'@"+V#f.N)JeT""5bGY_\h\IoJ$ %')?Os'aSgib%_MUY/t;8?NZQ:lN0;X?p3^lI:9RYd[dE4b42$ok@2;U^m1(WpLZNX2 %_:mb1pB:6Ta9oIsTceG,+U(\MkR9NVi=3s-#TE/u2Gb@fEjKIqNK`21JAt]LTg^XdarPH&i[6#YU.hH#KM.3`Y#uH29A/ %]LNP*:jn@1H&l2sPEg06Nth>m`^dGL2ld*F"kRT%`g-9n\@[f@G097m=5KEn9["t_0(4dG',Hi,`m"P=QhO$jD`@i.DB00;n#^-! %)HP]>d2HU22_=EgJq[?5hQ%IX3S+/O(WcMH?]]-egG0rLClMF1+VbHCcWA;KY*I74'D+'RorrtEq>+L>$t8M+c4u_T"Pf@kR5u;I %I,(ZG:*RqZW2O48VmP77;'=S[iOc]pZdle6C5V4QJgd&\>D;\"NVU#`JBh2On.&0;dp(i1qb[)\F8h^0ks]U*oT.Tc3j@:-IA&*lCKR-gTdI%RO!I:9iGS0L1Y3(L_gS7BKPMb9`-@21H],?6i3dt7`tI]iHcE4l\]?6$[9&g3hY&RXog %c:OB&6L[J%*cL'g@JkIA6^.*(9a(Ih2=*q'r;/GqNaJEF3UGgq.1b7iN:$SOoR*i%PO3t(2VOL8NORHe.f=jA6YJK0cG143fGlhbmK@fj&s[`V&dttHhfErci3A&5)Nbq %HVtQnM-@f\a.(H>FcbgD:#:n"YCf4R^2dEr]abZS-e`h%"V'gWShq3=pf#e2a^<$TsP78WSOqmeCR;B[T %_0B)8Ct0?Yeu2Y$6KFtm[A`_5ZBF3cnD(?oXO`GL_4eU_LgE&0$&^K^chn^c:0K!6R+]pSjiW+Ek4uP&_9O58GobjJ%UZ2@YLm>@ %UGP,#ApWj3_=;%a$a)loQ(Qn&#q-:2j?@$fmFc-,$Q1r:6]mlD7g,]D8=Wd!D55+Ggnm\q1[X?A,S`=Zqs?bAHuPN$3W)'@+3mUF=52K$JeM;GUKn64%A6Le_=_$m$m@!agsrjjlg/38&m(GnCd]WmfiFVm44]" %."`rSm]K_6A:sJEk3jg;:6P.Eo_/#4\,VALamJN01/b*JCIhKZ7_c_9s4gji-lbr+:J,0OtmIMPhUY2Nn %:)C:Z?Q6XtXg]J2;Z@[`>N,la*4@DL4f$!n1TqB:W#^B6fOX=Bp]p3K4u0tI[?GK`Y4r'X1kdu6tj44D=)K$ %Gaf0IJm>GH'X>JX@8l""Rr*MQoe;K:;aDQ$A^.=!q?13m(0j190Ta4,6l+P(k]NgH9R#/`F:aC35qlGC&fqK[6-sXEo/[.HWuqs8 %p-f3pXF`,tPAI(IJCQTlS:LR:c.DRM"\rqMfsT&JQp\/Fr_n;!8E[+Fc3="DreEohB5b"I<=hu9q/DM#JUQ4]PP.IPI_t_XUJ"T%5;iA[NMP4\qc16A?&]22l?2 %KmSiqNSd'R_ECEI*_p3MK>Ke)F8aYa.1"''=`r0?F]rFeGGpcb*]a%]4h*n[Anr&CAM'6AeSK)s %+\pmY[^CjH2AoSj>%+/G[F^D7L@gjHPLV@lK,#_:bE0r8e@m_udKD$4S-!aYH72Ka5>CH&dI;F+p[rsopEo`U.!?.rAEHQBhTA$c %U=b%>gcsYfs*sIBd:K&WnkMR=@+I`@1>$=NZ)=0l9Ak1nWa/5rh=.m)-ImR](o&H8Xk+u3@@Q=/9)>tnEk4sXJ>1m].aG2&\!"/8%$:hmbH-un*Ymlq3n5^GuY>(8m^u.3$F36+cEfI#EY-*)f^)0cBSD3WqnM%)7iu@fuV;)WqiaIaE1m`Ejk@&l;.Tbf5 %gfdG=RV(.UDZa %opV6,-pjI_d9(nOrY*%&d3MHs'u6mY!X[!39Jkls1qd4K`Usa1"qg56YH9M%=Ck*@u\O %j_XnOVFFLcI;D#:D5Sf>4-eFVrVSeOO?2qRp\'miKO'*L$Yh^$YF(Qe0.Abh&ZWim''siZjo,#q1OO>S3QWZfcu6Y0gDmO,7eE1R %mPZFK+:RHm?eoRZ/%0H4H#^9PH[3(\B&LG+Il$hY>$uKfq.brAW:t.[1tc(2k,Z,=YpR1Z^NllI(o80PFIQc7I%u/^\Q)njD,-HJ %#5"CgY'$1T$AEQk5'fNqd6rB7QgqB %cY^VhnD`2:EDk@Qh4?9ji1#2T@e$Z\04?g9i).M^EGQ+m,?egj %!*bO$SIj&XP77^Rah[g5#KKLj)8'1gX?l9tR^M>Ob8S97cW[a>[Dg&/VK*KrjhnMB%n$BfXaJdPiaKa(9N1Ljp)?N@m-$TTbng+G %0HU_G7C0l\hYiV?!H_n&]PF1]Zu&n8C'lb/'tttKDbXXu=f4j8WKnK1*rd=PPr9g.YM9CHH=*W-YS;XOh?UMU@+4l3RhN+3!h8,O %.:)6s&D2%md"/tZ5A`5-9fE-C=[g#M?^c"!*<`7?LNcAo2I0b,4T?T.((h\;+'<3i(S'BeK;or55B)Q/8(2V*W: %0_bVE'rSf6?k`GqRE/u&!ZU/Q47ZfT8dVqk0!^BIfMfu4MnO.C6NZnaAhcV[ec81?$?u5nO&!^`A3)S\7["S@(ha?J(We&j6"'Y. %fY&Wt7L2Zggstr73@3)a(nq.N"M8m!+Bf#$fuN8%!XNTRkJ`@;#\WU,ABp<^BBH.&Lt#N^1$8kWU%sA:c;%3qlea'"QhSBXGiama %MeQ0=ZE-04mo?E4Nml)fj:o=u#J2EU9_Ruua5eE[=I++_&!(fJigf.-RV`5!$GaQ-+%C2nRhhC/fe/c\FB2h.:Rl@V`eNkATXV)> %VC_lfm?mhc+E%'!_qU\D%n?T1Lq"rm1A\s,kHK'W9*MkJaDm@>ZCN,)%QQ.n?FLU/=s:qO3r:k@agrq:p,.fc1qRSW`1/[f\TGo4 %_2=3U\V+4\#;Q'skNCqF1;PIZ7L?\:=M=OE@J&'W=i2Xb$(-/fQ%m[p"A?:6'Kr`6BPTKV_FYD1TWQaH92h?eLpgF?HbdrRr8kL" %Zo,^(fmg`miU+H`F]MGn,.V\6PGr3lq"C?:jj[4?TX3327,j+hN-UcId/L\YanGTHqNo$QNMX_.Qp!]hJ?Lus2:bW0!PUslAh:(g %^)#d<%BPD$!3J?i^/KN4d_Ri`\?I<,O./$2-f__@1Ld1/c*o9W._8nriJ5ba@'DJ#Sb+>t]rR9;80d[TUjao@Z.$ %WTcEtc-D_BU#lY)n-o34VeCkGYhB)kRU$Z\<:Wp)f9+*.%ZT.%_`:cPOMZ/0%>S5'hi0/2=28>^&r.DIHd'=/f?:PC!$0NInn;is %XT6^mWcA(IQi_2)d_Vci$XmX\;8WmkK/Ks81'#+eX0?KMjMBlXqKhZU1*P*^!RGsV@<1=]N'^H5X?0c\n7"Po\uTl1-SG6XA.["5 %ikjDMXWKtHj$AieVe34VR03N!>QMV)Likj,APO"'!A\KsdqU@m+hsIF[YVdDV67s4AS\6<8u8S/;V=D/8u\k3$ethC:;D*g.;Mn02+56)l/mpZo"+=* %ktWl5i'hh/(OnUM<6L$qA/)"n@O1k-kBO"WJp_3EG!]UaS %OP$8'Oe)OZF^SlM%:ps*0U2=HqW&jTO_r4'AtO/4ro`(Mn")6ZDH^6$qCN1f%JhM9d$fVa"S>V*NMZ18&7F&/!Nh4>+e44S>'On` %U;gfVOY6RE?`\nMP)7[Ad`)X!Y*9)DVOTja?"e9o:_o>p>UU3#]H$[4T[79[f?3%)B;ZAcB"de.NSq(uLEBNJ'^#bf0(dEFV9if+IiPOQ*Z!,IHocG;&746)dU\HFZ(Jrl2cDK;E/>'^0^ZNl5[d`R %3G2_.?=9q)g)2L2fae7%MSMkfKI;`%=iAL[osr[g/,Wh_0CN*A^['qJB'/mC5Tah%c2MbXIWiEWqY$(u#:j="Dt0#c3HEEe)7Oc' %#Du"W5p`cnOG\u.iq1\f")52UZp(1<[$O+[]RAR#R]TTdcd%.!+hf_#0NM)=MM_j(1%Co=(j2h*LA)gSa>gmMLr8^!8oEos[\;ap %8--G]T)=%*W#S'9n`mWo6i`pVn^Bs\Af1WCStS7WrcYOCMrk5+Se3Tk'$.d],HYuN1seTuG2(`Gj-dBp694BKrTB!0j68#e$0,WB %c)QPn)=J:"NGi=aW\_[oL/FSm"59R4pEre,_P#.a%3W62>-&q^/Xs1[pZ>N@_hl1SAFKI2LZ! %Rt4F!/T_h*Af+-u3NI2;:pbRVIM`F[8su]U2d^f7>,br\667pJe5<&GLh7f/SMF3gZ>h\3`c[>2XBAp?6UP^.c**R;8#\O?QPEc& %K)7=Jp@0O,WIr58f-m6(UIZ?DKDb(E`$er,qZ-I`>/ebPT12X,>g;H$`o,inKV\bH/7,U>*QC`s7/ueY;*7tPH\_,D9'Q)&FX-YS %d@JcV#MXsQS,oae>GY_8.hY]fXnc*Z66_3m83O;!KL?@dYgXP7cK2I3BV$7nFmUXOQ#(;9Fh%+M_aH&j#=`DI0Br&]Wm-('G0<\=<_0gBVSuWe1Be@Z)qsL]npVEqZCEB%= %q<)/aGF83Vq>%F<6tYQ_o.Z5D9:rgPGD#M9S#>u'lLZPQ:jmQg=%b%E4c_lEF9R#S]Q*0SWUh2EPgFt,S %gJr@Qh7;5kF=#7^3fH.FEnHZikUu20YeGSa4742ap"2^Qg[>u%Ej4FpY&i57Nu=;V9-rK3=;+Oq`>?Ce#eDJ_NL*0\F*Cqc2I;D^ %Bq5[n8nIe;U8ncO``lQq!E)M3'NhZ/X5m7cR+h31W>J,Kg;_3G_S@do.Kr<6QT]DdG_AoBeL<3CaFnJ*PlgheUfQZK>4]jN'H$5o %k>G^d/'#.Z4L-kpd-GPL]&$\.\"=%D?_gs;kH3//AU\fMko.q#GT",>TPr>M+1cJ.I/t(kcDMG96fXnt?<`,*A@&(>a+lTpM*L'2 %n\r'*7INk+q:f($r;;Ng6*BudoU13PGg_%j:kQ*^!GZ-_l)ndTm$SBb15OYn"-S/-%d5KqF@!3Gd)f(6,"f7$>$7d"U$.?KGb2n< %:3o>)Gi%i3R[H1Z[fQ95K#&+hm\2)OJ=bE%E3>r!M84?WS:(S)M84?WHt1UP'D=F6j*>=/*++%89[n5t85s,kaESbPNdY3JT![(8 %?hWRm!,:J=RP('08/omme$`-\J@+i/li"[_TU0U[&#KUl#5$oqoCe %GoVAB<8W9((0c7NT6k'6:BX/N1d1251$*Ua;h*Zb,F?s"ATV':,S='YURM.U=^>9%(O/NF<`a69Jr)NS@npE5<%<$B[f1iG.m`Gg %WE%c8DJr%kAAuA4XBFIqWAOAqB+gB(b@Vf$@qpWl4=rA2K24K#jNt8u"eY.9.E0+Nf,%@(I'P+C-\>.?X)AW':\aM.oU+Rc?o4k` %?["eH1(Pft'm4PJa.H'eM?H\)mP)fIq1F^fTn[e/lbC`-\6>=%7`&o>EL<:,_#6O3Eo?n4`kZY@,JqTlYB>s-W]0;SW6SNd4Y8I& %]e(LC?7Tt)i'a*o&\AZddJCl-_a?/qb*kF:mpXobJ,8u3PgGNJgf&"1s %DG6<\cX^pr"@#o'j&e$W-2=GPk`*g1Q#P&0]9Qqlf$N+E5M51\2*i`#:CtpuX>h_G1%QWTDj:f1frn"4H6/,Yf36tUZI^e('7#Q. %G_a\.F6lst0+B3mc8@b83@Bo0[.aC7/Rj&3YUJH8mZLeI)`l/\8de@F'!`#HuKbCL` %@!+2!:CA\;E.-0%lfBs/N^ATR-ZWFY_t8eh?S"mE(urp9kSRUs$?+lKaX4"bf)I3.j.s"nYUN&ZjQCO=I3h;^>*f %%C@$4B?[F#0kd$E9Bc4Wp`3'RGIff/"UfWH$mPr!W:9EQ63DZ3H7:g&Qe>.liOiECCf"a*63U$+&S];7oPhW%XIQC1l[#Qi3IA6K %moeX-l>(5V^,?J"QYG'cS&M,"QTpHm0O@UjID.RhYHkRPg/(D-OcbX0gB`Ym+t\^VP2:CiHp0O6qG(WS'e!U1%]9R %UNi.77N]X63/RrTNf[[3$);`tDm+U^J5V%&T"&;#LkH[)[+!DVZnU93R;_5sT+D8O,EPU'Nqj1C)ER5s>-H2#Win5B<+YLEX %L06JoYq*\2E3<^o3N1st\Jj\g0>VQ6b$g\/-u;4HBrk?/!d43/e6_7!ncuH6-BbaEA!6)e(3L%m58)?*LsY(iQ*Nu %oF:&OepMbT31TlRUlGq!h3CqNF<9M>[S#d^O.mS1^k8L?+:35lQZ!$jaTP&4XU;r1LSAI %%%"A;SH)X77?rDC*%nCIDdJKI>#,`e_FT1+<[D"(ljZ %Z-8%,VWiO?lpfV0;k2s;@$qZ5bX9aBc8);A$Hm%LX6pZ3$=%nTYT/rhEPR/f]eWaQjICO#AS&3l@lT?4*Z3-&"!oSO"/@ka,$iO] %78[C#>)ihWF220Q;6C-nF24l`0@L#5F0%bm0U`)u)%fb00U`)U^QBgg?o/)s?cc2/0U`++XHVak?o/,4=sqMc^h=2p9Qm[c?lSq( %rF)__4mg"UTdB9S8c*7LHFo_nCct6l@X-WHoY+3r$l`Y0$)uDe_hOPL'UETm!NC2fYg5PM$C"6lKXKne.o8,QcoXDSIl#.k"^5/b %+=g8(.<&a><2a4T+=\^gmFGScUDFgK[Kd!85NRgjhL2?q`I+<-:-d0VJJ)sR;Yja0EImm(UB:Vgf.%"ALf>"rWQ1&-`3ae:V'D^U %[%mm,(O-&=aO70&OS/7,,B-*3X?:K-TVdJG"!uq.3Rqn3>TeZ_a9QP]Q)+K82*HJ+QOI[h$BHPFOK@o=%nhdqV?f[h@Em:/T!qrG %>!#-G2,i`!f$Ij+$V6$6;?1EETL\rg"Xh>UUobKc;u7Z1L7,0^R4&m8Pn@$gS#`9K63djRD\iN*5G/*qDkh5"s3sBM?Ir^1#t?#! %G!%kn)+>2)Q$Qa-W`1%()M]gX9G2G-Ji3>3[uB+[RhCF\_+%U:qrkpig[#jSnq=oN=82fP\ %ci"3Pg>*Ut^\e$NV?a94^?(r!cm.iJPUJD2ND5rpD?7ZF!H3E1h,QH"hR@DAm\5&6!4Qr)OadZ;2^IB@XJnrEE$H(+Z+BeAIC[(8 %qkJdEmE`E>-FI"l_X9;:_CQ)BiOg\DW@kjhnA[9&TbMs&pn\#ET;KOPJuOsZ!.fHuEY0=Eh>j4TkDZK;pHIVqGAo6/WP %l/C'Oa"l%HH?KBBF3Z;Q*a]%SS2U$F1[qCmIH5l7d2&D]B92h6\:n'3FOHA!N`E`2>Bm:[pX/<>XP2l9b$KY[(g&k\X37p:J1m5C %pJ3DZnF%3XrF3,>X9Wa3pnoCG=n"T8?c3?Aq2&Tm/j97&ANre$Hhgh2Si[%/$fCKg:T8@'fal_GkSdA<(#([QcPGcA6Z8::jU(7t_UaoL=9&44X^"n^m[(Kpnp_%9M\04u%J %71S!^bRM(B837m,P&#+@IC_8a=t/q?7b@AF@)M.mB[*uDGL'paKVn&EHc=7G8tASDVt=TKe>rN(/.YUUXKFK4U+;4nF('+u[kZ#9 %L]u!W8>J!F`4iCskKWmV[jkKhYOf0`m8!pZb\A[(A[T&ABhA4Jeo'?,M5'64R %C$O#9=gXW`fn-D'\Q`L/YM(ol:J@KkM5r=/&lWgfp[B1^ia0QE"-d[)O?2ZV[N&iYln!W"u+1ctAbG/Uc9Yg)!dAA0n&9 %l;S/=/=N_:[1LRa8mIWr&Z%GU\oa$,;PdQQB(<)1V5kAP:9@i"26%tG`96;\/MO-U%3=k(T1+eHNg?gV:3@(AChDjAbai?n8;b'da&VD0o[a8k4Y=)fZVkHJ5V=(B%^Q!r>?"d4[]DkSp:eF#h]sj=(=H?e$tTOXo".$(9pkVJp;qLXp\3!J %c[4',C(&djH;F8(HT26I\dII75W?-duH"J[#!jI5UI'V/I(5Tr:)X)TrNXQ6LW'mTdo*gN`B?#P'OUn>N>]Deojf8).gI+44rFd6p:Q;3[QJ9#qt7bZ">c<%iIKfIkH;Gq);^ %,+,;)g\QW"W?V".U-'/bNbd)7<4#/mVT[7`dAC!L(0c$jG-s9$0?fM?8RAAUJd?hjH/f`d,REH5X\PQ`YY %Su4WC%IGm/m,:?I_P+[:*;ZJa3eJ$HM8Lk]:_qW^06qiqa]53_pN]j`,sHlo4a7rH1`_B69A,'QR_qM3::p)BAuATm=Mk57c8MhL %\h&d^2k]9/n77lNDi/FVndRYcg7@GQ.F7OcL+2g@;ON)uAQJ+IQo70Hf(LH6Xub:o1DRii%Wb=aORQb0od9]b_t@m#VRc:H#1T#=Jgr2uh+j4OrJ)5DF1%hg^W-ZKjH4tk:k8)[<-3%qr#=+O5]idL""QAs*X %H$\AHkpSRF-tpfpVk_ZnCEo"&MT\ItEdmN$jTGBiCs34u@YMEh %p+e/W8A@5hPan/Z?//^9K"=>qn!^pIX57:BKT^N*BOLIYAl'><>4Wp@nuUe2#1?\J#^0/dF_QgRo!2>.;V&+kjMo0ZU)iq,lP %l[E`naGm?lV8hKDJt/rs=H9-K+WlUq:**7(Y4S:$=/57E]i$N??Sn*t65ciU5n2*SG(,BdUKU1h1U%i+VP&)sKn1[j#>s``_BN.k %XL(U%?>g!r=3UMF2qDW1b7i^qk`d&F9!,/eNMuJJ`"?_(_b>FSLt)(Gjlo8Ul)?QTO8W31DLQI[b[,"nNH`]@qY4,"rTe/-Q5 %jra@Fn.a`'E#mL`.D'Z8=W$hg0.Ie7ic]MVf'dtQA\C;CMO!m/6[:Sk4b%H5rTu9AT+Fs),Ie3KXk0'..hq7Cf22M&`1<*a9 %hrgO8nBsF>JP,92OkERp2QWc%"3LjPa*^\rcQn1)d%T@s@N/%E%\87b1\-_`IZ.2R+\CRao2ca-M %0gF?WAn]^2?eltYc*UTFNb+S3Y.+dMiF8jWfSZ0>^A?)lT\RJ7M\.fjU%jE,.X]-Z>TTSfjOiH=R"6X8:$-,VYeulFQ9&.4$S(7-_]b37Xgh+gKd)OhOdGo(K_ej?o-5pg_)K#rLO@1ke:?QAkI&f)] %-I'q=:Z./Q--b-?S%_cGn<1:rOTM$@CufG?b7$=VS!CXg8Y6ah:5V45Whe(R7r+!4EE8%8d:Q)/TXus61RgOQ"#R-u't)8;"=>9* %8Wln9@cV-NXonk6>/R;H?Mm`:WiR#LVMAfi;X4Jo&r1Mi8eUo&kN$a,P$_LY)%?le,eaIMacfb9AHogSWk)^EpgY:LZ:'e!ns.Y8 %A;MG6pQUnaac^`1c]#s4OsP^5FE>OlOsP^udk`2]93.4nb8e8_:DdYKZD:&-8DpMZA>=H>j`SZXI=gWi'm7W]-<\u"U3F`I,*C>j %5fH>M@@+'>c*+9CQ>B9"qtt3?AB>^5g.YIfac[uRlrY_%OsNi.q#04:OtET;j+RR\;p6imo%;=SfFZ@Q^-!1V?Th4,)d49J4Sbh< %a+dX8r_KJgoOkpJq9[XTifBu8,q`;+'$==;l\?"Cs7Fi)CKNj2LDDVg=%^[pLC %]1=3S(h=D\,XJ-CYl:n?i'i>]cFDtWIR96';OsF*1Q(D%l%QVeWE&]&*O53'XDiMPke$('in2u83^jRGK: %-D#48%.s/rkj(Cd5alegN:%L5))kTZ*9^"$Q5i+\cCVQ+@`d$CGr/)&XY,d]mrFQO[%Ih;@*(j!jOWTT[,_Zf4i_]2MBm,e>Ki;E %!Da\R/@G&>gXbf:GftEKf`LDZVDl5RpgV7pW=8SQ>f$E&3#-4e2LF4aGgSA2B^UHf`dD^U;ZR_iPrW[]=L/5HZK%:u%To %0B*;`V3d\+FSE.lEf_k+B&Ckths3q(?:&CCeu.ENf:8=TN3;'!Rc1iue!=JI,BhY_i1s?"Dtq%'C?MYJMPoRc?-]5:1-*Lb"5>T? %_@pm-W*\ZWBt468aW!`Wf)$gG\eaUn"YZKUo.,.(\D=@RRU:&@m(=S_E=ho@Nq4k@EM.L"+4C'*=S%:k%cC!>Ob-FA3HqZ&LL %ajG2VJgDO@1`!pE1jBbSA,s??K!O*\?GLt)ls=*eL`C`$nR1Dj6KHL+8_tH0%$/cah6?Aha+!s\O]7+4r8lVdiI9K[Q?&_&f^[ImR#?WL5t!m?`7UrQTH\ucl6jYTu5oL %gr4EFGk\b`0I_S,I:KAALGVI%NG&^)-rLMU[VCr]sgTk?,%+AciXGqt3`D(E,ZGA$fc[T181nAL:Tddp8moX;tB %`O;&/A)k^M>?+Vt_X)Fqs(uUCNbns34^g#EH+'!%(fG-RBf\/T'\c[P)tSte-+9(%6_`5A_KR;IKkjT@$@N[DXq]Vk'+Il4Cb%W? %/;@bEYcZ:N_I&$ScI_Ae[M>X&97^p`Hl*amJ^MYQ:""Dsd'iK]\C)c+nnfn_JlQMh@A8eC@Co+cb*qK068L=Z"\k?.k+gU1md-lM %gBtS=5r8\]3J@b`5r8[rD$<]P5r8[rD$;<-Vq76Du1,rpCUY?$D7q2,_W$B`7Aool[Z%/!"'<'6=>d(*srTF6D/7U %]D[Q#q^@U2SK%tK3#)3?nt6Pf#qRiK.hrC'8798Kgs0`,Ak* %\^p%^.ns^WT%19tFCCOrK5IILr"1l:gIfrjgQ2,H/)4M\?q.HTdfpJIAH-*m77)_Q)e7Og5l$H=7emqFScZ"p^4^R\D*)> %]8u=)_UX+RhgGX>$G>arr7slI:?HCXipT(:1F)2S&GVF+:O\RR#cD0g]D[QcZ"EP%(#gD+/e*mjPiJckFFVIKU8<\rf'2ne,4Zm.&K`=$/+d>-s1kKQaP[2=&]b%OAVfcFkkK0[AB$/Ch^k[A=kYprc)f %eAYnn`e7VK9ijiq+R>X+7YF1P"`^etE4GL\UGPnuhNnKb&'.*i;BX,&Z-^1f!\bZ,KlE##!/q/sEo8Dq!/sE+9M#>F#@&h4]1>nE %Dr_u)"kI`52PGHmY+(asWF;cK[Cp%[=Dl9Oho50Cq[rqi!>c,COp&Sq*dlaHnaLRj]OR[%HT(P*gZ!TO0fBHd'" %ab,i^*>"9Ia!7q&?=,Om8dCjLbIea&j<%QiSb5UWpUqSU.gu'j6d.*<X)jB(8+?MSk=V5dRaC*32p+-":G:1X^NK %[+:T$&,N>62lWkc^,aCdKpZ!UXXq]ZVjgg%XXrZ6,-QQSAn=8s6Z)u>c,p)+E/9o.dE7%]`R*0_Mf6=X,A^r-]/%=KP%\Dqq-ror %/EfQ!KG3FPZJ=$G.%DEm9@cN+k2>a/U0J7tL"k]';(edr)j,-V*djsG$X2`,c]&V!JdLH6,md>.$RVfDYn#gFS*727JiOZ\iFM*+ %kV,:S.8Gt_Dsh9nC3Dl]hq[$.oo5H_k*t+a#_&9d(JN2IL5NeRHCtgI>Z#+'+IA]8F'&2DodApD:3E^:$Ai3i3^[(Ds!kFfa(:Vn %9OZ,fDOBG($*qAMCV@SpDIWe(\'Digcnb1Z;DI1Vm3C&>LRZ#qO%@:t,,J9+UrAMU"M%E5Ra.PKi_O-J7Q+#3@+L[eRSRL9QOU/:p/3oWs"/a9`)?eJ?pTNp(4KF^,d^rpE/bS`aH4`"goDQ"OG1Sa`Mq:U4!h]"FgV;4l>$2n<=Rj`M6;8!FGn(c:`*Y!,IkLBaaIio1gKQ?B,D.Tc/RnWa;KB?V[(QXRggJA%fD %Ep/,&p6M8P9cVVkgB*,R#`$6]d,(M&3YTjDU[9XT^GHEaqndHkBR;6p"[>dj=:%L,S*s+TI[_D<5fb7]>'k=AFR3E8#..9'Hd"(1qtPBK*QY5GkZSt@_^+P %G4gU'ioXXF:34$dRR;OG/)YRSV?^[$[fUF`1eVla?0%MG8%/P\3csfupg*5i9J!bTs*7H-t@\,d>T]"^IV+:'sEYhMrs9lp((VSg%cGH.c2YL/$n\<%SK?0AbMmY/smYR"u:9R+9nSKp;c6k %[ToT.A[YBn%Hkhd3OK$BCG-g?E5kLbC5XFK2!LtkRc)%E=#A%lq_?BYMh2Cql5)A2i.$i;&V^`!10\u>:1;C'S!03N2AjMO@1J-A %fO3X-U7\.]2TV^Gpek21k=ZG:I)0J$Z,NpiN- %&C/AaI@6LkKe2)3L30Q)Jmt_O#6'HGF\\ZTU+k(gP\S5:%]XUGV_7'B00qMNN6L&rnA'V"'=8h!O#EE5!Si2pd4]mI9`LQgWK&Tf&9$C$L\[TkY`rd:BMd:#cBq_Tp %d%nn+D)l+lIggZ?/pCGc^\-@.\^8>boX(,IIcnDZGAp'pCDiDcWD^@<\\$VNc:bGfdW"ZkVmu&S_>E?;>XmUk %^KjHM+&s[/ZI<'bEa50D<_isqCNiUpL5adBie.6ilm.]ST@6p_aN(o3&9kn3Uog[,XpI5QB29%i5]ZUDO;^.6ZQ:4>;`>uDO%4fC %<]F!)e^IC1[;sW>BcCD4BQ/cNWr*X[=tjfo._eEZQJIt',eldr>;-;_._eEZ(4*hGbAWNd-[^\;4MO>Q<:F3ojgS^e8kJh1P268*Uaj,JdT5RG %W@YeQNX&?Q<)AG/AJT[q10Secg\Snm\R4KYGY2P+X;J1OA#pmTBpW>P4P^ASi;MF(qet4B+#_r=6)"nJD>Z;=[IYD`fC+R*rK82T"h9>nDT(I' %i,2HFpA6*3:UL)/$YZY(g+9Yg;p0ZmOc@I(i];QST6'?BZ^ZF`QJ/Am[8;4KGeZ,N$:qoM\l2hVfnQJ9_V]B*s4T.oborEq`*s8U %g*HC=UcF[?J\P)9hAb'9^rh5jia/fegq;n'mI"9rHRRm0[,Z]MO0j[g[Cq-RlQ!A8p(0@OX!R^&eO8;(C+7jVJgX59H\fibde&4d %&=5D1\T#si&38o[H\fib_??kap(3QNKVtL=m%L&>YE-SlB&VdLhChZ3^g7;AKd5B(jsc$*RiIi(Id(u2D5p+]m,&%<+ID-!aj/SIYSY'D+5:+?'O&s %UE).3L("!HN-,UD!DeD:4(,I\V(B"brg$p$I]F$=_m!'5&? %]_n&[Qrg]/?0pC7Et?$I5\fGJ6OTP,D6m=F&;i4DOjA!@ofB6HZ@f&gjuo9N8q%4g5A9W*p&"hRd*Wg`!%T#no"KS/S9O;C0^_V$0RhV*@0/dA9J*PtHDQ$r13$S9-BB %@Z"![_VD+0!?W\<.Lb1TalgO8VS\q>aAeP76]uODN1RilHA_Q;FMA+*Ks@dR*@bI6-o0g^(o.@LF('&.0>7i)?h[LI%$'_i,b,6P %?+aT<5iT=.eu:?F?Bd<2&O/q;7HVHhVo$e>(,m$V+bR]!jRBP@K:h+TC5C1(F1YflQ@^QcGn.OWHu@$N"\AdL=td/>07AdL=t@-1(Mbn=csi,u=VRjHQpJSD'e %'[G>'lUbl?q.3nmK*0e[W"]_Qie`idl%Q %-^8ie]R]u)iW4ue-m]pRB5mkIM$Ga)Z1'F:i*YK[h]j33oSc<`*_`GMjCE3hL^*u!S>=(*Y]NAMfSEdoP2qdW4UCPsq9XXg\8%8U %o*7E"6K0rekRFeMemmk(bK,8U"9LOqj#8lE%cT8"_W+f??"7fIZ@qr$J5O2D1oTa'dE9IL)FM6!mbPqTkYAIIn/(P`f1nh;A(!@?9mSI'ZMMkdC`&@EkYBVLQ %SsK#fUo^Rt_RNNCoa9a,l`^(hDlkTm6OLOuYNkp&\_8ANZLja3AZ+P%EJp59i3rsc?2V3)GAhXW\*^j:GH,_:XCdFHgTNg%TK8c( %9^noBl>/?(d+KK\bstuNkl"s.;jFsRpSGS?KN\)P&H8P0J#BO>6Bg"XHT8hc^g4:PRqD&BWBf(:^M3Di;JH9_"^&T1E#0#G:`$35 %+*6sL6FVX/`0lLD_O>'i6ORM17)]R7V?E)RIOV.*7Zu;saV_+;h5%NWTNMn$,5VE[o?MkWIL0^C`WT4@+MVHhqH+A(SFSY$Ipl&* %Z.Pm]q'DD_RS5EOL36R,e#`43N_V:qToVAn6jrj"3T4HPVJc/e4d+lm,4A-Rdqn/JWGRUg)\Gp7makUpC`i\VUZ[k%;bDQ>V+1k"'2J,*A?Z=q_qDp4VfofpN4S-ELP//eV#VeK`Y;Pa\I6ET&mV;K<\#$Nt0oElY%MIX.YRq\7Xk'R]R^m/:p %/eXdLF#E"?ik^^Ilc)^niCQ=[NC;_B1gRtoTG7L5UKL]f"JT%b-_;HNj_TN(7C1nYP:2q9(-X.:0^p!)f#5lpQs8M!.aQsQuBi4%.*H3%d&IS#U(q\o'n^.iD9qk,R1uG,G5nCY,hpS1!l1*#0$(- %N!^^_n7PT)C\-oaa$;@'OVjS8OqJ-pR(?-E.K>='#MG1Us$?!;@3gT(?_g99OPWRQ*h6o8'UFuTk$G*tRS4_NOd&sEi[Fr$Un"RU %[O"O<#,]OV++<'`e]8W;6:_M;_I6n!7bD#24+gjs\o2?6K>`:X-Q%%YUW;(r-'0GUH8]]BY,,*1)o[em:>OB[]!8ut*k>IugO\\R %T[I%e-TZBu8#..9W#F/1;Hn8[dGJ)@Q!1lXb!`.FW]*1Mn(EGdGk6(CidH:$0)NS9(i.>s+h'frE6Q %WJ`-Z3EpWSS[od9k5A_g:5X2K=523YmEB)+0cOfI9i.t8`UEth4A#(d``MJH($e1a3)R(9=0XBJ(M>I*]R.4o;.:nVI7_P&(Q4ht %\VIE<9D&fA&CUq=*U/!1QsSZQ&LXH&*R9QOnZK5j;*=XI.ZL/dI3%hOjb^1VYPIa'inaf,Z^bQhe+WRLZ^`]5.64`)Ab,b3HrjV)#nO`K^-i0& %6aZqW/_S5+,$].M1EmcX&/[V(H@5!c,_Vt[JGM6XT="$on]P5-AF)Iqgn1i-&Rdn\$cdhWc/h0\?aCfZ\j5a*cWd"0$?'>Ip75E/ %kXJb#Os**6I7pHA:G_C7XV/;'QI#a%c'SQ@MB>/JZ3>lg(2a,Or,P6A[1\_8rNu3G44??fn9FNNK9=/"3F9.kbA#[ihILRGWsKXB %8uX\_4LB3#W2YP$lK_O%"f0+X.0rg//1kIZI$pN?j*GJ?K@f.Yk*"(!,8."_`=9?uOH6l/';!tP2Yra1:G)5)F\P?(HBiY9R'_o; %+s![il?1@P;L))R*3N9=*Ze]SQFDh._jfcH!Rk@mk:Y#sZR37pG4*d@4T)Q[fXZ?V^ksKblp9bZeiY-qu'P:u2tdiQ6EgXXYF?nuZuo,C>q)Z&i<3+2F5hi!`K5^U@!N6M8BrY%ufY$fd&_;*Z49@;k&]AA)T:N[Kf9C_!%c)0Fqu]&.=P?i_honRQuD[C:PB&D'>qDZ99n1",<&MA.OWrEmah0f`S!0@%&]fX>4mr;UZqP>LNKC0P"X:d^9Xa'TqRK%'()lZqa\1;u?d($X=!>"Oj)30Cu6+Z[6W>Yk9dH4\jH!n*;CM)][hmOOUYEC>e %BW;.BqVn8,3KG$>J]/[mG!,]ZVg;_N9W>LYRtFIb640"g2UPTO2+5mbE[`C?.1V`IpEb,n1^D5rfZEa#BF\,I75Kc*(@l;5q"pt, %S_esS#=`dM@(1pA"'`D9?*!(9r$qH,[^NN)`DlqUJF7gh`DsMNb6ue*`Cqohb6o_eJu2Vfr"Kb^hYSUJDUXK0,n--62fa#Q9F=u9 %a=WTt`C+O]EM^28,Pt&B/)oaE"C9FG]0L5T@4MCZ,8&%hMlirB**ufX[Nb.tQ:A08=r!L\ATak@+PB8j's1&S2'i('SR/iPHU9>. %;k88Bk#LQrO@ZZ)b"taH0&\1EBY$6fIF;0LUrj6m4t7c08,'^>,2!Y$$g*[QOmL1MeJ+25ak]@qpN]='N,1q0(JYI^hTY%6\n:\< %Gs/C$@l5('+k[NLM;+7BOZi=6P!p#AC)^G=h\NFPT]q[,P3Yd-huf$[)+W;39eA@%+c&SA?V:jCT`t)ITX]8p;[i.an1KuoR<_nq %k*:2;Mnfp=]TNZol=`.F#@6bKZ3V(9HFl_K*B&lLI"-:5&hFWu"?X7i`"EYg$0W0`@Yk@u;:A[),pJb[&<L&dE4dg5Kq?7BP#lCj@HH6Y-=1fl*=O-MYE\%>%"'9hT1m:KsE'5JOM7Q;eSr@55hLWd^dDin3eGtPf]?1M2B+*fi`$B %&HBT-&OL[@@gF7HpLN%#I5-^De$$$'"l%U]lH!<+$rUdH_a]$@&>&g6EC(thKJ9Ib)^e<59F(_Zd>K,A%u_/O)((;YAWerFpp^*_ %A@!h$H;Kf-+WWa?kgHi.EC/&]6:)nUa;P5*8'*`a)q:!(9LsufG<,"k0$Sajk6cqMd1aMa:5JmGrS2,;4Zp#nG0oPlX1I.mCq$#E %CL:UPA1oiQa-Wr"]>g:eog%E53Bn5P,=c'*Krs6R'k;Vl$d(!&b9$,f-]qJ8i_#,l=)R`8@=0Ylg?@f.:NET)T)9)c0S[\XVo:X0 %_mgZ=@=/C:bsj-f.Kt[uf$eZ?nFM+*DJ$o/PmJWs]u)i-LpZ2.Dmap[C5;>,)uZ>bok*`Cp5^'oi8;2<2(Z(K!eBb,0SVHDdpfD] %_\f]0?;QBF%V&4G!G-4o(jiQ_n@V,\AR\37s(Xc;d^cNN%V%IOgd?\(bM19@rba]-eQ$$@MJ4?)=^CN/^3A*7JBDnL%b#m%\ef;;%O)3K-I'`*b_YoZA^\4bP/?e%QV$eSVQ9#h %p.j_s?u=[De21fQZ_)Qodq`5/#m.ck%"^c5^,/udH7[J50ib)(&>mag7H#-Eg'%#Dp(j^7VoO5AdGl8RNgp)A>)c/"s, %YDtdRV4*g$_"T3raN2U71EC\*%^8'64,/I?QH"=LWUG<7S+&K\F<2Je;Uulp*W,:i3O)*`X(d0"OK\H,I0TlQUYiW\3.^V42caY[ %[[;bCRAuka*0s6q4 %e,:Up((5;3g!WtH=Y+5rA4pEhXSt*>1_rk&Wt/R;&]=$u=hl$4)cotRN)uUD`0D)lgE)trKVGCXkGU>WhjDOfAirNbqu"ls"@LM7 %[2tMg,T&QdLu0j8$^gI?+O%_o)\NRm;`0t1JtXe4hd%*U,T&Qd#VM1F+i3phAf3sfTd,/VE@5Nm0Q]\o[$\3D_>gtrbjnEO<4"?K %+*X]pgVPp-qf_I\s%1[c>?Sbc-+/ugKeMoEN4,*[5nbg3qNjf^pUe8#@68Z.id`HAJ:6I\Yak[09u1+ce1RR968RM9Q;\r#8T92PL>C?A!IoZ7)dXC %(Vd^CEQ'2:T#OO"BR[#9SVs?[6M=,!^GYOQW<7lG^Sij'"R$<:#7NmCUTZQ##ceF)mV!P!bU^ZERjNH:GA[Z\p!'_OY,O.m!]Cn* %#tiVCG_JbgJF_6dGH+Su&JhUei#>U&KEZ0G8>[dh_?/m7eh@GiYg@`hb6Vn_cLT6iWB(e]PfsPg3#3hY3!]o>X+p?0JdGO_%af_10 %:STf@D@&A-;eDoS>h!lfTC,bIs2XC'$Ms3q$Of!)"rN,,l.PqfoNpkN]u&+mKbg6t/.S^:k[qLKNmR7ah*Aa3;r>ZUDVI^09c%2( %Wb&7jMi481&5PV>4X.;a)NY#;F9(5+b^D(0oNR6O1g_^U2)7BI4Q\[,Z[97aDigMN(73Th-n54*"fj+!7Kahp0@Ed.BZ1Q;gX)rr %L#!LugDl8MZJ?9MgX+ETO^6Z\lr>.I'(*,(G.LYb/RZ"i'M[h8>JP']hI=q#[X`\AMGL,*7TFA?Fcd*Q_56#8GmVr<7f&mg@UAt] %:=F/%<:ttN)PR-\!98#;V0R&#>VHY+f)QVIK+#\-c,0h/3:-5smThYWJ,2O_qr:J4^ALaAH5DaF7WO014FTLO=jB[WG0Ra:+i&BStHLq(%L-%"#nh;Rck]Bri9?k/uHbau997?)tk2O_qr %,X&\5)pN#R;+V48;:bb:?>T#iI*NVZoI;knNr*sR`/"=lC3>T\!M9g,A!3B@7qU:t8?$EA'^n*k9@t'PKsQ0R=FW:\b\?YhO`ikB %!(&gmq<\-&ZAE]F4>-T&[P>*mp8uqdq'RdgN(T^_N-s25d@Kh#P5f#4[TEQj3)%)Z3]F.keq1*6mPDs/6jTBIIS/%K>r"'u:\r-8#;>TWf8"aKjYFJ-fT;kR=8s(H0:nc?7JF@326&T4d\Pi1X*E-Y0j@[Wot %fihYe<@fp?/@2m]gj&Vp>TTCI"aKi._(nj3"Y5lVp(rPZ.MXTY3.G&FLfGu^pfZ2'\5:."6btPM,7@O'1DDBm>:is^bYYN[m>afZ %b6Qtr[(]TJGkllFM7t^lMIhNT)qN)>(!@!hbLUqNW`]8@B_0&ljo7[$Ht^@%O*2^9GL9A+9G%P2/2Q2qOV4":m0G4E[bPVkMIhNo %ATWog<\-%c/2HQt`)S?EG[/TQ+BYm2iGm]Oq$M@O^`X8k=H<'%0IuW7r=0RXTA"j^] %$jFgL;HTT$RA"$ARSF[!=Crs`eo]l.AVQQi3W"X`Q5L$qn`iHB@[Wot),gRT.[CqZQE>QPTo*CcW/%5X="J"ETcTYI`A0fs121/l %>d;LLY`-kc14!CHM*`gXOg#LO[!A)37)D]P]aIj47)D\EM';]e7)D]Pc_?;g8DSu`:/6r,)p7+Oi9,kOKFqnP=Q.XE:I %-c4_o,^SJ#(bOBYHGLD^rN9\dUNDXlN9$YpeAd7mV)5BhmA4YW>G`\U[o4YW<,Ai]<84YW<,QI)br%#nu4C_)Ke %JD#cYM&mMY!<`=g>RueUJ9fFu,S,jrJ6B3t1-I=[!sVO<\K2U4!J>cr>RueUJ>%1`A.OX]J@V4"dQB4P",7cJ`%%&j/2)6O$J=O+OkMrYVr$jFhCGf;F*V@.e4==+9uFHr;AF*#Qn/jGK9h,-jPZ-70X,F'NXZ-;.%i@/HFMId"$bNc3A %o=G2kK74W;gZ+=O+LGY2]CgV%D,L/"N8&10sp&]F1U)/,Ag*Z3Jj$FnA(bklP.iMOmB6@Ql@j %R@Zt%H^_*tSsXXV?0H`77Sb:t0(]oX7Sb:R.f(^=k_X\2AQ!gu@4,7-K50V,KQW+C^+t!Y3?In5'[[R#3t^@'MWfmBdtOr8Ab8BR %l%0cc6/!SLhEdo %4'TFm[,fA]bLo5V9B4s:cerYs3*WVZXQ&3uf:R#sKTq'[X9@#MK;%0=!@cDH[D(Oan^UJV/qRC<1[UH>`_?_Q3L2l]g_k>?/.HOPY<%sRd9>IbX(#cSOp:'c.:R!& %Op7_R/oSJq\W5d$fWpf)O#8iQM588ZmQ,>lV5ds,XQA %B:"O#T8*S1:Did;6LPRWl3Q?^<&&EK7`iOl#So+h`U1d)`@FWscWJRn@rl%?Yg1R/ %CK[Ga4:3AO%O_epO44(#;S%0t.?_K%V^9N2>N4QShV7cd]_X"pu8$DMnl:mrefA%U^P[8gs %4EC8\l=85jk[ghRg-0j6/iKlsJ`+%&2SKhtd:?]Dn %`gLNYNHF.BrF-e?=W+Au,+c>;9ZpgTAMDu+?dS29jmN*6HEm/1-1qb!T2ckA+hM%Mk<&s*6$O1X:^gbX7PMqQKjq821&ehV %!#C#JJAd!+>)o;SKLcNY)NTY_#U;(NdkVu%+cO@T:#Bqe$t1E9VDCIlKTR*r\jOlh+IO(rF9X.J0G;8^V%s9S&@S($Kj!!N?oSe: %;;s';#0Fe+-uj$7nD("$p't8b4H=4D2"PHkIYd$&nkLGXZN$#+hIoHn/A-/_T-h9;$qAKbWY(-@=*3R$_fM&jNI*5>iIcabSWbLcS,>(+qPSAk6CrNJ0Y8i/GSm:;S+^ch(Ui]s06s_kI/>K&6e\DpbPcfPaFj#Xd): %F'8FqnE^g4+s7*eJem_)cLD.K([.#ji6`% %+'!51%)P9UZ1rWTiH!t8>m92h"W@Y6kcSGK2[8pn>Al&$_LU-$Cq[)m\M9tO,s&;I&< %e/Jd^)uFjrnWBo+ji3b7:i@nD^X.)*863SmQ8PAY*6CeiaMRB^p./6$5Sheha_J8o!a2aGaUuWe(s(-IY"2U15Sg^\F%!=>aT>V= %IUtpb(;E6!Do[ltA0hXp=\:e=P(aV;kCA%e0JG&Vkt8r!"2f_p5GlT&+:EZn(E=7(hdpc3nB;Vo,V,RH'p>Yblsa,im"BaSAetiF %OlUmXen[Vc3BtO&deG"h$!f+SjQDA1-$6D"=+MTZQ-dK:T7nYUQ-dL-cnC*Tqme"CP"[H`9Zb-s,U8"?J:U#$.t)("eL3OTYLJL) %(X;&<.gp["N,57m8Sb)>jdf1Zc"6EL=caQ[c"6EL=dmX. %bMp":1n?jt7BES&iT%B#]Kbb"oFDk*dscRS$=/>8?# %/B&u8GL9A+9FojgCQ1i.c+7&[K7NBaW@g9!jKA-!/;JqKoM2a%8<(%U;rioL#(B8sWMSj"ZP"oNiXp& %Q)SVkV.R<>X/WYa_Tu3DrD3DWK*)VlL:.&!%fG$gpK'\+7d.K.HL_H\1K`cKh>S3.eQ\a=L?Pe)=2!]AAGAn%]O(^fJdmqV1'BRb %7J"4NIM$b;-E`]nJ0F!mP':cJ%N&ZX_Y7-bi:k#7p!SDUKXgL[:p@K4HADt/Y/':5#]ZOk2,8_QL3QM$%;hdh`OhW%W\N_m%WFD^ %dJM'Q>ZcK,?`>m#23Hrt'&p2E+r#gBYl6t%?YtT,lS#(/e:tL&3Q4*,Pp%dZhJ,4Xp-SBfHko]hbYN#EDD)\FVm@,*+jN\Z@*r+S %=UNC'?ZY-OfiLib`p)cuVUJmJm8792c%TIh)XBIg%\LC_+mH\JP[1nHrA6=rr?ZNnIeG4C!tT=...Lm"N.KApRoe.pC2m@H6/T`M %E!3`'+5b5\G[mUXC)n>^,$?m2J2D_u=Dnrk,<51hUE+lkpVFXK7(RDc'*Qo6qGBm#]Xg&Q=-cq39=1/.mT[@7;jJ5&HI4JGf>G@n %R9@8+_f)kAq9+'2)6e>$"OF$(N;c+Y7eeqB5FA_@+#Gl.>O0I6gY)/GgMX@efcE!YDcbsMA,!48CX(9kbhYFp7k>hUZqM*V$7o0: %/0W_[M(jVr>!e=SFA*i("qT?J$fLT'I+1RoSip7XWH`W8\a8ur`-;jm2*V8V#C^5NUWE7"),fT!jM\_4H %S'H^'086)SB;a3BJZJ/lqNJL\?5Z10Tl3h'As$%,=!>5g[ka;6'3J/NKaTHWXXB'rfefuo-_8*\^hh5G-!7u19[%P\QCN[YT'fqa %^sW?1JtZh2^UY-dLV2HVr6;ou_\?0rDa[t>4e6<)FQa%+!X`?He,l.g36&(,PTbl%FX[I %k$d8paQrY=N]u@1,LVTbAOWSH^*$"%`o,fiI1d?@Y[)K9H.p(e:XEge4#kmX5328q>1KHtSLH`?bMj<619S;hS`Prf;&i&Md[fd^icOehm+`+rE#l=rINHg;HZ,h*%mQ-i>(;1O<.=>)\TkJd!8*][ %'17oF4B\j%H/>6-ZEddc&n8^\*p+gdknBbI_8Ac*LiBb%UWH>s-4A@!PNc=BehWi$i4%<=3qSj/[+RH=O %+aO5H/0$!l"\6r;")'RG!1K5W/jch$B%YN)q@X_iThA:*p>m/7U%S_gBG(CmrC[H*J]1=p-S5142aOHOq$Vkn8\tPr8sW7TJ-f67 %'QWP#eMn3!OJ1K;]/BB"d$sj9QB"p/JKEXot4,a>uYjcaE:RZ_3l-O*ZB;:s.YmO([eOD/$6qoN6t'H$%bn %+BpG,:Pa,s/(Q(9S&Omk,YHhF%>8J(8knPHQ[bPWX\Xc(-A7T"')I9U?f-+&g[bIg$;](PK1C4CR=E#r1;%hD;ZtQG_=DV0$X(-$2Jr]K/[8D-OoZVJ0m6kSo`@-WD)2mBk:3qP-i_SG=@XJMh[ST+L+? %[,\uflou]-:T+I,7/JR'RT^.m%eKm._ZF:FEnDU6Ra0A0P]S1nCTo

C)@6SSrdGo^s*:X6e'KZ&\4e,u %('=#)c8]8U>TjY+RDKsHiM*%!<-(&T,ug\u[obnm>[=#7G,(U>XS-'Np47!QM?,K%g"[(F5Oas)2aD>1.V(g^X*m<1%N4?uYb71\ %q_4i:_+bKBp0fBCJUN!`C*0q;kF-"?G\Qd79G(IR6G=n#?[;Wg5m=+k[R=q;M8"WbIhGfZ0Vn9I(]hIA$Am&]84[\ULeCiSb".4S %]/V]M5oR(\SdDZ6'ZEuod?tQuKhJ#\B0E/]:bJ@tPomO1P>qE5+OT\kV3EF3o;T^gd(!b`f2a%8&;?4I=!@881L.5r$MIgk".\5./^Hbrh^:I4YN^*(IA2j;E*ep;-]HB[UR`q^H,<%@NmF:b-VlRi$]:5]M5KNHF['\51j!&'eGTN3BM%eK %Hq:WZT7::"U*W4%Bf^HM-34_g^+g*G>!aJQiUelkd1RYN@&fCmMO"g1#.0TT'5;&jDq&1!Rj)rc>`Qhu/OlXO@.-Ern]tbCO,Dp= %F=4efioo&>$B4oJ:7=P(!fPreQY#Vgq?uo8'Ib`uR4BEa7e@Mn/BSYD=eiLFBa"hp@cg:W!XlBYEK\`E4XY>X"EO=>>Vo/fhrmZ" %3MD^9En?D@Me;/I\B&@]o4eb(PD>+:cUH<)IPMg+(C`E[GfaXsdL:P6.]QPPlU88&'ND7?U`�jWpVkF4"BfT9kMV5:MB\bN,a0 %I^=D.[6WJ37b\Z_`:14E2+&S8'!%.2%8#-D/"%tnZf;Z?S>d\X$hup/U%NUr56_N&=t1)cb\D]#5S>N`s&?\Df_pX0kKti8NF9hp %VG"jd&]e)ElF=>l+Cgim&Mk10)1u2uBpc/%a;D;+9>c^B:=%V#7QHj@Cr7+PBlXF6q^SfM!BEN8Zr\A_'(,=3b8J`=[.a`bci'eL %o\n4_enq.*h!>5K,b.s89)hOXAAt.K'l0Y,?-mR'W"KX=TbT,>fM+nVUKko[>Bja1h.=Imkk#R1?]gI+LN>#Z*JZ75/eM7+6d/or`[]@_K%jVp*dX&;a9k1:(=PH-_E&Q^\bbe+qiQXH\.%H(DND5Jq3U<_HV %p!)!/aK8UW3W8r6hJoS`pQl,6o'+NfSe_.d-SL__.\UV4N6YV'f$S2k`_Ro]c.kSFLsGP'O>6*YA'A&X>1.?Pqo6mQRAEJX[+?t- %hnMo6R0?p@=Qi-nrl.&VFZ"AYHXr7KS`Nc'Gr`[:>;bQ5X9TFU\.>:(dINmBqR8(E3s2EU!,(gGC45Mmg=h16^lNHi#A4\scM:(T %I!i;I0_=V\hR,O.cA4UOi9XO(L%<]bl[>S_:9V?hDRPZkoENu#^r$*mQ=??>c)ZnI^G[e.glg_=CGiiT]pnKhZ1$SRXZUoA:RU\? %NMk>#e[G:U^\W):ataUS-9[I(.6ORR:,L_M7[Dh3SQq;;:2iRG65>4XW#n7U9/`]\L-;U?qiP"L^dcYlET$Nh8?Jnk+^A2'f^ %(s$(t@S3)l::4U[#ZN9QMiZWQH&Ilf2uP=Wic[N2F"'tR+.H4]Ss0gf/\\_cK#KaGT6O?D>!)2]Xj)=ld=^:qV5h7fiu,SedEs;4 %\VFtEh>Xo@(/A(h1Uku-*u]>(NHW]D>$O#+bsj#O0b\rO6p>3"_GH;cf)D%`fo+^Prq#<(*V]UF==O?H)bcA`VE,*thjW4^raZ%r %0jr2Kfg]u!c6Z=&b2k5O'12ld@7ou8N_DKba[#;A?(\o]Emc2\0Z\qo,Q#-ZB(f-gAPt=akt]W>UITc4Ydfo!/rRQ3q>CfU]9"q0 %(-7VR8Q[AN/#rRQ1XD-mrE@.lB]YcJP&NuIE"5p`(]^X.E'Eoar-CZobcYicl6oC!EFSE[gXp"HJ_^X$#>B=ITK2J?AQAmgYeCAHKZn"]XO %[JEV,Oo:$k@bo&Zm:l+UkbCtSRHXs(J!*nGYqKNqmESmu>9,TpfU6X$\"ENb,(:2S_h67P_afTC=BW7T0dnke&=UK\Ld[pCK@'Uc %0$Yr!k2BB(Ra/*^rcbq5cgTnk=+[X.iXcs,W]15O5+p5rN,q6urDUKl+@C25ZRFiRONhp;3NRmT5UZk>M^@L*0FhIVTN0nFa3C2( %kC?5W/\jN6oc\hLmA7*J#D@-eO*#BEcPIX@*]Atn`BsQRUPlI3*^^n1aNYSY[#`6mP`f.SrBQL,*[-km`DtQ6(]YP %gQSlkRf!^TY%J^)@^7IB6O1eNFpBgV%8"9K._@XI!@)3SWI1`L!K>c11m&6g`\Notd6olp_r.(^*.OL%4JEMH3V$mcdo@Z]f?_ii %WP,pLT\A3=f>%4_**-1BX`(c5)0b[iUR.NY7dnL]WKY:Qd('[3rQqY<$:iqLp.`G1>HcMqgR*cN+KaToV"0MSE=KB[De._p[]&%W %g'srOn(jeIDHa/l8UED`hsc&.eBV-r(!eFu?dk[oifBH4G3=7"V,=1B6R!qm-B^'Hh)W!ab\ka(f:A]$`m$lZ+pTk>Re[8/'GYcR %ppga3\oXNW,X1mR^=94iMV?eO8Jn.07T#pr9Jf)R+E\RaqBV`4s70E%Pf+;+;.H=1*C_Wc3sVp!d35RcmMo"]8$'Sild#>"8uN-% %JrSbBaIt5Z.s^IT7\c2s4P3Q`SMN9EWM2HZOt"rso:o?2gcasgoPc7\4(fRgaHj/l\^-=7g,pq(I,(_*@/qAVi\2[I%g7'0IK+GSY9[E5[h>SU%0mS9`h]'^-O2+*HCp.Dt6Rh>";I$`PC89!sQ`2IDn; %@AEeO?LYf2^i]n6`Xh!G(#1b&.V*ekr8C]Rj_XiaS.W&$jPQSJ_;aY77:k!d\9I-C'35;u=TqEE8_Y\B+aXK %\rH()k$YCh0TP9K`6J#FHXJZ8biW,%oY>,M)#.Q\4g5bqZQp'?k($m*`&"U;/&P?KOoc;GCq1h6KHI6'_q'u@,:CHX1I/\%l9Z3V %bn*gjZpldoG=5-(ZF?L4]ej-h3L"+VbdSFqM\Yj.+C[/j%.h0ODh!J0?ei:X(2Ya6IR-'(2#E2p&WtH>qSsEbHW_+R"IK'%C4>+g %,;ID$"6>q!aVBF'Aq59Hgk@T^/(FL6diGa\0;&'jSjbU&9"fJ!d53&2>ge-1*fj+Prh>pt-$5hlX$CMWDG-[jD[WNuhtg@\`I'I, %^7gUK#P5X>CQqKVp[aqh.!G[5m5UKu_ug7e+4!YV^q,?:d#6EO3(iMYUk7Hp`?iBd=!Xc0=q!10D3djJ[)ST."Ed84YI"#cl#T=/hDIub/XR`bS,t_5*_8iYmn")W4J'HrK-`[C<9&KG#DD$)^`m*7*1Z2><;s\\1C?cIsL&"OMBS?"g %(!0I,?g1-_H1B\kGW3G%cs#VlUGPPW#U)FBa$ZJQo8*$L<>;M3?rPP%Q[(Hao$@,qo%Kj:>l?sbk@_0"(1PEn)e"ANJ()Q %hKaYa4b]3>2hc%QY>l'HRDI(C-TC$kS8NeJSbiG78h58PC%Ck?`e*6A/jK8!O.#Z"E7"0.ccjA'eHgi;]].6tNVjp=\mZmL3)'3[ %m"]QN_q.oa]Q_kn3ps[g9VFCcqeCKSFhY;sNF"3Y.1jl8#Yes-5jX?;9'EU_+&n;d,cca%"Q!qRA6"OF-&%UD;bkJ,8\H^C?dJ0P %*+;W7_%^u6-ft+hIX,qOW`<_>WkF,n3EQor6;oACA@(G8=\\F36'3eMnprS"I1WoY!#GcmGie7<^%R$#RNd>)f_=2IQb@kSK6lg4U3JSiKo='&&!R[$o9?6CY32eg42_,5AYJI,6CbIh*/B %J.Eu_&g@%[!.;`H+UGg&4kDi@GLt'=HeZSZA`2'nZ#A_9m'L0=XWf8(jaIu]$*i\J'P'[X/!+/n@Y]lTLXn/BFVemH7iJ48kq4E% %^PRd*s5`gFM!h":/o."/;g6Uq]!?Gp9m'=d*C@>qVRk,8=hl7kFbjF$.Chsel4?DQOB=I_1c5mOlROPd=`2r+.gh/0qI %ALSb%i4S+QJ'JtEX$>EVoPX6E%3iMi42n\2ej8WPqYt!hm.*c`qiY/.$f:!kiFfiRq,0a@/%t4cX'?\-c//Bh_#DbF`CB'E`QT.s %q6B;"?R2?n!oOCW*",84%)t=&j(m&`56g''6u)uko$7^A1VW9j_`+ZCS8Nrf#g?caM55DHh`B=]<:nrEhHLK7#2bkXu'&''fX+p(&/R!BmE`A;3]?*t6gJicjFAY-bpD/qF. %6o;E"?UFY-i(YT36`Uk6n7M@^=G`9Wnt[D6dq==SH<4IoM\`-SH<4IoSoi+3sEJrep3B!G7'"o+su_Gi_G'/PKi;dbr&g& %;jl@j):Za1VWMb(5?"!E5P]siZ2mlS^k,:Zjq20KUOU19";0Ytnucu]l:"=mg\k];SGIpA@*48kDJ %q3G#c"j$M0c*n\AK*'<,X?[)ZKo8GnXR4jtPAM\6Gr5(OXpco+gTXC-EbJ[VFO[de"KH?"muiR(=D)u6MPS7cjgQMMs);8V]325" %>.$98T;Ducp:4>VXk+r7OD1nDCutk84]GHCb8e&YC""SgM:p2h7S1=N" %?QBT7gn3#<[P@Na>gdQ,rLYa.b[0[E%igQp.D>CN7??"?,^X,Eeud726CPD>Y>V\YR"W,`Wdu&"NO7167e(s$O&9XtSSk+V$AE6TFTPh9ZbNW*et+$_E[!(YT]m1%FT"Nt@$O+OL!W,S4;dXgRHSX0:PBRB/Cp#skB]`dY0qphZ"[Kt"+&^h!!imD\*UTdCHB %/VER*j=O/ %QR(QITt=3>\Wf8-WOQ1?4&)0H\6KAB9AqdSQ/tmM'15?]-;@QH/qkr#R"qrZVFJ/do7!qS!:J']#'\6HJISj,uKqE5/1nh9]$=D9GIUOgpb1*kKV_[kG>CO/TJ$qj:S!XZa;N[3+qjpuc-)V"`0M-F;ifj5%;j3b$!_$"\lO5`F %/>G`c1c^7SMc1l)?Yf;RnAI0*kZ?N[la;/RO9lqje"ld_;+#BL%/aHWKJ48V[M7e=^4PO8oU=s"Hl@-"D$FVd>UBBmbq!>kF\V;M %)!AZ)QWi?-cl9CjVt4\i82!)@*RUi!gSf/,bA^4aR'Z(9NOS&sXg4D'f/hI@Lt,G"m9Q5oS5,t.ZWV]4VSJ/.&"t%A8^@*Ms,%L^ %L"8dT4X3j^U^Gl*/$!?'I^O$BE9As.<_Dq?Ua@-=:5ot%P%>A"3Tk=ikVa*@m"?CU8?-$3*#_hX`>A=4_MAPhjLQAY+;GAa,$-5$ %k"D17)uV6[KTg?_hlgKB)H#HX0?K8G79&pAO.[54I7&XSpK#D.``bYmW\u9^cX!$(l)rK?ZZ9R'<2MhLD$f13@jj1EB4mSeLXhdA*Jsq^pjocd7;EZ&n>:TrLQaZGWEX"*eSLan#\qTHR)QOIW?pD5U %L$4.FX'js2-F"ii);"4],+cLsrjF5YA&[.<`SVF7mn12Fl=]8FF7r-$C25qFYCEVPM(XeIWf2ORAYRU$CZgu1>/Cs/P6n,XccW+Q %CC-V]V?@Qr[1m'`O\(hV7T&^@\@<5i'7p/rCD9Y/iu3!P*%TrukfOH"iBLF2^k4f+iKlfb!O4-`GQ=!CMg1Tl4Bu0]m1WtSa<1ft %+$&XANqcK@P;8*:3CH[mnY=HbW$X5_\pp1PD@DI9&tTK;9E-Lfn8[Ju^!s&6Da`(Ii%8OW %gf=G]Y_)khO$uW6nFNjWcrPO9iknouMq7eB*=B6X%!.hZZ[5n\@HBXcHL`:YGn5fZIJhY_$`@-k#U")f*(lj.hJDPR"eWLYRgBQ2 %4'pnK5OZEd(4=&U(uBmlcH.K+gLe;gI,O0N0^0B^-9-=g\5[Ei9Q8Xpiab8!@"JV=,DqlHG*4@Y&r;q^Y3F%o$LCH*S:@fCi9H]f %?7/Sj'AQ)o;oSraFqiX,M_5>nLF(Y]60a`c@0qB\%Q5?/`aq+\M:tV5*>YinK"f`b_Ql#(\AJrmW4(J?EJGjo?ZB_*A75bBX4dl# %91"D&#uuUH)1)2q9ELR=YR#I(1H@#6k>[Z+YXJ@=OQM@==S?YN*0t8f7FV&PQEC&NZC/g!FO8Ha1W0'Vd3L_'dJaLM?0OG#hb&Tp %pNiYq1pW%RTgXsVdP7qc;@Tu_G[ADdAQ=Nca-t[Fr`kbf?h!8]Uje09DHDpq"MW[H"i\jpf.T^V8CoLOC:UBPHL"ksk2Enp3o7k6 %gh,sIW1bZ%iAR(hP=eajdY?LqRs^Ch2Ql#I&/)JeRY!EPQFjfceFZ`>DE*q\*ZI/qVWeE-gUN!mh!#:djftMsD7CfjGE-HA$54DopMDCi3[VASmJn_]O9qM-=W=V%_(hs-Wgfn@_1C8$:r1[:_1;nQGqdoFE(u[4)2/tuRN?/\h9^t#r4G(d?atr8 %r4G'mNN8d&OHm5NMcrU>V%0r/_;IR>;Hh.pIs"Ie>f_SJ&U/gt@J3=2mE#oOBi'%Zg@#jHNN&+,>9'#M)coLPjZBopOqtqUaR(ID'84V4#ImfuT-_)b;H[ %DqKDb'$FcPD'HXA/#tcje0]d(4)*f]U!GVj"]WEVn@$K>@lA:fNMV0AXh:#>AqRj`8JSR_,l'TN9BjZT^g*KUAcp`/ckJ5S#dFD2 %j/SIUjQ&QbLFQm<+Z:JAU5[bjL^iPe;oWWmM%-?\7TRBB+J7//n#KhSW*lT!1)jm?Wo;/+1X8^NV1ZZkWJ]@o*$Y%3="@R.aV=!` %#%Gd7eV20('35V(/LI+C5_ojZInU$P6+"UiNS+lq]26F^+N+IDql6"mK\-9#(fecaEi6c<^FEh_ckTQuC`m^7QMc20Acj2-BY$6: %"!KQ&6WFl-JOib-K2om,+Jonc%ob8&a;KbF(0/Q_nn^[o5%VqBZ>"rhe08b35AqpKm!)rG`72)LD+^0)`733L1)l%KA^0nI@5a5/ %4RA-.@Q"crbG$r6fNQ.h(4'0T<8AlX[;^n,S?4)RC*i!lE1'lC*;J_*.&!W:l!.5t'N8ek?tt8P;c(@G\Bm'<8I\U+[om3_L;XY^ %BFPVnCC-J6ph?.T=U!*b>CKKYXteeIgRtNg %[qh5U:]<9PQ^EkC_h@O9:Prr7_0*loOQq9Pm9Zb'57:6t(8`d/)dW'I'hQ4h^RmAL!lnf"AnL2-#C,ZJ)1L.@%B[X6*&2PSE3Wkq %cUph257@FS84Q=5T4P3je-2JKT7tRK`8FR]T7pp\+ri0pI[7U&sNl9kUN<(4*O"b$ekI"HAs6GnZ#22DD7t4Ef\>U31b,F%nl.tHMpB9p#-o1o^G)tL&sM.uR07(%?#$KhkI.c[1Z%[: %Z_HXA9Q,=Wo&MT8cl$$"3$%ho*%kk%Wkiak`c'G0[!r$8b`H)XH+J:*d(8Q);u(3AKe&m$]SHbBO/tgY&Bt9J3'3q0e%Iuu"4-U] %^2mZ]\_HqjGhKKV_sS?G])Q)sgimKB@i`p]*!URWNck+FP\S58D:ZZefT\01fHC=^J6u^\s06e)H]97a(VTrVKE2sLD/;c\*-"a+ %R%0Y9A(-,.s6;1I=eSGf2*8EWs"hFCfkt4D9<(qR4jVg9CHjq/-$7J_+b6FCN\tlH>N$J/j2c^m5%12RX4P)a3ef$^#=\6NHb)tQ %muPML.E]r:g2kM,cMmGsbB&H@kL]MuI@l"q[kN1hK6K8;hYG*K;mlD6(q$TDD8^).\): %KA>IR*E^TOYFE--d9gNgk&%P2a7-4d&-#@DMDM(i[@$9bZJ2pj,9B@lb&d2A_Xn0A*>*c?S9abYY@&CX8rR?78(GtD5^2ZbW='2YhQbY<4qZh4&h(I*pQ>OkW1%sf)qDp>u& %>O8#\V2,$-j>\F:G47$0(#<493s="+\>R)!NU`mTl7+l6I)_##_RH%nD&-eO)"".CHL\E;@FV6MePeDJ2T`A4V.p']BrjIZ;gmB. %?JbPPlY_tuqY!t,mackin!gFQgkXcpoWK$0dVbp?DkaZc#@)>Q6uAHbK_ZAbt %R6cbS?>9+BbQ?8EM$H-g(OB3f$8.15j9cT+pq>!c'G8tc0VQW`EWle&8D%pG>XCu-+M$"_6^j.57kD4+(M?oj78.lYUk=%?=.nL" %=0SKOV?k9Y.(IVBL/i8nWHt=O4rO;&([NTiQX!IsaoR+;R"sWF\O+AF*$n[Zi.ALtH=Memj9cT+&l6Ua.(J1A,LkSf07TA"&qD]4 %Mb9h""hX,#)@+A!.(JbPa\-XX?;pbAj!D71V[$o]f@imf_bY:V$8/\\As?PCW!HX.05fsAJWH4u-O`.=defEZpX\J>hMn^%lWrbd %Ib-NXr4R.#J?V_eM+HEK>!P\BrELeGHfOo)kD_`IX.pe,=7mTODkh,<_> %/@B>ea,!\j.XR2_dICgq3n<7]c`T@5$c_7I@$&08T0,RO/=a4%1r34Rp4h^YFf&34q"'1"J=Q/&qVujO_kcV%2Q<*2;0EMrFVUfbantiZ#abGjo %VR3;&]C'Mro7e$TK6u)Bf8%b*YBaGg>sJ&DnS23i/$8aR))BYc[dBkhD$>m`7jQ"%'3ju=c,,mXas<%.?$L;FG$[+3K`gs&)@^":fFF2DfD^CdeS#L)oQLqZ:fDjaOP=PgQG2Wt("Uc;K']hDLDKO^p="6hE:fLrOn9#gC8.QcTY1Ib#kT.TZ$Ft- %;>$1u*XKF(B,0G6HH+)']C5AJHL;h\DW8ha]mt>M5^[jQQbI7[?$ppnQP<5Cc!F8@bp*igRl[M&#Q$aiIF(-kNN`ri+)GN"7ZXsD %T"nARcWLZW@(-&dM$Qrcbc+sf.58Cj(ZE-5.kpjq9qU4ij#*B0"1r1@rbMB6*nSfjE:be(/4P8eqb"I.IA:(3AT6Q#qH5qb'S^q^%n#'Wn70.La^=bZQ7@hnONP %4"sl"I&'nS1.EA]W2\RBS5qa=8kUe^[I\V"j'&*4",GJSc5;T*-dBrqDfg!ql$56_R+U.`5O,6R/<(BVBni$]:2qUKRd'Fc%WTKq %R\?5(:-aW:Q:4k^KG!@O_=Vs5J[8PRX$+C==SDqM_"^mP_@A]')b**.1RmsRH6R!5DJ5],! %-;]pZ`iPI0/J_/Wb->+cmp/a4(#i6:Jm067WNZiQV5BQ[DHHUp>M)hHna9$$oi"dNM0f08%8_$9O?g>J)3(-.0BqqRL*QQXQ^$h+\;IZ>Bb!o?U8r4W!ihU;]qKKFE*>%19\cXZiI2q[L8Pmp$PG0MS>BC) %]$^kOiJcMhJXjM%\@]W5VGks;#nZMIiES6P!:>*-Uu\69Z2_Vl@X*n@P.rX5W==ffQt %MF^"?/21)n/c]1blrBXW>'>4p:IMTAqH]b!MOq%[-X'-9%@5p'ErDp>W1KeD!XRB[9pM*he %@4/Ke(04$Q]9$jZZA)^8\69[:_A-%deZr;8;-P^J9<2eddFo_FQK:E%O04eF]IVggZA%(4B!naO52*'2eZq&(f'<.UCDacnNko_c %0A(a[dkBPBjVY,qDt^%KNQD;a$bGO8Y*QcT^aF=/fB"AYe`9qO$m:D,G8@?&44huN:\SX8d`)5_G^^&Am,BVEL9Jk[Dl`7)P?-B/ %a[-_GAXhEK?d^D3Dlg^UZJ8Yq@33"7*]Qd#=F?QB%+]hn=rl6.nd[?9eaV+gW.9++HU"KY3?B`iaom %0u>Pui<"Ha)/6b7F"-\G&#J/jIm?f9W,ACOEiaV7ZY)(S:"#cs:Ne+K=f";dJ%Xk,Q&kQ:'TF0^C?5;SuRTGQsb?mda:^ %T_S`C"kFW@g:D_c:pVW@iEsH?Em7p:d<9OKU^gR'7kC9#!^TFek>@mW]b*DH5jS?_+t<;u<45NaB14.(?`5Us\H=oer3joSPVXSLqT %09fc2Vp"n`_Kcr%=m3b/FgYb&:n672g:polDGFD'T[(j-%tY1#WK3u"cRP0u7Y,(bb#USpVUZU)heA_6OQ>\E+Na:_&6^K?r@H#9 %#q_C\.s\a\=\teCp9Q#IE1nhcPEf[pKsK?NK=qYdKsDEW-e?S?i:I\\6(>;2)=T %kpP>AZE_hRnN*/,dSDsgf1f>2N,kut=/VZ1SPB'+YH1uYh"JWiA^QFuicSKmDs[Jg5Lq=]%Nc>ue[ %@1,^]g]52uI!MNS,SQ*>q:,7o<.#QT/KdcT%PO+Bndl;Q.\gCrn*G5m(@EHB665@tZI9s6cA*Qk8DE#X_kG^F?G. %"\p8Db=/T?/:'4.b8',YTp$B`T+`tRBM:aM$ZY,GJ+tHZ6X84>7;.Jb0:S[09k]=jT3f1A&/jKEj#1Rf.5o+U9LK-rET(=m=H,h( %\B8_2Q]'_\P%7a_X/kuXkcTkE+18++(KX);mKbA)JoD>`BOqKcYtRJW50_W#/QPZHF':?,\Z/oZm!Ne< %S%Dd;IWL73$,2giaZG'b'ekWrqcM*'VH2(5"MkgEP%.tK,:.8'3;hgIZ %Yt3"pAU(Rp4(.o&%uCP2P3Fa:A,JGC56hU&(Hp$h?3bS0D9)#[t$WLa$1#\qm`3YTY@8nLUqZ<-&o$:LB.d %oDJC1r8=`bH%*-,LSU,hBFPVnp+VR.kVmc8aaO@Xdb.!KDJ&R\gnKCt>\[HW6jW_c3A5WlKI+=[TfK=Sh:G:S]Ncqt.kRi-C3hBT %,j,?3nZ\f*T:?]8F-n-6"Xc0]hI9s;V6J6"3`6-Vc2@ql][>lgR3K"Cb2HJ//=46"9mn*Q@(?t@RiBj[_.[nnH52&ja%Dl!>UgNC %*1gYK8M<8@F,AOYA]]56*%ZG70+)Q6ORr[Nc-buhfdGe+k4jCnlCHpo2O@q_2]%E2QXmkf.Ge`Z4oaO/S`5Vea5k@uGJRs6fMN@5 %nS8BFi&`h;!UK.'LDS4Ob2jmS.XZ%iEo4!=,PQ2''@SYQmh^JsN$Bb_VUS/b=L4>Fj9pB;J`ii%LO!eXIFpgW^$D?:Z&Rro@l\VO>hFd$u#K#sqDoGh5^.+LMOYo:HG %T:SMr%/M];q<]ZrQ^o94L%QW3^QNW]%paVXTH>uN>Y@hln8EYXpPDCWV4!M/[rVC% %Rl8rQ],llm8lNI6H!UBo@DA %@Hs9pB<4Z&-0Q-QUB^]")65tDa,0H5da$a/e_c>9hi-+CN0PVtF`pMPYmBb13'lbkpQDeREVe_2p`e3=Ih+>#sV76!Pgs\'7Q+"/"ub,W*8F'p:ZC>`h'gEK2>jLjR+ee7Ofr-N/[S50$Ani9W80q %"$,?B)&dPadjl:3^aI+C(9bT95J68kLf]SV5W)V"(Pfpp$=$(oN8mpjKhKNP>4Qa>6EdXb8V-TR>n0D:b@S)&WYIYT-'/#mN@kBr %!Zf>1fn745oHsg6HrSYGgdft0VfF)k2#6:9$(2CmUc+doi^sP7B1MdBnG+LaFB6G"nEuDqXms9(QSNM*\.k$+F:dVbj1Bdleri@'J#8(.F:`sL#N!_8V%A[Xb.A0RhR9m %HrGqj2-G0cgf4N\Q#"H>:;(Ig7m)V%bbou7WpTH8D\`Z*I')Urj!a2IMmFX>=YMgoJ<&+>Lu):dc1 %YTrZKaTqJi.Nn,WSiN`^/"Z&Yha'DU9V>B-?m[jrk):8$`BKCEfHa"F5s9J0]G*ShQ%&\uQamiVpD\DmO.5sQof"CHhU32ZNVpbM %$,UAGJqn^*l$oU,N#t+Zp$q=6\s)p)D/0/NBYl%%5.?XEJY\RGfiLhd.dW:jeGmk5Vr"I#ac7Fj_N2*=r)_o8%i/Go)R%.O!>f[ct[Ngrqq^12EG$[+9\*!b)N^gpSK"Y<^ %&+dI-[Wg)dGf$dFMuC!BjMC#WqON2%<"7'*;jc`/:1Vl2,a&'T29b1[m3?rVI*C;+rm3G6`F7VCr5HI!c]g\nkL!S'=TTef]-COn %L/!+ZGN$A<<:4,j%m#KaelZmZVZ%Qi.Ip7>(:H!%oaGnHp3KWkN4l&gTYO5=WN) %OjJ"?#Ii)@f`n\Da^Y.]p:(9MC.I/4oss&R$)20Bk:gE+n5iAcWlYMD((9@HNbTQRP9KMR?Mi^?/"rHXNWDLGe"H0^'QkTp+')2d %:7#:Kj'rm4SrYmCDkZJ`@rTDo[rAYPoi`c@IJ1h&m>6Q'`^C(NdiI5\48oLOcSSTD6kGngL=nnWBeL7N0$/KsHot;@XL!WERnQc> %'m&%:4,O_T[$\1RkW'D>?-$Ze&H+5$Y:@M-+aT&D-u@&Z6M.*W_p:T8JZ"#(`geW68X9:"=)0FS-Mc'+>Cg9Rcos$>kDJ'VUA)/C %kB(.5GW&D\_aMh7G]V(EY5P<_Dk&WkkS1-J`i*<\Z`'IDb7u$OGaUTBGg%h.[u=aF3H,0'",A(3M1lV=b!t&I,Et/R.[V?)^Vn"rP/7@8c:A)EJq[<8W$DFV"UhS%GZtq1<`$/70b>l7[UiWjc*#>BX<'7+&k@22^g9-On* %(07,Qg$nXLr#@E'f>lDDo/^9IL"\$?QeT(5Is"t]H2ZZ[?/MIKpW=*?/2o@[*2LISHTo8$9M8]>4=d)_-mH=1kX$.qLh %='kSK))[[BDroT32qtd(6.a)M;?V5PPXk@U;Aa;'mXa3-PcJPsrm77&DPNcXe+N;4Ad^JB-AA/33I5(^%N&_Fq0HFt%N$OGY]sPD %cSjQ,XfZR7_#,0+j15A=?oc"+NmU(_bCQN,J`W^AFdPiU!m:uFP8R(J!m:t9"cMX,SY,JN[YJr5EMU#FYA]lac9'=*f#^,2G2C_l %UBABNDK5'Q:Cd3QeD!_2U3Vj/:JE3>28!H\6\'+N)uOm@,2*KF%Ko.&PJY[qW/*fIb97.:RoUXZAWps.lMm9lc^*9kt$Yh %(E+%O6GJEtfe+Pq"k+K6J?1`Gp*m[."PBl`Ti-L&>c^o?Z^KqQ83$oTP"YdM:]WM@Ef[u#.Te_,?n1)rR@=e[ksB0Q.5#tM!7I^3 %?gkJ1;\XAVg-R=U6r1@^\L<,Pg$Rha^0$==qIdBWkLS/4BsqT[DjaRJ$+FW6[,th?Jfa7@3K@A<[$BmmhQ%bO]02)UI7ZQ3m/ED* %=C#lurrm#G/8'V@r6I=NolKeTN-+/hj`Lg+]#80knC,gDGi51X12#MS;'dX>KqHJ<`'I^t0$sK(dtN0)?'oQPJ\`DqB1[-:UW"t: %"`'JZ7uNG#Kj2_f*%a@'Q8q1LY8PO0cb^.%6&sOho`lR'$U!r57uNG#(#JZ-/(:?,$$#M$b4W:b?N7&&=g/.SLgMP!Z`NM_d$cE] %jQAC(($K:%1,FBM$WDb7T-_V'piV0^QU,;/jrOY9\g5s(Fc":`l+Dp^7uNG#"f^Z-8'AhE/9,Yu\WpV-55lh\B-u,?&V-$A9'H)' %NY;ue3^_o,0F+Gm7BO:rT(TFqJ.=utI2*L[l6$+,CD\!eB(u]r/VE%ad;^er,PiDkP$H9W#/n(Kl#M6[E8HQlkHVN^:32Lu&BD/`?j.KH %6%!j.:JA%g1q=I)h>V/aL%rh,hYGN&_Lja#0EN:'+LHa^Mh',"jqm0[2?M`WH,:-^.4hY&:O$8'+n92M4a8"A4nS>2LIe_^bi;1% %giem2pM`7K]LR06'&b,sYi:Oo#d:+SDVK?N($&['.^!4r>e)0GU"RBLE7I>giH5oX9US4@KZ=4$K*cH.iJ1Tbms@!0/bF#@I^?(Y %F)cYb?HZtm^SS%XF0o'O#OqAR?@`XpX2c[o[Oqnrmg7g+A?+9W@2MoHh\M7@L@saf$+__\qEZj %eE^V`GHpLWlar%g(?sP;7WuW+F#.!?j.QN.pbGKr'n5ThHqSUrSfcs5=1pdXpdVqUT>qPE$[m;$ %Rqo0mG(-3)nh8\9*9-oO5B()@O7&"V+]O&Y]\p`?]tKEN6RF;oAs\YaHhm%AVWEq]$JNd\(c+b(lAWHGK7CZCr^>Y'`FQ1..P7+X %/pegkGlrJeY3`>sa`!Ec?7A%\k/MUo[W+"9n-aDid"CELBMLM,:0&EbTdS(B"#O;ls.)3#db!d:F7Zs)p(]OS(\1fH`FI.fA`]]i;d$2[Fnsg%%i?DNOk#%/,__.u>.KMg\[09pbHUFO0KMR=tg6%b#Pkac)p:=S7Ij=@0FFDIQGZKQ^sDHB_%;mMhutTN;H8;5D_Ks#dugOf3F6>K;ramt:)^5aCh7dMq*J %pQsaPTAIr0J[`tl)APXN+!/c"$\RXl5Bh>\).nAE %S`RCLFBtJFk82PC[D1C!(d=J+4sJG/q8A4(l!8d'`buF_3Ir3RbbJn+JN^5YA%bVJ(OE&t[Ft=R^T"37@qB>NCYeBj>e53o^6g$l %*q.=/5[7jkJZ9ki*9XDK)8l02mt< %q;0H.]ek/%%KAca5UqBh-m6(L>elg`VTdh#Delbo2*<=$DP0$,lo$@'4i^g7[!jDH078r,[7TGJ,f:L+?UA)S,Pps#T_g0[FDe=O %BIGg!lLsiuhHb_tO(XZlit1cPq0;*T`^%Tijl>U;f(LsKY2H.%XEEIC0=6%WFgn7#i/BJH1q]NAE1ZJZ'r]^jSHq#sgginMNC.g6ka7e2\q:qEP[Pl/fDImXO>TnHJ9>+#sGb_Fa&KY8"M %BdfYi]ND>pr4^5Z?IQ"l>J^2DP("T6PTVh+["9)E*nVDJ>/=teFi7>M@V5qlonfd.`J,"3?&5T?jhl`sJs4)5=_IslY(m'38SA:2 %dn:^+/4=)bo65(FdEat]G>WW;&45(agW8V-+CF1=0=oAG6RdYe%K5\Y.S*`[s*O-I>3(pcF\\YGl=K@(tOS8 %,N>7(P6h;=2!h,0ua-&jm^!f#cp':KT*>T-C@bfB+p*F%fR1Y0C[2 %fcF#X]Dd,K5C"5S!W3?opV*m*h6\P> %cK1ep\3O,mDR[t%o$[E9`VqSDAtnhN?BO8'kkTY(`[<(]QHS6a(A[nApd)e&#I3p<*hSh9_+O^pl_S:%1'nP"T!PA>f*\U-E]R7\ %C7k!.`Ed3WR(W>;]"Clso'-MLH+&5g[>G_cN?W\#.KO\7H0==U2S %7HmmnFLFk`5%.PCdb1XKr!0)(WrQ!Yn*.cCU(@K?J!"+W8sBC`f=0*V]5ZV';iR%C;@tSX!+=Xu\jES\);LlrD6CNJ8?^jnc2\Fj %]s7F;#phD-La6g:q?nG/k^!+)ri('i:5e?/F^0G3m)u#>20H3'JA5B!k!@oY,eRKED;lU?_g%Sr>&,/7)k6NurHY0*+'"tEpNAA_ %TCG1ghj8P%C8_'^6$d6'#7J8C12,a86\p*QGh>NHEC<%NhBhr+9dQQndGJ($=jc;7@/2?g)Di>&Hk"G`)E--qbu#@l,;t\:RsQ"9 %(FQdXML`3LnWW"b7hH=,cnh)t50?IPgUd.nK5/]R-50-30>(W@gI)fjoDiQ,>!`@[!LXiWhe$S8s %b(eKKelMoo?6IKLK#pBU/#-\e:HO-6LG6HO!n<(8Or:0aVik!JIgd6l0t^kL1$2kYD2mkk$Hc#4\/9V#[H?RWaUbX(aZbg"OH4Va %ES>t>e"h$*TJ=J%m1SE?iO*5^N=A+-/A`.`jH*e/_&;VQifHI$JLfI9l]@h'?6t`jSf&l\l_Te5[]'::qK>Q$o\d3\oEK_?!jjuUXB0lZ6(9BmrEJFn#uc8:IsI:E//i;Q;M\`)`0V0^n;JjeL!Njtk%j9H(U_<_Q`BSBWkjar %TjA-@,IDceX9Qo=%"CX.mNr4FD0Dq6h40=[PgZ^df7/UVYn(312%SRa=u/jh\HoqF0%),D$2Q*GKt"pKYqK^=?R/ci(!e4AB:.mC %)Ge&1M*EKb1lVPt7;GN,Y--#bajap"4o:Nqk^P5_W0aKY6D,eaf9Sg]YbSnYiPfji\Hlfsh"))<)FF197r*SAX^^/+hF?pIX\j`1 %@7BGL5LcAhG8&:A":[!g+49P%pl(V2oV$0$h8BG#O\G+/L-Gq_hJ:%AZ,BdL<%F6`:rO %U`%PB_PeE$U`$Bt_l+OL,@e3DP&!$@Dkh+QGbKE-AcA-1K>@*IDNbdibo8DTHg6S("U>X?TZn3r`LZ(Ih#jL':Z]I[.,Sj.TB1dP)!>_&h_d:^0-%<,INgk\PD^n0(=qH&XpaE/QsYWPl0l[k(6Nb7l3,qQ/\\#$^;0)mhr7;_i="Q( %pas4U*PV"`Mr3Meg>RsTGjH2QdYU:Q"!>.oQZSrupFP=4pl]gq>5([k(15K"?e?HYhr7;_iN'QsG)L8Cm&q>ck"`bg3_j58hB\6_ %.5_B'I02!J_%l'/l3hlk[D5CAaGb'goaS"pKl8_>WNY%j#qEW?1Ib5g'smN>pK$Uf=1dZ4?EHNP@@K]0q<.M*FI/GD+;cuCk*':0 %3D?D/Hf_i.VL![<)5G8kH/-\_qrrAPf,5&/J+QhA`om*&T;$D6r]'o`ERJM %oU8B\ilg2(`j_J]2kb7OnN&\%pd-WD;X,E3_>4s^;,RpS%q/>K\"V'3hQn8['.:aj?_aI$qH,h.mI/6%.ahe(D,;M^gW7;t`;r1C %5[!JH]"[\4V'X[j')J4-H4R'AUj?1SX[8/77N_?PZ_HKLiFgIq`o*S\P%Cf5,pCH?aRf.;1K!p5%;i*7E&E0T7p>pjU^qfTSqV[LlS8)(eQZtQ^)&lEdd4r_ %H\,:,o(&T_%23s?XVJB*'=adD(L>%6Wd`"CIrUY,h7&-:[W"2HId!Er1b=%`VKAs9IXQ?Q>]Y.T\U>lNN_qc5>((l_V@R%-G9qkT %762)1al.*P//*L.bG0Fc:\Z)u'\Wa252k[_DQfD9QTXJT@&_,7k&VUq*8OAfOq(tO)066#e-8UKA8_@mmEYSTHE/8)h-N)K7(;LM %)tuY4d*r')5sEU3TAK0bLC^+pUj\g;h"4r*!bkE\BO=M*.37*PTB>)4M/)kJZioG3A,d@h.,pmW8O"rp:Sllt\W=`#[WO7k%=1#S#So9^"" %doJ+4'/cNt3)uB%6Js=AR45NR1T(E;d@]fnIO7Vg$'aLXS@kTaGpOVkU]S(7e-$)[]q:Ug`Qhe+_-a-C(siFVYj/aI=Zf&*p;^MR-R]!e]` %CYVHSg.1MqM\.l\V[<6V@8A>$,;GfCS#Ag9YWcMUWCP!5GeOC\0)cMB%i=YZ&VuDK:[72G9Wn`[l;Q7o`Gf;UF%jLhS81^!^QBc# %?Hch2,@;=0YtQEYZO>[YWD76bA%o$JkZsUj"D-!4VpgPSeLO^#.^S1/P(nE/!dO:jPB>+CMB*m#[Mk8D@jZ,%SpqZ%JF>BTk9)Z@ %&jf9:5C%/b`c-BNdpH;,fK7E'cHM-WV$!g(?rWl^a\IsFVpPAT.m(.K%_D$[&jupMm_4gUi*p+]^8nbQ3>gpc=*$0$EoWjF]/d=B %HrtpaHp'^d'3G%D+&PSjb+*c3'6a@6ds&kjp[Q%E-U-OS`es-SlLrVrEB9=pYhMe,7^'G;]oC<)-7bka?a=(C9j@d]jcTKQ[eIe$ %[G8#JK3(\?+1cds7,O$D,gnfO7<@t7Q;VBBI%@mT^N-0$73J20H'Z]ln,."^@".&N=PJV85PB=YVf,"qX??DI:RJs'/24F/n'q/s %54XCdlCtJ-?oA@95Io6?'TY-"Cm7.!cq[*Ma[XfFb0@cFk?b@eF.L*.a63gS('o`&;-#"u+@ALcOU>!N.7f`V!hgBApf$B&VE?O[)1dDo5#7KL'\jsp[9.*1ME)f5c<,0V.d[X8IGH1bDK@a5UQnQL(7SBO>?7]/'f?H>LCYd> %m)X3]0ju)*HIg!\@_t134Um*EfO]'KCqS40gc8],5-I('Cc/l=*3+oUtB"P!CG"b`ZM^&;m>";fYuCk^EgnZXW!g %4MRjAZi"Mb]Q6n1V-+po!m<-Y"E"RK&\Oi-@GBcP=3q@Zesb.?&=9@El'FkB92=:)PaTM< %atc""rJ=Y3X=Qr'\uIlo/H:(Si@79#=n$O)&!pGgIc1^/(h>k"q=X(1)CO)FM8s8;0XD*$f\3 %mI+dIoBWO./Sn,/r2QZrk?'8F+0!_"OS!"&pdgr&b4JV+Vs0gH5K.90PNJ]`7RUK.HC?N@A`f+hR-jkVS:04AF8I!Z9GHj@>Sb3+%eE?PLDmNI#lTpJ,r"5L%$9JboZ1-7XH7O/@LEg(G0rE_Y'o:L9sbV;LEr;(j!],^jp %j)D3pA0co']?XL]%c&uU8Q?B3;eiRPJuKNr!INkS28Ohi_*AIT7dO;7TcaE'.n_bmeEhofe=COTSb+A]E+N5@RYciqiXaVcXVOKo/bReSj: %5W)>rG*/fXn)r;`Y4J5i&pB#6MX]R\"S!P1Ne`&jfb+1QVK;G$E&9n:?0P*s]"2+VVsAbmbe54q@^O&YHDa?,lJu:?lZ&@=R2O"7 %i&'EkA89?5WO>.T1c]nOA&A#r:=FQ!EIR$Z9IAG)n):f@9)9SlHOmkuVW`AG"`&\]4aQfCDZ$<+n'SK9,WT]6LkNckiqS(HJ)9r> %Mo?\I.moIo>))tVI_SRU=6mTNtA4'Q04qSXgs!:._`94#NX6T9*]`YdFUK.lo[:9qr:LZ;[R@.5PTK00;Uk %S?]s*_E4YEV`02LN-`;s#ED-M4[9CX,okk %(!NlhhS_=%=9Zp.a+/M8_('btYbOb/ggbn83,'bNamVA-m)H$ogRfqq!&SNZG)-6H?+;m6%1\``&;N/AA1nYNP;*WCE%]^;b?p>#5aB^p)%NO?=9(f>5A/JVEFg^ %T^Q]"ei-cd*]/BH?5i.!5HnCu-\#/I-f\NSFg(bt;LVqJ!@QL=K0l-aNK3]mS6Yc-;n7@Ce3(Vs?X0_(5ktPMo"-7Y;Z4m]klXh[i.jD@JuuoY9%2K3D`pU]Y9eFo:(-a;gG(Vocp(]J\L-(otTIE:r.3h"T=QH3VR>PM_)H-?6Re]6S8X"\j8YibODSmPF/6;Zm.g %9-s1+bHZ52\LM+^=[-\s3S8[)#$6o4qE<^ffL?Z6J-ZE\H&O@I50)bms%Cn7ABrNk>fmdBu;XkmIHLeS(qqTIr*#LZ(lVf,=!j-)<6L[#_ZAHIjI%T73L)HP"Dno%aI4_g5=P?VtIk' %*&'M*):J]bXsC<`q+2dB]=&U656\AVHp'/J#7Rf"\U%Y4%N*F_nb'[aS.Uc&R%FHb.Z)(G41i=:/oBmG(gm&rZnT]?9?pn7eX_1>-[7&'jP_1?o51]e]= %$kC3N@MCkb)'"IGUt?TD<+4Il4`N:oWPV!e2&[LV*9VpDGU,>33R22IX;pH>SU;[Vh&84m+."p#/o`Mq1_aes9-4uqLiXFq=+]I; %5RE67#;X?1J?'4h@6kXk!p=tZ].>qeV-b%u!j%c/0"CX]"^"+N>gqb]&TKEdOm7iNj;@'CAB-\RNH;6#A7hh#>^fr\r8V&?-/Ce% %$'''u+Y+\$3*5;+g>XB@+VW(jp%9)'B>d/hAg[+5BkH^S97)lb[s2)7ufC,0nfkR,'^4(&Sr.KoEp192(l'*tr %U.&[f[]3Zhc8A0VY)!R*:2qnt]@(j#Y&@3/:E257e!(1.\=QLCCI1J)Mck`k1F"NtL#-8Ckc^#C9-ZZ)OI*X<;lT+D;YeA&D=TZQ %lZeMr,!Ved3:Q@4>ZElYL\>h[CUB:P\pb\cnkkh&"NS'3\!Z)5QR'U&n>2"`0sm6F=BUges2>c:qCY&=em9QT<&_%H"hgW2Aemle %$gs>]1Q/#n"d<3mAemle.k39la3'!>\,\=CUQl"pUB+sB7k75q"3iBW$9c.a)Ae'A#f#>-8aCPnQN.fpO"^I3d(lHWKh%>Hnej08?FGq)irm.7;?CZ %aHPX)oF%QI8k-AA3:8Fbp+<(Vmot:j=C6HY/S7c=I'B6Nn=s=&N_='AemAm\Zh3u";\bV_5(1tG_.mbe[Z:?gHJBli?/eglKcJM/ %Ge-KSWPZ7$>&A$!DKhAbcZ7=Kn=CN)r@Ce)U1OUH5KiDpB;iZkGdciMh+UgN"F_,2YB3cH_ee@^5>ga:o\NA*p%7oslZ+aBBr.Di %:P&3Tp0Y#k>&MYhrns^p+Y4Qml214$,P*:SN?k8E\#e[_7GdF\5IU`Me.-$l9c:,[^(Rn==+'V:N]s$ePkb'Q:u.u.T\Df?QSeH?2YW6 %(OBYG68lJR.JR0g@AsPo9A/L*DceIhZ4S"h16..]02kC5LMVWT_r,?L.%,i$`=K6T1KQ3QL(ME1[*#s6)aYYdYYoLM2SpRU7sieh %B*^HEBrAFDl08Rtf:LDsDkVEF5S&CA-_)W>I7m+r3hM@<]B11Rr\bflV3b&SP2@@i?B8k@jEqDXSI\CbV=Ofl@r(;8D9h@b\9!_o %CBK"36+4=M[\L#4Z!F%VN&)9Zl\XuakiQ7$Q3C@d^Uc#?l\ta'W#GL/p/.)]L>`p_m(s'k@7OB&Rq2lo8cflb$]8RX=aCs?XX0l7 %k!Lrs@i7loDjm@Ab7L7THte/!QQ7AGr=[PYIJi1!TAbbY#5CAHM %f#d-apqi3;hON.m[;fC%2ONN0YWjHKW.>sCZh[71S4aJ(eA)T@bioiKe1gI7Jq4j6rYS]Ibg-Da^sI:aZNoXU %J>'$if`MV+X*JtuIb,*+gi<#&r#@D]SBoXd$[8[sH!l(2(j6S&H=213R'+AQH=213QljqKJ#:CRa2^9jAbc-B4YT)*9YW2G*Z03e %:MRB3:-H;)h7B,T]=m4MFX#33$<.>qhWJO$"e&e3FhuE'$8fMVll3;0V:G=\j1oc'mNZd&-k8pp_-8I`Y)?f$$f*I%F^:g-0(ic@ %VOSb-8q.)C]:`:^TWX2:h;u@1Nc^UBECU0fF.D)PHTh3gb.B]09"XC$J9]uAE0nLM=cQO5J$E[S3XUddq,2'PH=qkFo#Ec8VrqiK'M^c<%OEAP@;%4(%1fDl(ef %:L*dc$I;s?,u'X8n&:0i@!kGVO(dqXClVT*NG!o.GMl^C_Ch@d1rR:!K8'&&4X@nJ.9W9B %)9)6[8DPn#.E2%n8DPo./j=_cZ8T6%LDEeL]Wb"c""f0X_DTc3QT;$3%5"BuH,4]`$OL^#bFI9BH^C$99NdO$`S/QP"Z-5 %<"mBudiqN3b<_/4-FjDUKj41004W:YRZaeDXuUh#2Lb_`Vf\RiXc4,j!tN#W$/7,,)-PBB?[bhkZo'3guYL% %gA&?X4kme%tjd&l::e>f'A0-i:8SVEFhI9"W+^K-=eWSHK&Y>:-\]=TtR[UfJ!XWt\ %L+Yl0W*IT@V1*rjEZEKqG`]*;3hh\66@Yne5/Zhm,C_rX#;U=tkjP*d2j!ZZ#H.'uY0S5BUd@+c^Sb=$4QQ%_-Poc;-'^kGWa\RM %83Kn-.ebeJQ;j$r8,!g"]m&LfPK\,X8h+>B?gn>p`?,aS6AY4dbG%K4iSFg+9C)qXZ%<]Q6>6+PL`@QPS)emE.j^?CSIM#5=8WXs %bdQV?Ls3PrMe%JPX^FR3,.g;M5MrP\1>bE/&!G=>I)83T%[NR!&=:Gr%1$t(e`Hp+Ls)/)(EDGO]#s+*$O^tE,.8*I.aVWk6X3_p %iAHS8&/Wnt#$$:J=jcQ83#!9W>m8Pb!JST9?);nOg^B78]'=atQ?WO6We"a:N %&:#;e91ld%aX)I<=:-]Lp=(6YdH.le=fq2`4=B5*O6>IQO#`lrT@KYuU4#-cWJ+QE:.XLZ2>QC:M>l[0D0d7CWY!jIe1u=0S-tHB %8M,FX)KR(--`Me+LJ3EC,gSBYqYJ[#CE^!]%b]jW#8AA+lKQ03J%P8j'Ae6ZT#Zq'4q5U0oaC%LQ8g`EL\DnV1[ke^aBkN`'a]li %SS-%R\h[*gl@3I<3(U4'm2nR[$JK]pQ38eJIfD1%rR,l=:A-LrKEs6QEG#JgIh)m^7!O-&0ro(@i"ZSB_S]n#futQH&RM(M%@S0q %7>*V4fD%.SQV.H:/#&)c6td1R/::M+RMg3C6]%6L1a`J\QgjGfBP&s0a,7p]i'5k(L"DgA4]_)92gYu`naYBYW;D[%(H"!^n+d$A %_VFg\g%-4]RD;"4hmrMZiGMkAXjALA8TsZeDJ&C*FCrmk(kaL\[[FsW99goVNu@[*L@"*`'\ZR!7DF<8G2 %F&uih&p/I>IG<'L:OLmD!mF&(97EILqY3jh>q.To$[-mV*RWcjWciGZRGfiLhd.ebIMPhbf[1V=-5t$$UUoi4[.sE!qSXDP+i-E. %$f3PlL'6>agu2o)]tP%JMiXJF^k%P*,T,`X8MU;\KA"S6A-+.`Z_(efZ@tOuR/JRA=%5G0R/O+J(,O!lBD&V#Ue2=8KA"R;f-Sqo %io=\12,"\uKA"R+;Ol]B$t_`Ia]&S"@PI[^Ae2)[U\4MLO.U!G_;YhS!gt@V]K:=iG2O6k<]sHN-h+Gr)3!mWTV%h[WAIJP`RZU0 %(?7J*kiZTPmhk4Z5sIS,i]\gTk@[BA-O'JBI*pE+o;&%OT*6bI^6=.tIMVA5$$!?IpfXh>)kn_WANnTAZ2ep"Hl^a0>=56%$F8HsckoSQo@)F&Wt/aYeKbOCtu`%?P$0Qo6^uVXPF@<:)cFf''-o*l@7enc)os'cPNa$sKYG\S5I-X)7_E_m00JQZuW\`n7hajo3:I+K5VYiCo %?%!,C,j>%T7"L'Q.s$o^?`c1]l3-_h,MV/n#7+AXV.9j-:hh;$mArRBW^:m5foOGF[.bunfq_\R:!]mn+[2J %oX&-lU7ZDRP1g2@\(d/K5iYq>;>P"4%f#jBoV2b9F:B:Q9"[9cTKeY@Put*'$g!md'JWFokqldCUPOK<9p.Ms,.`H^W<4'B;eS]W %?Ru\Tq&SLSdI9,+VItJ2`-H@bR.4+rbV@aSN+J#X63n/XT#D[*'6[gHfJ^&r-HW(%GSY?oP"CN#/ERerZpKW>FQQ[jD&6g<7hapD %ZO8>\bg!b=*K6UN[QTlk'Om(?BoZ#!r.R"C)4)-M'AXhMGjhaIP8B9\(PK_O5-7LU`;!/8r'bjC1?Ktt&`["B&)g6a]K26&*oX\$ %o0gnL'+[jX*70l.>*)^rGW`#l7#XntnDZf]7Ci!/8Vus_%VQD,?J!8)@Q_=&)B:i&$!EYbJ(/=0*aTZnE[Lj)M*o<-W]ToU>'%/b+YA1%b7aiuDFb]m\X\h/!f9cs(QJS13+F4*iX,CN"P)SV\^"oUIN,c]41oT:bC- %\oZJ07Ytq[h$=6#7\i&WW5=pp6JO2[WA+'TKr^]I/.YGsDe%tM>!3lYoMXFYZgjrBe&3?hDiYXj %*in1Z;-UYCfr0.[B%h&8dOud[q4<(,1",jh;hj4eoAF56gN#]a9[)0<.3]eO-Q<6W>O6/8EAks[ha2uOHT"KZ`AIss?bF+/<=)>1 %`RcE3Wl/N*E,QAtY922%BH_i4XsL]4eNdCA!;2d==&s&jZV`(2/1;P#RuJ=+8d %]bN=BL!Q,2*E=90$03SpV)1$,4/d9']h0Eh-$aV7]h4CIBq:p5HF%i'@nYR5m/,@>,.h'O,VgDsc %O@_Q;CuSD5f[05]Ij+PC];Z+[G#c$T&)nOnV,_]r8l>= %WgrHNY-IA/$SpJ3X^9i@hs&^E^29!8IlBb/HA#ENBcTCr?Mi^?.q*$&rDch^R@]W1B>T2UT=WHmR#*MFQ?m^7]`6+Ge(GVA"D/EI %OrS0)9\hA++E2]Hf=)4FI"N*m;?"7VL-FbDXhF^jVDn!H/E>#Ggo)&]0udkWZ&+N!lfM\9^OGjC$6R'IABts>rr2i+WO6b2],V(F %JD(^0O@O&`8HPAYD+=q=(G;9n(Cgc3!1r^S[R]h?%,aDVK\o+Omf8s?*PiCEJ-W^;XqDVfl@24-O/]@F^`+B@>&d9T7QRO=!^?5fiJtt!:P"ab#9^cekB/4T?0msG7:=5$D'I4t3)O'mD9Yn%:7s$h? %a(TgUl-\n6;A4r!0U'AYR=aXu'"V[?$&HnA,aBO!AgB!-OF]U9aKYZqdcMdAJu#OecFh20$BeG2iZ1J1*b+s]@W]VgH\gol1\BP% %mNJHOc!\#9[YHg`;+K+m?N_#tU5,,MKc"nX)e+o)Kc%o,e?-R:/]?!b9\Vp.ha39N$?Zk6I:\`#QR&jl$gs?@15rAi(dH%hH\go: %ZQ*/-%5F6qT\g^CEnI5+5+L`E_385jk@X#`,L+%Z:Z[q?K)K4WSt#,W)&XsJ6T>cXSqSQZA*9hUbX/G/AG2:)GVcUSDZV`Q_Lo=Z %ABo]5he$>1F)f"7M=%k,LU,_=[VfPE;QF-\?M\m80(O5<4*g[?ip^Ph=";Jl]Db%Q?/Uo=eY%V?H3Flc"+#5P'*nK"ot6-6[Qj!" %=Rd^Jg/?e!;<1Lm[!@9^5rUE9csB[arL$pJ:MA"V[?>0,bXsb%Z)/&>K/RWZYK(g(s)Ho7`r4=8 %]"?.$BSH2Pr@d;=fN3$9)/4kJ&KX:CXJS]Dm2ulK^sN2#9V'(WGJd?XMmQ)\VS@:+(b!+?(QHD;O)kYZQ6R:ZF1lE&9e9!*%4@=;&>'j?rffh)'W4ZDeXSsRbdeQV0cTdeTN=fnM66!`SU %>KO@iEik_Z>$_\d7(H>Z?F:R4(]W<>hf>ideQP!oT=A.LWn,lm-YBajH2=u,kbDe[&U5)n7NXdGO6DRNH'DT8:UVUb-q5;$"XYaX %Xll;5kbDe[;86H>X;@c/R)cJkLE6#UWE+DjSqAm%A4#9c5]8=XA1_RFOaDILT,mUm=R_?3J[42qPN3N%1\R'SYSNk7Udg`l#(q1< %!Ck_VS.WRM+-U4Y7[Q\$9!T!Qb[Z8sZ4J8)@tR&g=b%+HZ,%R!/\hY`fO0#[Qb*jlq>((77">m3&Z.UiPIhFhF&r]&_E9`DYo;eB %KR%AaR(!c;KR&R_qdT\d0TQYia[1q?Nt#^h^iMEN4>n&;/-HeuSk#=s$SfL\2OGc128U-kN^(B0(\XH6Yr=:gEWKCMCRFBsnAdY4 %L6_Yfr^3mZd.l^a=-+o%qK$o(Yk1pcO2m:CP$st_I>-I^/Yo%NY:?LZg4D0i`'(1MRRc,DL>H1r-=p!4/"jb6c.Co3O8n_Pa1I1Po-P_ %]*%T;fY$YK--Rp\MBZP"^Rj#G^Z]02F9saj[!--+2RN>;pMSW`-k8R?U4W`k6jR6gL`g.f$VN(34JX<$E,@<;J-a._#jODX@YeDc %KV5AQ//f]L'-ZRhmfu/^I1_(p)UuY:JhWfj!>18[#k$fG11dfs^Na&p9l^Og13Q@GEeJSNRVB0p^H]dTSLjhJLu9E1>NQOf3pkSL %-Jr.3'r:W-H>71SVbFR-e\Q=d`N<;tUM0:7+cW<,gIgU(6M9Zp@PP9L?64**G.dQdbe\=S %ZZeO/Q6_[fC9b-\&JEe89eAp`YdKim/R=9'fNQLrQ:,1t0q2?[V%dc^0q2@,pIh`m`GB;Jl1?B.MqQUCA-,tng!nHJ3[8GmAlB)7 %THe;*AlHn+0GS8:0q2@d*%WNR0rCr33+LoH6mbh?4E4OS,/'rZ]@O>g`)%f?Mk;&TA9o_7]Z^X5'p7A&_R+T+A"5i^f"ZA@15;di %lkLhC,1;ra&Nd[rdTqmdSmYc\g!kVc1=F`_2RQqbT9tKQgXK]#[j3o?#k(AT;[Xr?,&JoD;bN8[Cb96t.oou8g=/H%/DAZa2RW/t %OpG9Mg!g(0?_jgCChcPc%R,`KjeQO1XN/a`Xj"d^#A:Un3AI]g)Z<+g^]";ei\bZo4-9HY.)p\kQ,kkkh*h)d]:DL-0)$"3h#&fj %^gEi9[PWMa%,i;oITUiCT:_?%&_A_Sm0lb5bg6j78nF$;RFs.UA!qZFc%T^RY?Id-"lcaK@dIT)0f*jeo`C@i9B8)se=!N2A3kVMUnSaZbB>fgfKfLBoe]=A> %69(C\O37f3*kl/S5ICM`@A25m?N3Gf2)5ql5Qhg*NGQ"i$*?\*R.`kIOg-4Lc5qqC7`M>04^l90,NG].c%loF'b`M04nXg/SUtGt %1\qu\&pH+++.!T6=E,WCqO)Ld1W#F$(n[Qo6Y>sP*hJ&G8nR_U1B,%YKHqm#qMcYCFX9,;d>uHVX7;Qf`nKGoWCpkf@CV!:!aRj_ %q"TQh!aRjDBDB^CDN``q=bf(mGmV)J=U4iGgk8t+XRd[F`>3X^ajs0H5Q$fGp;f:fBZ?r("u7%OZZiVYbpN\=sABpSfti/0a^TIf8W"BsHLmL5CuOAq"Uq%D@nKSWT2U%$#`[NHF%m0aYoSN** %UUC(V&?kP4nqHj#R-6Y#H%p^KVlt$(W(A"J0F:nLk3r%/ %g)()N4UIO*Bm6fOp3./?s2uZukND./\2dZ:h;LNsB^7->-o,XC9;uRB;XGD3@0;r5>AW]hCqC* %?d/GC^$nO)9\B9<]D5+Lr1gsn`d8MRjrXc+f0H9i9q^K's6/&@%5[KaXjAVid(83]Bn^/MH9fp^=Xu<:e0DOPEON9*Ia`CuV(<5) %.Zj6iN@FVtRPLVZ&1)c[d'MI %8>OcS5.4Ho)6>/'b"\YBm:TXsGGR!V]kq!4jJ*i\]kpuIG9t50@m=q`1&S9\cX`cUq[O"L"0r4aZ]9N!NaX\_-bM/P4d.ntli$&? %<_jnuI_?i:*^,]IoBY5;RGFjN?U"C65C,JAne:QZoCqXI.f.&Z"n^;mWcgk,l?q]2IUrn)RSu0V7>mf9$U++uXAc+tJE$GD*nh2[ %pEnTaiHoA.Y((V8rS2]Nc5&.fUK%#2o%N>X+"*1S<7:WPD>n&&R&6G?XF;LZ7otD_Htn'2*V$o']l/_:"8$W8Vn-a<&:B952f,!Pp[YL^n#=$7VRAh`Y,+SsS'sM6FbX]T\ %V_?A2F3W7`c>W>Lr[$n-A$F:o>ZNqa>%-,$lh8`>EB;V3b"F%adrr40\']KBA7`.I90,mWqA\%6nr9/%-+bq`=Nqke1HLm4rW+DA %'7DeTP=Y5.(/54&/Yp`Spc<@&jAm803iSoUX$dQ%r`1#rD@,"_P4CSN;8K;abl"bIZj0 %'fRn\p,/`i%4$2"8M]mN+MhG.&?%!LS($mWS%W+R&Z*`,/"6u+'PV9&bfXOMGX,Hd*4)pgk$]Z1S($mWRuKF1daI9FVO%4aj?>3[ %0t$YQ)tn9fnB,A@jH%KJ-T8A[Vene'+n85XS^P_A/r3i3iE]lSB.SF8OK^7Z>[;:i(Q?[8V\p,P?A)D8l*S9d]?)8G?oppf+akr0*gKLZQHcrp]XE#@?AO/1+=>+T@LQ;gh %L'>tGN-S[4^V<^hYP6f-5YX&rMDCOZq3bD[GGXX%r?QGVAt]GXYe.PRq1_ljlmV-ZY_R9Jf:'[X/YE:`NSZ?P(A=?(NNe\9hSjYV %0i_3"CA^kC>"Umo"^^EC35P&M[-#to?$Ue7N%a'?p!1l]g\,?@i4sP3^:M\"fUi@[(m>l*%Wo&&jbU+2dFfYmH;T]Oj)6jW+_5p% %Sb__SjX+29R:;2hDS@ud2^cpr:"W)KZTgW0QtuDJ)4m-03*UfJ49DeTh,rXP5MuZs#lb'c-tg6>m+qApf'DSFLHT,/#C=j#j%WW? %h-56de]uV.r#KZ7/8Z\;a6h':c7Wq0IrmKC7=BCm/S$V-%':'.c##.?q`(ahIDq2[=3PsRalColV7"&\_a7rL0H!U[W&rO1@+48C %dqbs2\1?r6-5BnMSMSB_@i+"V\"2-q_;L?T%Ar4L,-agG-CdL6b4Ti6K01$9NGY&D&EscR1PEP5(^=Tk$XY_3#*a#!'=nSSdH:_^WeWZ0]JTN0E %J/LSVSYT:0"jD40!oD#g'3_4-/>QSi&mD+,/G.e388,EWL9DWAVq2F!-/E0HT<2Ju8s`SeY8b%@`D5`>irn0kkW^WdA#spY2#Fu@ %*,(Dfc(")lYC"o.qUI)B\sL[Xb%-&%YrtMTfNY7taC#h0Yn,.%+kuWKACu6O3aY2n10>on*Z;:O2U-Z&R]sa#K>k26<@qh2)oPd8 %V5K-uN7DA`^M5Jc>RWD6;q5>+SG@cY_uo:>Z#'m.mVp8*rPF2!(p;PdApQg/-o(E:T):_)S1X)U-%C,]Yp-P^/;TMb5>B\Lhn:jE %iq5(6Zes#g(1\/00F5.rQ('Zs^Bld#UQZ:WnmY %EC`5?r_)`?Ud6jsFraW'(URco&Z3XBd+EN3&2VVe)n5/n[i)Z=8>]VSUrC`4'RW$hc`9#dOFe"L$J^N6""F#LWt;TsqDc+FVs_XJ %P:Z"E:YY+cbWOFHT=.,Q0j8_/S4GiYBn>QpY;R;jag$c![lq^XJ[NlX,p&kt8;j5FD]d'6qVq2(?QcZ6kWf,3qH[PG7jh6)CSUrX %s"bE6m(0r$G*UYW?*A"/sB0:"cQ4?9o5ceLbSbXX`R06K*4l"EMPC9u3*9C*.uk+P %VH-n:O5f@g1X>X3#`>Ch^Xa;XbrBg[`(HL>k+7U*-SWH(,P]tc9J/0$)+WK_i\KQDMrEG.$&t-PYSieL^Se>HQ(DP)F4<_:E*Ou. %a:['WMld#-]Va9H*#6/oN9g)[2'jc>G,Ask%Nq$PaDq'$YSnlMU>M?uKp!kqdCm!geXM;G$mrN_l`35)B'M5%SpJVC@)u2`a^c<2 %,T(QdA>V(OqjN<*.aLLA%02\\=&$/k;3*`KFObRA:`atTOtfl]M(KU_Dr`?m"]qqJZ"+:;,KGpJ<8pN5dm9LZE-XkuY&*YSV7`N8 %=89HN7p]&L.nMY[e^[$T7UFJFB?!Om!0e'>YGdg-q!,n^0!gSsil[ig*q,b/3*fB:b,r[qA1Z)Sj]XDD %GGXU4U9@9%BoJ,-IMgC@ilB%0*=\&'mV+afE/,LA/+(_SKOBEp)Vbe6O)cV+\u>J!B#,pFA2$^V,sdG:TA%5bs"==iY@eNb?);I`!WW!411l=,(81"2H3**&Ep,;Y`o"KK[72\i44O;=<,Be3/M?9X\,[Kl80Fpbi7 %"<13Xlf*uc-A@Uq]jH^cc*R0AipsVOX"R;(@1`_@0M$r[n#hH!E68Cnirbl,mdnMMXq(Ze_e]j%lX^u>n(3d?Lp#X\7QGKR"gf$n %.'8Mg+*;&ZYDqf@*9%ROTFHUNUuBUL=q28K6lGtTK+I3?%+Ou]9&"2XZ3j@L0!4qLs@U\?>W?1.lu5JTb?5H_u6crk6F %e8Fqu_I^p2+]6)9j3+V:DI@Z!1*3Gd7J(p"+J[7"@h6RY@4:[E8%I=00;>XJ776O@lOS(\3m6_8a1pTj'[R4pP)M4g\tHr,;M/9V %.HbL=LL-0#0M]'6ro`N)ZYO0c?c%tBC-c-MG\H:/?;=L.5>9FB\hhRfci6l6lWZNJWm;cU0O)>#CNNr;-)3a-1"ScbRRcU0ipT %9.%$3HL\Grd^*km>4QC5Y$OjMlfn8_:JP[XY+Xt6::1Ar#S;?j)E;p'l$,p4^`oFGZI.jfcuY.,a[VJ(42c?6hCqC=_5F3h>IouL %K25:Z#LX29#G3%N@d&5D9F)pJ?g#>REU`3I+Zd;fNe:,g$'AbE%Xsib'8#g/PT5's9F/3[8N?LkD^A"LLl6j*qd[Js+d,@EM8=j9![eXulO)\o&:[ab2jtB=:5.t`d^<+kEI!XCkhd %IWm][D[\K*C]2F-6$IK?CW7X$4$2N6iXs&aRGKOYMi$1&.@qLAl;%.LO^a:i,G^*D`OVg%Bgi&?R#4g?5ZLZ(ail.HJrPPQ*Hi^R %f"\9'0%(h:'35fT(."IR!ieMD,Wd5&*!%,UL,4OJ`+Vr1<>=Z('6m&b]pUj?rBl!V!hHTUb+Q#pC;&]ZIdE;YZ2$S5F($*P$@ccI %Hh+CU!ah%T[a#?K-O['[1(3+\k08/58RW]1PVT[i1#BMRUl9.rX:s\*T@UEG2HUK8@UEJl %QrPod'ti.bR>"c=WaE5onSd:mQ#p;;Ro_7kNXh<2KrkhrGm8is>#U7s[M8os7;an!_r+)g(2H;"A]u@YQoR$cr" %HCuO)`$>RSP2XM)M+P.Yb@WJk"p]+S:3T.q9$7; %PI3MoYQ0*l33\R@FsD"!7Gp@6k(]^:`nk9jA=c.5GMeCShjt_^-5/;VYRH&TpIk,aLcq:NGuFT^dVrKJP0uG[%3"4E:@jEum(H,! %rKn6?OrRR56T4K)qbHY[f[OgX3:W\TG^ZW$3)4ilKJJd'ioBd(hT6Kf/RGWZ(%f@*71[8Qq_]XR(Ah@*-:i;e-mpCDS2cS^ET#sa %lmg@WkL7c>9?d:*,d[;#fgRun:Tp*-a+k?B`-3.kje#KRoFa40aj8QZD6EN:_`A;a>Es8*Zb8O2!T7^W"b8Cg@:oD"@0\Rte*5rB %q+#DDC@oCb3h`*^3hQBj0+i]s=lqgp)%jE=h*2f#QXI@R:f&eL+!"JOB@0?OBW-)l>9sf2$?3j>I0X)V"f't)9u4Y[r-p`s^V>d0 %(n=46^B#K;Vg!.jo"uF;8]oITX`LnkL[GU6hV`S&'5Ob3ZE_"kg%SEPJ'\`64Y>ECF/003"hlj %S0f?kn6SH@X4fq@m@t1V9$s)cV+pR0hBc?p>J6s6g=(K\4\/=cXJMe86jL0jXEOYd$_!!lZ!QU2q[#A3W?]. %1i%,F4o&'(f#5f%Z=^J]B2.E*U7:;VarYHDtdU_5OWp5O8hoCKLmukG-QaTQDq[n3p>H646XH@G)Z6\_Ug^B %_m>!@ls0gmDEttUS3S6g5LDP7fdA;ek:5gi't23k(<)Vdr\l=@TXbE#Cb2GXeCKH>l>rAp#bS/JpO:%k`Qnt/A4?8u"f>u0?"nb@ %X^e")o9lZcT<$?1aPiE\2Bd=5^GSHZ?RT?/9- %7I`-'-gCu='ZF[RnO=9q.;C`Gq:KOt]reNkD'$"mpUp+,gH=AC %":rh0)qbAV,^=PD*3MJd,^=PD4Ijk>>N0o2*e*SLQZsR&kL][N6/m.mSg4]+GTMD`9m6i]8qMi]^s.'LCD&`l#;1!gJqpsin4\!O %_0+HIFV6f!#9K%RO/_RF[%4^=8Z0!)VOIc;_'=`dVR.A>"o5/[5A^W=&U`,7kd7HgLb^sYI+96_L6jhe=kC_WeX`>@e!hY/W]NF^ %LRr"GeX`>@_i>Ie,^?gVkb0rR:4gO\`+bCmiVoLD`0lhIiA6UDprWNGD&.S@e.HEjaYZTY^\m0mH%,>OmqO`Ol`JYgCeUei(87'B %((rWLDK.2o"sTh7&eBgm"[iQ`<\,N%*tW^tHfNGU($GN.m5s\#Ij_Jga8+b.WuceZ,hr&6rjU&+q:6cu%d2Bf:3JY$SBjN4q5i4a %2h.uPgK^@M%e.5!oY.bP%l9!,$M(K?;X;-%FFbIE\KT+nDm %4PZa$2tXZTaWe`Z=8u1r+Rm_$RB(!+/UCKlY,8Mf*OYK>)L.L*SpG"#,86`4X^jS97,5M*0<[oOI9o[q2eR=@I>?*+J8C1"s00(] %XqY;TnNnTBh[DDEq"RuO0iT'GK[1:+?'mE9K&u2WO-\Lh-$:q^Z3SL^!oBS:U?Q*:@p_dg^Q$c=,J2rlSiNt^_\)kD5gS!(_pJ`1 %F9NM*cj5Lc:T]7Ek2%TKgpV6!fDB]%OR3dJrr,8*SaW1FXa[L`&[Mu^cW]oIT*7^1oF;.%iNjsDe%F\'9G&g&I(#S\/"TkJ'[[3/ %V[jKO4[pZ0-'?Hs:D2@:[8"7FPYWALIThI_Ju6*NJP$N6TR?T$FgjEA&N"=s8DZI=C9aF$:d3,[OrW %TuPa-1+6ded7p8aKgLd(Q%bha,,*$OZ%i3LO\fQcIi.Sm)q6jG$FEg'I,c\Q8Id9RV/j;eI4oA!7d5[)9JpEof'0p)(jF-0)C=<"fPF5ObSa:dXLgKT^ItRt=%lHf(c91_1k#S3l7n7e90FBaGr)1`AN6eibj3@E;^VV<1-WFA)),PJ:Vj`6MUheRM,=8Hnd[iO%mr %,5c.opY7;!OnQapngs3!XU+BDul&n]7@+$U@WLQ%b&1n)1=_*(7Q:i"P/S5VIlB4RqXTBH`,.bgHLbuJ0(6,:3ITfU=aZo\P$sHMuaZk#O#)2VjTWJ"/ %r3i=Z9,9OZ9e2*B-OOaUB$cFpN7/NVR."&i2.#M9S^`LJnpGh09ImT[5IZ]@NR+3NQE(_,e2s,_R+.?Y8f16BElpBk@YSL7t*6 %;\6)rDWKkI8-^>2)UW?_nn"%Un*=lB%^O(]bO]\Ui`iJb2!=l8H`c@SMq8qj&,HpOamEtO"jkC$,D@a:QC;.A[\p\,8XM/_qETt+Q4j2rYirZ[CHR8tLa+[TD %c^>b@Nf0"?_==l`Q\H=cR2iTT=&TTm&*C#-br1]:is@XUo3cplohf7?LrG/lTd!g,*A]^!UJ]c>%U+0OD)1[Ja[&!RUJLEBa^LjO %,+%1k[R6.X,4M&C5tc-IMSOQc#;*Ws6k.+Kb*8Cd!XrhnqN8I(EmW6=S?GTr>'`i`m@bi94ORH&hNEoWnjm[JXQT`%"[g5cc*XZ@ %V0lRKO/n`kDgQ/`oE;@&JLed<#nst7pm^nXMR7_51Ia:pU-W^=JlG3o*Hq'tA=tPj3HA1=nZmAr7d+tZWP]I22o>g %T;1JMLdr^2%t+dRW;PamWL^bmIPccPT>OAZ50F9&k@P+"Gh@%?0Y %%F>gfcdd$GZ\;&lE9A'U'sg>2.V%SL6-L3T.4`/'N(&Z/?lih*+Qe?]MT=<9VdOV"=J8?HYn#-;ad-@VYM$LVm$5prE4Xo=.mNAe %:/20];P_)IH$?WKh?&m(K1!gEPQ@^t_X7"s/#Eip1@EjJI9!lOMeX(G\QS';rVbsGX&?ZL?DOqhl9A)c%LAoFKk-S2B^'^I'cm9PC$;pn`6%]0T-*dNfhVTN@bG0W@)RN=7f^XV\6Pdc[dM*c,UJI+3CeM674f %/)?cA>6"RAd)I$9[%S5R+Y\.&_(1uMSA<-Pi^%\p!Z9R^CW"EE=spa+en^o.3A?;BSNe!QR2co%6N!;kg3u1qEmQ.RE'/j5LD$Z? %-Z[#jkd!mB2Or9q*uuN7"Ttkr`\7e1,bI>[@c$15D!*I(=b"!ZaZIkDJ6DHcmfmHNM*;(8T^V*WV9t'Q>\gN.M[6YhL#!gkAt_<> %0@6GD=cgroh(PW1h.E.u1./F#aa:8+b[;.:&"8FH(&X&eKZ%%!7Yf_T%R43W5.nXlNEqF9OBt7Eb"fF.&690cgJ1=rHdgL)W_bqg %AM%Q:/`_-g]pIJ?GP'U3c9eKG0tTt>G5D_=#pBR" %H>iRq0D)PIOgOSNVO_tT8#-USi-:<&*'1a*84S?2dX+/%D)rkOWq^IQ?CHl[dfkYONjtj^$SmNkVbQ(5*6p;2jrBPW4C.*(WLu@Z %0Yo@f^$nU9Ss^_$\;),6O;33Y1@X.=#YDb;0=9'?]66oM%-.3rP2Z1dUFrL/o;VF:2P8b+L=N0hh6okOoHet0%EBcsFZTgpCF2\,B7Ru:'PWkE.?X;*sQ(!p1E7B!?WaJ]`g %c:mtSJT=k8FTpsm6LW(a]?Pa"pA)3M2NIgU!stf,bi`WjpSD4]KIi?=)eFejf\D\)YDb,td)?BaBRmEn1T=At`m2MTeg'^gct% %%<_WSSK9\qk;G@gLP);\oH7Zh3ES\-[ioj;G94A]a(Yln&"_(S9jXSW'0]BZ:RJD6;^i`]f[F$2mg]qN&#b& %66`VJ2JOYQS_[Ls>Eu*DTlG?^hg[<*>D(Su6'q$MYSK1T\r6:1on/UX(W>S"YQU-LFnhnp(qE[koC0,LakgsOO5+krk7THFTqPGX %NO*jeK\]L@cZ9%k=ci4#6T0*?bTsdf=a"TDd^7SVg:>RFaeWS&g!6E>*?^Yl5[Q$Z:WhrRt.TQFiCa0]kUJF&(j)CSoGPQFb,.# %/abs(CCQ9pUT9h_SZZee`P^RC$#ML^>*GB6/jhJ/OEt0VQ@T=a^`G$e&9.]oQ[kC0Gs`NIX@AdoSNJ/ %=a$)cb5*jm4j2-B/rk//ZWsS%h:#So#'Sq/3D0BCAOIXSn4JLOrBHr`e"Hc]95J+Z85Q-pV6Ll=a&qb'P,#g[?.5> %QJA'^4C'oiKL*qiZd]OnI0MjXcCQYKpD@)t8ucLkjU')YKq<]>4j2,K6Zi"WL^bNiVB@.]_M0SWWn,5RUA%ErMr\9':Mi%$h(QN] %S6NJP4u7:#"&LnS$t%?@0%sRQD'R:*gK^SK0!]c-NNP9?HNqPS9/5sUsYo^nl`A3.K&DtV/.[DMoKhX!e*/_0`dLD3\2LlG:_AjQT\@S*IgQG3ZoW %^sn"&gZO&]4U?*+AoLKtU&>3Wm/Co`\R8M1ACjTuTq@Q*qE.*)%k`>u+#(7%=G90b+[mmp"(eIk9Cg`<9UePNmjNKr=/O4e6n=5R %4?JE_65f6=D-+0j,IE\]WNKkU[9h&J#`iBU5C"0"+"%e.WAnkVT&>kaE!8%IDatEnqr*[][5^TeXCGf&*`pHt^nrP"dL7.XQ]5&L/h#\B:b[o53-c`Dr!f_9B,pMlT)HD8,0) %L+R^V"Z&A!_j2mWicmQ&I %[DN]S%pXOo-jW&5O1ZgoV,slFI/r`j7/>5m5$P'%UlWtB@n6C2$H&U;b'EQbiYSdm<=V/lLGro3A(+E=%&oKb+5]dmcD6NQ/-:$k %&*V#91fa?B3FbPTkkUPDR];lL++8@_9>ZA6XoW_Q'5e_b>r>W-,(8s-hfHX;]H"9;j\<81W41J^feAVCOR%0CI4$#d^j2+dj\+NG %r94oQQ?WtlQ)&A-AVE#5KC5uJKMoeK[i3a=Dd**/Z/c'T`[ScfN$/@TUK2Vdk\tRb11$JSq_6E$eM;`^BDC@D:bRu2HLl(Z_(N\C@V0(>CG!iNC@N\BD*)E#(6lLi//rftNrb.]-7BaS($Zc>fL.Ki3C:O%BeIV]R3>(B.u#f%V)nS.N!1X+a_.Kq^UPW>(6MM7$04Xj)IM3g7#) %PX8NAMiG,@$qm;T/l#k-<1I5CPer@3??8$$:i_F?Yni4*.25roltW5QV,5^'6G8`]RWNSbf-+;9FZ#YCCW6&"@gZ>RnL?4HI,g&8 %O0KhNqP^10E2smH(pX+<0"9hYH[]/?KobO5J(*=Q!<[H=q3R^ %rc?9'f5\j\E]JtCb:OgK.6oC'mCC@k?Qa,XWT>u4r!pr3Q->UjWQ?W!DRjh'3L\!UjHbEu[q_sdUIq8"dT3La-.Tpjc!O573#IcX/#jjM2BF:J]>DZ%qPC]u2 %BXMB6>Ac!m?!M!+AkcRa^"B\'Q3"b6clo] %*_Hq547K-Ug?:ZB]VQq=0oF8/XlMpZ9@m?'NR"l7?1P/+n*%D).9pNrs'[W#/=,'*X'=cY^P9^.+)H?q*]!.7=.2V;a7472cgl]d %jlblm(V%j1jl`1A@!<0=nhR%TH6^,Ec\i*k/Tdim!m!Jt8fdsMDNn1[V!atLl[]$kRNukPJF%2%JHlM&5R5K68BM^0aa$L;MPP%h %RCU'f-pY5:Kp`Mq>L\YE"(^5C?fqt`4@cA,5EcXAgH48LpR,!Y/QDDKjXY8AV\Pnl9odT>WPiYYf[ZZn)AV#KTZ'$"N*#/B/%AIa %+dnr8&7I*[T-+:=,7nr?.N.ln3?BQ"Wg@F4d$2\:MUIQeqBq64EH\Xp-Is6ldq"cP<$Sg/*r?]D;LL]-7I]SBUo)9#N^u2PW!?$b %)1a+j;enjk9T"f']#+,QFG)o![U;alEE8eb&=SQa&nQX@AE`V.=s.[Pk-4b]m"p'QtD"Ac?Bb1tLggqN0.1JU`%5?"Y5VJ8uKZ/-=N"s5g.I3b'po\F42iN/d*7)2jMWDCd8k;UEe:-CaWqjD/ %o7*b%_53UP0)g0sq7'=<8.B[@ob6DeK:A;Qj*7HG^,hqThBg.odcPkb %8`0YR1+UU-qN4.'`02PSQCX5=K\@6_)%9)]k %U>/tc@!C+;?^,nq(V%j5qk>:LX_iBBf?,_,VF*(MZ$=*_;"R2EApO+d0=,$0F>.kRY<>O9VG"X]QL.Rt8WJ2M9[a5m[J0#r^a3uI^*s^!nN"YWq6kOi %8`38$p3^)W.+0#(8%un7^loU7QF["b*,V!%?.`K[/PZZ-K>p^]Z9u*0HQ5g!Noqp/&)PBLZ9pibHg',n,0&C^3eT?J!+O/(U-js= %QQ:A_gS8Rtn4?i8)r5:gq+i`09L[!qj?[@tRCe'!rh-R@Fm_lqnWa3u1=s&eFWLo7b?PQZ:p=%E=lqbh"mY`QZHRIZMW9?11<80M %?K\Ijp<>&04Jp4-%pa6X#H#0BT3::]cJ4]/=SYbUE9=<2l3f)b*)1&>RqcknS#RltR=TDU%s:m:8++N>\mWN`C$NORe3JCbfl1$V %NU6LsGL'RRR9sC+K&a!n?^phtg_G(7"#Zl_#ckB53'^UGg_F"V2>/LZmY^&<2nIFY=)&tL"-d3?aGX(9Z^d+o,B#].^AXIsQKTn< %.11(Gc%;gS+[!chatA=kVUGq-#Ft/E>:Oa!f,U*?lsQWcQSVkmbIpnY0Y2()IuA\85V@";h$*:G&;^!]%VFih#!#rj^,##H_'a"TK5<$qj$ekX!E[;71SdHc?A7=X;1/Y?!ZQA&"'&jik'ps[.1j(bJ>7>b`EIeUirg1%`l6ElKTD.%CHfOcLFoEYeP.D'7e %EHhR_gJpKd=J'ri(K5Ya9jDIpBU!uAK=)WnLYQCn!3(WV[:(8eaBBLBGGD#QH6i>DNmB]_M"%dRRjN6<%]-(JrF"sU=a@dCT>!X) %fZkhIL\ach`Qn,sVWBXdk=Sm'cnemdN7X4H'1WK&OdatrW$=1-QffW;Z\(JCeVcED5c]kmH:YARLr^2->$'E5(`_r04JXn=+;_D@"dSBd8:-W)%tj0\J6^GF(,YO%/EMI!Yoq(kjaocD_TPX4U0Nds %,!grcFK"e?BPp2WGYWSK:G,/!j1B.b"-r93^qcWi)9R5ae1M5ab, %Jdg%L#sp7Xq%":#>gOZ1KGc*:\Y)AB#kM-uE^>UccmN0lR0X=o>\YU5E/F)?'`P6gWMJnCAU%r8J>#u?fl?[eB`I>SUM0FEHiMjqWBnJg-u %nfC==4QnA(&f!<5n60:j21SNjjU!hqOQ6"(0":mJ@n*rR0_jU,gb+,=j)G3q.=b5i\_r27``'op!+F+Dd&:CBe4Fu@p'4eC##F,] %CqYDTKY[a+98?R#KY\&P`b1;G#-W59p^;^]GZ=Z!)j&ml98NK/6Z_!jgOJEPS %2'a`Q;@8S/K!;/k<[gSf#so"" %>GWHVJ;2?qs%5S!;O8`=YuM-oVLNQ*YuM,8jaFK$@PW5d(b5d3IBT`;Jg?n[hIaVs.7hn8^ci02V'&>W.-m+".KrC)6#^kL<=4n2 %Jp?EjWYGC2+Ranc.7hknE]e-6+:DK4EhsoCG`^:t<[gSf$"AXUWD\hR'BGN2"\Ca@R)[f/"oYKpBp=4FIo%rhr$Va/$1rT)\uipE %nORQO1'\6)o+I:"d)`sUN#8o2(c8$H1"Qj!7"OL[N85JYedUin+NJiY$jqj!EZ*Z68W!ob8=OfqE*n\ZGfmh[GY#['$q6ao,uT=V %S,@H19$Ma'Ht?\&%Y`f]%LMRkoSD&7h?GD2"-A48JifG1%/:N($HA?E8T8=+JHo"+sg@i9lt`O[-D(`O7H2B9VC.i1EM*C.-?kQQlm,$k/gP[S-2ooEqV%TgpDaDWfID %2Qf3ke@$EOTrp.)p2@>+-`9Qgh\d9@SO$&ffZ9q.Y6u'oS:=0eghsnkM]d_+`i%7,"V3L'OGr@1);9\SBUBhVKKjHT&4R2'6scqF %aoVfI`g'\)jRPBN@Cq'Mo>#Qu%%VDn&g^@S2q#1]B@(.RC]I)-*08$=YIl=09"d.>\O+'Xi?fIqcIu1pCN%7Zmiid7F?H(a^2QIa %hhBA=[ZDp(QSCi3&?dK>Ekf5j_,_90ce5C](u5S8G+k3$qI;TMChD!JgBIQmmsGp'gVr]3pb#aY$_/ZqI$]<,WH0fTV%1.V9,>.7 %*F$79QL."7V%:;@H/=$b[D+=$(X?h5\h62A/m>\Vi@Fl*q91+;[8*)98'ugW0U=LC\j!Hhcb:COUG?'_sWe"0) %aC;0SjGaBYg5"P+IK0aeBHOn]!rskV\8qJQ^S*D`_1q[Jq3F=$p)+n+_1hT^1VYMLJ^`mG[*NetQE/@r1gL7(\h'cb!tO_9h1@p" %#;KKBpcnh;"g5rE$S>cV)VV+Q`WH_<;r\ukIsk%EX-Gt%3.;Q';qM0fbOrc0e'FLedefnIEaKp5i0tHc %K]7qd34imI=`U.e8q+.hlFFm(4`jsL'm]5.8CHPWoP@6aGF!&I'R@96$8agRYoW,khP9JbJOCT39(\,Zppq7I;nkM %'R=NeGab,>#,,#:jj$n:2I7C_cNgE]"]cci'gR._YmONl=Hn(H`LVW>c]9gl&0IH$DlGLqG\jG)drOE5C@h?OoAl\lM`1#(SX=42 %*4O2mP5?]=.A#sfs4AMHf'XpW`UW2A1*)=Mq['sT7\g!\B.]VQ7"_1t<[BR.-:f8%^S#.6.K`VN)Ti,VQ0"7ND$9".]V"Z8KT6Y'GXWP_Y>[]U8Y"WGI$>!e!F$2 %/p1f)#,Vd#,ukWo<4QkB)Q-g\_G/?,?\8NHes<>989lk]4n;FSEFEP1b'.R1I_oHdKOC_o-BIS6[hfIj_LdT];ng6Rg;?.Gb9FCi@8RGiP`?*nF7 %Dnbd:d!T.;gR]nM/(tWqeRC#hT'rCb]?L1:7-ECoB'W@.h9NT@VsJc1i-<%r\32#rJ)^+4/G-6-Ok;YmbV!E:Z>$=ZB"Kb7)c6Ne %c?;L;&Yo71#I]P#_Wm0&ll60T3OU?'j[9pk9njl<1S-QIXZ>9'U>+1Y&(e#h0.?N\lSs-H-EZ3d!`&= %7B&7%`s0KQn9mOh*=J!p.3u)-Y?"3P^<"hF'I/)I[8^nQn>tK7)a$=@CDE/?R*$;>02uBp8MnjSGim^[@eK)eKK/ %0i5tCkI1:B>BmP4EEh%i.@U(QeP1cU^eW^K&dRd0QD9*e,@:*3gHn6Z:G)^AC-+R0>d_NA %+$KqS`DiLfqM6CfKdS0>W*cNp^70R.Yq=*,WcCH(\_4jlQRbTQn%gb73S?_K=N?esS89@6d_omAbumUD3SkLLnd)4FZWIR7ZKZ?* %EU2_$H\CTKZ4l2k3*R=9Dm*Si'F9p2cE*7_&h@R1B[u*QIH:'=#/3mKZLn5Eg %i\9r=0UP2e?NMgcOu;a>JBP#R*nOOtbH)o&X_mni.h'Ma@a%Y\A_%W+Kdu=Rq!rOoU=He.d%gWfR`m8ZDrH/m];sG^+%1I@hH^;2 %(q%%L1D_f]YL:`@B]']P,>/lNnG<7(0T9PLVih[IbqmV/1CTK4D$dmic8%b/GAdlR_+D(cT#tL#@llXeL4=;a4U2>3n2SMZ!Q-T" %_U-LK/.Al.n'2M46@5HJ_\5DbB[RpS\mkj;o6X-JmnGi`KoKP$E4S+,n(kjK"&kRadFfLQ3RZK5>KAQsupGo*?0,U%/7 %5'P@%8rZ#d@El+-LdWcX@53_dk07iJO@k%CW@"d'L:ctjCc)BaA9FSI95ck+'KmJa?DBJIaLGB(.)nQc](VUZ(`CI=&Y+(1Z>#T$/ed+4_jW3Y7*I9^N`(egdQm/8T93)W;tkm\U]AQ9+&NL8A"\e=#ZP@T84r9:`m-j15rJ20FXT)"o[& %(@"T5@Z3paCoK4<-aP;AZDGi+Dmh?de=!C5?UC@[VTtKJYAS/b[a^_M*LkauG'tG[g;7[*1M)&p\eN=,FbZJ[G.')/fONg$lG46J %^hi51)GFRQ*Fi^iZc-`?'9\V4bSIN&-WjsicO6+7e.:s %\YdY3QDI]leg,g$8>=DZKFiY_pKD>cOG`((JLXkp %eN3)6opV"u]2%a23dHX;="]Nnq+URVhTHlJd2?0%:%UOCE;@0DEq"3UTC:#omA$+lJ\JeQ7s"7o8M0TKWoI-^p/,nk%sePhL?Q84 %40@D@mKa:a`pk+0fFrabriXnS-U*\nrU8+>h\KifI'E=rl1$DGLh?a5f_n2In[o'Ekkn*?2I07Kp`'2tT8CJn*oA4OYW %[n.#bM+3sQ0JSoq'B(t.BK7U3UdEJ:E7's4N*nX"ZZL)Y3uM[1`a189qJ!q7PNUH5QUKI-iF#DmTmsHIQkkIFS.ZB@"?^jpJI;8> %1b.$KV6/Yg'k'g#\c's&f<(TL:5rPA3t"?2LLEQ"Qo=9'X,i!_kT!0db7e]/>'oV[o&o2ika1n3;dndNlm=M:4BXS1IH-2;I57#V %i:,t)(/5Umo'VOecMGRA)E+TY[+63ki`.]Wi5WIFP%sCp8.j6"Z[<3CcJh(<01OpuK9[Oe6ju-Zg?bZeS2:ciO3bUheWgs:>c)US %C?J4US"X6I!:.M\S\D`u\sL.EhTSQNa?-%:6gMu/=s0iKG_CaS]ob#+Ru6V_:%TlHli7br2/tNLnB@mB;tnJV^#IE-EYpUhT6c?3pBC5I^@^oeC)^>BRXV8c&BSZNFLb'oS@l+>pn8[AReH;K57IQR\(4dfpa#PB5pJ'G[8L$5B %h93j)8harV1mESpfAACd_"VsS'ou;W+-+>H.X!9qiFUGiPN/)Gq0L_\j&3s`@*8#tN4D+rTb:&!O!d#ga6p;>KO?Z#f^0B(\Z;JA %b?H$;8nK3S?=?Z!0+Y%rT&3Be6WTI[o"1&e$HB:_%.sHUV-pGV_:lK.)[N46ga)goL;td&?]JW^2:VR3RXb1Hg.0NdoL`U+FbIADF7Lm)q?9@I!0MYA\6H!]oCe@79Jj&3\I:1@&_JHP>KBbSKbr$ %b5O>AcK:pA@0:p`Cun.pP*/)!&H\sWNt/Df$ZD18>0#PYi]^>a)C\\>^&>Cq>6J96-l14ZG1IFA7s>[s!aQr[msH`Nq#8qZY!66n %i_19Z_i#rqb`hd$oTYm6g[?^,NX)U2h%9s?MaMSDdOh^E)BQ]k1F%"2SNM3mPUksmEZ&gWGLC]a64R6YcdOZGo$#H\W0C/^iDdaO %f3H\oe$$>7&\Xk6UfH#lc/j0sX6u,[5`36B0I_(jABoHf+O4i<3 %D[l=89YJKB]erX@b4M9t=PID@oB9,)NO?`,(U%>e=PGl(,;4:d?%g^*)0m$65\,9uFYK!!==!6`nC_$U4;J6BAY>MnGfpFWQ+,)[ %6GPH$L+IoVCHs^X>+d_qk'VX4)A%!grR??G.@L:hJB1p[!6`un'6O3)JGed;h&pJu5RA<-DkVVSi@PgEDkXnu!],<[]nOI.,^Ab_ %V&%[$+#I2>Tk:"3PFcp5_K4*?-$)dHNR!d6:j_DhpQ\]Ki#]ncetgJYq=g2D[e^RGaHp1CdFe2*TDR4$akRa %W<)lM*<^O<[m6uZ;cH;;6rH`&_8CU5Y)"gr!g/+tN(&GGnZqo:7*GE`5q4A^5O7;$:]n"6D<#kq7>:_']S4F2mQKIQc>GaJERc$A %7cb_2rH"Cig<^%1qJT^qh%bG]PWg8S_H&.X1VHOSaZ-17$G)]GuJn> %32sP,H:8WMhT"?B5fu;R[$H&=H-7XLD)eZ6P^h%:(c#!7s2>2[+Nm"=.CZ040e`RBa8u,f""jQ"*"[[eIk8_+AQ8Z6\9HoWS,8`Q %TOmuIC<<:L6]<%6eThdb.jjKADJ9*Sm.rpfn!8"aSeJPZoVo@f7u=I)@k.\1Mtq?!W/1;[ZC,73,,E[0A4HmD#5@NBJIEJe4E=(d;h?b-`qjBor\gI>o:&! %OLdX*7VR$_+/H%MNeb'(C+'[p[6ihQDF`!I8_0_D&BLHYhjoJ\0@E&^h*EG4Fq3I!rkR.QaBoRPDiEZDVP.NQE=#u-%ODXcj%s4^ %GSH%-7a]`sXYf>o=F=@(Hqtjq5k..PC1B:_1IY-1'Kf7emPfO-*R:WXA@R5*4*&:_tp %@;##)H#o30d^"MLH\)P#m,`TbLXim=AT@bIrN7pqrM%njGEUCl*jk[]aIpFXRW^fZ]*@VDcBbg#TQ>9W3QoP?rcQMnCkEtdYb!(A]p-\Gh&,e3s_CKS`f!i"n1erH-8W]3g6kKosu %PL7-LN0_e#)4Vn=Q3D9a]HVki$<;Vqftr'YgE4YVX8Lu&TIH-R'n#Q$OiD&O[8UUYoM\`#5!Ag0DpmFfODA]uS#,Q\qi17+UfIZ0 %)4F3i$TY28FB"JKU%Nt.eYt&V&m]AA[N5s,YLH&nX`aG>.9t3]pYXANoS9*jMmcQF]DW'tkZUHCmoMTfHm@.\lG9)E+W6"C4S@,H %Ubg\Ah'\?kh/#Ifj,45H(5DZI5`\i@;Ct\_'tMQurZ`p:^X1_Z4jn%&o'>S\Te:?Agd[4]Q+dKd[gBsjP+X1/*0>\p# %4ts%P(4/GN^Nj@!YtblN:\N)Y=[g;1IpP;qIiW.+EqP('Eu:t,ARggbC:DQ;/)rZ8iFCP?p=_3Dr^Fd52n4bcE+$(*RZU0sf"u\:91OJ;]dL@28_kk$KstZl>"11;B7fL#/)qL#[gZ %4Ae`%GOG2X>Wk9:7,.`:lKkA"3"Zp(+BYMdZ2o-WYV)#*SHW+cnlaTI]1ZdE#90G)GUjO-kH"t/US:^pO7kS?MEIIH!j;NdS\iV2 %J1Qm:a0S6Z,]&8(AB*hn?%8\T%kG\I7#ABQL#_dDJ7.#4'.LYr%'f,)Q8DN*(V2-D=A/;cHYM)mMeB=PHl4"lAW!>r2XO*Np<.t'MUQ=el'NCChIL.tJQIu)S4;:iP %)n0'nqVlgF9h'[Lf.5Il%TL,qetXb!U"F[^pJY<-c4oXb""UP;G[+MrE,e$[idOEO]&J$r%k\Md:BWutXHElH]1>).q[H_RjU,74 %]LR5.$=%$%h$^m$]f79VKr/j.<[q2/C*>spao,e(=0B=Ra*WJ@)S!B*)E7$!(#V\[n;?k-rZ=Z93kmp15C,-P\VF7h^m1GC&&"MLK)#j'RQia;#W+ihLsGUcG>c_uLRWBW+eVY):[@pq*8\dt7Gcb.:*%L\\u7gbpP`Cs^^]'B"c&]jNhIE]d#/PoSl %+_p]Bi;,cDZp530/1%dGgCY5.XNGIUJ6$K#+JSUA8p>ZV:Q[eITjCNpQdTX@XP#u'QbWY\_*h]86=AdHMikmI9jj)m,g`GK#>%ap %D."sNY`4d<;@iV^Of3t+BXU$oqa0LJQPeRQHZ;UhjK'gKTKtX=jS3[YjWJ(HJ0%fl:`!QDo %oG2LeBT94UoZ7ni>\d:HJ26o+d-ou3U#fUUkf'5ald%=s5r7fb+Si?O;K?kmFmh7^^+8Qt)=uh6U@i.R8>)\2:<6Qsrd$QN8PM8C %ZZ$C:diK!^57?mi[QPVu]K@aW'@Cq/Q?Y3`BJSo4+SiA)Bq/`F#AN37XiZNK3(PV@VFG8H4WJHn5>0ktp$0n5UeuenO\l.R1cP@! %0=XU[n]YIq-0c=M/;T&mnn@tfa18fen&n^Y7VgT@3K?VKMF-N%>da'(k]cQ/c>qpN8hG^"au(ImW-MDJc9gQ`9H-qHrlL2H=u[_j %Gb?4"@^L5@.m<+9$gHX("bG!7n"_#mi`.Gu(p8tq/@6aN1M=8XZf$-!ABo57B-CgEc(*mQc]\#SQduQ?jKieeK1D'^:GJ)-7DVc" %fl?/\SG2geqeZ$YX;lCk[+OkNWb981d:1"+.I3?QUW%u6!Y;IJUSW*RiH%U,MGVFu,1sM3_'*iYV#[*^L`cbb$&?^IYM1[jb6>J>^ih2c]Y_?l8nST$+FA-ldqg)K4`X1H_?g0Rj %:sU(K.nj?-K;n7MGQp=cdhKj`/m>]kJGFVnY!\7B:CJ+\?Cr@n.0TrCqp,T0QLhjhjD2HmZ%k[;=\se]_UQ%t&6ieqemdg9EG*GB %:l)9g:"Z,j,Eb(udEI)cqG@l8iK(F[5A"XnbX+(1*W>G@=`6HFhg(%/j<2;D/OLZWPT[gI/Q%/Qp$fXW&b#4P/gFPY]%&h %2FoGRXR?"2,dm,(`ZQ;X\Ts:sl#Qf)B7@Kj8qs@J43FT_lLq-Ae"q:/ce@UtMKG_`:h6.:l;B`)=2E#CK]sWcY0a"iA2_ML;N45$ %.XfU$nXZ1&S+.kD@._`\$Y?ZW/p_7=nTku,#:=Cu8/%cUpT4!(r:r,_M"\gUbO(^h-q1J(H %q1ma8g&Oj#>d\"'ign)>hcI`DPKmA"-A:5/)io^r$0-C4q`t)mFHY`0Yl++,?bF^ZO@_`04pm^TE5p$7g,ne\#?o3E[f6J7aFs#" %ZmN+/A@g!_*YZdFKSu^$f.RfWM/?u]H>cgrZmqmb<%aI*s6?Qs*om.Arg3'@X$(oO:29"LJ(0.i>,Ncm)OYXbD"*@D,EdA<&E7be %]%B@EjX/e"k'^rZ0pofcIUO^^K,=10Fcr?B7#/OFUdn/2GU.(cS6e\Y,?qI.iu-R3CrmUZ'P:rAZ6a;Ub0S4ZA4tLhC?^>QnOV4r %:9P&:`ZnW=;eP@Z)NSEg_S4FG2'0jXX)j*je3bC$IbJ\*^4g>kX(j?e?(EjE %>WA+OnQf^EurW'qH%@R@m(MB$l*4p69s'=.!0HoWo:-&$D'k%p*3f%#itY5ZQIkhO'i3a %RJk4XI,mp`BXJr8RZC-h(OkaAAcj/Y-j%F7\jJXn`1P'UoB"K8Z0&)V_S62Oq*?T%IB\B8Eit3l'4eX@0ZpV2q$2BDo%I.B/e8'QJRdQ8b?mGlO?6PD^ip^/DWj@Q^NGZhL\3TG&F+07n',\ %o]G-U`I3DOQ2njO3'5qiE1tb'`f4NS*"L,NUsiNf+.O:lBRKt]1Jn"/B6GC/+epU[93^lRi6i:9EW\S_6*[sk($oG5_*Y9[:)`jT4]JdZWt6Mo)M`tc:A-7(a*bBtu^/!V^"-*u.12\;bT %?]K>!E1u%G;061EbOLnp?`3I%lYjAbGlB7ID+:Y@Ptihn\\_qjNmE/;Nh>%Q[pi^tP-2Rm=L/g4J)<""_CK@=HQbc/")X;%`$\_P %WTJ1kBpp^c6qV?721;rg#/"(e4Tp+(:Pok40)]C*Z*7,'2!-Kr;VB?b"G\!*l(_eoKcJ()pd3.i$/sKr&4.`LsVqCo-F0 %.:=Qe(p`KF'&dP/2biLBkt?Yk$;KPRX].e?)!G3R9+Q>\bE;D[,45._MQJFg,Hg=SjlY@\LXUJ[G %[lqde:Z]nSBED?J)0@0CL(FJhZL*I"8RB3[jnPhI(LF95,S?fp040o#X<*Tqkj5ZE1N\2]o?EHJLj[_gTaNln*$:;b4SW3J*0CqA %T#q?/k>>MUnkj*%WNEWk#b"KKO2=GIisdb6`pLBaF?-.e"kC>f410#_R&BX`m@*A"jgNRuQqMJQHY4:(D@JJJF5iqrm1$CHNr(JRID7mcs(o8S;o9_cGHM)[,ihYFbC8IS$$jdT^<%.`nZ.JJ?KA(`nYUCA^5mQN4DAIL`>%" %a-]dLEOInp:!q3D`n[`3P&6/g77X:'kqS2Q\*+*+jVJ-YXCKI+[gtqDVASpC`DnpH=*X!ae.DaSEbnBVU*DKWQ)6),r16FiXug3m %/9@SH&GW>$.@gDM8\Iuo;KE5[Ui:<5EWBHZlZKJ_Nt.D?-No^-qagfqH0E!-M!`VN+j\FDHn?D%F?CH2;1L@)a_W\o8)mbj`-_U:uZT"N@Mrs"s9j^I[.:AZ&q0(WIn,;?!lQ6/ILtoh;ji&=Yt:4dflsW4/:#kZ4A2;IQ!\a\GrD7 %p9lFYO+bO7D12Gt4Dt[<`s5na42;.Uq:8iYQ`_FCKYF+,.*(ip)sV>Q9eV]GFZ0h,d9q+3JZXIVPLG<[pT2oe(>EjEMrSsnhFur( %jkEA/=tr2-2dT8%g[olZ._R9iKbh6PE.TUbLU3NdH%@YMd!]i-+1.A&0P+T\b?4<]kHlNVSpI(uEJ/5t]p3SNV-.0AX[KS6p[l:" %1CF$Wc="KXNTliO0sbHU3Qcaq`,B`XUC[,`i7'i>XcUjQj'1(basO"f-Q="XI$_QG-V0soNi/!#\ImrjOa&$g4U5_L_JfZs69co;)DA$deL@,F'R73K2+*@=es2 %o;!TG3T6&0X1/MKnr*6Dd^Rht3N3U9T.!h'j=%.nO-,N]g].tGk=J/n(g."&H(muNE7*h7I/=cU(Ct@UbC^D56Mrj5LE.#da`)If %2C9;17)We?W_Tl8S1l*mT%9Rkp+>>T;buAk>hP[`=14<=lqVok7Z1n#'h;W?5==BY:jQd;hr5FI7e^sCSO:e2a#"6(e %q]fjr1RO_t6r:[;BRudUE*Y,`@P;^h@qd!t1>iTl8S9V$7UP*k++Oe]oYVD!V@Pe%pF=ZS(`#=t0QrG#mWdVY@DX[^.m2=n/BJWgsmn-dtS*>CTSoG#h/_ %>3omEY7^?ZA`K\ZFW4)UUlQO0k$K)jqJn*5[/?F1B9Ld79kN>JK"^+h3%X1l&9KHm"VEiu"KWPd1Z.GW)6e%i1`!nd %RDJD-YmA(c%!]P>6%mBVjc^.ATqlBS^O`EL]BP<;a)U^H.[cCdX_FrZ%%=*B6tVt%D[>r@5NZQe<2GeXfW%/2l= %fJq+dm!+IQE#,-p6V(H/[rDtNf]q9O`HLKZN.)hQ/7/%f*PB-=7E25M2#UeR(`'k^LI0Y"92Cib8kKnEHL8i5L %ZQXY=&1I1N/n5q$`c`;b9For#`\LhsUt#1BlW,N8';*dog-faftR%f9crhG5D%@lE24e9dUsIQYBUq.o;`;.l93,2obf %91u"0pVtPKVqeh18VLo5G&b!OhS_uB!G&da\?q#\.&@G^\*:D2I=r30/"\f6U>UB7',HNK^KRp^,T)$jB0Yp@s'34MfR8QW](6(( %EjUj$p'a%^k&h(h:eeGdD[8NJL1Qe&DX"4MX^>&FJ6uoVfCem5YHLRo)Qh-3pq`b+?+W*kc]1A,nT8tuNGj"]M!,m8=S-On@8bZo %.;Vc(WqQEum?a$CE-\&A6U?DFiCo*0=CtUfI'+`#aV*Cr`46j[lim#T["_kaXEPa]*[^2@ndBEFGP4P^Lh`_H2Q_2nfTO*8A %5uT7/.X5,spJ[';FB-Y*\#V*ibIu]>f:+_ZaJI&)4C+[M1"cZCUDL+k>;2C&n[+i#BC0jiosi^lV=0il)):iRD^[EVHm@pg?.+dU %jRJ%\isGIB(iFoAn,5se?+n:jki!K2+X=*;`m3"ToQR51#`'J_5YtII!?(a4&j#to)6E.u-X4]VSonNS4Vcf9QoV(3WV`!1F3L.Q %b]%kdK,c]1'JmBdB#l\WK]:h6Agfk#W.pIXELRE6J6!L/3G*O-LOrEc>rInC=]PGL"YHj=D8iE,;D@;e!i-NLEf7tq:U@.CM,I/0 %5&-(=2bHAQa`L"/IOPHa(]s!L/Yu8H;1Fdq;D9E(do$NR4M6nVJ>X#5=+O6VSF[6(+%i6/4!e9!fou'L's@TD+eGK"Y':,O;dqn= %0CT>6;s@J3jGI#hRGXc[`!*?;/%]%YO'E!PE4;JVl&gbp*tQdE=1eT`msC0<\`+@NoAWJj`5H4Se+?!\4JLUS=d0u<&fs?aPpbgY %/)cVb,4H`iU(JH_b3qoJ6n(7`U`St!!pm]Mb?=Sf,?M`,?kPUoO'E!Pn@R,,oZ3Z\g/pWH\Q=KY;.^o&7S$n>sr$e_A\SN;HkYdfZ4 %Njk#19&G(^kOe^uSEB"0MmId*c:1uKqdV,%INUeG3b8B&dY9T@,*F4WThHT8Mq%?45)X=L\ObsiInseI,G2"d-ER#JUi\5r-8Ws1 %,0fD]WO&2f\Oam3i:C=Wqqui=VYOIB^ratpfdHiuT$KhtkMfV+F+M_]LrQc@ehX0(&spA3rshNN*SC&?o;h%MJGs(`R"r!en>sT; %#JPO>9FhNJ+88Ag;EbmGSP*hsfC1(djW^pY[WOG>T%$mIRss"3:_MT+M^`LNVDHqN/Tf]dl^oDH:Z_ %l]%g&7=>@.(X;X/QAu0dr2_gWXB%U%7OUlgh!ZksX$sfM?#_4Y'uBLt90HU2Co<'5m(&\`b&BJ'GC)`@M`cPu.S&56[?TkK8HOS>S/Y=FC`'Go4[sCbMTi`:1MT%=V_2P_,q4oWc %MWgjr]Us#;F]N.^]e6Zgao:Q]MAoT[_.[]IeY9S85&M5;C63C*'/s_fM_7`cn.p(R/,)Roi"R)U>PV/qqc3/D1SiBr)fQ8YP)7LMn'mV$4E?ksK21*0J9^(R':+pjaUq_[X0Ogc?)t6eDU#kL+RLbs`P)-jVUM%t5c=(6HcAW\dL9s %_TY0[n[a3OK%iA"P4(ZQ3#"hU6V@Uo:.W?Em1*;,^l&mUWCl/:>-OQ %pD@E'3QZL5Z^ZS&RS$=ko!Cf[CR\34@9UJ$jaiB'N\qG`odi:T`0N87#FFG22a)s@%GV2QTN?Ud&d,r.1i":KU= %-RI@E_PnK[)A=:F2V\r-qkYjPFp%W=S%DJ2b5%K"QTOXDdu>m,i[T(K([4oRREZm6m*G+[Rm:k;*`dmCXU?'?AIT)rN"U.>V!P'*kUX?1O\;?*pmKX@4]@2 %Iag='\Z:I#+5d#UFXKUq:;V,%5/tYJq,\XPIM.,,il+UJ=@1UcC&'emr)J3Wm^KB`[D)QF\EftDnf1G:Q<3%j;Qu@R %OMHmubs@tkCHC*gYQH?V9"8BAJ_YbrGji7p43jE7YuT$a8RP']nkd1DHa%".<(p\4@2a?E4!)4uRb6b3,4PYV1gIT_d"^#YAZR_B>+UI&mM1T$22Hn[Oa4[8[-69&`Lad](DG3?@e0p/l"?n]Tq[8#6jHk1l=s^H)p.QmM(??O..bs`_Uf0 %>8l@2#[C0Nf7_*+W[:`DJqRPCj>9e7561#?UdZO#c,Eir %UG9c5?$mWS@#VY2"M%W@ML:t)A.a_+kS_!I99E+*LH_`OPBs`s=.o]%,'9_A'k)RBki7fFM_SfL$nnbZ5i5joJ=eXpigkNtk;md+3WHp-S4?7ITnt)d6%@bsSbVQWP[40q!`)j--Oj %>&lM3`=j&+Tih3M0bjN]r.7/hUVFDLbC@!%I1\g)@2>f5q&.GYCc*kS\B*QI]?l6tB@+lpDnt*#Yq+JU`Im'K#*Pnft^ug2Z3.js5,V %UUc=1bKeCJFTYA3a2ju'G3eu %q-=SBH_W+n9t*-)b<:4[o@($.PYZ0Hs4c;MTmqJ=B`BQ'AK240a.!Vh(.Nf=IgO^Ck\`n(&q.poc`c!t4j0L:Hq)s&F`XQ.>aesYKEc!.CdFF^Oo6TKY'.]-lO#;j0!L.MQVjPY(fQ$eDnZX%eZ9EoWT0%9>\qm"G(;3H7IYT %TtCjG&5ZV+_9c=$HF)>l(V5KF*rE %DbX<:279Z?Epfkf?I1hc\?*l.`!a.a"i#u'@3LK19>-[SWp[tp=4AA5;j)beOX/f2Z@;i.WW/P1Qe-]*>:;UZJZRNE]Wl:tDcA5Y]*%[OZ[@2a %id<0#;>krd#JYlP>AgWK/7J@YG)r2g'l,44g/6dW%&1F\4jpq=L^CA,`c&gBa&A4-qQ@=2pJXn+,SJ;\duB"lccA*c.Ng[5r_mlc %E,MK5%W5m4Ii)7,HuNsKQUoo,)bKcJao.L@\<2U$*p.>ch2B2TkXO"683$.TkXL0kp"&$F3] %dI)usglt;N %'ZHf,]$Y^igSr6LIK^a8/VAT>"aW(%ct%R4EfEh>pq*F/1#c_Rp>n/tl5F.J[$,`u]"Ec24p&\D1]*<:q$=Smkj:n)g#7eK*ZO;M %,"BGc4c=7j'1S?(%8o0AAV5khbdVQ<3D&Xg\hSsPNJ(Y)T]loM7`$D`]TJb!,\l:GAC&gQ7FTDdD1=63QP:0EA\EY"ZUu4`7Q:[1 %AMm[m#pVW`_SLprA^Mf8j=:D5,f;!%cWfO3MUtaaPNs.m!q+]6n&P<[cP9*AZFt]oR+BT;unTss3"N;ZhKI`S#/D_e82aYL@ %<(=Oeh7&)kYb-U'\W_?@m.>hIK"JYK:(I_6#iP\)I$PUDWsG!_*5#/&nIQ=WI7/ZGW[D,eQJ1T8kslDsRn]j5WJYP,3/3J\GHqd0 %DRS'M3!h)>3pA_7jTP#DKNiAZ^&rd%7G*%`"6gMHG_[O[Od@BpiE3Xg#Qhh(V+l3&T9$mabp_s"7,Oq %L/ai4EWN21+I.E#(EaI5UekkFUiKEFqFl"PN12aVNS4$W#bA6=CZI*-l32ej=N>+5Q"T@cGLEO/=b0F'pu>r(7np\T/R\=(f4]jE %Q?pBcMu'T`:P8PD`dNVHCPco*K<_1X-AnZZ@-U0Z697pr0:Le>/+nLN(W[RC;_JeBe-dU0ro0I7MgBZ"^6K_:S_U,98CKU<%RAhN %af/@@5h&jT+)k?mSpL%Y-MFO!cFKT>.59>l`4lGp]',XlX>#*+QfZ?rd#b3[$&5c;I_t_3eni1psjfE>#D(QH;:fTHR_`k&C'<4%2b`C(.`.5ZNfM0.&kQBs")3kZ'?D/DRGY'k9d`C\$qO$5[1r!M@tW9(3]g9Ju^t+ %V\n;V&)V8't+T^p"/F@7G&R7;Vli\FYh05<>6\ %]`&>;k%@bpG[C5o7J#Zq-iW#Go_eL$\J^XlBtH\01kR"EMI%MB]JSTpahke,mp"k_K>1SM1#\iZ8=ld-&-'k$3[Qs%,2.(aFD %rVX\T.VFt%SZ+joB2 %Ib5Oj;du5/7q-*RVjD7l*GI4gQu#\SK5aF5;nrQ5i3Qg\B1HED$sEhW4?L][Mq:j-^S\f*G`2eC>r8BImX8/^i(V*D('Fs4(UeU4 %C@qMa]/l*NO48V5FN1bI^"R(nnXQWWlI1r+/<8"/[GtNNgEnlP)_<0_6f= %bXhh0osKYoRigff9hbg\=qgk-@%liArWn?X4H9>^q1ZPl[Aj,\#$U;-T9d+pFC!['Tu*Y6caY26k^`\%YL$uZd,J5tlq66R7c%=A %6frA..s]Y)+Y6)B,*BocC*4u4f;!ddMM/"?`P*HJ)0]U4a-jp*GW%[E1Q)>F#\kFDGj<"r(&([9p#&0GRCV!egJ8-V_XRCO@?#_0 %:-r_TWB[(YC&8rL(G6k\Tb^fnMk.cC]nKpVcO%;.L5a[8+>lt-3+4[&8.G9#SZj"OUo*B.X]XueRj#nL\2eB1RS/h.^X^7PY.jY= %,_#&,lDKKh6;-S15NW@4.99\@:3W"e,)l9peJ-]m08>W6jm)`B.>fc3.=rEAf+a&JY;J`_,t6J`AiYqOfI>7m"LBCYG)F44WL558 %m*sW-a;i5qPf`k==?6de^!u7ULT:u9Y+\EYMN#m)IjHB`(nO?T3#j"[:SkBs(fpp[;sC&66K3Rd<'![kn\O`p3_RFkF(O=0oPFXd %_Z[tXanY2)\WKkca+?i"-`/b%&[2_P`G#'TSM_P=[FRVF1C.:/F__N;?Z:tbO5 %[kLUD--5C&i7nIflXS>W.Q1&n"$6T^%p$m%&/)^R*]f^k'K!l@`7]At5i^U""l6&H8pVmjV9tW_5V?+j6X8PoK<,/3G4GeQ)bUCsf!caeJ\R:DU>^:=W25MM<3\Z&>W[jbm*s:S.o53u#qPj"J>Ks!ueEV7,ld+f'HCp`r&=OFBoJh)=2 %*o1qkY>D#Nc%I;4g^k=jG7EOPC@RbIkY@0;-sao-j\UQT5p%L>(,EnF5N2SRH?3H3F@q?nKZ>Y)JsJbQ=.cm*cpEq9_8ld31`:IW %ksX5#\Q$=kCA9E.ZC%"=h@P_!3"c"s$(mef0mI[XY]t#[4DnXt"4a%uipS3fNchlq6+XHm35+ZBab^-^B_<`%Z %&WRZLg-!p$DY@AX%_H,94];uI2q[FG)Gajfh1jt#df%@X.hCT`Y+kGC/Y!'q9co@MRDf)i:6YoKPKB6dL)UEslIh?I]moE(6tL&n %%lUq+iMeY>_)ELWc3=hfQa3T=qDa+!rsKKK+)T9:-<%;k]>XtkE)@K2#?!On2]?ZZ\q"[-<,ZB@@ofC!bUEh0j:7C4V&iJ %[9b8dIG>"5'r"DD2tc_EP<>G?j()YREYstT%5KEpHe*982GLg[a1jhlR'a5I+9/>>o!X-IdeR-Kg)oaR %9ha?&H/1kB"]L\"XGfp5Xg5D.ZZC-@\jmtqIKFRP4(feJITN5]jimr,B7:bVD"c<`^I4Z"o5L!aK7m&.DHU\?NRjhoeV:1;tY40GT %p?Q_re;h6XqoVZPrN5h';U/\%CY;*%`B\3%fg!i\cqf%hjjWKW8Q92/;6$gt,q1T5g'&#JOmN\'q/ZL6:bS2\!I&CRe-d>DE8n6o %\l)Qr]nPia/8:>'fm.rokqTL;f/C.]BtA/p=Ddi(Gn`R6tLD]Z!R/3KHbkra/-o6JAm>!f-Y)6*HEo')LmdBb77nO%]I3qi_Y:1i'Rps'lVUUDa*\8.jg2-sB[^&?3,T2LL8`#.G %>FW8GO^r80/u^\a#0Ga&ZGh`&CX]M,ee[EHdb*.)6t'meXN=eN9glXE-I7g7(XP;\CfQW-s2)8q$0)2L?UP=U?h[hpc?Oo=m%QrX %[!6#!#Moo!TZ%:`L@L3>B^l/*QJN2U/RH4Q]q,f %Y.f+u5`6H6+[.DcTZ%:h??\%eR>ArNnH+1.H_9aUnH(a]4qIfJ?@Z;bmtcN10?@9!?4d8k?3$3(J<\7J%sWk_R?T5-;GNDE![Jci %V]QT*0R>?WNWZprm,fu54dRmO/iZ"\Y3+/4"RPed\sa"oOeD>OM_5r)Re3H>1*6k(\KE&KJY(&2qcI;XBX#$(f;FO?'S1Gte(.oZ+X:n)$-6KV:KSR>JU6l4di^VJ>LmHuCo\j=k%;'S"MrL\q"tB5=friZl8d,EPgGD0goq<@Wtsa1B\40[ %B$_(j6\ekO!1gba"!B_BqL_%XTnMpu>5GDkg*'%c+Ru,:dmej7>$2D4&L#N,,Ee(Bc58_h#m.Nd9*d@sd?kFR72FjMfX_Bala390 %aNbQQWqC(rBuGQKi'>PoB,kpLWr;+'i4AlB-s/@9s1!lb%^Q$\RgrNg[pH6*B@V"$p/4!n*kl:9X(RXUmsT(:1N'j3'I%I"DoHI; %n=":Yg+0_PDgRMAMeY:s?[fa@s5JMuLY+iM2oi$`!!@S-%,Y3-ZeJe@I+pW$0ZE[?XACb^WiY]!"S0cWrU'GrVVFU:!.ZYYojmZk %^)NY^)\N\..NWKRY?mfBI"n8AFD3Ze:.M1b`/+`6-!4TnAgE_F^OK!glJJ.&C6OYRD*&V-?E&#A6I[o:E79PYa6"EtS)2;p%(5oI %CtSVSL"cH42NF\%D9#^^Tu_.fRi\opW&f`$:fV6[-aiS5Gg<1MOn^!oGtqOZfI>70q-V5,5!OhS;;8SE#-DCDh*G^2baV^:(cFSP %dcAf!0,?lIb2@[Qg0+ciq,H5b,Zfkt2iql8i=VP0b#[rJIjd-\GgJD$KFhk9'=4a\;g7HO>aS0<68SCbenuYdUOm %-"PAQZAW\YI!#Vl266ZDoB-X3kSCamQ)#J(J<'Sie*C*r*Z),.XCINF(VHD5ipB4ui]OZI?RpY=gB_CKX0AA/p7%3>)qZiKQR)+l %/3*\<9iI"a>SPSk^4Qu!pqGoZK\^,^XHahh]ntu^0oVEuS)FWd.m\!,dOjt&NI*`Hr!$hc]$RLS2rWqKBarC8Z,X+hr/MT4,mV%E %I;0(F_G,7E:q%V;n@I\r9%k7FP4Q!//?4N;df?u\7:Aoe>7RQ5eZ%Q@SP`upJQMD*D%j70o;R%ODl^/`8SDAcf(\(Fo@>%-I*gue %"2&'*DquR=>X*H6T/a37k&AUumRFJarG?q%jRAAmr:h[!$,=3ngP6s7CTENtCdEQ,Wf%`7o]RIcT@'$A.4( %5^tV(%;+L[:8obFBq[*qp?f5)f@uq?;Xh;h6u1P7q"7Y11unDVh,le3M,%k1*)0'Q&]D53E13!6/VnHOi?0A^'8ZNme!FSYAS:mn %E@dmOC`A["%in;hPb%@YIVk&_a^VM_E9!>E"36m:qn=%Bk!QDt)],CdH:)eo!_]tconJb"92=Nd!_BcKIoA]u5IKLt^#%,#CE8d0 %$-gT;MF0A*bE0\].\"0.X]6OT3"=!i:up$g6&Fs)?O)5lYEI*TqLWc&@#jghk:"+chWsbtZ@-OBQe'2cM.NQfUm7 %Qg*7s>!\%iAu11s=".LC)NhXK@*KrFkj>&#jnes?D17BP9W5)I74W2\"!(9BF,t)X4_qG`@+%b"F(aXg3/qWn3#Ft_YJ'RIm3:r& %&f+Ms[S.WsBB+6f9H/h$K:1U8RGj3@,OoSpj_)`COa&cL8P;]bI94:+4@L^#mn-^8s0;dgpkCc$[AI_?nl#iF1Ps"p.&9,1!%$&^M.q=jQRF"+3Z8m&Teh.cuH.fj4( %3m0]1dU\(r-!3c5n\,/>SS(e$iqL/[/YIG:+Bi2YCB<6AaflQ+V&%Fk&l;H]:hTn.<5PBm`O-K.I3gG6k-&>g5hAf.Vb1(\^FUsj %oj%l^Ash\VYeDVrEVG[O,J(%2KjBD/V6I[^:tW\O.654=d[K`+"rCujgp^f+C&NG`V*a(tK.;Ram=Ta6+$'n6%h%C3NZi!T6O.Q0 %3emVI*CJrsiNHbT._(K^li$B=f.g5=Zb\@NElZNA/_p0ZdkUKA%kZ!es#Po6FU\67(^d9Qkk=7amI,6-$1iVU.jQ`7"""&%L=>.H %SF9W`B=eAj=Ni1pWtpVV0[E3mTQWu^6sf^t %3<1X9"7Y!0[C(cpqC39.dQ>>$:_^Z8g2C-a/W+[;CMa:.W.k4d$&kP^Gh!9 %#UNEs5q$_tdC0RePM6rV%&(HK'Td)^X!1ua-%HO6r.5!q,1$l.r,iCmHIa5RpuD$hTR]?WFMCpc+V\'_s\4' %WK;gO!\[=LV*Ys/$,+<0%A?%r`U![#M$FkaTltG[*($?lUjtf\nBVI;Q:heAm(uO(Ktd*_)+&oE(WQb#6=EW`#V(Kon$<9TKYlr$ %$SI)6j"K6e'Mo&=^8C,m&o7i-5s<:/JQ[dVMRML'`6m&h]VZ1eV`U*^[Z>BhPM+-WFK7C/@6JWoN%CkB0.X7h@-J3OP;"`-K!SA#ONhb %mBnU.PrOJ$Sq#@T="BttfGTD&VpVesNXPRVh6L;/3NeMKm)]0SC:NjW:2^\n6#d]?I\*.&#B)>8d"S".@$V_2>`m)#+4J'ShlSQ9 %!.B'[2r?!udsP9#($I6_fR]&DXV\6P\eeFt40?cs;<-me\rM70mS7DsIt%s3fJbd"l-P/Voa9hT/4/*)TnjlCG;6g7@KFp-\!pZ`(9Aq?l+[OdHrjc>n`O.u.7oh!qt71,@W;^Mt?0$"2?7Q.gNnUkGBC450Y %^N;XRVC'djBd_3HWCAXM$K9`/gS-Z+W9BkrV^lcn4o=+"+e9TFhbA$J^UWa>H*=1T^7IrY`M5Ve#Uh_kLcP^ %b=ADo1i%n9n.U[%2GWiG7A5Uq;hmTFiZL20ITj*6L@PcsELGTOZcPcS6u>XedMiak@0_'>up)4r+;d(SYD7\b[c;d!u'j+sP> %0#&lile24841]N`Gk_c1eSS?kX:B[!A-br5h6S9Gj>,`V=f@Lt)gr4te!23XpUdCh,p(\]br`i5IbZ`dhAO"B^l*Od:?e=SlPQ@; %ce*PV)RJtbUu';]p#Gkm*5XA1PNGCZ"djdBQ8Fs()?,j^QS5=7XjA]gf$TsHM'daHRGL;;hX)!fC*5.=bmWc[PCeM,pJ=lsl*rTNRJ;SI$Kis1cK %Fm\'iiNC[*nrK'"W_tb=XLSF&%;>Z85iPpCF9P:9*5lg^YRd5j%d3*S#tZ=hul>\ %&3!pRn"j@VZA.7[n-]//hFX#+\.V8_+!`k2k2s.BDla4a]d<8Ss2iV,lXmJOolV1uWSq0DKKeqQu#o402n8s9Ro?cpup(qXL(`+V$a&&d6(ME@GQT#"ehW\&*EY`\\#LsUl"Yecsk %PpcuL\ld.&Gh"5'R'Kk^pmbhO]ZsZUrZ?L=\_a?hD4c?6E"^qH)bAa)p[3.$(T7#9''K4sV>sO'=@-JhFjAfmf!egR9G)>ZZst%/ %aSonf7nebV%-CX4L/MC:Cp=3\<,rLfM"S84@(LK$Oml>JZ,ZX;!kidCEins[/HN\?Q_(Xj6XXjKUDnUtrSU4PE6sf[=mFPg)NEA@ %`il*-cpSP0gW9k@>iRgo58O--rL;rpCq#Jj'fFf4l-0TU?+rWMUtdpn:[gq&6rVup`F#%pnn5>qGuaP\Oo^F1k.okj$=>/;3fK77K!KZ3I2pRK)^jG*XZ7Q.*(7N6G %A6X^9e@BJE:0$;Zc;Ed!mMki8S(B*fNPhV?GO9l2QC#J;\dH7]qcLq^f%TTVld=RXq/DL;Gk?hpqJd/_ZZ\ %oD=kk&W!mB).SqK&R87i,eX3K![)]OqHg;Dl)9 %RI#+VZ+P`ZN'E'9TtF^Xr(dV_<:%\eFM0IN>LX)lB/FUX4eg;KmT!.F*L(atTpDh2coW1NuR.*!QDeHOdg4h`FBX:gIdf&t. %BXX_d6/qDgS&`YUU_6'F:po5M]0Rp[aiH-[9*V?ukC6t5`2ou&DQ9ju5cV4,J,`Lk9T8#^G>)1PEVDi0+ApQBPIk2X\+E?t[[fiOh@b2`o7AEea^@dr %jT1V74&,kg_ID4YnTCPTYGsb4DN,<03@s,K%R.m]cs$](KJF^b@'XC("inj%"IBHIE'bu0p]PdJF%nKDN/5-p#_.jDI%pIE%"rX( %UZb7[h*$jfD$fFb9%8BY-tt^g"B^]]EpKl*?qrP"_C$hV1N2ZqSjYOVqmDZ#5#s/b4!*lT,<0,QlWZ!"OQG=&P=T#Za5^GcQMlrI %f2%)DlB"4jX_#o)^*BE'W>(ZQnm`QiR4Mr_+GXM!0kYO#pp]k`]+QnZ8^G+IB$cM5=I53!EE]=`%3\e(Oj?.KeoI1pa`1#]J%tA" %/#D4GKp\8iSfeXfd=IZ^lbnJ8#kQh6PbV1Y,i97MKX48P*g1r56_S=_Y@X'n7*]8T;CKm\aKtGYbmaS_i$He^i/:&n]/l4a69k6_?L(g!2&@BM=GV] %>7SX$NP>.R\C"_L3ES5O^,u2kb)QDt[a:#J./[3';%1HsDEnA(IjK:L\p9#:c@^"""brRS$E11*Fi/pWJG4Lh*d#Gm/++I#""F;" %iTNCA9hM2a'H2O=1%`ElGVCLgqUWEe4k_5!mU[A4GI %C`^;6EB:^&HG6V\Os0"GU8IMMaLU;/;sAVNiOa'0WH8RcQqM@*WMstkW>:s[2&1Ae<0AS)dFD2;^ii)75i\^/_/b,rf_qu& %^Rl$R2\PJ;157"e\DI>#157%"\_k#/$'q0C&q4.9j!tFN.$q)/^d\Jf;E:457>sj7@%a3p'GF:Y;i6+)]RZYA15(,.>'"i._obd6 %PD?X0KfbB2LC2l0F0^Vjb(?>LK&17hF'8.BA-t&X,rF>cqHe2l]8(T$m_nOBu%p[Pq@:(=Rl`'#PI:qYbdtH&o9"!*] %]mb=5fPf-E>.Zm;=oKM_B>8"[>#!,&W_k-Fs86pLe,Sh[>T9ltn(Xgn8?%"9H#(j_ %\3"W')sMJMQdMfVkO,IXk`VHq/]c(LKM4'!i8"J,F%$SS-5p0^DI;80*`LH8?:OM?gLhb=4t/M&)l$bX:B`He?L)5jiKs9_?r>UA %A>"V,$>NP4,*/Ul8b0*a($87VLQu\hJN:d3Lr)AbmdP)C[G_dYhk0EbgJY\5e"/^%gT[L/&RQLs\@V]cc'qW5W15l>"IAGq<--3$ %VEIdS),!_mWZX'[ar2BY0/t8CZ/h,UU=4DKP'M4gXrI\5U`K(lV\CMq7Q-\&SGUo4L"(jW2R\%=JftKVO4<)=,X&P8R'_'Y0KT+$d#&eu!tMg6&mC4V73-PfA5)"49PE`o"U! %T@,hHX>79fn!mrcgg0T!#X7]p@gIa"S4X1fEL]D^l7QTLSFu!rgLU[WTZ=(\aT$-.e\gpSHd8q7nK@@0nI_>_$/2)T4`&WqCc]i. %JfG;lNY/LpY:JRT[P%5nOeIO)&:SsJ6(;W?T+$`*B,U2&=jjVQ(Bq%guf4%^fh7AZVs(G3imq)p/;bQ]UG:cg1>]'IX %epC$cdEp8Aij22F!YOA,RV\,EkuV%o'_+8!cPhMaLJ+Pt#W&tC.GOl$UC\n.2pc,WPH+<#e6;!M'6`-\^B9oULM#B'L+s@j#Ip17 %99j3!,/?naD%U[8!H&k?%C-A&k%VL(:jLcGXco(I8tYL$i0iK0#N@!#N?Id$S[#6ULb)hj\,:upc(OP+I_p*rnaRu;KcI]_a&%*+ %X^'A'..gXJ))RMdB\Vo1Mi5U(7?B23K.uq'F;S&5(W?Ss(kt7(>590\'h_pkF'Q'p;N6c%j.^1BcRU\q()PeXPFD1jqKbDoe`>:a %Ua8M\:YEt0j\$WVjRhni+Pb8T)kAZDR]4,bPI/K_0-uDTM]cY-/ft3BAT5"A(EMnl;%.@tNmrt[E:dBK.hP!<'cd1@s8!8uMKYJ[ %ir;u]kf1_5<([q04*'BV2<3+8qL/l.aX`GW#B$?k+)b:*H7DMW&mbro%lPtFDBgEjX2n@4Ta`C;$L_6IY[Ip#k]ApETAM@V+Z%c5 %MEk;TIBm8c(T+rSJmcJ)/e#%&K4;_,/du5E2`>Jqbul:Ti#^q5+e!@@9>Ji!d_(7*4eG'[@(L/4CdLRm,r8r&,4*._&&g/#4@qsn %]D&.eqJPNXd?6`VaWG8)'@6-X:l!'"s*UAYNhH[f:ZJiUp#2sdI4W56__"&,"FM"7gSO'^q;]);m?0iqmBaGagP%g!"5d[dO`k$* %[YYoC]adLGn=]%u([<)Z2pd%HUR6g<46D: %RkWFHJOXU@on@^hC`="J;p`D+nQ6HXq"ck7G0_451,kY=%4)UoKh`0po6E_o(+\8*3OOS+9$#cP:J\RH79WZ=Tqj6*aj&e>09h^? %Jud5J.V;q,;d1Y4qghqi][H!<=iE_TQ.$+,%)j0$X\c[7qA+s#+-&\8lJ"Jj0KPbMkEl%9E6.rXq+@6XhbKTsFR>pZl<$VPC73F! %EA%neWKp]\)(-acU!u_XZ>cAd@Et5a5UPV+)lLm& %i-tNc,kraD:FRd+0FhslQJ#[o\!>ctJ412DXP:f)9.T55g^QaZM!PqNdBk7@6c0oIEL,'-_:>Ag/[OS*Ds><[C0S7o3mh/5kW]l0 %;Gt(F,c]8LXd#rmi$gD^k#7ZXVd%\:7&DG9:O$5M?S)2"B^#T<_:O3D^pSg6?>g-OO+0K3/JZ6tTeEl:R`>F7*RMYq3 %AO9U1.$M^bV_ %5j3fN$VYu"65M_4#mS!)MS!8i$\!l+B0TM^Jq4=+/AXXh$or9rM#gmC=+PJ!Jl9RI*nn8/bq%cAn$-uJ1l2)taXmplXNjV__asD>"M71sn^I#cR^$t'I6;F3ja(869iBe]m.+9o#V8IaA&T%\3$B#&FN,dl7hN;>QWiF5gh5(cpeL7@QToi_MRYj03$n=XrNZ1* %EnnbD9FZDjTCq3BN")l1*8EjIk4;5(hHa@ %g6>;Ng5!:VNrGuNIJC/R&_\UorU>c>IH\"VBbBnWrU;X=@nQ7pdXlJ8fo9:_Xu,"/I;3Q.UO5J$oKtu&UM]*tj]Yl@\;jCWomt_2sGShXWODW;K4CC&:?;9]bpPQ*S&*W:_,9Hb(d5g,n\.:_m?/T%MD_ebW#H:d_$o3I+=p%FXQieC[ %Z!&"7^atHY80T)lUiBZR&iY[-]VTV$CYL1hGRb0sg^N]bV!n,G`dqc5-B:_omKTB7rUBM6dDE`"qd6L[Za()%@=)\!=<+g51Me`9 %co`qUs'1A3*bP=TL(/o/krt9dJVWC38r0(6q&qd\Q1Akbl*l.Q:d*A>c*-g)cH:S0iq2B0nWmP-@kWuf(=pf-hcek#8\"S\PnNB< %(ATusX1c;!Xk\+KI!iUKMSo^'^mTYsOPJfR@bn,N7Zj[iM=7O#2&Zd!de0M9`=DZUgcIhYb[o"'Me'/J=i_$"U*rC(kfa+uOiH?L %C$-GVW@H&';3\YP&QV>+h"`LY11N&bW[R`lV(.?(N(d(`jjRFc]55QhU)$hRhDl<>_->,?&3WdiSmkj%a$Du\Hr4E/`X&OBW%+Rh>KjE18rcko)?f*Rt'_dc6dlf7oJ=rL9VWDj&tl8UCDp8U;j=q-QbB)dV'[l@Gb@-0^u"Ki@ZqE<4m*+/+068MAccB-*MBlhlq<]T22# %8["e?^G!%q:"&nt8aflT(.*l4eT!!;QT(o'oO'o:N"1I(r>!8]R(NFYoHBQ8@)Gq@<%4m_(XT=_nuoIMG(N,a.I %f/Pqc=m#%F@PbB680+Vkka-mLIQse?FFGZ\`i'nVoR85hBi!oZo'f:hXuKJ]RW:q9j7L"^;X+b)hr^j[3=C/JPhNsU4/UA=%4"\E %i't5$8b(.F@q^lHSN!h%hKO#T.5Jh']kio\JR?Ps$cbD*O,rUPd5;XS>ZEt-H;;UkW]3-c^QbTNtHo(iN:$b,M-B %8?3g)%5/1M\9d3=XV@)4^m?Ou6$8t"..F'*FF\S3T'=Vu^&C!jpTe^a]Fu=8eT*rYY>_.ts-;VRB(Y]"M;1Ff?JY?DE_W% %pB9NhBl>!*B)BMck#aL.^-S4m*g3!`VZIk"T<=qmu3#+HA/ %=(ZP;qmL2NR']i])kg!lf$U?`@+$f=0u#Uu!g=Cg/m)sor\t9hS!M$hFmE_hZEeD_Cg$s>4Lk6H2D"tZ*hJV+'dC97Rt#:Qn,h1f %aeXWf5$".R_Tg/0BYeLebVA4'aD1:&6:ubdr5eB7`@[J^IS!2E8IP6V(i`M/?FU./K`r$N9r*qCGllb84`4;DOC_=0^!J %oHV[(CB&\uG5U+4ciGT1=^C@40rgtSGYaUG`e1gOXHdEAs#>@cE[+q$'E7s$d5W!>JHkT!o8DBY*BWG,^J--(>B:eeO'Q$3[X %%'g,KKpTFJZZ)46O;5EQq[ra8rZ,1#ZoU)mhQ0DG*OOmhm'3OD?U=hq]IGA*-8ZW&<=?\]Dr5KbJlNngWADu9@-D_?&rRog5G5-i<7VpR@b0E,M4ad%R"-+*.3#ee%P %N_Y[.c0dh.ke5cs4;G\$ec:Xoi\(FSEN8nRJi3PE_H7DI]$n],?tG[GW]PNg7O(+e(ImBbCZhj% %VRt^+``Xp-K31SVLfY_Jf(qX$L#9TdPr2ApR8Bu6A)pH1T:TctKH/5B'cj$i+SjWgVV0uC: %E^:Yg'#[&rJe!Z"-D6&fl=--7f!-@YJi9!mc7n&8K!peHCLdh"SmpbdE0gsd@$V@_>gN\]"J0X"fA'j-+0C1(B&5V6@UP[R@cM#*Bs8F %45q:/JasV*"EHu6q+14]9gJ\8V1*[P*qF3,G]u1iqCVn@F:NTR4[9CbV5BH)NVIug_+"c %0Fl,W:#jfLN"DmJ@BB%9=p7P]L@ql.f*VIEr/7RMpK]/*:+Bs;#&&>bXV5m$+UPpcV'>F0l\'7;L63)[:n=hi;`MQR@2t;YmURA] %_T#ECE\``oeXo#u8gA_g_i.RDRq&FR`gke3oEqTgdA)k#i2HrUYUcR/.(DTq*b.'o\\BS2TF('3`M9h' %fK*I(Vp]ShpX]t"8E=1k>.7mR;`I5WgdhSO+QO7`*8Aa>T2W#&$dUROIALMJ[JOb'Q'II_KAasEm*5Y_m,40mkWo$0p4T##O-PKg@]1Rd_#mXG-;qKP^'NdL^smQKGOd=4"$UL-!mQH %?BbVMdljPa9V"=&]Vo/[M_4s_2^_0gN#iF]j2EC^Iku7MLn[JC'bpD@k,NFSTQqj\QSYB3N@pQ6o)gDJTU#d3Nk8c+>k.SGKscSV%n(rmtN';?4oq( %UW^4]rL$kIo&CLB/0FO!h#narH.FB.G5t&JH#GambpPLTK6=`AsJcNgfpAj[jmh %mB_q(4ur&V?ELS'@%lETo^bPS,%"$_4Q`uS&lNAL]$bb+^5BB\%3=12pgSW,7kke_f:i7/C9nN#L[l"iXhjV-_Vo,,10XR^\!BpX#("JO)aM<49VZg;Nb_l9s^HBu6] %AqJ+%BA&O?cousHfPG/7H38N?ZFA(P_oU%bbMFhoC8M>bca)E54M4EKZn0*Xk1I#AMAsO&&Tg=bZ=V+<=WX$nf,qB:q!M:n*6ba# %))pZ>_`@T'2!\<u3VR8/LQ4)FA %1WY@1dBi2aTAd6rIhO$*O,pSZfpb3)op4r-bFDMUIIUrrOrdQJ1;*NI>F%u4B1tJ37a&(]hIX-[E4_Gm:(Y.[p_1]VYXC@JPuCq^ %.Ja3BYi+#W5/\6L4B>5Pe=Xil%W_4cqU-oF#N6eB+&0Z,AMS97$l5GE5`f6aM%)T<:&U<3+^ %OM'@P%JB4C`i&G:Dn)k5oDhP!Y`'1=aT7ZU?+(3:$a*-qV-dj7IW2,jR-;t='rkK'c?eMcCO)t+0h@AZhj;;TNqHb`f,(AJ&Q<"* %G']8C?\1gAHJ(Xm8F!t^gsMe[^Jr?K&A:Xg;RGPF[8]!t+kfPjaeq4)k>#^6)f#cZd$F@aJ0WSXCO%9I=q9\O[_/lr/A&eO'o!9: %H"/G4o8sl,eQ^'o)qsl&>(FO?d+2J$%@LB31Q8dA-32*H7[:8G]A'@=HnSpj!>ks`$WO\BEURT#%&\Dh2,7uf7AU*+bd$>L! %P)@UsUq21:7ZM.TAM;o`3>Mb",/,Ap/i.t;B(cZdC.8&L=bsMd`LWteg@E6eWZ$a)D+WQ9]i&IhD73$&)1gU58^IK-pJb>!hetJ+ %-)2JWbM6a;-j4>meC,'cG6@!.Aaifem`L&8nsZoOn@\mOboq]Pb:[oa]:F0t0=?PP5E0r[k&K.g32ta)sL"l0SbWp+.2Y_:( %R#\J8;3#riG[>b>d=pHJ8dO,+6t^t;"5RR4Nd\5^%dEY@_",i%%dEY@Wq2?JEO\8P34n;jWH%OZ&P"jgNg1Lf;%_kM6eB;;BW4'l %ZI!U]K^bCWC-Y&l/;Bbp$p++Y8+WnV[bY%M6uSu3Iqd_86*"m_\'FC_3Y0P]4Ge88:;VeDhsqJPYtunjfa=SL2n&CYrpC)p5[V\k %`6=h;b8f.P5udZJ3LipjTZ8as$5D=:C_I[YjkkmLUZ]H8kL!U$a'm:IqfA,fZ\"DI]@&gCFL#ap0C^'K[dd6XZ\sH_N4O< %WE6Z-8&Jl@\I&aI#n++JQU8]^\!EVFh@V2.]4?6`PZ(qR\o"\k3dE!iZ1oirb.enAn$t\cj4f'tc;BA'k77Nprq&5W/ %i3UdO4G$5r&4@b`_j]R.LVheY"e$-d(p7/!Ej.o8M?d[7l8]o'.3@'W/O([*K'75/DCHWGqj:UfJkPXLGI!OpiKE14cSMJD@',$H %j'baRR!Ve[Vg+m!@[?$d>`&b?ms:"LrtLO(H\%T>/ERj8"%_stGtL@l_!C8O7UmCZp^'#-N5daWTI=b1??8p4d((FCn_fSiiOC+k %SkA0/@HJ77K2]BXi[hM1\2j%@J.rO#=&aC>G-6(fGefo6[nH'2Oi:>>/DCV5H;!.\?uGgO$d/^uKLPB4.@/Nc;h2mgc*o'6m"gM5 %9)(JSZ4UB8mdNMbh/tl;/suLdMK8#V=i[l`-m;<=>NYl6DlV"RLec".]@M$nFJcWE^WLS5jf>NOR9? %LI$$MHes#qFr3U`Zn`4l?,eb"oQ1D6:TB>1kX+`1L;]*I@0BX^K""`S7%7VV\!TM[8&gV;50-m?D2MC/RS2)he2%B %lhC8T&3EBgSe'7YKrZ8:![X`>Ns.c5kWNZbFK.Wua=>]7`pZ9t3UVP_6^6H1C=j&=TnE3o#g.mY`9)\Wr %O+;-=7,h2*^71TF=4dUi>K6G)JiitH:tGqXc8GE4la2n%3/k>CgXI$U<94])8#YQeDk:`j^IFS<]aUbf,uKXsJ!@0bTX>uE?mrIS %a.*h@6QV4#rGRKK"9RngJ.iCn3N](6,sqlH2>c[`a4uWcb0TVj_8!CdJc8c/^fStR`0C%MoP]*N(-COk[?RDI!b %c#dCMQn;_&K?DUrQn?S-&P/4B_/-+>rHY:^=tcgoQO#M40&37[%_a%MkrBc=P=9OBYVJ=Hb%0(*@2$a>>c7U(9 %FtREYTijD"f?RsA3.a[D0k;%:Wig!GF:NVJ+_7Q(PShgV%->TFX_\7OEUN$7M'94@&@?D-Jj'&1J4U.`lsZiJg$3jeLJDWBURg^X %`:kqE>9GY2()Tpl4pHQ]2oOl.0LXN(Z,D`,@/*MP]EAj7Aq;+;Gnrs[R0A???+EL8a=K$Pk?YSc)DVX.@96m2`/n,0Llb'00FZ98 %AmR#"(oHaL0:!G1$OkG5?S!pB()UdKZBrK@4W!Y0dX*AXYDYRJL?`Tc5[qec0[uZ1Se=D&J`2Q5pQ?@K$Oe3GA>-r'=^VLs,USB, %eReTfgM\>sLX/=+0I*tp&3^W7dLnc_&"hI&`kqdfO1Ua]SSkDAn0EojW977KlAgfg+=+XLB$2=6=VNNa("=J4[.QhP!_E. %5i@9l\^=On?I^h'f(>6so0r0kl*2Eu1B1T@2MhQrX^ISOUYC89)nrob=Vss:p*<>II&?;YM_,l]^eS-cP-1iX^%9qJ[3_q/\S&lj %IJdVhm6@bA?ET,k;Y%)Uk+GU.`?iCMB$J#a_\hT_1%k_;$f_on]oQd&cZ\;<$#;3-9^>"M9rj&:>(^,#L-"a<92Ft,UQi\;gn\_" %"L.kC9t@1UU:WH/Z5BG%B!b!8Gb %b;;sE`(J*R?=Bea;sNJgK"OGHZpHUe;!/SAV\KP&nd=X1$6cg62Qr3+X\^-p>Xi$CI9Ie=X=>?cb)i_hm5:\<8nVOIk;qT7o>0OIk<\`Z3^F6Me&Ue*\W^":Z`)$R9XEJd]7)b#AZc:@o;_A(5dX %o^nHlg:TauH>g`k1_bq&AK_Eo*Xa2$DB&02Qr3+XUomslF]I[ZpLij%FW1KLHLt#!]=t+$Q$H+C%D\r %dgBMY%b/FN`ItJElc[489;c6?(V>V%g3LErdZFlKS7#5o"I7fb1DWA2H$R-W"80c.>[8nX?O`p&JT<^BE@U"bQU^1H_'JQMn+?S_`(Db`E]QO"'gbp"PXY"VO.b)?VDjlW+%C+>+=3E@#DJp]oj]Y %qCgu_4XFH7(DY=TlZj#JQjY&FIoI4!d3[Gr_dJA4@(PhrFa\bk6KRo+0MB"]nDp"(" %O.oX2X[kCGK8t'FpmAmM4oR&Deh,cLF@'(C5^_BU0f+bp[]sr_4^Q`W-!]m"+c^_-rUc2M6:9c;!e>J6dd:24O/EkqCj:V?K!9.G %L-UrON2LgA#,j7(Y$Z6jlP@aN[f6,VP?Rcd[qs&96$,YQ08'tIX5d$V/oU=&LA0-5n]Q[-cO56gQHcq9p*4XfDCt($iaglNA]&:U %'jE^]mqd7H<6h>Xo?N'q(%cl74R[+]\V;Q:KDEfIf:BeH2\;$dG]4)9Vo'ktAA_20$<9!s;cY7e-Fma+_lgk(3]ukIGeo#O@EO

7kp7]HHcGE&tOUS9'%%B>_&dglZ6elamMTFElZqn??(/pP&HU!4Cl'><4n8Cj>XO@S_dBSIH*X(:56A %l-5"I\s+1?f+?Y<=s[9_":i)IqB;IeDu+=sqG^Y$hhRGF?HuP91RN:oL^3Smpa`DAF9iKj$Tu"^SHIkGc,FI3BZ\eiHFo_h%[u/%Wi`kRnI,;iuC:`X!`q5<5WlG\@(sM2:=3&2/jP]9&SjKn@C@$[GT7]_^LJfnJdGYZ/(ScRrb0ltZK*J"0nt+k@F'Vij[T %ZF@8=bo_"((W$pJU+M&_Jk#pK\$f,H0(/!k52&>F>o4NBpHT=Pa@MZ@@cMn6,2[+cJ$3Wp5LPP"q-i6EYKqgL&Ycbe9M)2J#]%'" %.'\dDkKX1`o%"B[U7ih@:.Ju,7NBn@qsTg$(ZpV,h/2I.K]T-&uLSs@;%IgbN"%6U>N@=O>]<*/j+2pfN[R&F@lSN5c*_>]^.IHUNqIFdRWMaan'7,,pE=V`G+Q;bcNe1V*1u)VoJ#E,&]j%# %/]-UPD9thEk4D4oXR?>/)mCSV[@\#.43`<*p*dO7__::LB=="kL-Vj0tFLVI9(5iK@o^C=6pF$[&VK!5\Hq-rtbG8 %fi]B>WQa_`ibRD+lZ1SAj@X8hKL<)IJR?X,Yg&KA4Le6aYcQ4H(X!bKpaGMkL$k8gm7t4b!5)^7\96V!1)C>@4mDI2;"B7&k(=%i*?Ct!Z7>paiP9d %OC[,YS"*`WM5oq%A9-+la]6mr9lU(K09_SM1i_(;q_:+A65)o?i+@"MKdN[FrY[[]Vq%E]aVC7H'+``*&"K="W,9)5S6V`oH7J`Y %S6VbE_edGQ[N`o_TJnmA65.8SlPl?*5SM"f6SECF!)9hRG!76#=(l&WR:.s5l-Q4E:HtJaCdJ&Cg,$EnS(K?%34T)&gT@1&q0IRt %12u*[1I@5-N^=IlV'o=T67ITp9MVbc"CX#_KJJL(2\9*dl&am2"/"cd+?"o4o8#$oA>!tHFf!qUcHdYuQ'VsUWk>r2J5EoK$"!Ef %+;AaA12AIS6n$pe`3e":KM]>O$/g4Q#fRaTkai@gTnGK4Be"'g!)<*p(aV-BR0'8"UTnHROdeiVWol3G/#R\0L36)$a%EK5D<9.@ %5;C]PYO`,B#ma)Bl?$>El)k'OK#fYjh)-<\&1JjP:Jt'ALic_2T_`!X,LS.K,E56<%7j!%bj>V/O%=I(86>U'dYRO"q-mMI\43:+Jk&A\ %,)Sq#Io<2#FOu%bfH9,hO\XGnj?"Pk4/kG']=(9:O>s_*FB9?I+EEE3G=An4/EgJh*If_P7AOM%"JfP?cRU2fckdu2B:M)R7 %c5a&?R,d(C7(QqhpKPOG$V6&;B!7#4Gl?/`,LTj"dW%#ZECBYc%:bOWp2K^'@k:N2jT?_Xnta#U;?^KH#YRc*VFe\IUig`TH'ulO %-AYatE&':s(q9jG,BUK,gtmSDm6)gMPDbVr4/13od%0NG6q8noPUuND/kE+RQ%$HXm_WH\cZ;Z7?7'tG'>2:t]hJ&n-M188H^RRZ %SC#A'M"G"#H7+o=3_SmPE[[X8pVp4kZ(aZfoXIN_JZS'TPp"L".iM[#A%OASaGM$?WMpeXaGM$?6&I!@ZD,B>^l$Pa.nX'S'8`*f %#)JD,1Tj%LF2_/KhPWeC[Mt#&]")3D\SKW?5J %.&`AMitm8h';#P3Z)5j0i@7-h7oo8l9(7D5k]%@:/sOG7*`j5:4*"l>!*>jE:po73FH99D.iM[#T71*bFs&r[0MMZi'S5,+5m6g_ %EE*VG(C_js\N-&8<7h-EN/,cD>.&nR8B2BCD5*Yr;Th0jrl@iNO:i$P6WZgTl7N9GNp$PD*ZqGETrKLN!kmFjCe?jhX3.]c6XWH] %pPK.j%q4HK!fVoM=+&$W"r.Z"+Vh(4J]:&b8>S5N)"A0*:hmbV#K!PpT6LV]%Y7oUIc;MY;;<:MLX=C`_!qtM/#D3\"^,N4&V3>>TQSHs)W<2%@]ba&Im%\EJc.^i[*6at0L8)rYW\8;lZ\^h5$2fa\#nWS9rr,@AZa`,FbW8mW1F%E`\"*"'F.*#4=.ZK\'hl/l#ei8F#eD78! %o>Uf_3(oHX>NiR>\cbSMbHT%DJ.c[OP+(,/3?C4%U[(fb7l,XjV1c$IMhL3,AO1E$(ckD&/HgF"_0iol^Zn*7ocR]A_^=_q%f`19\k%Z1.2f6e?l/5r9"F-X_5jF+]mTR67YBT2T<^e+T:Zeqj[t!d %=jZO-QY$$&O^G-_NIq/8*/mit36NBg`d*#DKpoT*Q2\?bn#gBVQ2DhGV0UNsp.ssAI[MNbG5BC)g(m):oTq*(KbG!dC$fdmdpK7S %6/Y=a\WU;-3`7u[$=SPJ7Xq[XXr(`(GR'fVrT-Y#JHju-[)J%(;CbsZ:@q%nVa@_=G:2@nLC1e=d=j.[+qIKcfS7iXcmb1e'@F=c_H:MK$d4QKC4#l %[>M\>UaofoQZ]'mK.,E6"[8obZa7orA="1i3CWd1?D%,2`r#"u:BZ$pTA*DoUjE(O,"@i8JV#Wh,%#; %lnbQ(&:MI#QhOr;S:#2f\@^+1@>84AMrUU!K`4S1 %(hPoJQ+Lft6Mh?:GF'F-Wt;sQ)#b(ua8j-ET@?knM",qU0[,2W!eauc$;J;ibe*b/X1R[>k^Gj.!($>m#BuLW"q8DN$u\rr%$)Fm %N!0U,geqh\_CuD8cu_P__j'G2g7`P2_*,dF_\0/lHtF4D?g"cMis1=D5*].cf",(bB*LH*RLP![&2mGtr[*unf'ca=DB)HYBXoT] %jK$^7)?*a86Y-a]Z.^6ML*U)Af^5Q#/FHN2YIJ95#;3$^fS@Skg,sq_i@i"DFp-t!LsD5%/Dpu)@:%:@q9Ir-4#?*_.Sc?@f*#$; %"@JWDYF8k!P$l+E9e^9Q0YZO]HFAm'@.0r;W0MX_,TDX3+K[;JuQ\:>5B3tEM)jt$+k03Jj,T,%>^1r8!8qOmon#Ie& %W[&EeI=F,jru7pUC/$B^8[-o+i7A3'=qV7H1g`,V<$fBEH1=rL9N;]VLb(_D;PFQ1#5nA68;SsH-ij"brUs"s4\]$VV+7Hsia&0Qb>0<2BD1CI]8YU^^ro,+t%?qSJ$cg"n>TSPDkGuY*]!_$NP<$\XW %G'/?B*34_J?!t0>g:%TOe-2^aY5J.386oWeZgb"*G'/AP"RFqM7f&qGl#U+0K3uVc@&>2g %+$MAV(RQ=#8')E8%IlVH>Eh7$e5-]VcW;AMfHQB>a*\]Q#noo?"jqJ@B+$i/*"!C(N)B-KN\?qnAr)TtO;_R\8b7>ON>$$/m%-l. %TbDb6+*`Tg'A0&?$)E<%$T"4'&=q>2P9"tK+f&g,7`c=Z!`dbg%"mWE?d-:FlT`lP(.dAW+>QI/]BO6-JVP3b6NhsqK#eoX:Z2#r %;p?2Sj9_W:k]rSQ%FGDUPbb*sVsrhp?!GOC`J+dsV<&&YgSRn;\Eg;5@kQ#d0,_H8-?#X\H=(l;"PQ1:6fP*u,Y?^WSGlK`?EQ"L %C[%HrAh`URjgKapgT9WNF0E+>;!C=!?mkOg/Y+.lh-Gr"k]ApL>rVkeoG[Rp>[=>?JeaeW4cPCeV/CXKdOJ$W%R/+/Y$fP?It]P>NiB$5niS^l=Qt&q.L/PqrX_-1i!IL+,Ak0lms$6Y245ahT9>V %iDt4'^r;+?#6Q4'pScS+DQ^0"??7LlY*/_U<:d9,ZZ!+h^4,RW4g/)umoiq%b6VU:mV27feZ[XiEC6a+j4hnDLe8NPX!@Q/ %_s[g@YJ&)hZ7!+ZB8MRh\L\rGFcl,LlbD':cA0P/]5:pu]_g9m4%^R=!0Cp);*?.Vr,*\8mF6?LB=P/YFG@cci9.,=Ed'UgKf-@D %HL#K.GN%+ek@C)2X=2\8P(ZE4U>D960S];D*_l(;d-eX[q*1+j %*_7H[m?@u&!HCJ6M!U69_6FR)9,JDGhEIegL9>i<>hJ(69asIS8^HOC/(I=9)/:1 %/6sp"XP.3=YQM'9$dXj$%9mT3=1n(OYsBjRXi>FtIrF\/D_[m99#GF#.XCg9l$X*>cVZX'H*? %(LDhJ=1ab@E\qUCg9o:tbg3NTC=gmW8GF%1>jY_[FMZ)'ja-e(bJVT/j_EC&oODLNQ;Tr[X4&#r>jY^@ar)#5QE+:!HP-Dh1fs'J %\0'Cb@1,i1m"kdGqur4,)S6Y]kd+WT+>;Y+lPH3ZO6afsmlCCimoL+QK=Q:I\N]j]+7Xp*-82oCr^>ml&s %IYKG?Hl*?)?.Plk7`1Om?-A(SnSQp![;/&52`JX?X'H,0Ogu@<>jY^.[H-+slt"_"'o$WCZBJQ%h.-?k>HZ/_W[=#39]?W]#'Y_g&R1skjpgj?MlkX,".,)LBnHmEL %rXd5kZoB0;PYcG[fF`uC4t1+KgZM]agQhq.nc#?JN,_-3hY9LsKM]>O$03Nq,Er\.eqiLn4Hr`QVBr]=_gU0ibt?+$l\a.e/_GP` %T<*])1_IYk/4)7.Je9(D3$Ef!NjC%@fKgOH^spC1:'dL!A>sj,PPm]Q\s3W7+?/%q![glI3pt1n]1.?7+_3$CJ$YGB)WB#Ip9^A1 %AX*&c`?#%:!?E^93)QA@2;7nMKdQ#pY_!O<$&:X>U`(`1=%aS\_BNsB>p[/ZR$//d\O,FEH;X,?KO3X*0T_&.ZPJi;Ekl1$?pg,? %3NZl?V"bPm)(:&7!q^37)Jp!j&W0KD)K2OG]*CK@UID2N_+pmR:X2:LFGkY0@A.KeiU7".!Q\\@WQ,D$Z_.76J!W0K_JhmJI.DD' %Le@WGg-]Q7BFJ736$)U,>tR`0Br-:.lQCj)(87K`QPl;5f?ge[p/KMus5WHfj-gW+'WSS.5FS/BF!$9PU:6iKo32V4]]6%hD!U.C %'MVlhL(_VOO&2pkru?oEs7qE,4i6*i_s]cVdBcrr$-nnP7)=OQ?oS78I=[,LbWNOhL/;Q?T]kcjs5P]S@i"1b9`%8a4D%IIXR"P4 %QH(Q!6gNB6=e<)NcahWLEZ#"B&Vbu]#kB94T,4PZC@6ORTYa'g`Bf:"6%udhPW!_L3pH-9:>Hak0RRoH)BSeuV/=5"6Sc1sqH5uap_d/m'NQ[7=^%c+;Y>%6N/3JM$MhS>IGT5]ssn@JFe8U[,g$H`+$T`aD$Bl_)[/LeQG[?KH9mtX$Bcar!gW&$^bC;s_Yc3098)+tmFkeem/jEt`!QK;Mu@25ZH'Di7"ZPgq8 %X?t0d,&G91\g1t/>**Ieh2GqFUf7m8pe&9F=JRJY9/@>IWH5aTJn[7.B %?\-5pakJ4V',*_&=;CVR^!tcK@I#aQ.it%CeW'%fk^#-^Qqn[tVW+*5'fEGc:F#'.),@S]jf;Kcf-eHFMlA=g5m)WoA'hO1YHqMW %Ler"RQf)O>3#STP>j6@[WTV:G2tX8;Ic&H9qcAD^!^%I)oQ<0QY;r'+O!ZQA53d%t%J.ef:qmP5-RZ5u01_A7lqpY#iY_rI6,A[E %(PZ\G<$b`cWqKe3pFfA6NON_8(EgMM/)YHc@e+3ISOu(6CSejn(Hkp*Ate>&jN^_+L2?5fS-SDh3WqOg"sts;%gVKNX.$OYWMQMd %3qg=i&)'P(m:dau\!<8!\%!K;.7OAErSDep._)E@r#l3j#Pt,0!Q*>Vea_r5a^?\?JIKnK;CV4^[@OAOd(O;i'iLhmGV`RL=.^^Z %_=%AoDFt+=oV`->3IBK:KdUuISOFW,-1k>l/XLKO#%K*Kl=:+>2phg+r5;c(H6qLdI=RYqtUS=7qW].H>S^_3QjJ3cEi/ %,,900P`/W.s!mG].IO(`6u]P0ptK<73*#@p`@X8.q>Bj8Upk>fhF%anlOF-o.]qude+Mj4/eq.l"](O_puT13LboiBYut>LTi8po %CVc4S^@A1IRQm#`^]Vl6\`1_Sqofj=iMJ_D'i1t9:C(#KUSB*,MC7S=-hKt6O^l?DCU5:[.)rCI$(f:n'i4V#&l_!((-K.hO)a4q %&:>$WNYP?mQq\\gD8[/bY*_q-%K'-V?Fbi5T_5hJkAPp1d*0A/ilP*feA!mAOPVV1V;fVip(?5X %kK6]sn\'_)k'fE(m@DD6EN48(]mbR3?bqd)>)(<,??$E]B;!`M7dE\6O*i6\Ao/8YXp%VdCq8dcGsD#pa7'iRM:-%Z;SJB%QP-Ke %3^Bj2SI^RZ*<0V6$sGTMd"j`4Lq,V;r_0bCQbZVk7m6"p""#>C7Gp>V=;Eo-mUXU7%8J*-IAb[CWF7-:bPepP/V5tpB6<`;C2el0g<@kEZj:'jC`gY]ciWfDdMldaq[Xpu,(Ngh %]3kbF">C4t$R="BJ6@+lAcl6..35OtFOfQn")-A++C@jS\<2a[BH]dJ\*=F/(+-D8"0K+(`>N:PH@?'k70'[Vdt"EK %('2Xrk]Lg/"_\JVD]\^aUd0h-&\oq_8W5omV2:HWBG&$2UMGAeBT6o.QmT2#Yl_'"k!^IA %?QC0SBcm8f5B$J_:BB0^]1RMB;QthoB30&EL"`@b7-Aad'>]E:)GB+hd$>L!HKcB/<(F='-;XK#/cmb3`OUY?V:UiI^><)P0iIB6 %hU^uIR1@gJ&Ilfm#$bf/-6-b6(H9/;@h(=KU9Ua$3N(27Nqt^MM;&bc]_-:.NU3="j.VN\ko9IY\1[@[3SsVB=i1pS_<##G-\tkJ %=&49VC:/hL8@<^t=RNSX)Ol@S@JP&dBA&KNl:DNh.=8@#4[Hqn!+es7W[G/#q^Hkq^8B?BiTDN.W'7<1_c'p=K&*oK&X\-aY^2B@ %J]XVTp0!uAk_d.n9=E3t=P=Wk,Hu#"!k:*O/^.)!-Iubr?g_td2C4$p?-o/0#@3GgkFMGS]5[ajs.j2d.7]Im%NM+EgcsOroOb^c %XUZ&"c"""$@$m00DSs[?/.BE\\t3^X(_$:3Eo781#lZ$-,$Au,J1qDX.-RY[Vj&I@r.Vha=G'g=g@u\p^iT(E8.d$U3\rZ9Zo&MF"T\mEn+Qjk_ %,Yas+$P)p&gift_;F-9C]K-C:TKhjTYmaG8:OXd\%HEQX\C'.4n:G8oP15ad9dr)*=U-(':sR)N88e)MC[tL&C4q&Gh(E4nXJ;3I %XKC!eGIP!1dK\!aO6?_k";,$D8%S)##$QTHN`8mpq;324.A;R,n'Eq7.027mmspn2c-3D[]:aafk_q)O0/5gM\AoARQ^FJ7\cY0o %QQ788*?$,p]TmOM*VM_*KrOQ&KY7b#Z9p+h+iZ2,ZGXW8g3*a1`HEYLS(dARL)F55cFIE./\_Z@/)I!fo]uh&L)F55ba/7\0H/?4 %@hU@?2U(*rd+&Yc%:dFf,]&jaKjcOpQOP/T*Pr;C0A.M6kg1W4@^59]8p#kQMdJBD\48)2FDV%\,Whe7*TGnH+CUW@MZj7$p/KE_ %BL`/Y@'u?n`"A0UTl^Kjf?a+c/UB\GI^G(krWg+9ol@):qiW`WKYe$n_sW=a\=$WC2NG-Mq>k5$,(:=m[?OA%0K# %)ohSN>1kSI9LW.s(;=Bj_e*.U+*Z>.W6Qn^r9\-"+IAi;%:[u;Fg5":Km#t*A(MkS02GF2[&>A[*=juaIZEVk'QpD)bE96_4nu9P %=TB54W/C.K'SUnjGm1Ibaq)>1`@Zo%!R*nLS_onRu#P,cI-n0Ae)jq5jo#=j8$c`9bH"3tE7Ze:"H"/GDA*&6L?41a:(,%LM %E'[^b=A*GMAk$"]=:8b.E^3jc=DJCL=96i6+,cKN(Y`Rl>L$>D^O7pl%l;r1``fV$j,UPX;LC$%]$J6R[d9%^S&Gd(p2E9$hF!Bn %#g.\+%T3Fo(VKKfTIk)`ARK%,[,jfS7ZY!jYnhZSF7'Q^_HI!g[,m:T"AWXR)f*]C0h/P3NO9lTJ-Xg!``hT4R*estMIXe_J[IU` %8CEtBM>PcqpLW?[EOC)GWhlW`Q;)IWSpc*o6RpKWqGdLK_P<^$LhQFGN+R&E(_9 %]qAaU_4]J3`q=,YUL=oA;=-Y6Zoj0+ZlJ4*R=H&!"bNK^UuU*4V67#SbEL)Vh7850.fFa8h1ekAb,6+BocRlk %bXR6Dlb]8"ZdE15S%tX%ZdE1UZhTY';Mbl`+!5\Nlp$KKGS4EmYZNS^L\U0+,Jm\RLF-&d-P9sc_;MqmLp43B+!SouK;#3kTBqY3 %FD0uh$7P5eKhLue@:s;#mh`iM_87mAg.>*p%*rdB*J"BWFXW%H_m"euM])Pr6Qm9jbdLN1^C,N8bXR4NQ3]=NB`[FDo9_OF\>4NhPA42=M>>gpNBP6RpJ,H=$Nk%]MjOlMJQU#+Y\'/+LnG<#]k+a:>1;LOrmd+dM7&hoWSOM+L-k0IQa9,UO6H!lsIs %G50C[bnH!F9kj3@Z9p+hiPOr'/m3rTfcBE^LP"_gFuUj1]ZaA\7>J4N:0Q[L#TC!"JlnALQQ@d:@>a,f:-Y.i3 %1IAm#_)`>G!]*T^L6;UuS/9-%&=A$`@#)[em#Xh]./9&J;Mbn2Rd:uEOc'_>Sa8jikTDo[UT&Z[i7.+)eb/H$?j?Vi_cIc.mlV-> %N@k)53RUh,9c_9ae9H";>=Vc+"BgMV#f*Z,3XPOLKZZnqT;W0q4qI>>C#eTp*H0eOKdXI)oC5]b\$L3;[^n60r"9oc.P7Lr4jK`) %Fa&ekjD#aqo1N!Ui3GI=hH?%Pc[ %lu1KgNRq3,?[%fCIp0PLa0Ib:8WCi?IIFL_gD\"jpUamYY_HMPXbTG#;r<'4Iu-m_b7"Rs>iV2UU(Mgp)_LO3h+-q@PPr5uMZL3a0?7PmJb]Yd:!:eZm-*:aP'^e_X'`2];Vtj\;.&6M.3I9\ %3`2HJe@tlDZ"Rs0.*s>**'Cn-.d+sGge++`1=G9iLnNEi^=01`?E9-ab"V-IR/I>TL*poa];+FalXBO#1;>ge)[Ko%[ug'%lFY:s %ptko$K1`E$)Z3hTeZG@4jh_qm#ZuSg\I5lA4"'&V@4h"$07W]HQ.g+4C;G03)stRW(!+C!F=7*Q-2]$gq_62!FL4r5#ZDfQI2`ju %N8Nrr7]KE;!^1t3Eg,(B?Z)B)I;eS@(In*Z=M+D,P"iF^rM*`m:#l'EW4\Mf!,[&=5]Zb)\Gp'o%,'aih$H46/Tf6qQPh(jNTH0Y %^\[^C6MS.($+%Z*[$Jn#:a_L_l^5s(Cb+)WT=Il/g_":Hpr9LFotg(rHp2YT7Y#],/nAht0oIkX-FO]24^\mc[)cH*/p1?SnMOWNF5P;J0C?hNWK509qRHOP.jogN2kB0B.^pVMG=6f"Co4)\.GEU=+cn]>?jgt:6:tf*pLc;U++0gQ %8R4G-rMIDN;6+:MU1Y@rK,p\qI0[HY94no91PqUEAgdMjn;#WbM[#&'%dQ0o#u,#Mp]50528p\qmUXVbN)%9i^^_8k?J5"+N8Ud- %TFjgZN"^#D8aA%,p/8#;*.::qmHkn=GH((rJ'OE(Q^"[3d+t6H?>hG+#cT,?jZ82"V3[N*`XJ+j:2jPiFXfa=&8C?]F&.\e)h %=Hucn7%l!FCbuuV(]R!I[Wn'a/`=-.\="5`?u"CXG9Y7#K>Cl$TVZ"_#(n_OSHq#D[5Aj2XY@SWIZYorZBfsukncK9KpAJh1YVE> %>)"\e%;gB#/_)GoZfT@:CT6P`SnKW;-9tel=:6tT4OBBQej<.Y(UW:`[Es'TK!r=s(-5q.BF?=[)3Qo%)%kGPd@i-FXHaj-8elNV %jc-[tI2Hn0V%B:ODlfe4B=jihqkN/2[_/j\BLmB@/ajhg-0+_EVZJ"\laYUU %;t;^jjOqJCi%k"MHZc3RnT6Q'?c+#JLpudQ(&6B4/Pu2"lk\GOrn-XA8?m./,@@eL5pn%">$Rs0cr]rI5Ycjm2fcf+iCGS=Z``d/A,3 %Spe[4SZHZ0\p_Lq6`o!9,:LsLWQmuj*rntc")WTW*!q,rDfC>S_OE8cORAZ.A@!JVQ=2<=uSW.@s'OK&n+ %\=p>94-T,90+LpRL@nBd5Ig`I8"`=/g.o4_]Mt+0@%[_4GQGj_R_2tX!X[AlT+p.I[a3)T:d[lm$91l":j8!*C:pYD'Gs/H:8!.V %Ij9DN&f:sb^k!C@4oiJ>BV5PF(o#=h=K\>@0SI.0TQ1KEO9LobE-,U6r':O%QkcXcbmUKN]b*-oN9):sG8f7WHaj5oBMYJd$LX]% %ChVD]f'RVjCU-3fFe5fAC4M/?P,QON?XU=Jb">M\-T4^th&.9(eFVAKC8Z20:3P?:n;>p#`,&ck]hmRgn`rK;c7XPb6X:LX3(62- %IQ2[(Hh-5KeW=Z$^Y7n@Xqn)^JH\>-6ec)k%6p3MHoJ>#5"g&jO6C[J:oUEa/4[>3ZEdBS(%si=_KCktcIV&WlERA=gV^m5b$oXs %S%50Z61a`G@S^.>+-/?bO3*WB`kh/UWeX`G%jNM5Firq>'a#Csk*$m`qabn.5!4soeDUmdJ^aLUmZMf3TqF^lQI]m\\6@Y*HN%^? %p++?fV/p`'7V;f]*h6P)I9Sh?>W[m4cX@@FW'5Yk?;\0W:U?,F#UT/X+N5SUS]3:SEB8a/ot:'gZR?12Fp>RUOLLqqP/69C>/'np=QjVKE8b&I_M6fhSgKp]->A@^na0&ZJ<=Y>#\93j.6=>"o[9+^>j/p]r0G1ZT9P:'?EC?fmJQHP>`:_;koY([kIfj\iT/f.LJI]kE@#\$bL1'=Y>#\ %b<:W6VkO`.(Y1![!_":!.5=<6'6%3.a;cL%TI@_bmER7!7n)BQGLWcKj/OLqpr+O;Su8:oe:[@]6JdSd*PV^rX^U(;%k_#fY:t$d %6JdSd^gd9^]grllYk$+U$@+-/d:Wd0^L^e)8=g74^L^e)5^YcB(8[a%T>lNQD])XbRO3XWD])Xbr*htf[g]>AdtL#n7AD9$AOO&% %/M;oIFm?;K$@+-/eXgu2[$@@`'KW+\HD2uUMF,t-#g0nnr#u:+hmuDtEuXPR#fsdB`[:3JDZucZ:UJIJ2g%7s.gjg+NF;ZgIT8=U %'nnH^(P%"Y^foIhAMMnJ;AADt-mdTA<"o\0d$?WAU4+S?.14IEiLhX\XXJkp"u6?)MkZ;6UZbKN#]7?JRR5kg6:#-Rb90e!!mBUg %/V@#"W4hpCG*5B1L"[#n_`tCT$DZ.\E@BDpItupTmh1LpS\0\dcYp'b9^/.c+(M)qnt[/oG_2bcOTtp2#$#0"^m$$=RN\m2/BC`M %]B=ZkHFd]+G6&g?"+LUX+ts+K_,Ep]^r5n[KG]9ZlZ*E7%!?crXsDe.FX8VOtj`G/4P2F.nHuC'V00c;ii_@O;6#isplq<+Eq(37GYr(_WHjn[A$PP2^$%R3@uO`CIKP^F]%s);U+5O@!UDgHm9>1#gY3LRNZ)_"h=TN56%^JMqN=:N=kR2l2H;Y+jP-fIf?@=?=Wsh %2"1s-ck9D&Sa3<0mX2HjD8B>r^&!3PmU`9!mlLnpU7E3kqMs<2<-Erlpf,)SaUAs(fsWIZhe%D:^6,PH\o69cI:7Mt^?F\Of?\X" %7gWu.r0c,ies]GX2cgMi$/pNDPgC85lG^:DRdND`f+/B>outG6IAR$[W11H-b[aX:9'm%)R\No-RQ+;[/%FUCdIZ^(jiQmk?0Yb1 %%p>8tHsOfhN##80=o-L:<3eAXE*WX6b]cbT@MSa3#FU@j>1P8c^4U=;[%,cnIJST!Et)+#Gm40:oc%38fZL3>>q_c3&f\==ARLGI %dJTL2i_c4nrl7*#6d@4TGc3&emc$"O4E!NeA3]Ysq'.>JoMntlDmfHbl'!kil(FUcgg%;#;`/qEd>7rmLi0\o),0L&#VR2j9)*[I %JBlftf%'hLX7ZoYV;4F.ib8FA^C\b/PmT@(>uGZMs'r#Ha%&%$L>HBtm9\#`bheEIb)7u?1PE`A^$k8`4L4SmMLGMM$E^]+l_.F+ %o)l5ND(+s4^(*U#dWb2)&YC1?h&GNVp#QP/[&sGd>$8Aic3%AqhIR/[jRp(f7`b_t0"+q[?JIbt=+EOpatT#&.c7c8=V7h/Ga^dKE=B7rOLOUVk@a %dVdYJ2Q50eenKWi'r7PLEYmS'_(0"%@+q%hWD"#q+T3F1G)0bn\)i]nF,@nlpA$sNrs8;AkcU3&]NntN-)>VADN5mMjqf)pb=W:2 %Wo^WDDG&1_9.Ok,XjE-9?Vp#XKq44TYHl.SSliG7]'&0+P]du;+7b>5"_VJVM*:)K);-?+32i`!Phe;)MajuMc#Cpo#@_rXNsBr$7Qfr%"H@@_V/Q66AOFb'Q> %\h4]>2SZmHA4,mAPk3U*-[.-PXgro1:[i0fm,_#Ih2U8'O.07CVeqFD`sF7=/)$^Y"OT>LKK&Vo/('NfYV@na\ETre^,>"Ql?sdN %hTIp2CFUm*mgYmOIcN');5A2uo3""cf_X$h&t56Bac!9C,?6.In80u9V)d#uJmS%U"SbYXihSE"2a2ioXIMD`>H-AC)-'*j07ft; %B5f4sctGi!n)cNoH'"&%cq]kE&M&I3KreZni_(_]SrK(8g]7Tt`j2mJ>ZtTKaPc?u(A](c.pg1AY$,ES("[7Z>&l0:fuORs[[ZkG %>%XjI^+KgaHum),PK`u@Yq3AaO%i=TC$?'Gm\QOo?@'E[.e_^Q2mh\+[Er[1"`8Np/_+"MNjbI_Q@?e1/R1dcjbfnS5nn5j&)#OB %1F3G+3_p$9aetM!&Ob&,%fK8Xb+N7JIl-UtDqg9E6hE,Pp6X?iO<8jU$?)Kk4`ha:nN7FSn&gQPnDX,N4AA0OiX#MR;Z'Uka@E$# %>)6CGh+B3jh9a7gZ"%H7qjMbYcNUWnhu<4)GF2Rfls+C^F8G7)mr@:Ce_`QV5ULWAIdZnKk\CQf%+b5agikDHDdF?#q;j^K7MNeXqYB@pHSH^Hb> %SK+&tD^icud9m_D@(Mgp4oP.ggcIjkT?A).#]Z`[//JP4lNHrB,TJkE$S;T./R*B-=>Zj3mb9^qf#'dO1^.B$IKn9@@rHQj.k<[` %oO"a.p$Kq\Tt1m0qpfQ]U/SN-coP2ccA:b83GlEpL,/bX.OLPA)ZWlH"CbgQ&3%r!<8Y(M+q>9J,1q[e:\(Rep"UH4C&au.P!s') %%Z1]OVLS+)Eb3.[SKs+O2ojrHlAiZG0KR+TG?Loc@:Ss*U<'FF%#>?K-;To3$AK"2mG[0LL9WVsdRt?q5"n4XQn^Z12Ck1Y,>:]n %4L#j$,P. %?6PaPRM@8sq4j&7+3kr=iC]gh3p%Ne"1Y@D#2Nm+0)n`c&(%;g)G8USPBB1`:-dm(Iu(!dNs%j7q1iq^]b1kmj<)[M\Te%H+OYH` %e)qgu@53@/AbZ,??Snb3Dg/BSST2%VMjLbS;`r03XnBM&Xn;F<9G*SN+FsH&-a&.JC1E5'2-YO9W2^0@q>?Ac#^2.0q %Zs*=/-%>**70l4(qJ'[WXcR`>plb!2@+^a-PLLqHQe(MZ^c=a.Hpjmm!O?Z)U15c07)5QpqJF[^;BZ`63c6'";b>UAOLcbp)5mi- %;`_3l0MiA6VpIRrBqR5a3O'8OM-J10MCFRo=ep<-:+oNt0nC%",]T8YM?aSh/n-r';ER6UXsGEVin7OIK>C3JHR4]Vn12IV^"&-P %4H<<%]YaH`=JShWS4)>Lp\=`FJ(<8>LJ6/"X"aa_t8>ZJp-a+WXUd^fESph?BGl(rV::MU02!-d[b6p;.-hA=0X]"aqlRXE]opBuUg" %`A=C>aC3$(XEaSa$#i9Z.j"=i4Nr$OXa&bEobBs?A]9l2L(SK0nK9d,.>S^7P!;.1O](MDI^7dYqsh)X[*o>%iSj'2 %`eWa=_V:&G_^b/@hFI<=l,.h6!,Gq_kpj1q8Xu8Xs-p.clGieBk0m&.Fd&p#lj>rR]P0rT>qrV6HClGV[5s@=kndV0*9kY0YuJm14?C6[MHA@>!\T\TZ-gB-2O=,5m>0L_sR?Tl99p$khcKldF1bBcc"D^rZ %Ql,BcQsacGZ#iEC?Y!8(A[A])F+;#o@4*6:Mr^_#fTWT.FqofM7`Wmoeps6rpTo=>a"(n:$*o>->%JCT[/*pgll3]'Vk6t(!jK=p %:"J71G32O[2Q3.F;kEq=q[lE?K:bIo+rN#\n&,Uu_9,3)&@/^-HG#;?[-2&"ljDF_rCT:n$*J`CmSiZWQf..Al!-1iE!_PRQFro< %7r8VQAQeW^cdLLT52[&c5:[>&mk&?BLZ'eI\@at],h2O2,lX@<>4!n(r?QnN6#U]#mim9>6#U]#`(pE8$$pqkP3m+IcG=9EAjZ,g %r9%KCRgC849s!b,W@i9u(s.4mb_5ilQrA2\?Afc^g;*k_2D:TX=CM?arS#ftJNI!OE5Js%ATcns^^4kWcku6S-Tl`\`kJ;84Gn:r %HDURtFVN-M0:q/2?G,.Sb9aheM2*4fk4t7[LbDht%YToT`0X,CR?TM4ieo1n>*u&rm]k^0MqN6jLA1<(.$U+*Vh6r9XZX=Mf0;LA %p""c$qJ])3b.f;'-RQBQQB2kDCOe%ZGYN4$d;*3.,@4OKqUD8).$+@/6186i(fdbs[jCYmR[PW;7JcH:mY@\s6[*Q$Z9:Stq7*;\ %:X=nNCS2GK?#$2(^4r,!m[mdRboRDo'Xf6LUtGqL$hTllHKraY%1btm7pWUSbAeKe8eKiC\hoU]1#,")1deZ^+RU=tQl-+?i(iDO %@.cP477]$@37rolj%R4o=*tihK3`0PB;DU6)=5d7MR/Oi(sN^QfVMBpZV]5*%!L#Z,CbOc@h-28"D&7q6a+j\JS\dAqH:t@(N7Vs %k%s&CKk:rV_Q;*7itHlPL@o)^=Kq@fb^LkKiN`P9a)0bn/,eakP@k.'tZ6*nGX9p]4Ok??!-Zr %>PAoec1p6Tp(Lt$-JM=ujk!tffX7lqG5kMk'=]LRV_[M,Oopo7n/J!7rM7`8j$p]D\!)AfuG#sS;cRqZX^TEQW %T)EUOH=l.a&%dLk6D&s]T^NL-s1t@K%AjL4j;d$IYYMB%ge;'JXbCNKG\)I@k0$PKf=I?!bY?MDG_VB^e/dD`?m2(ebs)K"k%sLZ %W:6mj3g,]J'MT@2NV$lGko%6CnkU?i1TX@Ee^1T-?L6J&j%qE,m-Ed4[B]M"Vfjl-]oiNN6.ApW9as#pCHk%Yrsf+;sEY"oeZ-4P#-$RB9\h@jhf>u(6.]lQ.=T>L34A:;*gX'U[W^Tr-jZ$eP\YHn %J"367lbaWgduO5@T%79:>-!Y;mHE[(/4,P7=357*O7OAYPGsJN$IB'r*A'dNal_[2^9f-9,Ee(B<"_Bhndpdh#:h9AfB"FkWROO7 %'"qWJ^9NuDGLa:X86$O/97+!.[CZ^U%GR(AGqr!cL\Z$#4'+n&@Mc$%E&:X*fNCEfj%U<&UmmZCdHTd/]EX;:MX_"X=5NR-mgM/K %^se4."l4dm&V,`j6f"$Z72ShR8h9SX]A!8=k.'***?TCa:*2R'o$)N'50(#P/^FNTBrNjD#Z2;j[FaA\GU?WpOrC"Y3GMPFYhsd,hRlUM+u>SD]CdueLAr-amQ^g %?s%7=`g]2_Ih.I<>jW[(]OVrC%3slLaZ@$0+E8KBktit=;FjU5D^oAtgI;.HqV%<1Nc(kPq`2;\IgFGA\kN2>k"&j9B-DOjY(#JH %%N7SG%L8p20:k91g3f5IIiar)&fh#p5917+JH?ZsW%59$O\J)8/3)r1kf7B8]mq!8RE:c;J;gj;[GIcB)i %IBqrH0W%l+?TT'Jc%kB&(Z)"1mHg>P5Z+mlHX7uM,:@&VD0q-k0Vp=ARdJi&'&gg_NFL1GnpD*Bc3m1I2hS08_1^+%DI75,,P\8F8CL3+GDk#d`_L?Q"M %1(AirU'PF:f`(@MmNtFhgu_.uDHp?;uYEc+[2QW0;m"?d72RLrRBm+69.2*iYgN>db3m62Nijj %i]SEm\u&%;QLh4b[UN"9O4Ai&Gi-,$0)b_!g#96pUZ-j9)%P$Vfrp:08/ila5Y9&<\8]g5^6015QuJO&beP$WA< %SgM0\V6.3tCpeH0+M"H"*.fFPX>M&N9+i\a49_).ZNqbcglqf%i1d'jE_A#\_1bg!77f+-_$/@X0Zd>',aYFe_DCYs-("5_bQohC %`],6q!F9_k$80$0b7*_+$&s_Nf:\:B2)<8%U%,>p(I3#c!,0H*99KHN/l0;@gOBMP\NC$3G,buA@O.;>b2\:N=Q\-Ed8!ET<9,.BKV]Wku2UWoNo'R=8RluC5CHGTTUh5]pR'oB"LhetCho;u;N-s_M[R$TAs6i@;=V+9CY,!XMbb%og8`_*S!@?[)72JKCB$o8d-&Oe(f9`^^!ucgM5^4#lHqk67CkXh %ghpio[&bhT;5Fbc>hA6lU*CL)*j5KI=F=LU]KnTQ_r>r=n]!Gq*/0R"!/hBS.%K^eb`Q-2*JK[33:FO;>9=Z8$VslP?q6n91Vi!e %hGGr#"eB9,:.Psb$TcVNd$=Td( %6D52*kbe\`./9TaeiJu7Atmp[X1=X'6=R&B5mi=K:Z1Mn28A7:$0aP&$;Wkm:ajV5\7Ma>n2hVR>F]VOP85;af#f+B+=2L9GmA8G %bc74E+?%eChsC`Q;!@adRV"lf-kL0j76`sGQ0X-QN.77XA2+E;fMh$BQTVIL-7;UDauHrBmVl.ZL7rplC0rX7.r#PMf(0A$?r2R: %ThceW.f#+m0si>]",AOdl0)EL]2[U*@=4X>lkloh"SEsLZQ<8J"jm`*:U484.*Z]t(6HWKkm=9^CK]dLr"oK@Zs %T#"1bU@7WYpSK3!EE\'l<+$o8QbLMdhD6S]![FOReVtjGe+`XjH]f@@Um-eNBD#Vb7S:5DHdJl)+]8Z\^/s&)HOmfP_haOti?*Si %(IFo3dsc>q81>AS!IYb.!9.KG)^J>(p!G)[k8"^[jcU-F,DVSCCWQgrP::nG4esSqj0Dnr4As\+.=R=qc5/C,$&b6Ph)!X %?hp6r7n$(ZVU\kPXI.S%FZc4dc$Vp"C[(J4;s@o[6R//Ed9=uZnZNkT^M'O7IZXUoMgQRIWJZLoNc6No:$Se*`Ns+mo%4d4VBn^4AHDm(WXb%Cj>)&!bA)LVu_!*kOb-5i2BS@T`*CSr[5ehR%mf_YB,h[@Zcu=<`$TGtF&5@73=.d9M&5@7s*8Xhq %K4pdHV8^0E-3E#!j"j]htl7M/"W8K`_$D8b7N%X/u:>r>;Bq.#!rtW$[0>&Z=dHAZhqbA4"+:A)7\pdJ804eSX[np'XcdE[UU?bM-E+tU0rRP]n\j6nupmfB*4@m@i2#4b]dQ9k$Nj854IeDsc7qf;8hc-ef %0gEtj1FTZ"n@Wj$)it\tB)j22*0G>*_aWM>,>.liC`28']1UJh,8=G%B]KdnLWFdJHq,eDFGOmY&M.sZTgRmEq>E]60m&4n %$;I27-&)nl/^Y]^E716d&ZDLUO\6*',4o/olE8V@8Tb'i<06OBFGTR70p0&*Uq3er7]>`!W@lu4Y]L[BX[.(GWKra$lRn@cK%W)f %\n`ou6\t1,F7)?'l65CRR>ZKn,J1bc(QHsBq&-#0-ImXJ(bNNEsV^YEPQM=jq'R`idfpX %bp!%spe=t%D%8;KkLb=BT$8E',?50AgCs>Kp5]@YI`K-@hf)kS!P^d;hi]N%peBq4M/#_0ik?^!]U:.JPm,9m_LUO8XXo*E(Wssc %Fe9V<;TLg\FN-Y:H*Y^$Wg).ehqaeuS0"\o6^rA,-D&#P'%Y8?NH5hFjp=d4W>pNSVm'd)XH0N.hSYb,ZAMCK(8k?KlV6kSKJi@3 %eY%5/EB#aMf#/6g?%b'+AD?^0H":@!DbjUp:,[T"&^6b7c@#07iOGJ\Z2" %gc)g.`S]QZ-Q.XF:qf?pgB.ZIUqH$RZ;Vm4#Q8=tJUU;`45n>HH\B>.sW6`o*[_]@r*CP:cUmJVR.TUr-U_c(%@>HS'oTJ93`0X,CTef.O?TWT,+4OM.d,rf$:Nor74)?G`NXo=R %6n)9nH.]aeg;"hZ9\Wkq$f92Wgs8Z'otpUV[P"QqhTmS)&%pI7GX'e_%$GUgF0!1]RcD6jk]=QT==ZHdr?l-Kq0\Ks#b^u8V4<5J %1rlW>9f3^s1roH.l5g@$J^Ia^U(iuk^MmO2,R%fE0D&5h.'UQAL/o*lUMIS2Fg7d=-79G;ILLt\Ui6,N"(G\K %T_I3S%#47o9B`V![qbPoqW.Y/WILIk=-ka2lI@&SMQ!=b5Qg(jI7BZBDkjY'I&^VE+/:[ANsAH, %mh*[i9PZN9.kTYp@a6FI8m#/4Cak3rG=?ThP9nKC;]/IKP9nJh&KrQ\l1iVH8rD'SBCo31jPG3F-iukLZW-)#VkBhL%MoW+(?WdP+LP3.G0ED4!LNP:R#/s&L5D(#87>`:e16BL!-L:A^o2BE)`lE9FEs*V5MO^=nU:,(mkEp %@=25N\;Y`!47Qn4F2Ap(q)c:(XEjs4fqMjae4N:LbQ7;e77f,Xid?I_*t$6.gumk.l>aMYEN8B<&ZNPJ;S(kW1EmQY5g%JESm(e^ %rr`3t=[D`CE=93d@fIDD79*D1Sm"a\Yb.:I+B:_J/u)4uRAAm)P@Ooj1&^-\FIl834mo&d&mTdBBc>'9H!Y0'PI %b,q&%")PYrP,H)IEZPp@.LCr./9t(S2.t!_dOWt`o_n9RJM,I,Y&b>bnt8b&7;.ZF&'A%99bX4Jj[&R&eb`3SZ[(8R4_n*X2^e:! %mD\I=Cf6b\k@Isb<8`!LQqX1V7.$E.@A%in8S/6a$60S1Q2"$-?K!6+Q)Y([)@qe^;.VYFrpT;M'[5fm$DUcHl!( %Z%WBA+$'#+nbCp%Z9k'$0?;1]k%f2*Y&f&jGnRkRHLl0J((kG2b*k %&ih\:$@QZ>+N%f;YIFsJq_X=2$r#RCF+#@;NiJ<:+D8W\9qlC1 %e`EAhFB;r/R2ja% %VcJ,n.'RpSW)Aku_e(CNg\VFM2/"TU85(fRTGtq>gpak7Q %U61G;+=:-:?2TXUE=GW6[';(ONi<^S890s[?$1Ga/o>M4g4H%?Y2Y_3Y>=i^[(:hVrS;k6U98lRFp5JRp#E4b["K_@KZm@P0Ep>[ %c(ML%V%g=9K.;`&P--<'Qf[mOtSM3DP+K?+[nSuYgG`+Qbbo]Sf%4#R-8TG$BQp]5R,%n+q %A$KkSOu)N/Sj1(6qhqE8r,N!_'^^KAYad/CZ!Wb*8bOio%,]SP&g(RfEPNMH]^+7SW6BZgPbahnLfQ90h`,9eQ]aY"pMO8\?Q#n> %p+3<\j]t!Ln$&iX?M_uq_:Fp`<7Xf[USZ^\r'RBMO7Ve1i;n6d.#ZMRX=j]69LGlZ\@mb] %7Zq/b^:&U/i*_Pf))G=PN[0n:l!9(TUhK9,52L`3IBW"h;9=-GFf!Q]CA"p079;@uI[hYM2R57E>XR=\,Fr@db0@mm'0#W)c#:#` %[9dTg1?t\(Q[^*(BbgU,&O0MZq-MUG=-I.GLVm(#+7+b,=6?U'm3/CQqT>=.$HAi)h'UNtj&Ru!%%Z-B$hQhk%%\EmcHodSa*7et %TbrXT/bC7/If;0eXD-U%\fK4=%,`-!"_?Q.0plli?6B=dN^8hV!Z;jJ$XoJ+XCF@rCo%(=:Dr<],qYEfVpuFJpqM]1(V>auo'Xo2 %g>#K,o5j@GiRpaSm[[D7>?SeU=12ojXEhTGa3VGOFj/6I@hh3"L5Z%0d\"bpYiij8=QB,H"<&`X5+-^Q%Dc0o"8%`S;]/]*%$HPV %VYn#$.K^?J!M)ZgHS?H'\DV,W_boTs`]ZJ-M=l-o-I#C(ZnoQ'^\`pM,D"ftke/'-5a(jOI#--h<*]e"eBo:Zkdq,jeBo:Zk]mIZ %+:1gc_G*tKg&Tt_!@8;0!(%DO80G%CRbpjN$cqDTH&3q %MR]d`?H%p\/m&5B>ku`9[eUII)XdalM']M5/3WY[a:@O&c)+P=36\D)e\`t!6.6XZZM"Wm,:!"3VoOqrS-Da+_NSm)+LBS:l<=b]#[K"-:92B6CG@7Lm[U %B;[Zko[uChl;ua*5s+gh'CiH[_=Jkp=QaD!do/'\N/?_IoB8gHr9q-U$>5O;?2X0+4n"Zc[Xmo,X)Z&-[Xn8Q?q^Zg[LHE\r&&B% %g,@k50P6pO)E1o<)gf=TL_">D,s[D"NS_++A;8*`>!G4(V>JX'D&`CP$Ljb:gGY3G`eR%8>*:!M)I7.C]0.=3`pLEs^cjT$gW#[! %@Vjh%0P9l;r5<,]Y6N6A7]!9tW!gq?1DH(D0GWAu7do.M%&36e$OE))4H5s#.cY9?&;kRtAu:53?1@O)oD@_YhHrC=Mq?G)S*tVB %f4pMeSm/d*@`;pOWd%_La&r^E!lZ&?JF%Q/m\u<09"IN\"M.$O5#?_$d1?2H:%uDK't'kI[V,>_Zjob:BD1*EHY)0SgMY#P7*"hV %"qG`Em#s[P-2sDd"'$raG-a(>3BLNC]2[U:H(pVtUQi]9<'`jUgLDq,l+:mjFu/Qf,!+E%H6Y4Y'j8%qKhQYGD]b20L)EA\ZARjV %2gq.4`ceD!Q^?F.U\`)UqsDGUU8M,OOp[B=;_2lZ"](GQH`YpQ(:^0W1q/oT/GsHZK`fZZ+'5bDcN_JEB=bL]]UliA=TA)Z$E/]! %M?RiGs-WB1!:cikkk>p,n..HP5a#8q!^UK$:r*JGreYo]YtTB#Jd)1uUC"HA$0$Sen>d5k>D=$nK0(0p`/oFO_[-6MXMt>Hs8;\- %4M9SoI*1EGKGsbuqYEMfrk[:gVo]Tu+,6129mj::hCLr+&A#tWf+)uI&1:#a;W<(@%mH'T9Ki[,r95P+P=2/J'kK_Q$KDL>J6/+g %.#>pQo`gSo*Q@qCRc3(jcChtKYVEk4&[/.4"YI=Y:k\A(!ge)'c]];>'1D67>!;5M#DIrA6$mdB[:iUC) %,Xr=609Qc`gq>-?[<^I.m8->(d*kHIT!%@mNihCGIA-TtlOm+?gZ?@)+1F%H3%,Y.^F'O"A %#!]h/0a([C6cMCOfa?r"dkK.MZh(!7H)h/"rVRhmX`,WsB0bt=XaIMo+DYAfGq+5bSBbO6PY^V0Z$/L*&,E6D`O$LjYKq2BETlIN %a7CL"5(qEtd-kLSUVVUX#B)D+NU1O>*4f<'J_LUk*t*5Hh/`+ZLqnB?6Hj6kco^8jQ9=[e5786 %Zu+;I9.uqo((ta@h,%VYV&g]GJBit'3i9&B4Oi<8Eu`[aq[lE?"6VB.Lh,cfPfR_7nog9`*UC/@H??H(;9,cSG*q1tM`PGZ[c?Ws %,jLaSfT%!.+]6;ZYIU@,OV1$6j%m:\"CT53+_0HA&V_/J8u:Y?9)%eD9^.KLn<_>CqnkQN.\]'CBI67<#-u[s!/+E^@Z`i/UVQZ"D;d)cg^;HEGd!qIDqcgjW@):X_ %@R-QW8b?@gPP(Qk3"XaW&:O>,LQ.(Ec\OBA`U/n2:-eS%N4EeLk"lC+8Wi'V6Rhd7@Yh!Lf-P*,c((/iB^r/Raao(Z4C`--Dee\i %^_W\>q`/Q$_S^0`eC[q'>!GNOE8fC%:M#nQOMpLtn'J+&8_0k*=C0Z1C4*%**d_j0'l$au23R4LQGK3a\,k`LRT<44*sBo8B,R&? %11,!HBh53Veh<0sG72/JSAU'o1p@,W(ea$"cY?`M9M_ipofW1jl,aIJno4d++,hO?m4`F7.t-M4\8l@IVIjDl$r46=iaeCcD/'um %>h;sDg8pG %I-4Q_2a2Z,oj9f797@OdFiok`>D+T(XSPhCKPKr*W0H3V35P(or!A6.AO`b(/D70%bLu[HkRkT^B;<^5bJ5$\2tnXHWPerBn3d;M %)TF]EJ:1Q&Pr':!()S)>a^4bH@O.@FhMrilaub15@CZ%m%j*\O*k$p7R.+^t92-/i?TJ]gnR6!F7>8U$RJE]mNb[C6+uhS %90BI>\sb3D;E5kdW]%C(?h1IGAr;;T7qEan%gA& %)F6,nk%*"^g]9S(/$5EkHK(k#X[PHTMltHVJ^?3:4ntROa':@,H)>.bLJmJc;sp=nEnI;gGed,;3$L*DoCDOeUrJ_W>Pe>dEs;kS %ER5M;Br@H,;`LMg5&o)MOd?bgfV_!TSTW1;*-XTDFm-.m?AY;edlOX7S`9Blk:tR?*^+=5I[6,U6iT:dUYdZ\'e?9P9CuTi8YNki %Qs`FU(dB)6pM#XM\fX`*G,ci-\$b%gnWlmbU"A^1COH*OKQ1eY'IUJ0lPHHda5=gMlam;mR,uZ6@('n=mIr"erOqf9ol.$Vf1JMq %f@+3]5"[*B]\J(W#Q>uH?kN0c8/"`J0o7`8h`*7I245G],;;^p]F#]g3b7T!2qmASdP3h?dj_'&(P3jA=BNq33`bI"OC#Nn0U#c] %MN?,_PGu?L-aWL,f1-*ZMukPLSOL;a/P0RAD$cqNc09)il"nlkhq.%1iOW3pV*PU3`W/-j$@(J:ks=9V9?]@(mT).:[Xs;P8Vh;+ %?MTGl9,Q5M=%Om`ls0qtSLo]/[hY^FKp2aND_"@kbBtP\m;3$kCuMi?TsrR_qsp_u8?-Gt4J;#CmEBNJN?pg$k]L*6iLdNIfcaca %1&@6,UgL".;UGEWj,SE7[+]8jL=N(54^g,[Wj06G#(>Yd<3e[er_g=mr=/NN2m6S='SGQ#A_QpSV.p56G9-YNj)=_AC_3EIGHq6X %4/G9rY*@6/D-O^%9']l?gd\ki^B\79MH3Nd%+>)LUC&Jb4ZuV2[<2H2_WIJGQ/A^oe/Y..qWMt'UOQ2F*8Bjg#YaKq(>UUnVk'qY %%-juEh.h8,e.&`J*%4#!a%J)R.-#->"*B0Sqr;\n%4.G"EQIT-P^GG#q4`!!L[.0!mUum^0WPuoh^,@AR+2Sno9$.m=?[?>Y8p)q %20DQ"PR_$?6L';.]s&q).ZA84eI+b5rQr,ajNJ=ch(YlGL6Qprh(YlG-HY4h_lR13D3@P:2pAj6OrRdebj'mREd6Col\nNh1"L5E %Z^8o*6a0k.$:;@5<\Fk.\ARTd=lg9,edLo#_+C3\lk7q[o1(h#;3j.A@P+!q62q.L;eIBijQp0/&.Ae;NbB*KI&$I:6c_@5]:8+C. %>LR>h<`W$ib]u=DcNS'?I;UOjCjejkdc$K/DM[9>>F6usHlF!gEoFFEE'k&H$DFoHnCe(AqbUL+p,%&G/[9'Uoga"n`G"83bTjif0h)8V %@>?K"-->btf8`F\E-(eVVm7T$1Fu':?Xj=:5hJ9!pWQ^#M(^[$O>?E-:#C@_kCQBT_&9#mI*G&3E@`2\56j1Mt.ekUHai5hc %FU97KZKOHZs2dJ;2DYlp3I%s-R3WG4>)T>TBn2uLG'sR1Z+Z.B;Y$dkU/?&A/Nfh3U53I>r#ChIc!";OWEs<7%S#tk'G"JNQJd./ %.>`h(AX;=!5apZ21qP^T7@Kor9IO-#(-U3##O/>Cc5'X"l%R8,@/:dFR.AQ*c\,DWTdAjHLuhEgQ"9lQ=T3tU,,9K[7P'$UX?M]h %QP%E5&.:X@hMbQc%Ylnr`!J$V65G0"O>eDM+*/jPr#)d;R)A/F#7i#L59Ue@BK.eWq%I58*@m_?=T7G"m(d\'MD]a]HjR'&+,2Qr %Q9QPD?pP1]Um#O?M.TEP`CW!:l!GO@KNQmm'?`rp3U4se&^3fo_$#`\=Flua;NJV^8JJ?T/`!,l@75.a8X+M2eY,";^Mh<=FV %WTJcpY.tG.,:N9I`WcI45BfOC[nu7jI.5n,7Go[E %+:UF;IQP.;rdnUiq!I;D_Y>Sk_J_AsN'%C6@ef?[ln\jb#2lufeM$,uIGV0,c0kK/D;Ku;hnJW]NU$(m$:V^OmW7k5;i=MT(;=PI:*2TU5:Nl!%si8LDdf5n4=h9'9Z#h'E9T=SKM&N-j8daNYSc %`C:Z>ZN]=QMkCI+fn-0f'1*LW?ZYBePsh1@10WC6W=e$aK;&UhM<,*>:G/7@L(TZE`&- %.ag/=VrI;2:IU_L_VOK2/Uc9u-cr+GWCYK;1F0ZLo2I!iS_cpP3DW)TI>k1%i&haR@0E`.c^%EcU@QW/OW$^9I1n\<7@L(\ROlQ] %:[?hOs)(#B;X)=8HhlU5+-rDbs&B#PW>Z"]"b!Y[gjE@LZ>V[ojlM\ZcVorQ%^8<#kWBSoRL0b$fQesp1mPng&NEQTR\lej6%.$W %"\b0CVHh>l.YGrDOf#*cjVL!S'l<`'Fe4J44J\,CcVot'WPG,WG+OS%foosoo2I!Y*mDBTSYlfM/':%O7@L)?eO>"6WlBH[W[`j#SV#P(g"\%6WDds]T1trf(jE\/$=08pZ5A9^f-fMC&tr,MqP<\] %9SoE.'ae6=Qs)&664)qaB/Eagonas?;^gk:1+3jJ5!eL:M!^)!5/E7s!=FO`:F&45Ks"4UMa17ZOIjB?5bZQtM6RF)=J=+7M'&TX %5OW%WXph=,kk[^)<=#a(./N!Y>JbZhg*!UdU$EBE*>P8Ekgp>nQh/PD*%KHn%CK46rF8m4*4b<]@bs;Ls/CM7UXFrW^TV!?C>Fl9 %rP-67`ZZ)rB)`\j,Fn`f\l:@1KmcG?.acS`Relu1Im]P0E*[9hiQ$_)n#em_Gp@(SO_6p2ggb`MD9'I0B4'3ASe^BB@kFl2o!(iRJi&/J./q[=:P$/h3T=%Qds`"3tE;#dfu'Lg!T5\&fh5 %\1Q/'L%gVZS,Eaq8rXU20t)ZpmU.$snSPsj6u!3<*lWdN6a`+R,hc4So;0obQ%-EoC#d]Z>"E-3Qqj^%.Sj'P<>l8KXY;;hfi[:$ %(LE(_T&+s*@^$@rb%g9EA]+4q.P#FpP*D.Jb9(>lAZha\po$!%T6ks=:%%1s!e6nfb&VqbN>1j/2)fmRP5=%=oDcjmb=jCHa@AG7g2G+^>jW0DmKL\b`!:KJ%T'EH2?M143( %%,;:W2sdt(GBWU2G"A^dH2&NqJ8J@ftbsCJG2]%ft\^KYd5jICg[e`OrRR^0Sfq'B#5Z0;MUjLJO)-VI:Vob!fYR> %D?f=<3ZCio($2NkeNP2%0I^WjXgS0^dXOG)R/RpX"?[Y8BMX %P]5P1!(ufSVm2:('kP,i+[0%E&.kb^`\b)kr+p)p+,Rnd)$qd4"Ed26l%'I#L"[E406.!c3[9&4XiZ'`Oaipa5LgY1an6$?eM*OPc8O5*=_g[4+28S]J.bSe)33EAY!&RDa6W9>]AFira6WVnG[VM0)H5##"e7(p>3b7c0tWWq %]T6-EG$S-0UYE(05-+Es2%t5I*k^(iQ`hQnf4.9oU*OinIX98@nTn.^LCmVQ)QtO\?c8#WVh!3#ING4jSdOG9f>DD^>?iVUd^%3h %H@ooRnp!=#/]Gbq]#O%jlUG8el.&4;dco<0^WisT\)sIh:Yde;PP$3[U[p;)_e4l1`j3)Dpt\$;FHD]cnt,[2?+T?lTAD]\?ZM&b %4E@(?r&fBnDlJpK4Sp'i>XsE"^Q5+O`8fu!qLdX1GZB=6NIiG!*2\V8G_k^j[Tf[Pq9.qWC!arBt!+;Zg'`,pQ^Yu)oBQi>1V@5jK'$gubk$j0ZUr"5P'G3_h32rHccZ0WL6.[4U9igI?(8\p6q,T`8FpB;2S83A]dp(3$lbF?+dT0tIJcV0s\R6rf` %Y?OWV4Z?Di/i,-RTE(](pJ^<%Rb_68'U5*]LT3;\X:eb4K#F0Rp&&U!'JH((4'2K7LLe/J=j(Ymf@nK5_aM,%gUhM?KW.BVr%o)e %Cbn_1@02^=n`>p?i.qY)I(?$hdedI/0:2=Zh-N'kk$#X+cJ=[^m*( %qS%a:-hO_0Cr+<`)fHe),DlB-/Lh$2e[<<(lm^5i`@A]CFR,R-p\B!i^)B=#m+5I]=tRun_P-@OS\$he%CaguDa%[FAL'moq":W% %/H$=)"4&B)IZ3p!cS&38'%6Jf[@Er*,WRsjAps;##s8V"AlX.r`kkV]QN"1fb_T;-eh9pW$I$q*\AK8K!jcVUIGZe""_R!Pa@ln5 %JQ_gW*"c*Q"u#!Od?ZtDDU<._g$0KJV>FFQZEY-(W`QBf6aZJg;`7$:T5hnNMOghpfA3D?_7mfZ[qQC %h)s!!_5(TeB>-:.(G;uNEr5\(qW[f(,\]/Z6$jo0i]L&!73s6WfM=1o1[":9=+U1',\]^Y<5%0U^[13ajg1)LJu+k\]>Ri#dS.G] %&j4B&8=XCp%7Zq:'Z6?1RpI#;&QXi9;p3pXj?\%r\&!09E]BS'Wso85?W`h496Hr/*u\eGC4f)$Ei'"T0a_RIU.g1M2D!.\7@=?3 %()CQ:,*j)r.2:(7FXYFU,G$].;;?",hC"KMQ?Q5*mN70s+eI]^8Zk2K$odfj,M7g%5u)[4\l,f.Tq-m.lJeZdEnu^Gm5prZ5*=h^,52XEC661MG8Th*9mFeiEGWOQ&HulVZh"u%@t:imrn*qlr\IJFV!#he7A.t#:KH]/][=PGj1bX2Y?Q?C-6ABn#Y\`rXb%fDg"mW %hF9fQ7CI3ZB^,j\I_4f?SZEh5Ga/l[cj_!SAXMQP>\LRSE8lPc@,993LrIm5[cG9%@'' %/+0([l\/p`$S6G"+"]Z,F`CTh%C&d'N_r2gc[:X,pHFnL'2X(^iA48Oq4[=2!hgs4,BKa=GK<+`KkR#bX6uCiQs'lri`_bC;YoK&SF'eb0fM\Y %,aFOne?-G$?7g#BXMZK#C2IFFboSF9p8am>U5;04g:Y,o;;l4nF]@Qu=;#*32-rAc4?_a!9E+0#Ee]A*o_$SbBt;m,\]8+7W>K;U %)bU]fAiHL>.nQ[qUUW@:V\89iWP`=WBf01`T>YVkbTD-jn!RI_YFoePhfR[Ad'3p._TM.`8MYd^Mqm?u`plg,@TYBhK/%[b`!3Ap %"fVK"+qq/Y[1sjeXH$h^4VG8V3&,!i90!Uh>k:kU:pTek*Eao-s!'!(d29#i@TKBA@ %l'*Qj'RGd8a(Aml2ePJWbZoa.2#d]\A%7r%=*)h_.6NfR?PN__ofD!g8f)a^L:pS,78pp`o$iP=Ld!c`ndl#=VAt/$7eIE5Bf>_?AFAk?Xcfnm3^_tP3s.JRFqT>_.0m`1LJ/]gT(.nI3 %4Ls70\5G*[OgYcSWuSbH`eW<_!rqp4Bps'38ZZ`G_QH^uhA:e"*o>2(fb[hM6pEmp)>Z[Ek=Y1OTi*_pHi^;)Tq+&,:achKZ`[-g %-P^e>R$cQJ'FGY[ccHS3B#V+QQ)k>SD2mG1#E"RFTt%k:9qfr,#uEKI-ks6Vn_1D5<@A?*o!T=+S!i8/U!WH=3/BsN'Y6IoQ'1@& %)aU+[eTco?W.A\V(9!"b:F')%6LfGc@r!&Z1YL'"]ZPS>@'\L;iU+=Oo3su>RWL0jPjqWe_\_=p0Z$UdKgOB=P!!*FS2)K,\iu6e %?A29C>3p^Ol:INh4fOT`l9s!sdXM-o9ch($[HQ1/_/U'(NM)#PFVLg*!Dg[p48Csd5C,p0d4/Fb;K4+CJMO7)Z!3T\5fs.5EDPP!Lgkb1u\&;AUlJYTL8TW*e"RKAi7+2 %7&uE6MBn,2.O:jBY)U&,a5><>\50(#Em;lkr`T*?X,iC2 %TkEQF'C$sVQHP?<>6#'>\-]k^S"M:f3-'+i:34r`Z?u!ZG:GLtj38[k^UF^F\aAQ"dQGiKVOQB!r[jYADaF-b!ET`\67[3.]W^3l %bcU[nX&NPIFpX7&E*XHYA3m#SVsOu?-BLX %&[jc:ih3`3*gKtMf/cImkqb,hg?p6>1Hng3m1/P=;LId*_E'1"0d\4g.QJ&Q@!Hn %?;ZVXJ5G;thE1(&ieg!i(S46.4+Q?dV`U..lK)0Em@l\h_c(9V#lF/=Rd<-\fm?5A=_P4ndPb:Y02f.J;MOoU:N<[0+Sk`fi<4>A %I2ALL%dl%V9O/o9h-A]bV+*3TS(&,qhE.*SnJ/df3:FO;>9=Z8$O6'j,RY#fo(:e4eM8tI\Q/7TCJ3&+F,OQ==5V:Y%hub=aX'Gm %1*`37*g_9.%AM2>#T+!@e0hi.;p\p6V`o[s6J,\mN'=5RVl)U%iWb%6>"mRVOJb:)6k0EH((R#34V\;bX^$KET)&T'pVdRGH0Q'u %7i!s!jJbp#Ob5rkqW(GV4+85*YWLJBK08f5HG>7T%.YAGiq2ok#D5/3$2Q:6#(o&2$!LcU%0k)BPI6nrrV/??($tT[58HjEe9Y#j %fsO*\$LR[QY9P>W3I0=Z`lZJJYN_^O\B6Asj/`];6&3??%f7$9a%1*S>:S07V^`0^_[F:cY, %eC@TqRqJ)u,3]bC@6?k[K1E;;PWDBJjj_tsNatc&tMpUVZhWM=2')5PnH<2j]e.Tm5T=X&fjV(dnT>"]0s]f %l.75+mLgO5L\^j7[0io02.mSUBb`-F5g'RW`4@8$p;U25HC>'4apKf#_A-]R@u+rrLPVF6uJK/t"J@K?[U(rg[ec;h)7 %*JQ9h,O(]B#5=\^8YcGXGJHKbL+s]?%bV&!c6J7S_4d&R\$c^]#)>E(>l@K9E#-td9H.77YGO8Jg#2Aa"bpcj2Rk324'W^EhC""< %3E-q;2SfFE4Q)kB_jCq8ailZQmV6KWo?^Ds(McScDHgO-31d%r^=03X7Au!%>[:6u@!CA,N\Wd]bH(?^G=2PtHqc0Isfk5HC?'('OhU2-h,Waj-K*1a!7\+Z$pa5BK^a\+)E^/C;Xk'cW%=OSi*,q5D%48X&EkkiW2k?H\Hs2:h %WrnCMYT.W5+1S_G8-bYrA:kT&YT.VJ/,[BgYp:j1>GRc^6Qf=Ut&e:M>(oh"r %kAYnW.%6i]kDY6@H\\TtCJ?X1%Y%DRih:tebh\je_/m-_[uuXe*H:5_:Ltpa38sM?3IWhZRh*UA2j9RBM?E8gI?)n[k=)!Vl[\S$ %T;s9pQV-ZCioT[uT[3!pJ,Q.gKgD=m5URnj$2K&[Zj?-:7`ah/j*pT>(G_qYqO?4a9\Smge'ieu4800@Sf3#"q=`aY&=n0Zd#s[E %qGZ-2rI+I"LQ.(Ec\T:I@\Z&1?6#N8i]D#!ENo(Jo)m]W89!C6T"nCe];;\cn\?g2m\nrh;;7*hk9=(bf9_N_:G9nlOINi1?KjVC %_h?i@itYkRaFZ])lG&qKFj,,++JL(M3$lFo,1n!,0Ckm'G&0sV'1U1S`+elAVZuUf5m3"8nZ;$dSKP]@inH]K%bhB]'L[+qhqA@<_n,cGS[hGqB\\a`R>_QaWX:n %T8B1hP+hA[.A6-$-iDZ1ekYU_2^,=GVC1$O8q-Wmdd*?-q7)!&2b"UaFr5Gc.MXN!V,'<-fqfC4ilJ=O*;I/lcbHLRQlc3gF(D(% %F=o`M/l8hGDIaf^R]2Q3hbM^cq,.@Q2Ps)-1V-]7\T`AD&lO,VJsO&ZQ4b^;=fAT@ehX"AH[LDRR1XOSL%,td2"1:sN+;+!jVYpG %/HO]L@aNQP.2!1A2Y*-?V8C*$ebRp$BOC28=(=7e3>h[scc-#L(]juVB=IDh'n$mgTNcljpSM/IGAHT(o@TXW(=guN"e4oK.r*m7 %:5C2LlKS;i:1KTZ@/)Ns:OLq6El==,i4L#05:acmpib4S&U2QT&kkMi*Z>/X`'0>c:L13nBetaXQ^qKkh"^LJDc=-?^#V,g"Bi1a %@I+r*k.7KEeOM%P?B&t3IXr.@0>a>hkt@H!KfO4$B<2#P2L`-4:e6kEhQa(HNH9#m@@!?tg#Y<.-%nZbrM4H+gcU,JbkG-^^T+?H %enlT#$PfDlqe7-I&"0h2F6e^Q4sc7P,r'++G/_KQ\[^+QoURKg:[.I.ZF[^<.hZ'gaT<&rfV;!Z;\G:k1gTpjns%(g.7'dub>T%; %VW?Y_'CqC+,hq=Z:W^$[PAG#roK9Hs`?a3,*F=eC>B7$Oj5T!&)Z"mMikeRh:E,4Gj+GoB;+fD_*qh4r)T248gM*g95>'#*7VDS( %s&FR4mL?3CD7>T*b#Q0aF)aCj=/'$)Z@cM+qDJ@Xa%FXa?gqVh(C-sK3X&6.`N8UOC/H6c@LD2"hP*qsdrK@3g4U0X4q)n'Vu+_m %TCd'E)JY25Mc["IT1I0,#DV\D><&UM+[,_ELp[s7C5^@S8(Y^uW%G*:U8?%Ldt>Si&*A0`FZh$2Ph)NYeCIUYZa$q?6Z".&1Y,T7 %W%HM/*jN-T6Z$88cQh#l$FPS)`O]CD)bX!#/?KZK?0q9*3.G>2%TOLW(AXf4L?c%tB^,6EQDH\3"r\OdN]StK&;Em`VFW#)Vp]S` %5[uY$k-'0a-(/lrX-^offTI.7h;:K?ir&Cl5$gEEG"cu;AM(BR?#)Ap%MS51DXYmj-FMm:K`0N1FT:Ji %A'_<#*7(0]90FIR]=*5jCorc*f!!RsRk3"TC:-sN$"rTtcMbqhF^K49E@iE[KJg'i>2,\l]B1$a@Wi7d)VEKY[D#M7;B,(1%GQZ' %:2I>FZ2KBW$_^L'UmWg5?n##YHN@>DR3-VGT[d9SV6tu#'jMYt:2?iK%sX1H[RS[ARem!\EDL<`0sle]C7L6-(l:!*_=QYMQnSVK %AYkYGk$Ao:%tP173)eH3nZWolg(\&4KBIr=GVHn5(^$?TLR44b?pi1/4Eqh7i1r+FnF4ZC4N'VF.b\YC?E=/\oY#7G8gKf*nISgC %8h>dR^]loX"nSW%Pn!=X56Vp]:pbGHVEeL''5lW!..=T2)m %/YJDr!>1pNjR8[t^D`n(E53N,D-9ZJH)QM+a;.Ok^/\dIF+]L9\4ge6O8!.Td>FhDO`W^QZ(`8$CrJJ/ekmmpZ:2"W'pP3HEBW.H %CrS%-KV!TF1S-i^Sl,*Cb]j2kGj'GC1?6c`Gh+`bZJrF$#,k"$hc;jD>*dp%a(<5jVESpVeb`4ELK$q*[%1Q-5W<,aW&sSrRFRcC %`0gkAP0KI4`0gl!(H-2<&8.SO#Mp.kMq@u"i.!BdHq2chgscXnKasZY];N9BR$Nlta40"3bQ^5&p,o]cH5Z@>`:@EhA^L$_c\!-J %etD1eMuS9?Z0'nUlCSjhVoAXLYqWRfiE'7iHGTiWJ=S3/oL)>D9hla50GBZWdOmD`d_qk->\g";f1/8*A@:.V`^&_EGbHMCl^#n+ %MebkA,pHN7Z;a,.Ytd2`M5a.2X@6V\=nJ<>rs[oB1KmbKK3+3m1V':(7`gS"D8ZqA`DZS@@35c,0d",?h-[8[IHps5d3,<"5Bdio@HF^F#3PY4TJ.-K/,ZIG[":d=$B"*YdSg %U\jaMM`I>Td?jEch78qg7/diS1:Q`9?0l["A^?s9imY9T@+iHh %@_k`b%$j'G_$2a`0e@*d+.7hg*e^d.CGLrbn"]G[W-($_%bnP_Rg?'!:J[DKldoWXXCHu7'4j<4@i]WnQmh8d)!bEE6bXH(BH?]A %X;cF]jhHdCiK58E8YR><8Gsc1KLDQE?iHVr8"pPiU-PWA?H`_Y9#UE8LAb4/!EE_,H5se*VOYUtosR3\Ns/ujggDH4h$GNf8`?!=c6m(_H5.5@k1SDh %#>nSp>XGcg)*2!+F2c_b$I[VU4h]'\gHM#>c@0>,9F==SBBsEncB_Kkr+bhI[e-+@QJPZ(eu092`L"!3`Lk"`)+/nTK*#b$[3)l' %DoR+tWXMIEqKu@\-O91V^naO!7Yg2U"?.!g=6u68RGoC(S=((7BHM+h("2iOViE,/cm?AEHE#dH'#g2Y'mHKcBrt]VZInB>Z17@# %rYD^4E_.qR?%a?7>ga!c(X_6c]]POP6I1)t(dOG[nobNJ&mohH[3#2oacLC_&4rab[j1FtgoDsg8rTMV4o43"*P!(W$uI1-iGd!;@+7XX6^pW=JC*$ug/=V!i,9;a[##2E*+P`L %<`#p957qJY@e<-PqjX%6,).ufFEmpGMAZ&*%6mOJ7Zk#Oe:WsRS("_5d3rJVI"jEmYYi?c-B_oEejjbMk\kVTZ=G!1gI1i%#AY#. %!6ZN12'B2pU!3SnKRh-aL,KXlqt*?T7HojQC2,%7:W+55fB;$=_58'/M]-Ti-6rBjPu%;p:S#noh?9qaqAq8X]@e\4>(jJ %Lf>cr4ekna2R!?`p,p$PaDB5pC!SRj\QB;e54*V:*-a,h %Skj^)iU1)2kkVUK8MZVuc_io:SM;1@;h*k4I(=h2qmcq\]V/OH@WXEi:`9Jt< %l68;5KBOpcI>?.9:u+QPU<#=W.$dr;p$]FNj@l$cE$k[_/]B03!>0U_dPM=W"r/>S&-o>ga"Z=2K4kMue%RBV:P+!X@!T!VDcAnAYIr0<=[uJ>E:hW& %m\ZETk&B@hK2!?ERE4m!W-A`DWs5,_j:[(GFK%]#%Kuq_a9aj3"6b=:8jP.]/#gYYIRP,uG8)g4GWNU8qtYkR!%kI"#;;LhWkE.+ %a=SQC!1aZd4de`$#*A,(>MMlH$=:iR='P,4J'=VO)[#;-7],T>`uUqS/ZmMi;PN":-;g#"^V5u&$[E2p]2mL&RZu7&m%YYIoD5;B %:X9$aELB:Gml1(l^gbC#DkOl@r:h614DR$QDfkmHR<_l*_Gba3>&E&47k^cQro$I@>[3VX,5OcIU6Y0V9tgf"o;\\HXt]^t[r'd` %>#,Zn&Is\eJM5^PJ8,kna-%65BX;N,#AcIZ.I["=pf2n&)lQh.LKd;s/Z,1GX=;t?HJM5sH%.eId2X7+-B%1i/ZOhOk^B[f[,KG# %=+@0#>5GI.K<$)oV%:a,f]a,1:Xsag-DB1&]%-u?cF"_5WT\MG_N\?E"[fa``kF\3\'Z'TD82[M:<0aj7^e'RCq%&rDOqj\f^9Co %@8q[?q,a7C7M1dTOMOfT<(+>gbG[0hY(PY[C"saUN_IKaF1F_[AhTeBTK9Wlf/SCA_Z=GB6F6];n;dkN-F;!'^5>c_j %l$C@&*H_S.rD!+PHE]UL<\A:FMa\1.(K[^\TBq^J&9M2EbJgmSDO;+J.i6h&dl8\b"R"cJ$P$A96d*Fp<.,qNi`[!dd,bQa(Y<]< %fP&(;F)e;g,j6P.Q&BEP+AKJBUg2^Hc^UdK\t8",R?NQ@Vq_^,l<4nPb$m35W*ET!Vp[:eVMrjL:%bMC(f56m481a;U*Q %9"7V3jlTLf^Ztu*67sk8.?AA\lNS''3Hd?Rj*:!F>j;pCDEcD=.QFbO2:d[b;%7T[E1-NgOR'XCs*G'_+6D7d;CV/-=2'sQg;^!P %4HCIo3%jpqRB'm)DEb+&,g##Uq(03ik4",`k-O[m..JE#,YKdr/B[Wm46O.tU\9*F./Y#o-NQAVi)S,G^?`-%F0fXu<&/2>)gYQ7LEk$UMp+%`1coS+?rhPW444(n7hQ-2\q1X-h,&5gQC%' %79Wo$M*Y/!_^c=F0m0q_7JDe>pY(bJIN+oCWV` %mSWWSXr12m(7%)V:A5OXc1p6T?;RsMPO5:!nnYLCe6B?4m[mr#_!>P1:+u#Xm2q]iKAZH'lR-i#`k@#$MpkAJK@FG:h:87=ZV,j+ %3:!>l%lOQPJkO%Lq(KC*kBS8kd/h^ep*+ikI.K!BPA5=u_E,B]QL(u]Be<9la"+r'9BKQ0@^AK%0fM\Y3_2lG;Kp29>Hu!\YbGbp %m=86j$V!(ZV\6,JZPL$k!L=8ILLi8Zp3$r::EP]Tlu^`Y6VB('*N_]!pONn#0p1l!^5X/!KrD+-?d(/b/8 %'eF[KIMLR?ZUb8K)kh[o7gqm5*D_i87oUP(0eDGr,8BhS6jT:r(i8=`$ %msm^7;,O/hl8C;r=EM>^o[UI0(@TVV=LtQpMo3'jS=l'lqq]BG(DKd[Hs3-MFt)%VQP %qfq"$O/):FVFLEC0`)o8I\e^pSu6iEG">0t4`jjF;LDV'I)G0_baS:QG6q?^GS'Odo7Z/=E!,r?M%1YL\1k3l3.^2m@)eSGZ617j4\[`'A$AGSn:*9<]oT&c^=76e^Wc!Z$JWL %p"G1d_J)*H["*&2G]DrrPW.FcU"](I9R6IGBeA#JXmIa#\+'-]3pk>\G,[@5IX,r>/TdE302@9\k./;`s"6SP[cA-5g"P3L;/H)U %kL&SR>4&JXN$PSYs&e7iS^E5]G4#1n=LVsd%olTsDr0R5)B>ItqY_'\a0T<0`G9d?n(`jFJ)\Wt]lZ/sE:N%Q?ILnB_;`Wa^!IW1 %-GFZI0Nr[q9@"C7*2'li]$#+3%)E=l2F-C%TR?)5R!KM`/d7PcGIS>.T0hF(8@XoM/@rj!oZ>-m'Ni0M$_md0oG@KZV?4A8<S34/DL1IB' %(T=,@m'X!6(T'(o)k\Bs]Ng6]ZC($'_&"_t_\Ujc$qj!=b"tBBYtd2`M5a-u5gQ2!eG^gGpj?8+O_889?>7h=;+)^) %"!XOZf4Tcdp,4s%aep%(!J7Ir>5H=gN;\PXBne\oG&[_6o-Vn-q$r,^3i,sccM*WfG^*<"U`#7u*9&L`Bnl(eEht0\R__$C1E1NT %\.Rk[S+I=Lk9\4iURpU`SEn9m!ird$(AEf@8%(S=LH0qB1)_WZIj]3TX1\t@>@!:\VS6+(8dW,6P9LK-$6BZ2L?543gAhIGF %H!PWNRI47]UjH.fLjd"\`bOsSlU.Gho[TubFYhZnfsO,f?lW!)IBP2l`!Omuk.I)=,C6ZLZSel9C11.i)cAH74'_i2!99p+5puH/ %V_&Y7nk*@NWZ\Rnm00*LJjd'#q(C(D>nV.k/,43&>]X\l$TsN,P[OJ=A4B=PH/nX7X6r/#82q6'!Qg!Zd %F-=_!LEU9@$[/[d4:Erl5Th"A$%_(*!Hl/R:'_8heW/gT%9e+'XEN<&OuQLS,eIuf0Nd`)HmQ2XeP3J&6#_D(oMVlAQP`abdUJn] %A.e\l5r,bBE)P/VjjXLFJN%UO\PaJ1n:G_X6J`ZR;(B(_),dW%IDRVL>U`=F9\nr!o6fe:^>QO7OloA5 %o:9n:_T8"JPR=M6,4^-GBtj!DDSLJ2oNp4`?%jE3;T,Ig:nB='bnor67-+0ldsTua5/2BWoJBpN/;3*[daNU6HXA0%OOPFok)#!= %!0TB2^kWMak=\VB`Iner"@08A$(0nfPJY-+AgMnIU)a^7;<<3*CW"[Q!rlA)/3p7;KQjS8h4bp^h'.0KaN.!]K`sHR:.LAnE;915 %dqL?uMuNi7]OA&F/J910a++>l2@aY9d4@Pp(:2QhNf+R,"mA'J$gC8\/AU8MMZmdV!"EKO$4G3)!Q)1HZN(fjU03#LHt;tq'uU0\ %C2CDD_dWYpV`?kBJEWg"YQ-6f+F:eU`WEM2\urt="IdY3EX?=Y>2rlOW=0TA6/:W>aTAh?JkiqQ+k1H[:3K-h3&Nhq-=2)1Ut;u*Xi+ZtV46;n7Df"2bsQkAS[aHKb.A`'k[/F0FF0Un=u(pf1JEiX^0FBT]2VZa&pQb;Mcqs# %hd@4,e0C-:LTV"ZHo]eu]D.!=W1&nENS[Oq?ZM/:?e;1[KSqLMoYSm^n`%_<]r'8do<10@pi8qZ]e:^;I(?$hdZp?^bE"e^Ij5>a %>b:XO3+KfNQ`&cY>QmufbL<%qIpN1L/l0;p<9*lW^0LBER?aC%^mE69B1tRp)YAF2o?d*g]BR:Pc^R#n7_aKkm$gWgKePOT:pbO-+]-XGU#e/f %;.MNIq6]r`2f^kd-c=,)kC!T0(Ku]kLe"2>["hR(HV`bRaa#FKR %54*XBH06mFq6]>LoPA,lSkj^)3FBm?d.:tt_er\%K:YkcSt:p*2<_#H7GXH"4=KZKFfkd]eg"@;hA:IE_7o?a=4e%C<*)Eih323<^!k,Q%M-U@4QT1`&smpA*dH=tZ$"bc1so/EqQb(!Ggg""Rl<5=QX5,#.ZhKSW)i7=Os8(+TI_\`ZE&s"nh %"t'j<^U_?Li5,Z)#1AH]k@6k\$AAG)UAlL,#Q@f!_uH7j^R2".IMbkW:\&h%Oh36f6-/AngiZ2cgd#r&l`An7krQgZ?E`EAniA:F %*U/mjjE4Mk3`P,`\:8UrJ;5)$S,4#2F4Vpf=#m)FoEOLXdG%'D#Js*M>6fbHcHYgFuR %U$Grg55L=O*j>qV\SI6CkZI\j26EX+^T=CT\>f_%Zp'G$f6EYsHn-*+\6EWt1U$Gt)Ff[+l5hEP#J*&pZ0BeH) %\W4t&@,47L>sLLA"^U:XY+mf8&%^'J-oAT3r6TR=jLQqR3#i4C[">,u\]/uk>2[4L820Z>?)NT6Qh8.OCuWDM=hb(Q?ak0epmUFo %KHe-8dL15E6P*V-10k5WI(?$h\-Ts?7C0!p2\T)Npi8qZ1M9+?p`^p6@>Dc;FI`fMNq^Ql5hEQ.lfb>?#@6Mu($`E^5+q4Hm8A%3 %r'ArFOR(Ci/fJi&$b6a)N%aBU(NNfE`?l!s\YEhEA)@NkYfgl@;/Z6#7'je,]q_NA9hNaeqB%#Zf\5<184L.)sG.YK:hlpO[$4YTb=%,Uktl,+]gHPja@ %"(Vq+T1W#XE00Ep=S]op_V@`!Qtjp2'c\KG(jLIFl,,fmLLFp?KLV>%CE`?h7O--R[@mO466j^^[R#D8/U]TLp+WL!!]7b4kIm3o %lf4^Y619/olQW.r7IPRtdnBlTdu:CL-:@"gr!-TLcpJ3osoP@\=: %6P<@ld.N6p`<%M'\iu6e0a`W;:X%U/DhYJ:4Ias54";G^Lnmg_M4]>5$=08pJeSPtT0UXCf)1i1:F')%6D<]YA,;&*V8r&Po0^pd %pZSk/IrT&kcKGpi=!>(?U$7cK*1hZU3(.=o58JX7n^8eFI'EYYKmru^Xuu`3?;F9jT!jo(Ec^'[Wn5]LU\-B?-opqe00f&57QkI7 %[7[mmWQjLN$S@7Z)M:ltqCcolH<`rc)>/q&!(3H13'm+FBKu\@<^$)McK]-pd`p+X9[2l-R?V*!9RIF,m$in+o %J&!SL"b>6$=&WK!@5[_,23*Um2RJ+EJe7ZifhYB*?4c+f,dT9#VSkWB;L++GR!6Bbg`q2FB&Xl-0sWP._VeVD1A$hc_]!pONqjN`emIiKX,Ym$kTrEN %34JbC14An%.&kJ6"/[h%cr+Rm[?&3V.b"ZNV"/kD[5m*c.@njR"o9B()!,@NH#$d@dIb#o*"P,2fT)mm6t82cfru7VRoU7TR]>Vg %MS+tf^eS3ANLV%V""T$'.mJ\U]oCj#0hkr!pbc$?eKg[>]*Pt[gQPBX1.n7\q/gEg.!A''&H9n=\7@X?L3c-E/XN3_ll3SCMos2l %rWI6/B'X#@\?TZt$MkO%7jWt4@_+(nMn3IhWF+N4p>7dKc$o!r4d@%ue&Omk^3RKK:"Kk]+s0XekAVkbm68e0k&(Eo[C5>ub&A>> %??8[^*,tG2;I9Do;EnJ;[%B&T!]j@+-kLJ)"FBN`;'99HZc$6;o.lsZ>%c6-,6tKH0c89m1KJQJBKkfoke01sWN[.pIXZ/=Z'1TT %9E^b]5>c`9^u1CB4BN_oi[EX5OY[/+Qq[#a.<$YuABNMJ:*:AnmUWe#Z%#h0?uW'aKuk$)OYZ#JplHqD;Am=/^kNIK;`mJUM/"Xa %%.:`o`!$AF.sad=^u3j4,"e_W^<#h4W[O:p.8k\g/52pcMA/W?A]e^pRGoYn5eW=lastJs._HqV!\Z@2*@j>f4Og:W+]C4Cr*G0" %V1P%VXJ&r@74P7ofi9at+alS$9"U;p;W>Et9%R"BkfRA-N,!+o(:K81b$lFAhk`Dt%$-:VN[dhJVal,LMkK&Ehoe>Dsa$(0fW2RRp`S %Xc^l?ItS/sM\rmGg'!bkGU6KPa?"L9MXdaXO9qF+bk,>Ik5?\OgMVcOYI::RNbd&)rHh4(\&HP(HN$q.)[mp[J\_!3cXj-7ZI0_&ros5Qc$fT/d\9J53@ZY+;5DP27XT>X7?:FIr7lCt %baErhafK-FLkd!.>'5YXQ0>LJ`:D'NW:a)kT@Q#&mDGca7&t(1e`EAoCBY[oZ)o53+Uof9Wq`cV%a)8IFni2Q6gjV`T-9pfXr=]UhkgMqCMj3o8s/:NSCGRX'?t`BUc/@4k,1c_j%s[3+&qVClfT %f(IFJJKeI^tmpK1\'Y[Q7h<2Ag_)V%,Zgj2sAWO!PVh:Jbb'*#b-(A5@4J6&g1&AT-/c*/OhhCoQmT2<[3839BXre`c %[Po"3R@!7)5rK`$GOV.Sb.d%QhLh_(R!m<0]E`Sb0`.H>H#MuWFS8Ac`lRa]`BBpSqQ@4KXLKWWgp'3Z##YJG^a(oKUk62\B$f^G %(F#4r41T`_`AL5mB4)BSIr4=sED.eF='m4?JMa&''eIQW[8r>H_jaJS'ukM?s$')r9l80mKOqIQjf[+^"6DSG?J\.dWC]FU_B/(< %mEND!gj]X@4H2%a<$LcD[pP+DU1e!I4<`=FLf327>BPn5r1Sf!,PWm&@oh(lB;%jPb6p8af^VArUa=5^B&fok;K63^OGnr$)BE^di6Y0 %If3t1E$-DLYmmN' %*^]\'?'IM#;`M/!!X7CThK2VhqSd;?,5NC)*2&Z02fQeL/;H:9pP_PB!n %!MQ/+Ndu"WbT70a\%0R_ikhcpI!*?22"mm/;!@ %fii"W%S8odT=l;']THh@7'Y1:f(DB9C`A7c-Ztq4L@>RG(isb9M7IP\`2fgQhfIn0S=:&h6Kd/%K'+7R]V;2S^U37`3IPr];OUm] %>L4TiEGeh&*iM0!8UC\0F=OIQW6'IHS=?nrlcEOsE,O5P-q24fKugl6>MDE.]CKmsKq0oM1WED8Uh^^B$^ocSqD+N38,)@qlJs>$ %:G$R`,Wk+U2:OCTt:QBrafo/C1l`5c]9$CDc`-J/l''^PX"P/AtNX?71Z05t)4/Qi)`=h]bT@CZu"/NZ)u'?/*]8TGXpMNrt6I27C%-rqCH %iiVWERT`rZbYkebI]MNR,EPJO[E+g,]6c=8f=gei:7Q%QKeb[4NI,'d,9KhTFpJ`q!kC8q<;3PT>4$VhD-*_7`t7 %*Xh#*qu+7_6E%N0@X]I0:"ue1h.-+Wb2`,KV_];,!==$_D4rpJ-_N<\\M174+nS6I1IJG'&c+VT-4i,:g#6WtO-%nf9i:Kk168>g %4YT6oGcLp.jaJ0DI5sbZ=A&.p=O(e8?"Tu99+RZ[>$UA(oeSmT@/541#p+gm8%h*8WDA"+rk9X=?BF5%Lk-9oO=m#.gVZd!\47WU %!l;W^YT.La+((s5g"KJLU"_SFSo/].O1sd_GQF\U#UFRG]RY&;"!`P7]\mt='>+;dX5Jeb'eeL15;6PS`=%hK"u3@A"aIfW+pK2& %%_9,&)%Sl;*]R]t%6BgPFG_$uWO\'W$nO29FME&HR^FP!bc-c$4,Woe$ %L)2,?8TPqt_.`iTL)=%_!bcq4,DQ5]oS.fEo9a:c^hi"i)#c&6)g'$F;p6m_71;H#?8@n*?rH!W36:UC4=^iR$'*=%_(`JuS93.3 %h:1q!0$3'[_t4OTa$VZ_e.HC/8#iN0j4B.]SH[,02`sP`iHTKk!Tsr`mT2tr!3F(k&:1`:IF?dN"=&2J8gOCJ.t)+W9sD'1Ef.S %MVU)hZCf,98%B!$C@gM.kMKNuIrcA(;Q`?*Ti[=\"b*/3pfmuI))(5#2mnQN?JVqZYiAV-Zp1/iWZ8^rb<2D!bWo)StY+0D4V3^(+PLJ?[GL%r`s4[+'N!f17)C %kF'/'V#dnJgU2!!Pn-..3c4On/+bO8Yk2*EnXp;\@W=l/L^eK$^3i)i2HItW8lu(ia,#8B0`"%kq %.)7*?%9OGN(qTRM)'*slO*LU]R`+u*:&8 %5a!?H]XXUG]#U\`d$/r)1pE*Q*SRS)ei`=MbeV5a7GsgIN5eWo+ND5^5QZM%5",=^5!F %k'GeWf(o!9[p"R")d,VYq2Q*Y:V/BaDD:JU8`cWU#dAg?]4[sPXCA)@TCgbJ!(L^.pDDb3u %LcG&)VPGm0R-[>sN&-J3VDrkeTBXPLpZb3EiFD<$g4!VcUmK$@HFEe8/]^_B_#a]SgPh"cp%IhtSCXe1/C\m/nmrmqT,Llho<\I@ %\nnIb;.sJ3W#QOS3%BV^m/)$Cm#(5G`UU2=lYnPuc,;TTVJc=r:P\S=n&Qk.9NUG::#dA\G,>tUdT!MP2u?VCo-/Z9k?QW'lmW+/ %J+_d?lqe4ll[.lFkYPa%pYADHCh9("690d=)KQ_T>i.(-Y5\7_pa&o[1a+loF]8TDCtJ7Vkp2hIF*W6\;jR[O8!LE&o %1n*utJWXP9M@b^pEK9"U(NG\(*n,5%Lm-p-p1rTCrun!GK*mf*?N:!ah^+0cXLUM$<7p5HFk-enOn:'/%'MO+u %+@&:ij_P6,4nEetW]qJH#2Oo8nZ5qsQpWf@Z8@_G\(\G*q7PHeQb.0!fBC>n%jKi`7Z/MDKektN):OplZRd-p>,QRg!Z,UHh?#kdW0UDn&ANQ*?(bA)VQ(A %/F\+FZsH;dq"X#L)KPJjNM%4,JK4Wf3j\5*#<=Eph,mTjq.f?E-M1ABlHcu&:OTkpDm@NC$[#&3qOc@)U.no0Ce?EoP`$R922)5G %^5Q\4p,/-Yi%&N6h`[>nL46D67!!3DKDiVD[9i]+k(%![Cj!ePN%qY1?>59X8J\)#oCCff&Fe54A2)B6$-8V.UJNO<@Q7)QD]_je %P`X)S)ap1X=knnKDAaJ'[$%MiWL+HN>c=@*=>-#B-.E)MT%M>^\('9$V`BNu5NZP'l0Z7]5r0US#./>R>NdW7T,L\+L(;K+R@gJ= %iES?(3-.GC?XaAfp84"AHmo!@%&Q3(O%qZJ#3eA_E#&a:ZVkI#]G,fB#6A%lXH"RY]83I5am)F68=[.8.8erLO!U)2G76;@*jm!` %A)_2J]d!hlZ,g+3XH"R3UDQ]ud_AoN+,Rtl]f_[9*e0*H1RaL!g%-f57)HM*\7o[4Ot8YTS"t&5mlElfNLR#8,4i=B@h))Q=em`F %KZdsc%)X1rSMPn0nU&02`XALMD&Y7gd-f#X`5U=r&PGJLIZ^[e?IC0@geP,YVdb&dV\pc_DKEEP'8QL/( %/"0NoD&;.;V3J'AkNsKtF4"BYm$PHSHG4'nL]E>k<"W`b9OT.s-$[[XFPDlZCItfJg'W-o)V+s8^3mSeG%1E$mZXrOXW71; %jW;:I2_#UUk/(%0l-#"@SW8"p=PV1_J=<\Tp8Ro[dID=ICglh@"au:s9_\5HFtVjh9#b %&]/qko3T5H"^o&(UZ6Ia@QT?[c4'4#nm+3-'HJ4$a/aM*5$Z#F%J$(A_URRK$"S67#+l)bTf3V2'-$NZM373 %)/#kONTbuUW!LQ02;!I])bZdj-m!;+cTHDac'S=QEpITnIYF+L4H3.>ZGU"S#a''HS.LH>hG$LuQi$UCKXeXo1-TUdPadBG^.kr- %I;?mCi]2-D8S1.1203ZGgkO%`])EAFo88trmqf#KPII:7cc,1l\6e$G1R:RFb3eDsX5$GsE,P,SkT9(Sp8X1/)>#2HNQp.pT"+lV %/9;CUS,;Iq1%X02chQLbppYt(S(oJTK'^m4'4I:M`Z12[U9-fBK:HUF;I?YDZso?u9@M1%_C %5os7>XPL&4fA)kARS(ug=k;<.I$Q&T1KjhS/2T&P`ffAI4c@VfDh9(+-&0aop\?ri/MVVgi(?4'9+7Ghmu;ZL>%77XXR5Od[/Ba$ %lpL*7S=CTs!I++Y+sM#%/dSG4^Jm_i:9N,SM\p+^6rZ]5>,&n,b8Q-kQkA4"U*jgf\mS+g.Pp[u5Hl0,*\27#qB]0"(L)fFlHCg:L&WojMKf(d;dj\$H %$3Db:RTg8-@q-I+E&r\_64^n6nt]3W3I,c[;3#-\0\&EF1S?Bl %hs7?JU9fodRTT@K&DugCHVdX&g;]Gd1Be7M4eT!FH!K+i6I+M'dPHA^p(;#Z_t\r>5m7)_X$sFEY-#O>llsNYh'\c*fJQh_6,*K %S+?%MD:J]&oW;HB*\@q@CT%)5m56M3$\0%sf3am%O$>k0Q.pI6\W8*1V7X)#p$l*Q.kAEr1"0I9r %^'Pa5n/2a?PK?nMBiFSt(leG%jrRhN]#gA56-IT)r37Au9J`bS0&m^$,N>e/]uuZR/O'?N/&`cI\/uGUIYK,+:=,Yn(j`Za^]Y*M %IYR+JJclO)>#V+.1nr4Xp(uXYZKME#)CS#*75O) %5?nL58P4Gdd4?^n6)3&s68Rn4caCt"c+;l/ZHTDqcj:UK.dLOMiIICYBEC%b$:*=ei_@IUT^d?"X5Y_'&X%>$5pQ7?.g,-WaglA.7kW-,^C&g)Ck,7.XPAH,mD#:6$L-Xi3LX[L$I*U>*+4^E8UrYdd]2kdHiFf1(4:p4S4: %DL@QFTh$c92CZ#)EeY7ReI/VWcjYIGSeSS<#lc-(3@1fDtit5'num^ru,1gu:I42A^Prc-t8:F*f#& %bGq'.E#MuF/`1_n167S&kFm"JJb:R7k.+n/p[nK7mk;"1OoKTI/LQ/]f!W(/cR*ca\DL.G."8+b"_Lh9$Cq4jE`O@HL %>Y#(m/ORO]1E[S-lpm?FaQhk!Bk@VS_sj20efckLgPWKXfa@.0,O8t:M!r'KndC^RaSC; %#Q?bN.2q^;JmL`+M%9%*]20)3=D^Fa;Uuuqea6ONjbIfm;AN!QJ%jH$^Up?qETD4XF,1Y3G`5]\!LsH/.JI$dZ0(tW`/mLKZZ3!auC4' %5r@RN6=j@gaQ+24?aWp7Y6N/p23D3N7IPqI":>qlI=d$`O;^m?p;(KQOIFR^k(V@(+>qSQl[-mEh-H>^=n1_9ZhB9NLcIkA0t*t8 %hhduo`F$&L>iGMYcrBq1'&!SS"<;R7JZYX=Q<&\i*5<*C=c( %R%g')BJBl76?0dJCe2GXLEOqYa?MJ6!_6)NDe,Ob'X,co'gdHd&&9Ft%&%WA&*QT8?N(aL+V\8-P%$d,E!1l[C2Sc&T[PAEKYij0 %+'AjQ`]92%E4$<=nc'Uon3lWU(461\\N'E:^b %ddSR1$568B`MSrH4?[C.WU*h)qNC%c'J9"S3*&s2^6:RI"dj]tI*)Y88YP=diL-tC#&^%I+`92qk6Q)CD_T_:5fHZ+CO@2acjI@h %M1EU="*1rBdQlc %;?F_R!)A5^S!#tdBfqo]&)ZPh`a"\@SRXKRn"j+c8R.FM:8-3^Q^5L.8Z_.jY5E4]3>F*KcWS(7;V1+.TWBgUK.s$O('VT:Z)s/s %L1(X*j,l^GYc/gV>=8Wh%AehZ#`P^$mZ"P.*kW("f_K37<2<-m`hbp4'iIle)&HFcHg_>d,?`JDhWs3h7tX60E9<,bN2SGfQ.$lk %![B0?muRmr.:jIZ0t[G:<0Cm"\pD,6*-!\\g1K3B/UQ+ogb:@flmmrU8igL=EP4-f^fB;aX(3aX'R/KQpUrRgTkYcgb`\fWPt2?cl0.X1meJF %#6:Rb'u6(A\-8F"aoe(e+-?cP@-2Z%=N%WJR[l:"n_&30"jOFLkJ=#2f/a!dB]a91nO-Ju5r3m9#Do\CJnBc"b,`sYh-T3pBhk&i %1NR86&T+_gjsla+=mT.@FT(/P<^G4)gNgDs]KL+C`'im %]]t6LbD'ZK>'Pd*^ca"qf"r2;iN+CRdl:u+Yue$G[.I/7!P6$$A8/#rU\WFM@)J1AC9'G2!LXNO_s&9V-#O2P+#?* %Y%qe7Ns-HhM=f+kZU@g'iSPh9gB(^$97OXcG^Q)OpQu_WX`+3B1`+b9]psCSDYDW"b'hj9\Ti.cX=\jM!Bs_CP`#SIA6SorX.hLJ %^=UaFQC@DUbm^3J>IpJE9W'4EGh#Y_3-Cr(aJu>;ML2>eLie^=$f?OdfC=A_ZlP9pI,Wttors;Pf\NFuH'ubjOtHPT]&X7@Q@0?N %nccW$B(gpknc_/$8,@hTCrip6[6qs)B43l*RTu/[J;,U3-hCHG$q&Ti.@/71DT1'$eSPN6Q+,(+OQ?hPEs;:5*N#l./6A^[__>AQ %Z8Ea[J(q:.D9MckD->_eK5&AWJ@7#PNIDCP95D^sOtr%kptor3 %g3cGoj32SNK0.Rg`'fWZHORZ)`0"PqGn.96TG^AL@+T_YGm-\XU'^QN8!5ObT?F']79TDV$Me0_79TW[IJ1T%GC1JLWGm09b=WNE %Lt#=381Tp8cb)S=*ksV[^ReH&o+0N4ZAcH1BT'1c&?'Xcd1p6O.rIL'!j#@m7OgO:7Tkt0NDqs.i3H6<4'I$@d9eQ^nGB1u]GGOj %@f97_2\g;8hL;L&0u'?Se`SEl7rV4@'>48hZQ0;`<&)KmYM7!q6(aI]?S3 %-KK6!'L.SO5>6'H;o;DmjfB9aVkS_V[q?u!T5*(S-SC,TTMXtT+&uCI1+9gq6#k_+ba!AqSj"QZFe5&L8.AlE6R%K7Z %9rHG&6Mm`q+@Xm1Ekmq,Z+log##aq03=JSa>#Y8Jb6-j=YpF+p9GW0Eg>da,.lF'T1U^_C[0W* %HM'&9Tk1*sU6E=^/g@J0]dQ@Vo(qL,/Plu?.'BBR_Hf)>e'b`DH$qu=kaC%h1([#+7M<0K9T?-1k%cPqn#X-*p%S;6bq>A>X_XIc&LUbDK9/k-f%rhpKYd6NL<0'\N-clCcH<`d"X'pl_WY_U` %at$'0ENmgg;a.L.[U8+k*Hp"7O["JCO[a<>fCGSm1Y %g7mLHRor)ng(l!V$oM"X9;j,(27"K#@YMaj=V3!c!^2g-R2'-C.no[NrShY20$PF.II;5+JmUR@a/AS=69<.OjA!#Wq>D#Ai6$.0 %g%e7C3-6cC'UgZ@SuBj_CE,C%,7;-mrO^eC.RJnjE4\+3KiNApSCupP*+9TGUiM5jJC8mY>Xdk\$7gfW,3TY-4W#lSi]j@_A?#Fb %$ELr[&[UIHP$u6XcicElXs.si"`<^[V.kl=XF`:6P&^Lk?[U4!>D[8MV*R3Y[g?c-M?m^Ta?o\%PLPcHB^="5[:gdNN..'/!"0$9kWN3X>/:G8f %k/mqIq3FbVS"P-o=EBIL5WnZ($%^Lc"!Uua-3O[t#B]FaK6lt5p:STRY2j5e4>Eo(f;$s9+*?pGTs'q:.4O@Rql``uZl>X=%cc_l&g7Xh\_0GfiS;2KQVdc8CV8L %CBZmGNRZ+PU7]Lai/De>\S3QoVh\%:q#KC&Q%Ib\`D()=EgVLd<`2S"Ts[4N>"/`UF8-itg1HINGdS5#roZjf@Fr:G=t;G/AZh>h %SgRW_B6g("b7V9;]=s4h:sY>Z(+#C'o5p4eniY/@LPUg1<&q+m<&e1Q-\lfG25Z-?b5\"=(hi>5%Ui^B&:0.j*+J-jV:.e:j:EU% %KFc:"bTM[Co(d\9o9dTBMmEteAT#2bSOqaKZck"A#]"`"!U([ZEl^1f/nC:DhbTl&0$Bck0.C:p3BcItFI'K1dO'qXN\/c[UoD>` %_^s=>O$B<>1a`+s4\!1'\b=%de=OMr@6G^A"p %mb/8X*hhM;fC4FZ/YE*&UdiXW,Uqm]t892X(3+iK*q68=^kKsMK#/dla %ONq"N>)E'L&tD5orVFE?B@&f?(!jIF\JiPP %`m2GGdhY6)?5X-An]f7@K9"&+1fc9U7ZP6=4[qYIo'A"hM47c1rQeohphpu=qS>ea^6=SRDiAOXG3ECVF-nagksR@M_8$4[I1^H. %/[T!U!df7%gj5psh>p8WRokL*N=1#(;sqB*ke^Ts]]]qK^4CK'R-n\Rok6+ %<]_:\CjO7tMqS=D]M0J.s3khg/fZgB?5AkNCjN_*1mhO`HQV58Chuk-N#fX'ip[cMS/AkEWS`G/%AF1&`ajrP]a7?f`3.gms/D"D %C?"?\BuJ+1.Y?4;e'Q`&R!h'6?M&EAH&=HeY)hl_@rUu6@aaOIY7S\h+3E97YC %>m@d8oTVX7?&nUL4u0XI3:K%6c]drmW[2:k.A`gNDlPEVk)6-gg7FdZ-9J(o$0B %3S/8+5tXQ_9'J7ApssG!gb6HRPUaNmQQ:%EnVIFZoJp%_jRTrC@To0>oEYV>E@<"/\17Wk %4967%q8GWP2rJH>[OQP#EV-o!Kj:5,'^fL?ONS;V8Ko=E-f>'.Jf!K7Vfd\$Ed7^=>sfe?Ed7^=K#@gYY"1\Dm-,4WL5J7;k5nlm %Z4I)J49:co$\VcVJ.)7m76rP%^nj-'`'CJ9of<%<"'h!/@3JQaWKL2`mM6_(R%9cc)&T%0O0jut=hPh'@(/WdWIo1;j\a)EJ8$32 %"`LPX3`s_ShigT<,&DA4h/`=K^)G@'cX]Y.l;!60XZgu.)eM)QA]B[Pl,>=j$)CAP2T$bUp^4p@%bgZj1N#$$Ai6);;a;GX$^0K%.^,IYU %I(>mdGuok*?`k/K4ldURa+ACfD4?h3(53j!`ral[rWdjCO)"8c)7[*\7J`0PB@01odCfiq&=?6cZTnY*i@gs+ej0.f&d2fP;b;uZJ^&@YE?R%.1A4L)LL"]CKhUrfRMLB8!4Vc.>"%fuA(!AJ %%o-c.Mb#o/(5p!;ib7Ai#+Os[&\WR)qck_qrr#%q?rBE3mh9/\1S %&i@%KRLg[UUe-HJ9@g\OZ^?k/?*Y7!7eHW+FNI]49nnNj&9KqRQ.nZq7Zo!N/f;+V4';u6Z**!QI-.[pC8mcPCC-KZ %-(.XZ4$[.4LPC"1Nu=`[QpOq,G/4%!N'c2T-2F(36F_5j^JNM6KbJJpHD0]]@P,3c?l^dEUd8jqc^VqX$N9ZPlfDDm+DU9=LiM.4@Lbop\j<&4t/,?Jm0GdnFLQKJk_47/Dn/6hgcuM.:4R"#VlQg?N3Ksf53(#A9=tU&,YYi['(0P,r]9qe#2d(c..LTA]8p_&Z-6QIO %OkD&5TbML8Q;6"%Ekj^`0![t+UMBpo2:.W.6.bmo2:_nW]Ak)NoXC2&od2qAAW8nKJTKq67H[L!I@-FS\^5@WDnRHm5)tLml;1Ui %:&,ZRj2"V2=LWZ+=Nh89f7M]o2BDeX(gl;lVb3``& %oi'#\O%;>R6@=eX9CNe&(&UP(NJ*?3uM,;?gpBsb'Xf7Q.TN19&K`63G1.^GAr'!a[D*VeT>^_VFg47U2KAU;mTab*iC\[ZA95"E.d";:OUP(O5>.:'a %&Xh5;XIpk$MTdBR!RnW&XTE8ED8QQp(CR. %l_iNEDAN=VHq`h^-+((ugpc!7-Pc=6H`e>BXW+1`ZBrpiql>Ui:qEXT2YIL3!h'g,'d\"ujXuMBPE)RZGeoE-Uni.nFOLYKe4Kg/ %Y#]kKKN:/OU/Q?NJR/I\CB5r!mC`hRV01g@N4jm&+J1NVd*A66bu$bWa]p.!!Vn;9mo)km5DkI"qWC.'s)T+ec"E1,>36IOJ:*Zc %JS-R.%EN1UX3X^2)j&AiaF^sU2B\Uqcb:Kr-&0`tWukTMa3&%G$JLQg'#SAP-@lE^Zd9Qt)Z[^iB=U#dp&KnDl*\dYB:6t7n,N^u %50HXL&RdopUkC"Up7j'#X7Wt]@rFJ[rQ(2KP%9.;,>UL]XCHkK8"T=L,R^t$H-W([Z7CNe?]35S:#CQh8"P*o,l9B$@e_JnhPW,4 %@e_LLo.`W5"9Y8"g>0.g3$u'"?;Vi=3gn%< %@$#eMXfV>^:lM1c3?I6eE$!DZeCmb,>5[u$Rmq.DJnQL5'q3Xh;d[$7#R4074YL4G+;dX$B9F;T>L-)[RFtEQ"!G6IXW6Cbm)RN` %F]4J!'-I!@/QXR['WhO?YS=\Je_7F^$Xb3YJ&OJpDVLCorTdFN.g%ebOEfD5=,&2+8Tl#2r`.a-:u%b`F/er[Zh&QhhfsLdZBm]t<58QY#?JRR6hCIX[0QFDUPC#[0F^8ZFTE@+G?XfY3Z(K&Uf%,lo4cK@Un#[Y%Tf;OQ"g1ME %]QFI`!1p[3\Pe1k&Iu[sf!At(CNfCp_=L"m;YNo#J`53&t>;UDn8`5i];0QB0F;pF:;be-#9FT\WOB>!&s`"A37*&J%>\ %;dnk3;4>WdeN49'*N4]m2dAr-l61Xg.`kJpQ)4nf9J*b(;aK*u-qt.RRHjdKUb^IVJP'Te.d3)uDHLsZVA^?.An`_TXb&'%H.j*f %=/H$H5-;a9Xi!J$AUn3P[k]hXL++&ao4aR)=IEp31XKLj2CTHUg2QNk;8q:?-[%YV.JAV)okk[&7bFZ&FG+T:B<8Uh;pUW@]r@$f %,I9BfA8c4")2>r"cOmNn'dp8B%r*p>PKiCN!>R]fg1GQ%LQXl\q7RDQgOHn"d%+u(a(9=*)o44VCY$_MNQi;b)jZ^7rA.m`Zmf,5*j+nr.g*VeQE]`<*42L.^:s$n?.T#' %gH:nEJmfB4;BbN-5!N(V>i6aen9G,:DM2I6)H).P16#;LW)J:QlTm'b/=a]-%1Pea]2sU0ZRdCDd=lKZj5qK=q^#T&Vu%9*kuaoJ(fu_;*CHVa.$#Lto7AEFeg4pLVlQ9u=uX8B7(q6p*4I#Y %[l*_G`fk@+"O/\BdHcmXOlUoPJ:rGn1,rdHJ:sKR7CBgq?Hjsdo.n0](\qsLnT.'h<$Kn64E@k8%UG6af%k?2fHa863rlCKqHG's %bjQ><]l%>hFcP@@+>PIULL8Y%@RSq<0Vk+O'Q9Ns:>I&;G6rUP*(PRN+$joARXk_D!dN/Q*GJ`;>(@U0I5iZ%@s5nP,tY574k+`c9pW+$+IRIf85\Kf"a7d*i&FVSfIMl1]P\_9a$@='d],n;]t,G %PoHmGV]ZJdCP@edPF3Xu,+-,`Cr24W@?`Kl`2i=Wsn1p)Ya3bsL!? %4k7^hM7!RFMR_F6Cd<-DMmVm9mD@&abYsd,.P7^;e>sQXS>%)Zml2k__#\+V=Ls/_=#efe^eHL'fTUB.lXfJA##@/-c[B?+(*],89K[g6J %oup#0(Z=R]:&L18=Rp$G"SC:l^Kut$X[f7HTR&b%c3Y3@3pUn/YLd8alUc+6]cO4X:QiWZoiTajY]%XYf=Uf1%P>@8X'3go-,=N) %)$QrIfEWqo1&>$7in*M$WqA'O@+OYG]C^ENC-!0G@amNLg^LAPs6NkjAbGBBd+p;&VqiEbioR.'J[s&N68;b %4Y"_`2@ra(!+GO/U+etI"&1&_TnsrtR`O#6'SIlDTS\K1.hkk!5SN*5?uMe'gg@8*Wn)e[R7FITfGesa1g'`m$&@l(g&^i33+0%i %[dUS'B3l[2+lpaifNc_&=$M$8OR*]il9hKrN+gPZ&I`?cON$[@`,9;$XYl-.6]/g")m,Tp/fI^TdqthNP!.iM`66&I7#GXg!729t %iJ'h'JQ&ju[fEO(\!MlX0VU]7?:^5HMtS!4+`q#,MYO2+,&VjRh>+)>Jee_g_?j1TeTf[NH/he<$m`m`&WCcqJk %>H-a.Ccq,U"m3Qa]32\J63X_U,a?)6YFSqm'jYo=9D#RPZmNqp43)m51kf*@p`):EBpuOG4M+kTRsDeR,:3p!Onp2O1XS %hS\B,5Lgq%q!bd=-F>-)5;/`2KRa3*0NiD,IpZ-EiB!!I6FoTfX, %4C+[s^,+rB?krROdYK"2J&To^0j[f#ql2]3T6np9Y:\N%7iWe-96#0ABWc2eYR@q;ek7+-*&JAgfqW%c'uR?+]f(W5_dg"ETP&GS %e??&"N0pUD=OWBXli,k^nWg(@]>:ejr.-sY)o"4Rmf1LC2BS79N$RMq("Y3nY"L$:T7"c$ljLPp"[&'1lh@8e*p7U0m)*C_*OcX:V'ui##Al!5=t(-6i`BIjp^/FEM4s"\+V*n.)co/6!7sZ=S?F$4j:,?;kh)sC\@2(ERkO)m?#]A,Ep1Q&7qKH!:-C/%Z$EJ'I,9OC&OIVKXV:8/>-IsW %o71+.7prA_.mLJI(ZTH0pHg6OI4)49[`^@H)sPpZ@qT5_BnKCK %mCLX^hn2'31(s)!=hQp:3W:?0MB`]`0uc)#rtI?9_P+giq2OoSkTsVV]],SG[IJ5NaDi1pVV(^&YoT\]r#`5$Pj-(a8&J#Jdai\Yq %WJaP9aat:7`8eGTD5eEtMg/L6PpAjt`8gFRT[f4UX`N(j4C\nP.HYquf`GeL[OU<-c;BiU0]j8l59hT9EHu]Np7Iaj*Artn %CocsT6D&aqd2R*p(\%WQ.d-/!oB-oHW.&&kTmLF%7@+UO2F`^ol^Oqcod)d,j6esg\X);IMKnKBS_1qGels3hZGVm\X@loT%5qs1 %@FCcKQ[-PTUEe3ILRfkMN_$MC>cQDr)]S"Fl^_`E?"YPVG^EOkqWVl=Ms9a&@LDa\(%JdB42=ue:rMB<[BQZ0HkDETD:9@QfBVM) %[[h4"r1oV\MhN_AaZsOq#lX9mFHKbF^G!6Ua$jb%[!B,bVs:"a6BbTm$KFcpKdO2mD`O$4$;G9o8SJsB2,.gk?_W6bcpU*&=@,[L %@i:lL7D4TRpu:*)kd`d/K+nSGe-AQ#.1fZV%(FjsKJ:c)PWJA;OOK7TiSH;8qckK;2Me3kP@RH5`JUT%&l@aNPU*HY(Jj`dj&A%p %fUhG9EX>;8#d^jbqr'4TA,DXE?a=%Vn)gF\40"XTSK[i&f7h6bus[4s/8n<-L)/N+DaU(ge'IK;fb=1&%ene4E*Bpmru`X/G3R.58DLjO\H'h=g)!WnYYahG7d`R6kocVL?"kY?$7((2MTS&`[s)>qZZY)s1;i %X&jKQVDdW0hd-,*tecujlgieFiR>"sI9Qnm.(n&4<4RG)dP`9_7\3e@jiZlH,N %,S>-k+6t@K9G)BSO(+m!rcul8s4kVW4:u\NkA %hTAW/_:>1*hHK>X*`I]B&Xj7VLX(?S66+AtLMfU2B^sE,D*9,\l+n"(6YCX5Htf_0U_`3uS3^qE-FG+%N*"3[W?hlACAF&skZqoL %>,>=^Za^`CmoQte8'p5F;LhilT@B#,H+!QA/P-`:N*#>;P=-#>X2Ulg$glL8kK:G>;-pGl^JbMQW3U`W2@?$^ %/_1\fE*b,GV\Wf2M"#0L2R*JXC)KdKNP[7?/WnDYZ?q)W&7`@:&Ag(BYgJ,%-gRh&'l0BS6E/C0>adOmq-NJZ/Aq? %J#A>QMt(QX41/J(']IU5GA7.g`U),IY%R4<%l=.\$c"(lDd-]4ZQshI?Gb6jCdjbZiT6M>dn2Yq>"[u0Bo^!1pucZ(Y<#/%6jT:5 %%$T7]D7,2fZ1b`:(<3653[3s9peKt\Bml5r`55$"Cm*%$BgDr#8=NY#[RgkZKTJ)D#*TgK.`9uI(ee+r*87:/!3U-ue=\]OCso># %<>W6Fue)u\Tb1psi>R!$*oE=X^KZe(N"'nh@kCI7A_:0KbX8WpFT,L4Df*k8-5tQB8ahOIDf2#s! %;lq*7SuMbP,X(eYhcF%)EhfP"?V!NtI&gb'k:1NQ`IF&IV>mikJV#Et<L$94o3#leFu&kr=h;$G:4JVK'$U$?TqNLJZn7$Jgs_>mLT<=![=O(LG)L65M(BZ=fG#^`oWA6gLP<+bQfi(BN`K)ukNa(Sjk3U@/h!GKiF=Zcl3%P=9IV,0+^nc.9Pits9qH"_Pf-b7>Q_>Y4EZ6&cdOt16DdN%P-CV4P.Ms) %?_/X!K\:244EIuEkN\*FhMB/i!Q.RjNVtq*Sr:rf)7p]&^-hhoYe'DCjJ+Mm-n"[XHHiF?N?iHid4[7Uc8=Ue!VP@L.cP,e-kZTS:XD@C_i]rDTCDs#@oeVYE %`A2\5f!67;@3[kH]keWZi,fT(,o.nN$]N8:!8KmPG&IAJ9guf(S^cE99flKNb\(=AU7q5Ffi=Kb%qj_nI_>8S$fSqF!KKn#hVW3P %E%V?gB,P90P0BP)_(YD4foe;-Jm[Yq<_IHlU1^*VK]8`!nG\dT9]qK#i(j!]FH%!'[^q1gX&3Pl#&Jkr9]J_PoX?X@%9*1Z-8%@n %^;kgBR]Kd']:E[!G`cT5R[THBRZj!2=):>(Gs8i6;Tq`/b!0`<3r3r0mY*ACTm%emk$AmG&km]nBnlpL<%`TN\3I@n>#>ZWNou'?_RA)Q\o`\ude*mFH2o0mof/BSI+<[>.ITBVC %(X/pE1P(*%Ipk!7c[7ZAoutJL)!b;.l@pa=+cKaPQslj*(j;+g"GSW+$d`)&QG=%YJ&,)OM$5F_\,tol>_'eY^OQ5K+AsLPb %\bWgbOmf^s5<#BlRD9%4pZe\U(8A.A<-IK;kW6?:-UKlUS6"NQ>%6%8&Osf6B4n41,WXl<>(!8>=<;ZC]o&E(BPVDR9?V:NflVD8 %0:K]1>-,"SXD!9p[&0>JBeX".V!=tV='/F[[,L3,JLTEdOlK:P6q2RBPVC+>T%Nu/QUQ`m(one]:%4@kT9&S0=HE8 %g'q7jRt>UY9kCu!>CgE=BkC*)55K$YXK@IpIQso7ZM./h#m&3Xc6/"3i1W8up+*)9)f5n@jMefs1UJh9 %fJ-Pb`RNJq58VLX]/FB6EkC:*?J^4TfKiMSO1.]$[lq4TX1$UFLpZ2&P/-=i[5DbSWb48VjAf:N3VoYj#T!+$FA05O>Dl-i5nCk4 %>?a".4?qFML59Z&&2(V#Vl>Ma7GP,Nu+D`P6cS5ace>iMrgH>"C/'Y-l`nl&Rg`@e;p3UguLe#l[qdHb%D=#$U %5%.jFj$D2/5;rD-&)b$h\%B1KL[p#=T^DpMBn7l$HKgXu4PfkW6Fc'f"Uj?HQ-(V5cf^PuFtf%c86:WOJ^8j&guh)]^mjj*E&,PNj] %aK!`2N%7ED^PA(pq8RmKH,30heJ%H7:00B*#+OQLZ2#Q[;]164R^Y.qlKt>gXM;.a+-1@+#CC`tr&Fb%9M-CCo!MUaImXUaVkNs=F6tf"XE`/T$!^l>\7_abkT4&WXLP0q%TZ52Z/VXJmS9f'N^hTK*6u,-'eA\i %.^#\qM2;uAgeYo@79$@uB;dfS89Mq0_eD:/hWKq7pC%e'A<%2H&eI<>B8C%G)Jtp#Do,^P=KK"[1,Rlt+sK'16cD?4,qN*P1K5@W %>kuBs>Oj[5Tlb$qm$Bl=WB5rg`PbPW9r:aJJNNrB]WbLXcVSWR?,X^>S"\hgkQRdscu7cJr_#F=J2?C11YZq;mj0s*E`I3c,V)td %"KjS=Li0YpM9F2?YPb^>`VgtjS9?5l&$9_^Jna#*-m&#:e3*7=)%iD\H8a%R#b%n1g_g^ZXHGa"3)$'V^R[q/PUPsl-Z1WNb_@I) %A^05@nB8Ka0,1,@5n6J,5^LKqLU,MZfen8"#gG'0koi)S %q5u#HCQD#1'RtK3#uhn`7q$ahfntglefG\M?3Z)24?76^X?Anr9-AnnX5&^>Fli>W6Y0A3,U#@\=YXpO:SkDkBY:h0 %7"<_WSjZEK@<4F>NGRlg!DU(@oYC/AZ_=W2/U@GEhORd14PNaIHf]h,q/s(0l7,-AGg_-BRqM1R6H;I7,01A\=9\E*]B[r&ZKg^= %!e.o>mqBu@j!K)ob'Aa8,Q@*USD,8&X3cq8\h4&hMHBEOiV30%O8->J*3HN`['_Q %kFoQkXgMH,&rlSp+U_4s(S18[pa_u\TY"mEG;/W8hE^]2AMf$8#"n?),opTcJa:1sKa-,bGs.Gd/#].1BRl+J?Vim/QSL`d0-GfB %4.iU7kN?+(4%Toq2=`[EWRo00)epb/hSDfE]NSKB3S\;P=',7+]cs6Fc@&+7nKaNK7&or5[]tmBk-10mT%mp`g,l-M,l8sI^?*^OghEVNm*_U.r\>K=f8O4%oJ-R)+jA(6mfBEbhjp%R6;CCSZ %5bt@iu3eeQ,JF@$@VH,EK %#a!M>)cn0;Va>06'bc9DamSUI,RD[Q7mNMD"@7"5ZID!hi8CEV#_MZ,6BFN`Ga9d^P+ugQYoofGE@3.?c:)='VXGqPG'Lej^Ena[ %3*-dqXCD9_i05F3W1R=oYrd@Ic.p^'s/?S-1H.#`bR@g/@e]YCYojpJ"$ePD;EmILVN4%Af[i %G9Z:rU?BErM$RS]&=cGR32%h$hoj@[[(i=GI&2gb,F&)d%(lD#2)Q,$"M>XVZ]LStThV$%t7,%/rV5>>shV#KF[#HccEH=)KJ[Q[JDG\RfTAJ'H8EGYJ6h;.)B5K>X%@q)^)DB451%]j0YXWn1Rd%!$# %^JMR%I*S57Z#,XD'!!_*[TW?,Pd,)0$RZ^jkXah%]P/N(=CK-W'j>DmnV`7B.Q!qfEYUuO'cKtilBEj$Ed"SlN,>%VCl9RI9p.qT %'nMp:S?fb?o.CHIih(E<.^feL>!n$F1IP8:Ep1kb#1h#MQR",o%:'dd=N*ZXBZ/4ZmMNT=A0&GY>m8VX`I@c/d%uYMIND$8Uee2H %)f':mjlmO.)//Q8f*^/O@\*kE+.jB3MBmHA\M0D):j2ON33O3Jg@GY<&Y2Y(H1G!X`N:SuUVj6T4.0KKf+7j4?3hju&ZPO.XiUjB %1_KZ\_Pm\GHH'h`>.iY:"%fg*aVRYWl3<..Y,[H,Rfhba@Bn,s2N?_N?CbcY]=fIl=oI1Y:$bNUE9bqnuEM)Ri".D"CF< %i9*#FCmhlG)og>#)e7H0!Ie2SI2D<^!WH=)4HFJ/$h3QJ65`VOakC]XAa,()Ik;H"O+@Lpo4+O[_dF7$d7,1a4jK+F,ah[U)ZOPQLA1?U3:N?m;g6Z_X&Fh1E, %%aBM3\<8dRJ3R+#8)ddq!rTS1TSMK#(?!LRcngJi,RY%4OsMENghD6iTm`5FL\n&m>Xf*#]]H1E?'+"o;g/ta;KG!)+gQRuP%IOBp/;l>gh%2U_PItUpI4:OBFkS@d`nMKUjoXQ+7!aO[cYQGsq?@XP2 %^sqt6Yj?TQG1cN.\`9u$L)ii$B\Do4lp..?"EE,Dg7B_PZ<`2*b:t8!0&%]$1j5u)a(;jk4-CRT>dhh[6Zq(8O3;\aG!L0`6!UkA %YTq8P`+?Oh4"sm1^)'2XA\5Z*ft.e:QQ7W.MDm0B5B5E+Z@bn%:L(?OY[ad4K&a.BL)lgXM@R3kitl]Tfe1/P=tQM*bB>$6?pu;r %bB=bHcoMq2>dhh[j-e^8/hYn"mm:\m[`bmb\cp'mA\2h%\m,4EbnT!57;Thm($'*2PX_l_8+[.O57;@C^B6IO'nnb9F9/j4T5Z5eT_$Z(CL/$96;TjG4MiGo'O]l:f?[,ha %Mq"3K`@43*LK56>XehhZ.MX7PW20%\a/uCkp$PlhNTAEic+!4;p->^7Dg+3ke9HIM)%eQL[!R8[J3s+",KY7LB4h,Nhc/g'/KUYP %ZF7.6]mY1`Stq^e0lkKVDkE(S5LlqVi)($3+6,/](M.'69++b02cQj9264\s$fkaIe.K3_Y#7bY:cIiTqcD_07mIH`7^gd,5@a-F %A^o0f6?%kON/N=4Bu]%>EinN>\ug_s"^R,,/[Ent_:LS(3cc!Zl/CaM:[_rKHnaqtXnKcSr[E0Q_8g`"^6e`aX#btTYS*Wcf"-p/ %ma8@C^2F]XUSR4GT[S5]djm9<'GD(+=e?'rN-D=nS'SE0V=u@.1Z*oKG+`$UT:0mE"tQ"(4]29@Beo-qMC6_7]3/p@#&TDY;=>i@ %c)pd1'UI7>c?MK\TKYM=q56P%%IkKo.-'g$'8q=MW\2-5(ec[uqF$>a,"?`[ZGtV3X,]H&U>SZsFPcd*&=7d?pKRoO`5T%(b)"]r!tC %22D+EZ%O0`I+%F`iF"9DHP^=Ok1Z[:Sr,D5?M[L\JF^VT3?8JR)(\h_g)0PpO3,h&T%V@d^V5TPBr:`:q#_mFT/d\-=/I,0#*T8e %"*m^$IVJ6*s-_,J?HfN`2jDKH>3.O0^XU@o^8-mY/`eeMuBFlaGWU*j?eM)\#?EXc=$e/==ojgcK`RTu0akN2d;**HdYhhiZ %s6!4T.+1":q`lJ!0cXi1c^>f*%ec6+9ZGU!!m>?3gYI/BaJ\kMj\XC'5EsKC(26d?L,$JD-c2k^VLf]AYA9SD]20#4*@[[^K %XW>N,>%>+UKpMDTb]L/H=fPdj.F"&nl@[KD3JcEg,nS"Y?]6Q^/Iph!0ki7H`$:g:/mTjGNJLqpf_VB?M.!sBgtl36r]&d]MZVT+ %nF@"YY"a4j\rgjE8.m)&CEb*5)&ru^N>^QVDU/>9=oXk.sWKU:*4_5_A$L:ii'l[RhT@#jQO %E>U?/8M\re`6\2;Y@^:_ml(%.Kq%2pqURTbi!N"nR95E-i,Z3@VV]_PR/D%F5NaC^%Fm[>d>VAAc,1>^5jRFM(L@3chRM#VPr_LFekC2NZ[Z;31>QrUd%J569fX8O'F)ZXt*AfeW1Xq!aonJS'd/kJPG06H-?K8?" %!*JT6rH7r7q"(gq\S]r]qe5M%\i\)A++LAj5L5r4pl;g_J(EW\]((-bR6h`B*P0>7Eq?8Ge)!f/Pp9)+69D/9&qpQk3TA(/1o,_9 %IKroQ.3%M*=G;K/5hj2;<@2(A-WX[K^A21PpG\Y_.Q!qfjtW!#Kf27g_QeuY<7"4EVB3N^@^-8Wris)_`F'G79E\KW@^-9P:L&"9 %6^[9hQ>gkr<+$U\McFG/F5&mn+KXS_I1qE:BLim4g+lTck.6?X.oSTAE^[!,k-g#;PI#&?[0DIO'$7!_<(67R7< %EN3H'h_"uYeo\__>%h^H=!OQgY.1,ni$0\s>V^0L/82.3WQ'!32r$_sM)$t-S`L2n)SWSHJ==g"Ggkqs&X4s^)$2bYI %P0B,Q:r-=G/6Hk*n'DKsRh-;\etWgW!kL"qpW`[rZ1b?i;KSZPFq]DqIc3U--1T5WW._#p5=;DEi&^ijmX5B03)n)j4g.T %a-nH4IH#fVjeaiq0#m[n\/6F6,7!@e=;`;Sp>q+QrZ%&a+Ta+Ln-ppF7kTN%'&%tZ7'$e/G^4m^7'$fZ,`BZJ1t76JA3\l"QP]F9 %(CbN'$ko-U@V(?,IM%ONB]BZoN.f)SE)QW^3;hVLMS$A;56Kjs:,YD:kP_$;UrSM-BW0*N5mtS994254.HCE9@SJB2i3mTkl"^mb %b'BVrNhNjlHV-OogdOS93-.&58&WO]iLWGegm)-jhL?VZ`:ti-1-XZ(lD<`f)4sBn,3VWUdlha2KNsU?GDaD#K`%Ua5F5"qEX;:k %J`n7aEenh'>)fA_X'i7KfgBf8SY])-aRb4pj+5NcqM96>aKM=CV9[-9Gmfs,$mK9C#!p\Z1O#1s0D5q[)D5)S'Z^"T#s/e%N%1AV9C0?:F,A&Te8maA(0Ro %;gUZ?MZkH@(aq%/%S_7(:gPCl69+a\5qgH?'jm/%oG:Zn7aLIAoG;Y7 %bi@r`"7,*<(c)kpP9]BHnkp"Pn!KWr=C0l-SkLdn'R\^l3c&NL$3hk$'X`V*5ZjeN\\0Xf%SqRSHi%`1cn&26)%eHNO*@X'3kMLG %FI(?N%;<1MrKV`\&S]:<,k.3lUdDDJenM2:>+p_He=F1a17[`+,rPKpY\jtjV$Q1S5;XV1qXDWjIqXR8<4o5mQL1*cf-/4L$Io8NZ986fEpT4dd6DXKX;#%L0m.qG37XLAuNgs%0N3n3>7R#F\eKL&ZEfs62^2JK1'/;^j9qcSPFDOfK$Or6I1q %&*Lfd$NK^Vrkm3=W:3$tkW`737_5M5@3%KEIO\,6>3-XNEn,gp(N'XZfr9nE#7.37U-c?7DoU(MUO;[hd6Z-eCW*]^JhqH9T*8+o-+6TPm_9$S,AnTc&Pp_V[e[ %RDY6LTBNF_P+ii, %CR)"PQb4h]#1eRrb/JTi9'?1''bPQLOuG.;XE_O`>b6ndi,Uj!K!o.-X3[VEEd)C49+MDC&24U6P.RA9j-G!$ %hYU0HN*GR-lq30aA_^20JZ:L[FI@0CGVqO--;H@>3jCS(Jc@$@V\3giRrij@:JsBU_`D-iL:8BIWFV\``.s>A=e"uQQ:(4O*YR_Br.DdkgLGWAK)lCJGYhiL2 %5/@FSG%.Cm,4ep8@OHnGC:H5j'K\$7?&KHZ.sY/Snkk;F(Ea^K1Z1PUs6Q>H:3Be`0X,]r*'%4?uZtB;H95P2K %?!Ctu4K4K[;pnZq<#I*S20=_U9!Y %7'#k"l?e]<`i#q9k&KR[!I\&r=#?Qcs#er`i`^!1ebE\>&p7Je,`PUNS1$hYpgcZHgr2:mh6BW>fZ7iMO.iCa7C:"Y-*SV@8p#pG %cZS3@>?D`u[P&utGuqKY=1!W+#7Qrl78%ktg<<<#5>dp(4B2Sol>7^!>X0ZuklVin[is9,A0eMeErsb'.8>M.RpeYJd/:@-h'lu&F_Lb(2!deedi),>(5<]8f:i.A %Qk9ok2#m)EOp+0)`k75f3])=$)HK63d%LWg;WH3!Z#^\.:*B1^[Jhq1fi=3]HO[C=s.Eu_r>4H0A\A#r7u/G4qVS"'Gb*kQd3nl!=V\ou&,:iuA[pHT\n#EH#t9g#Kr5 %a3?+eao%S`I`7]h5]arK30RlOF&n)Ca"%B'RPTE3)4m$P2.uj/j,u!@4M'Tn8[bqFPE@/P>7POorssVM\0QuHVtEj$",/4'4)LqW %EIH_"F??Th5AFsc&(OG@O5nS)'@KYAT0/-<1Dh('5/,NsalAJSWsd!?1PKN8([MM%KF:)NCT9s %c9EZ]$,6R26q!#1[cDF)&^6'p'p(P<*>!PjG]_'fYZcotVtEh,LKk"S`i%>MVQSGZk>o*Y)'e/oMT.$hVpZ`rHrDe]o=7KeiNg2c %)*\TP'd[!5AR^00$G%!*F??USr&E!3o*dM_'L,>Q*a1..+42<^gaC.Y'gE0GGE)[os/-`Ym.',G_9f)]5tq3diC=C4:?rud0$.N] %,$'F(hCgZFUkQT4qJmO.Ppj$\+MGBQBmO$d(qhh_XP5;)c6K#6Nf %1!=&;+HIds*22!;ET*VOa5O#Y4X,CR3:u]$!luUC+3.0R:H+LTBSPC@^>2Upil<@7<]QOFR3d=;mWfW/VkV.k96+\J'n^oAmp#W- %W!(&"9Ap=Z%/)+p;(#K>_r&ICrpf$eO6iEg-RLDHh.*f#4MgRJi-t7@^_7JJ%el@N@$/BgP<1dTm#Xk^#V#nem-rkjGR,BU:7>=7 %q*-@&_scN_'NXeb.69;tCj9NHqFRgUCbpkWEVEBCfc_.sTOk$ZNus-5(;'s/8DO(IXUWEGh0548c5i,!4kC+"(t]>=5;V`E`/hO8(q!Tl %Zo:U?rS:>"n`+uLHKMh"Wb4Mua2ri&`WbF_;t@tRbun<&X=S\*0@]h[n`Bg%)f %cLDEo&+T:W0"lcNYirin2a#LW?A*=843V@L&!qqDaXbTp7mKD_*N8 %!o/CDaW/lf$EJs6#!.'BlMcc*3DY"`*KcDce3k&G$1pp]e8jPs[T;3Lg/79=?%,ZZAsgA:)LLZ_V%h9phI#ukLYNrO_#"MR`\*gak-sK@`\&"^(:llBF)?oVB46cDH_G=B5"kX/YSQL.jKmeC_GR6NOO&Mm4ChSS %"/"[sEq-%*q=.UiA@n.4)tnGJPOUlVaTZV50SC'lX?$23OV(2RET`JX#DP&_TnNG$HC#WqWG@sPG/%22O4J,ngQ)o[q/5\"KDVUG$RLiT#UJJR^[e\E!$IrG\XWno-ZmM!?R+(ol[&^0] %r&mf$C\]f@j#@lOJiSg3P%=%F7r`,h4hH?[aXOnA^^Oep@PaICg``"(4\h*m`7s@k^\C'A8[%(HD;aTlDo26i*'U-7<&k/gV*CGa-26g6. %""%]T>>@HqiG:3=)f^/P;,VmQ*FHEWO`ij??Y1CBDKf8JhG@*CHS*'@!NF&S1LbErcl9bVI\`6@GuN1X.CdW1((lS#Qj^.KLJ1O"@88IS/nR^ %hrWGXp!Goaks^&1qp^PkWnERaVK31ugE6@BnDUobq5*JR'9fK4p/MLFKY'LCSh7Dm._g0M)m`6Y`KZHW*@:4X*sUA]]fuGb9"$Rt6JcHlFfRr$6E-[*OfK'LR_B*f)JcQr$$u!&ddE!F'_"/`o"i;AT5b%]>@3`>b>Pq3dGX&20>EQI8hQY&J/Em=ci2!A] %$>bRQk3(I5^8#D1-!o$mukM*j;L/U([ %!o'U4:B'_5_QAC\;&Qajj]Fb9UP1e1Y6.3l^`Fa$5'aN0-g-ao9?o3k+@p7t=Yni!3KG"4Iir %a-1$`"ELX)p;@2Y*M)5.;i>Q7QWWi#n>$aNN/o.N_=YGF&*$=.c?kYc&g+2j4tDT<5NW0*gmEA8jt\1bI(>mdHLEYAYP-;egM*Ft %rj'Sjf[tB*_a?&7Z#KdsP1D#eEd7^=oR7AU\_Ir5)rNJ5;FNi':V]EU0.t>RLXs`AUqj-CZ1'S.6!.t$XT#I$25RiFCo&*7\g8< %lnfbG,S5E_=:Z#RdHV4RLhh%YC.Zh;gSATVIGjO_SkC,#D1k]$ZZ:k%GhSH(ES80r`:+fnRKL[oH4K7,C+eaCZKZ]A]V6!+9tH]= %\AuJRJ]ug/7]4jpm/?Ze`[PbPdMiVb(P2gi#Z+t>6*A3?^\oSFANh;b8p'sXYa6nQ2jQ'XfIV\>hG$LuQOtup-^>_S=*EF?-oVNl %I@Bs;YPc4tkd2ELk+cr9J[A$Ts,#*Hm_&aX#&E5>$6iO3i5\SGgOXI"ZhZ7G3_abt!j$ %3n&PrZ`LQKjs+rF=+pN#l"*&AjB1thW>nPiZr(q5HK_uFgQ+T>+"1%uEYO5\O$(ZW\f+2"rQ*H8,fp,T8"TP=GT)XK>RKY`l^bo, %j\k(/bp>C0E[cE7MRZoKT%>@$>RFP*+iMDt0%H<;lN,2*nEl0IQmg.S*3Oj+UWr?.R##c332s6kE"PU0lO'ABUWk)>W+Eu]$!0@> %E[h!jkJ5L-=O/Y5>fsbCMp@^%J0fe\F%OC1jq1+QPPq`lbGF\]2)HR7b,$`QE\@!BSk]SCoWt$j\iXK>3rn$b9$U2rS0'UoDR+W\FfAh]e@nk5?F#,rd"9@Cp'WV %UN7hT1-=A.]PG[/Mac,Q7J:/;q6'P857ib#Jfqj7.kD%E1C+'U@-LN"?a4j][2Ottj*gWKF0$sHfKC_j_K$(\?3j<]jm%:m0>(<`iS@HuNaG1q %cc>2*iEmcp1,]A]GUo&WU(C48KitB;"_!Qb/![$,OEdhD>,a&7s6U:j;(1,g)2*#Upjk5a"2a1KZ7-.>fdC>,rO5&]japf\]k(ek %D,ALfD_G=.hYrcK*?p+'YpdDSCCMP%bUW\Q[g(!BVAe6ej>Sj.A/:DYAJ+Rc/?p9SW`2*JA:3&#u`WI;%m7jRfIN6Or^WR.]`Hl?2P.gnV:8DS-Cd4=u^a[f_I %[Qjhq,#+C(RRF8i1cr_oZ'?6o^dn,?Z77`AqU*!3iRe!WIBe:#0*YLhe3q&dcs?`4Gm4)C?nXf)h-QJWIZr)melB&mCQQ>,gh92: %lu(hDOgUR`IU]jt7l!p#I=Cnm^h?o%lG!&qlZhgPr28]CgDh\`Y:d?]98XXZTKC\2W_HM,aj897:Oaf$h^'g>=%n+cXneCEPp5pg %@)cq.3\PZ+Be!$uGF2M/9DsL$("W?sQ.@@j^P&UN>'R3crmIlQSlkq;32s4sV?HUZVKT)06A9[]92TA+r;@qo\WQs&#h8<8>egMA %J'%%'&]8Ynp6Y,/=:=(afHcJO>n0'Q7e?+%I$fu2#CH9?_DjZXM=gr[ras.o;.+`PbgmEpnkA0-MJb"S6:cpH+h*co[IsIrf;-E: %[prWNKW#j^7cnRu@^HDeX#qrf?g*j=,!W_b]@>UP1mDa"/nqI<%r[4F6BaGl5QYDFKU/(jA&k.+IOS@7JY?nOAR#&.\Ac4L)BU %O@B4Aq$[-+rR=h!bQCLO&^'.J=Q-B1f6Npo$AW;#h&O]TgaCe1;17j!m^96)T(%KtErZ%_H&.@'Y8jR*?H22ikH[5RF8$&B$@h1? %2&[`hL.ilZH%(h^At'^>WTSWOWQY_=n_U@\$Wr6E0NJj*!XH#n:r1b51s$eVT13VPr0mJ/3#ejh=[u88a7/bC5,rSp!W$U2^Yb#X %:e,u'+3Ijc+pjQ#h.H%XM\[iE\H;abU0q\?"9ltIJ(R@`_g"QK7790g&`^Ql)K"Nk%I>N4le_,=]G6\4j;f3"NLgq0l*T\ON&OE< %$>\c8=uk1U>,.a&cE&#Bf]fd%AZR((SMn->"_LgAa;^]$j--%d)"39O&Pe;Z^S!C"O\QjUnIB30$Q-)<]Z&m.dtVAF'omB>(Y:pL %igjP6Pa6Trj^ujX=jh"I)($3\m=PcXFY$J.<,@LP]#TK"e']r,]C9sD^e]Dn0?_7!i[5Iai'jHjL0m/e-f80&+J&52&YON5jA&+J %A**6#VUL:1e53!gXs$g9BolS71n$Al&aeV(=l,N-C=9cZ[QON2fH6ecH*p5Nq9El@4HLJr#Sbq_tY'FI#]G''?93%4UQ?4'KV+c,Joa"gr4TB'[cH"T>PTp$Ocgmle"Vp\TYQl\_cFcD`LhI:qch:2')VdBIO>] %MVU2JWE?ZI]Te/ZmGWMjGB'5.p%nMUg]\42_7)_lV_35@7O-@OTZb5u`7N;sq&n46d>m,SSNIiH0nC)%+^I$i:CA+?i!TIdP-_?p %^G^O,/beC,8c\a?'+F?FT:gIMNZ#^i<8VH(T&'D9V!(X4^a9aS&'bB([Bm0QLt6+ln1O)R>:8g=Qd-,o1&o_IPa5%a?2(Ll6#pTp %Gd)D(9Q_"hc(T((;oe4c9']kV"dmgec:X"(#50Zb1](<`?9%.^7IFfjVLFuYL%J[@9i:"4i*?:$V?,!i6c<[eIFZg'SqXh3P"!aZ %D('Cap-:MsCO9`;=E*"^>g4GT*j^WK_uq=hoEg!8M[r>c9?RqaO;-%hE*^D&m6YTY!/8YX&+S!cAI(YN/F_Sb7&\HV55HB %4I*W2Gam4R&)-W:h?_j!5G2)9Sk0d@e79T5LFYEs2-8YJN4[/7jf:QPBGJ:ffL3j`k)pin84Ug3;UUmFVu)!h.-RYD6n^e$\engd %JZ@8XA%g@4Y(^U*o8'4&_3@[8&]n3f;`d6uak`EMJ:lu\a(TqgYG5I4]p3rUH/:r=-!`c.jfo;T-_t+.qVhF>5cm@N.Q.lt![egQ;?qlOQ:@Yj_jE^2"r%SLU$2.b>$k!C2 %hDn^s1!'a\hE.NqUWG#=mi?\:9=4F'*3-IE:7h1ih8qE;$3BT9-A(+2U/QIrQ0'I>HNuWi^@*PjHRCj!Q0c0lOH&M]4#j3nECB9O %5;N90n'WjD]lu_#[G?',%,k$SpC?&F*]1APmiD:Hg`qZ77?SbdZoji:7h1icWH2$d48taePhG2?&JC%Y/bq5N,\6VijjYe %.XTRj424F@&BT'a>0p3GHY`KRkMHoQpWf@$jW6:"6XTM(@P@r-N8]!'iK/a?n15!\Eu"2e;7q+37jNBK'\.?`g"nf\EbgVUoY/OD %H1)AuJ^LR]42f2gReP+QH++ST3Sli]h,0oj@>OL2c15(rn_T[j3N!@6;3(A\Z>=@O*Sl):NG=a@mI&N7[pSU%QE+fU?X*dtT7b5Z %K5h%jl7M%WiWZij;,`?!>GS`Moa7(s1q#u#cN@:P!J]:DMB6e@/2EW %@G=I(K^kTK5TrBoPQS@b%S%ZF^T!2ZE4Hp)[#%c+i(6I!/?#!C\SAl570\brpXo(#\ZrpJSdp4+BMPAE#8LSQKdV! %@CGc"5t`H/_R:\`&8]*-GJGC=C7?Z+fsaZp"h!`;FL/ck.6N:R9fNXaVJN!uhC,>iQ(m+qX,^H7[P]KRFdZ\!+lJ4,aLnuYeFn4V %BthuG3sTre.Br1t`gWU9IY);8I:LYqDESaDom)*en.5=7sj2@LKB>e'g:GI4]N.h*N4OE7IqkdrV^4O%@,4f^spA %ZYU!ae#uu/nYD/CD@V$>KG$E5\qCLe(NG4ENj:nKo)X+%aM?gfJZPtdBj5k %[LGGS6F@0"KF$.=19bV.fi^=l@^']?M[@ra,c)]S"MU(3+b>QVh21)rb\C?jhM"e.6;f:.cF\:B66j7aSOj[7AE/#]>83C:;]:e0 %AgZnu8#o$d[s>W*;72:Dr:nprY3/8'l8$8kWt:'B(AXs%?,)`VgsaC:[W\.BXnkA+/YuoWj$TSjYe#Br8l7I/Q_,Q9Y\A#,&:.Cj %'h\0q(G1N&d-&IOYB_l'o^t%YD1#/=RTG,M\3Ldr`2!Wa/>M2sC&L`JWCqARoc5RfPXB[U;H2mdNrneLRmkVQcl$\WI&l@6t$_:lqYYP^N %V=D&1\22%G8f"p=ama?T'NOe\c@8Bf-taHZlZrXqs %.!U:`Xb6iHq1OD;i.;?hmh[,l44Jg%-R2X0a:mE0VnE4r-h:I\EpSP@#*f<(P'[EPJoNi %QQ6pq6.NJpA-[#=c.KPm^deq#(I>Rt^qbtqR3GG<@,Z]dM[Wj6i08l"OFYLa[-q\2cBu-.[!uHgf.c3(fn!q=W3`XA,[<7VhF26c %G$n\_k)tDWZAAZF\1]0>%Uon6Qu?No\Eq#H%d`lp)qgnpm%EYgDIeM`Y_*tPU.0=)"$=l7&iR$_*S=4g.Ce_0-)eo$AI"Z-Q?Q:b %/itbkj&(1JES5o?(>cTBgKJt"7dd<7DWLe%h54]?Z3*fQB=3[PXi'#FZFE&lES5o?(3W'%a(82U3/-@tXes[pdA#LNbH?F4]9lZ( %^F/3`?G$#]%2lZ7efKY1iO_9h]lXJ0/tB@qo%Lf>arEENaC")*7`F1]Z/9?b[a3mCr'8g-6*4D[N'=GfVK1I[0A"_0C;&HdJPtDoP6;CfF+78&]@$g"N&D+MJIX5>D+e<]H %D8(cb%&@+$h7(uh]mEi[n`c'pXj)pq:>gutoFf@/MnH=-P_)MVLfYem>3^%BMs_O&'D)p*]cK?^MR,*XRr@`0YFi\@*ah_#!>5f* %h]I/Gj);;bT0-Z?Q-n7p*..A_)"qCHiCP*Fg$ac.kVk)db-S`GWMat'HCa^-2-s*ffD94Y\\%W;)-V/`o5,V]qM46fA3GM\b,jmc %Zq118XBL,DM)J/pbk+g!oj5s//>8EWLX?M#e_4V,$%e%Cl_qKC>[f%;CUXQqkQ)L7sFRr#]q8IZpPb()P %B=R2=Y(s/P\sV88@,I&EmU'0k%shi'amGoUGcm4$#m%ZtG]I$L\AV4nr^lBmir%O/=Z=]T4dl3?YZf6-5MrCqRGnDJ6\(PQOQEa84fkaXY %#K,-Y8SsBF53Mf=Xn&pOH%H^BJ_#q)SD!E*E`PB5cj(S%dI">SQM]5)60/3X):DNe[@#%2)S:jum7K0?/bb>rk%\j(Ci?$AIV=?A %[K`eW+.:,Qqs!A/VQmm;`;AKiONVK!raEP*^g$u>Vdg2=]Y;i==P99*jJ2MacW!!%qs3dC*1W`A3-Timrol(62]DoPZW*tkH9l`Q %E;+2+-SPBukhQ(`^.db"/09=9HjT'9YK=b3k:sU@Ksb$&1-$:@Dt5rO\\-ZeJ)$Us3-us6r; %K^Iu`XB!V=SPf&&V1RTi6F@.lWDKM?,AS#l9dG3`gi_D/e1+>%TD5c#8Z=,T[0l/8%dI&q\HkO+nMY(5jj.3rMI#dpZ_/RR-NY %_)#H?9M%cr1D9W^KoM6\AL)B3YMW*DK=0=E!$_NpQJ@]-IRXD*-VmYR9J:EBgV.Ik/DP,g]Q`Sq[EuV#IXO[@m)1W;U$K"1EBe1)&tB%H-d?@#+V>Io5Kj)P;b.T1CndI@W`L/R:djqZ?Z!9SU"V3=LYf8!htVL5Mj8`@R7asdWFm^A`2pk)%.\V`T-;JhQ;$' %90-c?12"pW(+i^bB^lh!?A]`m7FEhgnb'7%;1&PC(S4840>7M9bOU^N(12VW'KP/'+MC*g(8A#Y]D1ZL(LI4-V8R:u0snU'kJ\Xu %o,JjR..ME[2pFg"(^g3WC&(1O%/%MO/sj#oDqSCl?'(4VjIR-sP@`hl\b?J*58DMRp!,8=$ct'uf$Vg62@AX^D.j\%4>eS)Ue_0m %ldE7kPr^NoRpSRd!j2ED]H8WJ/r\l^!a5[ASqd@(St[E3[(h<*;5:""no#GAF,tcqVS`?SjH[8^!3;8Bma8VBe %1qLSDh]B">6oaqXV&A@,MfA*<9/DKN&F/%dA(jME.4KYaR-(4(9M$\55klFD9$3^-'`e9/UAnVN9Gm\g3[J@^=G_V/;5^5h/R")8 %r^TEWOa#bPUWjNR+T*mOf-_(-7n*HGSIn0W5:ZL?p0iWjs#fM[m)$!cUAl?o;],FnMZ/6=8R_*QC5m(*V$VbR;:0kQcXIglLJFni %&-&E!s-2I)NpV]KU&Pg,+T.:(LgmBp./4l!rJ/n'1gd8`EacO[)#TGPr^1>,b/O,Ep(f0p\WO,Ep8K_N8Q %:T@,K'\k6kg4%g6lgL3oo7YYk'G6JUkSVE<*^:Q!u(:J[pJs7A,g< %^g-hl=e2u&bPZ);"Y)4rF%P?[Fo/j*6\2fE$W6t8.58:Be`f7Bae:1VJ[tUb;DX,/MAp`M0d]pMk#B[ql?`A%XuYtE1OeD4c'&ta %&hX?B?H*D);pK_s9K;J;&;ob$R#$78MTF`<$(Q#l\-7WIriG7RG0\fLVCUSj!VH/a_Jof7!k">s07A6e8c>:bbR3t`egj>jWcD0p %E@6Bs'PLbg&iU;*,)7>i/A0*3][4s]IuS5G81CRBbs^TtEu`SW4B%]b$KDk6iE`hnoW,-A5lOlTlI(AX1K9E,j0H;F%,K%R\Ep@T %1F^R4/j"BL7;(^3C7I:dh@KgoOb*,J3&qXK:4A=WSG`\_t%RdrOp@g[qbWEg7La?;+D&l*cj5NT=h+E"95AU;r,%@d]2nil)-X %+=(O[!i:2-/M9.92l&5R0Imre(ETh/.4Z5'.L;.hqs.6F[:a:oon0f?^bQ"_7&eTNPe(qC9c,l$^2&-=$c&/;7_<&nU:1k0r)aJL_pF/3Bn3851QoYK:NigSR>bTB!>3%B,>3bP<[X_#/)!PG/@l]U'*P4 %Pj+&D44oB5f#cG=_O;ZbFg<:`7?e.F8Se03SY-m^)=59Ql_LJd.YTn8M.%#dM')*&&F6-jiPA:Y11#hYU5Ro<*)=*"Zi%m8-J#W8 %p&L=Z:-)Dt*KLl^l,2%%rH8(=g);(?E1aV4c'?PYcU[_SKcK(8@i:XXb_R95pRN'K$5&K%JF_;.m!dp8adF,DN-p85Vg3Tio5:GiKCRC0-/oq*k)*_OCp(^BjA'\Lo]u %WPLXCag6ff6Y#A>`:ou(Z^h]6$SC!KM']^2`OS+fL"D%@-W!8+TnU8&;/Ic#LGkWu-GkNRmQs:+dL75Of>c]t>eagl_cHc1IGO[: %d4ZFt+"Kgd>4$n(.RVT:a/>l?0@u?=8UgiC;a8V`HX&s/kA`cPkBQhVX+kqe2:I)RaQ#`+rJ0@#fhGm$O1WG"8t>(#jGqNRdEsW9 %npU/o*No7H:K^?*9H*D)[]aGpl:37Jgs4u4*?0:bEV-DUf]25;jDjp_P9";SDRFHS3).0+-'-[,Ki*?/np$'5B1Q0EHd;C,BBD#U %h/aot4:W?URlrBb4DnIAqL$$pnp""$aWZ__r4[u/g2I*7>5A+*4=T?24,Gh43c-ht_;c[NQhWC+*_4b7[)=?$@:XWtI4_3u9f.-C %7LlUEpmp3^H5h;L5$:[8hq`%RPbAV:LYqul&tf.:qChd947#t/Pk`0p-]972UDbIsiY)E>*)r*G*g]AGOj"P+#',M]/5E6b.PTu('O5o&fODH="dS-'k%4+K45m83n %%7N-hEoG(;SbFh9EZG"e1WpGISn]$iS97Rh*e#)C0gC1n$@Wtb.PV1,(riHf2%KLLRMLg7+#hZSkR9R.Zj80&S'&M[K-)K%]h6)$ %_o,AF)9.1K8&$@=m?#M5W2SDmgT0r#%_;)hSk^K%m?#M5W2O^9Cf]".m)%#S*PtC-"i#u7:1lI*!ZrbPm?#M5W5M%a%BY]S8_^P;"+Lf;/=3ngG_b=MbgE@A^h!BqfYT7bP%O(;k#9]@b+.ja/9#6SKn)=M49>Q\Lg^2>fXs3b4#/Mf\5Mi^YfWGYemVp]ef[$us[Lr[P*T\F$*9]6VpSsoQ)]D?#35Q@1QEY6:.JT5*DMT`Vc %%4$\6/Ndn3T:IG4"eql*/j9^S&k1k+P"6:t!qaI#q,+nt-'0O6r=M)Y=.ADBE*;rXM1Q!>"HOaFW\/d"94=,kELL&rU1bgPh4rQC %G45D!CS'&,qM2&#;4Cbh+t@!eVO!dj.fj>OBkj>V4DqA:6W6WTq,;G3Rp)33`gNjMhp`"&98^p@#j[A*@qiGI/LO7V1fY@B?4g9X %IP&R/Wls;L6<[&$9>`=i_)j,uV%I%\g@'G-/.K(fKqB/Q/.Lb6+$oQHhX-HDddVUdA?duHW^i2fd[8b`[C$iIW\/d"bNU6mV!@M0 %[B+X.Y#J^+VA;g+'_Xu8AQ1R'.hVLlTT;2KJf/p>948jc"0nMad/&BT6g86SVsAY;6,.df(QJ8WHJ\%%.4SDl/l+^4K/?6'JHr;r %pPh=4Qe'LR*0G>*pamJ:\k$/(bPBDZM_8'q$hl1)"*Gj^ZV6u(F.dEhI[96/@LgnIfZusb]30]Vk-]DG.\f&:Fb+%J157HXJ %R.;O`?&K\WZDRjnDZ$IZ-iP)5FS2C=EcC)!=]@Yh,UY[okrQkRirngChBXKJ`W[OUF(URK^H;YmTJ/G?kO3DSd5 %k"]q@P-KJLYIt!h\p8>Z54R-1mcRa;G;FWfkfAt`)P\&Yhcp$cp!Jn:IK^bp%J1loYTioM++4H\)E>Qn\Ql+I=fBh)%3Ci1PJVJ %@9?'=ls0OL'@MQ59r8'I%#=BK)`'ZAK@(V!IQbnlj>XJgJ])oN[H/*]0Bs.k.),*LC4:@IpC\S!TW)'KP#&PO!lP=mhLd[5*XB^* %^jE<-?nl&:Z[!(NSp=jY(`t!b"t`05:>@/+`M]8KrSpZ6q>u$2S+.,oHP;&"fJ>#0EecN5sEc,Z=Zk %gpn%XK1).n6J"Zq$kfNZU/IH?`T.s1rN@Nl(9.>Z;orE+b>M#H3T3_JHTUZljV=,9A_hG:YlCAEQI4a!f1\7 %&i#tDo&6n7a5hiT'K^q8RQuI1"jS!]4kiR%A!saRUr5Vp13T+Z[Ue+pnbFTjFEC`_CB84G=)dE73?u*-=Fk/@19?eY`fI(98'hu6 %rDV6F$\,abBmB8-XXk]_HnnqTZs%'$0+P,nBpmuTOYr]7,mtRbf6iPp!/t&J5b.E4`*jsg0gTTB=?Pb:WD'!8^nLI %7b0?TK0%EeK44-:,O4b1hGY%EIRG2?ZFlrA`fI(97qbWj05R`5)Ac=jC+^q^;f=>HaF1J9NSL/,gU&b*"LHXq`fI(97o51@N?=Q' %ZTtB/gge4@O/Trd^*H`n9KenN*,YV0K5[p6%[Y%[F7`EmKQDEdF(\fQ"9$g@RZc]g(N?+P0rE:p.]//'J?WZZS++> %b0GD,L.g'\\R,lJ2+XW9$/Aknc`e&o0'.R4]iPbunkrW6PkQq^@YZ=99#&%+'qhn@JKa48r@E>%7"e4h^QbdFVuA[3I9PJI_.pM: %gsA-lP9M6fI)Zaia&CKlN`I1DX%%PZ8R2c:bgAY?`iuQ=)#@C>djm:\$MUls<$kc,;YZAP<70Z&UpUZ%?""a*1&WZq>I_PH;GSri %M5BRh73Yaf\k"AoM?WdQ\&;2Coes)MBE(#tFI0Uls)6<(mbsrJG48g+llLU*fti"IZ$UFq35BkQZ$VAnD2%V3I>\U3`Jm7W>N?"e %rmP%ejYPer/Zrj%j8N:'/OjVrU!)@ga,UH_TDq?&'O$I-ka>GeqaDmoq?!crK)"n.YH,;l0.'_I"jWj:noqY>HX)FXbV^0aj)V,L %oIe`1m(cC`3IBBRqjZ-AdB'c!@Uq[#V-b-PE;A#=M,[?<2enB]pb9!e$?#[=7-J[]pUEoq&h=ks/-EpfQtRN'B:=slQ"pNlis<:g+V)U`*^Wh)9->Ba#7D;!OEij)_!Sib/i=2t!)Sm#7Nd$UqF:)I\WYjO5[MsrjqriC8uR?F%uk21[AI<*U)eIi28HS+:n(ra %dV*dp%u9sD^uag"oq/Z_qUP<5#h=]a\oomD)!2p_9<2_\T@D5EGoToh%?as(rG\muq+r$/`X&JRc0)l[e^Oe_r2Q!s.;.Nn\cIpZ %Xs#A4dt$)j:?D!-(kFauTfM7[Y,!trYSInpjs)b(*&8@nc'N]ordK@pmPVc*N_LJC?seE.4k4G-Ygi'P=sTWPB!,Wq`"5oU!D.3% %$m#2`d#Zhr#)ENV(gTeejR;84^KH8MYu(:^$O@\?AVe`nh.2u%YnGPs+s]iZPYN3h"-Y/B8n[aTQ\E@0sN-RnOU<+ce"K0GDkn4&oX6fU/916RurL'3a"*[!VP(gf^=L)Viua^raG?c1#9q&XU^Eu(lY1"[3ngL0acCkd)?>#Tch$oJrBiTt="o7Pf>*sWK@>B%#_$ou_Ck1e/RPm%ghY@)E]V3u2X20TgR\*PA@ %X8haud(R,AIJ+*tjVOAd(T1d#hnsl2mj^HimQ1CZ0s*ClruS!&s6i)'fO&@LUIlu)aBmU_l_4MT5cug3qKN0:5d$J9=+TcK#aY-% %llrpL,&4).Df;49]SK`Sq3\%a]MT+o7IrG-&?<1oHL>cAe5BH+^*KJ`&[bT(2cShS,&4).DbLEK'N&'l>.JI1`:AYY4CJi0<0m:. %^1Egj=sc.,m"egpb8VsOPNL\Re%-SJU6`AVX9biB_gr2],=;$Q=IM-X,p8rU+.][*Ft8_fX9q'c'Y>'tB.DL#lfJgWkbc!772u08UjH %Q4!7Rmn+P`>tJRJMqa*TO,Z`LLg$fW%^21g&[cTVC0XLo7:\ee#SD %5)/KaU;hrX0m%&[<']F)U$;2I+ZW>-=DC\MjKNP?'?3O0n[UY>RU:u`0Ks.G5OMo\+O/sgUA>5?hU!9O+ECR9kqKj.Po(&mdP$P5 %^>.:,H7aXHFcbY@?\g\`2+?R6n#%]$XM"b/ld8:T12(jA&ZTbF:t^t/^Q%@dGCqB$??#^0KHlY?L[X;c,GN0=r!^0$O/>UEYpN`(KV@9%DPDVDXgt56oL?8k';l`)Y*(j]EOpsA %3NH&h8gV`q+F!ut`FJ_abc[-SV:NB[SF)d2JU,F9MEhTuEjrj9/#VE6F+(h%g=!]Bc_-3F`r"l]WQ\XLPB_;G;9^.fJjJkQhX.TM %Mo)WBI\BomC1h]>RccakHm4Z5:mFX4[-3k'4rGVJr#Oi:E)G9i,WM.8U %[>r^41;riG>@0-:_Sp(1/DaS*1K\Sr`kOoia4P#@HJI00:"Z;Qju]KVBCaf:8R^m$*GT/^"J6;!EA %:S=%".j`:hnJ.#)hsDMD$4Bp7Gpu>D[ABgd,ZgTdnPYMe@H"P`>q?=o(+^GQI8Zi'E)726>=slIRbCc_D4RjE %o:+HDLC7M1cln&!+uLjlqc*Epi78eZ-X$n+U&2Ls13sj)a/;E*TNk7DF]@C+^5b't5Fd%+OC3)]o1>30`8Y#W85g!_VCQ??"> %/YjqXa*M@u'1;V]0gPd'CjD\GJ#Pj^[*H6Po4)tWY#VDj,TTZXh'8)jb#uH\VtR,Xb5o)Ikik0ImfVg:3hE*gF!o/"j]Q`jo %ET-#b]QY]L0Og5tfmALgMe?/Ko%s&u[&+"Qn&3Per4DTZGjeop8cZ'h/t>-Qb'SohR%qIXH1)G)MKb!1HP`P1`-LguFcc]&!/"IeNmI[A:)dq4V$qOm=KLe5VfurSm7ka4R\ieD^iqX#Iut*qbEaW%b:K;qp+chXepOod]]]] %aMkh`=3J:DfEOI-EQ8?c,8ouYqm@=`7]WJ]fglAGfgqoL,XiH8NT>iA#2F%DNpc,YZ7Cdmk@]e8Aj\'W`Qq#2QJEj]&C/&5UMpnK %a"3;?@!jAU@/>pk!Yl3aTFbN"+qF6^kInfa63pB.%7_QE^F:1WJF>3fi\l90Wj%b_Ytt_pV:ds",#AQL2pP(Ok!pSfVc"F!bq3EW %Y-gBu*E,G-(b#_hcb.25IM@AqO3CASk3$RpZCb_A\+u:;])'(XmB\W.%ftOP]YnYODgNA5\NMO.Ip3E-IYs`\`QCQ(nPo@0gCU:6 %f/n2r.Z(WOcW<;H/Jn*'n%B@p)kg>f?,X(&[;En8D&#[+J' %\CT'*Fi%d6'K,Tk%`@?:pgKn1'u%d/SGG0%HUHC7dBIK]b_TM?)a,oG,dn0>A#rkq,AK+JHAaLlQ$Cq>Ulkjr'iG?(E8AIM[Lois %r&H"-Y\e@P`G-,c9a&0oZ!)jW<+#r;XB#qO]81uS6T)VdXl@(4h8'CdV7acoDq61-1:%iW)e]O*Z^CH1*M0]NhirjDFrPP\_U=#1 %[0fL)^m`KD%VH[$=_\*N)-9oHsp$e)./G`A9Y9GVi5u/JZb"G296!%+d#Yo.PoM((_t2PC`mi>OIg,/Z1*SPFu8j] %Y.I0/3[da+J.M'+[+hq<:qL%!FYbloLi>I!:C,W1XfS32CdYt;md=J2K$N#npn4P@4?ho&.?k0, %DZd,-gggGGhM.gN`t^Qihaf)@:upCAl'l.^\^7l-DGk8G\K0+2Fbjm& %ZG9V'Ir:#u[0&T=Z#_uPq1-)O6K`M_nj*jO[mP2L!T-cjF3^?1E@P(!F$"*Qe.,ZG\]FpN>QMSPB-RfREs3E5l!/9kA?Go9@0FpD %pp^Au"YDOEDEphV_;*0t6tdAq[kiI2hDCb>]O&cG>Vt$1GQIG&4'K4%aX)JsAI$A'+/N*[/itbkUSq(0fn"\pFN.kLZ3(1jn@V<-AI%XE7?rJJ%L<^:N_7)u#6o@QFY*+)cJm^o$'uYLfDu&="C1Yb4'`1G %3s'C_!\W4hYd=+K)-'9aE7of'DY_=@j0Aah44*)O-s`q*"8)@6i3EHu7n!n?S)iiKO38#Lr)uZ*U2ek;CC1Io$+T?d]aG^fm(gDs %P:n7lA;C#W:/0At_.Dtk\!O]B]4B>_GdpG\R/Ur %0kYdWr"%[\[.5k1@TNMHs8!cX\RNWUmJKoXg0(rST:at&[pG!a7GR)V'n2agU0#l:''Vk;D>Pn$ru<9tR:";;M1s7O7j;**X="c^ %UMY6>hjo;L6g&IG6?i"[Qhd5)m[GN/RX3,&.*Rm95N1H2p@DXen4&5Sbt#B*GaCl6f6V;JI/KadS#L"hPK2Je/d#g4p[,??GrWli %a2dbCUT`8/@!CD))ESLKG#`9P0$ZE#Q"W.Y:[j:fga5;P=Ohaf^`2fAg!m-0CJtmkoZ_5/M*t$06at&%,s'R8h;EIL7nCn;Sagb0 %>u>[X\bn7b3=+.MW]WGQ6=2kb7d9i]\Y(hj)Ge&IdeUFPAJLm[P8]a>X+/*3C]i`31m?HcnR.HEH*$,eR:.a5<0-k4<#5IYQ,oN>qpPJ#q;+V!dsF%PBdBf^?G:LKWhbnIgrG"``KjZp>>*<==l-*U44nW9 %Rh1+03`L*D>3)%(b%^HTiU5Fk9B#T\^P-t9NHa=h=7c/>mH&gKPDbWm4o;5N>s[l?@T(cpr]E(?P1c(E\4!Ktk.^Jjr`IXq^ZMQ\ %NK\290c6X-XBAe4?g2].p+sC"EVDZ\8=Q.T>.lpZr+]2#`D'-GlK-j=L7UHL[W'h(e>jDY<^O2\];B-l5)j:+)^U?kImh`Td$dWl %@WeZRc5R/9p!On]@Br+;[RpS]lFUKcqfC$pSM,FXh,LEdN9oiAK&tY?h$SI%q'Ni0hYiq%.VFHYZu<:9P\W %a"V#ad^03?3RB5d0LRY\N35@.]kUnYEjfh(.r3SD?gdp$QA=q2/6[A^oT*oiX7T$U?U)+lXcr/7k2H%RWP-9@Or90KLRq+f*phV4 %k#\[/q3jr5b2(38ZW,W%lJ:R0^9oo6MdBH8.YpihJ%sc@.(;.KqrN1`f:-T0pY;^[Ic=u`X5@%GeJ)meno*(no]/ %dpYD6eXqcRoirk;l4L:EM!QC^34`mKLPS*%._K[4hBBc1Qr)W#G)..3*pd,L_ %PP?"p?$J7nW9t9]oDUBel!`+"S#"**]1Aq0.O>;T[FAub>48sodp4?H<6I&]Rc8,nG2;8s,u!.VUBJq*7$sMt8p=,o7-Io*=Ef$i %fDU_1_Jr!gjsui^MGa\OFEC`_CRApScc-.C6[EXq88^RkJ4N`O["l/[6^I1mWBCr]=mAB8"GVeoQH[:;l1Rs',8-J5X4V>^%V\B3 %g?kYJj(rB[PZLJncrZh$&6tPmm3/XpOOFm+D%CVDLD2Uc2BE>@[E`LTmAs5^hjh'V[cb,( %WMelWg7PUlWY-jXDo@=Zl$QJEG_7[ISh$s;YJLkCZ4ZTl_.CdcAXFdIC;,RWMi/%0n`@aDBOO@Xb)0c9O,g@H"=i[Z.bXS9FCY+[AZJ86`&Hr55+6H*$!CnApH&0egidL3EabbeIs %Gqlb)(IQ@Rmoi3s?gogW@Mjj*hYUdQMmV6Fr5_DUf!YVm#@%D;nr):3.+$%eo8Dn!rjmPYD%5:9=@Je+07(9'f9a38Obd_QfjOc:E#J1XnX&I!:ca6j(,*dTO#2H6,jWf(!)]l7ZiqtqY.Hf$m+S!dD8:YkAY84+*C2uo"g37s%uE@ZY(Eer^TEW3R^bJi.'6*.E=G" %!rhr_dUMb)IoQ%^r"``15:ZL?cb53fs&%0n^k`O+s._bADQ9c-A&@/R<:h9^r5.BAS12YoiI=ghNP:<1p`C7LLXn2"n38E!DgI+o %gB/[C^u@MB!Vd`OrMQRqiI=i!T9[YE#6%+]s!as5p`C7L#:'Xbn38E!%sN7e_>gIt5<*/ii."_u+0(OD_>hq?oH.Qm'-$k1MZ,up %-22[dBfmAWLVk\h];j!d$r/W*G&0/ARh;mr0&89*04IU>f=+/dY?OH!,YrHhn/r6Q[,)gO%#1B++uBpN##Qr?023tXVlhFoQZp2b9]4Y"FXQR*Hu@sXSq %IO2<%/,r@7$_0PK;WMfP/eT]_O'Q-O'SL"9`seJYf&Xp2\EcV*H#;"ei"tIL_Gt^1b"B7JB+cm3k[Y6dl'6[g#j]eaTU$#.bGl14n92AdL:G:k`!p#C2gnr[*7PPD7Zdf.Euf@,DjV3eqmF?6jf::Q=e27Sp]T) %F'u(J@'CtJT*&So!jgaKhDqgBj0@gL>^0=>T*&S?6"*!:9N3)LP\/5c/uihj^9J_8m"e"0.XNq(.#1N:F_"8B&s*-JHN>$d1D'N7,k,,!dj.X7i%f,U3&jmBB;0WC$5]CbKmtS"7XBa-LG$;&]XB\2R,[IE#W2^lIokrmc)T+>*aHeI+SkAJE1JfNk+)&-CH9!f4G6:k*XlHSlVH:j^b/Mh*2HSo; %X&3s?B*Di-3l_?Aa)aX(VkW%orH_R_l(.:L1+=^ioS]9+.k`DS;$CFJWHL;@hfG$HQ0[ie`PRLF''\5_)@Vh"603BTaQU>)7/FOF %_!X5P.*A9C]C%]3m?'gTGMR=2^IY,Y]C%[j>.RC%U!PTd=;.5>2,:"^CSI"OZ^sD1M)EZeX^a(@SQHPr/19N&-,ZH"XN&G,idq^E/uXXP*kN:Ka'Un`&diAcE7J;Z\omk"P?Y-==0af);65iuF %EKI)MA^QsQ@\"2jG-DX4WSbjIMA,?p&F0HUi0_>U%'`Q@L%,:-TpIL#PE+0`(XdZTD7pJG7e1782MU+pEV9B?5<6<=0")GA]jlLl %OXrP/K*3S^d,ps7?\n+MTEo=XSB4=e#:9#GRZ6s?gf6rp]Ng4??6M#_eCscrW2jqf0-M3?f(M-Ua/.7Gu'aX>"[e+X>3p^7 %^:tG5p']b>9?YknmB7WWJf-2'k!;YU"N1_YK\+_nCMD6.n>W_VP(\W7WY?Z==NqCE9n$NGW,,nMIoc41Q]HoX_T'7/4FJ3!`Omin %`0g15s2!>8JS*.-IFZeQ?=1WB+P&OqW;1.k5Zr4q&"`u6SHFK,Kes*HIofYm>.=ql4O$8nF2?qT7/!=j8S+7k_E!GSHt_Ik[/Y[% %#SWf`iJibY>ZANcLj(R`%S.2m6OSC+UM!qi%kZRj#!O=F5.#8FRcPWtI;$OaIpTm[0#O@D9-2,(9Y-s0Zod6' %:[XDb+G'qpHucD4Hl$l.d;@?bFP=?U(k*I@2 %LEB%DAbPUk,lIH5MKcI=(g`)Z+9+Qgr<0KdmJg`^r@e'4+3K%iM'(p)IYrq'(Rk:j`K-eg^)oTm"[B06kR3:4oqFM#%j73j+3.;< %?3%MMr&Ci2=aFJ\nDe29$,M=R_N1JLiWkQ<_2ffe*h!Na7[h.43@l+AN&3of=D0UW)#QAgPl1,P1@X>>LZ+c$MLZcrcA;qLO+Z=F %jo?.6pllD@J;SpUn8HZ_U@@3lBdPTK&a50N(jI7pj(O.'5!-`B+#d9EW;SSSdikmiUY$'onDfR!^iTk]j@H^H0)R]R$RZ]SY,G3c %#!AbM938"(pq'$`1k(scSK8#bVl12ELKoP3U.2L1Eg[E^[o`df+d^>Oe;1P#0%6NMi>$n,%Cr?nb&C?jj2X=[r-Yq?0)R\NX!?:- %\a\X&ZD=i5?H:YF.>$0(+89jjNr?CROn`ppPCkQ(nb@):j%_^c>Z%J+21bPmruT29?/OHY,u7$f_2kAS-$21?b\WO>IdmEZRi,2o %pIb%Ds5T)sif+3=@k=BXOMVuO3/_Q/$PK;R8/5Sn($>EXSQ$be;k_DX1:Z=Yl&.s"6MG&jLY4NJTfKaNninR %$t+J4G`^atNZ-e[;CeiIEF3`@,AK@99c4NX0[2n76ZnU&sXQdF)UKGX^o1cUnK* %DpUfENAi#J+&UuHnL7"_5XYdIYmO'o'SE>,fhDO9)E!rj*]^FQWi>LtOs(7M>JN$:#pQeLidHRaHq %n)cN^,f"C%7ZoNkDV+J/Oq0VM/g.O$`^4rg/e1`@#`PO?.$j1$$oMEMSXQ*AAM76_dE/3/:874uDi-ppH:/C&i\H#`;Qf;UqBK]R %CbPO)o/o9>+3?%nIj>A580FM`j@n+cDe^`^rtH+Z=@m%EMqa*TO,_8rK*k.Debp#Q!f@/MA&X=^#6KG&>gnpCfXnK"Vl4l$)%C`=5W!mOFfM/J]BdUJe/Z<)%YVbV[Y,2uIpLUTdglIIY,a)7JjRaPA %/.GYuRN?]6/.G[B\P,Qa/.K(fjmFNdASJAbr1Z6?4&qW^W>3H8b21XbP?aWW])5:)WNKoPlQNs-^]-@9$/Am<%#>JpZCo#dS68'6 %RKr9C15%q3e:&15DbhLc8c:Q1+3Tr=IMQ1:N^-lr5AO5#/aJr`UHn*.Gog$T?WU;+/* %N\X,MaHHR/Or>'Z9>u@`\_BZ&$uS/,S2oaLK^idAE44g2$$;?YV;[3a"+N2]%Mq!]OQofB)(dT79u@H^pso4)l7fG<@X; %,#a6LeV9[LWtmu&TuuJ&6]1)L#SO(i'[#D*%\BcM1)JPJ/b:pKND?2Zl@jR)7.A'][gh\XD%aH:p*u`I1^Hb['$>hLd3.qCNQZsA %jBNCPEAT9o[I_)82-'`DPn259LaO;lc:[^p"[Q8TEahiV<"K0XIRZXiT\F`Sp:>YNr`nKQj>nuEL>)+erqcG*J8=?YrS`7+ggBFG %_A2FbU>FSHY3*-MH+!F%BZ\Tc]&);Y;-@Ik@Sn8XKb*/%ct/8"rt6N'r!/,kg]Un[U@>-% %$Oj7n^%$mmLn0T,P%l-%'l"k0VHH %F(.J)YY!'-'dZJFJ90AdB@%%_dc4ZQ81$rEXLner>sph"M>%Q``@]pKoTBEdgOeT.@+3!90K,0Xd0'2TITn6h]Q\r[>7i03%a!W6>$:d`tdZMam.3'oCX/3aRWS8r9 %/m;RsH/VY=?BWNO.K=k&<4'31L4r:Zdi.Y.@mZYP2M]e$.BH[&CFqDKb0_k?_kliOs/3/o-&5.(WIKlc;UNnSppY3s'ChjBh+94j %iDOi2^!q##?22!uT)I)DQ5;.gbcha%0'-D(F=5sN9H[U*Yn8+%Gf-@UF'j5pJ#qnt?ZT6HI[3RTi=2-b>M)2M.,2&#F^EpL$/"2o %/T^GrOEffmE%0WgP58=+(XDA\JOln#OlU7iV[2G)rWo(;X%hu-m]sXccSF$:I[57b %B]2jGmpbG633Uj'WLJ!DorCna^(oMUo*`QTiV!'C\i?X)hj'BYQTO0^/pN:Cmru$K9j+I$&c5k8h(J348+1ZHaI7DlYL`],=tC`P %>Yt[!+=n'lD6fqs"*/G^B@ %juOi&P_rXf_!IPp;(AT@&G,^':Z6Y?<\s0U!-P?nb+lFe*`WB#B'q+C2>#Dmh9A13IgJt--@\_9-l#b(T\<B*B)"7V\nu*S89B+1Q@7hEkT!$oH)^u!p?i(%=$V't01i,;3n/&ea)t@rY8(=,'dnX'Tt+r1 %0/MusA?rCa^H?2Eg\K5kYD+!%^kF#A]'b$A2pogHG+5V9C>GMW2:)Ar86Hq,V=&IiJKu5H?dX?Wb^Y>]LX)g38lBEN:#P[c_HZVE %870Tng]Fc%L9Kd!jOQig9,?S_?^aWs%+4+1!m"\chBQfChW(P<*CR`jB5rh9:'Fo'!YZj;'PRJ>t0(pjS$JS4#8a.YqPH=`N?3^.];konisB:[n*V/)NFAhSgp %3dW=B1b/^5De&NQ0c"jqQVr(X:V-$a_sB3%t]h@>n-P_:J8h@<:1IqFn=9#fWEO,ihMA`E)r`M!FRJnVf&g;COaLUTo< %H*9!nG-6:NMRR)ejdtF/@r"e@?j[AB?H.m@YiRchp8*o=>co+>pLTKSgcNR!jN;>QC[:fnY6cV.+3O]j"[c?.X>,CI2(:#p1?Tb% %Iurm(H!%MicnA*hXli2`\k;[?Tn4K*]1QB$Wmam]U6#7m>5G(#"hS$25Qj5pDAYrT0J[Q2f7\$h)+XC+qflO+X,HBCB),T%`]En: %G!;u0k1\d_hab*_qfq=mIBOes<&>Ll+"iKmN[e/*IBRd=hqWR^h0)8eiu`]W5JeVWe9P.9jI8A?'-GR$.,r71qdZuqikB&?J6=V2 %;eTtTSX4=40pn9C6>-/j,FI])/9H,G.#NkAb-95*Y[A[]uOC%BV>e\9JN%#\1Dac\jS@%M4lcP1=:eYkjV07`Dp;$d;eO_UGE\17)rl4K@M`?M2obG8*]Va %_CT4E(NWaCCl]dLM2obGVl12%FBgj3\ic*KFBfSBfXlrMU>rQ+!Cnl-M2obGV[2SJKQhE\Sk@o5j0I%JbX`um*LGD5)+621DbLp- %W%B6^kdW0c8;fnmd;`=Q9TPoe-q(j;#J6`cTb%VJ3]o,B*XWM+h<:qd?U)=mW&O8Z2WY?jL?pE1^h8lfg %H&rR\>Ql#[U'E&G%u3ISp+jI`+or#_pupqRaFHS[lHLFV?4[epTF>g$K?Wj8CU.7R'I&'\E-;r766QE:dkFoX!=BE(6D-9C$n+LD %$%YY^ih6o>-Fj7F+ThNK5WFu.Ka;e4S.kt.:l#)a!]VG0r%tt9/cdXVbTb)dXP#E`dKgGp(&=.bW%>>'1+[!DWO\c^bgfPKgPg:f)1F;KbCOaJ>sbZTnM_FoNaup"eF66/b^^lD5]YWo8g.1XT)T* %Yp]r*>b@\`M\(RTY"uoM96Q"%Y#!C^S#&pu_rZALf4R+UpgDS5,NnA9`8JFP-ku;H2uZ_J$+_`U'M;2oAB"ihrG!48>%21:/0-K7 %A\a!iKnXI#-FNc(p'g2^e5jpcs.P6giC5R[=\%r>MN2T"Q1o7"6;f:F%HFKn^ZqRjXg3eJ`OH.U764<^PENYM38I+!;mW-pp(G(: %kj)].Pm+0fIuj7t,J.R8)e`D$_@]@3"Xi@TXg4oHTYfc-c#g`eH`1F25PE^VYM.!+4IbQ[;bRT\8GaWlkmBZi.[@U/;.ebchtLF %WIuY/irSK``"f;miWAH``"a]7QiK2Pmi=8q8>u:.hB.XVY[d1ZRHms3JDJb.UPNN,mm:XD"FBOpWJh.f@up[_I"5M$pC3n/TTVkQZf(AR[^Ek>c45fd+B@?)$`*eCm[OoDcPf$p#c2?efK&(bYa&CJY7jNBKE$DD=da@qI(\$;? %%#Da8BNF^F.=k1FHO'0IWI[aqH\\b^\3MC@pC:9/1'AL7lkt5+Eh:.6+)]KrZlWCkq>g?u6dNAPPW:Qu#tN$m?VrKja)SB(=.rc:IU;/R)6=q$pJMQ#oaV %D-BBY\j)ZWkYWe+]a:K3;Y//lX4a+C$(lM"-LW1%]ahs"DeShs<(F.a3C**X,YfCR@<+E-kbAaMYHGMIW0\:Ila#dN8.KXh_c#\T9NsF2=gCZ._+c&Xu4Nk00.K-hH(hY<#+0_"PokS9C?NLk]K"21U\QO"s'$O&mapf?H'UTgYb0@W^ %q1WEPX.?@5A^jGegZkq^^kE/#k:!Cdd0030>H_hM>uWVY-fKIsJpu+f5J#Ol_\*U.Kmr?!$XQNaql?;bC@`1Jf(]X9!UH(>.#0aS %f.^m1%pqESO,NR_]"6_N/O-tWG1"IIVY9.U>9@4uX;GXKKBA53-\!+4g)Bfp<0A<+6H+=cY*NRB$u=+sS*MS#,;9>M3\Z)7<_FUb %3oRD+fL4D.0T:&8YQ[Pmc?$IH*Z% %$E=#Umikf5OD5uHNla!H"I+d(0.'StE:GQ6@b[CZLr`c=*LtKtn*lZJ<%46A0ESV=COa*SG=>rnS^F+T-&H3B@:`lpgZ5WobgeJI %V5*`i4pjs4&an%D;8c&MJ*j%1Sl3F@/8>[)$,C0)fU?WEObQpq:h"@WR`R5FQ5@(WA/jbmL$bYWD %5T;72eu!Jg_-L/%RTG+jG6$Y88]QJH`BGJGTn)nT")M/eO1p?k!)RUo((L+?B.[fTPi/b;F&.M'?N*6[3sk*aE-/E7P^).LR+fJM %(7=B(\ANIMhSolgp/j9#ZFk,tF$D[D/5Z@FD@Y5]p3XdIRmb3'#%%*/`UD0a!dH=h<;[5k.q#8/Mpj.$V(s8q2M+sQ.2>;5-O]Eb %"Vd5o/ASH,i#^o)$h/3@d!+Fq$h/3@b^,5//ATRH5jukJF$!HokB8gd5Z)%9m4`PaX;uP:F$!o1X6@)7daSc>OZUmi!p=_tnj*jO %[mQ;hi):7M[mT`73-DM0k+(b@n[SmYbjCMWGBCh-cg?gkG48GP8J^7I$4p-JArm2k\H37&SSN+uQR`((oXJs(rH8]rB6X<(OO-ak %g55K%qQA_tq%B^rY8^$]BLVtS!$lLk06!5[VpoY+LFJpDln-%-NBdkO@9 %(2GuFWb'MFXqcr>%WjnmH''R^Ho,6I\ElKH_:qTqLs$8b"dJck4;'8.0X-2cl/H^9!E6UuO";9;*>nRUP_EdUG$n^u<8tc7fn"\p %F/N*da:@l7KfrNE\87b7P':Gl3j8]-&dc)7^qbu)$67`m%d`-L(JuD=e:AX(WZ`@K*>mE0s-NpoG+bf2r*?cdaVHWPq?UMVHXt8Z_?eN[S.UTW&)T]Fo2:JXq*UQ%I0h1pt-Lab@pp3EjooHeHr^Ftp2/IS\7I]ls#E)A7"- %X;qkuUN_.;HKbj.>rZ]mjL'D[PW#$gHNLei6^[;G=J3+AQ*C4ba2A8hm2`tF-l6`p.k>1V:G3nQMdhYFj+Oc %/hQl#?I(Rsa8$M,ae)QB]:7c2c'q$-7ZGX4_Y.H3:\[d(\$D8k)7Dh+h74bXEPU*beOZ+D50]W0Y'%5PoXpKB8`AXU\+qB10T_#G %bYZ9PGON[=52G``ke<&F:>gutoFf@/MnH=-P_*(fLtUuRBtcM[P*N@HHf^UAF`COd(4ArLFIC]5dFoWMc9k-jM&@2Sd#Po``U']o]ER8c??[pQ %Y%tUiNUlVf'<7s;J&9mAP^X@>d$j<@mV0Xdb9t#;3Je6KJ=NZ(I#"u"$1&,iibOFc9@U$-2?.0*FP8[U6Jf=^+V(B=575^iq#+*: %r^`R>&ieA\iGQoLoPC'uuNm+ubtq-`O_7o1ShqD]cKQkNg7FYD:Y3rr2^WooE[)M.1)/ %f+1embps'oEN-$Nb'P#@A2`1CAr1n\gFF*KAIY3jDdBd1G"ie7ACNMPq]!%&B^`00IPf7"7nj,/*lHIXl[=\!&"2@eHMQa@WJW7gpG7HVC;E[Mh_^$V,#ZZ0U$MfZ7t`WN/=jh/]5HL1S%W9t%Z0T\H^FeDGL3aJ"Cb %o[YHem/0J&!N[n6.l$g`:,Xedbq/,GE[b^\H$Bp%Zm?ZY%%Dsr4OI]P[VIH%fs;^3F#?r*>-/+8!Y(IPk$`ag.o$;MmHpTPF,g[] %YdFpeHHjuWb?-1+Cc3d=K44*=Upe7jb4>Ld7^BV@Cn&c#&rr/bD=6=`f#XRH8lTI8KaTD2*.4CFpkgWQ&g" %ICmp$=3J8nY4bm=-$*+>M^JtBgAI(I]X=B'NaT;AJ$4\&_=o+@gMHi+I+*YW$;OC;*!Z,[_8u^J_.6+Xn/5_?e^B_WJeIVkbSM5C&Jc8G5tMX[5o8mTbo'X[;DV %$IpUOV.($'ibFaNY#Z\p'm*^aCDHK\>Dp%i9Wt:j#/.Z4PpWs`lKQ'>e1/c:"7&[lJb2OJTVthlP(2+f0#G75Y`iBcfT-8W58la2 %6(q#sruQm?+JI>+[AI;JDm)qo@B/,n&.%"RID&Oq9c067RRp*/3[0EC?mk*(1J"F92(`m:fWo+N]NqEB3m6as4k3XbnhUoK8M1KF %!^@n1ehLK'!^@n14=%j\*^WHVB-]a:1bU/+T98&*4]3OgL %^HNk[G2fk8d0G\^2e:X7p5N[3RPt>ZJD1''aWV/tp23[d9al6m5!o %Wun*,`7cA$^EocF>!h+'>n]&%)0PETgQ>oo/H4SV<@WLuFc^[B7fn8MApGk=AXLaoV!E>JM7#LbeJqK:@!a:QZdad%$k*luRR;$V %FC"[&#jn>Mk"nT:X.j?]ogD0ZD,b_WVl2r96X7kZZVl\-*o^oE5mDP/p(1;H8>0rLnLSIHnE,haWP[1,@V?5tdMjj)7!a&pW2PR> %W-"KL2@X=Vgl8iWtWqn$+kkNi@uY@1,o^ffa'kaC"ZZ7nV&;=(6C`B*C"C;2'5P(4*W?k'9$4]b7)8i$;c;72-jos?VG0WJD(,nm8"GeuYDXOu+*C0_o3k&' %s8I9qk!T/7FWh1m7n*G,W^->$(&\AD"_$mbC7EhVP6Jf&W/W[o,Zdt?*u4aPW6FbGbO<,j3;eiK9B1-N7DSr%kWeO=21Ln9>%9(_ %5klFkeGP7t.6dZj.M,iS[fH1F(&jo*ZZk0a#AM%kJlmU/WAsQ4mK?ZSVpKpdObLXOW-Bk4&.+!h;*-29[M/oFUS@d]0.%,,7n*HO %GGR:o+8&453kPN@?rOotop]%*K>^jG]QhK7cX!V+(/W&,XTFQ8`iJ[tVm[]`KF %BTL>8MP7gla5Psa_,P$(5R!HcR7e0[1oj/H@'9Jqf0u,0j*%@j;IH[,ZIWPp$I"Jjh&*a]$@42X.`IqCq-@8BTYT@-B<*]JCS(l3 %@'9LG3U_D#L0hlo"/fNk3BS;UI0aEW5"ro0AOU-Kb6Z.rY7"8gma#Y9C$2Q,G.I`,*-VB-:i#=ldatCZe.5/:X?^]4]on%kXE%Br %E@8Y8"i_\hJk+lU+O.RTl9LhQWl_W\d*CNuNGI!;-CQctNs@.ko8"Z+(>_tO!+!-Vh#m5gg/O\>Qo).UCh.M` %JLSg2i,Q&CPq^#i4"GN>)rn#)7?').`]=8-X6%PcYh8bMSeX^)Wm=%Ij_@+NcnpV03_bL]:bmI'*bL+jXB\]=p^\]8/([BJ'BnC" %3VZteT'G:H>[A51Pm_sVP(uhL<\DV18H:1B8hKX[.F"kAkZPI>1J1&Og;f^6a0mWO.i15kZDNahTkJUo,H6JK[?e[' %N/s0fX*E'5j^mQ53n[-KQ'[aDb[J!L+=erYI2=7_='epF81G;LlK_G5[:a:oon0f?36R7PS!PO/6Cpg,(&V(U4`-/4HFNIW&sefp %?DD,o_TEt:W]).Q\"KR)ei2s*fk_1"bHPg;fibl%,Ee&lr8d)eP-]2t(@1cjmIs.i*WKF.b0#G6atQ_IR&jPj1EllN:+U;k;s@SLs]GtF,S %SQHPr?lp_AV@un&;uan-T52\[U8.Ec81Fn9Yuj&#WY\4E8-!R5.V]rXDD^fs.02;$kZC7^G%-8M''SZhM03j0>p7$Z1T)F/`B"U[ %9DO11(h0&_SLh6!ipViEig@t/^1,1F&Km=?$8tY`'18jbbNk'+m)0J$K\#4o_+kED:1dQa=+,k`7&2D[%]VG=Sm&&3J0Dj?KnZZ=4Pk%8V$]N"`:DYNdX[6a",r^JUs[UFRS[_nGJH+oP5IsXe@$l1Im$j=<9mPb_0W3 %Kq.pKF?B>a;F`Pe!4Y2Rg7J&B1!$L(":8%\Iml/TXG.'*eO$Eg,^*dm#AMl[)I8?&#YCsnC>FHujCZCVr]:0hG,Ksq=P)C6` %S(sJ-,BcJj%au>K7I4&b563?U*D)4(kP`d@\/RR:>_3>8To@qCCnWb5V!Y3$pTM&['s')Dj=,d*eO^KCiQ>mA@ABbrBsZO>KJ0C& %7+'BHU:7LB'7Of:0mD9 %U%tV569-8AW.9Aa1W#ADo1u(=jKL&S-&-X&P=+q;U#?kq!BE":'Ntd.ROa0UT0hT-/:;MP;^o)Wb3sgF^Ea0b7f'iE5H3T\r/2T %+00;P;paOM>;[[.0$C?WEKei;jlhLEO5gtV`?(@9*quJTgW*P!H$nUPF(ESk'5+I;"+Tld24b\-GDZnir/!51/W2-#`_RWt2mHQN %!(l6koR*(2a5bUhj5WleT(sK-ko]Nm6HoH8-]b%[,,Cd\T009T,QggHH(;!j3@oG\;8ookqNJt9ZOk[^Pk-_jXJrSRmBll^4/21D %&p^!oZ9Ait%d3]4`i%UnLeD^^h/**["T7\KqCb_bTBohn^I;2`PKu9m$@*WhrG[R!(@nuph\[Vp4:X0[,2-c0alADWMMT9Mq.r'> %IpUT[gPjBT'ArRqpH>48P).+*qtL3004*-@g9"f0Y<09%pt>_p>uk14mhpB$7gsio#33uNCqtuOG;/FdDp\YOmbg'4%Z-)P+Tjt. %T4cq>nDiYN@;2VKK-)0_9>Q[aeO9b)L_W.7O,FZ:/d4HLCOR(M>RGr8?LnDi2e&=9K'/%"5V<4)Nn2=g`"s5= %>Yte-\J4tOU[OI2=NA\"F"t7S5A6G3-1jTs4hTi3](EMF`\>!bTBR)E+9*GJITlX'rUdSrktcIeMe/*tQ`s'EC@X^5Epq %/d4JBW#Y?]_"_n/q>p&:*;FMq>hf=".JRnWM=kOh$@WuOOO1V57,l7/*(4uMSn'b_u!4`gA3#m?2#+cZ8"O)b7!9@&IisqE2afGi(+,AXj/:T66I[m28 %1<0m`8QoO3*DUk>4L%7kr4&I*N#crL*(nT1+[bH)G%td38kC:WS7JNR`t#XHLZX"95jXSJ+f_IA@u"<__b%H[DsWQ9FJu,=@u"<_ %6Ug*)oEGZ)R4G+JI'm)Spk/dq&3C;\+,AP75d<[/r4!@rG/tCZ$uf2N^lQD+iW>37_2l2GG949`d.hURST&I$!.GoP\-kPS"[Dun %A)-n=a!]2]^N,%Tpi4(:Vi^]D'\He\oT,oe?f&:@hDiV!$cf5#n!4!/Za_t0AqJ*n<$>kD92YXZ'k0-;MX!R/E#fqLcN+5YXT[bPB%lK@^!N[n9:ufP^Tt)3_23)$(j2huJ2=:Yi$:%Scd'Np".OJJbc\lI46j;;Dq<)#f6j4i9 %4o>^c3g#io5-TJtu5K@Bo=W,`4]\+NdmI %r6o%#;,F\lgE%l%,*`19XI^JTS&snlZ2F^WQ'^gje_EUU08Uk],]J-L;cMK,c+d8Fhp_^gO1/-@1::kZ;Z!\<]\.T-nMTcRCAe_o %i:_Ym$>@2R2eUtn!mS"5KV->UXh+G-(:^(^Mk(\Y/SinWeZ-f2C5q+SLLY&B1:;W;)iUW0@qq^f\29KU'MFZB^82g8LARHLpIu8n %K;m*@1eYacXQ-`?C8]NT-PT4kroe$V8RlJeVNs6).YjkZnrffR1i-_?,'1_3C-bHd(/)P'[1nn@)FejV#`5>$>A*$3@+]=dEM=mpj-q?FpT8W]%bg,QirGXj5F[B`N+;s!F"c/7eIlf+4/?NoD?ac\h0^]au*t]MSmcW^P1rd"l(

QWt$?ZII=Uo<[9;-5g5KeFic!71dd*I;XNo79/<^05S.?;t7$ul_#ah.58J&rrP4B#l28oWr(:A\NY %PX(-1V>Z\*84*^L_&kb:qlYLHP8nrd]1X>*s,#q,d#)l6!1Gg311+8KGHD+W>/_:bDJSQ[L^r8('c]7O_Rhf/?YC_urVXmT51Ua# %aG?q[EMO@Uqh@<4lQA)'dRr:1CXJ8dD,n^@j@^C)m*X]nZeGi%U69JQ@BI[`'WP=I0[8RTUq3XpV*+'l/L:B%sVX3-eRbD9`sg>%79-8ZQe; %FGJhXE"^O6NB*-cqnd[r/Kip`j"HYAkcnrM?nq'hVGQA90e\/Id@3Fr37feof=U:`f6IlW!\OCV."OWS:NIc-69f5W#3P+>,Z+^$ %,*bP.=l2l3k2RaNG&pWu,`5m7>IE:Af)E4HeU#>][#)uROZDjZ8q%sEZYUI%8JH,ds*%$Kp3TFB'#ip7%qiHoU,dO;7H %*^%Dd8u&+>\TRm"hW19P;]=a]3"/YHE-]*,OaCSHU3K_RfL3h%&cjjE;7oJun8oMn.uJPO?-Re?\Y=>+l5@U:7.J?:ar85da+_,Y %8t]hUdhal'M?c5N]4ie5ah/H\?PL6l5^SI%08_uO#BrhgL<.Ko#`p5e4L*olXGifE(nkh-r(;>_aZ,eA9uUA1L. %TIX[K72aYSY>1H5*kYM26Vdi9Xc/ghY\M?gCG@\@\>]Dr'm1>ItXGC6BBb.s61o?(ijX: %etB)[l(!C(mPMu#F8F#4*iL@0/Q1CKpKcR.XYAIWR,FQSG-NYE_%lugVk<J4((,mJ[]unp@A,6Ll@/99` %PORh7ZQ$PeEk0T[7B^b/ZWSdgT!r\E!`h'9"\gX+TG^u8m4IP,Z43teIO_Y5Zr$#H.O*g07=hU!qrr]su3Mqd[%CcoFQ6>i_a@1q3V@>Oq$"n/?4WK#heJ3UJE*;d&Lia`F*!i!Lk:-r-KBF<7^$F0:`o %Qi)*^>M-3D=i]WEH%IstZe/L5)MZf#o!5akOHi:^&$.`hErnH:4",.T)=Yj*:347ZO7QUBVq[S$/u2i*H.BH9Fh.91/pd+jC?%Ll %QG35W8;X%@Yfp1')LS8ui/q3On^WhZU#G"m4!`DXX`'9,-=e=sZ!?psq2O8\H1Cf;1r%eJJ"mb4]rM=MF_YIF7-gXH"[_ %\KkgN=\B/6W^us[qYlITSm/"-:JpL2dMo;`hFi02iOs**WKB`P,'gT1M%QnFHLn1trpp7O>'3c=b\eeVYK]?rJ@!W1r;CW5;"Xme>_F^!$Pk0/fcjD@Ug8V>33>8,P#L#4:^SQ;hO#_Da1p!KLpirKq5SnC%\uWZ0?Dc]YP0R%*sddn`spL2,uG-$>L2 %P3]C63>.4i>>:QYjZ38RFGjJS:Nt-=P2<3&9KQG$las.DohuC^PnD$^qE+YolY$0;dncV1O]Zu!4VGB>qhQeo``=^X[LlC?\`Fp'YRhmccD(W[g%]][L6cZX5t7@[d:2ijSrY<5:4*a.!E\4RmQ\s$8-mpLX=4GJMe] %Isf$-4(O66+.X)*OPtrLkc[fb^;dG/p[=RA-Q\*/R^13n9+fjj^MGL9X<#%=c9H%59j\s<1L)NGZjpHs]G)>%(D.f!]U[W=X_uLn %*thoJ-=>-_V9nlZ%USQX0/^$bK"5g4o26RnFZ-nfJM(j\*B3A2.J)B*+F(FE\m/+?lX@Q*?,+/?U)VNC26q`@ %+78j^PhK_M]@gJ-TRTp^m_``77])onhcS0T=e8FH7U,(sm>fUOJiSftNpciE"S9W)Ic*RI5>=*0fP[[L8%],a\A%V):kq9[d9iX"['IQ;"^M\#@jQd>I&+umXka%NFIfB6mT %VO,4tbDZ2oie)WPZ>`*FH(e;]l`gu4F]i+6O0;Ja:b=>*0+rka!?6*sF^$k0AOQh!r1+Es5s?L42jkQq7PL_\;ai[^S>K';5-hC8 %*tdO#G=t4)F2(o8!*o[-C3d^(Pq9>U0ZiE+k*8if474!V^mGM0jgC+ALb5p^nfl%#"(P*Epb3:ZI#sDFnL:K&+XF&JAC>S.NO0u!?!_%h'.7JH5.(oecLWZ]h@@Ao&# %WA7W'p/';BhFaBZe(XW1gA&'uQKpBnhcH\ECL4>RVQ?uAA[9h\>ct?P[IT`'QPW`2c;Af2hr?In8pi8Ce:EuI5".6pgq%;#5n'Xm %?S?:%DBXB;l2(B`p&mQO&)/fKCT7@0G2KhM %I\VV9o1.M`#<@'=%38+WpK+]a`>l&n2W!NN75Y?YGLUJmh_6d.3A_gRXC961hC %NLuKcFZXnaq>i5@S:8k4D^/Q\^']>FAnk;umDHE]N(3*H&%).,i6DGXG[3D0V[(i:/O.#Sq\G%U@Cub;f"1nu8(.(i\H[m1BN3+Rg-[QC8oRU6bYg/_9>#gATli73++L^;A43:HWokNK+USa\F_,,eR?.P:18_rp;Ym@[.?1j-B]XPk5(d111:5W\5o*OFe4K&6M53 %bOPZA/r&T7g+p3^2XuZIH0B?94gqsLW&uS$0+\*< %Pr[)$ShB4kGGPS>$i81T5uL.O]n[mg!uF_Jg_F!AZ-`^g&BrgX8XLcOm`GZ2S8H`8WM8rB0T?=blV$G>ai0gX":n5Pd#ZC0GP*I] %RCc?rg>l7=eD+&.99"rRg5;o>onSLeb$T6;;^S]$b[&ob9,9:?bA6E7`1BApg*bPKLEs$j;?4ni`G0MuAGhHn6*5t^> %8s*Z?)#iW&LuM_,rRGBW?7k;!36EN5*#S7l@%B=7>m,ko1EbNh2)OBbL3Q47+mhP-Rs3%POEUoI41^KpQ!j`a&Q\f5A/)!u/BnTK %B0a+NZ9&-I0@4p*/&SRsZcMt5A=*n&>;Z<\T#af@(`$OnO3*YqpmAqbRoC9F5\oGD@6TKkQpqSmH)DnDcfS9Wle6Unh;qO3&T<#. %=)1OYK5BXQ]Z4r#-2%&1Pn[4kUgMU-j]YJ?Kfb5ZOQASrn,=^C7HG]+B7T,G:Ck%]jHMPX8e%R3,9@s!]1kJZg@Ej!OR<[R[f!NKG2<=_hAPd!LKiC8KDV#=,E/kC^u#qoHM@0Id!$)]I/3YG %QoH\5q==9n^jQk^HM?U8O6;Z/LD&F*`''WH&3tR9B+"d!5Qp?-T.L>NIj.GPr]ruQ_]+%ib[\@bn:2?aH,4#`YQ;"uPLG9LJ/IjTXZs3EV?VpLFgH&2Ii<;:Yo %(OM0mrG=.seQdKINoY])JUTMlKPnGt&mTR;(*_oQo#^WB57UeA76N$8@&IUk%-U&l0(sf;L3?khO$8#n+AKG+47$L2 %XGD/+8O>;q7+`S(kKcO<@LA*FM(j*.(]ci8Ld$Ldr#Y>pJ`oJ&P/d"/`U\2iL*$aj+*p\%%X6h=Qd@4o\bsJr1uZf:PcN5T"L[Re %/`;OLe-O1_@(KELF'mjiF4\#pRrX']1.ZmqaM,&/8L+6:P53akiY=dgS8a&91ouaTs%2!5.fU8`q;Y&BbU.%5I\W&3q9s"W]7*dSLR78aYK'A>[N>H-1FkOl2^NF*bHLVnL=459^;Mc9D+Ce_!>q1jhg+Wt[A.0N$n %r54@,o,o05i?+e0^NqRRqSV;[o+/n5aM+m'3\$^']J4jC-Q"LT_r\;iB.8c,A'Osf2%3gJqLfrY@3\o+(*(PTah^9p$QL5^_$N!O %jk`tK3I4k%_-?7)iOAVVi\65FelhOaT>L]C$+qMnILZV6Pogkr&dL(FUNkj1&E.aI>(m_-4P&(FF.H?ZrsIXeZQGseVtT+cZ#<@p %f3`lSMK&l^QJ%3Y1T7iC$&ni&]@u&>1X*At<#.VNCK5GCi\H[':Q=Ku4X4,5p7Qg5A^Xg7=i;_?;H<_h?Zt^(B)NOIq)M,:r&V^O %^%P+\nHu0W=">7BNR5iEjX3gJk9"c?Zn";Lj:n)5k%`Ds %9BTO2p[D80-4Bi(di%[ndu"O$kp"Ga3??+7*j!!aA%9Fp@O\FG?/()\V\Lk'l^/[OWbd1/TqCPG(m+?&eMg][g$O>inO;L=S5Mr) %kXuGuTZ*Xfr#2p:R_;/Dp@+NC._a^4EMrS`eucNLpl1kBN6$:um$i7\][`Go)*)Uu`VbdBB]M:i-]8dJK_0ljairbFT<-ij7*;q> %CKtc&D`2("qM;#aluf;%b#;[]rO(\L()3peD#FOX7@""];$#7l88.20htI2(XpF46htM`U";/qG^[D?P8eK@8O71WTHZcOfB*&Zn %EJSLqMK>X&m4fY)i\V-bn!*p/#[0p%$q#>LUc\%2&nIB;(]V6-IpG>ndIuJ[YJ8=hJ"+1u21NH[GfbsaRN#r9^DB+Gpc'P,ih6>'!"fZi]JV+)![P.S)V+FCVW=-pWboo#$f)ERW%o15K*I7*S0N,EcFCZlP"R)9T:j&s!r6.77N=01cP %3"=u>>OlU8`>CjYBguN43..tDGZ#h>;:nSs9/BonL:o`N?d'VCEPI)(Z*QlQJ,K?>`Sbe9iL*%)cQJs_;Fh/B5D'4ODpT3Xk9g8o %pEQs:hC,\:G+SsgrCnR2nbXpO]=bb+IiI?21gR,fh[`Q`?%6,oA_/AYNK83-4fe/V[E(C%$Da*G0G-%ROLS>eE2\U4\-_2/%[%)TUn\-?3HK`Zu&OejQk^DV3@j#&Tl6A17 %BbG9$NauV\qY4\VVnO^$>#(#1CE1CECU/$^5(]mUNqa)Na;=d,05"r!e.I%>a4eU[_),BB9G)Q$;WWk3ZdQ@_CkG %0"&XnI&UcnU";$UJlZ!]n,B(P_/C"EZmu %;&H%F'@6d+8n!Mc:I0a-M`=+[-_LQi(NG6@:[8F%7n"R^496I[8lKDtp">"hmY0jqS7g$=oblIniXd-%J.;Tq9*W(;^?6#^kWh4P %`P95,^Om8TkjS^s^mQ_^d1N&=2ZTSie*%b")W_lcMF^-j-_SA'5:-T^iAngd`+`Y9%So?F+qi;^$0]0#A5S-m:Y/9;"X6!0Ej4L7 %*PjeHGnD'gJ.?[]M*lB0!]oh?.oD*4:I#/d/VP?/496JT'buGdnC1Ve,p3nr_c(?=;`94=*M3!`;nWN)FEe-FZR%CeU16(S'=dX\ %O^r3H1D7II^![lSp*QOg"F?G`,?I=!a>:_>,=*X[5r9OAlgm@7(;Gi*_'q/$O %Q',7O6;o@I%3nuUO@l@L%F>bkZrWlk54I@"BU*JA;acsiBcoIqkOV_?@)C7&.U>R6lRf8H0),3-YL#G>b0c&C4Xa:WOutU?6oQ0E %k[D,Tf"Bg9=qpE,s&'rq`Q;aq9DjT^i+O*ulRQZ=kA422g$KO-Go+q6Uhu0\GHm$k.][,/gr`CRqV(>6Q?Z[$i<\E">i50.s52jB %Hsc$^l8Lek_p3_=)d=qsD19I;#-H6lOc-fdK3%+rfGt0o`m:R)r:'Gpcu3?7C;Ta&pukYIR_"k'*;3XaGB(2Hmgt-K\/-!7_`g*9 %/Ru6pY!d!&_C>5VXPkFLfB90($8@uL?"tbb$`>+cl)L8:;E0Buag'oDd]T)Q?8r,G<)Ma'i9]e8m^&">J?qHj1`8"ni6Y4.;`GMp %/W7#Ub$=P]8\g0q62ShVoW4:CJ>3\e`$aL0r#9r_ng<8r'McJC/::mRXMQDg.EP/s%Bo09.H7\Jc3(p*u6as'BCN1k^pFoP\c-ukP`gJd"=H4$Y>Q,j0@8)A"0"MFC[Zt3Mg2pfVB %Z-$,>4)9b]m?re:HI;3#BsN:*dk;XSjBk3b*Zd2eK5N]p:d&C)JX9@.MlWc&)FeVl0>=qC>jE9J4C%OnXHPfiVZ^$r=i<5LA6UrT %s6HHlrO$]Mh(2jXja+n0a5Zh\DE5=8/`!-c^%t#&]Wlf!%$B6k:lF?3U3q1tP8q %fmG#k-KocFl5M<<*45??oeT<(VXRW;b;WVie?j,bW,5g\Y.59CTj`(,$hB9,h2;eIjY+3+8Q0#rbs]<_6mE'[75YkOY=Zj$^Z0#o %nI!K(?QO?cP4#boV=]2pafs))42lr(&B9c/g==u>>eG+TqQ76@:UB8_J$7hi,X&RlbTcTIW8ea@r0PgY=EtRCKgSAa:S6ls,]QSk %GY6'GQsMEuTL[T#q@Hb`H2Y%58*_mOpMR(s(UjuIc'?IA]leGb@44-#hUI"-,.`cBP5]J+lUh3,3rZHHkdUndf(#B_!FJN$!m]*+_5ukpBjF=4c=8Iu %RZ\7S"85bN/fLslP!M00k>/nHq):+[.45./.iIu,Od:O(7>rEF!GRlhpNX7d&E>KXFPkGM*+hegV&9,/+O:+br8IBj$Lf[_]%j %/[thT#5Tt(_h3tmrU>pBS(;$*U3h7LX:D&"gs\=M93Vk-Hgo_)dlQ\2]4r;4;D/88JW81>rFuEU"DHNp[h\;m[*dL.()D8rZTV#+\i]oSFnu[:9!* %&(gf#H%Xqi)$`nDRp'S14ZSeij6>-bH$q_HgHIRCa6Y,"C1VT_BJ7=8MBCu<':i=G8:5'Q+%Zt5-SRln+%]_m%`@eri2R2L4i>F' %;j[l3nIYUXF*5;cORqPRR?8Y"IN7i06<5]nnDiGTElcBLL;G8.*Gh[s-)7oT[,bT(A2`S'Wa$`]m'NKk#*%sSj^t"bZMA!Z`&dVt %V.Jri'6T0^-<$h_ZH4uM6lg%fRpW%1)Jr6X/eLfIJU06bhBi3Q-(%=)XW6s>'f#Ph^Pj1E\Bo5Q=5<(ShhK0KcuJ5f;3jLb6P3]%V35$L:83j1rJ&@'\mJ\p`i@`R2g?sp2Q-hl)?0*FmP9ktZY1?obPa3ZH %Gbn!+B4rpm`f$h[pq26#USoc((ZJ8&1!.g[%G,d)]7h]XSJ+AnPp1[Vgfo)qLJZ>eBPF?BSri]n>tjroOJ9n`@^=%+bRD.S/gbr, %A`bW+F>:`^9hb&XPh!``2_eaM>#H0#%9HA*H!O,;:)t^oA99QZAsB.dV0"HFAsB%4lXFmS'r5t,fu$SF4XQq^a_kQShaLEZe(]cI %H/hT%Ub4"KMT+6i8R5!k.;(hM9Qh)5V8Xig9K+boH*b)Lm#OoMrJKrNZ:uFN?=\15fb+cA+CoULft0@7h^c`T;*YJm,L"XCU(7Lp/@Mc-H6dL>;[blH5_p&*fM)aYlg$FoH%%KAEk-lLB

Y-&.c5 %IC7QqY:lHU3JO6Y2h9Hg`0"*CLlO@uE:c(J#O#6#.d0t$(A-1WO^T5ao)!AJqrePk,3FLX-Fk*3c(W`\tS>FlDMQM/geumHBdQ#"L]_=Dt2>$.9h %1lCQ1%C@rdqJL3DRoRoS$i.gW/Js<;f^*:EHh&RMh5m>sD2\gK#WR%iem^G;VgoE#bk:diS76/gA,=8Q,)8;Na]'Bu-4h(\Ju8[\ %k?e:e!j,-=m*qGe>es?iXI2?Rr^q>U-U`DW`4.n[$P$N;+rYF#+ZIUJRV*toeh9i]4H@T5R>'1FkIED+NhN:H]U0afIO0[&@9@&gi0%4r<[S#2+5^+g8>+'R.&9V\3u*?TA(RW.?J.[>r(VT% %qnp6]f[_\d?Y\%3c=6(t*3;TZS&s1?oQG%`7o=!WNkSUipUOdXf#:D+)WN9l+VM6:1m38ra`]So%R%dCPO4fOK@I.(EF(U8f[spb %Lr'/YSG5.T[ODMAi*3KugnlPDVoOi\(M2a/:XJm!F82\\PH^NP@CB>BKmTiq<;XCf:DhmIff'u[pYaT=-S-hB4=T(73!q#;DN_J> %#JoeQ)BbXFLRB9RBn/>/Qi@L.6e]fLAkDF/&FiJm);HjIFU/=5@fq'K$F`6P)cdd=*eJTO(^dbP6^9%Z?,)u_qlT7"h?&:SP'k'N^eQ:9mIp"E#\]-Ori@8erAt2g^8%j!@9?a'GCU/ %!EZ+e!LH/(h-j6#(Om0:k6(`"L\K2OYZ$OtZds;D02$,iA4H$4:^[1W-jR('/ %$,/hhH2A@/[F_fn"&.R+[gHL@.[VQPVG:eN:E/>$ATUkGb\dZ#:QONMp,8sD^i/0kFTTCnbQK4'KL8+9&Kas.&oBo`822+YL<=[pV`.E %5K%_4/:R0^.*fmF)#8c)9U6c0]-2ZSClE_t"8a7G;]-GZkib\26gTjtGs`dl&$_IMBTGaV6YqlCAuA;&8ocs;;Z%*\%>"9O@f-d% %7KS$Wa[o(^B-b9/!\YjNT94Yqqf5CChc?WMhK!@QrQs0-k:=[$[i)\[8i9&MY"Ijh1sg*8Jlg%(uXL2na!>)/'F9-i!Zs2"*e_L:`0(;1Nd'cL"*d1$:0Ed^uZG)*Ck+J1b**oHK'S=o:/Ip3]m97C@ %KqPB=;d?[<([)[?.5"eYb@5WLE9d3IFnWLC;1/a))ob5DGo^tk_GKOE4dhF27oJV]V2_rTCq5#E@JL1g'K&=2bZa5h*`1mfmJ %%SMTFa^/AdYZNrAlX5kI7$e5m6u>UZR8k`4-'l\b#fn?6\^BP.YB'NHM3d5KgUIO5S:^@to?.'b3ScVU+"(O=rJiBcs+sN$oZ7jZ %i;MP2k%j;\Y4[l]qSLB0\$^?>K^#WiJ04n"n`Bs+])/JJimL-sc4(duY/ujt(&N]\:5s,V=3fuJ"m%EpFt4rR`ZY8nIR.@NTh %VROMLT#8$eS/n/@R/HlY7)>fT)[!cRrKWfq#@KLS=1XA7"]J-s*o3tb[Rg"VbR@&Rh80[g](Pnr&S/CK$!Ho$9&9.l61]g\GB%^PVuL!71ca8omVQ8 %-D?r,@3U9i5_U5I*u'P4#Fd3o!>c&['aAO?lsNOF^FK[\Uf'EGLmJd.41)#2QN%"MZWtQd7o0`gZ!R_]iJBYi$rW9=U)0U$ %V1)a($'u(3B;seQqh(fR5=q:uf/@TlMp[])(SE="R.rP06e_`Vi%'k+SdQ;5>ap-g#N$^_f="q!Vag93-F=n,0c/-'Cst%4SgsT5 %dFdG3q=2\:R@X#&8q&mDD.nue/,:?K\XdLlNsf=#NBc%W1GKTTJ(;iP=j1;uor8?^/"^7M=,DSL.#X`92`M]-&oN^>DNWJM7)BDh %PBes%LW$K]+lNX,S)>/Ceq>!L@gC>iYpS8qET,*N(%$r!CVgONpE1>4pVE8_E#Uk`*`D7L5NBc&]5Xg__TkajL&rsc2W9be0bi>e %:PJpdo9Wh(NVoYi#rcp#>U2[f[`2@$1DIh3Km).[lq\HDXs3?76.k-OUT^%$iNc3Z@2Wt7!u*M %dL-nl0(J%P^bQ.S'27?Y4B\Y9Fq>b6NT47BMqMYJ]BipJ6!#tR6-,rVI1rNL;Y"Rf&A %p-;J$A"^m606/eo=OpY-R9g`oJf*hT,U'!nTJ?/ucXj8r@A""7Q@n(o/8iUoM1NYgh;O5``#a/#B>nf@i!]PT9WMs2-DOl>gW]r3Qb>0<+t,$eddrX4m79C1'Ha]r\iMaFQM$0+T:=cmiU*WOVU- %;AOftMEggm,/(^teNd$kZ\-e]!e![BD'N6LjegPD_/2WQ3GnCC$J&.L&6krI&+g6@M]VT=!;9kBqJC7DTq%GAfP)9[F0>`Vh8(T; %ASGcrlP$Xd%m&G;_a>@.'=>@/<@Gi;8p9_7^XU>C7iTLnbNIFt'YD,h'DZ3\"pZ_''#.W9KAO;tr+.4eHr/VbAY1k&n9Wj>11QZ! %:/2p_AY6Kt'78`?AY3?*8Gm(25E`,6)g7c"6^];5gHsJ:`[PJjE6g,jAY+bt]$?M5bS-kF6e6P&I>GS&;K5EP#gk+YV1PV:IC+kK %A&ad/%ga?I<]B6Sq!+?!n,^Cn!Of*5p],=0TKOV(5!Tr@B"+EUp].n)n!%P+%(c.D^]t-T`aX-_L0FnWc>jj[pq,20bYD:Jgfe.^ %n=bi0EBCU6\2?)\8Uq<_],^6K'&Wl1qVC0&986Y$T%8ik\@"*PW/?.1e(B<4iRX4',Va9(qk]7;(gb_u\@#;Qi<2;ocX\d"!W2Z* %C8oU.[[b&rYH;6dMEM?QfG"!`C@Q$n'bLPW`Y3Opn:B(=>-qh&SnPU>!TDVtit?`tFL_"cB3FP3)agF?beYDjD"3Qb%F^7&g`Z.9h#Pn^+(BVMr0d[8a_XX-)p7Ql;j>"e!'(Wk2#,&/J->"]>W[OJCg'Wiu9 %9Pr2.'"%U41UTR][?IrgA$R"BiTO&n[K"c.!mgP:RmeI#@FUb(jpCDYYa3Y9O2BB^D(U$2B8'M^OLTA"92_i;ZSR;GC5]Ndi1<'U %eFp,4)GAH"=lt4KJA+[\i@ORlZai'iC/#*48O9g9lIcbbf>/G6`mT'<#:WGM$#W6:C[O`s0B(MJn>8-LmVS8j2!Dpe5\OLcDgT&\ %I'+)uOg[F.q<5:V%p,_625@R!m`k,KAKs)"VH2EU>p\]**W&H7)kQ"'RX:g+hB5/u,ko:`e&FCM+4$Ht>ANcH[%5=A:q8OW %bV-QjNkfG?*T@VMglnSSi,Ar3SsA.e3-[;/JuoL]^50lUs1'@EIa#5`[`k*5J")DrPtaa4];N7l!s!qhLVe,9H`mq4OT''EJiK=-]YU.EjQr`WAbkR3+h-m\F%K$^qIT"A!.0(H %$9?h<8M^UbiS95A0;*[-_GbrQhQXbGA5TJ1-.8t8CX8-V4npWl>GV!5D%9L>m@u_L5SXSDKG"18hb[8sC:*m/7Zsu4Zg"?M7Zsu4 %K/`9$7Zs4m,3Nj/%>;%ao<#=KpHlR&p9EMsI:#MD[`\R[\&rl4+SINs5mrbp\27!IS+l$bmH3Ho7;L\I0j+dThu.RTfpO/YGhCnn %A-(N0$.)sPE)^1[`Uo2p;jqQi4t>CbH$'.4(7/gOQJW0:4t>Z0FB)B%Hi'r1dd9X&o'eGHPdKm@Celu[j\!@:Gqeco93:l^G:"Z^ %FQolki?E^O2=V^mn-SiY%hG:pn[+s!`lcbLJNHBrq;@geVm88CFK5Sf0]M^*)Xr[AETME-^H8RJKu:pZbMk9bh6o@;rJ*125G2d? %*LX6?N"00Tn[$DdP;IQ#:qAh^4H:fQ+:u#/UP!2fIBo\ECe(\\ITLHfl+tn[DYu=25GD3-:P81K5Pm#Ai5W3oNFTUTR`p\8?7N10 %G#/3F-X,Kf[5.K,\+X%lprq#R;,i.Lpk3YMpMq1)pDftd]W8L_qlj"/^+6%OSS`r?ipu,5qYpDlDDY8KHXT-$SQmsXBqk`n%^3>=Q:ci[*R;+#=V$K8!-5")CaVU%BR0#Gb?&.e!7bQanhrE#&\2?MiBI9YBC8rfY^ba %.t1t+db3^'.f._eJp.*AgD'fTYo+.J4><)%dd;UV/WJ5CRc-r!@ZTiSQp]KFY>^D9K.3NW`"OB(9sut3\_--ta)W)/iRWK;VW$,; %>;PDg%/k(?F++nZZ1jt][S-8il20U8`\s6(Y4&dV-:>:uQQ/SW!Q,[egB5L=\]'odqH5K&Gh.o3nEE%9q;ma;3npC=FBb`bqfm5l %noMEb03c3V\XSd1X8f"0m3fXt,.6F?'AKi>qFg2fQ?9=]EXD^G],)N@5Cqa`RUkN$389D\0^B[;Qd_FJ4+cV&'!/tXk8l3mb!igP %9<9pTE:h1L?1MU=>ZshT9G_Y=``$/*1L7sj1:=V08a]Te(hU?A=jTKJ\ua`kr'F6:9\9'Q,trI'S*@dAR?I=Yp.UfW]ulf._EGQK %$Y@GJ/st^/@oe8Nl*@o*,SeJ]b@`r^+g"QV]3U:DWDIcsQY*j8-@ncuTe(Y$Msb(q$Y;d%08q\mcrj-pPXW2ai(TImosnYXFJ8.I %[nntfk))eLdKt]'B=]4Z.^`(gcZGjD2Ar)T/^d:LA-5[H^$ %Wb)e^''D6@f)Brb22,*'A%l:[5)`EaU2coRaEGY+)GNZm#n3P1.g\mSa$rTdNrZfadUP(3F/q6P:RtYATc,KlSc7ZA9H#6-V^n(`%G1SJ-Y^, %=^A=V!)I%3LVa2`'_UL]141K,sM>Pfp1^`C.dABO3l^'/\ctAb#&JJP""]R4Zkg6:#"n_;#bDsIeOB?#bCp!5c[*@A9cFJD(j[ecVCX8 %)DAYs*;5QdR@bi[XmXe\[/%5/`Q`D9`V5!u,k:Z:DjH#Ej3?+FZkr+\YPU5?GX!N%n4'N>>l5MdM8O`FqO(;]L7-Z:GTpnbJI'rO %[,nGD%a(S$YEo^u1FA%h_]fNAK7RRcACPOP%)ZGsiJXt`YcXl;kaA,,]H3OWb7!]D-nMX9@%k4S9F[B4?'n=ULufNI[S]K:TXAoa %G&M'Y_/Zo6SfmJ@r)"P)je(;d&*95Ja(/:*cIJkfMG]DMAjuh2T6Z1^'U9i-(HReYW!orDd%NQlqi>qP06ATQ][rRV]J9HKnN1,9 %'+f;<\OE!QXg48f&_TEV-l)F,o1Z5\/cm/Ts#48F"XX45AruG*6I494[>ZK(!co+9)YentdJ!M8998HK1MFbTrrDo-!Kk)_]Q/H! %NdeR:,B`UJ7K<1@rnbLa)Z=AtSegB3@XRn(;6M)a3p(lAOK%XBG6l)kSaDkW>b'HHWTNEf?c1aNI[X$/jg9Bgs]fNDlnGdJRV;"7J3P_MD:M50:V4i %P`'2eTE?An"gENYFWc@V9F/.,OI9mOg$ttZJdfB:FEt$&5mG70lW%4U %61tnIQFF/^kY#LN.ELGV+A(]0A9_Pjd"/VJZTdF;+^/*Aa.->O04ekPA-*Bf$oT!5497d#SGEXpIFANTO?OW>9\`fLT+!fdnSm-<&F!;$OXT"s>%m9uc,]$*_N&G)'U%#ZiZT@%0he!uM!=:ZPf*&RbQfp)aO!df,AVO]p0W2`\ %S'8:?B=>pZkP2Q'ZGlBXK>Ame2]t_&\5UN!A^ES?d3!5]LANgp-pXaen+;)nZ %q1(HV-POdc(]NV.,7)R)4*B[rMC^_K[V-@T17TA7,XiHC>5[!AMCKLhDS>5"$tmVaQXRm+!h>h>"%$W`8MM",#?4Zl&1ESMBY>LO %#A;)le4b#1L9pW?;krZ6^=GGS8IF^4OO3kdql4`N*Y!3)lD#r_(3Fc!eDYrZkUs%tNZQSbm:Lh8NtC$kouk8GF^V+;f%SU"5!3_o %>LRoKh#])2&9!]>4e'gdYsg\XE.&8q_uZ$#8(VGV"/tm-MhCY0]@O20JEXJ`^]=B&'A>V6Vs\odL9Zhi?N90omI?@j=H"MT[a3s0 %6Kac0;kS7gLI;D?Va,UQc)6(.Ju'$5dQYoPJm9D(EXZb4R;9tebtuh$9B@pfH7!>0^0ITAV"[#[%kEe+k@`JS^mBY!=N%3CEdR]/ %TUsi'6n!u5Z.9F6;`m!M^/5Ri;]lAt<*YLndN&`%ZnCgc&`gdShBVcsV@nqgog)Q^bN4E/gSD\0iPYCT].IQ'%q+]h0_dsE %Z>i]O\Z[Ys-E1CA,:'Rb_&'B_+^pJo%)1*@jU$JhBCLVFSQl3]UDSA%d/,!PUDSA%1IVkT5)R/m10%43aYhfh@SWnb3-6c[#hXdH %,aZ-M2dtS[Yt>WT\NG9`9UlkE\NC$sf_H=A?c_TpU,>Fepa)9)i,Ud;$6%ch&mXqg8sn]1'O5.g8r2R!'O7r3p,d70VEL:,ne>>J %]a0g,Sq;kJUGu1mGm^\llp38Gjm2N!5Pd7ZgbmH![H[>o?shd0(7Hd?Y,sl7]^?MjmHGkS+ce+bcI1IU<@d %Q!E.YGL(u+hPrarVgY936#*d_YNW*XXW6UV"m@09<)GF?S/t*Uok?U&Gim6&8pg)0_J6rRDS7unbYXlLZ*B1pjF=W %]d9:,`:")M'3X[t'?q?1'18!UVi0:q,^HkJ_a!BRRra0,UtA6dg7/hE\-kOc7%86apLM+(::0+F^0?Ib:CsrK]#2TS:CqSBYdtB- %ksV"^_R#t'-_4qF_4F742n&dNUj;N2FqF8WeianKI %2n!U)i4'G/C,pUA?o[DWXS&lYT`sfk541gT%l[1%D:)kKl#&Re2sTdRG++'?L5_jcE@8WQ_EIAIa.3K7bNuGH546AA_]*XOl#.+$ %h]CXh4hQ8kGlQ_D?2umKs7Yr>mGWbi](3=cpMUT2h]CXh4hQ8kGlRL,rpA\Cs3SZQLr=N"b$[#qK"Z:H8a)_i8GkPVUXeq@;U3/0 %o"q`]3VZR9;Tl,&`Oo)`H#X)-hQ&^_*r*SQ!R.56+F8%/GR<+*06;H.oKba/qb9S(mn9*q<-["@-ehm01PWXib\u%ieHiN_-BlW%h'YO5CB80A93Pjn513>-RYf\,0aagQPZ+T]<>Xg3mHh6c,Nt`D%GHdrO,7\B'8XskV9R9 %e=R4(mN8*/Fk)&1k*d;s7)-\DAW4Tr'PRbTbU(Q182G?7]>YYO1ddTc=+.8=UgoV\!oM,%BiMC;GNaAr!'R_F1&M+,ck3B2aTeTUh%/`rRW34YU+rYa]P%XlYK:7GEukNIB-VSKfi %k8Wkhs!?YAblk4$h[AWs2Z2+PP%n]40ujb&5c^tcn=6hKMr?6K98^ncCZ/k@!GY8P&on#N?ma?C^F%-XR.Y>KnbWMTr5T\Ce.MO0 %DQU5<]D66i0d9&3MSh5t#q^sVX4g9d9;=_h-P7mhVD'kM#\e\lc\frPdrh=I-WuOM-aBq6aQU%k]/Bm#7XPkagFk8#Y=UdAGYJ\d %&uj:_T0?;6=_cu5-"fV155)Cb\NrnG,1?2Z,tSp=WcT8tkLJ)Gph:BMn't"dl,YG^qF:-c[=YbX:'D8!h@\ff-IXPK)V*4rj$:'i %g?9Lq0=<`$H@TnFIbdfHL7,%2&Jj+\65Pa?5^4mPTDg;G<_BGSBZ^]n-AI./ %,*36'19]/'I,H7W,"#$aW=RXG8AdXpliZ)&u<;4J^]fiYHE+"NE7c[N)iE9$GVF\LFEfbhu\0m&b=YOM`NtnbSC*o.r7ib_V %=B1rg.P:0e:AGu1f9D9H^l)]+)\4L1O9-t2QgT`Oo0!a/LR)b47NkSBJO@mrjHemgP@F;%;^Da7[aBXdV,,Mtrd/6d)RoL`MZPVD;& %I2>pL+6+-7[g2P[kujlO&cGB:-GjY%VZ;.7pD`<<4'PfNGlmhu8Z$JtWaJ(61!,+:0JWWVKJZWW);ZB\`6QE9[O**`>EbG1*>,Nn %.p/*n>qqL9/T+%@H^-0dVTs[j"`NXFG/3s5l62489$YMLt"15p.cC2(5d?!B5K+l5h6fC*8h2*?P %B3BX-RLc5k)f8`e8GAgTbB?1bNh%Rc^%kYus*7LSFe\e].!p:"A.bCdBJjG)PV-HCo?A%5"*&A+MFi@9RKVX$^>;Y0bkls:b'>N> %0jtG[JmaY5$T;3O)0Y;urT6a?qgLPZKNJm8Lg$dY;A>&T=t+`A!T:8=Ypd!/NM#rY-0:5koZbPKhU^m^3?L_Do++/7jj8!=IGP`T %pBU)7B>7V0l/WZCctO=M%Va>$JAF80ioGp@3J2D-d9l$?W-Yap>Mibsfl2`toUK3#hd!iW@4:#DV$%$X1XT[&D&57KY>q3Cpdl.R9!KW^%1E>DTn1,Q] %NXDnQ!n5QO>&&0Wd+6tJ6cS$[<At!]J]B-e2RmUL9KQpc*&@nKHLrW8_611_:<@JC:g9GrR$eSr!^.`4AO"@?Z:(1H@s %7AL/XF24la/Z/hs2Rf,]f?S0q/shHQGh^+9fpFpa`HbIpNo.iKlL@S!Bo2Itg5@9)#He-(4"ri"$*p'd,E0uQd#Vu\@2VT9f$f7h %1HD:kN)BcB`CL5J^P`LpD,CMC*8A@K7J8=]NNh/kMB7DL//,qhC)9?CX0d`7A)6*h.^[q#f32\PW*gj/crruTa=tI:)iX(N$V*ZG %.F$k2YfGDjfAb+ok'MGh\[8g@orhc$mh"%`YOSD1i*A461eZciftSS@(&7QLFae4]U9`29hH0@RdQb*5HmWl?(2M]eGI.8nC('8oU2MFt,jU&$IQRaV=/G*jOK+kqaPdUqhqS %/4q!c096*NKHa<4!04oacrVZ..lc/aqW/PFj(p@,#^J)9".JK;PW9IL9F9blBd9g %WdaXVcXO(+I=LaN[V)?h]7[dnf0('aPI'Iq]'G(!lPP+62#Dh#aj-A6A@r;@@'=,N=sY*/lu';S5:/6n^o:JU.P1U7(EGBd.fJA^C8YB]cS$:WgFeO<=!Jp&X0 %N"N^VP:Bj#G^V?/G@m2$7-T;W$g&h[PV*Bh`M/Hoqm(RrI<;4o1Z8":R1h=nJ?N$oN4"7R-LK,c$b/:;F[ZtY2nJ2C[SI#S[;/W %!d`A\0f@Cub!M"N(J^El,I(b. %VEWclLjSJ5H_\+L'EbCB5j-d%0m&$nafLC`:%^EE95b_pBI,I=Js?=6+>=.[l31),693F7;@NC+5=g@@.,_S0iB[f>42jY3E%.gN %'Gi@=V5OGo>j;.J;(57k_\(A*+lRCfQcbBoLGLq9)cL]8befre,ops7&7);nb1`^2VG#I)\FV)ALDYUDs+RRLPqiJ@0qoTt%>H#C %d)^$?WaWJPL%7$0k4+Kg?$60jC>;E\@R(_UJ1=XR':RZCChF'Eroe9\=dt::i%.RP7Q5RS6\>V9g0?W %LnRO#9UDbt(MC_?VA^dlK_tOh\pOR%WT*)i?j7TUUhDFTNNGFdJbSM/%=2$cNaMN,V8mb=FjD[?E(.B7f@I%HO'cJE2UsKeWotFl %C/_6X;ig[R%DDF_>4CuEAa<6rG2_-cZ:0)+lJ5MnVdGa5[YZV:nG&=()pVgPdAG&mfJBWB/E`Qs-h+/>FBg.R_$3tcp^3QnlNE(l %>$SeYAH!n%`!PZYTV]\K,_!)*9DAkP^'1,g@J(?LFaE$M*cPp/-`lndn8:A``!PbBM.b"*@')ao.Z,-BX"^6NnOdL2r&V3r;,i$n %_lRa'dF[OGK)5$YV^FoY('+[?B9'7pPO53A)fuiYG9jV`P2FgP?AkL`41bZMXhgp6f/,t+PC)\o?GfO?D"(B,TdeYRqIJ95cone"X_jT %9f2J"=u1&9H@'b:[6MI/h*or8Bcm1Xo-=t:s"Du-FQJTUBm/:aUf7gaaSBH4O@SEZDRu/1C(+mWpWK'$hi8i\*CHFkW+5irDETJ` %l9JJ`or-W#MgB.t\XM*pk>e=ic>oIfrVO`rJ'`]pioB.7WGG*\G!Og_U=pgUtRBC]\,Rm]L(c$CN=Ssbqa3'2XSj%!_68/@*e8!T+l_/\tpfI5!n)f%B& %:MVC)E=Tb.k7E>E(s&uAW>EEq,+*il;_N5+/^Wd:XCnAcH6MjKB$d9YYi*X3h3mT9iqlgPQC@ahD*G?D?]0>JM,f&m"^E82\"c(2 %!Ba1j/c\a %g[VkP4]a-R/WGkUIJJ_,-KZCkUU27TVWFfeQg+YO=:!'r()Th/%*)=U7<>THeJ^3+jb %(KbZH[$m`/h/Kd[BXMRhgk%9m,@eZ/##bT5%8's6)Le=FKWBeqX+=)R.[]$P'==4=:3OG'oS]26#0@&YmH&7lASi%MSWi;!BNk%" %RChWK8T.TNBQGbXe7cI$d9AP63WD)WqmZdd,(34`MT&RI]tU;F6?:^A.C1#9&)jtR+XUd;bfN*T2qt-%QoQ%k`u$18_Y@9rEKNUb %Zi)FEY'!9"$_>D:UU>(uN$NJdF+FHOHVLH;]EGVbF##qN"YhG>Akkfm=XRcCqg01BA>#8ZT67EUuI=g&J655=W_?!\c+r#p2:LL*GU]Ud%./p7g3;Og5MSD>p.mC4V`4]?B,`M7e9aubQ./s'2 %;8jptg,%MBAe]B2.`Jl_QXtTW"LAD8-&)n2gTmlj-"+p?PWlqUC]Om^?_>+sR9?5JSl;7d*_%X+Ea$E>0h%0jn^f.%O*O1;VN?d*YfpmGT<^V!hIgcS6_X9#o?\MZ1AOp`Sa8ts"]-Vdek1,U%StI5\"erC %k2gZ"&#(rMm6lEV`/UJ&j_Z12X0k.Th2d'4oL""8L[8nUZgnpf/"/9 %D,bW/.'1IdgI=VUND9aY_R'YEW@06cf+k)(>[L2gd4bV4e/LkDJ$;Sm??oSkXgar5^R %U2M_s,9ctCM8%g)1Z"RJ'HMWI^?K/H?#9:qLqYm%\bsfr8BRYqF8b5#Qt/iU2T8-a9]Nm90Yj?pl,i!Iu84n-2^5# %h\;+?g[Mji1idNh?K&@,m$h[FLN883VYIW>_Z2%P8TFOMeW`CkC;IYRI/&\W^7fUA7egg5IG9=V>CtE#F)tLBS/^if"m=^:E`<%_ %@=7u\21E8>d&u7JC(=im#U08.#;@Y;78L_pTo>\=VQ;)h57JQBN/igM1A4>UnSW?Z^!`(7J&D6+Acg8E"hd,c]CL!5b(B=Z^tJNB %1IE?6!GCTQXA1As#rqgu>eC\grFG=6&'dhpuOfK$_I!,0i$.]/=a!e:u[cA@S0C-Ma@n8qtKcT\LffUXX`#2i.%aXCo+?V%L %StF,I@e6+e>'dIQZJP1G;.*ke9P,_->CW'm$`UoCNZWNV+"=3P"_R'R7?sddHp'Z%$7p!4,;8EoXqt4Jbgp.Hgph#$Afjs8egO%> %`L0n@Gn_)XN0cYX$g>'E+W%uq(UT[\oY?8Pei"Lb=X&3akS+q2j?d84_W6*D(;!`JZIJ(e.ak\JBdXC9Ji,;+C1%E'ben29nSrKg>QYNA)<+?5_Jk7@=.E %cWb_]=2'H,0L_fV@?m>7Jf[#,?.7+`J*6We0OijT]nMr0`a1i6f@uEo+'i_&L0GVUgiP\B\3?hC4q1PE&W?XAnrgRh$%%&N!#R*Y&nXq6E54Ga(UrgBN.CGu*p[qu%"N=a6+XIk0YfZ!(WTK?nUPTp7X#]b %GTV+oXCRY?^c:l3E?7S3@%<=dMCJc`5(aIjLCY5dpF`ChfiruA$C/Y>P[Si1\nZ!0A/QD5L %QD0+DMbi31lS#Y9=NeB].jarqls=o(4gU1gtY[P5t\N#/po!-8%YQ*Fp72+i:XF4AkAln %,Hnqd@O.@Fgl*NQ.U.Ru`V#feYb-W6Ks.6t`m5Rt-?qOS@f.c-TdgR>Jc..t6k0X!aQ5m\(VRuYcXs:=G_VQ3lX/e$&,Uc)qTV6t %-1btb.(\?%^fDj5(V%E? %Zr:*8?AWu0CJJ,V_(5''EMKld15)GU)c'=E,pG_n]FpqMVOf(J]Fsn?kdpsIGdWm_)RYCK<^C[u@:CY[;0=I=mbkcbB%a^]&+3N) %\%LE8Y:s64X6"KhX[6d_5/*>sq`78>H*op)9b9M;V)XS/'@CL'?mJk,F\AsXJ_'gGN0YJ=p"P:O//KnuYO?pUel+GG;*lAd[QE>i2sJVnp6KgWl=LUFSStAJ4m6L4gQTaq[Rb3FGJ$6Lg>2>bMb#eVRpU=1T-r`77/BKL<]DSSS*Rif %iRK1aj3Cl+[0QA9HkSE4Yj+B)T3fI:3GYI5)2jreJ`%E%'osZ:^i#SHWO8r(diJ%/!2gg8,hFfu?3K9SO8\c6>oOPDT/_Zsq=& %dFABG+XB6*%L;cpG[Z;u8Sb`kYU?ZWo`KSs$7sjPA)CXO59!.,n'l]"q5`W*g?'3a"#os*4< %XVWLFf6HQlYW]J$pd']M=Bu&q.6e*+,&I+TWi[X3AW!BVZ$I&%a:q:Ce/!-mUu8>+.%)j`9ueHs/#O(PVKdt4FM3Ko.@q^eG<`WL %$D_]oaV7O5U55$_Sg">$Oi>EV:QZ9gQ\X>-1A/A?Ea5M5Yu\)&Ru_Y?fB^@[>1^"Z8kN04E:kW:D7dn_6^3Q/Fqe]ro=U_1-Hth&T[q$-^(4jMqT@B./[U %1IW>OoT_?fF(e6.,-1kaW'+WX.>%@hF3%7_r:U\g3J=eB&:95V*#^VgM.7TMgkckk6:YD&\.`9\=iWu'\.`9\5u("g\.`sa;B+FL7Njm,[oJbMf0JXgkejLef,7Lj%dOsdoc&D*d>1;R8V.nq?LlP'#pK@9ru4PSH;OpEK3,kL7Ra&jrC!H %;``"0'CjIeQC?0?-R-tC1F!OPSVVDK3lgcC+g'/W6H6MK1$f&+R"TIWGR-JA %qm[?j^q2[e/N`C>lTDo9-r!$I-pWoK.Vl50VIr@ALf9G)? %*00pZ:]5q?A$Qf9r=;>c!ZTt2i7]Mab#4N(oEj[2o5j&ASNsY7MrBn=BeBO_?_(hp6Yt-N6k`T+[igP7VFAuG9Od.,A]'hp++u*,BVIHD(3m=gIg-/QuP+06T]H9qj\8^ %J^GGk8ji$2#I_V5J^GGkM`NB8"/@kaj0rtA&'Usn%#=``5T9[K6bN[H!,`l2lE/n'C0E]koIfrVHrhGO6="Q8fZH\.#Q9 %)pbXXor:bk5CR>'*[V@EZH0`;M%+Jeq-:C-heA\!ES5uLY:rkshA#fc/=o^V[J2m)Nf2WP/(1ls&eXqCDCpo(_+N%`%PRd%b/Q+O1t+gRF/q %r5LhPgo3*L1XKVQVep5"o_fDK**l%^0HAI():@I.75tn>!n@/b]Hegjgn^-,,#EpFZXBIXig18Nm^4F^mJ"`i\Q[s*BnY'g00`lp %(\<]u;;-SrcuRZk985Hm*W)D(ghd0W5?:5`($(knqqQggRe`W>Vi^-bRCiIil&c35^Dl6YO?%oT(2Cus7?m``H4N> %D?tOp15_`lcF9tFi@g`r(B.CdXTr.D4Bl^K_N%\;,C=g^S>&$(h/5r9l$b`W]7ZBh_UQFB]'>/hRW+[$YujWaA_4A! %qJ4'foQiQY=7nraG]m)/O`n(pk416^I\OG`9.r^C,JN[>PIJpsJOeX4F?i,OUlq=sQQC=.7Pp98@hrDSHI]\loNQ^O8/#@->asNf %S`7hK/fSpbnJaWbgsTt#q^,Em&^nk`_$UucK_0kA0jaB]+*1KD3kN-KVL*Qn*Xa:.h@'#5g;eXipO+'U#qe;*,X?Bq$8-EB$O0o" %$6@!rQnZYD.CeoMpW%OR),%*;m]1,M.M!('qLsjXDZGVI!lfEgB1\/B:&k"G3esH'%?P:16?M3YufWpb2_! %C,qCANqQ@7kW0N#*B/EOJZa&_%=t>,lkHhmpY2hfh*nqR_;c30]4f4qIht(ra(J%K@X(m/WX#!O7:&29JUmFE;')9N=u2=qS'M'n`R'Mn%qP#BAOhl]+.R[6!iI"nj`93Cl$4A8TB3pXHgCZN:lFk/sSV8[i/ %)QU-8Ond,b0TmF:cf:igkF"P8k\+N?<$r**N)G'W;1!/?7YfU'rS8I+KknYFp[sI$Vg3VWbHAj9GmBmPf,YD_-!9Sr(`'i)-C[Y! %o4OXW7AJnp,@u[Kp!og;=kQN)s0?nO[2XY=,+WT4L\OLQrJcbC":r"l+;OP\FJq5Plo=#[[ko %Ns3uGY)U]qKkA[Ng_)%,,N)[gj]6F_6[lbrLIUlh>hMtDB?7t,,/:+p(SYKDAiW5.Wr7_)(P54eLGSRr0fVPu^5ruC)<1CEd!#d3 %Dr^DBcoK,5%.X3]MCRZ*4t-["Xg7rO&AKlo"E9+jIA,?\NbN-^h\W#1E6iKXgqM,aK.f&n%eDYI51f.KFVu1ne %?lHJ_^4l!EjUPIkf%(,Z*bId!hn9n7`aS'_VR;1m%*(NY@VSoNc=E#%")s>+@gV4n$f3MC[-R=9l82f9/qQj>cDXqb*Mh%nI<%,H %W&QptE24KJjO.T#2T2km8Yd[oIMW-J`1j\NI7>2.T1"7>L2/m%mD0LZcE%RjYt8+)^Z=c6^!<+*19GP9pODPCpKlmkg,=<]5)91K %#t[[('@M4/!uQb:hDr%WQG<1= %^?-ZM/na!hU!hEa>9g:kS(^d))0k47mVp[)3N6lD-^^C[Mt31^I>$'R8#sc*K"dN/Pk]]FU5q=Y^i_Zpe):NQLNQN&)L0<-bh^8q %[a8_?@,@S[r]L+tjPd=m9hto*nr*LmH[(M/HWpA9=*",'GmhFaMaL>Ta[^HL4%JL5T3*r..71D0iAmKo*)ob24.=`L\:8P$=l+HW %,2i(*A?!]\b%TaED%f7r+7S48/GHG?h>?n?_jZ%0(b\IdNL3i;P1S:tN0j%Gd_iH^a%O3LG)iUPYneb?lXS3AN5*jioG4C5T?ED! %>VC1TJh9fp>Qt*B-t=;3Ck70hJe2(8O8%iaHIJXs5adh!=:^&r#."Ug'Lnc.Tk! %6kRB>Kq=W-=b(k_l_Z.(>.N2_)Cmkp!lb(:\uqZhm;d2o%LWt]:&l&VR?S+KSgXu26Tk^/9V41R=D1L[p@4c,Vi]$.?f`_Inkn@K %a2:'Q9LgA.nCGs)'O"\@f.5)=:\=oOM;i?I/X9C1hF9#E.Qeq?=g/&:VERj[J@5g2I.)D6:^h+YKaLV=7:cMfjdOl+p8"+)^RCU> %YJQ5o=G7"+$b,Ui?POV)5,#tDe+ZJ]iUKt-iTh]9pk7=(r)Z9)TN_:_A]&&H:r_,-`=gWf3JY= %5%-j0c5;u-HK8Ua_L'MZ@HSfDgqq-g`i$S:"HN)<_Af*gBoGj_jc8M7OiF=!$gA*ooTj!Z?]=Nsl$a7XHqNWdmt-Nppd_Qk:SdLe %dp)$pM)@Jb.*3aE:+-CNORs<57`Y^64T"GnXTfq[8M:!7#(e?N]g[/q>m(tTd1U"ReBXGE>KB[Eoe$M>)X@ %3g`9Lh*%+*C:E`[Yph(m[Rd?:p2O_E=1crKi_5,l+/q[g,3a?F;4L9pU#0QlGh(#T,igg9WO3?h9jgieqiY-G9L3G_-FEigbb_]k %P?LHL?ne_E^?-S0/P2h4[3CfGa`h],fM19"h3l-3#tMaD/EY@s+;fWFb_k;C)-.+gn,Ejfqd\QBBuhTXE-\4[.QX %;fJS>4CO^tBh9nX\tMaiMZR[&jUWl?U.9sP9O]jCUPI?^AD1S/.&7VP8efBr&P4Ro>e#lk(@7%0-2U+S[6R#GQg>N?e@OC39'@qs %Y=R(0,)Z=&G[<(siE7^J>=`(#FBbPUP1R,(@^NEK>(#q8!YW@j'Kuo*ZpP]dl#!NEqTh(,Ca+WZGn_pe_(T60kFiu3b1dE()XlkH87HUp%R6=W'S^4T`j$&D;+$N>\flJHEW=nI)f'g)'msaU"lr]knLBm*;p9Ad>KU(KrNE,G> %]"@[[P8up@+KqL_Ir\%4K%,9[qZI!i6Oi.3M@KIaoS%Y3\u!C)qYi2JD1)@GXSpZBK6\X4ln^Fb/m`5a1Y8ZZYN>0ff"QQX+[AUO %AdAG8?eJh!Ln,?Vb970Q(_&.Zhng@prP6Vb_&Jf+n`e$-&'CTUMdUq$`s]^I^JNsS>\n:u`5B=jPjtKOh$l$Mdk]n=@1W4Ga %kk!P#[G/Z#M*]Clltu %POrfVGRSrae^7$2p>_^@dDK9neAnD\6&9)+-\+-\d3LS"$ROmO8-8>40^T?%1JKm.J!!mHoS3#?l %A^^;Z1tUdnBZ5UHp%r.AnKdEZqg.j0C]A..Z,7*.%'/E^Zho1LHI<_7^[0'X>MWT;m,)Z`bP_UOnh[4glLlm>\)R:?4tT',:WrsK %E'I*4Xk0'..m!o%:PELo3k)5^V.Zbb\:+q^.XbCWH!djsV9[R)>&Sm#PNI?VO#ISM>BdbS/9>[r %]2J_G%pZq#B`5X->(^Qn3KfCbl#S=ar+:_d6!TH$K`%d>WDt0;% %ikSK,J=LbBi\qCd+f#21&AS0tp7GKD6dh%kVgbh)KK,,G7/Z3CkdpAJ]D0W,;+Wl/VgT]uH7D@>h`MH?P(e_L4:k#G6]0b@*!pm) %l+\/4@e'([oJnpoIGELk.+@.`$I@F`[4uuto(0Tc'#/^2Nh/5T?2Wi?OVcaY9O\9aTHbh;n;a/_]@'HWP.A3._lT>-F6MIg3@Y,l %O\[ja(7.9XGk85229D;KS!n(d$^Z3VG)\umWA_O6RcK+[ehETO=P12O_AkgT5@=/NXDYa#V(V>-hYp9m$0,o;#MH'0.)0J=AL:+Xq8@%M:A*]So:"m35_B.Wt*R1,&A&%oY2kMfl%GP[$^F":68 %X?^XmZer=N:sd`phU4!a"@\m!ND?UTK?!$A_=tHfDs^hP\f2Uc-g6DBWoY2mXZGfT2DNp9Q08TfbBW+Y4c@k&>tGL?rqVKh>&Z^\9kC!a`M_t7h%f%u:F:LHcMktTcnc4TC7 %G-MU!7%BhDK*QmNU!+DPok\'%_!)m[.jEhcL5ZC9K\S %8$ARd!^/$PPd?m8JN*,gaJ[.'IT(kqj1O*I]IOA_$H-./4W>N36FZrZ3URt1kt;P5AiD6Xjr+;ug%mXfkd<26nBA."]sLbGf2u9W %4HN'5o8a[4JtL`_emb>O[6Cb%N%aU&B$bZ4@]jcFh`*``Y3WQ\bdE218UrMtQJQjt!@?reg94ENXP-.V#/#iHMG[5$+HE/W@(@gofrUreP6A3BmW4rh'o.1_%"Z:K7W* %d9`l[,u*a-P-M3nq^e''88!lS=37tdis%/'S@rd$)6d%QmHgp(]q=]WMh4-Fqb2Uo.=e9ZX,<`M3M#eHKnIZD>PW_."!4A(K&2f2 %p:;0_BESe28!boc5+%LI,A!?dc-7c1>Cu18eBZX+dddU.mCT#*qq?5#:#`LH*<.6s^XZT9?N#!L!bEso0)(e%" %(:l,LN#!L!$i9XM(bIq!QEKZFB=.I'=cguO`+\]"Zg`&K^hE8sZQqQ:BTE3O==n.D7=,_r(6R_;*p*Gshc->`[4$EgNl<3!p*f\e %]E96MZq!Cg6#qEBd@Sj2E'^\b6r7Y83b\6P*ZQqPudGi&VRJ_M5 %j^'X5A[aDu/,.c@kTMP-Eq^AEKmfA?X3X/D(HlWlAgHtk(17-AQ/!u74L))d)JURYpOXsj'155L,H8)GP^qX=[h]./;#[8V:C@f\ %)kTW9&P0$SOsU70"l2sqBs#IP(3ZH/AsBWc>-L62RSh@*C15,>NNE^WC.U1-7QGf^3P?@p$E8_ZC5a%lm%frMk@_sdB.(+ZmO,H% %Ect>RP1_Y6fu"eG-BUKeS3>(^P1_Y6fu"dhPm')e]a!tPc_r'pfUF_K>=LW"U'#X0-o/s2[r9f3 %qWIG&_@SV$Lqd/MCb3(*4bTrE7]$[K5b1RHNS\7.m)=Nmq3M@Eh&o0rs4/irTM1R4NHmX]%,,>'C&d>0YMRUI; %,ROQD'^2q'9;;3J7.D(W.(E:H>5+E2$=9I`;G8'a,ZE&nFJRK,`=gp:\28W?P$3*[N+Wk+tPi,C)D8[R'&H?HRq!kn9`Cn`ndT_=hsYd%7>:+3TT9DB`p1FY6Ud;L!K89K&t[nZIYsd]X&Qia!(o(!umnV0LTZC8!^lVmSFD-a??"F2=c!f0a:EEYtu\WJ1?$Yd4ZrW.KdnQp"Ds[)K9;-C7RS,'UAelEnKjntj=&QI[5&kr,7*4kUIPJ[E4%\Re %:kE8&^-*]GATseBT,T$f=a$^PA9&%$o>N)]-;u.Rl>$$t53]#Zb4##',J];'a'S[(=OCTZZPb-]hMqo\?R?luEoI.C:RZ9*oq %U;U8Z#>M:,c(]Mah;.$8]-A:+FFA7F&qgak!>K:VeaE07Gt)tdoMi=!PQm",\hj^XKMq';(7+En)mZgaDkD-ST"FlmYBfT59.RTY %$*BN&jn/$0`cu`Hrh@\npu`A9"EO+702Dr:9)C;nX!out/u!T=%r[`fM=?Z:],WmBioY%)fBk9c%0UM8YAV+OT%\?8$9H2fPd.RV/]^@e/d?dRpn\d8) %rKUo>'j.;6#Q%O6(TDq_>1ai1)Q<]<#j=m%74K").*3_PZt,f6GcJ(cMs'!ooLcFLYEVe$bZBs!Z>VH/7jXSN0gmJqii",dr/6+c %.`lZ0Md6a5s%Bn/p_rX&P"DtJGNGbKdhs[5%&OS.1..m-.L,HDP+e(#fO@aA6+7AGI8L>^(GR!L7O3BO?Ns'W" %pJZnG#mM]D,l8>Z;(9WNdVsIllZ;g^pOWfn='3$Y %'EPFMCE4W([AQ2&.7+VS(N++A6=;3.'j'h=-45.14`n.^H]W$V?a,kj:oXM0d*6q^4L(W+2S[6oEkBHiZ(R.:be,mBpsnEpm"Yt6 %5"C5BB^l/lIUYeUf#(6`W1Fk5m6BobbUW\MkF2KBiY;mXKu5O,g0GQ71?6es/CW$Xh8Kqj@=WOfk\4ui8Hd^Yi9H4mK5(aDUIF0.BlMpI %3h$?:CAeg3"ui$J-6`oEaFZc,'u#U)1cR,:3!8gR4!^QKi##WQ,G`0/BNPn7#%u8^kdq*nK1SqqT %h9r1:fi`9unqU"nUYS\-6?m+p_%&Y=N1Lnk)2%)KAH[@gi/Y%i[(MEe`7HB@$0kqj>=*t6SktMO)WaojSKG%?.$G+`-gj?j\G(\^ %&hL.JcMkC^W96('<'FF6AadNi59cLNENeAmD)CogU98Y.I8mTKj)gogW!c80d%)^ge:f2S=?X`2e@"7,.R5MC=A]l`>V5WA-rH>Y %QkN,`-E;U.-:1++(iUAh0fmAZ0<7o@"lMr5#.]*^Qbb":ArD8O,%tWI#.]*^(\V#$Jm?$?$QK]i"1Tf>[j=%T!&qlFDI!,g!SeCE %Q+kud.=dm3ITqsa+IAO%?-ZA6Y+R&RVubZfn_:;&_[UW`\^@0;/ppR[jXTbN>eY^rc2>HV./%U4nUt/]J.&MD2ot)B0hX8laQ3f> %Yi^fZjRNIZk`#%a>eY^rlhPfl/mlDjo>m$q\1-FHN<]):!Sj1-$YsDo^M'?A/fSG1B$^r"21V16;sAnXS'^B!<0_Rn2VB@EK*/VH7jK)c&eBSS8.=Fj]NqPMiA-GPEDe1=WG29r[t#Z?Rn;9Uuo!.#X8r %coNM^:_m8Zcufq).#WL=i33ku-u7t_Lb4k14s5)VVX]PR62!(U`^p8[SW9@ %8W9*;JDMqg$Y@"#B4;3ZYn%,B@q#gWnMNbm7;SYK#,^U0&R-ZAI6]jj-Ep;^h`c;M'3Q_VcF`"?.#VTDYd7YHTr_b];IH1L2XE[= %][/uJb\((hetNL_>tK@Z$>&`=#apc@$YAiC7o,u66,V2.#Z,OSZNZ0./T@d:V^U'h,!Cj %gU,)WBXNe\]hP!/%K=N>g"Wl_WF1M;]^0K=^D-AfL!JPPoh.ksPjE7/>/-<)\I+h>9e5`'EY`KEgN7nD %a#cis)8fe%ltopG)dY*`B5c8qV';]l1\dgGDm_>(.l=A/VGPt#[!jHG`Zer3dp>sD#md0:c,s+BbMK*R9u/t.5'rbWH(0X*%BUl9 %Q(8td]T(M'#hdt>akQ$)M3,DFS%L>p;6mZFPID.`MibVHS%K3A^@9h1[)q(tr=V/Q7i`[?(u>',E1 %N)(i7g*aMTc/a2P`I#KhaCPSLa7q]dR%Hu06:%r!7r)`ZG65@,P*KV*g!q2XY%lu1E"2;%-tI],68er]-9+`#X%#Q,p(9m:_n2\& %#R*ppml_sA05IoM5`K)f6hrmb:rpX(]!VIdd^SSR;25 %r&+LXa=V,Tr6+c^F`CO:\h1sp06])o^eGL?TnEYAR#8LY.']6ceG+\JnU]ImL)Q\G,sJ2(`KEpVmLRK`hVm&D(ii.U6\ekNLH[u[ %"^_cQaak_ZL'O]d]c)fYIMSZ(OGIo/^l#]U7'oe&_67b^7*U.'5mia!#1\](ojTog:7+2a%jTtRE2A3H?fY`>:WHoq7jK6*[@gh9T3=9r\ieHMcu891+A#AVg84R& %d]_Ngt#A$:gL,Y_-Db1GanE,qm%5U[SL,Y_-DnG0q9I^.H %L.uSso?ZpgPMe%7o+bue'>3^kDI/4-i%>sTMDPt''9I"SOmb$RJZ'8sdsJ3:317#B4\"if7n">Qmt%qb?UYlI!5VfQ*#31,;@gM8 %4Ymab'_s6,8CNbJo2_[c"^L<0pNUYR+MJ(9+o*V98:1qKG&^NXOV5Ou8E$d.u$6hOQnUI(q$grMr07Z3Mh9j2!# %;a%9/4o\?jL^DpiEtsXiCe2t^b4+PWi9b*$]G]RR'"i5AX.[`[42Dm,a1-?mbTqF[H":iJ2]pKXHAf&HaG"F7ST,*X2;OYETNIg[ %eICe*GuB_Oct>Yr%2sp_0q0LL;^%`E:`])R;B]J<6"/Z6D^#01&&>iupa$!'nc7%*bW-7XWbW;o2Z8_6!h(\i]0W4]$8)e#+C=$uGql&e,Vtto?DZ0]Wc):Q'oIFcf'bXE\C][\> %6:*0cWT8q:XtJ'W4)1\Krd>JrV<+n%s7"g-c]H`I)s0b9PQD<^ESOGq1$uq1B$mls2*Ul![mZ5s5fmQjmW"P-5R])?$tDs %hmY_e=i*f-TpC\>)m[XF9`IaEo6Um4Ic984 %&,,/gpH#ptOk)G38RM.5kQcHR/2p'5LOT3qX]eI!r*AUL2n)ZfJ%hMEceVX^1"G4M-ek?@b?!XXeKABG_H&JQk&Bo%8!m"Z!Nq4S %Dtn)+o^5n@'rHY"s!:G?F4pIKQORNVi3p<( %&BSKnQYih@Z^,WS_Yd1W:(LFQ%/qqY"rF7WAU8Z';VT7,M?nDX0$s/^L3bOYm.?!XFgM2% %BY??'HE+;;HVJ)(fIMSaBPrq^dh,//Wo/3s0MJa2IIoUVKA?7s-ARLYXW#a&12JS(&Y*XFR;,\17CV4-BtSLEY=LNkm'OJkk'P@P %A#Ft22VcD3Y=LNklni5`c;hZVW_2RlBSNiq-E"l:Z_u4#a'T#U40L8O$.9bpA8mMr0?m6D3P>_#A8ha\,Xj)!)30^G"BrdfoUk3n%5-.P!&cE %/i^=SnK[4+'.As@h#QHSU+cIhI5laRV-a"G/)/@6W\JnU=@ThW*L/Goh%.E*d5_/?!fah$lLk,S8LmjaUNOf7bAHQFI*LI.VF`?s %cX7#@68,ChWUWLAd@^q>[q[A06DeBK1V+r29`)!KNIt7KT'\N2op[:.-2hUj$oX/H8To:!3l1lW:US2NTq#krl'N69>\]ohlNas" %=5RgfZbFf$h!M9jMb82'j%k#fj`oE9>W,ns(7Kq8bTNCeec*O5En>#H=fIF4U)E.^40*W;,#FJ9bAHmNO1%0,!'=-WN&./f#fh;V %DO_6$m:YPU%H#eB^Rs7OCa7/Fe/lq&TIo[2O6X:Ge#PM3WF!#_[u/Y`-bOTXO,l'R"Lh7a[3jXlS,1S2ebQUrq.a_6_a!&^_^k7) %O>U1A:YSnPD73fsVXJ\"V7h?[$DN0>,AZg`_6e9%%:rO';EQH9gq)W!Q5uu*%O#]Y-Hn@C8!`.+10KRFQM_WD[']d6-G-o*9AL@j %s!*L`1T8:4/11BP#IPs!R4*YHi0$L%()sTqatF+0fU,+b;rWC4MFS`;@Ug0sQ]:<=JZ-Q-/G:#C!4>o<05RT+`[n"%1,, %`HdN$6S13._/@).W'qSR#,;qQZ_5j3%r)u(qA&Y\b:FqhWgV;+<\H$3&CDa%,c %%>Lb:_.,)io*fs=/X6tuT?Q%PPPu0K1ietS3jc2UH7fnrl/&X2d^A>]`joUG= %=df[J?k'jb,9Kk7]uCIVL)[SN,"+(6&L`Q6K5d)*(kOdP.*F`j%TDPeQKF(q]ad %amlo9.0gj[2u;B"\:Vrh]qp(FA&"/eE!;ZdD]3H,_-PA2$SoCIR3DtniM>%J[W/1XaF_X#?d]Pd3&:-_(L)u8AeBhNaM]/g&m^TU %-ZGG)Kbe4Y(V/s)V1+\b[,9f@O)3_3BYVA$WXK'!mGjB?]DY33X$[Y5U7:h$YD!2.pGnXPZou(Llo3mp9%W`7VX)"ob2Dc`iG62Z %2tGn@LslR8C7OANJ6t#c%`gA-";3oF\bnMa=Y5cap[ano_u"=jT!CdOaTX %Sa?$Vpa#u4iFj!6Op1b:gh7I1Op*4.o:fAMf:4;[J=^BKs"j1Q/bp'+7UV!8.`2nCYFt@$Kjb;M=,^DgcQp`4>K-kPT#?9.$qi:h %JgOSP$qi:h!btqSL.+8tAQXO[WpZtGoKO0=_\11sQnBEh;*ok,A"S4/-H1>HJlmnh^]0$IFnB#f;bZ"cQE"Xo_\+6:*._ZIj\$\j#0mX#%h+0@nI/^Fk8J=G:iZ %oN17:k^um"6St+a_@H6t+D`k2Gk8:nIO(1+\83?u'bXD1D_]O>KnND:9&be084WnIQ(5)d$)oo?[9QmB*[]HRKA+As8 %S,Z%Z$ZHk)F5#uQZVgi-jL!U-"Z(u<=^$)pPp9tjQ!Ij>g?b%^4bZ@!:7D^!&4S#.[)Jr^NQ=+sG"N_;q>G?fg_V>18LGVgf>77D %ZlQ]gT7l=5fea;NT)FJ>W&\]Q9n`=702Zi06kiMF7'JU&<,RD(,!?kp1f4sSdq7&sn4"1Ydh^a8`uiDk8-5]Gkd;BtK#8('M$G5F %g2*2`X#^FG[+R9uc6\=hBsVLt1r0OBBsVLt=N=+0#eH`+*-9j#gF#=j!ZfUCOf3iMr,3]`?1sY41!t?8D'u7@c8EH;=N`n*7m1Od %.Cl`+>eN#4X1En%=+(s*AFLN=TOWLuotF=UYlf)i*U4#iTJcL'[aC#TOF. %6\M'0X3LBV8e6laa0*'?383^)1*4r79$b7gHlU1K-7hIki( %=R%K^CC:'-O;q,lhaA.7Z!jP3]lg\@NR`c`?aq,Oi!(6B`I('t;UM1nt7mtN3Tm('oEek98p2Pl21.+HJG_-CL&^aoL4S-H* %gd)`0rpauY?8np(-0Y_Tn/0*&F+P]"GYY>Lc]ooO&9`@Q5@hh(K;f_igLPD87Sc(6kMV2# %TE@dDN"2FBoQ=(I-*>s;[*+CRd(pC`WH;E1#Z<'$2t+3X%rcZiiYj:mc!7tV9%_BC-q"@[TIA17h6f^'^p)1W+@u($!2N1Rm:dMD %Z\eJ2+T%P`lf[]$Kp.a>JWBVPTH9mm+us<:rC-h(Vd9nS%.plep$JG.>\_.D6Z7KMn(@u:p#X^:!9Jsd\f-T^'^4bkE05_V-t3C2 %'oa%e5Z+0V42%u$)su?K>G,KNQJmH#AdWXKZ"ia+IBqCQqsh(MeQ(8>l`AGF;P7Mp(KQ6MO9-HpY&mb/#V"-*RZ.0S!A4O:H8\at %S:eX7%6n+dhB2)NgA:&+kJ$Y*#FNpl4qF%M"GbeAj]P%@J:l\Gh.L5WoF?NgKMLhe??pBgE^,jf3%/45qGA?A/fI@_)6_V@YIkm( %I+2pjh*u-$iKnF,EI4.d3r7'80lB0u0p+8Jf-H=E@r>_9[*s+%S?e.PGI^5iU[C<>+,in0;YU6]1_M:I%X-^?:?%qiNNe %[$6Y7lpne>P1="Wep^"U/P37'>S9@TTf4_kqiNP>"RDG5>S9@TGuMsr?Xs66>fu>=9*jM,SRXDCMq%qa/.H/Ogs2Z\>q)H^#T\]E %.fDP$5V'SP5c^h@%TA;%XHJt]1rj\pO&bHhe5C(N.^^-(aIsU)-ss3-2e_eTGGuJH3s%?r:`5dsKS6JDH=Z29Yj]YLPE4uk %,5R>bKDekqX6e#2[I\0^E_"FjlG'TPi^XWuAU=Bp>B]MmpRYD;%VOeBpp]elo<@pegIGV[:kN&g:,))[Te;jV`>*SW;3r2N^o5GE %d2dnP\hAg:W;Y3V`a,pLC[p,D6XoE79Y\GIKXNK/a&-*!CJ2oWld3VIMq8X_(V26slpnc0(O@R7(VU*$lph2=90\@7cft;Q_g/B` %e+N[gp&-IJ?^PZs#eE3SCi*Ul54gTglSB'45c]ttGN"Kta"h;+q9+)=\gmf?_:M,4Y3<,WT_HH&9Cd(G\W4+I_j7S8q5sjT'h%15dM;\^[3#M %TMW$OPMVtO=-bnX]<=echNB^B7+1U5\tH>S?,5p%fA+g'BJpC\i"5jdlb7[*mB;`%+OL!SXWTa"$hX5\/D(][BSMp-'f+("Yn]JYI`P]]?qG(-0=M>K[hELUAj/TZkdtBRpPEKnS0+C?$G9Qi]'AKLemG`K %bs/?/X"e5(I_aT@a&1)p0[>^a]9S.cE6:(\f$i_s7nMBg'a@rXI7L<&l.i^jQDU,]gkB?oV;Ck@jiJf!7+Z#;icO2V3K1SaX0j$6^\*"uXO"2i!u4+Pg.`/SqLK*1HqBY((`(jnDq_Ns::XJkgV:5DMu?E:qcYWl %et5RLc`!r2$gP^cEuYF;UH@-L%A"aIK4>]4&7K`9\.N'HOe9!:PtDp;9hoPdQ+rYu)chu'/j,C$L7(b]Tja=X %V0i#9d:0N`C#9?bMj)m/TY%hoiE[m>jKt1?&n_+TIYuKM0\D%[h)F1[kf;+uIE+?6-T0L:GUo:n>q-W.3Q-?@caWfNe`7ZDW$gI+ %K<]I3U*bo=P.>Ds(+eP\F#8cnID;c?)F,NhH-']:h-K5g;[:oV:Jgh2gj86;^K*hDY''&Q824UI4N)02V?i]snYDs,dFu(=Df/;l %rP>C85HSuR-*Oa'[ul)DljnY.]C\a1jr"ZleErrB?YlNiRB$lJS]u[iFc-Stkc!jN\9X_T>i:i6?Cuam`\7^SG^%#*LtT\*q-*&8 %1sl>l\l=<^jGh,nHWR%h&aJR$XGsVcns7D9-0;YS-fGV],qKch5">@3% %m]jLI)Y^FpV$B/iP$Eo`,r4[8pYq5/a;!DlgAr12 %6UpS%^4pWodQ@IKQiMAXgsKjAFUXkdnKe&A08C'RCX[%@F$"cNa7-J7En=O[ght(ac*I[$duI>SiZI@<"Hpllj'\$DYbR"g-;2IS %I;)2KNi4$qH&*iQIMJ>`TTK]>^VHlB+@]jOG.Y=f[:(60<2Rq*mOV"T(IPZ?s)Ckb4NsOTq/gA2-OtricWE&5Xi+5_>r'et3ceP` %S"!XO,-31!e'J2#GtZo)4^$Z"('RuoAk[g)bUePr6c6k.,1ogPq09Jik-4TKF8'e@WTLdm9:Vmf?PgW12<3rto6q9Hb(KUPs6G5dhOLcSCQ'lWTJlX$I54qb#YBqShC%D-D$g38?GPrZse;i>FF,+?2kkG9Fj+! %mp@To^K.5Hf#kqhHf38n,fJ0Ng<(,TdhSjIC!Tc@mB6ZM6XJnapSsZe %HLL)j!"O0)j*6a2H:/i:f/UNG.i3Gr1 %S@#K.(:W#>a4=bCA^fZ"mQtQFi:$5XGO;9E\\%@R5ND4lmI%7s/!n#o6[Je>?AK57NcTLK\tN#,6I+PL/1O<17U>5]:uEsl2CVPF %\R^-.q7+UIK(/.mOJJu8t,oZR,Q:fJM %_/'2Q5RmY=-!>2["s27,:+e8jrLOL:rdbu4C^.g*1f2)3V$RR[0Vs8^lo1d19KJNY<8r4sQQufg06e?^,5]%B>Dta6:mmp:``bL5 %^<&d08o,Z&+X7+!re4&tg8GDel;b5T7&]0!VtR.RS(^bOA)]7j4^;E\+TaCCFmL"!.H-X'>kP,*O2'8n&scj3VnWMu66eei54FJ\.q4?>g'V;&+2$<@(r-9*:7oAfksJ2ffq/_DqpkRFrUSO%=k7kmI9H%dZpFXoU@p_gZY)GbTA:2=r!! %mPiNXG!Uf=,$T"gELY(WT %oU#0+r7CY]?2#KEX=0A](Upm"-Ko@E]EYRu!W'k/'M#?1a0W:0MWV5FgQ;pbN\7 %]M&OL^'WBCcJ^)f*FHY9K,e9dfjj-WJR8>'&&-*OHg>;-TI"FSV"4La`*A*pDnp]U3l42'm)ZL6GS5.t5Q %E"p'4Ao.*@m*07k;p=!d`pU"cj*Pig)P?6LDgYIG9hI5,QHAU(P*)elG`[d+cHP[]TiCF`lh7,7]BrJDXR/:fY.i8%&3QIT1+geJ %7(Gs8OKi>p^[Z8qpQIP!`eu;EB8R-3k+Io$p:.`cs)`]CgY,"Zhh*L$;t./GcC!5X?r7m`bX)MdK&2dUT6HCcP[ADW22!Oq4&)0X %X1[/f]IOA?:A=F/bFU9u2#4^%Vd*G2K0hus;#[;67J %=38N_0`Z/>f*+6-$dEIB.`%X^BdPk=;2c<,qQbtole@!d(f&J7W4Z]3B@4p3P[pE95c7]79/>0m%`/fLa+H:6THg0Gk55Y[Wt2cn %C4>B@-;T-#d/Q51fpis/<-;7/1u0])9PeBmS=jXmjlqq=dcqUT[Y=6n3LhPqOZZq,f<6R(iVL_= %ajXfI)p^qX;*8,tKs=lgi]LM0_pp'Ydm[q]'&`!Uc'A)*`-Jqq1bJ']''8@El^6f!''JMrb$hIcMn>kp\6%/0--jsCrlX_X(G4AF %ccbS4>"HAcf$ia9;\J9Xilo14Ge-$8Mk?mT:20o-QcZmqrU=p#/qh/3O@Q$%=+SF(P/-=d@2*5Xq8j&u,p>EWBH=FAPqZ!8K^N"J %:RBmN5SK\$f$f?(ABWLLcI7KF^37B?k5C@JAY!'PF*CuHf`4*8jfAmK,G/_LXTT<0AZkqSls'RZJR7p_j=8f]J\H:[L*MlJ>Z_*C %B%sit64tNq\SPo9837W`!thX5SF'Rs,Eo;k:HKAc='%t[&3C]R\T4!XH0niBm8Y:\E"pKS9;f$g9*;?UG/E>._E#:1SR(41?*H%s %]">2-0;,Y0O1PdC7tWk7R,)&>TK>;-?>hTV'I?Ne,]>*Ba\hUj8'>Xk0=)EL9>a5)UrJp<\4^W*-5%BLA[Bpn\-qU2+l&/B9>dM, %Q"5d3XoOBH>7Tk`-Ej$r2G?%S=ImWT8MWBN7E'7([Cjb(@8/C"b;G@@RLrQ^EKcO+5Rk&`95L7*5-r$LPJLFEf#<%Fi2G %!7iluJJqDW`YiGMR)XgaC=iknOb"DfHJqo%H/Qjhr?G)eUGiaHD.EShl'e?]_>q=B1bm&a_o_0m4Rd4jF^H(WuG(-F'Lt^M*#oq3E;,h,19BM5PIJ]qDABFG>'_MWtP#@J+1;fdNl`?ZJU(p:SDMr#%GoH*OotTF %Fb+7GXd?6.g0PTg$rsLJ)O@7#g0--:(DqBdfR.)qjjnDLj.KcW^58[7D-pl^9nZ\'MGc*5G7gh*Mo,1A-J59)?505BrrFZ?=6i:P %l8>mU(G/tMVpro2[u=5N78`=Rq_/Ut]dQLdE!p`o=tbb203rQ6WR`T].J7HS\8?L`^!N2f[FU81eB;=X\L#F_Ao)m6S7f,i.9GA@ %aL.2md:nT)/5H+)njUFqesaR.rN/5OERf9MG[C:u#f]d0#36h.;OU&`m?5(A5rq73>. %ct3oqegoi6os2bqc"/5"#6_Hf$`u+Q3A?Wt4&;6t8O]u(>S9lh!CkM6W%rP"_7i620%;1%d6WSl1PI0 %7%\(p*Mim!,ik%T[Vi;,pir%?o:RCKuo!s=]H+M4BN1TL<(>1iV#es4-?/[qP %0TDR)/odI8+9!RLV[K%pcT%`,U5jdqLo8G[9;7;l#k.#0^VZ6uU=3?RnT6dse6#6K7SagqTJBbXi]LM>\YAUW6rRSfDGQ?::DY]c %VQ3@[V[IY_(b32(S+in)XNY2.?a.-HfUM3jM(VE&[4@EgWe8lMm9E9Pk=Isp=n.Qi5fZo3>jHW0MFtW-`-C\!qg:>uFLCroYc0XV1V0RRC)ta^[jjSZmB`[%CWQIVlK0-^?\@\sT2P@AaD[f0Z %G=cj:]D/nJ%!O;&U6dc1Sg$_^g?/tg-'*]>Q#ra$K,$416=!(KW/rP>)g1-#(*`1HZf%utX$ZW4KY#MJ$c60j-"pD=Qf/bP#Qi]N %jF`qi?(Jis//LCgL%iUh=g!fff>DX6F'ND?pLCaGF$RVGC1-7ZHf%3qC:O+HUOfUY>?^sL9[;<.qqD!@Re7ML#:]LARX4-@@G.nct/^jG+\PVWc0DkI;h?KeAY!FOsG.7/A_'VC`+CE;'aePic7-P&AJV`s0/d\Y;o %c?<[6FE[o^-91I]K%=+.hp<+aY&I!gfaGN3'cj`gRVJec(iVDCoG/A[E2TqOUj%/k0C4*VTtb3/F:Dn1aY"u!P8`Z-%,=0^.J)%5 %Ad4ElR;k?Z"4)3[+uB[d8;)YXQ1[itrU?u6L*Z>AB)&?qakGY^c-Ug0OL5Z-RQ9H*?5JtfWKgat%;"_K)o4/23=1Ht[9b;3(YEGr %$JmEm-V(?4U9K&sG*Ki<("2g;8C[uMlU>7ZdQ:AOeU%23@XfJX7ERKp%gD2_U2g][?HC2b'U!6F1LRdIaY27"ZPFk=ct:(D9bXt.#mRf2oV<5HqGEuF]l6l:Rp[+95D1'"VSLB`BrT0EpR#N&N32]d&rKS4NNg.$XNjT"+G`CF`X[%8)*Au %R"kl5dmXB`XHe6AWqK)DQ]kh6$aS8MjVljc(SE#pbZ?Le"fY4jEXcltO4F.S+P5!>o9ckWaYhjD-`0^mB#tOpYm^HIS^oEr`\'.J %OOA2?4k;5-A![\4A7_V9e7U^`\WcY&b.O+#?'=QZFpTmHU$E>VoU8-m`IIgR89/7hMo+,C^\8c"/g84e:9!AsN*SoQ\S^a))S=@1 %?&NOc$L:;o1NidP-5=$Nn4VDm!Es!",Y-#uTJLa/Dm?k*+e#Z/a89EYpki*co=J1nVh8PrJ^Ro1Y"T%l]aL;,P_d=3]EcX4j2GWs %8geA8du1*iQJh<:]PB)MgsFaOFu)kTmZh:4O0,cbO4Vi0cI[RHq5Ul&?alX7IltTp.?o,9SOOlT,'l#LFdE[_I[QAY# %"XJcb+Vg#nhJnc)>/t\$]*sY">J'kt)Gj*@`Ebt(cGkElrQ(^+"nM/YJAbc!?/$T@i(M)@Gb_"W0?!%CnHd1f7>uYSY4I&*Q %>o\i0`cWHTFb-eJ$OMS%oT,nj'OqqS2(.!u0c@T2e$\UZm"-9/T=QY8`\*d[6a#b7B^Cmm?f9)SfHnYRe]AehPJPB&;k;.;38%]s %8Cbg2lJc@+`?Ae1Jn'V%Ips32c6RuG;kr1G_mJc$VTF7H^Y049h+=rQm>TGR>a8LI(Zub68i.GD[df8NP4ae9[#S.Wk6*!%Sgtb[ %OgkIK^k$C#XZ-A:8HnC-IlUP!HTTRTUaYqFn<7[FIXVKN;r>l2SCodKR`rB"R8uNfWAF@:4spSiU2fBjp@XA`m7`8Y@A2$O^\gf] %*D?)MHh*mVoAMibc#YkPBr3bUG@rZl@tC%SHodI2f5j1g*hU_gZ]WMgRN1+N%,6YV;NRSjN$6tdd=MdNiTjOlN87Xqe,'p7h%enJ %FBq,mk$f9M5ouJj(dg+JU6/^U!_05fSpr=k;tZ?u^f!=%[YjC)eUI8R+PlK$GON2LH[[i_l>e+.1,=WAe]<E3uF`VH*op`hBGoDj+.]QU-boCERZgo^Mp;E[]d64gI?opN/HfotIDZd5-^c^l+0aVGXkA<>Y%\%!r/2S;FVg_Dgg*Z1rg`EeUA]-Nf>@ETI+ %)/bI*L99OWT3nkAD>#-==MN1u^J3\%h8POYGF.f;ke"cr^&:I;FtQ?un*skrF4kIdO`i?K%drjbcbIW_ru)[E8WF#sR5I't?!rKF %PlupeJmkoap&"RM.RhF=V\^2=JBN1Dr%:C5VW?P2A?G!A.QPL^GjcGF'RHoGY8@_0U/:=i[MM9Ii;@+Or[f)2+S7/-^Lb$doK-3K#VnH)36/dF]=7.9=L8LSi2AP];MFZ?Xn>uJ1o4e#l?=:_J;l6T&n\K?uk&r`;Vh;]3Z7_(oa3qd>8(> %98ha,;H*7&E_0!n:8#`[T7oB&jRjJl#PcC\rr8B9Q@0^CeFW/&7K>*=`N-\DerJX_Tf_eXY0"-q)d(KE[+8RNUMKO&_+n.?dVd[d %jO1qBO50@nC0/b1rI3K+CY'I)dOfS"pI;^jjZeXRcG")p_:8ZO3&paE>Ij:K7G$/Xjnn#@oC;)O]aFTF[JPAQT)!W4amp_Q+^>ht %amp_Q+[UQ=PN<$n?R2rok`c/8?CXn(X_apY]2rOL(L"lAgV"f#^$o6BT&!&SdLdD)d%/C7P6scFH<+Yi%KatFS!.=%2#;Qk`\qC; %RaVWK9_79H@i?etD2QFlV72g\n&#Ke:R8mN@NSW)`,TDC;qe,6YVfHiJiJG7nkaa:_58Z#U\!]e$?e3rSGKJFVPt`/e?hr&Tp;6C %+'((%!;;CB+'((%^`G!9I9=>8K/$S"m_`L7WUXeQ2G@&X.kOpHifGcJZMTgRnm"IcOP7lF$jNmCm65#TU=efUb?]pEW,;YT$UE8-:cdu5PNPrl\?jqI#Z3qSBE'E!bnMHr5golm:1-Qu^l)(KKLib-Z#<2Q,8ZME %OCUInQK,0f[o0DKFXr,H^hLUV0lhRK+EN>Y\h5NgEZmg25]=a\X,s2c]oA.%<[!1<@>ml%,8X8<--8h8EZm;HHN'9K5/b1]ofZD3 %I)nu3P7TprAj\7":;r!]jZ(6!LY0)BKu=/a+Z:;!lqHB_LY+DO,]i$6i2!75ba.&[&=X-6F\;T-&81a$3'P8%rS[VuM@Zu46.d7m %`J<)^#WT@_nKE)&P0^k=?]872&2HghMNJ8a+pTp=:f7Ep,+qo/,=N_jXK-MoQ\OkMN.I,1OWr:NV(2c>q#q5-+'2Z3&$5V\aB`/M %l7_Z2(jFT^o?Z$UcLO@S8.#ihMf%h@7YATEDL?hqo=.rmL(W!*&OPB&6KHK*8]S^TLNAJHA4G(LUQ#_)f_++&H)J-8ICqRV.)S_c %\*i2;Kg%sYA;D5$c1=qTOYgf[I:]^jOlaFt%bP@UO-\W@tTP3bgKETEH?/'>tAj3KBHpk:Im/gS178DIU?DCdL&+!VSb %?Qq@$"iSK9jHkOuTk='GOrDJ%7Li1.D.f?/?UA[AQ5I/or0!Z'-P3l!'AM_E"sNdggm>sH`PBbPU%^`DN*Jo&8WoKNj?eUB785Y; %$^(&K>u2E;R/&%"Ar;]YaY0@N`FP>Gcmrk\;j5HPQ1lVXTc^%hOc/^.\uq\>50h0h)'^oFd%'M)d/$\8i0PR-Qm"qZa=m3eNW@00 %8*F+1eD-1)QjmfHe9>t"*@"'o7+1VpF?teH9:+%pXc6?Q^^j?eUB3BF]a@cUGG6KB]q65Lj_ %1.2UfXm'?V6AER4O,m0>pPidMeo^Y$dQ_CROt5)UXY1#!SAY"N6jC,9;bN33*C9sss1q)T&\JDOW$RDtFE4?,WbpsJDS-hfZ"+Yi2EoYp6 %$J]Fl*nR&#f@?VL4faT_MsF`n*fSJ+3krYAOF:AMG4h0F28:3aNd>g^K)i+h1^g8TAM(XlOOrR^Om6Y&%IS;&r.J3KUVK@N27:%7 %gI,iE!F_.@R08u+g1*ap#:lC<9m#241W+A2[ %IG?h&j>N6eN`j^lk(?hU5S]LqC<8-f`'q&W<)dtf=5VYQD7[0rWH(:!/2#Gk!L,gGL %f7nFP&!qfHMJD\t^4o_B[L8o3c&OPqm$68i;2ku._=a`rVS1o6<.)ZemO.=hF08$P>VE1E6L.L.lU"X\XX/J:1+hl?Q@Aa&8]*ILlXQ;g&IQVD^=#fJ4#l!Q7e6P\bjZpds%4J=^`LENK`]fOe,1sot1$%e`,+o %+(k2Qa*n+r2S&qPpf)#KQ5cem-2"CZeO,UmB(7$I*eni%%%1_TjP,Wr_ODi?HKbAGXdd=Z\+%O7Z<01iiK$N%;MOGGX'XZF#+1d/ %X7)og;U=)lokNfm`_Nl8Ot?H9+"*MrQXiBX,sRj;F3R&t*`-atO@bbQR<\3Oq>L-dW7sl)T0b:a_>FXJ0cg`r0Ya?/hL3CYf#Rl! %IKa!n/dtB,^Og'H/dtB,^LF%.dk`N[,_dW?Un[>;_lt+70eC0=MVD_&6)k>%9/++imO6L>//P?4L*`3oJOt]]@@=smo^+?J=Rfd$ %Ji>mo&bP=O0kXYlUQ,GWR,ecqdN`_!g<1M#2dWt]q%]g5'`=Vti %B.H?D8]4[AAfVD1(R?AcmYO[ %9+)2Rp.K1:huA]8(X-$dk-WejD4ZslXuU>WBEIXl^FZL-bQftU&lM\(gOGuVe&Z6%5&Mg"4m3-A!95@%ulL[1p0?':gjBU'Q8#-ol/_T,i2<^hK1Os>2#f$*;jg<\_*U[H83Gfb"^un/Y %@[bA[$jd;'YhJ/,jg<\tOj7'ca_A(q,1og,Q.'?o7$>?U2Oc&1De'Y]e0sd5n]>LOBqhQ:$?SBTS1tp5)Qf*bTX]&X\d&mi-g7Oe*F"X\=%UZkFp'nX.lsE+cf)!l!G=eB[)?E_FakM;ZR`MEAY@ %\rP'U^TGJaN[csZ!qi2dnE#4-VIPEK88FjV.a/+dXk?6LT>OQ(,LAS$['T %Wle&n_G.DS=Lfa2`bOKu:r`A%2GkiJ!n[#`KOPb.puMZihKrp5>h3L+C(+nYXl['+e(mm]T,03ULns(i'o#*eA_I,K-Km4. %c$:AXaHnVs`lQ6A=D4A@^10?-'[r&/&^$05?0E6B4l)B-a %WKmEW>LSP?R%<4Ff-TJQa^/^nrI2HRF>N4m9X3VZaOJZB5K&qhh84WpMa)nC\pJAeN`%N_+,Ja>["%N_+,nP$/G4%'=7R,RX3677_%XOJ#P'La3Htb!ITa4,^E$-% %1Qk!.:Sao:Fo>(\'55+pDB_cLBMRLN:rWAsKBFO0Iqu1SE=#_1#V"+$:>?KjO<0C%pRThsqQslm20mc*33q/A3tYguDC1-ejlYMF %2_SbC*=l6n`ZpWRFE#Gh$,PNjD&b?^T!7OP(9\4+Ya`$0h!9BgTuA+?lH8&S[]Wlt[j"t3pbd.7l-BRlgBa*R3$ %BkNa>D/RRJ`P7':)Xo3&q5V@gg#]>F38(mE\P6 %14J)r9IUGk!&]uOjb_h^B*U,tSG#]ra6B#:XmG%[20E$s5a1^.+`.*'nmC,fGMNK\A)l+6\@m;KJ\%^o8WKW#D\(2ZVPau`OGth> %QE"o]W=C2O`R[ZNOZ1ZC48J/KVLOg>2YZc(BlQ^/Cug+2@H#8MA:Skh5gO?].7&>X1ht.]@hm7;jEpd>S]o?-j@_)hPL?Q2ki%I; %n.q0j_S'l*qiLkn$!hu)r?rq+aiI6f@m<:-Q'PU:A<-@.?YYFZUaL[rE_]6>*TK%5Zu`B0fT1EBTu>E/j@_'B1JCdFd2ZmmP!.lh %&8DNCI2BF>KNaOL&%Ns==sBl5B/f9XlaaX2_sC`'#iX.$K=_>Xm75;a3GdlucPJ(HMmAL8(s@t?)FG3]6&/V5O-PSUX(:<>e*,ZN %YtF6PY*IQ*R?mSd5VpPk>#rc>Lns&sY-iOC195Nn?<*1^mla&4k$jT4H2>.,ro[uIQrO4#cWBj1;S@VkQET_9UjCMe/-9s4p,/aC %U%U*SOrVE.o1G^rIH%?*U[7/\`T]Kg>!P#TW\X,;*LSK8_IRUf"D9/,GN-B430/Z>8!%f2_g)sW4'K;j9]N$>+F"qF\3g-QSpX*r %3894M6DJJQGu*`;mW=9IY;bCsrj7/nfCMTq;6.M?Rdn@&U^,2l^iRG""OpH'nNJPm>.3cf#JR^+KY$fAb\_dt2kR!bfWhsrBbAMD %4l$ihd"#n)6/0;N\CC+)]c7i[PBkiBHoWhO]O7&KqO1:J8%orZ>%-4Lnc'2,hnqnFT<@XTY4&RYqUi*],O>3)OrjhmqT?Q-9#0\g %rG.&]6=XX[^6QdTYT.iq:8Y2Vd6e"!)m\@%rYH8aZjF)i!2HV4#%jIrLFe;$/A^dH^fEU8bV1a742&[.\!TX@hO2fq9EY7V(h %h'tI%AMr"7dkTcu)X&b2!*#gJl1*9T$[\N>YG%@K/H%HYIgq!AkmA>C3WL3eSN`7oYdK21;Was4`HH?h,j,b2a$Y?qmtaAFf$eqN %oh$_D[)QOJm*:6^_V*dFdLYdRW?YE=-->X%$FV3gBP+L!%$m^L")G^j_1Qj\m2%68IBISS#S6cgib])U!3;0DZUEKW14JY\5;[[B %QDW+%7^J7>*49-KC7FjobfY`TQa`4IA+TXtWM@qN]q?&!c@4j#:%U`,))O\Iko92AMd9o(sAaVIR^+%f;ZLQ_?m3jFn`"6b2:BpF]1ZUa??g,3'0\i3UX4ki9rQnQD[=*&/Ts'cW;.CQ[lL\or %o^8_?c\X\CD*M)[<'uuZJiJOqDq^(mn)'<9\h3?R--0K/l$6W5NlQV:/e+\_XjQ>[l'pBU!It="#`UJr@;\f4q`K)*lNs#8:%UuA %cHiUulXK@BmFLu!g78.^kW<:l"D^+8T4f"Os0+G[ohu-`IUf$et`mGTJ!n%l`8kku.RWk'#]r2eRL+9,"L %.[YWc3]PO]>LiZC>;,ZK`JpQIf0)(A)chGr[L;)Tg:GiEQ6,78#7=,)aKYD`r8=$)5c=Uf<-IWk>UlePXi%!iCW@NfGPb)-n-YAZ %-u%dDj/oSoT2\WTnE%GVf+5S'k.kg+UeeWm(3ps#?A-Nf)]PJ>7$`j6oa[*Mq/+291K<)a,bag89_oLg+WSX0E %phEjL`=;,a!m1(;;hg#"`2G_>O\Dnt#AjIt":*1^.ll%1O@OC5YF6HI#(7;L,\2 %Aa/Um%Q:p0l&:RU^pla$A+ium$fHcQ'&2geA#)1`(\I*;p]m>G&+h&NM>'+!dYb#h\$XC5BGeJ*?JDdC&kq>lZ_/`bH9tR&A/0c* %d6(]rDX);f3I88e9e]X-ELnd'Ms7AsZDX`@X7hS--X6PY+('r*E1S\g@u*V]X1tQ*IokpE8*]PaX#sEYg>d&56J#eW2n"W@9$ls/[JY:)J63gSK*W.E.Sf@(UV>:6\_g>@da^.V2WmOl.!chP,(h-I6>=D)Yu8OS%EDg.NnPPe]s %GLp7&2.Xe=PssW[%E0^U*-N#bASKeq99SOZQPt@H^g3atEucL3i3(%7SdeU>6"$nfpp?X[N^cOrqCA23-t(NQ0BW)'A)5h)+X4B)9rr9R]3b.%+PTU?$aald%umi@EPie8s7)M7=S>M(-Cg^.`m>@E!,*MI\p@^Y9AublS-4% %^-85'[tOa5K&4C[-*CQSDQBGIe!T>P?h-ikVuQ6sD)e4gChnVdno7MR.f&WP]B)068+a6'$XZT:&(J^)J,3B\:JQS/Up17PH9&iuDgQs0A(r+i_bC9VPm6Pc+.]6N&U,1C"]mX5RG?WnUTMW/@,*[d-2ibk_TkdP^sBCM8^!Lf_VIWt^8>M %R[5[Jg.EOq1]I_F6YIncCr2+u)fHtnA*L\@I7E_t1&3>0=GfeZ,4R#pEQ*>?qm5.pG1!"m:GpO %(2CDWMl+@ubZG9,2\%CU;sEG[/FB6;1$UH>l#s4pf"Ql9Qf1Im!V#fmUX]k>(d=DkMUS)+,rl^PK=)f!kf*D&$K#r54bfm%Qb2*H %kB8A)BqE;!9@,-kU^"ECZ6#1N;K?GXg6$eOdd`u=CAng1LNjHtoXVh9kE%[mUG+/cBseq]8N@%Z2Ze^59=Faj*Wnq %"r&FU"bi_Z&m$Z'a[@67b],(LDJje&uM?-eFJp:H$cj2CFfh("O1Ql`0-g&icS*Wj=BW@]@PhCD;$!XO7rnM@(`A;e4SPD %FC&/J0ifnklQj=l08oEkq\BG351<:m=N#8POHqcb+/tbSh<1n`;cI:ll1_A^3P%<=t--jtNkOqUC9PrYcb5Xk6 %egggEDlHp%SL_=F`A\kg;"%Vcjg32"'&(VGO;V_M:Z57^O8[5Qc:)kDP+>7/Z(]?Vk6_Jd$tJHUW?da>nUu:dPWYrp*^rOh*Pe?YqB4[?HZRa4,K\Qi69741h5u]CZ+BgeU5,?$tF57UD^*B3.WJQRAF8qd-$d %a\r>aK-tY6Pl0'#p2Md$e)Dtml@O@V7$bi5EkGtY/tE^d_Hg8VfM[q"=W4^YeE"RMMnA+T]KC5MR5B1pE>Ju2bm7AK3A/s8B4\VU %33Ko8[:EaWkVt3X=gV'-70RG941R`_C=r;-#^eK>^@n<)C>b-_cb@ak%1KpXG>r7KL6\b^1f+;#cHsBZ1f2)W@0?gMf]ir=n7>8m %aPc@uMo_.T6S7W7VYI>KJhKW[(^=?M/3IBV-2oE"_&'bC'-n:"=AV`TFEueXj$&<=^F)aok++LDf,qQaf97Gj/(cD9B_/;&YB]bX!W-_"6T^/X.l1/07P8`WqblUfL4i[YZ %f5X2'CVp>#JjU1>2pjj5[u$f:(,V52=W>#IR7,9Qi!mrH?Q%@cCs7Bp]Tc7Yjf>Vop!piYq^S\pdR6su7H";8F)iZN=:+2pK35"I %DGo-$SF&NaCV;,g]g,!tZ.=iMp16;N,Lh$:P^<:@Yh6Tl08`X\1rBTTQhQelU$E?!er-9P9R7B)V!8$;M/ %Q[6>PBC&MLh#S+eer-9P$a!p/PN>@l[[F)303NbdU"K-d!^AFh=WX-bONI'h>^:&GF%8rj-gC?OGN#&C:DuW\Xu)0\ng&]'\Wr!j %5AHir:oNqZQ7(e:UGE[ner-9PbK?;%4B+E/1J14S^$0a\kc#qo]00fpQ %Jns$Vi3&5][o[OTQ_bh!m.Le-$k-hC6M$R_[o^'aP2bLFeN>6*Oga!p3'JB'6ThrnK&bl7\V3P_=)`OLf"lCjp'P^2Jp!#B[o]f3 %$P;33[o`>$qXpXA>^tGej6;.H[8:F@9V*lXl3p\T`T68Mpa&V%(SdnOlq2=)\-.&f,h[?`M=YiR%'T*a''JM2g!XtbM=YhoAIjOg %FQlmY+>/e7Vb9ej@ck9DZV6rCSZcS_]>Ag(@"L7A?/dtPJc&.d:DZ'kei8>hD?p=V?Vd$#01hD+$e@$ED:MUS/'a_=4mOF?8O;b. %dZ_K>'.hGX--7^PLTm@&$h$04+7>^Qj8FR8?/dtPB($[MKpUoc8f5]5]);d]/Ch^-FKoP^?'1@!=%QX%*FS'1S7&,h %/j,*uU]uR^F1I;Yaj`iQZ#^)%/m`lkV*F9e3HEpHP6P!0FDA-#8lT6'#eXh`544:hRB^C %%"g6\7o9g+_daF#YGWP/aTSTP\XrB/P0?QToHHf %mm:!VTp+@]X_rg"%Jh-;2jeUp]iZg0&U'VA!r_6,HWcdf!P*qCmfi+24IE<[h@#p';7VFih8a8<(Q`EGV]+j3$gLta-(V!bT\hKA %AF)'l88N(.#\-qAB13ilY!?LKZIS1#3;jQ2/lIiRIq';/PF^8W+iZ.Eq@Q:P$H`a^D'*Z%;+Rm9PSa1nP3fGs#r-Vn9f;Z$G.CMq %p#7TeYm[,P.)rE'Xu'dKkrMH)+:49%6_CCS#b4LDb:`]SXa&J([/D5l[!DL:OOY>10^'mT#bcn0m5k#F01]H%m$,H %L^L9<7\DHd=0<>loB7dg$*!DKG#9@/F$+:*_JHX/g8/-40%JM5=f-$Q]:>9/-*=RQh*T<]7saKU\A=8Co&j]Q %10c_$f:5oFQR)IZF`B6]6$Bh8?'fEpC8KgSWr:B*jWpY,bM`+dF^8F7>s%T6,\*1+G;3=RQ/ZHC_Ya8l\h9#_0(]pK"'g*g]C;7_ %Y"n+]S;`P`?Ze-EiagsuI&`B5Mj)s5a-C4L3p]uD-[('7:EjI+2;3IUq_"=Y&M9Dd91SBIQfSshr"$75M:'4$5`Sof@:Nu)0gu'% %f+YfW\^(RM5c&suM(=)^p86EfI?`qCGL]ac:LdSSh+uU:k.B!q%U@1?NG\@Hr-]DQCtnBb:U'%q*XOs`RI&/aZN;_t,&d\mXG?acs/&UtC$"FVC>?$oZG*8Vtf_be#YKqS\"A^%c[r9/JqZOZSc_NGN3BEf-_Mq76:g %#r53M`>G?"P#%0J3`.ECN8I:T'T-Jcq(5[T$R8YaM]fL&U1OIjJ5s\f2T]Jt]L)>!6:lpE_CV(e-KlOIAW",ep9[/7\tI>!KMC&ZHWm-%HY(>MA5=_?AG3Z&p9[.:iK,4dO?GTF1F%k3na+BfkcZ[Q %a0R/69@daGT,f#fZ-,VrjFcu:llu1+fpuDr)S9ra@R+Rme_#"S\J%=eFrC02^7APW)S:MkA;H3U3W2=;"[d*R?tfItDd7kLr^.D> %+#6U;C17n]>pqi\4;tiY$H$$>(mkoOOZK!AN\Ld46:2\2cR?[gI6`t>'H9gMrs>ChAqQdaB@gL6Ep^`qXeI8VZgp?? %jAKkJ[`ch;pW2oWjoJF^QI[oG=AS"\ck6U05h!(lnp);nYoAu_u&t#\tV:ULnnk^@%-FiN)&KbL/!lJo.ldF %cT<'eGd4fu?'2JPYp*X`EED5T/m[/LafmWm4ikOFIO8/b<'5?[h^!NRn %L%u)<^!LLC,1=iUH\&&\LA>$N'h)\IW!FenL/HZgrtAN$1DWc/eme/XHl*HRO]a<_KnuNQgd\?@fd+ep^ZGB\`ms5]^-'ccA.f4, %95U:L,NhaLb;e]f+VN=ZM(\E10?bTNZrTt<5Sh2hq?FOG2jN1nUejO!OS@"u+5TY4R1jCipiQqB %MpGKr]LYh?+_2atiRsc?)2d]g,.\m[3u$4&],>GJJ)BU;2M2HL@HZ-[+A1u;4T)uX:K&rORWZ4c9mRLA(X/1'eM[-pm@+q7790]_ %9#&=>Xnl?EIJ$0)>:RO*uB^0cIKL %'bPboDk_Be[=Nj6$qRa??,4an,%[M-VFXIMh?gK9:21JDJI=-OO+21WH2&R1@hVhi^LU19o!frigK^3pYJB]I<+) %b\H>ca/#qN?@g0P8[cdS"Hm9iN?"\:WuT3$AN1f[GMDpqY!CMT":P=OkI+XW)1W1m/tiW09jj1^kV3&Vb_ZG/3W;U)/h!;a1;Qm, %b2a7mA=CX'Vr%n+EK2"@f#Mr`&N$4,+0b`^NBM*[N]o/dm8VG`M.Jgdm4*2?UX"-fHerG %^Ch%@,a4L4(pTQt:,8M!k+\8YC>uA0iT'#@U[^.4*0rH\5qicbBCBop$%V8^$@''Rg?dRf_(PLZFdeSNb4NYpKXKGEYpX %AF9ku'daj6KW[sML2cY/dc0P#cMg-a_mHi6n(Xn=gGGa>gkDt,"YrfG45#Hj;AF;*f1Q\."!;G'h/1;`$]mg6]jtj`2LK_Vpo:3R %KR4ImJc!I#O\?kqCN)l,\;O?Ij]F?KHj6DRPEIDp;AL5@CXA&&J8lX;.S4D3m5[_)%; %lhqo;7&78Oa0B_0IIXM_Lk)Cm>OejdaN!45#uSA$&[LA$CNAqta/fG-dsb&ODVu/`4\peQROu(Gf[2MATN.:JMB+jt%]44e.>[M8[Npd[F4jKh`%l'`D334%m-J=UrZ/cI\-ktSNta[% %L7P@gQSHH3G`NNFA;3jaA+"?BP:30%f[2MAFSlb7`K#EE8GK6hTil'aNac2*4V]NI&^=!4b.J %e^W1?:Doo1ehSV*HOZNTpX:Oh=-^I)HC5GRQnd/P0clHVjoip*9T!*t+q7akB6mUIWH26hY$&Ms\]b@lbFgg<3(e]_3@IW.c7=G. %h.=21_CJ0_a*%OukBh#fH/U?@=Dc3.GQh:11`NVpAMDr-3`sRK,K+\VGHSGb("2`4c5:2q68IB43p*a(#SD@`>KtHKKJhRV?E"`2 %5(qe2b27=$=S]N!+Z:8@/5I*Hj=ZPY`c0T:iBqE>"J1$=I#._38K8gma"U_<2;NKs6X9Eu)duo5M$!G`Hh>e7X2(ZRr'C=5]Y="F %RZk_\+Z:8`afNAO.&Iq6XjL_6i,-%[htt8]&WE7,o+Hop3C'dH9a!Tt9.Ih7,Dda9_EF0elNbH/NnSb/%Oh!APJe+/?V^>Sd(oOf %Li#(B&Z-L<"ggrYh:89_g5QP"5mXjl,\O0Z\<\E'ZS/I-al\qK7%N"sUbA>;&lq:+C.Y`,V11`>V7S]S[j6AVo1LbbMeYhXmoo>/$ZKlPppMI$ %r"moAl!LNg,;1jW>)I&dU-=jf/#_.jdC1D.*&U0m %Fo5?,\8-)8`%OF%("\bI$h`du"P@C_CNg]UPQ2]SLA@M@L,,^rQWQ=`8Ok$H%l75pS[>/!kjKMbZbtgmX='K4))RY7#g>/0^5]L_ %/?U;@mRT)hfc1RX,G# %<0EfV5%5?/r_8^<]Ba-@9ttG)]s1!mQn`_>j`-NR)+>i9G@k".8!>b9IG22[[@J>0[rh&17&g&uQtP-I5E" %%cDUCP^6VBl$V0`f6/5X3VStZ/j27`LaJZXTQ5LlJVXIdck?daO]gafmIK_)*.8CA#Jl.9T_N0eNC3 %<(C`Tmi8o'f08C6Il,%s,[dBMBLL%YXpflU).r?lCUok?lEfRfmRoUpAk9^L4X0-8\;A``!IM2ZK.tVKCH)]Q[__LK=j%;Ihc5F/ %CFaaND?>!Gr+hZPfFkE`jBnDRr:FdM0#]'=Ec@)E-"'6*io(W,.09>3CH_1mC0c>.d[B4a=Rroi:.Ho0J7[j9#XBt"Ac]SV8CXAm %d]A$[Z@[nA+:b:P#XU+$AjQ2\(hu?%UMtnT5go`G%CI#XoBkfD-8?3Ln]#lP]6_i9;Aa.G;P3?fh."AG[ %O%_hkTC"2%Y+?16+tmt&.Yhj:eRdJ7e4ct(>jEdK,+m?]`"`ZX00_6Yk(dRiEo36P+@F%Y"_E6rn!Y`:7=K#VXIeYMN_Z![7N-3 %Z>Fnf4RX#O`]'I[L\P?J\7ie%`OdPK,:l2<^Rqll-nI1GDM&8=oX8,$[#Cca9]@K7o8(>j=3&u6(5_9mnmQ*=AGaVI4mB6/kjBff %]q3u-j#S%5IP[&FF.6&;6J?A%DSa-)bJ(7)BGhhO4n]h9[1"%f9X*E!^Su(b0p28/ese)])i(.L8.]`*q[H`LgoWM=rSZiTml3)R %Un_Vs)bAN;Rpo'C!5S00[GF=!YQ5@IRZ\6;IUdR/cYL4N@_]bVQ;"D>;=$4B4&\K"Dg[_`"(dY'N_eANq[K3"[alDKc5SU`mPiN9 %qWZ'H':_"!fPb_-*`MB!Yg/`[``l7'+(!GOoE>/IAAIHe(NA)Yeh$8+d+r&0)/'dmOp-36XH]fYqN+=UN&+8AiteT_AkPDpT5A/F %WJsFo$iV_GRO.#,M'NI06Cr>*pSI16JS%3_l=@X;`N7T<25:F'nY9678JVQK)kCT7-6?:@4=\V89="Jf,p!'2Jp6F20J%aZmE4R_V-E$AaP0A\iTl5Qi_&oNH/A1Q$G`6$N)`+UQIs;L`[W70K$K_on?Lb %eJVo&+7!Kn58OE&5oAh+66FTF&>gGAZ/c\oVe99ngKU)DS*(C[Tk#b_X'bXElk:rQ1KnNFPCrmQqOH>?n\e3Be@WfDd %kmiM*L]fnu/M!ml=FB<(k$QO9!h9E]:7Ig&-4.n1ZU'f3ONStD/+'Hm"ASUH3<,L,4/EC%'a3X*fe?'^R<.*APJS`DOA1mjjg;QO %%R$_L`4id<,58o?k-Weu&bPT2oZ7^6S2U8'k\^mmhO6\iD.N("8ecQc.76k"9bY@m-Ru$RhHCu&\&Q^-oAqO5k-We`h/Wl1aD";) %8cna\M*+Afr50!u9a(C.W15abR)<-%<)/oG8kYb#!M2;g2U*?Nb\=Ct,1mp4&Oet(p-RoKfeehl0o&C?46cH)pK6plN52Qco+ZDO %$24+>jsd^kKsmGEV$?d[FSF@ZY?Op:lDcE9oZYd.GVZ7Q[F$G0oa.$khIRGCT %Ej+ITRRla^AtBdmIE8pf*7%(o6j-j?rGtg\U4Do4>5J> %2gpm5NAc&GQ(,LAS%/E0[W3$eppsbARD!M\=/'qYd%nS]?!_;VG3H72B3DcOkbN'MaM@\Z*0E<\/!:.Xe,L&J,@W4e!?O6&8&WO] %fr>uM7s)7=ig:]n\Y"6O!I8p/r%a*'-3mrV&rn1t>Y24V7$+2\Sg.]ULh?S+JN+jilG7ul*->I1E($e;8r?eN`5E5O8ZcD],1_&J %FH8Eh/g>X%p\>.&L[-?kSU#lO&*g(P,KO7tSoZ[bWTr%b#8#YM% %En9Q$.Xk'=!rF[Q#_ajGN0H/22G6Na)Pd%K@4e"EWN-[mCQ+K7Ah-i[D4?m$_cZbQ1^PTYZdcFR%/]O?)kDBL<`]o0k`sLY6D+*b %d7QGdX'h]c*h9i@SBIJJ8bG%A8aGQj)l;qg!eMCF9@dG$VOmInE3d4.4h[+&n7G=geBJtUmTVVmSJf7bm=5^J+X%S&@JF:H&lR+] %b6_:)COlu`H&nVK@m`2P\(VAM0G?7l!Zg+?'>VEtW^)?0GJUmV8!:DBGU=1K+VHS)h6i@QFJ+ajP_7#*f6dHL@L@3rFpFPglL#.# %#7kVI%khC(NinEV0uKGs)i^5iqHj@bGjP5H3,qe**h/NOP)c'^N'5"?M4#$XfQ3>NReh0Y?@L"ViF\b?'QMd#%Tu\um+X.?p'dceH/C>k)YaaUSPO>t(rbbL^_G]s7H[NWhI5O-P4A^`_MQ,=qAa&!TXkm:rE` %fu@U*T6\THpTjP9_F]n%1SA*A#Y--TkhqhZ4G$Ab/rgh56%`T_B:o[!)R07gm@t>B[](jDeqsHllWWmpYSju:#FNGc5m%NM"&eca %!JUXr8S/;J#dCb"@Kq5T(X<1FP5P"'LfM#VXcr//a7#Y>Ukf'm4C'osFG(@l?k9I4-\W8u=F9)XS:daD3l\<(f:7Km,R$D;leETK %6/)2".[nBGX,jm.Q$2Ybn=r)rkT+WHf=Cd]YELlR+9eIp4H,Wa)s-GTV'HOCfWBPOqTXrpOp(*)I'rLQqJl0#cRn2L0/a<*do"k)u9AX!H8G498C<=W-UtUk6 %l!?L[[00TjC-U]E/R_DEQi5!LcPLtV>jOuEV#&-DRI>PVp*3pZBc\qILK]jcg5gXE9t]5ubC8M6K1[mL2N0sS8NcB1^=8=&`JE@7 %go)N7GLSLFo;7f^raj)u`0XY:8Mu9OOYPp<.;Src6:dL3*/WO$ZiUY/?'u+EEbJ-JMJ2rSa!%c]Ds%CUjCKGTbf=SYNZ-n*V %(uMSg:[!:KG.KQ*VK^\(=5)*=0#LGNp\r7g`?APi?#rBajM?\Me#[Z.miW!hC4HuTr/FeS-\^g1^Q+TUrq]GgL=eoT0W %>pRprmuP#!fAa2r;SbFQPFk)U+cDoE_7gmZ8i+6A;UeY>T(DaWR]^S50in;&p&1fSqknOa %oQ2Qf(G`'Z!!`FG_DJ<3+H1S6"@UYHHF[6p>BKFC6g66eo@k_9iF$52_2#cQM.)gETcC4A@=Z[@B;YCT#CAFA@b`a %eoNboH.G7ZN;4?Rr_sFE4)4pNanZg:#!gaU,jQsFhca8J/>E/Do]/(+WdJ$%G\R]bOuUfqft6FZhnIGGdMlX,s0d:0KM'e#-bVg( %Y:d5hGt#t$M=fG5V@!^4ciJs0JT(7"1<`_f>LiOQtZ %&]1*Op3_E4T\Tcq"`N,*1,e/_`fF5I-Es;Qd$NJhn_4?jPn>bqeFB_[3d&3c-kCBIoKn+1.p?!prQ+h_YgN7#r,jm8CtNYCRqk!` %)%FTr@=PKY0X4QbdE9e&ZQ1?'>Al*cc.PQf>2PHWVVAT)h5/5Z"*^G1@Au?!IXQC]$IO!!^Gm7GIL`-UBa#[MO3Y_->C`)ZIf)?& %R"'9#D]Gi9n%.acqV%0tV*<64I$jVre$EP4Q5psD#QdtD$?4,uCae@`f)*fFrsgTgO5@3UafKNf.(A&Vc3q=/F*asT%I6fdEt?jX %)D!'L*.8WZ#$9gAQ+VG5nIfIE#0/2\+N!JQE8qU\ji4EE\Qj_lP>eC"b)^MpJX,7RZ3T^Ls/P32tTn_+4J=lVau1c5-.G1.#1epV!Wt'[,[eoKP1NUUTKq$"N?MU,Y71Q5*%e^0Tf?L6J&@snru@Al^kIShBY>/6NrJ93@aV %/j/_EXtF^c/necO?!ZGP>lf7?,C$eAoLdB#i8EkZQYK:eFSVc%oC[2oBOqP/kmH"a'\:aP]p7iJ'Xl&gQ-%q4otT;)F?=]>rNDLN %^K)\AX\@M4>th@oOZcu4>++N"]"#4)m@282?`Wl`KN?98G>TKW$Rb.mTt4im/mF\=Ne$[jZ9"1:ij*W:(YkPpDB7R=Lt%rP1b1l_qV^QSWZf2(XDGN:qsa0S*@rk@BA0C %mCf-7lH,NZf%'KRFt<+4HqHkNGCeq*f&%4\h6iT>n*U74h5nAL\%<$=0nR/u_;,8?Gb-eRgmftp\tSnPS7@>F1Zhq5aLNRO`Edq0 %;C'`q4'.(n.;%Asd=Fc'R.:La(VeAi5>i%N=PhULc;[2e1KF?,h2G`AB=WV8>bJV7b&Y$PXq-5;j+9-K.*L^&X7T+If=a9J"#U/= %QUj^2kZnMTq,gmpL7*9/2GaL:kqKp\%Fi2?$Vdj7"#\k//l@0:Tp!$hg9$l`BhRR8(rJPY%p)kGLd4XD"(54CLMYnK=1*2KZ[nFH %e,l3?ng2$nF4a'<['AB0+.@>[DF_CgMLDUUQnJJa<q5&h0a*O8+$5bSttPog5'c;&i@Lc3N4e14)NW@ %\6T>Qej@aMGcZ&ml?hRXTYBF4QYdXF<2]CJGiW!k_R%6Qeh1\B/1MjNnD %af!9eZWJ7rdX!]p\O2t=dcA1<9nC7]qEl\p"2?LBcK/&mX6#?CJjfud0LD#PXbl]keDII11d\V %LnU)`4$Gb-7DWkcZB9+KN)":-o6fh2Uj8HYTVn0d3K;j#HcPmCehfSS=l`sqK6^h$Cd<0fU3[V^K %k86TQTdhl=`(1/j(_4E7EgO"oC\5X[U:sdj9u;-0V>a5o@DX"*1<1G[f>c_AgTj1lkgU1_Xp<&n*E1%n#:g6.*.q]q8i%I0*TTXg7_+m-Z,8C:4F#=`L=B>TZ-c9Da&gf1a4CkBfD58Ri:K7R@H!#?BWG(/JF-L4hO(ALfTo7 %1XNU&Rpfd@H[_[A>u%WIQl*O %oL2'4T_V95=>FD+o(1sAE!nSq#OU-/14;:f02jq=rr#US\e<$h]2;-A?%NRP_*j"^`1^K.),HSe>ht"7D=]kqe:b`Nqakk5 %nVVdRmHP>Il128?0LQXXtF^c/mY*nSNQJY>+qB8$Q28P//pL+JdeIefd4Ht?,6#uXtF^c/oR)9(f(sn %Kelt>i]LM0CqI9A_E;+Q\NPkQ'gnJb5LPj?Eg=`&r>]DtG-:C=$,B%`=]_(C^3l7&/'>iVjc^PfW>[toX*Jk@8d_9dGj%o2O6C*: %U4adIg:8?f/:T\mD!+,5#n1*km9GB<9sC23Ehs)MF5caOB1WntSI;.)1?9?k`mVcaBe8)iJ8;Y8qmsD`(:-"\+elRV@ki@,^t.F[ %B,;Y6(NAB@c7Ua;XrY10j,Rd\)C<]@,d1j'#)JH"4^(lJqrr6X/.MK-1DLKGZ8?CI--9>#De4V?G@?a[KGu[WC"Q5gnmQ-qTUt/G %J/0fI*"^QZ+`El@T)=OTe\uOmF)it#.lbQQCphQ/Xl`_gY2C99`aW7W--ngcr8IajV9hI:?i8mo^2g=5b6,H)o--(h"+PE@jVJc4 %0tYab,#AA/0D)C])lSITem'eEUG;a"a1Fu1P$-POU@oqD`1gG9E5&Gt2Iem?#+Wa#"]`O71:X"?][7R93;Oir'Wf2^fiBE'i2`^8-]`s5RW %k/[r6V92JHi"go5NN//a^+2"-JRiF`:EeN1SQn?K,XO;5ki141Q58)`S">F(@,>P&2L%SFM3t]e)k+SG9C#A#5Vn2.PgopAqj)%* %CKR%V8@;b4H:'3f/UX\Pf2qpWe/W:P*V9]fRokh]qpMC#8@;b4[P*L*B^%+m`-frM:\r0+e?4bo`@j+`*+euZPRMHZKd2?C2>=>&Qf=]bbiMGc!GY'%,:/ri`/;;M"+pWlE;#?pZ$eM;&)(L.d<,OMmG=fHt"ls0>=%s(,\3u9n$&Z9ASnq-76etaS@c3;mRVrO@V3u;kqY*(C\G-:WI %LCroYNQh-6)6Ni2LY^536+qBo.kWEHgFubOo6,?BZ_`.a(YRWP)h/7VmZQ^SG4BQr@:k2@fgUs8_bot58A`FC(UEL0hHc %>@=,D4T#gD:h+!!S%paT"+PF"_MAZN+>arB#h5O/NH6_"`pX_+JJq!5R,C4=/H*I\7LV_[kIXU@Qj.kZV27'2d%aK03n*T8#ARW\ %KK24#n5Xd-7dt\kcBS.l>qVaN=33Rq4ET,VqN,3[9-olhcabE8??]K/h?9`Y1p8c<2b(CeqOQ)d5(m6d90(+2i3rRcH[+V7jLDW.j@iR8Kiq0^:0?V_l#7/Or+ClkmXaSCP+Q&P@RSB"ug4- %a@l3^*bHK2UV[qlc5[BV8?X'BcXT'/eAqbZ!c;ITpTU`t,!JG,D@a\ECpjKJ8&@#&[4k %]F4D++=,Rch=WnTjM6&kbRXO;oF*Y+.P6;i@m,MD/p"a?b>!Y8O,'929Lg?A@CJle20"q")7bJsXAqYjX0R^#ons5rro/I:kZH"n %i^.YpD6*p?(K%_trqq5&D2[XlLJEMbSQm.kY\*0AWR<:L?937E@$1q-m';e79P[^+@i&(;%@[,Gh^Wm] %`ZX$bNZU5^-A0Y$"_V<]XCEkuQOmXC?7fGG?E'3)*iA9Na%Zb'8OC<(]hbKj$JnGhfmDfti+"S)l1$Ng?-fE.?N]/r^1_)5-Tc0@8-R8j76)RVGj)W(8(=YH?=VUC9<"Y/l4<:89TILa!a!\M:`4"()':J@QR$pZ %>saKUE0%Q2>saKUO>cR5G4@80c)bctN;1nFEAVi)U5i#TQ_1N5!ss`moT//JX0ITD9]9RLJh>Rm2KhZtDd=/LA!c7`f>Z.iL$g\1 %\h9#_/lQm[W9`GFS8@nW&ZV$T(+2b\Dfp*-iagZ[0f\^MBnidCq$IOu&jbd3B]o@K,s,ecm.^"Ioe>#;2_*PL&H0[M&b9<_c:@_7 %[(0>s_65nJUB%E+($@T.#cO*\82V#]!"h3;c(l4I+=-C1K]( %CgV87]Y`T@KqM?ORTC=gXjDC/3:[FNZ]31)CY[!Y?;6T9]Y`T@Kp!EaO#1Q*Xp'"KF*VKlkp*E)K0h=o27`WB1-^_KZ%(+:*e*r)]pgl?BPE0`eTf;>4WS8Cja=NGiS`X5;k]'@ol2K=$<.# %]O.jo5rJ2IiT*naNOD__;Pj>V^Q[u(dR2)B>:M'Z9Q9eCG=A\%_C3O-fqS"+_p$TtAkhYdFpa2]n;cOkdcP76,hI4eBX6/jEK&G# %g"n:M`\e]AZG8T!\1;SX4CI6\`EeUA]8ZJJ+2_+jojE$^QG]l51AEng-*H\8`Y)X.)j21F\]mh+hs]K!0B(f[@YsNV-]W@&fXV@C %it^@pjk/l4B]h]a/9$Z:HN$h]rnFYZJ!/6nDo&a>K*r+\r%XN(GQbonC[1QRl703JerKIk/:8q(cuRq+@sqaif!Y;%p<`S8dp,W3.m"#2`P3>V-(Q<%KgJ2,aZ!TjjF``=#]`o:!#W@Wn"?R27ri!]sK`j2IP$(gLc%\!;um#W[NBh,_II&-fVon)TG^ %MS_%"$+_:lM:]JJhGN5pPKicWA8Bs$I:BMhmMU_0BqrJ8@?D&W>\WKM>o5,22M1Y9WCSO>%.\ba_q]5nBfVCl=#ulj0#S5-q[Z]du^]YR8P3)'"q^9?oKaEHNGVi#WI]U#DeRiI=qEc*h[bG(,Ma.A8:rcOS %^D)!#LlSIehA?ek$Vfj"f<`AYHpP'a.DfZ84L,LX-D]Xpp-*R34Bt %P"7EoJnt!lUH)5Y,-J]s!4j^n,aV"Ge`0+n6gCI-D1>>Bg`&^@Xq: %IK"a3:69Z30u/em^(-ZZg#7\to/@(^'++jhTVPn?ILUh/QZdQJ]i\-79d@#BADHA6gcpPYe0rf>2Td(gr,I %1h_]kf?c?<.$@c#5\V=Ea_B$48]NWm#CQ[?d',Z2hM-c%aD>nF;*lXYehVa*]H/HY`.R'&i$a0CZ/X"Y5RXp?/;W=$oUT:M9'X`,Z('M%Nl!;S,]5:D&U=P;hZb53bAecPDZ_O$?`ZS_IW_hB:TQlL.Zcl,3c;n3D'V+U*tlq=U['OSa,N'n%G]("p^eBY %lf_=W+(DQ"crqKE&"+u7)#Q:rUF;!1Z#;H]NsXf5CcisLj?j>6"J+'p83rDo?\3qu!h9 %mT;Lus/kq"pFFjq-^G7WOnfe=H0UMcPoAh;,YpQ9>%'f5,_bUC%Tnf\^gb\*E0#k?p\o@![.f%#4e4Fi*Z5sSR^ZN[U1A4F"=M<_ %QD@($P$`S:ZSs$?[=i.@^G%U!=pbhbk"?@2oL^6`Z<,*">ju,Z%o$RBi`mM'op'F;*fMFunCV:hCqd&aXQ=Jj\;lLC-lGO6Y:!A1?,HhE)f68A?Y9hj\nsZ=J?/L2\7UC-E]]Qmd:1gaRI?'U4`s9YZPs:)W0P'*! %>*Jn/Y;len9/=Q'ADb1<8IhG:$l!r7rdE6MZCjdOf,OmrTkD<&]N/piB.Y^?2::?XehpZc^C9\!ppar4: %MiCltH&7>\d'MUNd04N2'L\GoE<^k(Jm*!7JtV,TJ7f4CAH+Ndt?MB_GH/M=Wf`^d-G[A/bV-2S\k;% %Mj(IYLK[5tA.!(&&s8_52*FetL=g9fd)n!M[I?r=r)&B#:!oC\%(4`T"a3E>TGA*AFD]62,jGY$/J_sOa",@P %H>1MIT#jOEA=E2^4)6(YFsUK?al9Ak3D(ke=r8hlBQZm#)>h]X]b3OH[kg\V)bWmJ2p %QkfQKU?-Hq`ge;K4X0-8k_rB%Uat9Fdpf;Y`=k=YDj'bSl#TS4dTS^@\i0&7LJO(Fe[7\)G5*=sr:KC*$Q[_XuC'>!g+AL$L>"06m*<["@br2n1dP?j"1.epNAW^P5INgL'?,Ya[hpnY\Ys"i[VKJVL3]Ohb %_98X,q:]bS3BjqN7Qh/j^ObI3\V2u9ilJhlm(EtO:7ka8'@_KkrMDSo%*^B:M/9p]1@50d`WWd.!.H(,hOr??c[HNekpVep`n"CO %,VC@1U$sD7LFrKrS3,$5-=<$HbZslJ@'kg3d+5kdk&3YM^/tFgfp\q+cU*]3pPgD[Vl;!\O[=oApiB#Me>1kP:Yp'3KIbYGXN1dJs!Q/ %ZY8oHg2Jajcn+"5(1412)h_H%hCts*YafAB?]mk(J`fG-YU(>mf:7'&-sV1<1eXdc"/&fdr]C;#6Ji4&SLMr((-93>:.fV6Qtm=H %WKm#C/&8h*W;-#S/+?O/?s)XjMXIU,cEJR05P:g*^S:W""8GPp#@gbf\aYLf_r=+b,_h#uY8E.Qa:*tQ:F,K]T]hEUY^!o3M-k75 %W((5u3&Z:`(`#0IJe4Q'>3D9Yk:nO[?!E.!_aGq^f.n:"2gL!Hm;:2`*t %=R5aXc)M,'H&MjC!iiKLL2un]8Q:E.%drNh$_:Y`Wp" %_/e7GI%n55gdG$8QqpJH9bX4I//1r\@*!&O_nAs),4@J`cY9_","$2t,cAnh\It(S"t+OGB>Ggjc2Qqb9G*Q=-9_ak9b[=JJTD=M %ep1d\3GgZKV!F8`jL!SsOX,k.BsY"BV772#dq7&s`qs=2;0;5!'J[s&OrT3)$Hb.sOjZ"D!p8TuG@P]IhY'$)PZFRc;4#P^qQ.-e*9)E0O*\2+^]5bKoecCe%"CLRsg^1[0 %?b*0oQ.015NoC;X4O=IA(D5TK"23'(i4QuYlA>);g/T5p %C?tYmik[#+*Xda"ll$\t]E!HhA"]YtE'LloC>;7ImZ&2X?@[Glddb\&+Wo)b0-L5HFm5>0hSp$8q7m292roo%;( %lfT=dNPCHe"]d!tk6bibkF3QC%hn)tS];>F4BQCUFjmVf[5li._^Zq-@Wt',_C?h,U?D0sYR1nM`maN#=oh,`2u(!]n-tuk*J]\/ %TS"U_J^0du$VgjdL)u)=K4h3HL`,itn8e"p$?UBU7uW)@Ib-qNN$npl:!DNY-(C>hVc?-9%V,B36t-@K(U;@tTsAOQ&MoS$cG=#: %n!4GaJ:klH5a">hj1ldJ@]&m;'RRhu,Pj9?AjlDS5j[H"Kr8ec&\&Y@kdteo$6:8n3dQB1CX,5u!Za+'#g54nchh\crGZ`[kO^r)$["X&0oks6-d!d(#LAofpV\ehWji*BW3*\:90DR#?W]8Duid5sqeNbmd0Xag[Ul/%)1VA$#C!qiIN$:+SlB+%;oi!$cQk+8P@# %@a@+hqiQ/%B0rR\qQX`-,<@KtbC8L[CV;n>0og8"DGN+dOm`^9jtV>Y,@>0l:ZK+S8&!K9(Q3RNe+lg5P*]Dd67nn?(u9YZKj'(V %rVut;kS9p.d;T#lq@=m*"R45%ZD)g(3APOql)o@3rJlF!8$Y`qQ.4$0(>jEdUHICAX#p=5/YfXi+00a_5&u-\K;\31,pY1:Y"CU[s<04+]>XL\$>i42Qel`d%[f20i78@sP&a(HZnMeNb"%A$rP%8O@ithb=cY %o6lfslPo4Ig;;5FPcQ_poRCYj^+Z-pE-7:gl>O*bmNS>W*PM$^>pRoGa[FplS/?.Mj0")A=\j=i+-9XT"eJ+hgsuGtmX1I2^S_$O %prRc#*'=q(`Wla,f7JlQc&ZQbK^c2fq/T_BWT)6ED3.l&i#ER"_@]p'cWU0q6e?P.OKJJRY4"S\+#i]NUWn#HqEe^WYU2S*Og6&q %lh]ON]V=G>EW,fr\P[YH;7XEU5A=_F_`)@MC?`)5k%@I>Ih]6rH-5VlJf6W`Sse17ZRa#0X[oS*^+A68EU4]Y4= %FZ`4@%X(5Q1eX+]he9pa`9mCp)T;@J(1]gLn*OM*Tb'j0*i9?QOuQ)IL1WF*Ne8Va*p2A"K%%;Vm)e:8WSBO>_5?K0hBB-b9B3F. %]Lo[`G\^g0b4md\l%1mA@=ffeZ.!KgVmbC.K?@jF&SMp#U1/;RL2NR$TYg@=l4s_mHs;MY?mec;g,n/5qrjqkoESYErO"2JbRBI]^F+K>A-8F%(^o@`p8pPp!p$$*5lb,4)e` %4lT8)s8>"H>Aca.Z(8d,ig"$E'@HsD@]Odk0\>[oGOk(WBn&0[h-9a32HmtHS[9Kbi4cj$5:V<2AHU6hn-o9&n)EH@DXscIf.<6. %8Rj-i4W9?C!^_mNl>EmJ-/R %oE;e^a[X,r1-3*Sbi9Q[?%$,j2Yn$iC'sT^RBnn:qK_M1m2b)RS(%.3mnN=DV,'^l[KWlP"Vu$m,LBdG;u,gsb8JnY-eDCQl;c950k+Inu0'"D?@;BejZ&KR^NPFkiAV]t5M!r0'4i#Tl %p`?0k*4QiM]+fQjEiW=-"4'0"T#8J4dmP^qV88WQV`)\iao\57]EiYNkm\use[mTWrPKj#Q(b+!X#t's[otGQg=2^T%)L3ZjO2c. %\]/,qiBZ8$R(kJ-B&>dkO3QNHRB?@OS<=dt2peY?YSMMP_5ek`%ZKYOFE:iIV4QI].7Q&4eZ[mT)Ei8I?I$IhG82,Tff5PiJ=33i %r@`r+0q]5%cOI"%o5/;]cLLX&d"nWJUn)-18>a#THrFg(]6TlV6E?qK1HCXB4Q[rFP%4J'8]QJMFOq,P$?LY#$J#ImZ[C6Xb%M`;d_NI_>pCJ.4Y"K>Pc6%1[m@bY+-\r9-?@pHT;`:_A,GR_O.4>dO1J;6DEN0Ei\duC!G %ZTW_>cm:<\@R9;\u+*J-dBKIlTTs!99KIFYi=sR)%iaH9:Vp'mc-BiMt;$^ %ZFKf=gXG7MYC\lBr):j3T!#W'k$1#S4Be08Hb)PP1'R;lM/-[k('V0&c$6i!T4he&VtIf*VZ0hfrioM$aI]PBX\<.d>s)>Zr&n?F %>+&PEL,)P;73gYX/Gffg;@5p:;2?i/^3+I]aPQk8B"U,L/j!/1XCRR9Wm-eWHks<6gu]Z8SZAA6AOe6eh;EH/E28YCA&B>7a3N4t %A-CA]%HHo5Z?,9#GkBip\t.#\?l*VAE]buVm9HkBoB;11gUR`RQ,Cn$csA_ugfrEiV2*%==LtI4f5Ng3ipHkY1$e98jmI_[5p(<; %7.b]nG'E3"\C]UQ`8.hrDrFV^c9Vh.l\=C4EXoX!Ui%Tp+m8X37)N<%2CT:(deO^Z2CV\^jjAWKD4#A0(:2nh0>MSb^%Ujf$,#gn %8VkYeBr5:L)8U&aNXJPtJQXTINiQLWjgaYVF*hX(oW"Z(VD8P %#&<'p%_kGGTSE-B'H3p$B,%*EJ9N,uVVX`cU4]k$Nn8^U`3UE+bXG1sWE;cO$m@8=#EXfJj@#h^UkJp/*U%b7VuEK3G:q3#*J*u/gD5_Wed>'tH!XT;)@Ri"\I'!S,g %^CKf?(*.37:t2EnWU.6KJCF[GXBL>B%SkWaZSpUc/D(OTa0VEV\=RPV(>BmCSp$0ab2i2rN1ej!;-f0P*hXI\RFC/&#?tA:lf)7T %.4/tC[F7Zb0L.F@\o;7un:kQ=:*r\mS=u>rq[-"W<_i`cB$3E"P('S2`Mbu)cVehgnT>BhrS6]TRq)AbRsn,@IHg3KB&cr`gR!B/ %R#PIkQr]W*D;\CN)s-GT,orHAIk!a\) %;F@TFhGuk$^:n@4Rnc-Bl_%0`\NS2D*IVS-MDDl_oX&HaZajo!k25,?#e7o/?8QbYbBOE;@NUBp)%YF3&)T*if>Ng4mRt(63kiID %%l2!UVB.8V%FfZ'H`iiHESB`[0-.Hl?^Fh;\7);EZMAGLdfXoNZEXT2U-l9Kp@/"`^Ur:a"GH?F7oP`]K"1c92;0+RoFcLcZgkLg %WPOM#@_N5p(Y!d)H"\BQ]NWThF2?J6dr(`7d:hC3!X#eSpVXYkT_AoOC8H^[_5X+UpfTiMgj^s3g:PpuAPs0,PeFu=3N]p**/5M^ %U3@X`&tW1Qe4FAO8*0a0\Z)tldpLM7CfniACul^D[g0'KU#nBuLk5t;BK1gWlT&E6#S#mi1M5QM]K:-3@%LbA)smB==-rUHb/\?- %1^qIU4@m'>>pYR&d%-fqn3,FPZ(#$nn%g2-!\l*J*M[X'plTVD2$@PO+W1^+m+:*liOmn.s)_3&gR2*R=Gc"k`Y&TL)1:%/iA6SK %$dG"/m9XkX?N#&NUtg@Sp3i9qR2%&(#=`1<,!D3/%d\S^e4qK^_'WR'keRpCFr>J,[ki[SjJg_s*#Co4(pdq^NJ66N?>h\u:cbB! %hq"khl+q]s3Z-$0`H/%>neTsBJI+f2i^IbX9'@&a!jQekZ8nT`j %I#%CA#Um/Wg/fqu?f9iAm&#Z@]"#"l>=p'_1E>2>aA@XOrn#s!F@ie*lLOIe"^0T-4C)b0LCl[Tk`!L/RHT#CD-*&` %:RAET=.H23`0H(V8s#rDP&49e3):?hThJOS3)>kdgTE/KShIEGG.0*kbQW3>5[6$93_UE]"j^XJ33h,2)?--jtnSk`PNlTVk1[<_d&D-7-NP`um!=MAr2V>KF$YJ[I:f4s!VB*$%CA$j,,\_NU(=P$'O?SUia0_541&iIj%=hYsuhk"Na;Wa=)<[[8O-D$C^\5d]afQ*V#!.d]cRb_YY\JWWg4Eb?/<]iJ%RYgdOP8#%-Vm"H?s^ZK6T`/'=uo %GXenE*#EKH%*3GmkI>X-c,F]tpZlpe.lbQqag<$a%Y5N8H;1TX,nI#MJBfXa0%1Kph_P,%9%K+W4]*Jkq^gfE/q8EPQi3TQC %aT;Q%bR%Q#>h<3PW6XMU0I^b],\W\k;,LjIlt; %]fA8^$E!E7IX>.\mOi^%K(G#ECX(ChOfiqPKi:%V?LW(fkcj0VA6hpKJ@heU[oa_KRC]1QHX/9iC(gjKX8hLV#0g%WSCcqn)RtdP %;YmpqbR>aa1NEgGA9H0\+q^8@6Pn]tD^hZ@:Ba66!j6Wu,T9f)]V1bMp?TuWi!ms#C.[YcVEm"n]QB/A%$ZhS("R&4._^l.=t^(Z %k"RfD;=!pZbdT %R'Htm_(bme0,%JVW:aUJon"^rUXn`SA??Y8WL)J+(TGuDU!sH_h!l/pc/d$2qHj,ajW@%$?4/5Hh %P3#:71it+'%0s_A$b]n,-d.]ojWup-X]NrkpY]`"R?O2e@MWE$oo`kBamu6*01h1/lc!9*Z?&RVqf^dL+,qj>#=N58bjVP'E+$,# %d_FNE]k/m(a$h"m6+9pYg?`Bm5"=o4U1=I;V^sY@#OD)PG=9mLn9!XeJNR52;[QOe(!+i-;dZIYY<\[3EupgOgPk4X17VVE\J+/j6?fa.%M\*j %6LT?GeKrMi`?T_K^8D?Z'uIm8#4lrqUt3n?Q^@*N.c7[*CmWuM*JX#lolSGh&I@oKL#?<)Ge.:ThfO"WC"7l]\tlR8%tQiKOt;8K %MP@WgN=9eV+km0ipA*:_tb/U2a4-q3s>MoSM>j/c/9=ff/\X`W> %ip9q.Yu6'L&8>5MNo:DVXcljZm;9n,dpdrj]??t(Rd'15]=VH\Yf>VhdTKHIc7Vr*(0F+WK3H&3@a5WUFu%o"ijn`r4s1nc(_Ad.kpG%7(N!G$];PY3`(^QbD!pf"G+KRGrhZUpA/AUh2GalB"\LPSb];AVQ[8X0)DZ8: %PbnaoQA_78l4^+)G^0DsC,"\78:_]E##\4^.Zcg,'SL?\lf0"n02+cbVZR"jg&nE]KLh4*?6?iF"9(-?:6.`o6<.1NVMSiJn5 %\n2&2-u3hqY_`9W6186i*/As>$E3GN#5ZN0r'K:pe>5fkB(X<_eYRH_mUodqbm\]:V@:!TOT`o]5c[-V8N]DUlFNm":3ml9OMi9g %bhO:]B5R-mAm!MDPI84GRc,eT>@>V?"(P21lO+@W.)>@AXS$%AJ\aK-lN:q"d.l*@/m`j`?Qj8nOJN_her.fHL"dK>eTrt&^$Ibe;=U!f!D4R_ad[eEK;.(fAu**JWO8 %<+gIZ_D&R`MQ8cnC@<*7HG>S/,8,ai(SW/_L10kGlI37.(ktrtQjE1tk;A8;Ql"BA2oD&bXEaE(l/kPb=]6%Q7EalQ'DX>4o$i7O6N*VOkn$7-4?CWF`0"Cb\K*a8U)60/SU_a-p %"k*XCoX\Z]]bi.Nh=LWdpU_c_(q]d(<:f"&%&rCg`if3LI7]0u$`@`!X^+8P>pNJiIq':bZ1&V5XMum+qh\E<`mNEbc!`*s(q[#H %gM-$^D=!u3g?<7dVjPb+;@h:d`tg)ZfEJSkoHkES%&*8kjr:od8oe+IKG_>JDt3)^g4M%`5uVrR2=`LIab%D>rLQX5'i]''G/2c' %d-s;4Vm.bWn,rJ)O9A4gSL@-3(p^h)qM/ieiUE]84=-]0WIb1i`j;D'sOM>DMg@[HEktKcZ)]&!igP8O[$gA.i8jXd*:_Ia*mDk%'bqY7Ep'%]/Kl5 %Nh(a3\+;L?a(&'?'8ua:;o?`=BhdaGRES)a2RbKqOjEK09f>%riO!Xi9Fg5'$/1e`1pMpj/rm=7n?`F)nffdV4EsZ5H-T/EUgSu! %S]MML248Z$1-Cg&h*E2FP?AgW!d,i^,RH2[P0>Z%E&P_?*mZt*Y?)l=n+eTP-chCCpPhP%U#5NA1&JCW;Gs@iP^eeRjeS4F7:?YS %><$EKP]lI'gKO9CL8dI[LYWi[BD*Y12m',-[nj+qVXm9pbgYul:$kVt$8u[QYSaJ\3Q)Lme]9]S:,8l4WPmP+X>krG]be="flfQ: %X@C3nTHq)e)..A?.Eu2j3I-=pdgFLQ&"H]<4KT0%(SA@WjQT8_Q>UGI:L7K!ZpNsp#b"gSRoTfaY-bQ&g]A$@Y:t3)+m:M1jqS(r %/%#2lg%,Q'V\MgEnEfr.amn;;$^r(X4?4JG.0[qU&)PqBpK35Z_17MNi.,4Y6B'@F"_kcZcE?6@`i`dBTs9Ni%tcGa*#cFsl3e.B %+*.4%q(1[K`eOn\0BVH*s6sah1)$QQYV#rCj$S/_!enXHd[mZ-0gnJ6f1\`tf_CQ%nRrpNBPIed)XgXK0uV(eA1ijICY%/5OH!OC %SQt=cle.D@!K+K_r-uT*[=uuuLJguIg%VS_PA:g3`.i0clDb?u:N9Isg+N$#S1X0'nj\l[!emm#OZ2j1mE4Cpq(P;af66u:A65@OE)o@l:ptOY.ICjO+:`,Em+3W,g_J4O!f<3s3EV#KC2 %Z@C'[cWiV6hE-Hr?*^"1`(qIN:dsW@f+:(&&>HK_D$P%Q%<\$Vb]o=nF2)2)A#WV4f65 %[l5J>cTso2MWtO:FP5p3g`"Vn1@>:0N6NIQ$er3$BZrdlms=4\$l %3QXS]eY7*UOAql<4+i"[jqG&L2/T<28I6Jk%bCa/LlPOs,K'A-@[Z6Gj_YZ*/?!B?B'u77fCJJD>j9CZ!f_Fa79W*V[rtksC%(Ko0CCQj4Q]^7[:E %)n7V(4h1:.b*=\D0/P(J<@6G27-GQIX\>7b3W%?_Fc!V`Q_Q=`Eu#3$R#qTsVr5bM"bpZ=?3O]M/hj1Van1.t50k8J*j3mPI_DO7 %.kQRt>0JD:QUXQ)DkC*&6_G]G,]e?=@/.2EFc18,f`678)GBPIY,Z0E'!R_?Pu(F:+XXk$69fTZl=Ip<[JW6c6oZHi[O;`]?G1Q]Q?W %qF5Gk2k$:E(LtV4"WAGnItjEkT)e$#4fba?E"/_6#>@Pp!nXk::Q+NR8HtthaH"CS5_uQYqG=qa>4\[P:aZ)40j\fb*7\!mNU/\P %Vo(V@l$2]%-q>QEFBg8oLBhq`&&3Go!-eVo^Z>KHBHG&&OC(`f.Aapuro09n5t^B,X(@*W%Q#dAb!bmi.4Jejc0EHEP&0_oR%od[ %O,<,qr\b[Whp8m3P@iS`N#9e=ieU&4'T<=?Y1[L,8H(1s>ej4\V9d7mr*-U'e(>V3kMM.&ER=U%c]+4'3mQl(2c^WK,L)n+qFW]c %WP7"GPgR^l0BM2T'^RFY9Y#-:=?083cld3QYOehKFu4Vo^FRA$@W<90:3>OR/*`IAJPRbDgOH*7(uCOP;D.D`u5D3eJDFcV*!dJEgH*k=-_1S %5NSWj^G!AH'sf[O/*P"'cDRcV-1BhEh*Q>[lP;ML!o8=WD&?4[m!0DR7jK+93U^E_mB":8cshI)bbtq#URmq,N&CUX]C_fc[L4/WY9",`?Nh=j*MlN^*qK?@hpom$UZL(Ahj-5P'(?#k(QuDLVfD^ %e@$>nbAV\I'tTT_Tb\TRi+C*_B68$0]"CmurCnk4KE0M2@ho/L#XL'90VS(k/>r`Lg2S7b@Ug0F[(urV(3io<67k)\O9D9n)m_eF %L+(P\@i"DJ&qjG)b_"AAJl%Ab=o@meUSASDZTr8h.+D^!k^Z5=Kj*it#LE>.IIr6Fcr9g#`[mhl,bZHZB_"JAp@XUh=&A;6Y?T.[ %F*2OFC;JG!l9uS*)ffW:P,I"1_rn+>GQ^c&,0*2!B>Yt\*F*W0"@:UB %V42a6/@Dm1@OLURO17<#Y,PK+CPNrP!U/&]4sJ*%49@[2Idn!i_]pG[2a2h4c,59+5aIj7Hj%LZ#e2KNnI`M3\7A$B/]Z:h]'%1- %WV=7@Mlq-\@MEe49Vq?chknetBe66i1eSWi@Wh=urQ#-Tc/MC%3%!;A1lF$/!kopt1lF$/JeP*(f/u%;ik$cE=.^GVi_-T@Wgc"* %$f7MR1G&0Td<#^cAQ\0o$HDsZ\hM_]*%]WEf>C!h=Qo[?TT!b!^CiT&Rr!NKW@(:8MPF00J3Cko0EtMoF8DCCW[9!S;G/?\f8ES*jBu)m(])l0)&E(OXi-')U%9eEpJ$b8Koi>X_"Am,=+S;n&98Mq\R(f:4a\*4 %#^AQ6_a`qi4;\hp^LHOZE7FP0PPs#IpbiKQ7FZOaB!I5>=@equ\/"ii)M6:*/hhrfks %84WpI_:fVp3uRBnl-tnU-ectX(g##WIl:_U.<:WEepsMS0gaeXlN@5.sh\V@c-dobJdmR185.?3TkWX!PKK*qI73ma-BHis8&IUS&=J@2DcR;3m)IS@= %JEJ4Td""!iee"XlL7[AE%2VuAEsO8_ %QaM(>\A@IM_(M4=7jN[>pF:&G01^"Hi!Z7^RS)iuH:MrU?QSD7l?!'bb6,F3(?5b9lt^K+0D&I:J1hH*E[HEY"CEeFoaDj.R@j>S %=.%j_,"!ti^a7*]O:0?9l3"/D&(=j+H?QB.f+/A@f?@1dV?#r7!DYJhgK2to]fs8(182:CH_;;F9e\ar^d,:-*ZVkE4WnjWpiqWO %HZ6,(3b`hF;T&6S*0I;2-Fa:NP'mk\00.tBN&)ak8&WO]=W%f.Nl[qE_g69\H-Dh"CB/Mj(\U*(o0iAi)_L'W.`6?>Pr\S-<;;6XT>dO7*F-:(<>J9]Q_3-&R>pTG^#5[ %\]fS^;a?Fe5`X1)JkBd*LuuIre#joFb2^=;-d'V/+&k\Pg/!E(b*fhGcYh2&!WX^/+W2if;7"04c+;WZ7bb955jN'SEr3Q:]s;TD %'=&KG,TRD>%/Csl0/"IHfi?JkZ3CR<(Usqt]Ghtg]pg#kDaPL=!9^kp26R4=dQS(+$'GgY.]IAh9PhP;lbpUOmqOcm_g-S]#& %:G[]:Q!SJ#Em-!\F!uih)YP2>Efl_$4eVWNRMje<^WeGWprCe!G-L.KVRVt8J-Bf"3:DiIp@j`1*Hir?[=7_A^''alX,XU=O/&n^ %>4nak:]GA7`1Agp>#Z+ah.Zp;=dl9Xf7,hua$kYWo"'Wk/9L %37'ts/%Z8p4ZM@j%Guj!Iku1QeXh1tnYENOm<.!HN`sc4bGuadg?G_U5+KN[%ft9uCr+a))nqs&otYuN?o^tFROq*-Q+9,a-Cgir %?=H]IJfhNeBn4.4A$.M_eT!bL4>a>:HjC*IdS@DsK"EHoh\9@Emu7i>e.*ba]$\mb3]Ju`&:`9W&]@h^[0>p2H]Tp1EHOA00^3"f %Yi(lZnYtAj*5Y:l;;^n"Rs4TCcV=$ATDn\bG2W1;3D\dEtR10>df^DFpJiNC,!n'WL*pWU<4MB %&+Dct'.fA1Xea6md!0CLYP5P+14*C)m/-2MSY9I-IkPF6*[,()!Mrai_lG@9H10&"=PsGNZ+_guFX>(H&QH-f4,-N\=@=q,#ELSBcD5Aa8BQQ\1[1)@unS %Y?.@We2R,cB78N_W`T3eCK?bUfhpuOla>HnO]m@Pk7,b#WMD/L]9&i_2`;=7j")9H! %TTrrb41Tfg7PibT77X%%\UJNZG5^46[.1U[XhYinZfCA2de6(>pkU=9Jsbr>@@J?G75m]F:17SDXP+0P&3V4Vf0mo!t92J$n454' %6"b#74D:h*=tc9^[*+`TYqJa'r7,"WSm5I>\]2*QiBZ8$ZuTC)O3Y[?cON"`$e^5fPp7P\28Koq0$c@TOaJA!PKXsQ&E %Rg9^6G9lXbF=*GB`TJLPe^1+a/F!D3k\kB)+6Yb'PYjNkZN?R^[arfT-5Ok?R9^:%?220[>Z69)bMOE:s(cB8po]/Hs3#U/T]HEb %3js1O:Hu:91f.)HkB4!DD.fGTqjZ:9jhGPRG]O.AA+`R;9%L9mjfjU@lsci_^^7>&'u7oNSLU;)]VFJm^+r]=B'ChFnUiT$nOY!< %.Xm.N1!?=Ke>r"'.5;oDmFA?%RC?p*a9,H"mOrR\>2]"1$d3sDb4pI2> %\Gf\*b"m)D"':qL4t1lVeF1s]BDKr6`.KQ\V2OrA\15Vog!O`j^"CF/l_nOqNRbn[&)]9n^#9ZsdDB%O9DID5YO;i!L*jKf+`Iu2 %]))#ncl`TG'3edGWWWVp946"Hk%XdTR0N""L$%A5_?Q^-$$Q#M+WN+Vp:3%DBa! %g>295@QZ:U*%ocectla`&DH(UEZ4,@__PGaU,lQCrYE3;1V1JX^2YfGJs:A,Mo<`r6@XbXHGds2S6CX]Cfj`s=^)%\jsX[Im;Scr %>7c7'3F#=Bi>aIlIgael[TH["UZT(gG0=eCs&c9jkTD^sVp]ho26FEX*@R+@^#[cE3B>j^)f$DoH^(`Mc>ISbHfTXAO;Rpq[,/XsH$FH]4];)0-Q/'PmVq4mDD8=#i+%*7( %/37tB]m\X\h.bu"j5.8mk!IAM^sKPo?[I.skY++tS^>pdq+:KCRQ#_RZ/fH_+I6oF>7@LQp0<4`g\@Zn_jXfKdT-3;R.9X3mpGr& %\hV:'E8\=Or#GG!(Vf9LFmAJ[^Yh=frc %`(B.s\&h,JH=fE$kds[]N@j)*T/$BCFkepg?W]$CPGnG<-d1O6f]"j$WC@4uoTlt/os4JbJR*'BS2S\&o_NdcT+5*"f$2S0N(1QW %d$l!BarC#K1?_t$nDLK+mm$3OGkhhXp<$[I=<8hQk6.@*gM+FT>#;<2r7h3UBPtFfmp:L7/ur:F]Onj>/;:?4#%rh`fZtonnP6Nu %YOAdVc;)NW!qY=,]rYQBeQsHNg5Z\>?te<^:,W_[2t-"u@Qpe6R;iFd)#cNO\Ba:(*T,m/Hoh^^Di.=@IC"1\V*09C.;?>uO2hQ6 %p`QhhGU=X?boi(m(dA#Z$Qju/R=pde"`lh^D$2'UN'&b%p>!O&D\f+>0O@GP^Cr`IQuFBnlk-^Dr,'2#]<\(IFmLq"qn-\oc+0jW %iTDhI*gPN\JYo+,S<:jr&j[P5rFs.0>&nAQr2D5tM[1t&>oTi3A9.-r:@R3+aPpS%&3T\;3@-PsDJ8^\Kf+4F5uXC8W3:]mVsGqJ %POXVSmAY25^NV!q[$\%/mk5Ru(q.<*Y6.i7[/(MB/>C1`e]X?t.!^^\qIc>DG!NRd7+9k`8uT/T,43]d\"N-?R%PU"q+/-^PBA^h %jI9>ZgWe&J;;A`Adu#o](PcNRCriKO=CrESPC!Jc8?:7a`/1kB#t[,e8qeSN,es1oc+8"Hfkn#MM]mDnnC %NrJIT*^57C?]Qbg7L3W=_T;>^7G4`:mu1:Eit"_)B9D&KUH=D+kCplZ'ZF59RrUFI/W/O=P%7U3;)3a0aOj@#n.t96U1S\c(>N'R %CJ@HpNVjIs$rFg44]!Frp<[PT. %S.'Ok6ogeZ9`.r58%,=gFj,tZKHE3UWFT]Acm>PVaE0.P34(r6rYPmrGV@ROBSTdHGLaemAB\1Pao8e@W-F`Hbq=5)ZoOUlN8f,*2B.F=.`&[s;cDRC3]`e=+?c"Bm;]WE"tT1X"OXoWQu/9kn*RcTGA]19#ub %0CrkZaJ9S@(@u4AaJ9Rt)2t9QpYXX-FI6RIkIiZsBO@C"*DDkXY-fQ[\70dt.qiup+iAZ9RWa$VCaH_teFnIYJk!rk#7*Wl&lWj%)P6])0rR5aQ>:fkn2>pdT^_d1G$ %bB4@u9Xo][In0K?=9B:MB:pn?n!gtLhT4Z^\+L9S^i?'I:KW(;_/X`ZW4OD9mLgU?mG&'mB%)-g)l?q3):!M8[JDeW-GAaRV8#;;hdN`9u,'WNVH:th4=_ %%tj`F%b2t,hr=B5S9a0_of8Xamg.HR(F_SFN\YQ4p;ONdOJk>X.0)ra]N?/a&)Uk@&P2Em82'0JHKdG:I=`&%>QIC@C]](h&m#'r %+hKbZ'S,6U63n/o0-2g9;CSjU+PA"IWM(O@$m*(#<-7Os(SZ)=N>T?f*PK\'[j!8U(skAjH.s"\qjBXP7Lo>0;LHXU6T5*1JDOSX$W%3jB3$]>5.TIgh1Dt %OaFjS:!6#5_E(-mBk<6:h0&I`n1WM.J!MurfkRqS,NO\9"24[g %k$TP;Ag#j@Qn1$)f!-W+WI\faIj9+]>)F2R:22>0/Gsf1Ad/l/]3'fJ315?c7&l9u:3Yh*Pdh:s %K?Kqb>FAaDeA/F(Ag#AmnSe@qDZ"ASnS;3l6K@gl(>rn"]7KV3"[rT,#(j":U'@W+#3)Eb6,0Il"AIT#f_DH0A]Bi&]3*lAZ)?$" %rBMs\<=5/:?A@`g)5^)J'ItsNX^bdS@)U^I./1))>dHK#gSKb#.4R+b*=mNPmNYVsJb5ot4>0alJ7ZDQ3@/j@i+<2Egs,L$]:ads %anEZ:@keKI_J3LsltO7YTtA"E]s569/.2*r#Gi'OF7=gm[qWH!WR/5h#C?*Ie_A@tFo8@[p.)V@/U&7J#PmMkf>JaZfh8ghof3I#c\$`#+/YE0bg02q%(/E,1ZaJ<, %Mm3Lb$(>$Oa[NJB>W(3#2RRMS(M@MTRp,;\C2G!/D^j:fM6aOfVA=!YD_mbaQjaaCC[!#,.E><$):KGEj/-CeiQ4S?6\EA/OuB`; %]/%[_OuB`7[oeTk-#IB_hJ93p-#ID53YlLH8Xim_=*.p_@Y)\c-\%VPhHrOo$P076&6(WO`tq,Y>3NCcY=A=j\Z'%Yoe28rUm<11D4T21Ci'j(PF^Zd@6`FL9Qm=g4Y6,91spB+;2,LP*N[ %kHsu,eu>Qc:0L_'dp&s(;tGiVDgDfiaXB59LelAh05e?#?:Vdi2?DZt/T-$VB1mUF^Q#W-6cjWu!12@aZ@@8Rj %r.:n\@Jd*bfdq5Zjpk+ZeWMUE"l<8([d>E]VC9kDEXW='(fHDcP%N*?@LnslQeh&Ue=#^:1H-6[8i)rRbM6n^.*\tg@W+/HlG)NZ %6a!XG_pl^ao_uXq9p"?Q`e8JoWs]qQ_mE&oKQTs)f?g92)B-/@&^JH^U;]O;\ss(E/R1Z(C1s"2\;$U2!aTQP\;"^aC5=8(1iWsf %WZds(f#0HPTM\2Bs;E;kbBY+bSmK,JiS[)VpA$sH"Nm?\QinaE:Pb+gg&;]jW<;n6RqdDe%;]4_ZGY11HKoWBX? %!Gg[5$KggbLNUG)OtNo2GPaYU7u?P0(tLR4?mt>lOffd0q.XhS$H'IAg/8c*a;D#_]F.3=TgW!!-;flb\eKmAfdW=-iJ&sd5qCa; %l0He,2oL1L=5u@#L:CmL0H&f'dU?EkdZHSZ+c0biINtng)3S*Vf]/0m)9.AQiN.UO^.f>N?$6i20s4/X=;OjN[(%`B@9qo"3'pl: %_QYZUg#k'&7)HMIfFeR9q''Uo;Klt@2!>U<2rC&1YbLDT; %5o8[F8CHZLF)rN$S3O/,XY-[_cR"_6\eKmAd4$nN$H'FVHPaN./qm_>@t(_Nho-Mbj\Q"XLF7c10);E.-*5;Oo2!AK.1GM\k>i8U %\eKmANTgo37q;qlZ@+H:>aN=30'jpHj15qZF[7B#-*BmL=;SP$n[=ajWPt!\/7E92-8hr!@9Ak%?,YB!d\bRu0*_ %8Ximn,&!dS-#ID5r&t?D?I72Rl6=g1OuB`;]93=:04ele-\&*&lQWj5PI?daWF_G*[MCE&FW"-$cEN53[A6MKd/.XtGSsEf-\*l_ %j'tfcgNm+N.0D;201eqCNl#2/[A<+_B=CAXaI0U%8g+\-BPIROO,Xu0@qrPX/BZP,2RUoD1>^TF2RVlXL_s>hg=3tQWH#A4FBB@' %,P+c$6pQG1#HCT_X:*k+OcG`rYV+[YA+lMt_n(Au&`m]*$1"nq9"Ldo`m8[G'<$qW)F"UEr[:90NLp@fG0Fj;Yb)))2c5U$R]nF: %]^QbCK(bMD=u%%%K(bKnpW@;k$//VWFeR(VVujni?Ra:K?k)FR^2^QlMkmomP8`&L0W`IN+,`h/Oq6mLpVNm3C4sL9TG*L?jl6$E %I.!KeE]*H`hVjX7YcdN1,q\a_9h1n#&ic1`Z20/(^&Fqd7b/1%Gl@9=>Jhf?;4:`.d&RURT[ejW..oA;9[_Re)T7Z6S1(tN9:O%h&/l[kRtm>*N+?!(0kj15ps1[r@C %RLKFs):Xrlc%^gY?*JCHMeb:4aeb/93#U9N4,UVZL*"mlku#sI20;i"$*LupY+\?CN-7\i%5#R2=s'nGiHXM?&j4W`H_U;0/qm_>^77U&XX.h!J[1*>[A6MK %kP[`)lV\SN"n.d[>>*]"Z?r]`Cb9@"b:jfM/SS,kW#DqLQF*WF2)76O?I72R$C1c505,+2:F-r3ISbl#E+pp9$`@XX.h!5lq<20j_lL_TrT'0qQSS!iS]9YV'$0UDtjCIMS_5F+e<8L33NpQfX$D@9o': %73+d@ghRqhBW:O.`q*Xr7n\i6L"9dP\";L'1;_!)OJAX!X:%1V[(%`B@9l,\i%VYDm4DQ21E0SNp(ljaMSZ,CX:+qB74aFSYV+_+ %W)Ru'<#9j1WOb`.=;RR1O47Gb_Rf6e-c^?Y%.!HtF]_p%IZM[T@&%![900/tG,o=0Q`@8BS<]sXHr9QpV"hNml>K,'$0oK28:!`! %.B2S\N1Ad,[b5Tn>ppLrTsE@u,JHLm$a7[0`ReX&=1IS9(Y>K;XNT99-cL3WlmT5>bDC4E$H'HFg+ik>-l^_`P%)EQen))G$RN[$ %%$MU]V(etYPJP=[>meK\@)bgsLn%mZn5C`T>mdDGm^H_F2ADBfkdp7?)[_=B)&g&?0p>k"\;!72GY?9,:Am#n6u'GMC>g(W9ldIA %lJ`_.J'[A1f>9E;W.nV^Q?o^ms0S.g/Z*!]b=uDGk(/YB+ck'Qao`kK@!7STh#h^[.]!?]Ho(5K4>;p#p(s^jE\\'skI72k]C;&E %:)Ohrfqi_nlYlE#*Ee,r=b]Xc0c`"XM_KKJ;54Q;+q3<]>%O("o4sY#=G3A,Z=4?'jFH3]6MJ:hd48ta[8Mu%9?h@8-FdLF;]3)s %^eX?#SY,"0-jmb&KWX(-AusMHhQh;'n[fdH_13&k_$IBYo1/+I2_c/DB5J=Y`WOp#gK)SskiSV\Y-nC%,TRDE$Lrp?[8fLCG&_&d %pLS5onW=XsMTo>=A"A+!C\BPg+_5<]Z#R[k7*#.s@=Vh>YjG5&%9\6I3@Yk::k_bL`G&O*54TluIDu6QM\s#J5raBU>%$/j"p?2qk*>Y\Ta1TS-oJ*UF]BAT88I"U;Tc)3Zqki[q?& %kD_$&H8,hO\V.ljBU>%$0#NXK'NGQbTlhnGg-lkF>,6og&"2HoNDNaZ?'ls?G@W:*aU(`'9orM*YO_(NGHOp8N,dm)QO=T=-Tbs=QY3ki^k#.k4p`pE9`=ec,;FD/HVDX85NLdI\+'Fc'KBj5?K2PkL/&IUFL"SZ16Q(&"mbL9l7*7E;8]2!-cZB=[Ykk0AUa)CjicjN?@1?b^% %TZHHc\`+.hd`8h-EtVV(nuN7FGNPGJ_FlSu/*ufF%h"3sGYs;Y9GDd(:]EucIB(:f0))a(BNUhS@K+$0Wo;be7;/?1(&Ali/Y"@` %RJC$5SPEPu#C7D]'[piqe'ghmCg)i([_&dIpH]9h+`C`_5N2(mnXkQ#)HpRf\e)"8YLYbb(FphJh/9K_I+X+S0;S?#jrLfMipUZq0i7F8)> %SZfBB`.r]qL,ZD?YVK:]1?_?(?tHKCAb<-9%T`#TJ+AADi>W_Z'sr^EiQ*\E>pMbOR[No<>-C&:ktCgrAUM<(]\8T';T@YH/)X"X^TLbhT_H0-eNDVpX."Y5,'jr+6;XA2blH"pW"cgll0GW<;3qJgn/?#0K9GLoT]feJQBfKjMjUum+efXY&iBccPI %62mSKhP[cmS>#MTh*pf2+CmpjReZDgZ&N:9$!nY&N0RSgO(=Z?YJ#.,0,MckDWZHYCk7O_UV!X)!D2O6-ao;ZEZoLDh(Eh=>c&/!8kLqkdU<5UJf`[Th"(r9!FYnBQ^U&?*$-G4M4"IgA)lAH79j6_KU%ea(tA=%u9an0'P`TH-MKj3d!];VBt8%6jUSiCX%*ENVS+>JYb1'Kq%NZKdEltTdsNZR"CB?sZM2US?nX'@5up>3;A*Bguf%Yt?>kigE*XJ(H151)\%-T*e`Pa@CO]f-@! %EtrfhkSCa+/s!=)j^9*&oD$hT(Y^t=b(XB)L!JSN-ppLcDP8j[20AKSC[/JnP'$?[(-:XW,#(RgG&[phY_eC@L!ENUj$^L=geXdH %qD#J+TmKJ7M2k6qTW9a%neU+L#Bd=K'-1-^*M0MKBqjX&U%;1*jlkpU/T`\_Xb)QSh*U;;pGGJ?\l/]G,Ce1M6LtX5p!49(]S3MH %6:EX&5?eV\tF?E$lXEOMo-i,ej=mG4uOL7G0JC.6H33qW4SR."nN1hX[1tmsUf0ro`Y?0U!lK5&ilkkKfj;B`$Fps6!"M:EP %daQOrMCb78%n@R_63]pMKu^`u4;m@<$+_nb\]u;ISr@*ti9`9=#L1+n-/4\fAh`[?-f-KPMcsSuPqblr!/bHT7 %[O)`?DsqNW3[3g5kh2"[i[_j>\]h8'D'R#@e/D$gTIjhW)m89mcYjS-0'RNUVj;K]RsL>?To6Q'r,RG[='7[@i^EbM#AHF@9e[,(i$\?)klENaRRgV-6"+1DOWl9=S]>QT:Wl5IVm'g9.9Od]$#09JuBC8!kWJLgNk.rAS:%u/[2kEH^X %=t4YoP38^_!D+shdsoMeE&`317l2Lus%k`rmdg![[?*CBCgpu'Z%=[=8g4/=Z;S3g)cW6aE:+<0a"tr<,>qF&mWTFJXfJS+PmKET %\(aBpE-C/]Q]9sCcL[bJ%d35rl%Hr_B7pr;m9Od63#qQo;p^jnUeADL(E#Lu\TcUY!Bb"j3 %22P_#emu`.CD+HE`_@"P=Ha$A6M-"'L38kkh)[_cMGH+IRWSG"k@MlA7Q9YV?5&Tuml;-+N*iYb)%j^ol\HNemg9hJQ[e]9rI^#S %"N.hN:eK?AC9lKnmZl/4?a[,_68_o9eWRm`5qgngUs63-HeR.d5o8BeaCIS/4>hA%(N,#IFWR$+IRMWS5jq4t/=!P:rh4Ag-J0m5 %8"K!hET#85k?>Z3617E_;u<0.!]q[=VY30:"g+(F;u>u?O1/8jgG2T2.'m'T-4;s5gboPsT+-`GNaU6&[WT"9KVTQpNWW%c`.NHp8qC@<"`aO_t=8;DOh-l06=3u;$jfJIEg2E.h %K!^p)=oD`0=Ok!O0+SLL7W+0<_s)26BD!Xa_NG)T[4XQPA$lZNKVc+Y(pjWAWJoX9?ELN)HWo1f!3oE2gU9t>"WJl1Ne7fY\;?:DuX]?SoQ#W_83it_Pi*_R@X]?So($E/),#1?=lku,5jkWL; %[P4=I,e$QfpnLT$h?@uQ.8/0iNT1@6Sbac9$t6&c;5[7.E.jcO[&$cG(T=&7=0UuEdR'Z7I2AKZ;o,D2aEj-d>'AD0o!Yo#Q!*TT %35SF#U/$=Wa0UV)h7%o3'Kd4b9a"(YaXB3E)FY&m&^4d>Ca+57>088A_X%nl3ZVujkHm^bW5qF? %K2#mt)at0-`gPjc%3,a)),Nnf7M18IjR)Q>JfTqh,/]X'MAU.RW*ps2,)0lJa;[PV)Ip)1P/et#f(VCU$oX6mLlaBLGdn)IZj\^" %*d<1=/:'uJs'oS>o)#d<5I\,'ph-n9Cq\Yn\8hb)]G:Eg9nVfD3JXa9LPP$W=WLiW%IT>j/ugh!Ca'ji-K %L#6A)`E,TVfos:Epd/o'[?pPS[V9UL9.m7&_DT)ij?hJ%ar5<\Ri.p?eH6H[M$#kQs,1Nn^4hh:^mt"mlqDTe%:!d?*IdapolGIs %.K@aYY!kE?\0"1@]"G1_6p!fs]l@8f/:O3C>YfLJYoXK)a;NOMXDsgE1H6&3.3t.aoF-c[*b4o"*XYg\Xr3b7&ngln`'DW3N@a$# %Z#8A9;B?G++[RP6*Ri?\lk'QJ,7A`aX:CAYm_K3bLt"Sd^&_#N'!(%(GtCIL*YFl/A1h@)"\t,hfce)Kk8k-p-6ho8dN7<\Cik*'lG'7o5VEnnaSkIYTK"M$YU^Rn^58N"?g2Fh.!ZJ."N)dbl)cgCk6*h %FTr37DQRl)ef#=,B4_Am]RZrj:>!0Tb8MUH'FXlV5q>0G\ZdK`Z/1sk"!o`D_736el<0!%QH3k`D^;Wblijefb[oOD%HMV0Aap.' %_APY#b5=KfN1AeZ]5*26BD[8%Pi-]mOp1X?T]0k_!-60CQ9Mc2mQ6K.Cr?iLBm]_n!suUN<5X6o[Z>mJ4bZY:>[hkoV?U\dntjPE %'8pE@_,n!%5'rWa_[6eZmcFb@?SM..H3:j"(n,d@l;FEb\7s#=/RJVr13O.DhHBF,?bg/Tc&.]UlaS[UM %Y\,-4/OX"jLQ]BN1h:]+@l-mo$X#A:O,\j0R">MCQTYo*8JJ?QUKGV$?)]c;;acOPUQ;%$N7K_$)D]W#g`FO'haKs\U'8lsI.#%Y %7L)pr;o^%1Ln5E#)DXMbGs&jf6UU!K+WL3W00gm_gZhgh/h:%9-B1-W2U=l\k.cA\ll)d*(7Xpk6/f7LYBXe;*;so#PZUn5HR^:-sJ %quW2XqPR&kn@AnP:HiUoqR*QDYAUR:MU4:se.&M$IXT\^T5iu^FeeCJ/9"F#N890_)Rl?gJc(@QrhtHDJ"W9G]mpm3fe%RIP4A(Y %Dm:ER+ER_!rr224NEQk\c-Ym[YCAW"Df3'8Dld9'"c3g$\&Fl\arV(Xt:TeGV;i0(+Ec_@^o7tAWmd5&;?gXB?9s5t8jc8=L_8]DYNs2sY %G)m`bHf+Tdmsa5ZlKqur^?+DsoYaCGj(GES2/@QKSD`ih6LRO\6$/eS'uSNeK*uT/]A8*CJSOsTejNGeqL&RWb)YZ(O<4Dc[Siok %(K9Jj/ZrO%E[GuMZ9jk,[su^"";!/tg/l,1LK=kA6>)oT;#K*]+MW?]^SrgmF#Zn%Q8XZp0&2W?W4j(FTY1df6X)a@c?@SBYgR:]?.AVq0obf0+.F@"/QXK:%)Bi\JMSdR*n9i %$o+7FHU#0SENF$UcdqFQl7T(Nb``nDAb(n`NGmWhk$\abbtJ#db9jl^O94rhS_1-Bji23u&"$+8#heZ^QtY$oTR+@ST"a!q3&:,* %#(^;gE+H0\(BBVPE+HC-gs!4qRQE=7Rm'DthQAZjg[!JSk0!LV43`>ZbMpM*7c<_uIR/,(po6X5jmB`52C_oa/'VG9%oVHfGFiX; %0/W.0fgPO[>k;QVTbI4reSBW)*SV54K73&CpU#6FJlBCEf&ZQ9]_]W\f"Z[bg-:l^mb)m8p:o6Dn[f)nDl`;SJ4]G!4a6D-dDO.8 %om?3J3\`.cBVF'mUIBDDU7"d>gCL>LG+bh?j)B?Y(l]F`-h_b4@OP@@!&CYc2q;--RQm<6A#e6XmE\tNGu:2b?F[&tTC]gXrqoo' %79*]mT)OJ1]",H%r701bY#r#nO8/PCRbGEp);5;_mD^E`nMAX>FXC^(cTV$`O5L]>[iZ\V'&fE4WBR\&%nI?A3n0Yl+([`&Cb2aS %A3gUsU&B2AT[?>:p`Bn?Ik9g`Z(UcpTOn#IKNQTh\^_G\nnt?#Ite,TF.5K/i4&gJ+rL^qqY:j"Tn1Ff'k]!p;ku$&S=-+E%rL)Z %!UpS.&_4PigPY9J*dNnWP^PVNu^K %$VUqC"0*6988aF[=g]JiZJX6A),)Wo+,4?)7`Nr0Wul+m8Xio//mPcc-#IDq1Pn+e".kINAXLn?HOQbe\h:WiHNL(1iF:glCb9@" %98Ii.D/'q8K<6G1C6_j_;p4%^NNome9eE`4`S4SEVO#[k/3%q#C20Fu7^f_I0a0.qWPpmj/8/dXZT'1H/SSAROMM(h`]VD*lm+'M %:i]5]i$lY!>109KTWaDgCIt"!n4"0I76"!nn18$c/SS,kP^':3-"LbeQh0sD#J$3Q:3HFA:S/,l>7J:b;^K)J:De,'&=>crqI(e4 %(92=L:t^sd^P^,to2QYm$[*5Z*%df_1g4(a=IleX'#1%BqtpRe9C.HK5O5ueo^&"?Y.[CrE4"-i=h'3CE4"-i=l\RPR\Q_!cgmYD %ZD489cb^E5KVPB`ca(0"I?%>QpMj8O4a\j=Kn@9!U7?]7'bLXk6:p^Ac@HOJ`Qliu(;K/.l"J4Dk+T*LH# %Le!!/^+g`2p>/hY%F(nj-A6YT3Sh*_cqF`EMkdmr?'f?!>Baqr3B4tI.8[2f:/q5lq0n#*#oCF/O8PXPX9HL@`8cY'6CW+mE?ki`00>4j\bHN&E[R8D[J1)oc!eJ_,4QD2?Gs"9%"Q#L$b%oB %=`Td:4&P0&XOf:\BckuQDU+qGV3L].,9._XTp\;$nQ#CQG,M:5B;c4XHn%9JKhca!OF'$6lrm]\E@E/QnBR;N.B;SL.\)qN5=O\i %0.Y$(r:7E^b3?J@2MK.87>8Hp%3;mgi/kLAB'SS3ed#2ec.J]Wl`%Q.-&h9k\$mc"QDpUAV@E+dDK-k*FDD8TVntP2*,ulj;m!n3hCN1Yh[>WNWc?I'>[9$A)[]1nn<,c"%0`Sr@0X['nNK/;_?ZtaO,a^"6!#F? %R`[;LJcH&\qu\9A7KO\bmm`0#rVA*]Se.mN!gTQ0:C+*[hN+*u4`uL_m3>DL3HS2AnHS1?6Ic"E%VW7+]NmZ/kVHFeQ($Sc0/G6I %FP'=600_!`SLeZ1&:VRHfSrK^GLUnOh:1u'N6UW-YeoZ.;0@@qMiD.fWlWs:QeO2Oj6aib"&uoR/"&J4\<$bsd<-&mWON"7\`Ujj %akRr(gG!3\h"SOk!*Xn':c3pJgu30D%mq %23GG_:)e;pHt7+*@7DSbT=>*G]IXdOi1\e6mJm5Q4T1$g_KC$EVo9D/$MTo%RNNb'dX*n$=Of5=k-4inEM?g(qUa[)ua!t`C?S^GtXZ<-?.k1lP>4NY"e %\Y&?iG*[oebq*%EVQ<"3l?fI]D<*lb)i`YMeZIZHG("Kee#<9BH-?;ppAM<2P!C]p/.j4:&+<6b(bX?OOAm46NFraf]dJ3(pO\QC %#`-E.W3$W69,@Oj4C.:N9j:T!52Qd\2qc3thgh)DhZUf`rVrOYE2D03c)c1Jn+,Z;p#-Qec5ZK_DZe$Y9`oq"8C]B]@6cB%VOcI&`Dful#1$Q%8=P$[=J?G$#UNNPGXkr2?FYj^P_5!oBr0Lf!CT=hW$ %N\X,-(^cQhWDRB=>jD'P]BqDuFFlNV8n[d9o!G8!57T0E>0E]3<]eD/1c8)=1GHDH97_3T:HqFYG/hl+i4TL1kQdG?B1PbBYqcDen!-3KjC\[[2L]'N0!P!V)o(,mr7Y06Q7U\2+s"bP %&KTZ%1BR_/M*MML_[MKJGc0k!^r3@,NLphgB$b[_n@MfYY/mNhIg&+icW(=?b$HD3B'"6K/oQ)082M%3n8t#;$oH1AC7lP&E',t2 %fs]kE.3OSLH!r10:6f?kUICIt"!L8h7s/Afp-V(gA8/[.ArA5"T2,X'o31/*D, %8CVt7:sr\cV[OH56j7S:YcGRn]I@`5H!2c9erhr!Ll;U';hW!:iohDJ0X^71fGIgcg=3uf(POX@g#(rbm4STgXlE94JtPG0_4H.h %=m3jrYEBm-Z(I;N.OI(rX6>T$WUTdfG)mj'h4XOGmksCW'Zkbif-Skmi]eX/cbansf[5SD&sMpnm+kOMUSYuVZ?Jh'Ng:SJ$_=On %7n\i6L!tJq*%a$sQ@3%PNn,o=GW86qG#!C&B:XAFk+m.-28.O44Z/kAln)W!Eu8/6p(m(JAiI4&m4HP9@lLolmB+JJ'o/RsR,u^2 %AeiC5p9QTY/ojbd@7sY!%!c*$ %2S-J1XGK56>XCD1M5nO]64u8)8"omo9Sfn?pU*_L*JIaH9#;U&L8g4;kXdEM;.pMJU"\1*PLYPoOS".f7>(@B8M>R;#J!Is@!(HZ %jV7SgL!8Rl:,ZAfM(dc#1DXFcXKe4_rH+m__hkp>&3.:H;m8uN%f;^7Dl\jMa.s-d%_KtVEV/V7l>rl8Jg"JT@%*T\:u&3 %,Ie,ZQ>>^S21TYEMee]'WJ9?Dlf&g4Ql"cil`sSbAR*-F`C3[,Qi4):__q)5)U9%pB!d;^s.U71@2#TZ>XNU:[@fCEdXJ%?)Ljp; %=!LlNehLH86Vlg(l)&dS)MU_aTm'3?Ae.]+VeMNoI$ts%"Wk1it(I-4XE"JThJQ)grYej0&9LuD2.>J %)V0V)U7n-!]T/-7\eKmAfpuD"6V%.h'p(QL';bgd6U/'h3\gINDcdgiqW,.=Kje8c:8Z!Q.1GNoc7V^oQbosZUb$2!>meK\THf'/ %mh-#o18Oh#FuhN9Y"N2*QXNeP\eKmA6,t!9'VV2!26"P#[[)#; %(Qe8uD(TI#$bp'.Cb9@"$S.,p>>*]"1/%mV9A7lN9En]og=/G]S-KudBPJD3K<6G:C,sE\g=DEF[ID_-ZaHT'/_K6I[C)f)/aOg/ %[T7[AA8=c+>#%S3[&kWkC4U]]coMpt[Ceol3+Dg?UR30$8G?2JPbDMX#<=Rg6_'/gd(IJ5C)P76GaXOu %"XsE[VNtWY.&X$Jh&Wc/QF*XQG==l=>mgaN=30#NWk[+'bO3GJ%`7nZQY([egXa)rg>l`u_5k`1rI5KbaU %*A'-tQ4`.jWU[=A4Vm9qWU[;kV%i0-WPi)bLK2_]rl'%S7X56TVsN9>#&5iIFePgrgZ@Ge\/n`'][`2$jl-g:E\t(:nYM'F*o0[Qeh7Wp/'^jskU7/5;r['jKY/R9/3s5!^D?>S %P$Xg"22JG4fo0\`p#7JI]q"^m7e%cCf&_!?nqo*GYV(0%.MlG*@9rA$,k6S.GPlQl!/s!3>aN=3Y#("D#elB$?>,_U\1WJD?-iu" %AUb#?FWi=P+0Hn1eckYSPdi?"@9qOCB5][BP\.-e_U30J.*_*(U\JFg\Zi55YI.92TgpuI8`2p?6]SB'W;1RU%6^^7SkIMM2>!i% %G&F]/Y2MUE`MCD_cr6p'CZt:GS>:'T>XQhT)>dl(\:u'T:sHXT>Z_fVa#%cFM_gXl]!L"dO)*s-;eJ!S1Kq]Ca>NV:)Rt]UbVb&B %InpMW,>:5HK@]N(g,5T^0\o\Af?cm#(oBL"Tr2q%%TUbe%3SO3iYm-p'R^d7>XM:t@jb+ef?g92!d@T[f?aok1,S^WL(Xo[H=3PQ %/u1%3EErph\hGF\$Z7@*X^s<"BlHF>@9j(#Y"N2*([cn+#rfef+C<*1_@7OFZt?fk?J>le1Y`P:%3Yh*'%`s6X:*T6[5:5`bA`'5 %+\aaEQbosZgCksSFX[ab6;JmZY"N2*QbaJ,-tmA7 %:c/r@FVuNYXX.h!_0(UB[A6MKK>lE)2RUP==`Htp3E++,/Yd,6BiE4#Z=1bm$^t8_*fIM8UeNG6!liqtd\bS`ne]F!;DTsAB5:). %=tn&e[^@0(e#p!R(9[MnCb9@"$_BtmX^h,Xjn^X8`-?m5oan`$m[.1F%)t\o=&.1BNh_+\VRF6sU^[3LI_d.>#%_JPfNQ_#(4K=? %&`[Fr/c.+8@r"Z*>,\lg\$`#+/Qg&&D(TI#Ms?1;lmWA/Z85FH;2'Up6Kmcn5SYaUl[hmQ-q?p)=;ND\53+pW#j[*!d3qLX9j!_o %j(PF^Z]#_k99#QtY(!1AV8gi5*Q9Es99#QTR*gq[R]nEjIpk+B"RRer$-@(($//VQ7clD7"RRe^8Yj:I.0RTLSR*q7L.GF52uBI. %,T3s+-*BmL=I2[!R#L?/(tJlWF>Z=CW3EFE2@#;d`U@e4GDGR+V(>Z6Mr3R36r7o/QbnbL/L9hBN^AnXM%X1ZmU#)F-o=ULieuEo2Wc9'=.jVe:;cnEeKQS00[.n)9lS;-ci[Y_o29rIi^_\cA$[qu>iOCLo@9jHoAdZGeChJD!i%L.8=SKJW0`/bX*s0kDCCaT2M<9s"XiEkp%mXOmV"3FM'a%uLCYlC4pp%ufS"\N,MXA=+.43I.hZS0q'u %@8Nh>#S)#L:SfcTG+g^h=,*^B\VfU27!GqC)2:QsVJ5:Z@9A3ARU;s$_q3Bl29R\I6oM.A@"bZ9\ %![=QMkKEP3G"B=`mSd$AHq!p=:1'X#o+aF@L$GpFi@7(E"Y(rTg8/Ab$f/q@d4R#'?#V.r7_?#9G-O'?Z@cG),,iZ#/smK=1qd/; %CQW@W1%3"N%H.dpF=RC?/B]959b*O/$]'_rJQ;WIWTt$LVE;oBNJWhQlR>1f4ZTQluM[l][8>`K3d]""\623 %%!L=UKo]@Oc7HCL:MhnMq1h<"(_s36^sYNU9?HEL4,?_6]i4,.Mo %hohFmP'4R6I4nt?W,TII^%p]HR\"=/F^bU?,h%sje8eoFnfCt/cdMiV(0gRTG?8Dn$bbU"PaiL6cZt3s6r^pp:K^LU%Y'-m%f,u2 %^#p]kE>ZE"raSoee<4FD7d)DC)-rW[WISCo]`W+"@MmOQY3W(d(=lr:X6VfrJ$W6+2J]E<\e*?$6MdNU.42OL=8tn0'OSTuHM3UX %%&7T7TJn8$JVY`_AYae%@O`4Ld70J9o#iftGnQsm)2<,N'#'CDLP&3Z^Y]SeQ(/kM?GBo'fj4%,8,ZaI>/a9JfP-18L40u5^h`uK %d_B'W.\^2N.r0hQj^kXnIC,jlk0e#m?W1!?Ag(N_+/E\V"oJCNJ849!ksXLm!gO;Pn"ZWUT=g?NFXff?d>RUa,#;U8m=X)jT_N]R]6?\LhtbV"UX$1(9@[m])_=L1milcZ`T61n?lfK?gYUA@LkHl*%d&pbd<%E_9Drh0\Njl8.l0.8?X_Is4t %qXJ@+NHBJZ!EMkcQ/E#b;9e"dqTU73T'H+cirWY>W`GXh9MLZ?YbKUNm&lgC*nEu0(njqB],RD.>,XbP>g/7(<_>nH4a%,/M.,i: %jIi,pR/MFQ7;2/@#"XE:M*AA6$L*mL/\aK)1bGO`9aJU&e[XY-X5]q=Rd#@M %c.#MO4R?U2BB.f?XlNpMJ=I=tkjhQUJm":h%C;4F/,^rA=0Cs._LVlcJIRf+*#Jar`1hfk^60]\=>1X11/]t8QB5@&NX.Y]'(Tp* %YcOom1Nse?e%6aa:OtV(Ykhk-rF>B'@qSKHDqaLTrp,]Y8Q\>uVu9nkh+N'$K;NA#:%d)9jpu*@fs=WSZds&$!$MJ)KNH>]kC4NN %q6RMUe#B7[m<@i:GGk8;UQ8ZbAgJPJ&/aSi7="-i(?SiI4nn#un?2H`If&[*,8&/8NOh*^":=tjP7NuZkkkJ/ %o[.I3I@S+-k?UnJKs_a\(K`"!Gg(i"bQTUG%tD$!;Lum#f!J]?M9]%E?i-_!!]M$$Ad5/.U%Z$AhKa@<](;,F24(S^3K%a?>up=K %ppTMYM;J6:%OZC].`gu4d/ce-L=J;RmFXP#LPt>-Z'G4_VP_`k2Z5!eA=(+nqhr!IrtOpR77_TcYjqNK5.s.Kf(8@5*ON@e*k-,T %mqA0PIQH]L<4nT+]5)sO7noGHL9(F(*-H($25AI%-OJS=f>,1[Y`=/!]fWA(WgUGdo;u7J>HT8k"e5AU>.S@,[!=+6.tgDPRDR?` %Ndo,?BUKI+C@K+c@\-1V4C[^>2-k%t\_7*X@=\K@\@tY?]dBWa[tAN7?$].OZ%K%a*kB0=G+;Sjpb'TGq/EAQ%"2U^A?o4[[p(d8 %*KbG+bYY,Xn[5]P5"N(f$HKpNm2Y#O\!)0M3N*_ufq&_b%_N2)mJ"3jZWXk&IE"&X^#Um5]F>81-)@o:2]jsNg09EI=`s&ofhC9]l:S'>59Nbk%YOn]*BTT3Uk(2V=/^;db][&K$"Ih\^f4sk+If)C\ue6^d/:4 %:NOu,\D\%uPh?-ES=a$^gqL;e4JJhj5CZ5mDf;7b!9N5Zig]\i0=Rj9jPk,%Oo4uVL!+0*Zr&Q_=LOdDU:'OE]?D6qS077CY?=rA %m/-HIEG!hYkB@ba9!Y*Tt@@?oeV)r,GJ:G)SRo,nT7X2=k=FJoOOj1I%[18>\?o*`(o,5PlXE:0aA!;AOgCVg6q0 %mhIVR\,!eiDlLmCEM(B=S.guiqGud^\4DU#b!0^fQ`SB6^%.P1[ks:u3-``4VLQrkaZKMYN1BmXbcf?0,7/>=)L72?qT#*CVJW\X %Y4eqr]s5d$lpNfWl$/k.=G!)Y,60KXndk,AV2tgHB6L.N\@FSt;l>*R;``QfTq)VKaHFA7%..S[aZ0=\?1W$>'>l;Tk:>YGSJ\5R %0V_htfI:)VZt9u><+?`mSXLhS_FFoo+7aF$X/p%rN"/q+l.DG(Ml0_Eff)'o`R?AmWDBpH63CL0O;c*+8paj'C'bs(eh"$e.^*#J %8't%Acp+BBc]'di.)&Z\UpZ&\FQCbre(7!".gnM?L!!DgX-SoB'A6KElYRh5mn.GsA[6eZD\JPjGO_$T2iUOBBH>R!>!1%r:&e(` %>!1&]Sek\4jh%Enm.;A_Wl;Sui(fk]c/tTQ]p=p%o^Z0Ham:$:4fZK5I]u3!>X<%)WAK];aY-)`()t4U]D@+Y9?R1h79br](nK6FWoG.f@Hc53c+fl[BO*:^Hg?B>%(I3V]3>3b's5qlDHsntO#*ti3[UX:67A+/Ao6P,AD>\g!R+9=1g%HZ`of;o_^\"oi2d]eGqFnq*_MgL4M?B"CnOT'TkT6M,QGkbJ %=U2$fAT$A*=tDq;Z-4nSX^t4p2DJs1(t-K,8+-i:f?9ck\Mg^t?jTHArK,'Tac*^$@`7O0kRi:sO"WKPs&i.p@Hao0^\V<4eq;^l %g$YrFIlfqHbUW%:\?UM5#+`pA0&E:.q/"q9X7tHB;sh;%Y&:&+r`/k=fe30X=23OZ._(c:L\J>Uj`S&b^&E(6$e]U_nRRNlF4dM( %OsJoT_n@^W4aZPh/pYm=IT(I9iqI>^>ab#W'!8:skQI3PSaPlcb$V?BhG(3OSI'2HM%i%fD>/SJ*^>VnrPGHi\ohMWl[%T( %X,o2SH[,/1qrk6hX'tog,QV^r'/Qdb:]_J3A'V/=Ck!\sp\PQG1rg"/`O^s#Vq[i+EqV7E^Me,$`E85_N^FgpW4Mc[r]09X0oW;V %b)?1F-f.RR]rHW1NTM4,<(^kS0+k$?8)GUf8=ub_9:JB6I9Eioeb?opYRg4IeFh>2Qs2_d*cLQj*8*sqH=f+`$8Z?H,+Y')qsld. %SG;m4gIo#\ll&r)V1!De)uib,RZ)W+F.;?6bJe)&42<]2>Z-$=M%o91W@$"MlM>?56,/p0\%k,K#K3MrhiE!PXfJ3bh)bR0UOpS0 %,cEU/eRY@LE"CrEQHE>Xs%p7D'24N_,W(6]Lf%HoQ3^A(/2dmV&P4;WVU5*SQAs\Kc:/2/H]&OqbO3\/;LGfTr/`e>JlP%Cn!P`B %[+@1Cmp0q?-<%(XJB^F:Q@ZRlAMsqHAAMP10fI2hCsnB=*L>oHdGDK3Lf#Dn.u)10Yj=kA/C>afXt:AJ/CFGhBX1ss@>X\Z``c'e %@Bj%I=so"Ia^5Wh5mImsOp)k,WrG'pF@@tn3rD_P5@HiZA/pp8Z(V-;K)Qi"3lYSgAaKh'aF^S@kC,NE2W,%Tn:-&oD&(=MpJs#Z %q,m/>U=XDJf.,,[Amob7?`T9QMDN9hVc='/9e1@qga=M./Yj#6kYH,Xks/p(`kknJm"gm\0XPZ"D=l3HnhBsqRa,6CBR) %pPecrY3P?as36'QD<=_lkaJuA!gJ5a;PTNuSE"b9(V3Q4$u]2XK7=P5!_Q#^]Zdlr9dcHDl==lJr2`Cn4Z"YEgem7.F]3KWhuOTf %^`4,(90;,G9eHfWD-L171`B^N?SRr#^mLdUM.AT\SG`79gnY\UPtr:2iY5%:n9.Q'WGJ``>_5X2A&!LELm?7;8f,<:j!ps'JV!R7u=8NNeM9n %kSr+\4)c2jmA[BIT_Kdl+pOOX0VsaQL2..'GtFce_'VK]N85o9]-A1^$oS^!a[/H/Qd9>9d5"h!:3"mF86E!:Q'cChGCG;gF]tF7 %quH()>5=(4W6e2hX_P/'SJa&Vf6/cr.nSdkR`A4_H'o@R_.`%_<%>=G8.&.p+Z5Nk@\(MY-ijB>,`Aka.R'/)fL]m3"-^5u9Kq9] %;jbSb8M=;]l:L%+U_e:89#]CCaX2U&=C#W'T#*6"GQOUR4LXn)C`[d/1Qa8#0@WNFWo,X+2TZ,p-@`oENV-O%:&ICmZu'Tr]C"n77DUA.@'4 %EYoBc*`8d_4bI7rA"n7BX:>j7-]<=>XBW0lmu)N\@tt>\eC]5!EK>q++o8CaIpm;Pi2IFbLfed7F3]Tk%$!E9,ifQ"hVl0K)>>-] %qoQR]Gjd6aE&g.9;nXgL0[/XMG4t2d]X$m=Hp/*`,$:1%3(2+$-_;-sl4Cpu^bIk-jEV--=E9#:%(\&(*YGG?']\_/=)bE`ZZ/,X %-G+nq@.'+p"pZ-BaD#N-1:f*n1h6e+1-DAr/.RTm@olX#Po#SXa\P:d#e#-*=fK*o3cKBU %$:RHZcK"kpRdG..gJD`A(1IQ6:uub %KoFSnRte#o;Wrle"is8omH5[18'j.=3[@A7I9s9a$8ri(>_j;^nV^E0a4O^6)JUn-S'OI-hrJ\%kE>,:n69Li9^a?oMN.#1l,S@8[WE4C'uHf"K>X %ZH_dWh$^C+-Zo4g\iSenkWBhq9]+*Vrtp0m*XB:rNEU<,18M(qc0^G\Fh?3B%dVmEF^t"hd/0U#59mDcoMSu(S?N;B-*i\`+\ZbIrUnn8CnW^icNpEtF^fH9#qe_s=kG57t %;Kjhb/5Nc9!Rjbu`T5Kn7887D4>4h["B@W&.Ki0+#-kkrUCdSka\n>#.DSE':CW@(.I[InrN^13G@gUXqNUib+'i'Q>mIHmb[+*I %%9^TLmCB#;;L#U>]6O.loL^2qM$GuiKjbJcjo#iSiQYPPq:/2h'U.Rf,]qe2O1!-I+n!ta*_jg1\t,[1jXac?RQGa-4&@#9N*lCd0ef;\lQ-oK?^QMnbanDuL"#\;/n$6)" %?Gddc,>,WFTa^'8j%qS?ZLn!7nc#Ef17*I!Lj-'l)A;Jol*Vdb,NOlQ`T7:5:/UtL,?G!o_ %K>R17\-G)Un2)2Z.qR3J?%!uF[=2Q0h)`@`ZL,s9I.t+V4FD!XdF'g^rV9CLb;XI6Xc5g&0FQS:P1cul^=%?o %;)JK9>f?1M$OutJKW[s+o_3/n[JG8,m+u7l6\e!,I2M&=S(mc5:$>`bs"AJMXn4ZXR5M25?2e+/>jYh2jq:4>,N?le7qDZfu"ah2uSmp%ldG %qsGkRjGKYh5&"b2g+AZf^#j50%/1&.2=g'SjoeLt5#L0eA\H,A-Nh:F[CJ/j3>oJNV)5Z9A87+9Td">*Bh/8rJ5D\=6Sc'B[teBik4e`Z7+U]2RTf+^GO2,aN2bo] %5tBR2d\`>DcQ?Y48Xio`Tu7q6XX.h!iB2+jVEG,^CHV>0Bkp;0=q%B(6-cj!WPq1d#i@oFVO!Do*GoRHQs-Y],aqn]c6CQbOuB`+ %/J`,;8Xin[;pR")o.6c)@;6je_Y#7Wr%)n"Ei)m!$7Ip.6oDBF9.e`GOuB_fSbA2SQF*V[e,'/E %7,$-WcV(pQ-#ICJ`trN,Z'\_h4,#Hdaku7\;F2u:?4Es3'Y`;eq0]NqD38-Nq,u'+C-,V0.6tmQ!=;it*%a$s(0Y.fNn/R%9$P"m %m1s>;579HaU.;$S=ehh4MUa^;/pVm]WlH;(/N%tm]O.BQ/N%tm<_3m`Q5W!2jXF%H/N&!CJ#AX5]-R?V@2;"k%gRsAc=ub7XA_pP %S@#H-VRKa.VreZ7i"EE+gtGXKDhm0*ZE"@FK1jSJJf].HK*sTHiE-7:il47+oGu:TR8?*'/4*Yl!Chg>rhFr_- %Jso`_mC)-)?2\\[rhh2gI*1#L1ad&7=rI_1ESuJ<0(_G0YSIXGLrZ(Fb<%#q,Y#@MTsMhi;$[Z8#4][/?fX6TXk*$a::-L`[%f>) %Vkcq4L!"MM_WVh.$:li)YLJA`^`UMZ)cnW*6IIAD@AceH&\;j<0&"9Fl.6EI8iajc<$CkCRZh=:#N0("p^5Xu;B:JOmZ)P^"Y\mr %l4d7j$l/Q&6;pj;gU$gVQqT&L1>&FXU+*,+)(Ku-k+/5en!A@.^LCL!=p(Qmmdkn;T5TJLnHu;1\^(d3@N*E4_ofL8cqZlD*If]Z %]4=MGUUuM@\EM1lh.!j'>ntQ]@f9]2&e#SYJTk,#9tQ7$;+I(+h@DL`$6PBUbq`;k0A8"fqCd&N'5=IN&"DdLh//[@)GXr,Q=bln %eSHW^bm_#\7#FjN.!?fNmJ*h:X+;jSYf]*VK5ciuD.(jUBC+HAL]_3H7X60%X %gFX6*\kN#rXLlUsp!1I(V`7/45(5A<2u_=nP0NuU?]?--5Q7lOP'rl'W&ij@EkprC;0A>8R"MCp9RUGhO3!iAi!RUn(Ra$YZ,atL9$,k@E.I7BV503s4cqIpL!6YR@u+6C %:1Ob^,]e=O.J,+R,'/*9DX<6q,'/)21W'?K=b09/FtF2L.U^%Z\^-p=ASL!35S,;aHX(H-H"+kM]dlB(\&[T"mn1;"f8$o56>#8h %JSOkW"kI8);!rnV4dA;DXH7dt?Vq`Kgd5?rdKoJ3!Qh_hdP%9*b.b]qNGQ>X]/i&gU3c4B+oiK=a./s_"mKeP7o[b&MRX/ctc+Y2)Pc^IZTc*mN=, %8mG%ViHk_-Fqtm9::YJ38ih;kpdL"\GP5[fMTG1&?N,=:gU.h$]*40l$0%8E>5"uj$U:sJe^KLaF(N,bg+%K`T"toYeYnHk`Vag* %G?mjNL#&\=O"R+:lZ'!8*JkGPc1)4X[!/.2 %g%J]mBBFBdhViM3-(d!Lg[!JS5[,DC/rLOD)hGbZ-.Q)AhG7[-/kQF(uopT6#a*,5K %@,H:T4g!S*i0<]*2>R1QYJ/XmZ2%nZTq#<`a7@554,h,W(Y^LR!0c]uHg]g9UPG2PlM'9sFCJ9OT`_'L(?&Q_!^D7&NtM40>AR=qkuAO:@.HG`)*\^JK_0Sgf/3OCAr0!NT[rtC4Fh2c&;E,ZqXjYs.'+3o]OQSl:n1JrjIlZQhoLn %C&[D],?LsLa[c8VHEN_235bIN^"j'/&"bi_87l;Ep"XW#k=4qIpY1ai*sn!hBCB$QWI\fOJReXFUB[`,"p40;MAiFJ)//bJql,.U %]*D&k)Q8B.811e!e3Gn85`N<:5%\1j/rsjgOdL^`Ufq$I5k$>!W.A]NJUu*!*RY*!QgfZ6]Q=`o#5WT)I*`BVK?g>QLeZ1"1BZGR %71(n+Q5RcNnI%K]5AMbVQuek2L**ojM@O4dJn8n^K,KKO3?kDQC7'Q\LURajK.GO7h+Uc+-3L,Y$N"*1:M&GkhV=ui"?:;71fB(f %GU[GjkkC5U.BFOjtP23F0EVb?RMtBD %"5W?ela?6b9"HsZ>_6>@oYPD54.&]%GI,Z^ES?(mm-OH%WPN$+_j+ZH9!AU:c@al8<;Y!?bpV)N8ZFeef(r0=c)Z\;DK[OmrO005 %Y>EJ\;p1l)7GD"oVO#&-CIt"!cpONcJVdoPNOq4rD(TI#b:jfM/SS,kn+=WQ>108`3$Y]:QF*V;2_W0cC8()/Denm3>$KO=WJ14% %ibU2\;p3@eNNfgd9eB?;#pp&MQs)2e'=PDIk6CF!Y4/3E5T`>>*]")JcTK>>*]"$I_c0 %9b@t9MqU8X\$`#+/b$_gD(T'm/%qIfs#eAJpCMdT$Jn5=/GjHgn>YF %BMlgI\GWGdatJ33MP'"SL]L.cE_=Ps[++kROBN^eBW:O.:c0Nh%9(gPHE.TA[G='OquZSG4udX]$?+,a,;aP]1Yr36sVt]ateoeOs\TQN4?2-p1 %$UMP33DlI^4t]J*Qpa6fFJ05fP)Mj#\Brcm9u]MEp=j27f0?QnYKm^hq-Jm!,Z@QRHM4'[B+S1YW1H#Cp$8#;IDgEX?OL$6.)Lp+tI1f&o[<#:_m6?Js6L"t/! %A(U!LO%YVADosgJdKFemKHemf.0[^qR'>F@l6q(u$ZZ13!Jr0,$eHks,\#F_DUu\)MY5PCZt:GT\!?`f?eTIDV\V?]uKmaeD>XK%(@IK3Ai>R$o'N-`/E=Mk,]_]-m %*n:g:(^[>g@oug"TdoM^OW6'[Vij!?$bC4(EErph\mXuY'%`s6X:*[5!_;;[lb\ij3oPg\T7QUQFM\L'"$p!q1Y`Q1X5e(GST$sM %,aV-5TbH"2c58.994:qh@B-1BP$!H^JtYf*+c0doV.EBJ$l+M>;)fhMR%f2:/l:Pl\1WJD?%tq1lV\SN"\a88>aN=3/n4C<*S7,A %XNSlK;ZSYL@LR8$:B_WuQILS1\VW>1EErph])Ec$S.aGm(=n17C4',b.#ZOrf;11&lb@uXa;WW@R"EZq/q]1<4sqH'A^KJK'S^`r %ap]T!94:qhSc(s8lV\SN2-*;%\1WJD?',W#ZEPsk0&h>Hlr3/`K(<>UL<7alj:CRnX!Lu[Q:+gk9QF"i\eKmAU$@4Ff;11&$[a[$ %>Sk'dj::KBG;:bQ/+T/#R9G?e?u&?'>)(.,CIOUoCggW>*CMBo\dT?Y9A7l^Drc.I9A7lN9En]og=3uXj>^@:g=-2("p[%md+!Y^ %S,jQ^BkeM4K<6G:C*EPmisH0_>2\tig0-8/(:o9OU<-eY8XioOZsYF>?H1JMPdHIiR9Fcg*So:u7rqV_eC$n9o9icIC1SX0bK*jS %[_I\k)9VYXYpi&XA0o7=Qs'\M0j_lLi_BLc1:>b\7qGCHFH=Dq>1-hbGa=+)f;3G9@GGYCLaj)IlN6g?'%`s6X:(qm7Q=Rd_R^^F %'ZJHt("P8)-q6me.Ia[JNu[+lWU[=Aarfk]WU[NLtp-$SAMS@9=>GqKNE$6$j!O4R<9=TY9I17V=Hc"N.g< %;Iu[*nbA'*j15p_'7-tkP.E/!X:%fePN04gL33Z_MqOXLcEJpg)IV*;iaH+&[ti/gMY+DZ801hTd=BX+iXb?q3*3-!QPpJrB1JY( %L;hd;<.@P`7j2Z?P$CMNs1PV^;hVWI#4WEhjUOLX[J1)#0,bp%D+C;Kh*J2AP_F5`\nu0@900/t?'E7H(IM:@H7ELrL$AB:0(S@u %9L]'i?3i@"P5%@uYV)_%BlRDc_n(6g(s*+^'\6h/g50fT$H'F`P8`&L0W]%PS&!Zm-n*?e$H(>/-n*=KP8`&L0W`I^;U`K?oVdLn %DGMP0:b&OSS4$Xf6]YtqGGjcc)L>@M:u]'rLAui@;oLU>m)!Jp)L?c?8GgrV2>!i%pAUF#Y+aX`(k5X(d-&nt%?#iO26=urS#YWi %H;uIl!HiAkKD@13\:u&."4h#,2+4?B+'QS?P6cbR%6O/Y&(f/Y7)9Pg`AR9_\\fKWr\7#YCIL.RBj;AdtrmjJh/\eKmAg&;A!r(:C" %(NEbT'P'bR(o#QD).\!'f+8AVEd+X\5_d]q?+:-2*7q$LC@7#GiXb@,P?K*rS3pX*-*BmL=P&$C'ej+Za%$a)GTL+8P %f;11&bMBXdEAusq]$PYXFL9PNFhu9`-*BmL=I7i.7X)5hpfRWtL,L6ge(I04[++kR\@RK8[++kR^ep&2[+'bONLtVgK1jSJ6MD=X %_'Nc5)12XT?s&b(l=4OQ-P]qc8=#"!YV,P`;lmT%@9kS[*20tYKlu(_QmfM,2672BaPp?asAoG)tt^U?/MCS1YV-=I5NP %WE+DG-\4'q']M;&Wqb:JPa!`IVo7IiBQJLmYQ4W$5V:tG,e[T`=+g8T8M@a*X'U1-UmGLFMD(s5/mrkmM(b!q0(`G6MD'!PQXNMH %$Q6gm@/>]mf;11&b=aQ'`YUC`FTE;='%`s6XNRRpRHuTsYV)=(M@.s5'@m>"N"Xa=0WYY^5)s5B6"pPp@NA2 %HEG_=%6^^7n^e,ppU@(s;^733;f!AdF"*n]*GgTPl4 %R(Z\'oY=!-(m$/QatOQ0F2l$KkYi\JYl1$-_(O$41r7!\oNh+30Y*c*Y3niJ(=XhOE)@'_A?@TqM_K7moZAk89d07*WsiK/A5bA< %"[0P64YYUkgR;FtTaL^4$\*.2]05[IR%X2=_[XQ)ciZ-EYi/]4B`/^Yf+Zkb([q4i)5RhuR]K"G.oW\'%$Y4[pc]s\'=Og3J(c\pXnjG@b&/^_Z7MW9_7!@*PCD*-Ik2AiN* %)N:n^%0iAbP=AY#q,[>lm]KgNW>Y%(U5k3("kPDVYR>jq--fT!mfi-KJFg`?fJTO@pk5]&_(ONtiud[:1=uc$.Y5u"/V@?Ud2a(k %dPBHDFEj&]G)_?OdGn!-K3^0j/nTEPl75lc_(OG*N7u*#S<<(YmF!cBAOLaXaUNEePFB=95qpJLmL2uRfG0uM@nDmD+7-<1@!,!V %J)cgCfd33O*8QQ2:%$0%dWI!ZAlI:C!0Gjaj/]2u19BJYt8BrE`gZ %A,5n:JMPl#I0mMKY=U:PQ3"[]cna6bB0M=\YnHB[:mHIUc]=*)ntElP9S'TL1QMY3_63=ui4#<6g8/Ab$U$/Zd4R#'?1*'3K3-,Yf]CP43-^-nK3]Q0M7L7R@j:UlF=R1&J\7%=`g3 %s)43qAk3j;Jhn`K1P@@5228B>EH8>e&7p3T#m,6&L#L%th`J8$Z3OVaPLiM=O")=gSmg00Q/8pe4rhqotc %MTo<4]oH">\O-.h;(3j$c<($<0:]\\G]Z%fqLX5<_9LNgq9CdTOD!*j-LMQT5Wq3c7J&( %T;JLiPo?h%]Iq/"cRJs(O'5_n/r0$;8D>dMUA)Ou.TV,on0F&m1JBD,LS.Q:AO!Fb3!>M8;^n[e&.=JQr?m"Je\FNU^)05Yel[hB@^[UAgmn&?3e7VlfET*khI#XI5lZ*d9D+XE6T#W")!rskOroMalg*ZkL?^E8>rgjt*WAq'0+"LeEV`>DLgV1S %P4=km'2mL[,,'* %=1#_QlhqZBTX;HJYm6bJW4_lRPb>*6<1^M0Z.[e]1PsI`oAeG3)sP!J]KE23W:`XXel"2m@?MP-``b,k72]5eNsF3%VL:^?"q%Fc %!pTtj9*Nhc2(S@+^?k_`osnF`6Is@5@4d'fZ8YBuH.uOQc;Y-d(`g[9KbYJYeb;d$T=/(p]CYF%XlSU=0mpV^2J]Ydr-IHBg>K8R %FLMu7m*7RS;2N,S`oHG%R/Uck2DlM'bY>9]cYgm@'5T![.9-o"ET8"_[7V&'?h1(m,TG_`rpI;"@q[Bka5a1 %L*,ct$Un!6K`pErEKQVrY)m%u_MH/6F+jalC0W;:QqR.3pQW0tK"44"m3s!6"qS.dm!:52i$hZ;$m'6R^^c2t9JBO=0]jeK1jD@; %\d-E2L)HfYg_\j)E`T305Un([Wh50XOuI!$jhZd;CElZ.jWbEiqtOI>Tpql?RZO"bS:a!='m@& %=K2m4\\SsG*9N4ejpDDQ9Ym*(Y)m&Tk80!^jpDD!&qs.U0NUe!k$-FP#%GM%8a\TYGa`.dg7L*RJOm?okM)*EWX0po!WO)&lf)PA(OgO=HTc?4lZUG)MH_Vld:Hm)Hp%/-"ts-54E(!U$!iGZ;\hSYTrb"TeB<3MMB^W':+b+GT6kO.\@FU5\u/j,S@ %"1\IaWi-EuP@6J3RfK]B(Z4"^qqq0:gF"k%k5?g>JmL3l]$6t\9'"TF:XcuXlnVm>RgTZ&0a3HM0V^LVRZ[5^d^NP5q?/lcg*+@> %fA>c2I3+cRFSdqu$bB8rb447#P*E0-0m'AlU\'fFTbe'4H7PY&,hZ#Kf(mA2Xra^^r_C[[4%pdk7-X>P\(jiX@nQ %A!WQRA@^@,H,-"NRXi:O[_0]2NMe[75h.V/k>9BZ1+,KMuNSCUB;==Yr]9)#b+]jTtRZENi;6u %c#a:O(C,)]0#EfBpBbq7p7D+r:BroP@%Z;eV2AP>N0hE8S@^-"gq%@?Si@S]o-_SBO7k*/>*p62csT)`KeI7\/FPXCK<:dqUC)5R %GVJkMD&6c;f&_=$n(6iAB9YGHn,9uR+5o\_Ep$kSODfSp:&G#2U4bt#2qesqc05?nHQS!VcD_uF&bV'CJ]CR%9@jNQfgI1;fM//[ %(ReI4(oBLIib90q'A''ai9qZjcBo*lir++L-YlU3Sn9]NIB(98/<7$/Wg;XN>#6MP3q?p[l*F^cFiH:'?+#om %XV\'Am"n\nC2ptgN,%l>$`[UBW>;\)E;!Zc<(e[Cr]utV^FM1@(@S$Qe*)*WM_\T\bKN&r/4b]`NI=^Yf1/^jSn9]6WYY&?%TEmC %Wlj%p$Y;5@GA`Ob4QmlF4X(KpIsS]"CN;u %MB\^J+TO[=;+*@0kLO1?Z]Sj4C_A^ecLqas1OgIo4ES#gfbmbZqt,do#5?Xo^[?l!V7MDdc[%W?]f+)Jm^3tu[I&nU\C\-jZKgLP %V]I(4=(U>Xmdq/o`PkK`L49+MmPUDYND:r>obsd8;;>qEZg,B["C9$$VQ#-nBTKoX9OI?@r[AF"H"s;0DO28qH``$KD4&`+CGjUW %QUE!).BlaSnZ:sDR``FbSX`R62\XGd&MNfdn)QVk&e_@)Ed.CmNnL?)77-\#:V]HLIo@=f<[jQp[Ud %AtbYEL<4,8$lEdrlF)X[.^W?W-4<]ei\nsoCsn@]]#&t`Ur$Psp/_Z$emSk#eRX.UC//"bl%e?'i&Pc\%SO1D@[LmMQ=tce0Wint %@4:NIfNhp:6i$WpoMisn/7GAIoN)H"NPcCnY>cL\-ge-7r"\CaqRe(&LZNI%[%dI5O/>?i==O^h9=2Hco>L;fNL`,fc*#SN.H:;8 %-urFa`Kd!SXZTQ2,d(O_<8k&Lq^Z0C8(M+*p/f3)rhRFEmB7A()M]X&YFL@F'uq'>)O+EtLDAr[YlSda"ar14d+tD4@:AEdZ\mo4 %H`NOhI&o_O'kdo[YdqX$&E_bX_HNdTd'Q\p0RGpU/@LX4(ns7.4g%I.$bBAI4!I7q^u"j><^@,fg-uU/B%DW93W8/G=1.lc=$mh/ %3n7s[P#B,sV,FE^;C_C3P"MiC>2\b\$g"(\+f,7CBRD4CH?X*0'.g&k`mgPGZ5U7=A_11g^JGVAhNb0'+K''UZ1P>4E74f %W(/,\KW^6iGZ65_S2kS;nYfQ%)5adf$HAiA8M\I9*iP)h4UTk1TYuPDU>Wj3Ca)ipEZ%==b3f=44=[drSB2JAnYikoC<.`RIXZG0 %W8VYU[Y^[/>&-7#_c-D]m%*B-lH7\cY94X4&eG'eM=c5RL`d%6O(*b?ZG$:AAgNOn,ZH(T^"7JbrTB]af$]@g.Wa+,o,/UiULK\u %r"l,*1s.P38+g?Rh*T5&]Z9Q@Nb>EmVMl\#9k9eL`$c[,Vo:cV8&a)Ej'Z]WhmTZ0c(Cqr_=YB4ICRYSAmk@MlmWKZPQtpp52Tp8_#F+_Abq>VSWXl<5KBO %\bL2i6o1;p %_O]b>[:U#0@i:2WqdHRXEJtM(Ifi@2o%$LGXS0QAPV.5SLBt"9X3q0BX@W(Kp9]0d]S7E!,7Rj=6u&8d$tsfWP8rh1P&4n2OJj&ZJ,#RJ"ig,#X1%muHfu %iPZToDoV],hL(AK9Xd*L\P)YJ'YRjq*eTn(+i;^:X\2*&4G*`A2rl%-C"V)I%XKU1GXSg7e)roj]#(/]gn%S/_MoYfc$$aM.e]$=O(ccG3&n!1 %Q24&jl'(^j(clU%Mq+#8E3.CnmX/3?ke %7st<3HkEW/jGR'WI7$)a]V!Dq@,K=+L=Tm`6Q)u:3>]u^d9l-s`#i_Aq69&[jM5Q98'Xoe]a+s()tg.aT=iY]LAX[8O;QR]1$GTA %*tmTp,"><,YmH8,*>&B1i+5GQ,PP4t$]/jD&YfmJlpG5e8&T@/lY[lPLm[9Cfe+O>'+ojlC4\Vn#%eP"L;^SS@khoWM*XC<%raYc %rEXKIZTPuu7s8L]L*G#SPS#Vi8P"dD09lATc6R$j9i8h>gbMuL.0WRkiLjJ<2CE+ae&qlX9Th,0K#\Rra,VuaZHR!@4K-;f@?T5) %Q22KEf9dC9PkH6F;Gu!i`%Pj[aj2cqrpWR3j0o*$a527<_3X;a[#2:KX]?bGB(IbD:-=6f#%[ga_\T!b^-d,Kjh#^.!FP%NP8esK'm0OHhB7+23J$RpQe\12 %jInnGY0e)qPlQs[+TX>lSi-Bm.`b'MfIo'*])#GC*Spj(FB2p*m!ht2?l4.^/YZYj#/bEGCN*@k0[EA[W8/LOX'cbe:HB@]V[J7< %GjfN8#C(En!cW%RSdj^+_Bs59d.nd"s;rY#!Ih4M5_aUX((Hs8JsYP6[*T+CmjN^mhRFh2Y1oNIg\EMf22BDr8UBHIHcOt*\=`dHA0-(dZ*r=UF6`Z>'Ck0>Re&4> %Nr;q(k`!JEY&D5XAT9KHi`t.is1CnNfNVk]47mEBcJ*p]Y[%2!#5+u[GPJpnpK%T\iSq[!.+Sp(]5ceE';X5k\ll*3hVb8':u[j< %Ai6$3[-qetDA&?g`K7gX$$F_79Y/cU$u>%99)to*fm23?FXHg54G7?(cYt4<9,3]AYCdn=V<)A\T68V7`9n%h1oT\>Q#!^kX\hDC^c6.H/!gmYIhS.'#c0[6^S1US>GRln1"JZ4@T2B_7hc)i]V[@gI;H#ATPeW$I<=`\7pC8"7VE)O]8 %WPt"P>-:ROoL7q6:R4FsWrg=4"2@cX\r6W4@tT!c"m)cI-dg0$e28@>q7>annihM%N& %jkA3fPOqSZgUth]!kiMbCOtm#F)>YPS9h%h[@g<0Xf^\geoGZk*f-&S]p$NP6:iMUY%9i-1po:U>KaFR[EKD.A;ZJ;=t0j6%R&e% %e:LiN[C2AO;sXEJaIm91=?,%6LD"Wqi2_!"$+8sf>m0oh:UjfsBSB)gC]f3-3C(Gm*VrpCNnHErX+&Vi?4?Wo)KL`lU&-,,a/g74 %-V$#bZT,qOl6^\\@f9P((`Y+cIMVX>D&b,cIMQOngGiAQr%*PmDWti>nZt43hU,fmB0i-!WMA"#Q64,\6N+"]IU4[]B;a;Grarn` %HE'*TgKUWAF-3q!C2[OILYUg.BQ%UPO:E3-_LeRR#Y8oj8&/c]!(aW6MES@.hPH*k3#?FjI)>9bWaLi(*bI#m;`FSM8ZU[PI$I*2rWPfUcN48.dW6eJb %A;X!MTb;7hj'=+l9CAhn8"S[^5=K-J6\Xf9-QkSn:GYEs^W(pd,\"nfOC9$^ALOIL<_n1-BF0T5 %0Of.Un.:qo1i#XA\p,f<>#K()b3Hl5oAEp9Z"]!jqP:PP>gu*/&KYrbGX-(LD)R@6d.c$tGN*La-(VIDY`Jcr35EY7`cP63BkE`) %>M!]T:n#MT:W1M4%],RUQ"FhjKZEnU'EGBT*ED'_`L^L[<9[:ZQR7"Y"9JKf9:iKo5\.\0)OUUK#b1p7'%uCR_0%Bgr@#="N`DG$ %SN]sDe8&hP?T5V;b:OOo\et(-U:W2A*./hOl8oAB+Oq("+bD"?K^Q6--Vr4PWSQ*9g`=IhfYh7ol,'NgoA1:P@XS6'qs%(AU= %b?DP!.@FCY/SP;l(OU\P4r$qFX-7f`;DP`(jT^/h)_uVIBH?$2jLr,KF0@\U.flgL>Z%q?DRIJjj]\u8F/rP`=HbJ-)kC$\A8^ss %+ZEs"Ij\aI)`"mKaq]62-Y.*pjiRm.hN59J/iSm`=30/H_FuX2F"[t4pJaDKLN4J&O%Nkc$UA[&r^0-:DI/M2\8j\N13[R7@4NKh %H8fD7X)I@W;?>JDf]jJ2##D)P!u#->S#JaPiMrDI\V9gVBO[+8TGReWfO@%k>oAVrer.Q6c0OE=$ED[sU'ZigImH[&'U0DLA=?#H %oj(5X+M(!1U@9P1?1I:$V@4"YUWK>*ETjQ`o-9tEk40Mg=6I*72k)j\^'gL4-LnQ`(%fPQ_Q'Y[(+EllEgq(]39oe1Ee8](6kLq.a#B>f[@g"i1rq)BJ=Mh9`7Al/loL*9Oh7B`21n5Gh!Sb8G:e>W(E'n0N9.nA4I)Ysls %S+YE.5(FAk3?OecTatqQ:kjkG0tZS+.j"H&FV+uDa[q0C_`R0bW<4tm>O/3`ROel@p$IuWP"YZ_@dg6-NBD$NZ8p=4^?ib\#UpoqTj7_X.=k?]1YKQ@a=\ndW=B,7]U$P[HhJiX,Wq,=o**W9rAY;0>WSBG,^?Eh9k)K:)-ZK(>XSeZ^aSf<0On]:> %l%N7Y:AP6uaWKDbrEV=#=UqImCQHTo4_`Xg:A`#f1H;dWfds*eIT='2c^jW6h1q>?iBfRlV^5>n%ZD<0JqnWA.XSU0HRLute/ih3 %Fnsk,I/&e,I[r#a`&oLs7RN.Pd[)sJ`)VGZlFi^G+8`s#cKcS`WIM%m_iNRs8&sHDhC:;mH@"tWJS^^)kZpdFG=AqI.<0[sYL"pY\?jA`haQgROZ\n4^T0?+%3Z$s;MJn]LkXUVI"o\P5\B+( %Is,e(1e/:3QNIfn6V`n#0IC9aS'kBtZZYj[Jk'aK4!e_FhR\MgkF4?a]gbI+=' %mUXH&CUl@231dq:Ec#PWB$+:]bI+;Q%e!S*bI+;qHV&!h/_?j8beM6-f#/Cbb:mfLmc:daQ>9D,eM+(g %KhP/lP8*.Z>AIY^9q95JE]eoT`It&-//H@5hW.f4='7"?Nb?7n[o\=23DA,=l+ke8^WUq-bI+<\bD;fI7;PXLqVG'sVA;kWY-kZB %Rp(\")V]`I-faqcj-V4k$YI*'2Q/rtTL)D/.dZi6&5k1GP.7lJ(92:K;:uQ@J#0s4G)k(u>4,UtEAoHH/=W=^mIh7j?#1N5qBMI) %=YTGbFL5k]`#SVVErVN7UW(7!dSVkq*%a'tQI=Gtl"I?lZT-gud:2-K!CtP_dDC?53VIlf.mJt3S`Zl84_n[-)sAUWkD8N-`Nr?R %E&k;7cojj.E&k;73')\MbhcNk;;lcg=;pHrKnN\mQ3Q]h'jq3)\nNKZD_]8C$WL3TTXnOrfg^/hQS-mG\s[L[(]J0I]i/sFfa+2f %,p(pa:,JO(K+`E6kl&@X),':8eXpXBC<8:MbNpe&4]fkH(OHcS5t<*d;mI*EB6cBUKhhK/kW9,_:9QT-5V3_t'CfXq?EhoEJbUuk %0>,cW?@3Wd(WR2H0,6qm2&BW*%s@tp^kLNXOckW:jE$k8L@"6`e5*\V@J">ri`%A$2Lt %2$@:1/$>R<23d9d^#9n/D-Dlm=I88)*$_V[b1D/"jqZKE>P!3^2,kY>fCNH>@9r*^HbhS(r7TeqqLXaF^6VF(]br&J(WB?=.%G*:-P/GHsX:+tZSo>/3@9oCY4gq?m %L7T4$*gg)4Qd/<-JK(m%lV]d"aP_f5_n+oth__Ko@9==Xg07=/YmTepdS.<+)raJ/3VD_Rgea\YGmlXMBLAjO]n@>6[,LTSZ5V?6 %0W^2m=jmf(=GC"Z"rj#))9WR(5\OkdoO2$mTkYY#`A"A$OsVa>\ep0Eak+KgY)?^j(HhR1EEs!j\s=hf_Xq:Nf!T[-N(I+fa#aA@ %(9,0^<2p-OaO!L\(KBE1EF&SYe_FG4=&Id6L\XQ#\1WME?2Di!P+eYcL^Ig_q6?XqZL*Zo7@te7ld@8&6X3][?!%o`>K1e?%-q*J %A#jTT%)]Z@pPW0Z(W3J[7>E@hhaJF6`OYQO8DPo`Vp\FE(WTb"FYO_R1AanoiP1J>jY"^M0]%HK%]/I(T\u`ann^!iNiR4#F?)T"rotD/.1\ %O)&P`f;=ilq9.4;Ec#PW287YmEc#QjDRIL8HI5Eu1(!8EZ8h5g/_?j8X=t^(N[^h@XScVIGeL*LZ?Ck*CMLu[I1g!O99Pl*3"!&k %@b"gsV@42'^RH?Y!bKH`Cu-En[@i6t,K@>M[;[VE3a9e8WTCF0PgIp3IET%,Q>9FBbS=.;\ep0E.9$aS<2%3A?_r[r/?Xn>=I6Z. %BC0B;$0s@Bafd[-Cr3d1:U,&LfS"B]\I.1*i@teo`mJ8UB5tStUW(7!6I1RlUW(7!Ji26,d:*d?L&Dg.K?Kt%-.@C$%5*G0(A(j/ %(gIQg]!U!ICR.G78^^`9a@%Qga'i6nF5:CCeg7Y?aE3d?YV,]V/E45XL38&nFUci&)qN!uoI^rna+\=.FGe6&U(?QFd"+;O8nLd! %2t&.OkSH>NL$n@lLE2)Oqilmt$IKa_N!6/PYk(,-)5J'Pq7R>HL9_[[qd,(3KCm$.95Sk;^/rk-fJ'ism!OmhD>g%+h(U,tPijot]FeSO;9s^N\BniZPnn(7EdS/dO&iUaj%-tdp %EZT30eUN\0jP=ba8]&&L-125o:o,)QlI?iVTaKY,GGSAG6ZZo$0@=6h_n%ha40G8L22#iqYIK=eh.!>YR;ra:Wo9]$h@$K[8i=Oc %S/uYZ'rk\lR$JaCDn(PeDlWSA*htU"]fk5G23o,'Q=p_L>$[m\O:q;HCT-so6!f^U>XL)C_`P#pg>E$<"C?'WW/>D9Mg<9!<2kWC"LgGqQ/\f(l!0Aa3$NIMd]^(GY,iNQfG;&\p6$.@9jlA)Is+P6tQ8"/p*/b!#^rSF[>2p79gYHYV'Cb\Z;qe[.:!@.bM=$m_cW; %41e%jKaFR"n(,K>KaFRAXWIm[C'8/>'a9"_U`aEC>h8-hU\-+?(5"ObHodN %Ec#RM6j"WB]URa>L%E$M(iO&%9sX*591b!1SrrZ4i@$\JrDi!l4g'F-$'_-G$0e=4e(W;T-;1Kf`k*t55`;bP[9T2)fLoC\CUl@2 %[+XZ/[[(]-CRluu-EIS(4rRCo6VsIS>HU=.\d[nVaV6g,MbR/k>&=*fE"hRX/N/%n %a-4(,meeX.Y-`>YeqA25Ab5V^[j %_Cc[[p&m`5mc\7-L5P_F4l3ktgii(QP4i+k9C+Fu:Y+AW3T-W2K\=m\ct!)uM-[[$,0Y/F&D+o4OQ4e\I%:5PYZCo*6%kM1bQZLG %@c3!K/j9_::&hj'7WQAIf-s7U8Rkb'26M;C/K\dW;cG#79fX7S,`uK0QHri4_!g1&Wk&<%fi=4o\B6PA]%^@Z&\5LPUFS*Y`ZS=K6L!P>SL,Kpp)53T">#mmk=6r4_ %R7fek\*(EaX%uH9LYbW4l+Jt-Z>]/0HEJ5GpBcE>A3qgn7b@@YI<+o1n"R?geiZ7W`ZK#4^_NmtFeh($s+mhJ&nj\s;fXjA7\LD[ %^Y#L'Tc).))21M\#@Z6<:(aeZK1>Rmb+lgA%r._/imu.BrM2iX#BAA-)4Xd3_3mDVU5gj`:aA#->R?1=C58kY53,VC>5d1As %2['C\,(4hpPn\nDi[DO/8d`^(n.$?oWMCZH#p,4.1f=m_@loNc-Bs*E"*/pH:c^$d"pcJdFTdAJ6Xq92Zd%:5f: %0sp!0fZ,pL8O7TZXc%+@0*OA-&ng[sN`Yq=fJG_Eq"lDWe!>4!24g'!ImEAFNqk>_>R)2ed8Dhn!uX(FqG5m^?j$;H'*W`uErdMoM7+D!thY4LiFFO(bhC %Z"LRhohQU.`e?+X(XYf-Dm)>NFF+g6epA5&7fIW*0%=[Ni\GRjhUlB-lZFg9B*YPA4#^mB1=nJRIN,E@UG&ELbBoZG@Q9Qf>ZKLi %frN-Eji)[/p9S&.[$/TeqM4#<>LC]SIq)H,(k(I[Qeh;,ofB+#U4:DiI'bt'#Kn)&a.oC_?US_]IF3pojR_!PB/g0Kj5L%7n.u16 %,ZHCKEpUX"%=Hq%YG%H=:%d7K?Hg[\-JX@A*G+_H/Vp+aES\kmG)a.ThP#OF1Ys"Z23 %gD>*`bP2-O@b4=,KLUga:[@/5C-Taf2[Au5EBg@?8\^m-^RG,Act'S)VG7TYXg?uTktHjOB:OT, %$Mo`eNM)-2VS\L4IcgVYNA`TI#H6g7'kq4H]3-+ %X^-rfin]r-*]>;JJdjVlV<2'F$"i:6(olEqR4R2JQF,G&hX8@7a5_'t!FHZ'f#,:7T@1c&lm^@N\&J);ADPH8hLuY]cgs^_Pe>27 %8'YJj/B98L5aAH?+4:OCY!Sj)qNQ.Hl)'+I%<=aZ(8n=EY!J/.(IO8;EIB.T8?,A/HEkMGE&QQ9R0iEO5r0l`c[?Q#akehjm,L2U %?MF>&oT94e;RMG^-k16`"8di5@BMKX&PWK'5H^eS5$/M2oCF/R7pOi3GstR?lq]RaSs!Za % %niA4D*Hju\mui]6nF5FWrKum=5lLY'[YL19PHK.9IkDT+-JV$t(-LsYLh;RD%!"f7$bD5L,qbN",h%>D3i.5oJ$cohRRd1DM( %`UOc(Fm((QQ"^U(]]24MZJX%KH&2PI.HmHPcCja?JDTh,F@$8JoZC()hbKnD3o5H4YUQqPLY%9$?IKGFieZpCH0A3.&b,RN:I?_$ %5fLe`d"p!5YR!nc.gP9dG@&EObC7drZ9jtc?r0rF>^UeTnXWEOEVFU$pb-uA\^JdK./YaBMR!Lk[u=JQG^[qbV/iq'5His':4h$4 %Y7t-P-M7a/ %dD:'9jSagE.)OD/6$4s;7)9s!<78LrDgbtM<91\nCJ/7#N-rm-nr"=7Pr%-!_L^j?po8.(Y*p7m-h7j7Pt+A$-7Plbk`oka5KLo*Zj.q8jE"A %e:2?=hfBeAm9"XP]4H2JE^4'^C0dYdL%&oqiR)[UrtD#>q6\jo+JUThLijgRhS4.VYU+=ChQGP#'F5.#%3HTd%BtGO>,D_.F2Gr!e16rOiu-;HY=%T<-$XG%#,I`@rh %DVFW9EAhG&%,mgF*/k`_r&e+tAe1q?TTS]S9OOb#`PP`A#q2,"4UFSg]Y]cTb]:@cWS,gifle?L`2en8\ig)$j%^p"YVk>"N)ri^ %&RBe[,dDnZR\VIj>/qEY');q>"TrXF]SRPUnLUdFdm86dW9b'PAN6-nF\k/hZ;[^_9ZEN %:n@IK_X)#BPY0s;%)3!T%/0?bOR#JB,>C=K?_Um %hU+m,cL(c,Zf^L#N;hsD4?L'uLg-9G^TRV,ZFFj^DpeO\SJRSb`hqO-#-'`Z9SNp.7PZ4q$ %[hDc8>i'VS4OfZ2U<91*K&0?3;<>%?!Pada<1-B/32s?L$?d/5A#]8%6+MZ+Re&LH$27iNZ43KJ;`;/tcopS@\t)GkE=D&,lQm;> %/(k#hS0kS(KUZ(9W^S9\Tr;-JWD$_?TI\9,*.'=(EXg2]P[0kt*Db0I?"Nu]DKtE(*G(hWI-9.^<-f69XgD/^f`QVag&T%3N*G1$ %\lnT^%:?Lh<_k?b%W?\b@A_^NE#*J-gBjk<8c8o]C]"3#C'RTfe5nlEB/Oi>SWFQA416J>>F`EmRRdTF%$\^)"h[?./VR?rU]b.? %G88tEOWeXc7'ko>GDG=:Af:0EUr;.^4`o=kAqa6l/X=<>SZe$qQYF<-5?`6LE?8`5X7[Lr@>;GK'aIl"CGY&%CCXn&8UBHIHWRG7 %PEV**GJNYhFPnknU).:F/@9.>%D:O`SZJo;kk"/-hVa;eQOD*I5u]k/<050j+fZ<@.U&^4<-"EiZ)D[kWLt0-&602d'jAXk7$U,2 %"[2>hU<91*Os_B.7?p53A`t(?-`S.Y.f?o?M^jLF$=$H3Hn'n3M3L2h.]J[!>#mge.$l`R<%q\DPu"5K.Tu:ej&;qW7,>=_mo-3K %8g_$GU+3XTpi.RY3"LEe-'cP)A;5o;P\\[TAY`JAKC7T+4gQ)J^OWKcg:;GlOP;Sc;r]Yi,j;@/KP\7Uh% %-4EmdHO6^J;TZoe&\XfViH?U$66E!?eoQ/FU?[IBb==.f3Sm)%:(\A^3Gi9$*N3bDLY`nZ4aZB&"%_+3'7do)4_pbrq1:\37LG/HI/f7fdkBrTQY%HAWqL6R$/mp%kIO!3VV-qkA2kqT!hP@`aOHN<#n/cl)glB6LGIYun=8`63a %rSi!FnmB[8;F`,)e:>0i8HS;d;W=a96.k`s7L*lZ)H,\e@ticI6A*([4O0"$esL?,B7UBW %,nD2A(TiVIq6NFI4:'VS6$MFN[c`N*&&PRAiLN!*JoqDpJ;+d9lc-o^b9M`TTT1WK"X_cg(j]uXq%lre&(qQ>E'LS)Zi^/nlL/Hc %j)[4M5H7e;2c?4]pB,b7VSJfADn0;9JNm,D+4[R%R*/R7Mbos-2YgZ/S#_RYG^0:Un,Z@UGG7Sm\'[lL^N0`hKO)?h)9BeDDi)cN %N$uf\*3L$lTnnTd[>(%6`G=un$OMQLrYX==5N]o-mrojQ(SO,%$IGl;VQ`9\aTXj(U5\0Z$>K<_0Hm9=16'c[N#ZbN4e\p+C9nNl %2Fl,'#*jBJYFF`eHrZ>)m?d",`KLt,*kHc5%91uL6F$4&0P-!G7\D,f+]7Z5e9/W=J%&:(i^XoL:h$aqb<@b*`;V/E3FlR5"\`1&,Q*%kHAiS.2F$?.g'RsgjQskO$c&7V#sdn %_A0pfE&47"4YQYf")F[8EUhJ!Qijnc+*5[d6*aOX %"*k9r`LB:)2h?0!3Sq\8446;QP2k5+8(o=\b$(kST5di"cbFo)Cj:S0U3gQ3?bYj.Qgk*1!!2VH %*^'/SU^#Ch(#%"t=[k'o+RD'O-K>VO:Q';c+K)VrUR %V`+U&IBmm@rbTXmUEqP@*@t+;)E0a.$1??7%lFUJrMDSs45nsRk]an)grjP:W]Z8%Y'L:HBHQG`Z0$JMl]6m%!l'nSpJI+K]6IZi %1tqZFD5Od*k/5Qlm*VZQ.839Z?43t$]1#/;*N>j4A&CablD9-^5@A*!eUIQOSC7quX+hcccHuRsjM_JS#!iRha%St<67I!cT[f44 %UJa7Lg$sRtCN2b+&34FuN0^19Z3RU-;;^f0(@+&r2L`jY*L_!b1f]@e+D_c:B,Mkjk^/XUmpb8YUf@+%qbagIrq^a*fjCj]O&+19)6P;?2:k'FO!ZBb2:9U_BoT-L2iZ@:B;5H.%7ioS1U[W<&+,hpd?48EiGrcPs4 %pc?_s/%5<#G+Jo&SnguZ<,V"h-d8&d!%Mum0B?r0Ja8+9`sWunLpD-5P:rA %in[$4h1dQfpgKMk8ulUUd/(5?QfLSg4mmnK%R$lPc^6bBmBr1L'`9d>r`/?]1;qlKM8BFp;1GDoA*oW/$[H9MiId:!2lQR$U`4.qBpW\3jtGRMpgd9!s0]P(;4^C+OH#LfJe.]j!j6V__0?)nmf %]T]2H]4k84B5DFrr>%hi@t%/2NU1&1l5mAA'AH\;KjCaJ4mRj&XT5 %;cq.39CW9N^!,Q4V0M&Pjl7Y8&rbpgZ'q#TR4bYs,f-Q7h.!n@l/sk`l_St[G %<-7l<(Bf`07oUpcC_@RWo(.I"fgF"C>.RJK"Z_t%E>Xcd33H %N!+1q88./S/"'WqCcEg+[,1bi1=ZhBTfWb!e^&q!latumc.H=H5u\hG0CYh[Q^qdj)Sj %?i8:#\c"<'gHYPfNSjbXE`-VaZ,7dKSXLS@i2P43^DAWuZjD]eX)_+7e_m'oa`D5jrlf!nqfGNYr([%pM"t#+C_cNf.9Jnt0-hZ# %F463Pq0![YS*_ih=4W&ZBE>6)j1D%)HX?*tAff,%#j4]7R=IQ[;$BNkc2l-R+gc"ITTMV)NI<'Whm;OYj#*Z'0bf5R`c4qEc0'(* %BRZ=,mk%)gStYs7R")@CcaNkYBi%oF9m3588/2mpTANUXOX_oB#E>"FQWI/G$Emr7j;!riP5Te6nqp%E6.KTsY7?.M96irPY/'.= %,d4/beUg(T/[)+k(!!X-BUFW,oXrhuWrnZHL]_sK73o#O\'JNHMcsFaM(:TMb>_e>!M?`7.Bf\g'sKaDjH]74=clcbiX4jMHGh[? %Wug&emR1C?7i7jt!c\D"*KK1qQ+2G2Jf0g#ZAatt-24CTp>QFmO^3'EP):d8WP"r<=.E3774#)jX4)pB)d=ZD,rN %YbOaiXQXLOi_3c^[M;iH?FD5a\d=t]PD6*\tq>;bO'hf"X0ah=A %G3EdGLRtNKXA(-3?N*FlDMR@ %p!.F5=TeJJ'7H".T,!FBLJl#dnNJ@7++XY!DqqV^A[p0#=EL@%SEEa6(bumYZ0:[V\cee_@F;jXE'BfiY&jh:\&+l/4YO1h %%k?Y\]%W=oM-5K/5hBQVo]'JjANS[5K)BT1:F:okp57[+r%Jia^A+#m@COObe%LV.aAZr,NbsjYQ>o(&$GLTJ<21[sOG]^tg-H(3E,Y>P2o*4t1,BN(h/SCKKdj94Wd-<7Z"urWSM-5;#qcff`!4s,aV,4,[O3\Ni#1Pm`F(.O0u+Znh,']_ZH7MebjgWq3+K4@bOO9NDYbs\FEoXeQ$2tf?b);tdJSB=G\eULu_56?4TQg!'Mfka/3b'L\%-p;3TE:9J[j?I@JT+PP\?0j/SAkLQ[)Te\Yd9A@ %-rh0`$'bh=4W"5:in`'_(4G5`rdV;ps(IDld2LWc)I"#MCg%V%:Ec$AO[0:gkHZ9-RR"B&4I_0]q_aHh?VGO]4GlZAgse$s`)=)O %m:\9^(2>C*4PN7S^G*:ZJ]-==K)^_%?R$?r(MC&bJ39Zi?p"B38.r2R&V8gC?"?%,UR2Ws6FhcF=Z[j'c_Z*WWHd'HN^?%3#$uXS %-(iim&7[c8-]BSGmd-rkGh_Ig;SS_WSfS\e`I %mHdhXg>30fD!9eI$*>AQIFtk'`JqQ*?f\Et=\NIdF)i5'N;fWunGUeF\UO=jk?._bSaScRc0O5)&;!cBb63!*1.tElah-,$m__cL %>LZ]f^q/\4(F,BpUU+*2lS!]9(S^#2)*M&hbKFJaQ2\gg"me@S<>JBfptVl72-JR_4GJ`>B\1EfT*h\AF@Z&MCTtK%8sSdO#JK7Q %ZdpoWY,E"GIMTMY]oYYe;8fT%73lqGMTf&Gp-OW4VRSIErKj\-K8E4?&5`rf0MODSJ%:cVBH!ioSA#)^\@-6?3DTd_?HaMho$8RiHDjblDt1+E\b`I]e4[V^9ZqQPU,PHHL=Gd!+@S#>f7Oq%f`YA)7KO,Ga1Feq>(@I9:]@j#/\T,V!$f?@KopJE9i#Qs %$58$[AD;)^(75Zko/ij(Oq+faD<[S-834u7nSTb6Ur.!g^OD]t4XPjB/Ioc7'>j9W.#at>D!HtEjZ$IDFH$UCC%>Z3MnKn3h/+@5),F9Nd#=R&kI;.TcUX:P]f?$,i*JFb*d;X,O$m$f#Wk#N24@->3F^'9F+CY[2imi %JI/$?icM-K321Rt\!W6\f@jG&LqHo[@QbQ;6BJ?T42g8&'*#l#:4_Z?;g_l#bdM_ %rt.TsF[Cn`UiK'5Tp&G4KFl$1oIghDOpQ%5+a0%6J!^e19`.Bdq2Z*X+!JQa63r^L@S@'4OAntf7Hl'4F?q^h^FU[r165,J?DNoe %n.qd10@EKCUll]=O[`6jo3uh.`W&$k@V1c1ngloBfe7!p4iQ)a8]C3@j6X%HJhuO-iZZSg9.G0m %4N5u`8]C3@j6X$uJ3438EVB0(bDnZfE;#/BjtY.&9.Fe9R8-`#,rRa[`FQZk3.!3UTQAaaS3;=X.*9GgI&a\E.]K)Ma&AMAQ$R#" %ZhM,@r4=p6$ukoB;P?2*>F[kU&ru]'B9+P_GkO;>fjdUmnK-`WD=YU_ip?2P:Gg&T\t]i1`]_;oLIkF3?/b.T!.mls:N?+'GYfi7 %MR1?d9!8"Q`7Ze(n=JY+n\Vo*k3rdls*(=oU\].+^e?Sc2jaLO1M3@!0i@=5B>mP$,::PpMQWA(6[QlYp@q`!Ck]"2[:HitUOb#? %E@mQ(Ai?l)3N`Nk"De:N:8;%Y6\G8ii/l)p(T#KDG#Zo't-'PnntrGQZ>L2jASBQajsuYN"Y>[VO"?+NbA, %ASr?7;mT%I%9LBrXHn:fD!^M/3icgVWJ0poiO$1deag<6s1?p9/7u5$Qil12?Se[!fO %Qj2njR]p*UL"b,Oc)n6ZUHYbG0VRIs4r[sLTVThlV1haVpBd!T#[4[>=`XYR3VL;h#,fJS!0cciK?1f %pj6I;3\)%d)p8%HJJ#oZj,uX=Z,'hR$L!:=WZes;NEjBgC)]?C7B4j5dOWc-C/>V=I-/cY7Au4bG7DTF1e&i_1kQ_kV3^MAB5RS& %2!\"TpL@"*Rhe,"iemGNK[DJ=1ba]<4\!p32$\K(anJ]d>]m]5hI80H^;g3RRs94[2_3mU3o-X4WO4N_BE='e@jg,K %GP0QR20"T3RX:TbKXr`[QT;7oi?:5m:RM'fh7>]X*.NBn5:*D3TMhLao5if>T&MO?ckJ %e_DIbO?clu@n!H"k]N0'6XkYad+T]KA`[h+M,[X*p(ftX`gULQVQ3\8V^eb)HT*cK1L4R&65k>T2@L#crFFIf%-Y*r>%L.+X41AqechpO=/"qHXfU`/($DmGP"\rN1IeLJk]IUgEEZpBYH'X,N[1=$;KCXQ)O*dX'tpbRY*N7&22j\8 %$9>BjHS2kc:r'R=JoF8UXP@tbCR%mTp6;LUiO4PHi\+,BqsG\j<,+pV-*AHEZpDZL@oRiUU(H;V!iU6a;A2FbAd\Ha6F/0,s/sE: %ZJU'DZ`8p?nl=.:9gQOj?;K5oXGs%6Atb&&Jb!PlR@Td5obaBoEhfMY4[uBJgo)ZIf@p.Clh-J]29#*]HHM59;JLYb4V`,';lOL= %oSZd7Q)^^Sk4d#r;UlHmFId&kOfBk_\amn@;UlJ-p-&#H<&MYbhYC-NRY![K=("<<25T\o,ONpS=&WcQ,LfY0e.fLjNd[qbH[DAW %omp3.cmITc\D/jamOO+oqTD7]N7:^>P]>ARY%Qc/"]H48=YH!Q)^]hJ'9F88l\eF[E0A[b",`rM.7p@UG`r=/cULW;QcH8@%R"8i.H$E`BIkXnnXt5jk_KuiQ$"l+ %j>J@qg[Vs\b"V?1Yc%tnMW6k)W!niHj5!j;A`@OUbg588ZKdoq2+'a9;Z86'U,=r[IkseO32haP^>8R*GB$um?Nm*=*7V!dE,1KYIT$[lcGP`SU6HPI+j&G% %-*+,LI5n2lqiG@cUb+T(g1f+Rl#78GUO*?q,?:oU6B^lo.k@R2AK;3Xr6DXW8<^K$@ZKKM/^gFHV[b@c8FhA,aZ:]X,]pg$Gs]-i %qRAm#fV-gl?QleC6CUhlHKT(=Qd"]SQ8F2+Vk.sDoPE;+NHP*s/$qs)8L1H^dc'2&a=kb$KXbXhWY^ZH+d]*YDRm$^UhONX_nH:o %qlOWQW0Kk^kI`:!;LZ_)IoX%N[,H4SoJPt[[A]+!G!*aG2NQA!5&6)LF/]>Bd#pRh.u18s[K/D:]**[g$]SsSZrdkbcr7IlGNpq' %G;9Rgak>n%a.3XV:3\,5@b`CN$gb,A8AK*R1G#.E5lt:4Alq5iJcs+M`:@&3f!8Z)#g6jPOH?LN7T_iIJcpNIZbl99&gV!@M%Q'" %;T1;$H'i"8/0>rr/'84BB1\33;Dj98I$K(@6Ud(j9?247j]e^1('Fr3DTW7.kG7:`($Q]5lFP]42)C?,g\3gY^GR9M3#-Slm3*7RcsI,/h,E4h<4O_.3_E:"?N:1nRQgSbn2N5&hqEah\2a`:<$gXWf/dZ\=kr]OM]3Mb@aD. %^jR$#Y^Db"$Dn#p@JMH#'n5jZ@JMH#Q$1Hi'p^NDptYR3EkNe&!r'UCQh[H(?V_d=_RED7<;OJ8]1)WnkUW:NIGs("%DM!2rVOk@ %&nJi3?ddO2GE0l5VjCb=enVqmR-`Xms"CA@(sspN9M;C'U5r?(;CqGb*Xol=\Aj;&K8V[s3(8SIr=dVgb1a\jVf],M_#S+aL\"Hhu"qbNF(JmZ.I4,N"Y&pW!3. %Xr998&u?%/]8mH`N-rW]S*c/9h_]'!5%g5B)'nV3,"_[%>lrm%R\\b0K=Uf-K&6!DO5=oT#Bo+mj&2m^Qf*!J)+!>g+P*=N@FBli %Q)^Uu4#:!qcDJj0pkWP&6Rlg;&P\_]N%]cBdTpp9 %!9#2Xrh85)@AlK8meq5Esj3p?VI8(!Y=*/MPlq'R^;b%WMn-TBHh7*8l`!8'AbYJkVu&Mk2uVlI*Rgh+ %bO\H-b+I""B^p;5Jb!KPEo2]LU,Ru33qg0O4Uj2ibRn[0MB;4+/t,fD=>?U(bS6e,M/+%;K/VBGtQ24X1l)_[0_I[ %Qg&+anp;U"@)u-?DBAp,+.#&$HC;cHUkMYTK4ULi-[pXOR78LNPY_(>kZ+Cg>ZRUqPj2`2l6VpUM^N-;/'"3ur]'kM)Fu);4XXb4 %:1s,J^Y:.X+2&^PhEDk&VPMEIW&?T'%A$0gD8k'SC9Q@HBK"WPC&D6MW/T!t/P;;e7^F-Wh;HF3p%?gaD?Sj<*Mq8c]XQ/.._([F %9*r[l?_:mSgNuF`S)G$QCAF[.g$J`uV;h4Sj\l"blT?e+qr2tl3e=8]5jj$bm_c6q$Bq#K7Y=!mFWs>WK8A6e/6k"'<4X3UPIb?G %:Z'r`HS![qWtmXPf2?+RS3>PO68JE1!r%k!I-*0^'\Bii6Fp.H.67-2.XN_'D'D)XgU\OFAL@MAngJi8_j."8o*^#^A=gP`kI;s< %?4BmZqJ%^2^nY&BfU$fbDNr*F4gfu/Ik(kS;#sC>"E!4ZgU"b\C1YLultP[$Yl(1>bM*95#Or81=Uh+G1f]>r>a5JI,CK8XeP+RM %-U[*i9'm?eJ-aIEM/Xg[R!U<&:C;aZ.AXS9,V7"R;9`>=SeMf)63c\<9/B)\O9%Z08J)rim!+gqo6_eV'^9`!&%.tHb1p">*lI1jm.!)M %*/$+P+H;srUrdu73/DE,W;H:sdg(rNuG3YBQ[`'dT)[eEMI3Ktk %k"0@+NOIqnHZc@r;P>u*br_^BRWLlf5(8tqQFWD6_]@P`+-^nC(J^2A$pWT$V&\W>!O[cWbL1!.Z#qi]T6,F.m$NWADC3E-mnRol %Aua^g-0=1QhDL5JlgDUVKs"t19JdCg*#!s;SWq/ZKdeh*B#]]O1XXFp<-NXk0b_eK+3qqZ[#>O')J@#_PaA>(lrN2>T1Y%!ccTrF %asR]FJ*&oZ5"s=6=(jIP:R7\Mn^g3F14tfL<%07Z[Z<-dr)0J^+mE!P%";al7]mA]/U@8[7fTmd,7b %eQEQ:k;&nlJ_W_a!@n %^OYd/,gb8Z>o.C&U:@>9)1*hCg-XP$L-IS"kWq8uJ.nFb,/#_Ba/$k#>OI\DL&,Jt5*&,-p?#+8dm9g?WatkR'cW'1\.J*9I,IuZ %OG@o8J)HcETmLH7!4?AqZb73k`:o>k&("gSF&MTeTq_o %9)#lcO!7iDCAd$MRPnBrQ/jT;olEAdaP[e=?H9)oT?r[_L7km%e8hNA5XS-J2sZCNZZ6-H-o[r([\KqloiXNG=61rJQ>ZYa@-lZ&8gJP3L9%f<3Ru)R+eMlsGqot'Ah;+LT7j1*2eSfMA %]iZ]9YLX1=NR[W,;@7"@k`7Z8*+/!o#G8P)4E?pKDtXBi:)5a9/>->:3a#M[=:PCNoR/:SlJ$KfYj#YK/iC79(<`"Y.UJ?;NAG,9 %Rdm-5r\9^4?8Gn%qC-3I]Xs^[,qj"uaNH/",6=!Ph$AVoIBL[,F[(Ic3Ih*d#0]OJ/=Tf3)'^+e&47=jbq-/-a_1gnEm"s(DEIpj %'!Q6/J9eotV:+SjaA>LH5/.>1?Gf:rGYc,fL2p@=hO0"A%9n!0O6cn7f/<__)49$[AV^0Yfn4PZ>BZN&#;QAP)?_,ENPmUY4IA`N %4,74PAV]/P'GBm6B93dEbPj,?:N]#UkRB-iSlOAOS]#m.($drqVPV4p)uXb#,"rX-<$p!GcP"#5JhXf'9AAPe9GP5@s+L4oIg!/9OkSgE'3Pq""4_h]"pAFt@A>JEX!)@Nn*Spl^!f;90N+ffUfoR[0f[,q"EWI3kl@0C=t`Is"7<4!*b*R30gM %!+*Y=ZKFYrH60/iFPTK_?L4XnW6"p+.pY**9dHY=:j,=@R7L-XTY(Zqbs[.N&qsfr-o3#P9dE]lak+FNm&.3ll5+l.nm44X6[pJK %R[MFLDC+ic06;O.Z?&&#D9otOSqoN\of1f(Pr%W3Fn"YYI%nf(X]T@u`[%#/@Gn8K?6c52A_bq!N+eFQSZX.F6@a?OQ'%LLKMENN`n/S'e@a@$Kmu>u;;@cdf %hMOI$Ts+;GN5Zj(HLM^A<:"%m#HO]!@Ll*pk_AY-lsZm&A>ksmH/kuQZ%o.sFJt@Z4gBJ0NN0n6r#YeJ%!qV1@qa84WTb7'X[sMP %VOHEcjfP7Z3hZ)MJD92%YKLoJdP=$9JDpdOlhYZDN4q9CC]L`,7BcGH%%-40nb_MHD*3tV+6-gnPDEP9G'r7>7cNn7*?iQ1V3PYK %a^muTDHr6R#+WZW&@`HA;;r@=@4+Q%UC59B@r8"Nq]0b\-2VY=6sVa.Qp>5E:rX$oC@B2GUmsTiD9C\AUYa6.[&!)0_/gCilXH#M %m/oN[@Z[UA.D62pjQ.5E8$&bU$6@A-W?sOkDRrOdNtS"V'.c`AkJ\cs"BRqK=0d0062HJ%tb?n0^'YS[c:T$^EaL;nt54F97.sJ]Zs4IDOGifB(VOP:rj6-Sn %aib_&1$f;@:XM5c)TY?tj2/>5mXd>'6=;eI6(8!#0T3ZZ<>+asDGo&]?$os(Ba.)Inora1N556q`dd(Z-WTQ@_Z,n5^H-U-bMOlO %.lWCZLX?[QREi6V%u&%+fVPPtr+)kqQ99K8N.r7.Z2Q$O*W%_H?[,)%_QdHcl9E@>'jHs(OrkD(Fn0DH&#q4r^5@VI]bEXsCZX.' %R1T/ea/$B;FFtZT3g89;L-?S%2VerS#0@&$Tn?_T2'XFubfK(*dI6(%TIfK?ZZ;67lIB`7I=?d>ITt`IA]D87;m.\RQGZZae%EcO? %+,15LQub@`5a2b2Y)?Lub)Qqm1*&heP:cB7fVHDMg94dG%%D>UDG<;'RrfLlDNBqk;`pV"\7$\QOcmNuZ"GAD[`Ykq#Z0gfXY8k*d7IIL9!P.I>FTOP9eS*01jM[S%uj4J9RnNHgPKf(]EkFrGhPs""=KeZE;r% %nMRNoL>#A#FjcHDa67DGBO#Yn[(W5p,e:7'kql1%a%1MY2"/ %haA@!i5?dlf/1ALALQ0P,hgV)1/p$>#dg9EAZ4t5&88t81;#ZF=,+:m"YTl#R`&!GJEHOI&1P=.D0Y`o[oIafoEE:#fDcJ)(a\<, %r_O&GY9^H!1=-I\$jEfXiBXlROboLS%L9RRKqZ;IBa2-n=/c8c5W8]O>'Hg6%M<9b690:7K';_*DrKuseE3>CR8;Lgs:X:Th9BQ$#oYH\FbNOdo %nD5O*Q5p(L]dDK)b#T4&@7iQZ!5kXT[2&$VU9XkC"h<-&S>i`6i2-WSiThI8=-TL7B;De'2Jd%TenG;>.(\<).%BE-/c4Mb399>R(9!`q/,/@'cR7Rc:Z*ounImL2>h %SjKd>\bq`Z`1B'5)6)9cRjhtT(E`;A0%bgL<:"%m#QDH8@Lp5-dI6(sfMaP'SVXu':POb`"nQ3S@S_3E?-p3V::C%ms'eH4?osSA %3$ZuK]TD'NPqFr_`1D-jg]Oet8qbf:'psh@'0!`0Z"GtYaBn4AWMf/6GU2u>Eu#gS4iJ*/=R8'#[<<\doR3rMM*3E_PT<0oYm9AY %M-fQ-UN!k%Yr;\17kt")I?k.baZ6QD*aSs=Rd;#hp/(Xh$'D>r!U6b>W&F#YgT&T12"jgd`_\AqINLCg*[G.qDdu)pap#Tt"J$nS %[#co&s1o"0l9>QVX.?c?=R8K:FVk=_TIV]3QT`%9$+,,]8maH#bQug%_X6<*7>UN&6^*I.#r5C;GOn_/IZc$'>[&;tm!(d5YtnZu %<<:I`Qc89IY@naV'I#lG.!H?Z'!Cc:P%j3]);uK6(Q;9obm;o.Vq4+T@YP7W?fprr?mbom_+B/e!? %6@qtY7>92SLk4Q2JGdQ+Wa"puIg;G"=Q$.3#WF#<4UW1o2I[Z/k9Cp*fc2>0&cSsb/ %IiY+m)QE!>qQJBLa(I_GH!f_1nEVg$O*pr"00f>)5$du]q6/JtkO+sHIp(>Z2qMPh3VV_(KOQ&uq)6m5rpt;J3L,mkNc+2BYP/,J %jlu`Bm%A,jntR/+o=fHXar(5)bj80`hqNENXDdH\RCa$,`Do&##09/Z%=OeUR]Qi,P6.A3,ZqASsj %Z]3`@Wh/sZ@UhLQ;D+Q=o$PTf5.i*'S(?kQgCH>2 %GGs0D)OK-Xi;H7T:*ZVFn)op %NB_V'cbAtN6-kg-;`K^j%;OElG\5!3T,/n_5)4-al5l2/0]];."5Qn#aW*-TP9FenGBUH`Em<4tLsu^CS^nAgnDAWBH"pBSqKl628Lo,u(EI.=` %Ot)Yn(TU;kfBLT($.>BP\rr4ed':k&0:3:1"S,,QGes2b:*?1p#VW+M?Rk"p,kA"!% %Z;uN9AS+@9\kmq_gARIo$3ZF9;*(i<9&$C3G[AJR$;E]4YmQ`mP`.ZMSI2Icj:*RM#eI&td&@@WH!V1"B]\fh^0DJ$%jI_s[b:')cJ%nOkD=XeXZp*N`PpoJGllTVC8rK3oKHCN9@i=>O?K^`s0GLGi3/GrRmaHOgPiRdDH0X[uAtI3; %eqVlCl.pLbLYEY:.S+TN<0hTict6NQB[A^3e/cV&mh'F6_nRkTIK>M]6/B;3*'eWc]8D)EqUWF2@!`?,>:elGTX[VH[r9E!W5C<(VYkE))cTr %U(d"43G@X#'9H0mNf#Uf\?(>g;JFqPYp$)KUrk_@W>nT`@f6ibOR9V(nJSZ)2^R^K]_ObD[-s$>hj$f`jEk26_d*K1E0k1cJjb0c<4GS'`uG8G;H:;udm2@S\B?rkgAq1)c2pS:b&d`de"^^]lCKLr %je-1UbS59#XN:s+1+DW(F5`VlP#C6k@K$G-Z)[%Q#PrU8[FOFKWU?fMS-RuVRi(iO(2f!hmJ-B_7OKMB0'gooXuJS2P-/ekMj\e8 %ip6)2J-P?g^.o#+gT>_p[%&Mr"5o!K?oPSg#C:keHbZq*-$4(T8j[&>m,GW&^6]Qe_E-I`6fqT>F(9"gGOC$rfi@g6e*hl^^FY4G %^[_2jBcIZ&6#p6D31,=1rMI=7n6(r_4I)U]pbND9&ugkDmDj['YElc,d6VQ/ %BQcMN>+4`L'^23jEMZ'r7WZ]@K:A.VPe4Ca0>>l_&q='!bsk %IsZj\5:tMabCtj\#MH.#gsJitKC408UJftc9h0M/'#u]L@kMe,9,rs>&35&nF$q)W?uY#U-bp%NX[3%Oqe2OYP-tBPZ[X_M:X]Lb %`9KgON7FjG]rrOhlRf4[G`,_3r"3$oqL_p<*Z*lQEm/$07'CK==sGcIT+L-,2lI\^nWDl0f;]eMD^s(Y=]VcLU_fL\0:\?iXPThA %o>99[j.ob(h2X5WSSBaYZZk=paEM#[MAnu1.NEk.fH6DQLU3J0lQ`jX-pGY'BEGDh?>ZW$clmCdqD#^T4M5--&aep(L&[5#J&#<+2!f(7%OQK'3Y%V]eCHT:i%;h5l0I8=^A&\!1$,IEh< %&n8Or;ih&V,<:2lS`Mf+?cpcl@8)Se85%6#b;!jdHc^@<;M!jKM?PK/5h6>+dPCX[GRY!)+u]=+RN);AUC/,8+9$-Xok;O.>9[!Y %R7dj=OB=1[mA'kgepju22f8rO0WTX/CUXHC`lVm,DVPkm"E$Sj+EpKHIk9CgqO2nT:@FK^l=;sVU#CXP\g9&Na%B,5Q>VOkp$+(U*99EoNB9q#%qe?TXtMfI\867VCYF-o>=dS.;m2$76mO$S088M42N*$?]e>QH8YNCZ<08]-Rh4d5W&h %eh,k3bau%Y9CQc7\p,nJ\"pLF6f=7YDe/`i0]I&Ul'njrJ(XM)f$.;o:!Sm4-,@&p)\5F(Q<_F>:Pj*\R!f5Q^.Zgq=nPEki.pA- %.)c*IV;MDBK/BT?p_<-A'-#pnO)EEU;YaC6S3[NklGG.h%/,ma0S&AhBo/22UO %7l3:KhLj?"d2W8`[au+'o=I&RZ*`A18Y@.?mn/kCLZ5=lUHehL]@%r#]*\QAY(BaIG81/bcO1$`n:V8RB\6VLGh`1^I0fAuF.E\n %l7n&2^oc&Ng_]l*>sh[q%0#Q,@..at?O+<,0DDQFIDOE`=*\/Q5Z"IE:\)6:bHrpIMg:T^A^dKQ2[KDG/iC8R0/`,iGq(u!qbknW %d-m^Rqg+fean*5W^P?0:>r7"kiA.&`=`=2I0n&$lfe$.F"0c[a3"K']4Y-8baa=UmV3,a=gs#N64P21ckJ?,)%mGnT\u@jU_9I?< %iNBT3q&]M$Rl0@P\[uan-bkEU_5fi@9#^73jg]5m9Nc1Dm:F86.sh`K1"-V8leITO2M %pU^uf?%d;P+@^89U+7oGTGf0N_<%/(l^6(E,AB>Eq(CR>n4YR,87SJiUP %ml:M'?sP3+(Cn=J_0ZZC$a?Zs!T%l'>i>Bg3\="pAWU5V?>IR?bOAcY%PMnn,tkGb;+;8"RI([#T?Jd$feR:[eM-Af?q<.dAETEG %%^i+76PhR2Dr!r,0\eklQ56O;>HE+?n4no#hc,eMj=4efIAOl^aiZYU)5kT[a][JUP8^[O=gh+/p7)8gG2+gn=oKe)dsme+k;$]' %5%PV0R4u]b[SL%\>m2!(bP!C.Rb7gF3Qip%bNK;3L7(_K-QXs^BUEeP`8A9t=hm(7mWdrO+JZ#:hVC6"Hd4Q:-p%/qapbmk:M:Y-bMk16YV=KbUCs>=kfDe?M?dq<%UfIc!*ktP$CW15l>GrFa:6WXkb'>N:DE4 %9FQ&n_fDe,B]Rn-DeGf%-@Nqc8)i^IJ)@h"Rlsh[e!k&6(6qHrS@tY`g1d47QFF(2d.T1(?u1VE?Vd@Vfb\m^9D\e*omPICq6Omr %4C2p-m%_l,>j\XpEMf4Bbd5I#J\u2XnV!k!9NI#mM*;sU\FHV!WS>*6TR46Tc5`lGOiRqpS'D@ %\9lf6kq3%1l4&78E?ZotKBVVlmY-j/RJKFofGB`EZ'Y>\FHiA9;gj)Y*5UN(Wo_:kXhq7YWk-3n:W! %e)fYHAi!`89VN6rqOO;J8JT&3gD*mjIpJFINJg\K>f\%-)+5kAlh(P^W,r(Igi>UX0MQ.NB=\f6KctaM*h"^0oTj(X(<81Vb;+<8 %1WQD"F4-(@il)"*@XI.OuKqG8E/-u-VnqJGGTo`I]o$b5pj!de+7+m8XOProFi4FLW]aP9V?n# %4b(Sc$B)p\%NF1-a0,J%RcC1sE,q-ca).olhNjM-M&tfmO!W93gn;="?Nde7`7-Z_^Y3Pa3[CKToqrqeTBDeB+dN?2Z@#@9O/h)% %rAdBke\uT>2JOMeDo>FCo&Srn(_=H5<]R2;T7j$%+0UqhDtu/rK5g;:!X#+S06<9bNf(YD(:> %HX"NuA0P;N"*\j#A9.+W4FrWOFJY7f8S;T-2`jGWd%;;F)4?D3(e%&]HEQA>mcWQ+dSLYP-mBsq9##E`(O6Hb6r)"R"@n6H_nubK %9)k"gk(%9%Z%XG9GgN[iW,nZ[$55i`'pm;fjnU_9sI`'+'P3r?hV1,Mj2FCh4Y(iVIaq;]oI`Pjsp"-SkGVS-+B&o %7=%A.j2l_R-L"h0_R8*W4[hCPZ2Qf0)25+_Dl@A2[Rk[Vp;0OI(N`$LkRP#h%E5BEAqDGX)*hB#O&S1#tr58(#G(!Q6)ptmcrm^?<\bekk.=[EHeR$mi=GG,\h/=fBh%9Q- %Hf)B*\up1("^D0:-IdS5d!MqsOqgl&,nNTl]o`-k1hG^%D.Hj7qn1h>J+g4T64Cr@1l(3A;U=Strm#2P^H62cISUH`q8KW^*Q82$ %;BE:,j`48*DYI$OFCn;PgOhTflb=@iD!?<*Yc"%R@RB_O2b1Lo^X718b2<4RDORorkqH]>\POuNrHK(`=2ef$PW[pIG'0'j%fhi/n!h)(gR[rKb,kCX""8DGr/uJKQ(YLkCEa(63rptI,;c&L2[H8>DqY8,%2PK(H4[j1k(T) %^"RRm>TX7VP*,A%.qkkL^&Ff#9[>e`f]18>%6a&2p9V3WSeMuq2Y/\$W5&*KkD"eY$PpLE9AD/L/.\+(MYk'^?4U@EqC]58Ks8>Uk$7GA %OS9;>B'&L[]5P's05k]2E-N3$'9;kcdMq?rUU_->6_ssATW^1o5THJqHS*9PfMt=J:@CQ?NV(-"%Z!mY%u$(DEh[N4WWjM4Ae'X0 %^OBC,$ou*:d`?Pu4c3#4%oJm6l@;FGs)@!2@,ui/jF=\.kKJhe3:"b[S\am5!HY'Y*L,QSs+#=)ebCPE:5#)Xh>^b/M3dHNHOsG1Ki%o^0\C)J@^3gs#*ME^4Z1GAt"^,`PHqN %&`kNq')K@7VQ9-SS;ZNa-fYV]h,@d`NUe%A#:rn*6iSUO+s?IUb6:]<$1q_r7hGXs*Kh":Ls4"OCIBfMHBYXDj\\\eR['V&8Y)K. %d/D4ucadGq=Yqm\\2;Z?4jUptW5SQdQ:(/lcbbK[\b\.HioZ6:$.b$*efYJS$)HMi]D0$So"JA4DkO_rF[a"0Go5LtH>-RSHke45 %&#gI(AhmV1$?HOiqn\`I?TgNt&Jl'dgLN1@,EP-MiYI*YB,=!%].%4fg"j(.3R %WNn:&)P*PD-$repLUh@^m6/gEE:rW\]NpT!V^;&F\_m-nqVWN*S9G&s6JWmc7HOgWS@.<.-hS[5B(jncZq%g3\>sOX,"mRCri/`uJVLP;Z$`Vdr$0H/%0X%B9mZoIpCP %+-,_O8@q"0lojRp-5\UC<4NXtXDVc'I]Z %4Nsr5Ek`W=D!uqhMj;Y$S+[m/nWDOF33`.m=_YJV4ri=(TK:auBX:E[%lguRC%1*6h?3KMSH^0rm60C'GILe=;gT$W/U&+\R+QbM %o*kbJ%hD$8n6s;mUCW,EL!';PFtTi\i3W`T\4X,OX=+2nZS\>E-1KckfY*__%B;0o&_[7g)Q46p4'e\HGb#9[n\oBT>s`9U$Z"7>=bY %nPSsQe:Ua#$Q:N4em02p==Sba.[N'5dIA90<6[>icV8'PC97Eb=T,;*g7bc,G-Si>TCg%KckenQa^a?^_2r3I",K7Q1;&LZDAqOF %/P$R$eofnAcF!cBW0WM>GtgOc,Tn+"Z)21]lfk3Uc[.gqHds%6EP0n)8HI\WHUU)_PeOsu_IB7YJ"q^h]4m&pAIgTNci>*?Td>s< %34+n6Un"BZ"Qt.FSJ8%q9"sKHLN&A>o=_i4G7g(t(RIDkQbhi(G2V=@;)4`.WuUsma/(_>ad'6WKFEDGO[$T:+B@bjGaM/L[Ce.% %nsA[dr3SUY4^@qjU*#.tkSG&Eg$@V>T8oR%-Wc2'*t'0s!a9X$'CUe0gX@ZNQUQVJaorUd7=q\[+fW!T)nANT8?F31^C,V'KI(C? %S7qE(gf,onGJ&RH#*E^m#!%\e%[pm"O;%V*X-lkKX.:gZPqdt]Lnc(V6>:sb(r<(WoX(J31A7Z@WUAeoZ%jBY-Hj4j&G"QJUsOM5 %J(+_;P&]4]?9O=QD5.PDnTe)V%@hdaYD#EK4>*h+o??m8F?lAIA,]jg*3E&p9bdl8\ghaTk,D>QJq*:Bb&sbX]BW[L^DU(5S(dCX %`m$/_>p.;N\A7-Abd#2/#p8WNbN"WDW-hZ29@+t^#@IHgO6kj\*9XJS^!qMnd$k6[YC-AC+k)*NOl7,JbigA3;oG4 %Ed2^VC/f$J27*Ae=s8]qqIR++ltLhM195i2cB@fj/Kh2!t>:M[#*0kj'<>G(1X`\FS73f04Zma,adghB*f0B?FQKjhpHE5JhsK;t!$iImo\KSQgK %3&)*Ua/i)H[GSrKQC(urZ^WDfZ2i*_$F@GH9J`V7_'?g7K-u-JI%MSoJ8Goa/4dRbmf%))(jOlH&A-.UI@[Yp!(.u#fl]V;MR]ZT %X/.rcQmDd#__YC]!>p&Kkt&T>KC]W_,83Ya/.'*S7M7CJ8Ys&eWQ.>X %5k$0<)['Vs^jc!@,t*uG1[OMMGR2UkBHj0c,kgjB/qYd3Pn*pM:Pi+#Q6BlNfH$2CYnZdUKC3G5%h[,n)gcTeILT3Ol %l>gKrOA62N:9FCN)i;=b8c:#9fh[@bBkX8$2ZkctKEEFCEkGIHV%MdE=4"]V:=2Qm:WFPZKLI(lR3'/!4E`\Xa^NUe+GTfOlK\a! %#(!H[0D"?E_L@PWE7\l8&/2f#eZd:d)M+:L&E1s11>$d>>js=D`E!elP@Fr/JBr0#APNWO-oo!/JJ]OR=64#MqX[J:q81#d"uK8# %^=]M@DWnQ?obQ9#>gmW5l7ML$G"]Rre*:nCm#lfjAn7lg'e&CWjL5q&Ot6A\q=t]\`?"oCXPSQ8$b,b4EWZ^I&P_4dE27[q$b!SFu5R^EjQ_PWa$?qCT60-b@ZlOU[4Oa)*gr;05IG,uY7]Nk)"DP3YNOqp+k=BM_Dr>H#TtdVm6,6Sr8Tl*o`7 %jDe&3,pR)J.c&Nka]QaHU4,b7'R!9e,o:L8[rb9XV:(:4VVdQe>G?=s/,Ci#]d+$i7!]Vf4Kb>I&P_P`K_H[q)l].(S-] %DopU`RI$5g93,sse`W6I9;V]>1RMDC/QodK@GK=Mabq#rK"@f9P"CE7M;-ErQ("#uR0=l(NdaW%DkRba9tr!T\"NW\Q@;J-Don## %o^uF/ZOuXZ0'TiUC*T5s\u";IWJuLVK0/o]),aUVd<&cQ!DfOrqCNR_M:mLQoNPli80thJ];"2G+dLnE5:ui">k$\40:2<818Me2 %@>002]W8cUT\iZ-(Us$@18KL3Y?UiT\_;d+"1Ro,#!O;soio&6T'>IJA4Yg%;86\a=2D=oCI_HjP((Tf*hQ?F-'&M*?+?`gP3J!Y %lId3VQE8pE]pPbU\tQ7`P1=r6+\+Ems5;J<%=2:A' %at\tjcc0tK+5U!SWPQ-#f@H^9?Y"Ziq-mR3_jS?/T+Y?*a@)n9ICW4\*R3#/4MY)9Wu5E %AhqWL1;1=UoNem=bPEoo#u`8-jf@Y'j7l"/[`gZ/r_;r`s%*To&Uh@XE3#kqr'-?dpY.D'DO%m6]T1=E>(Zg9G- %\I=IbH$7kK^Jb8*nW@7'fqp,ql5MoSjJdX/pVSQ1?rT0ST:."Ks5OS4oMueAhDAR!d=%])>D?1GBEuWDBRtM5L"LQ/hVq1<-7Pks %V)sKg[?ZM3Cn^O$o.?.uPC(R-8M_&SZNtT!O %XWj;G=+;7R[X*fm-#NqBd-P,`)lG!%1ZX::(lAqbbrqE2PgOn&Lf5X-bjo%&DQ(KLVO!.;`sq\qb$;<;CdshN[b"upeYDaUqR?5& %qgqr8m)^QQGR?sg&k('4EDp/QdFj`\HFQ^ngtCH6)DfGhca(F5c'W/!9(t"D1!c6f>)l[0GUa6B';CENWVY"A+7tp35LIVl,oTr] %r;6TTB?'7UqqL8Oc]-tl&.Q<3@Sk1l"V%6#%;l;4Y?J(<5sOL:RAfA[lZKZ%QlRV<0?<32VZ&900T*Ias66\eO6r-[3R'^hoFXA5[itof/'t$sjhZFL/(D&Vpb!fO%#BP-nQXB7>l,hU7l+8.diH#e5/TU\S[dMBqH5O>K6* %D4+Hl*_L*=(Md%L#>&1q"%Lj3>A_*+[UOD?:%ls#5%`j2X&M"6bC1L:mkf;,3bZ\VCY?cC-5=6EZ'L0=K=9S.l6OQ0p+UU8Q9!Oe %0M[e*8ae)H0aC:tV!LY!]b2Y\K3i@]g)FDW+?(.Bj'93D<3MOR?96#9O`m/Y@>q.f9nR#U_[!B6UFR>`9M\,n(XY2/p?>u>Z+[";U["haj`Pdu%P %pZG1,2!CbZXS2u-Xp//KFL8a]-;)WoXRk!77ffE7cnI!b5Sn_[f#_?a;qQbf)0^,Rj:jM;F$A\*2VA:&XN+:#CmPgY"Nqh(#+R?D %TJkQpdus[ %j5VmS5IhmbZop#s'4kJo<^"'/DMSZ]n?mFtRAa$9\].=-d3<6;ggVVQgUH+njpj205VYZXR4*\f88#0U2j,(!-HnlgCBUOucC'Nc %"6cq]K!oiIW7QR,S,m%kn`BDB<8Kj4h$r\K&9!:\8-W)S45<>>n.n.qGPtb5Bpah,O[t8.^GT2n^5qt!Hs3>VHMat%*BVWZR7JG+ %E)btOLL+(F-iM\tFjo#;6R?YJ_1ZoL`GOHU>.ZRuO]Z7_VtlR46%8EPIXc)fkdSB4"K2=e%U3=L)_*so %$nX^-3$%Clr:$)a);9#pi207l5"M2Dg;t"-.:N6pS)#%3hMmV&95Ng0e'8u*(X;3K$e?5*3jp?L6L/NCJqfW1YE8GW,SSu4a2Kf- %mT+T3*EugP_d^p'WF+W:;AVa)#6J-ih2C\#:pOsDN2Uu-&5%?KqJH1SWt3WpXOV[25?DOq"6d;R54\+;XGeZA-l:IBH[kH)6/DH% %RWAA28/9,TP0hLhqe]oEH`Wlg_^4]2r5he*F*H-DrLP"uQ&As@P'9OA/=2R_fPX2"nYDL7'i#pW$_n"LL(_Xp;'BOoP$8Y^oB7O/ %.b$C,7"]6'PR7_O(9@j[)ANVU(RgVu?JQ&s"E"fhj?=%H*[J3E[+VAI3;1?>0e,S,Z5'E,3hBXLPV=S^67L$tDG:Sm=dIO3o3^B3M9>_Vqe4L5Oo]'DI.N1"$PmWP8]3Idrkp=hH>f5%Y>2*"/_=`&4tC3!X3^;;+c8d@tpXC(fi$(Eu=V%p'p20eX.n=#s'MC0t[=pKe,,n/C5+h1I7(G0,H'?aC8)f!a[fT65K5B %rf81[4O^mRkVej5FqA_Au5'@4]mgCQJK0AYc8s5<`A6]G"]c]u"45j1TU'OGff %Wd2B;\Ap^=)Me'tq=/+6"175U7mIUUo6tSIidFrFd)[:#/?[?k`5VH>hk6$sZf[XX9OQb8IB##'-B@?gff6E41`KnEP,e$76JbD* %?$mY4CC5PG@7oE3h:<>61blLMomFYYe(6aio(1+CUiS8HXVPgW2Y("o=E7*%2).^13*0R]6l/RaA"P[$P+jF[6-j#7j=>`ZFP\qq['5/AH#TeW:'WsVXig5R0*ZC8Lh^6FGc)@L(S/Pi>4*e%)rdL1 %5V7%%\9KHn$-Q"FVR)2^X@Loe9pP0%Iq"/-cS* %+11JUo$B3,a8o0@rg7QGJNS2QA-n>9nAf?J%W"9XAg/'&6d]qiO;Ht$5S6aZ0\@KS@51\m>8pi6apKMoLR[H6?]G$`Ys`=n],3]S %!CHj_Il:&+"LCIT:.YTKTkQMp=D6`CT9eShTa4-Sn%1-&;6XqC'Yt&K'j[#BI1a]7pgr8**7ln@-K2Qa:l/K5%,i@8N@;?^'Di:' %\IR8?.TQ4]Ymg4&n*`'>a]oj$m-V$fSU`9j!hSl^j=3-?>T1D31P>AW1'bJY %G)+GFjEKdYgE#dI2h#u=\_Z4e9_>rlj)ug-F4opj]o1rqkFUG!17?*-\%C'"@57-3gs#-"N)1h5\8m;,#&IMED?JH%O"rEp:#]@& %Q.D+REK[Nk-@TC(R8T4&s6.]YiKqr)Ct3n?8i,91IS!mC`%S-KdDR]lam`*b(EBGRF;)E*:&Ftjn]NWqC2=-(l(F=%U'E'U)/dak %9hVER2nRW]l+VMt[:Co71o:(E1K)>jq\ZZ\I5.(aq\ZY)^X?-H4rurin[U((QSO;=UQuPIrG`Hd,e2*'6nOOj>6J4qmokqq66)[7 %]2,9grk3\I5cW4#X)ig?6S3gkXq53%GX9Rd*2YZpQbY9,6"UfoWI?[1LN9AGVVIQfBmUg=a=c>\Z76s`@N&N9BM-nmgFQc[!I[C. %.+@*Ij(q#^.+(uT_t=SHY]iO;b?(b85sUX5Z&s+r0q.:-KIibsLQGmfabF0LFo:%IDRW0i/(tITP-R'Vj+hf5&';\F*SPa7UY?C4 %=jtA`XIGdGGS4k@1`a:#L0p!:]TN&)b8YjOh.+0fLQNHimd\gcebGH:1KD.-<.2Tp+Y!rQ/bf$TJ6uOb'c9gK(:2R+Z,9WF:In2Y %7%^Z[),tC![>d80<<()M!fD@_K=apIYD1AfLen5]hpXLZC/ULW)2ce"U342=LJ^TT?/quZl9\DM3TI.dq-Em3H[I\q(Ul6b.]4MH %)K_-O$I\$P!?Xt=a$U,[SFP,TJ'5pbdQP;_S6b>N=fLuBE"/R;KlM[IL/e?8$%c\G8=crm4#(B_&Wa%0QaM&k^dN#tdD-jDTkrS" %Ej9Z)j<0VkannFfDeK-jqp4.,?sLYqplP)WJf:Ma_2)AcpHU0k#1G,XRn_$3oW.O!"bYsghlfakWFu*^i'7WDaeL=%o(FhC@,S0: %A/C;fAb^4I!dK93IbRrRLDNlr&Kur'WN=Fdr>.bnT18_Pi-am< %SosB%@-dppUT!OmC.uMn>)"Jr>%t3g$nT:QBtm9h0QjI2G"4u4C)LX0jij`9R"mCQ%AS_54jI;?$/lfhq_\5Ubq6g9\!%h_c*:iI %a4N4B^%m/N)JrU8lB=t:T8>`m6#03gZE?,&/`sad#)R/aNRVk"iesXKS).G5UI`a!+l[pDeO7^e!+BCf4okHAa8<8,n%UjJU'd3D %%tOJ_pFp]:!)2fflRW0`s.dqO>N %-#soN-!S/SffBfne`p@i#H5rj810-q]EI\T-AJd"10SIIBMpI-=2N4G'D1?.aO-#+dg4?6C:o&qE/JD;&H_`[7[oCA\(Z',Q28V= %(%q+FklL:)q*(fe0OedMOr\G3D[UfHX%,Cdm'<-Q_f"ul[Rq7\P[+%PCuQbBXJ]WnCl"E?$q6ZHD7h\g=(FOXg*@&!-JL/DE]]U] %V0%KK5N^Vo9].?+igj]$G;Q9pRX\)U^!'upED[XW_[[ACZ@9j33)K)E;hHJV#!5TG"imQE:1PNEL(U7$+*ah0V&*Q?8EhRL_PUbo %0OAO=(Qf(SUID,Qd.8I4:VgrF,a3+'.jq_R2S"KA:q#6ZR:h4$E3u5t_Y5_R]"%?A3ZrUK'Biu7ZN[,@Rm(:o7#cfEs%DoiIbtidM(ABTg2DlCE.r#4lF]5UcBmPBS#kfD\@cS%1Y:5V %d?=KiWR9&44&>TP58`D$orTppih3^a(ce8XU5p=dBAEEZf*+KdNXIu+`glP&4:GXc_@[<:19NGnp=A.o,%kQS+:V4(Bt-EE(%KZN %PfSNXgk=P'A:g"u&O6]LiJ=HZLcX#,r2g=c6r)9+ZAppagnTEh\pSJ_#33jQ3r*N=d-C8]o$gFbuXgGT0$-88FDbm%O#qCK-C*Q+r](bo*k@rc1=S('0pJ$Llq=SVQ&#UH[0*_?cB">8>qC&00lKN*(h?q^oP %6,M`H7bF>[G\oSNZ6;6W'"mJ;?AF75R@dCUiN1>J.@E0oniJK=8]&7@QCm(trC?WZ_P3^GFWjJ%6$#^Z_-WJFeoP+f;dJm-Bfjom %SR)b;mGcsZ)M4A1,7NZ;;4&8c6TqkDjfToGE$!$b+&3jNG,k@G'RoW_;6LCm<&66?_bh:Q)YM>Bj@Vm=IcrS#U*g %_OJ]#L`Rtq+A=apE5A8C6[1uU`=7_`%H5Q7?d-lk9ga03cKla\B\S'.c7SI=!(q:Jr)kh(`$Epdn],'YUQ4dIBfCH*=mpt %2LjjuX/kCa]8RMc%*bE\A1`KaD.*@5,bVM]o([Big=E+'Z+jJ[Hd[\+?%MXg1]mGN"i'YCh9h^o&33:O$=#4ofQLFYL %O,h[8E1B,#0$/*iV5D(4ia1jdD4+lcKIa$p/[8E,ab9;jQDCj+LpkO4(3VU5J@<\,(2+@pTIk5dKt[p0Zm>aK5C-E>p.@D[l]26e %R:@hIa%4UDAcc+kf+D8V.1tkW//UkKYa1AU9S6HFI8lG59?3m^(>>M?9s?6"P*:hYg)0u0)J[UA_'c`pL %J&#,o$Z##'.bI!jk#dO:;VnR'lCim>bd!I?%^.1ceXR9Um;0/(F=;=Q%tOj&akep5"?RXEBc7[I%G$^@/gq(FhV$OrT.P'!a_;)l %/W=&DBWDNl"?@ICaj"/h]OP^Ym+?L51?QHI;X=Z(/_M\elniagES8@?9^,3L[4Tkj_E#-#%Mu:mbpGXYG&_TXoItZ,SB>Sog3@6* %<^ArF$JRa]s0GrinW"!;D:FQHs)BYrF["G"PQjQpUNoo*cRHH*_-X+!'8ToD"IGEH[!#Lgq3K&.>_TUg?XnBYqHQTt?gUM:"l,WC %Rn6u[8rTj#o2'eUI.*hNG4:ZpI!gp+Rt&'DQd6-lpPl+1HFkVRPuKjV@n=TqT]0\Gge"GhS'rE!1*./[hB1rI(H`+001Ig#goTn= %QYtT[HadF(j+]V+%=9>XOG'X[9ri/NlC2;A"t.`bM)p %TD+':Hn1n/qCqh3mL(E"^K5n)cuKf%dsE('6eB@<1gKDU2o@OmBTCVmV`Bk%A2*+@PAWu?gXO->dS1frna<,J?s>R^IG@+TTW(cN %/)OtgXqBriJhj0VgJM56nZC-fb6YQp\$n\LKRJa&1-@5#2g!a,0Z/UWP;>$_.gZImlEX8o-cD7^!if(&GF!$7pEaFp)pEU%.BH3@bFYu7<5f)VADJN#[te@jh)]psk/>h+Zi)Y;j"i_q:pd:'a8"b-_tG6VVq.Jp!) %VYZCCdG^AJTg-G41HJK>)TAUP1o#\LbTK+"gl+ukW&r5en;*L"-9t%AhAonMf%kNW@R/1HbL/H.I=BM(Jf%KhPRtcH7Zi4rk@&&u %NV&6P4k0?u@AOiIjp2bBE7S[O2kjqS-g&*'mM;5bMVqd=\f9j6E4@\j!Gtt4R;p9+%T5)rFGnAh;`tP[DNQ5WQgJ[QH*7M+K0-Y5 %W$Z\&7d"1gj&6E2kh;0Ol=u.Cl0ho0<0QLMTus]Z7V@FIX9qa_pHW<\d!tDLLm*F\%h,R=OHAe3-P1<'rs7V[lZF>0@sZqS8;5;u %C6F^JDtLifXhcV2_abW=&V<04`HX'5Bdk:WeeO0#;J0fV4K\1>7S+sPFYH4-j0B/:_1+7='cF!Q`R"S))6'PS:39\f\]:Q,XqDX- %S[9Hl=Zm[1lg9'tbd2AJAFLS6jtp_(A@AKG=-/C)eu35_9o*>%a_r*)@?ND+K`#H-*Ml2RdnnqPfk$fR``HYC&l1O7-+Q9i$ZG?< %>Tgf7iK#u#0efQq>ti@Y<'Uk\an.!"L*4L1s-QLl,@P+a5n)VhBMmUp5n#qWTLF,^gpo_e9o\^UGYc:rK$,8@T.&-^]GV@=YZml6 %b1g&Y*PYs*EdVT6G=^bI`!YVNORQl4'l]*%Q7BfpDTYNqGu5B.$O]aA0'9!r`hQ=Sg[LC=Cs'&Arb7AdIp[,^>;u+cD6A?Q/R(g, %;-XVo<%V?PfD_o2XZ"i*@HLOQ`WP@A$'6!sGN!.X^,QS6Cm.7_gp=5Rkp^I)Ei,a[U*k9\WFU=D6Nr=Gi[!!ZfQkOp;Tnsc+FgrI %bYQuWeAKh_-2MU%aB"@ZW4#C4hEKhoikEM^T4d8hR5KEBftgBRh5pPDM^g#*PM6ji5-6rJl..YsBWS %Oq$3^+[fo#k)+_Zi1@'TE3j?<&,Ss%bTX4^hYHg;M9E7ES.MQQlNYA::\Qi6M#oDb!NrOXS)f'5tJ.!lWj6\-BLM`RSm %%jCVs0q:W0@Vo5r)`_be*cSD&P@_CIp5tfZ#AI\O0njOLkNCm!3UcthKM,Q)/[%aoktrO`Lr-FA*:+0.K^+KYQ7];tC_X?`gd(bF %mGg[j`D,Z?[(E'>j5T302El$9Y>@g_bRfnR(H4^".&nn;OS`Y=n]QNB)l,5l0\a&#ioXZ?4(qBb9,l2c[>u8D(H40[;@UFd3^-O6 %0L"?D#>oa).t^`XX'T+l/>7,*c,fl,aN`T$9sN3>7h3IQ:GQ4F(diD;ZQQ:tHs(BP.+<\e?M2qB@kE(ID(-02J %YTl5RY.b1:6Mn3OVK4Jj]SRSf(I%#s71\9rIudm,N&0BZS\Q;tTLV"/IgA.,De'r)FZ@32Yh7AB9WJi$V=j&i$QoX9XRFX%\%d8p %nF\+S,8G<-G%-_GZI#Ze;s1'PX%GM353IObB$n]BpejI"_o+8i"lOYAIi.'CfQOfVIG2!rpiO(C1m?q]NKXk9D5q%dZ[mP4)S[PB %k0@2kX0GZ2^b727l4@=bJl<^0]]IKjIAiStO/<@$gq>A(jAW@/TofOhCelX7Yq^of8/-;3iX?e)Vo0bJo6?0:Zp;1&0,>f^amFfkD+=H@k(Xm=*g\b_cO:Li"-9]GLDeM-[IqT`N5h=];JNLMMPqH?aXfb^,k!3mNjBkK8^a:7#HT[>CO,F=j<`belEf %[?0B(34H8uCEZ]cGT>pNoNdIK4H4OWpkVl]o'n2YbZ'6>K="u9\eYoY9CXF2nrITH!`JF.@XfS?-D91*(#Nh\$nlHZ0`jd0k5Q]^KR\(#E+59R[]T%/)S#UBL^oLOBY`R\t\'S$m")oB3bDrXVUAcR^I"@ %=/-L7?(k_QRB34kfNu01gC10`/SRk.5pWI'jD8qdBH(EUCCu0O1NgfGXg3_O&*<0(prQF&]_lF#$+Yr>NTB7/%6H$; %)<$%E0D0sqNNrgb*cXh3&6tpbTQYkiqiV@0iPoR.)C+eM\$YA^lCDMF>l@8GfM<`Nn`#amb;tW%./At[]/htWEn_g&n1/,jZ&AHG %F]"=EfJ\I2OT/bpS=F8QWQh-Y[a)`F3$Ef!OMr(c'\LKoNRI>kdrS7T0_TnCdT/K1%q*=D/\bci$%::P2oik3>$oN_Ftnp)0at0q %s"SY#k:.CC6QO(_1%\afqkfoR8Nj'g.*2O59_2!Y#P9Zo:j;23m.mOC*?&kHQEH=j2T]=oP/p=s5)T-Z6es[qO$j0hRBCIs*f8*n %Pmnr6;?Ri'O+qoY'f-?b11-"SuOHA,]`\a>$J4'7=;ZCU+6j@B9iW`3S`[6NNB+@o,"\?JED1A^5uYu?b0V3!,+^& %Ma^8Wkru`Gpc<6Pb6M`amRm68rk=lMI138@N)StiK)f-_.S^eVqkBO3\o^/aZIaYrpW=F]*d56E$AWe8MDBUt-4KC-WQFdT9'LEI %Lq28n_)%Jbkr-Sui,u%@a&qu@2>A9i&RpqE;Xu'"Y*ke\[&b_6_PKH9N9pG.H<8BhmR(Os@r^LC*,1mF-IrLi)kW2V?!bZsJ^Rt3R+IDW0 %Os[3Y=@)dr5IT:lf'qF3AUgjE'd."oXJC\fYD;"hjGF.UU8@#cYep6_Bqjh=.l>2i]2k>@Is-!?IuHc5<7:RW8"ZeibP(!S=]Qm4 %mLPJU9(.Yl'98dF5O\uoZ27eIO.\lf[,DeA#j(7e%EGU+0$QrM-\'Nr)j"5(plP6*GN"jK,ce$9XZAITF( %F]pstC[s;5CM'XuB!;?R:c!1f_bEVPBtes-#cO1P-Ai\J2Z[2CErIX@Acu_t2G=E6,1^1[5"Iu+;WdI0L+-$b51Ytd^kSQf;[bsL %ge1P\PUEh+^GN(1'LRs+g_]#>C'gaSJeV=Nl/k(mJJ@^Eh\`6+TGES[`A/Kh,"s`h^o2j-_dlkJ%XAnK0Z=U!5dDXmQpS>nAQ:;A %@48u,_sQ3r:kU9P+N;5pKIM3i"dj=QoMj7k.>H;Ap?_(:5QTTsJqm[E0Z=U!Lq07%@#F2IWOd`KdW\pSAlE&ZQ`o'.VZ;Im+GYf$ %U&$\?Bo#R'hCB1)#rHs?,dP67[MnfhW%>L(C%)F:j:RmDr<'P43C5I7U>GQ.R:;1Qm\9+D"8gm)+d$mnYDfPCM%%pE,iTSp,VnHfNa8Kn985%YtL8g;/cYWFCnc_/8)&PgH9pJf'lVbEXnUA.*RS2+(O-88E$jC":Z-\p8!pWE)<-TRRV.@=cb,@kFik%;T+eKJI, %_S/gacI0nC<;:^[iWd+Rme8SN`,IVP9,428=JN1rm[k/@eECnp3%XQ^59JQf.Ptor:%79O=q$V?p3lAUT:N %FshX]HMHhBY?@jne_muXn=Js%l]D11$#op&R:8H^eiL7M,No.CkGJ6tn6$f?=a7LY"-(!7p+ij=2Kg+sX(NN-od0ol: %[P[MtYGgdN^)dknf_)PH1h2)YRu<\ZB+PT(S$BDbNsX3k0) %X!lFS\nn,]'k*,*'XXnn[KF*Ki8S1dTSmtKr):mK\[pP@@+oP!J1c)@62/W(k[La,YR4YiE5C'.L+`/+/'p_d/R=)`\3r[\^:V_q %!uJ9@/BQ1KaVV6'kc=NF^W!s&b=X5=3?*;lREZ8*lt"gZABnG"MjB0Q7U= %6b(Hn2WJp$/Q]IbDYDfIBikp2[UjY*?,2WbB'm3&]Z:!s[gdt:%DFTi&#'#d,d8E2C(B!"1pA+j[H$*9Yf?RGC`^J/SA^9c$Wd>C %YU1/[riia]L]NF59SdOf&;(4X3@.9[*Hdb_j^Ie1jbsgPNg?a;j54>a2#Pg=W0+Fq@Ii0P=rZ@M();n^,eO`rr*4>NU70\BD*2!c %$dX`+@hC;:"TO^AG3l:cN.2m9BdETqoMAH1qJ2lT1MfTVNU[J4m<%DCmP,,j(kaGRKVT=,6goT*i\:'i]K9-tI2?J]rEr,`jK;T" %K@"t%g#\MKR*#`j2,c2F$)U;L;_YZqgksI*1Z'7kfR#HR&Q;Z+%D@Og\AQsGMqnO1m(obb:><#Y %_li-$)/6Ht-+Q1k7U,8_4da;iES2CLj(n%b4W(810Bl9!mD1&2Z4qZCW\q,!AEN8W1lBrM4\3O59^u)^mD5q-Ca=?8MYWUKJN_Z? %XhaI9IQL,S#g-L2QsJkJ@#\!sJIlFn^s+OF7J'`\"YMcO*.tI[lX#c96Z4ir/$d?4[=_*jHd"*t@?<1`*82/AQklIqAVY--FO/Y*ii1&l;qYDu*+7]l[R[p;D6TCf %q&u_S0nF$nYWAo>(B<0:K;$H$2]TA2H\6]]iXMFG?_SWT!H544kJMZ9H$8K_P[6Sf#6A05?MEkr]V3PXggtaolse]*#Bb=j#X'g[ %K`FhLU]En\O'.$&V4@Q^-lfS2^cep$lWh,fMO:`s@)QaJd*,X+p]TFt%ulRuR&hUiMJ;55B_Fm8pNR&jCHe\,;_WSC")KC/H'80W %6\3`$bg>Cqe.bS>ME2au]m^GdbG*_imHEc)*38sG1cd[DKeMYQk]V&kq-;>3kih\\i"V2h %7n;k-I)K'\@>1aX3\`T;d:6jK:=*1.]r]s.,#(r@3)AP8&H$S5g.ihdFFXgBGmp7)d;%Yd:Js(PPPrOF>Cl299C[f-F,dlhlNSq8 %Hi&V;GFkU!^83=Fjm4\0\f-pF7d_iK>:l^P88s])IR9W:'9+Q`iHuHEr]^Y;I-g*O=HdiGToFI,4P& %M]7C>fO9>;gj8Y1?RN[!3=cmf/ZDl1X/(rY_e/l4/CJ@1:[YJNQH4[7N/<$arn\T:>CQbJ_q8u*4_NEHJ3ESJ9F_05`0$fE2@TZ! %5HVB(H/i?6A@jtYNdfOk6:oaMP$*b)0Zkp2>n?L5oWP2DLLDED/Vd^\hqQG&)4\X:5+#<^a+feHU_g+YVOI1P#FYcC$CY*NHD!j. %@'*tQbeC1Lg'0i6r1ohT@aMB#R.ZUTgml:*_h'fcoCqmM&2ELj>2Y;C$A$>h$&4=>'Ss4Z9fi^4ZE6WjZ&#Z@Yb*(,]Ce5?N6;'_ %d#(le2a3,Slf2pZX8JM)Urn:!h/E)q9&q)Q6O@P?8d&Zr!X.&`9&K%rG>h9=">u,q&^^G&[VBrbkcZcC[-4^anF.HSL)Ll[;t]`0 %pgQcE^\sgo>qn4'[g@`+rP/#8Ef[T@&VF[%(R0Pe_Rgi::n?s-q1-J2!8-NgQk*l3#LH.f_gF^Z4b32Yo9i!.UguZ^q5,?^V/8Dh %.CDPQ05^:]:#A@&.r&`]!/%j-*V"-H4rEAmQojLS5^f4%O*D.id"o5J6QffJ=)A3soTW-A?*YWh'f`3Fh6eEA-3Q:a`Nfr(m*i"2 %R@+%.W5h@K$SePNXKuh7@CV23#jTgH/iT9j8Ib4o#*GrE"AK(^Hm%T!H"Wf=TW48<h`m1]%O1Cr^.\'laO/&%"io&k#*=%cibdIU`^gHj2]TI3(lR&Qg9Nh-N' %W>R1CjEjY'-djlT7jGHR?%4R;98XoSH6TUM@]1^'k_Ue4PLZlW>=TWuoL+"OFS1(F/tj/"&7<#(Li/dFq79M %""(1m:8i^H`'D.ec4MpqJ/AQ5bTSi_Qe$!QjTjR9lr!pc(GkHIiU31@H.<(4=t&Sc*)ZmJLk5N"Jqb+u9n.^.^U*Mm8ED(u`,QgP.MlkQO]=:$ole>!@Mpj\>,1L5#-rDBY3?Oa0ke %O^Ug=N0t7CT65&pQ=3)E*t>SgNjYO3[>_OFbHNg.388,i*,>k/AERXL*,FLOL'$'aa'-97Y^s56b-2#-]L.KDT;/>4`,[EH'&UYP %g)=U^Q=O*"s'c"Gfooj\.3&f(AR5Lb.&!apX>S;CjLPf&@oUg@Gm1,0-9+=rk#`!=:!iSh-T^FgD[[+'n2/LX3S)%l7KI@o@kC5- %Tn0Yrn#:j4S>.ZWXG-D8h.Y!*$qofA>!uS\AQU"_K1g&DQ$-_@36Pp#&Bh %N'a%B\4_Y>=GF6J^=bY@,%D=)V>o`cYq4)&^,7h*kc(r+J[0"MNI@qVl;ibmmOBI=nlS0e6jnjTZ+PL57WmOPPk,U`ncYooU$EP,(4WX7$m,^WZ?oc#"TP-8iKgo.bgc91,6o9iXXN@Q@LICm:q,:J!iI %":jpMVXXo@F.@F9&'-P`omt+)d)-\(+)P#&dVVSla%(bS4TG;b`P148 %gk;":a:Su3Y-9f:FoL*5aepct1$$cJiD$LQNFqWD'n^K*EO9Q+54>'X%k2t.ARZ_)%N][A[+V;ujKfJX<7&?DXM-R^DD,sF5Iuhi %q8\J_jSfVD-<-SMI7DR:8sa4NXM)`R!G6DXl@j+BGe(9'IoKck*s'ZB*fDB&_*F[)81+iJH6oJ*(.ST7es17-\&UlUB1j+$a_6oY %i"9CpNS?XZ10;Jp^F:K7I@\<9cM:7fhWho6]`MfbW3K##Q%!A0]D[sma#697(8PR/'!G]1H#i^',7?W`-bjn.c0K`5s8@9VHhp8J %iXZ9$7r5eBD6o@GmkM!ArW=%;#(eWAj&g=k!0h>ss&]KJ_OBg\ka.IDC7*39m)-GmUmlaqG+,)6gIJuD\>7mG3O)3dbY3K9h@?c# %DUX$_B-"D?Z.7B!LC5^f3IQllCEDX#K+#?HT/ot9.c6;B&*cZ]hd_FIgcTW\#g:.``tGiok'>'&i!DP"Pe!'$g(%H''[Yj^XCqFe8K^U#X?&3^o=lImP/VfG<5@nWiQg%U+-p^n"X#2uJ:LKp%N_3Q;1oE&MmUP$LGJ'KK6:/_S*i %/e]Y\o/J'Wl"=R3tON(iOAB+8uMX4(u/Pb"]JWLIA%WQT:L/:\0]?r@ba_afpF(6KN#.Lf=&_=$qTP#F#l_hp)7GA[ro]EDZ>K*DPU/S4]k_p+QD0&$sZj]fq"Y\-79E=?=,6bhC%J^U8*bq_H#!Y0_t`H3-qYp3^'^ %qt!8K([&^$;;s`p:DGRE=%rXfD9n$MJo!;C8ojeNB+#5;hA=u$hB_KX+$-5^T:mqLh3[G!qGB3eSD9+`@3*$$rbD-'e]0+V0oBLR %EQ*.LT@jAt%E8po*)>t#2h-(_LQ0s0\[Q$bK2n@AY[M]55JGB^doj1T>VbG3fBHPj@sc$+]BFHjHKi8u %M*a3A*D-%UQ]fgM!@'[in7g3\o[8B>Lq,%p6au%O%4gbr/_;7q,I*TrZ@n:+$g1'tVb&X!Pjj+95uW);0#flKFa]U$g\?>-%$OU#anpM9),W@:HhQ$P41c).B:V[W^A#BeQ@KVO$?.[1V!1DmtX-)>l+D" %H^\.IC-gjK4:,o,;%d+opW;j>khr2:+nH[3CJEbkp1"+-OaT_8;EkqS.h#9U)Kk^Z&64,`*DibI_2#sQ=l:fir:/>Y<4"UQ-FC:X %CoI3c1uaP\+uotM*V%AEZc:NkUIX&uc@A"Ai/6:E;1Pbi`Yc5ZfXhdN:/t)3Ts/t5.!fS+:NK%fHVV^(-""l6Sct;lXQ-)6/SX(i %7!g5j\)bdMr8Q9H*)-:e:d"4QR.T,P\;OXEhrL&2Up6`UF.jC"7iI$/O[5qN[7K?;B^or,'h7t(<,#dlZbchdX0L0J`Ttnmg[kY7GIu!ZU(j)*f,EdD@?:_+AoV %cpg0Uc9:f.hfkcrUS2Q4r+);Xbs#LVS]4@(O:KkJ?1cKMGu/b-TLsiT3rR/"3p6O(3TlYA?BA$#8HRp9K?, %%X6/-<2P>C&%mo!CFLe#*3[JdMIGD$:=fp:Qi[fmcVQq)gh'dh[j-ct"rq`E#DO"kOh.:04*VIS?^H[ejQnqV?eGEl;8`]R)4A5I5L:^91Mo$N(sXbWO %k[PQkG:S50BVWgAf\r.`VNG'=QNm9/ %F_6*VStmF1IP0$/__:Y?MqdUkE95FE52:W8?>hKp\Ol8S2\l)W9D!^j3tK4K%I,<+5Wl"mRHC*+P-q7`Z[r/&fV%EGI:8A9TJZA9 %_-X(Q05fr^Eu0!o#IYmkSOsV2Cg2,M+>J2sS15*'62iJqRn*>rDd0J4,TAM_?C%"E*l\u)1Ai^\]kV0f`\;aBAl]7EdBR.n3j^Vn^!]fH"=djkd2e\]2l($J?eKIqs2)b)E;b5,DV^AZn3.V%pNW:7Q_=RR]5qr4b95>e#^b*r?^ %LFu,[>s*iP8Zhfn0gE=/`gVBss+N0CplpT(J4_j)5b4FrBpl_0.Vc`pS`uIJhho.$>')/>\^_;:J>Los?Wr:^Mk?qMhSj8Ih.$[mZ.PSU.[R70_Le@Qd7MqJhfe"#_E?^[BXj'A2T$rpmE+gj4=3@?T/'WJC?R5Z:a1-o>mkCDkh@MUC>IlZXP %RPPu3;e_0U30E?P#<&>k]p[##"HN\VE"dWI/&n'oJV!pS;%[\Ta"5X`5EK'\85!QW#SD?c1\3h`rH(-Q?6H1G4%'$+q+UHRTc6sj %[rWo&@hkA-Xq^c(Ac;)Q)a[Ti(Q>*P?motT1.+o\0U/(\VLtV_Cn;,kJo60G![9XZ65\Ai7FAqJ*l]0g=iF535C+/=WaID:MB4&Gi)PJQ?(s9a`UF8/?9#es'k]G^J0GLV1AgiNJ6U`-<.a-(c:Kc.!%unJZc*.I\nk0TuL9QE!!X_EkNra<\ %:5*OJGnja_(t5.#9[[iF:0A"P:DRFbFr;n$]J$mPMUKJmpEmlG$%UV+*rP^;_8FD-c8`_q0DI-qgR%RdoVOV?#nq=6RtA<)l^ua_ %)EI08pqg/GQd$JtN4S.9#[Z"A(]1P]l0Ci#[OQG1-1,]`hE!]iTIT9t&;IL9*L,P(;.6B?i<+`G`N>t#qCZSjK2CS%UJq_0P1]1A %aT8%A#%%TPGBU0g_r3t5N173s)n`q*QBM=eoT;'D&(2>q!k]`D7$72:5Vk`n_l)+A_WR4a3IFY0:GmPK&*'H!7G_%1lK"c/=Jj1akgTQ$.13BRWVVVs(UlG2rIG0s$_Y>c0PFqf?`o5BmHhs*9*C-qPX*BQ\b,,[U;;?>`FT\6$ap %9gd0M-BmY:ZHIE:L$3q$$=4llj);1JH\I!ZD='+IKX>Aag&$=okTo5I[JaqiUcee%Sk"*#D3OZ!.!p-BR.fs;;tf^)ECZ#\-mb-' %`93!r8OM/uc\k`M*W]iuj.*JH5hY`_L86u@F`SBC+RKb;pAX`ls4>a!?Vc#/'701cSd>jr?Fh&NfUt+GUTO'`KHS(fYUQ`NCO1OP %gW3Sp3uUo;q=9b::oTtGG8EtqpZ6[p28,Bjp/>XTMlbiSO+%5[hU`A91#h"BGZMOMGBeeAu %?SZS9Us`VeaJch&s7ZlFjANKC-pO5Mk*d1FhO3#?8@E/'PZ6d`_AW@JbQD-4F<`qnmFBAI1rGMtF"95kA.k-=@X0B!pS6qk&Y %;Xf\H0:@;+>'L?SQjmL+mW7(s]S'+EKUCQ39>N\ag92a6FM`b^MhW9Z6?TRiOjhn;s2Wn6*mi'ubLV!B\MjehW5((378ARpK86-K %E\[b>9#ZlH?Aa-]i_K!+kgE-pjCF(5KQ@u&+t)\M8?-pV6)Lji]]W@0'QP#^tronC#kH9+N\$)#$-3@Y;V/N,$nRTR6&1*OdNCnIeSM[6rL!KpNMFjda4:Be&n%an'$N029Ss %83[0g<'1/2PS3JKOMX-W.0*[H@715L['U#t$&TlJqGl]_rXW6l!P^:D0+SQA3`2\n76QYPFKA*\H/A!QJCa3NbLPK:eTghg>_7u9%c,='!`6oITjr3L?B6ZLT?Ss-o[&EAMf^l< %kb33o([5bWdDI!]RgVk?4lGP+cqoJ?gjCft)0G)iU[%l.4U&8b&'eUl*=6HW&OL6P[NhJ)I'VAr7_!'J)k#MfTi*p7'\X,^a"I:5 %!5BP!_nVU(S,Pg%jp`sS#N"[:d]#/DoClc_6enf@DeZ.)=2=]^#sEjUa)X0m:DmU-(jfZZG!8SjKW)EgWM_4 %CFd@4O/&;i\eC-I=HhS32Np;TG?0-TbPIOF3oAT+,NS"_ZSORRJJok[=)H*U'&(hiIB,$`37pd*3TaaT#('c'`rctR %UGZ\,cOOl91M?ACK5.c*$OTm?rr@1oDXb87XM"RdciXmgLkS:#f9[HfW/7%'k]sr<]?h0N):J+=N/F8e!.nMj0!]U %oUP4APVXZ&/j?15G$4N]2(2Sc&Q&n:IrH*fgbJrDPek,mrS0@7Fp0E$5gW.j5RY4:EqkpT4F!9UH;Zm%^GH&;W\b\4'dSa'ZK0p2 %0iY[\Q);ZT/Z.(;j_:UkE6sVHrk*Ql %_'2"$92^%\Q\h*f5Gk/aiXrR6b,dQ'dO4.MH7ZM9HL:kXj]o'G^na)d>AZjQ.j#HUm3H%*s(O/uiVe=]J;>L`[SrX.t&[\2h-h(0+:b,0jW3*F6:&>'1$/)IkT05K`F)6="*W,1()p049DprDFBgHTX8QM9Vl;8g@6$X>SuRgXUuRp6q3=#[1'?:pn`)3^.'F %W4'9S_PrX"dRe@$H)N6aoRIY0Oi`k`$LSN.;NKjq)#12DP=crD'(o/TT0F.4=igq5LJ#p\9#3g[%mXlKJU%"mBbN-\86l,]EC&Jj %S1fk_ntPO.ne1_IS>_(?s%^DJO3%_MINYW,4s[3XWbRkqJIqU>'&4q;aJ+V=:^q6&0(LT:,u?nI>NP/!jKY@%Wja'cQmmg)GWLWF %OX%6O9J\-S5FD(QX4C"#D>!WU_`ADYJ^`rCML#o6(sb!^TdJJSW_)Dtoq:Fh9m\Sbn.1-un+YuABG@cVT)&>aa`l9l":B<_(Mq;Q %&h&f&2Wc+m]9+C9BLaC'j)^[59Vd,XSBU>.^;%4$!I@HdpeO7n32P#$*@SUmH%V)@Dt&7KhEZ13isk,U55=X[r\O-M^V<.mi9KD6 %r6e7os->eTgiML;QfS %>#b)9G'Il2-*:\YM[o,`MkbCmGB9-rrrI4sX%L%WI?T?_TMV%U&T6r5?cHLkRG^6:_l#@EW$pN,#u %%q$7Nm/^n#$eJ@%Z2@e[\4h_kL`PP(\)^TV]2nhY#7p@WFncTESX8(#Ih]V_HIq_5st$)eG0WChb-2 %/:hO(ghXbHAdN*ucFkRK@2ALRXTL0ES$_1#mU7(;/HV:ck?$@A=obng_"I#"b0`Z@lIq["U'Cc$PX$FZ)1`o/-rZBGD-=Qs9.@[^`.q8dVD>ml`OsN[;J55lhke:0"oPO-ue8-O:qD<&_/[5S[FkZKW %[G.+d!rm3!WNquok^`[L^o,bZ&o+>G:0!,O?Jk?B./kn.FThBL;j2:8Mif[n^RXfn2P)B6%JihE<9`!!YZc)IZ)m+oD(A>@Q*n%8 %&'].aPRI.Yg/]u4%sM:^4GAklG2ke!OFGEME)R-#r.#NL_AJ1)T>0LHD`RIE]lj8Pq*'I\/:VA5;X!N^lD,ul6,iBp='G-#i$Q1g %jam*6'>In5lPfP,k%28L7D8"q4n@/=FhQ!dhJ/VUInp9#qmd>V-/bm4ATh3/A[eqq,Qcd)\%KprPn^6,>k9_;$";S %@j"moi#kQt-e3S\(GgQ:mR/?)HR5(T8lm;b^nR%+&r<7,!=B9%#K;R[VtiJn/\NBn'Q!\M_>f"BdCT/6GOV?f6g"0!d*`N/#JZlIEm8VhA/s7D+aK;o/BVE-:KZFI#9DdEl %?/u^mFgT3r@:TVs.J$E$Octo?(L?*TdVrlmJ:b;bm9C %.3^.TQ$0Q6jY\K-_DBlRG"RIYne!\]fcjLIX/>.B-4i/>.+<=Xg]WM*7(2d`=C@JpK0$$d7o=X]+X7`Z9AKMmcDAo1^BqS#E8R9_s/WI@`YpU&QB!X4snSJ8Vb!BO/=ORK>(6dm\Us %?p;-g/l/mt7f$fQ"_SX[RS];R:`dWT$0@-3LOLuN#4>q6N4PZl[E\E?c1OF[=blB7S*PiAZ7[_g0%\Fekct)"F8`lZhHG;k*NgLP]G&:Tg#r4r %Wh7cl2%!SQj1A*Nl\DMKdeKbCasP_9JbMn!URZ?&TS@GDJi@N,7GoSGpCZcCL?@[@oHST,QN1)3GZ?b)Y!qj>[79CDkXl!HG/)Ib %#[Vn7$csrA,C&mkIP?tpfm^<=IU^>i_tKkMob5ud>.,MiY+M(aD`TqUpd?jD.@UesDYE<(8(d5;LD6BK4,BpY*oJ++sSXOFn3Xa!k%BdNC$KPI,c1N22bM!\R\UIp0Qn;`eju1Fu+C*#idjs^X.LjV=*(?37 %V.>qslPLX>Po7f/'\me!j,^epm[Wm\[6&*&PG8cuDY %n;BY2Pm1h$Z>`*/V1Dd=S9N,M.LjURrC$im*(<_i#%jRZdLB'=,;3`B.D:%q_BqN`BD&G=ZeT/l#qu`q0fML#Y-=UC_(>L:oL2au %QmLZ,lCoa;b`WMZ>u?jkAtdc'%8iDhI\dcVPm1i;R.cb5<>q6YdhkBbP.l^b#EMdhc"u?l$U4'$t+*0>j6$TLAje5l9[T %BVBW14;**Y"LFb65uCSrI4NhV %])-B$W\cC;r:sV0hVg6(b&Xe-oj:2Q4ogp&lk%p[EDqPcmO8>?^WUe7KS8F"@>W+Xti.=i>;0m*S^V1e5#Wg#@elj %";:%Zc$fO&Pm3V.QlZa8ICOd9TQ5[W#d%7e/L'][K_XKPJN.c_(n7fk]0VB=GCp97Xtl2.dq6GWnkRSf'U)LG$'ca %Wcn$ILn>ISqG.&]Uol@5e9G)>'JcL-#?Jf[Kt^]lNg% %YX1nRoe28I0(Y<6`>-$L2I/X*=k/_aBDutYNjm&1k(Am!n%\IF9!R\*m-uIKIGlAH]H+=O?g82oYV?"-MtaOD?ZS-[Nim%t@bgq( %4F_^Uf_&'C"_ES[c#E1Q0:F1gRq4n31!P6B4:4_+Y*b]52 %V*LfRajO1PjRNCl$pQ:^oD3NZ$_HLs[*FGWC%ebBn#e`PY5X`'@G2au0%gR[\_cm+'AB#-.n\Dl,jC16,f7Z(Yk212>>Mssr(RAY %M[+C?6)^l&Zs0e8nZn/>LHpmoo:[pHojpUSSA7`:3q!R'`!Q!NKd7m5B&Wr,"5Oc71N=mi[]oIQ)dQR.HT6o?!@eqC.jaQgRH\9Bq?oHN]K!1-a43gF`-P;-Uu %9K]uB9&*q69\_t+m4O/*3dJ0BQsH$LCgk7%RY_\[M(:[#EhY/Q4Bn>>kbc%ag/UM*BM1G5(,NSJ+e^?/!'QgAkf(@!r0f`Paf.QT %;`Z=#f*"W6nE;cOC2fPQbI3gP)`1Up<^N!7CGX9P?W$9M=A2ke<-> %2$@!a0sGF),AO=dJ$ou2*&H%8ph2YYd4-BC'PKm6U2r/,:V9biL6\[0(0&eTinoF;Vj4SEjoQ=d&XISBo__V#4bE(TN2YS@/H=fN %iVtC2msCuWT&8J/BW(,4#FV>0&**>T6osBgBQ"#:/hXXi;G#Qcn1Y=iBr]HLr29N'%@j&&mI'-ENl+%8@MMX/S2>:XbSB'8F;R]P %CTanO@5>.!!`"u'(/2@#RfWR&OLQM@6r4*'C?Z92&HEsG?1]6N)HLpMKs```O)kRp!.[1jHRZ-R!(&Kp.0Lgp5e(Ic$j%"@+Q;!t %"G$gYO< %`C3nc&,+jg-KBsO'Z)?fhteSAbsUk.>+PCIBZhEKQPp?.]M1V&_3RQcXn$4*lakf@q0s^.d)R$E.)t^`/N^bhuoT:VT %`uW>,hb*S:_^sZ`;+[cn9H>?npPMk-X=?WHG64[*W17LeV+sM7_Kj4ooX2,h72XbCnOBD+d&23\CeL4jFcbdqO+\Z7,\YCdr$Xl/NSpbhC %KeVTWll9&=8skm`#G,D;OS8+;9$-1>+n67AL[UM%c1VcbIcK'a3_C5K[raK6Lk)I6AiX8;YgHCdGSle-L#`q[2rfU2-1>7jdU)PO %C)B..Wm=t&RXR33'd\foEB.>2.q(Q!bOIo.2o4U#+in5RDqMM$`=$D-/&Vho<9"LsT7LZjpOBUNU9kn2U458KE?T6R6UqIC@49,' %Tm$fUYV69+G.d1mNUBG()Qu*_k>rBTD8r)@nU>:r8H79Un_Bej?-BRVnRY;5IETY!7l@@s8]*:].(1UcC[pi=q?VY09GQks">;kt %:dTk\'N`er*h;j@>u;F0n+eQoLphs:?XZ+=/MAd*B>1kLE9$l%%4oYphU8FLXkpUu %AtHbT:Qt+jaY!@^UDdQ:7cqLq7kmi'4@$a7X`rqmrarm`#,HAMPM1caqbZXsF:>8muSPger]bI.uC<<;0Kd %iUJ.F+g`:+Dqu8mpE;Wrj]fAq0%MbW5dk^`i1f:2RLQ6d]ZX1@;r%&X8^Wu@%+URmTe/^H(Ka`Jb>(ZiVhOk_]9G_ %&q[[eL?$:Q;hWZU[/2Zi'nRN+#TGM^`NA_B8hL-eHlZ^`J<5!%Nd""H1B(MsQ[hI6NPr2VD^_k`JC,,)Y".IaO@KlU1^>bNlulFW %7@.f4nq>Vup!!ak8aJZJ'%[:(?=@?d]:rgn9G\7uki\pa;n"Ki[6g,<+UF(SWebiT35a7=-a;d^fA:tLJ]N7?$P=a4\-P2KR69CWKFP&/>^-^_pBM:`P>JQFR;"kciDu]$=>oZiC/n0a14d.65]8@KH?1V %!:"+=I)hI"LOlL\Tg@nSVug&X_[Z`L%G_02c7Y"OmBGLrJEjCq'8iT-G!R?leSsU`H$q`&!qM:A5hfdiI'/WH.0EW`(ujZohBE5O %P$#O&Jt6U;QI %ECj+T5*jl5Vj,k4!dXB&K1knAaJD`Lr=>h+TH`C4+qCoWI/GA@J)UHK3b$ZTA1% %1@5Q$-+ZZ4HF,brVaR/#2gS>'&ArpiS+NIG])u(]h4u,Ug)\HSUmgqN8%Xs)&'TdY+mmST,l*MKVVULlI@<_lHF,bRL!cUMV('j\ %@"6SXXSJh7:kS)8>C%!OFsl@0fM;:B?=&TsBQjNiK4`Pmh?Se8O)EC,??Kr7(Xa'gTOt]HSlWqj5r8V4FOF!I=[c9IE %Cs'!OLKjco/uaMLHRu#/$WQoX/Z&;+^9sRYN/Sh]P$S2u@.j9TB4_(IP;o`5B7J(f0%^`#Ku9fWjf@rXOG60fH]-$&8?dQ=QR"`D %em^P=K!n'a+%ET$9?[U!Q)iU])pEK3ak#>CY;<;,F`E1:Z?R8mElgrA8u63W@97Fi5=[\o96(O^]*i)2<%8clnm?,)Xk(m-/o$AjV>[Cu],+T;5Zp8/c9LMNl@H\O0/!Uf[Vg,;] %BPA+5'Z-2l\3MHp/QlJN8to&8mRBjQcX3oq["a1=oh[4ZfM,XN=10`]Vd!S7aJ(V]%^_tlm010"XY0&1&T4e\=pV:u\)hrl.%7/` %Vo%h)#B_sM#7$+=B!)8b8L^g7%lP#3lORsc+8XhmK9$8L=`hF90+-[r;o`:<>4u$L/7QlDY.2%sNYJ:UVgEFLlr0o._R4rP^chqs %`M8!A^co0CMII(POb&DJQAMq0]G[XRlr+O0@;DOi:S7aboVcn;c<]#@HY<"D@U:#'`l$.e(7$hmYOD4TBD&Wr"KkH(7is4A-\W>I %_i4>mRuMI\rdplDb$_33Aq'$B.YFQ)kJKE&I/@HDVQ%^GWPWk.(T+3:HW-3G;T5lSR&UR\.X3V"VCMO>[5V)'^jr]tV[\g!pMQud %=K8H_^.2+e_,A7VjJJqc-UhdMZLEdS0idK4U>nQaL@rMb[6=uPPGp%"1)k;]p#:b+b$_28kg^2BPlZUnrg9\opDU\*9&ETZd)Rm? %R&UR\.^b+uQDr"Xi"l6")H2nJi:bN5ToCNegQ`?-G%,Xb1/K5p'MML29,4,O'iWX#T\$Ic;jG0s7F:`i30iL>6=M,&Ee+F@&q)H6 %)=Dm\I7X_AC!-A3n#\lA]EbSqq[)1#-tin9JcBBVcq#^R=CSY62Ud7!*G %D0>IS]qU0@6SBoVBcVprB1VI!=qME?NM"Z#&8G:p]H,>:pKbdr>H/*O.Nkiqnc'53`CF:a>A!48BG@$.:X2spp`(N>pKP+*/_DG* %Fj<33B:mNlF3Hj/B:lu#m&A2dR3Z14f(:3AQFW0b:K%%Z1]GKVqdaOC+lT%5ZVNCDYdd]ujIFRWVPuX4?U?n[U)Up!PGk+di>U0Ho!ikq!JjUC_?BCX*]PNddc1,r[&CmXf_3iJ?s%r!ANl(S'#m46&X5b[G!'03*lP34Y[NCXHQ.!A"o:nIE?u4JqMpddKS=m%eo]O# %<\p`I:9/AS*,@Df#7niH3UdJH']N(Qhcb$Z9AOR5ZJD20I4oLN494I-Uc7EDO?L@,p %ngP4YE$&Gi&0^]>G.,&'j58@h8I$cUKKX4MVrDX\:rA"kOQ#Uh(t\m!ga,Lt)J %\nYF!(=Nm],p`rQ6SU/Y/M0"9?AiM(C2)(FnQJUZ:eT!9Sr7:hC2".G`D&'=5qO\&O82r"KPP:ulbudW/O:s?ba'<.BaJNgQ0'_1 %`O#cU[-5'h[@#O@Q?K.90nBfTV@/I(ZimeDs8>tF#RZUk[PIfi1ATYHjM7?]UQoPA0s1JX9L*)$eC#h7_]F\L$#4/lej%/S]7IB"LYVP^N_<,-)dZZg$.@NBaJNgeM\)m`O#cU[(u-Wg`f$9XcXE@;+qp7?V;nTQ/92Xp.d2oV;p+3YGK4k*SuZf$#42I.*8Zq %.]iTjP>'VA@88UU,am#/U!b)q^Jd:>f7r]"81(0uae?huGkBUL %9VAnjAoc=(S-nPm*FA!,ATG*/MjG=W\PL9,A3%Ra1eg`2,SPJW<[K3!HosWf6Saep@bsX&D)RV3,"RYS+KphqLQjsD"P5iFkXWZR %MG?7/lq&Nq5A"eMU.7!'&e56/?1(61-$Rj3LK'60)n%,^(m[pPP_N]UVl&Z*n#?"FQuAtr-!AVh*_E5]fJ:<-#oVP71m9f=KV%L$ %>U6/&5R4s/N5%n$`-]#9a=@`eO%rmnPet-[b7Hh>,)4Cg#%mEaMo5to:d4([>.[4E*+YBRL`L):F]dM>-jYh@%3/o>Jg?*&3tAPd %5o>Nj`'IHPUkoiEZ(cf%egg)9GOCnWmP6=rk:ZZT;S@^IMq^Mlq`=jf('fEXeAF42MM4OUi?H\'RE]MY5-V.?!Mm]c#&c-a!m6q>Qq&"2VaM=EYiRC>Sthb$VT#SA@KG,HXR*s'0`n,jY_m_JA8hn %]APb^S0/F",_0%_Uh!%VrO%[j"EGnlk1bNh*CGp\(ht+6KQ(!41+\g&$A?fW,[3+[*lFEJX`43;^e`B_%1/J;UB*/roWPhH5/pAe %dV(n)?b?Ck!gn[gGeF,0!gpr/&l(9Y!EC]5B/C_l/u1aJ2&`\%T]mM,!$;=%g$9/r.*JQiYkJPj4[tOuCBgbg!5>D!S1N>@L8AR( %Z=KTc9K&\qq[fS6aXn"uVb9PM&3(X2-VkAp6aTUu5j7;mk9M)MLo8^?=GJo/?`Jn_^W,p1gRrE)7PN=P$.ncRNtc"o9bTE%/+urL %``T&"U:^\Gqa/!*:4Xq?'ukj5Xstm;>-957_-$QI8:[pP%G!\^,"5Um-]GGC@5X,;lZ1o4[SFZ/llKZ!+tW;!grl_1e2?/"A!%rd %n0HFV1GhI$#[)Df=DJN"0J)"nF'Yl%.Lf(:HdUH_)BZ"E$(f6I=Qf,WRsb)kR$-[3jgI=!Sl@HP6X`W2-*'qj>HfV(>#R`tCS`3'H#`uJk]?Ktji9KGc>+08F5kph)=0;[ZU>@d1k\L>?'1,)R30b.gq"-US^j98n4ff-C %Q=5.(0.,Z9&r'uFTDb=5XI1k3:?\^"6W)NlWXHG#5$[,03tYkGNXoO/(a8\%M757W==b\11[IY'7i2c+!)r<3[M5!HMe:_-Z'\sX %jqLfA=QTDWZm-`lAgGnq%u8G,$CkeJ?g@QbP0EtqFd/7>MZkgl$ViEsJrUur-n5=>@TZtc.Ka^C$'q*UEfQYR+AB$II^/I;@(mgB %3oE7:fn_\t3uQ7;kW\.FmaOA">mr6E-X5]dGaL^tG#FP&BQj-<:CV+.2u,3FS!8\^emF0VeTPFYo_IFOE7Q'nj[+H\J+8T*c1K[p %RL=#hjqgg]88<S2*UtE&/_#R75l7Ie)'UiFZHq. %%4@>"Zg\Zr6;ZBoOZ7W'Y>o2/8nfXJp'H>c'6^FS*_ArZTr[RG$`O+7jZ-J:-RV*.XtTJNp!!Q8UYr!Sb>&oe8!5ANBt#3pXi\*V %WF4fp_([:?8g0/0jtN`;iNC=Ypt'ND6p'Zn<tN$Dc2"QmZCk"7U/Q,'AL%W`qdVb3U0nd6tZ %/m#nMnW-c0]`B\dQj$8r$_W4CeFY6>a`Edc3CU9r@Ms_DEIuS;^:a&:_N6905(%].'OpeYka*OWag\mK47q3FRL?gcNhUR6SJ+i] %&lL/WT/ij5oE=pl3^e2B_RCGQ"&g0]&DA[`%u@H3X76rUWRJVW'QqB#X.]kalXed! %lHh;]jJYRSV5R2ZgWa8@_qRq#qPTA![au*t3g#R_@0Hf+QE+dDNi4f:@LZs:/uc7NT;3-8D$q.]-"\*k@k@[cc!?[i9ZeuOf@M;G %/T]O;p!8'W](u0-R_+T$HX%r%PNK#8*piC-kV@FS.!H^!77j9<2L1iMGFe=sIT^UA$tV:C(pA7@#5Qk>^Vinl6J&^M_HnaR7:H'T6PE$0$+d:1&a%0>jE`Q-IlUS9<_RY:7PY7iqa&6F;C78Y@MqFQ7gGho8TqVV^TZ?=A %p5QU.cnJ3]Rip>`ET=CsE;E0$qE]Y;69aA %s(s)NFRibn#@ZP+hmO]\YI<>2H0\>J5o>?b?i=m8(5259?e_dSkl2a5r?cT7\,AK-BYsckg4![J(:Y2A$Gu;&h*Da.TfBU\kkN^& %=S^M;X26oB^A-7KX26ofe*BrQY8W(F'+THUpf/8^_40@aa0-qpUu(X"L>6H9ab]Ggj4CdN;\ha\:(M_KrVm9uC-V,5At(js@4^2E %XADer8PtNP+J'K\!..9o]$GkjJ;`\FrY"&2![XA7%dsR6Yi#Eo+S7:I]jWm:&H00O63$cQ_pD$;]TYrK/rc^dgUre$&u[\+d.cX@ %eI70"]!n4XKJq-$nuH@N)&],(g!E@QHAcC+%UgdT9;E='=68sG< %jbb6r/!V?=J^R*nn&8ukrRJ'C-1)ujCE^k`RTF==F);75CDW9sJCZ<2rC8k/e %JPt]Lin_P,JJ>]e':QGLl;4R=Tg704h;gU=`Y"<\[keS_\5!,`:rRS(/Ya",0QCgWK;sb9Vd.#u'$C[l:,[*W%oY6k"F1gI019(W %`ml%k:V]orHjJ\+CKG,LcrSLRL:77>m538Dc,29cm.:EGTGKT/c.%Us$fK6Rf\_nhI#0C\g?id!> %fOF/UJ#8s['G'4g#jUb=t2T[^V]I#TGGl: %EuJLW8SDH@o^.k0*%cm%`Vl,U#C`ZBo<.T3^J%Yd#:mKF`m6l'+'qa/21>f@%(!Yrr6Pj^Z6*d2r-[h5eLCDI]5&u5IR84;fW6&. %TJVgajJ]Bsgd]SKYn.L8r.FQ?e8DVI4_L$83 %>MaErM422F'j$V,Y2K)+"s+l&p-_Hq@biN&WUH",ffd8;J.KejU^o47cq'T[i$rt)1:#W!&dbD\mU(H_A-PfZ:k7%D-2YL#'gZ=c %)oT9VCOCG*73g<=@,ai5ZVI,kl]*T5D\()`I6%em.Q>kD)mL/>k]$Ls;b--37F8@g1p4,ud+2WgW?G=:DK8'gg4pB2qp/tLmbqHS %6AfjSbiKTtgZ+nm@B;nOFVqc]O4W7,j!,+^=1Nd?:Eq8mCVt=M_Y'EN5gk"Mla>2!WHOZ"#3uOMa"uqNoan(hO'8l5Bm,Y)GDjYd %E]fI@3U1E`fO!G"$d6q:!"u[9jX:mB(7X7HRch-p_?#l@9Bq#4?dMU'MbAote"c,!ZD=+!FR=^$;7^ZbNl %nA?7XDPGr-"hR,3r%cuS48!guCtKbF(/&O#nkt01^g]#F4P"_,2N,PYSu]($oRHY]n#ZqT5lW3+YYM7'$p/U6r_LsG>6\?V#cb*7 %O;_0!)6fS"kc^u&,1-?EXK*hPAB'c2:K#t.WPUFW73_]&Z3'Kg$B%/Ca*=f)ZIJmTcT&:UVN=kfOX_.+2qJc:]b5V?gUTGRPK6`^:[21)P@DfPf!p)s)hQkmZffg/CBB)fkbE8jVrKC'hIbC'<(8Vg]'K!/?IIj?nB %_2@MrO+Yt(#^INTVZlSiA8qtm)T;AnQ9cD$r2#q;Y%/'[QN3X#`*L/4$o/1=EWj#m0.*N1PY\#VM'bSt:NV8uXK^7t9oGDgg-QqE %Wm5fjY%s1qJ[!O6"eU@HknL1#9?Feb\]#lKdUB7o+5sOl6OMG#0FmSS.<-=o\F\B?s6k#I23)/eg9Sb&#k:bX>P;/,kJL+]>6_/T %>VBi?'l-*%aBGt486h^6q78X]bs*lMQ73l1%'aa_4fh*ZBT@ClJZm\hNIO9s6CZk=hT%Ec=^DqBGNp>F=4IUa*CFMS`D6<4/pE@T\s#=A&PBgO40lr>"*>V#i1s;M&2W.TdHo %SX?5]g@&!XP+LLL]G[Me:9O/21M.^XiKA(V3"*So#p;>#cKQ[H'%/sA_Y?kH1gcqJa^7W3lpmp+ksIOTSWeu?U^rOSZ@^.^8Y7`d %hB,<2^^Q0^Y_&kp@=fn1d51nX;I/Ta/H:06d&o/SY?9oa0&I!$A@jJ(iWf6d)B\Q]0+H1R;C %]pNnK%IQf?"UXB>70C:O=R^VqLZ[>^#7^gg)Wl/'85bHBBB!"4ZP'6]@hCC0@F2(jrG"",Q?PPFH2T#0QLk\6dImb9ir@kD9TWehCp0dFA547U)@8Wi=;6=M5(s\0@U"WK;R[d/1PPBEldf&hRRI@6I+:&.gWO_g%,P+1UG^djoJLqGX:4)q"k!Pe%N\e_D_d3Dhe`4]Iq"qn#Nns`%7>%oBiI3PYjX\ %^=mtBu'BodWtJY_t$0hQRD>BC&?[ %kW1\p+0MqXY/O3GCQG4FA#T25]%=VR!jOmrhVn'R+P&M3"3Fag^:Oo=[n:%dO+\Xp/e%i)jZqnk@oPM"5/2)tS04YR'g'f4:@Js% %`D2`?$/J\FDCK%MB6o'h![p(2`fclIlr5EV!TmpZakVM^ShtQj3",:`WKj5S %R(<9ueonS3DGh;1`M+Mu!Ste4Eu,fskN_c89$sU6A/g]O1I]3cDIr]?-lSJ:NO]FfZot:-:=6.Yqk]Lf+=6=JBX#;e%EpMZ![eKm %%<8SM-]3Xe#tPu\'TJ>EijP\:oU%Centu_;:a@9+-nZ:j\CW,iJkF!8;Q,8pA>r>B1K<(&bY%%]1T9q1gAN9(O[->uT,T]E:QS?' %'V;OBXTD3#+oEWc6)=S@"G!LF7a'cg(/D+:[2Y/S=G3$$d'"u'(5SWJ)IEa8r#Pt,#ib.e(;7W/JQOL[EaXGNDCu0;BEW.u?FL?I %>E,gjfcKuC6sDJYYX!PaIkn+O1m37RHV*uZ %4f6kuj>u8SWCG9<_Y4?YGNA3YB3+>kbe\d[j=&_ %Hg`b+KMU5%KYS.[gPl2-jradH4_04.``3j%758q-gXR %nd&k[o[08$S?BAORZO:#\n]+pb$at)N5Ze0h)]Jd`GLS+aWgn1"Et]ljO(jUC"k4WB5kSJjKS#Pl/nY%3ELJgrliutH^Xh)5Pp\G %4J$)Qd;8B%+2+#Z4OQJZg?_dKJ'VKKGOPCYfI'b"?[&]G!g0DL"*Sn@2umFMTU'%k)n!BJq$Umk/,h>ZQ2Y_>3]^.8=`s,5`]1C- %GjUC=^\;q^q:pMa-JO\d)2kIOZYLB-h3?,=XJ'6l:[:B\,7K,M!4DoMU^)WVoF1.\>:Q*H(7C)/2[8.2>r %.<6%K-ah,0'2pO^4l@%J=;`WDR^Js)^BZ^%H`;r]Q9CYUaf29Zf9NTDUV"7,a&Q\%6(Ap4!"kB0QD@4VjW's'a;oC<.-CkQ//>27 %qLm(/%^9j8X!MI#1I=(OP/PHsXNNjh7r`QOC[IuIejDo[K;)I<26i6dih.\8aRlJHjQrZhaO)$*5#$QH'0OSo!IYYkC?:e`dmlKR&<-T)s6JK84G84iE.Nkl2d/l(>b4kL@LkII1P;N>u* %hNLi4g\dnub)O]TKZ7GJfDiS:]:[ItESkQ-.YMf9_:lV)]m&=3HFA9$%-sa`a=\^r1=LJ1M6T$D6TL@@TAI6Se2\@F$KA">IVG=S %mb_:DV2M_8/aq^)Tp24$mK*Qod0a?!?LrS2ejKR$JX)#]l`,\ij808V30an8Vs8\?iIXN'\+Z!%URa/`jSl+H<76dFh^c[G=1fB- %q0bK.?KD;q7o=260`-1[S-ZuEZCb.#(aU;hjDWSL^@0UUW`T*tPb,r[4+/Aq4,:GCkG;XitNHCGuMmIi,8.Nj1 %;P_rGn[0c([dH;T#r:*DY$@=)p"Ghd"U'_<@sqNLa(60(-cM/aWCVjd2RPh=>;Y(U,_MN7"uW:&%ehYA %Db*;a\u^T"\t`%O=AELVEE3E*,u;WVj0gN-nQalpU"?GWY[C.!Z,fU!gW*+kmZt#kJg72o.*2LPifZe,+%-m11^a&*OoNE9N<1)l %"!Y]1N<0uA%Ytgc1lAH&B0DC:P")/"b@u6:mN&)Zs-&mLhIW?XO-&htrK``O<-&lAsGi31lCM4F+]TX!X/nl#Y`6!iMQS]')/KGBO/nl$tga=II %>gb$$mA2YDOc#+U.Ad_,rT#eBk&0@lT+jSa>Udp7?6,dOn!?pXl"0UqS=3^o%e>NJiD+5RbqC,iQ'Ad!Iu7i^mh=AdqWpuV_6bEZ %^JIXk2TqBjeIC>VBmhGPZVK+b>B/r=i)F`:Y,ODR>]:$ko%Jt"cNU6;ChZb]o69/lI`Km,K4^M40qsjaD>#`M3LNMJ46o&[moYT_r].KrS;`u6k6oQ[l:dnmahZ`\A,Qm'`g`idO#Z7G %H,^e(g/C_42@D.!VS7?*8]mOohu]a9:E*SYS4Lj^lXab$g&8rrBe(WNT%/I^Pd`2n5<5[QJTKJ9)iT! %)sm6lSCi"7s!]>(ak\uhqUYSn9AucgKYHiJPAe$/2?ojmd&2MF"ar;V=!a:#JJQSQ/+ROO%P3'\&5V@/)@!3QgcI-`B1!7i\ON/,Xf %qTj@KR7m)sikQ+EJ7hOO&I4&@"3E8c*cZ_BGo]=ele6g4)=Gsbmr-(EDhg/>)eKr]I66?Djo'kV06KLJQ,M!*?a%G[B.=d!mA*YD %]ngH<+d4ZZ5OT6l`/Afbt91]i3OJo-fG#A.`\'qWoMnBQUk!$]34XFH/pgj?fi %EsMl!k1/\Hm*RiJ\V*%/^;\?@YL*a6R&Uf27>?Au[qb7C0FZC$eI9V\%;u2k+H.6m]5(:G]'.OfesE"VU=f%.V+*e/r0t"ALpT>F %.`=iolsU\'mKr>grH.T#e\l\]4(?P%Qs>bFVWr/#O-amA1cUEE$oucB9mn:d7c"n%clUZIj7.i3>cmZe/AAMUjd6(MLM=c2LP]1s %>6s09B"b*BbYW4i?>\9o&q4%imP"r2\RFT6ET]e\UF'AUCE!.cL*Lr"cg=$h0,iqD&]c_M-SR;c%6JhO$ZD %FV5LW8m-/_:kO[lg.-Y'LS*2.V(,6.a,%;tYKiL'e?k'3XC\P)C@&<"lG1PBoCuu:I@_hM,.6=&g%KMj"Qj!ca!YOG5H-%[g\U,f %bF^hFs0]83M%j3b::j&f2j#:0m^S2)GnVW-&$G.@eO9Dq/lLk,Uj.q\llpT/7#DurcEYb'?[4bJG+3-PM]or$LKR;6P_Z)[(E7[( %+.(`;kbmeXf&NIu68.!,;NE1c;^_eg=R,E!4aeY^rVl:LW.Z"<1J.nJIR$Y^rVl&)I\.Y^p\i3n!'IVEBJTn+Oq9Y^rVl %cg'^m.kXiQ/r5,h`Wp4EH9>#GP6;igp7c%[*h&>W"WKEm$#gu&!.8)+Clgs7$b]pMbGcN5PC8Ef>C(Rn"WLQ=LNr3<YtkeYe9Q^CD;%t4^KA[ %J:l>+/t8'r!bB&qHe\*+lKK6X]U5t1)MoFP4aV>gTdW7,(X0Xl]#p"r4;Ng %fQjhGY.FCI19?+-Cn`MMAR[Hs=Xl<2Uka6`EU^iKVIH1jpdsrgBY[l81_\Wh1$"]WZ6YC5hNAXcA4[UmXEg1%S\9!r\n[Fc/`eIl %9uSI(`5XBs,cTEb8A-XnLLqZX<'C`/1U1.4>WmgjeT^fT'Db^I!o_!M#[]bE's6@*L(/fKYL>a]r%Nop:'/hqbsu1-oCrfD3;WDg %1pJ*(VBl']2R+n3KZr/'T[1JjT27*YkCh%+[F?R7egA>>*r:Nu4&tPZ1.+!8Q]7QnW"X*78c+1b1(oiKfIC%3EqB\8KZr/'+H+$` %T+EOc2@P"#Ao0l]`9OL$8A>tk4s?seR;SXYH^B_U5,"6"TsI=)SU/Y.T9._6`eg?fqh3NE4t:tIAfgdp^JBgk1Lj)U:83j(KV1&T %DP*$RUa+LL;T=t9qh30]H2&gXcmMdqGS0$dX4@dXKF0H$XfB85m'/s/S/A_WW[$TcfYsgW:42s1V9$,ahYZO4Ej9,*SDJ0=QNT%q %Q^&h\"_k4RM![I-[j*i5^4+>c9-4$3JYpl]o+r+Dk0TI@r)2.55[],g8T`EZo`sqSU\fZfUqP"Vh!LUL-flgp582I*Y^'pJ:L?HBdlh"]Ddeb$D*UV^:6,A5K'; %1EW:uSi>VG8PQp3.GeQ:T0r7Xll-u@Su$ZB1fr2fH^$H\s*W8/?S3FLEj@d#mO#+d.NCUHBoir^YC6<8su.KbeFM[^gLgu0AkU4@Yi %6?mOBULi(pVL>YUFa&5^Vir,UTq9CnN,6S&9fN3YnLB%&AqPJYLjm %)e"l>eh>deH#]D$L2]6!m]2]ao#=b]I^HM3YQh_>p7nb_K55s:mC-EfVt%J5B`02g`*)2kF02&MMg=n[Q%%k!PdL$]_RKprXF2qs %B0,k1/,FO+)U4.0'9'O7]\7bQ+Vaak@rI+,'2(fQ %%\JHXrQET!@``;cnl_mJM:q\e.L,MC_&>LQ3R193o@Aj9&YGm]6=tT\GXgJaI]qZ>><[sRm27KOI+DE0WQNi,4eq,-cdM2Lao>hp %B[PeFBW0G3o3"'1dYcEj?g$\C=Uagnp;1Gs/4F!<,q*;+k<53X5p=hOdLRBRn6*&(b`^AJ_e1D:7IrrL.5[]UB-B'iV8`bmT8O+N %J?bn[7 %aK4WkN/buFAV.kP*1^pk.9qJnU]r9`6.um-]8a]MTV0_+4tD7nf$5o'a"ZpB(aOYuj.`AA32e/t!$L<5aE>&(M)K?2M**h_]-VQH$RQGqBBZ[DUbAF;AV>]KWaHDmmUhB%H\Qcb.1[1L/'8^(4B?,l %4fs0\ljT\T-?*[t;]hQDF'77M?Ll@ko'+YX23=k./"LTN6^!/+q?%L1WdsI?Erp-!_""\bGm!)Tf0)[#";]3kQ6!4XKiW''GMPZn %p&.<9S,=8V`^A\jgT/]q7Ru!(8h@HW_2VskZ*FL,8kOVPJ`[e+_/Z.^B[6S$=FqlopYm&I.1EE*5]o^SclCf<(tRk8F1j4u[p)!" %RU:FZlr+O$9dA$?E:e;H.;A)=1!gopV]`/R)lV%CCRS\FoYSHc7_^#o#FaZZ#<3)u"3p@OQ&Z6GJL]]g(D`TO^':$9aK\.:^':16'\-KObDh]E[;c#KDp3'YY\I]9W7a+4kTbYt(H(XNXCn`U54$S`@P:P2c2_^`'A#l_%N %)m*cZq;BYGVXdCDkc_pl2tms2+$2mspF-I.X$W#2D0HBGrlXcu_4W87hI/keP&UG\oRt5kQF1L\D=2tTe'/Y&A'Fc$do2ZQ56hEq %`[>ReSJMiX3`"\HM]ob.8k2WMT+63qVc)B8NXM+1=L_T3+QP?"ps?EE29,RR_lVcf:=HK]nu9)Kd2WBsS8i$2qteY\"YKVikmI6. %.&[Hbf]L)D$\Wf*6QED0@NJeJ<57iI"pbVXpKH68Eu`G^H[#%9<9I;O3`4b+>Di/?6UFM]B.;\9T9Z#/HW0h.4bEDp0&NuLn"DhX %6,*(IY@Ln\pFO:1JlE@13Dab%H/`1>cMK+"=Su$[-X0hUPhm;BXE"=TRq4?] %<=>E>l?Qj%^5'$?!!8Fo0EctKVd5h&-\cMgMSOG30gLnrpm.!Kht^8KebrN5=Cb=Vif``ECs-R;d9t?OEK>Ht,VVI[BU"Nh\]_^4tP>'Ji#d14_5*#\#.+[_7Lf(j:li0D#oOL]r6>*A]tm11>8hRI4,% %U-*)ipoJh"RBT@Q?Tn6,@O;@KH*H"4--L'De;FGa'*P$l8NFF-bL>oKc_QuS&]nL]2Q9F %.'&O?U-/@$nIt7tKSBGa\!RI';4a6.k;Hq(A-!E%=4.^2XiVLk\OR79]54O<`';oQ<:gk\iNi>p(dg)o$Vdiio@X(^pQO`u8b2VJ %=#GG)$2+cU=DN<EkkK3$LaHL0;Lj=sT+57Y( %>HXU1.e0dupn!&fJ^Eq9iqY(ha0fX3[D-((73<'s>ki#ec'qeQ:P;L1I/W"P":5la"fVD@SYGlb]>ddCg>0#a[ASo)(7BTk2!K?1o&<4O$9sbF/=YY384;s %+QH^pL[HjLg-"D%FJ?uh=Aj"-(P]b@lLP^,T#n()a8C`O-^_q&7%5t`*IMVJ8\c@d=0SSsTCY(s*0Tp8[!>uBH*BJ%VTn_,b_%H[ %12WU!AY+:_QtZ*:@#^gQ-e_g#2IlN[?m2%k4t1i5q$H4f#\6-SYm5ed]9a876H5D9pC8MGj?rMe`>Gi=G:ci#Zh(M %ZkkCDX1Xh727[InP+OVB\5![6aIJaI12Q!rY7;rF,(JT,&d %7f!Plr"+pJW4tu"%/DImcWZa5S(Z[B>9>,q*T%)4kfgrDJSIM&K#!V$jQa-J]5`Y`e5E: %\$qq`:[smNle=TZl#:Jt/qO@EkX1(r,AVI1QmP:,enNM?WH[P2p %s+m#KNDCBr@J:GNX4@Rn#edn6S/@mXbK,K4HZ6s.r;A"8Ve(8(+/(!j!\EKapnWD-B&F#?E;O?s_VbbJV=A-B5Nl!"GWWcJf.H[i(M+4Zs+h3-s0jfo9(gO&!Pu#CIV8nH%?:bW>TlJa[fK5VJc:*MVp5*35=5dZ^ %Ru[EibAGuT?%abB9)?oj`%6t1@==C4m2aHXf^Y$bj@6&W6\h&7]Md.b:QLmk_.+p""M0DtGO`oWdm?Fdc&P!`6S%D*`fo`*ah-G& %p0L)2NL7YBb8Kmihq9%LS,?`!OleBbl/u/7jNTqY@%WUH?(MI("SO:!ok^9VfVd*[LINlfJ9n7lcXLP>h.5ZL&,.gafhB"X4fD`H %"\;Gnjr1q*EDF)k8"81;I.WV@pX>4?PhY<_h"X"G/)5NbL3,EC]#6-93%!DQfh[0+P1#h/0FQE]#]3-pbCI%&.2/AHgTMus.Sb[e %Bt#FebocSVmdk*FD@NEG7On`lm4g[6\&.MrBPF^lW-##7::F<"%Umb"+Oi^Qh^/=QE_F!I[Uk5S,Q0L>=SYgoD' %eQD+&1I_?1ne,8G%AC)k(kcdDBjE6Q.bs9-Ff6l'8R*?uiT8rtf&(bdI&#O_=W[3iHu4:607+oA&-es3R0-VuQs(maJ$3 %&)CY"'nE@]^OmQ2rKkLghT_MIF2g;g,(NfK'114/a/8\0_-qtC4:UX\_CX'N=TU2>#CqUQ6k=\pXu8Ydk30-u?MWqgPYg$gM@]3E %UpZNKcq1irS[2FeFp;X64mqk-qGSDZ\:PcqjLL%CV9/Drn%pP@Z#&in[g+N)B3R3&Yn@4nJ`"l.cbD^97mQ36"'^gWdAUCioKP %jI;bFd?irB))"-a+pJ0N*Yp5DWS-sdIjVAF2WXf90X#ESDdK&0>PXT:Vr+W5BWI'+$bu9/N( %^Nk7BH%!W25dc9q!_p*%b&seZ=PnI3T3=U85t,>;W,cda,2l=(h\dQSqELM%2Zf<.4\um1nXkgpQ.6XQ2j.sB>1,EKa^J;^-g+qc %TEEn"F,sO4SF0Kg,hFZa+83LsPE_S;:alRL8kCp.S\Aa&ET]q%'Z?_)(0;rD/@Hl($,1t?0&rqQj]*(5(,u-9(CE\PV3[h?8a-+Q %RX9V[ZEd^aBhs@IrhRV2%L[\P+g.&K3(V7GDX,RpQUdVafb04n&FE#]EP;;He_L%5VS!4f7JouP*5c]:Lj0V&+gfkg8&$qY5-kAu@Xu=2$em>3TC-p9+7j!<'e+Wl[ %UQmYb\S[?NKiEs07:Y/'.M=[1O[:OM?d+5OM?HhneE9d=khKj*n@fQ4A[YMD+;N1!Zj]6M21d^j %`@FQ^"k+LpUSF`SgN<(cU2Beqn,V<_8$%EQb.t`*+\>-37=nP(poZjpX)rI>(C#q\7K+mBb3:e0aYKkk<]nP4R'm3r80Z/03P))dRe4j3>PkbI2-ri]]r1js_<626;:^lpE+clXRXA9'Ed0NLJe6S?W65(g+u@EeoN7V>plj"S2_&EpZhk=Kq8H@aqu%lZZg;uGItB[\*NZ]sXHgT:GUW:=IHcXU)%W*S7t`[DEkqFtD2 %:FVt*`%p%O3KsE$2MZ#E1X+lmF8g&ehY&8L*4XVNpM-SMo:jIH);V[c;-0!-b#PuYS#>W&p<^?*&"grX)I;`qGmIIaC@f)g988@pD8VK($f@e\#-26Uqh2G[ZP*8K&_>39=*,qc_rPM&YPB#94&^#eW?/&a&=a29aJ_LtDV]dMTAM(*66N@9>)8SbI0 %pA?.?&gW#ei_q\COM$I %lNu1$>2Ksg^j7anQspA"i!r*`VHAEa-1A\N;p[MSGE`/kfK85:#i\R=b\FuUHl2N7j>$nU4p(l="MtiYP8nSj'QM"t]Yb_/dM-]n %?C^/6)i$?R"-FaVN'[W1_*GrZ[YmRFcT^=J[,W(s'MTA%(C.O\/W=0iT[AcmW^EAr,oMjadWAZUe:A??Q%kFOPYEV!%re7$5:Lf_6MRe3&jq4X9+9s+M@]l\()hr/S>]`OUT_5.E;Ns4)kUS&.U+`J %R[m]'FdSD2I_,#-=`c6527PjMP7km[:*8lgH?jXC2M'adg9Wot^/lh`^pjOUNhCu`bD&Vsga!Gk<:?Vf\6CumD>$#EgpjnZ,o:B. %&eOp5*!hJi^Q8YT"6E"JBlN?@[#Q#tS-C>o3qb5@+bsSi4DT&rl=\Z>ou5@BFbsL>]Q9)#5DAPPbfi#WPN&S@pNA'tiG/X+Q.Or7 %V6&F17T,;HNJlUU+J,1ckC+`/9Ums]C\QrPaP*=dQ%YPBR$HE>_unVlBNV_`%EX*#;42bf!bP2ecLtS2s/_Mr>FY.>RAib*RlUmPUe>gWg;a=99gDu]opQZ-,!&fD7u+U %q1)Tcg$Md>m`Lf*mALj_K@jejHDP5IhbMCYLG^Wg8'gI.c/0'*94CHYA.9oL`kUu5bd!sajQ&nYA<*[9jC>Z] %-9p`1p4V/q.u002F:.&]Rn)QW!2074"p!Vda_L@Jd.`W2L(E %(Ba)?7Lfn@Zcu_]rcTp\q0BP?W%6U&/R1?`6HEZ!'%uMMB%0mo6f&$cjW4b\C()8-f"4J])G1>^:VEjD/^>S2*IWGp1N_;?;-@d7:uM^;a8udlFsMY*6%DG&3:2q-)nMpbQ9lmUa`Y\^Jef %jXQ<=fk*(1I,D+Qk)flEd:T9pqg8082l>eW)Lo8?HD3Q4Lb(?2IBPE=3FSGihJG.X_=W"\IS/t7c[V4?sqGs1Opnq4'ToRMZ] %'Y06IUCij=5V6]hn;K4 %FCV>23KAi=8T!dV3S5\kj3-\.)M&Pk;>\ZATd`+kgYWl?MqB9oQK %]l/*japq_rLL7ca;RYtK4g/A<6mdtpa&0Oe/S@=D(3rMUk]/mC?0'gj3ftrt"NQaHi"X!Dg2a'0@cq4Q(%goBqKql(@i##[#l[m& %Q#rb8LS\l0Td1,LN/HP\=XaWd8W(1;0MFO3(!KpK(eJ %#k,L=YRg1\BAT24bqpnqm\F'6].!)Mb2q\GN6.,q\KTjt60^iEmC)s&l/&;fir8;<(YX]jr-]uu.Thu_:!D#,:)PD@F8.<4Y^u#S %7Mk,fNBfT>h[dX=>ITd,/fI*T,5SAWLgFtsj0Rtm84nOQVVgJr5=Hc4[1ir8r1p_kU\cpV8F,.@NEW-VXq^+sBZ.*KfF3GY0s>aC %CGSfQ]Y/l-I-AjO?jFR$#kAPXV0*`#Wfkq-lk_I.Qj6,qh13I8Zg1YP5&jc8S8_"nCmRqcV00sUh_`8pL:sO."IZf:kbiR8>j6Bu %eh+)t/j2M(CIN#Vd^g;gSfiBe_6C;9IBCp:BR#.._=Rq)W_UltqN]V`?i--\8G5&7UrRS6/F7$UaV2#a?d9\l^l,bo"S&`_1a`)s %b1D--otQ7mclu^o\PhmE)9mj(9D\;=rN9/ZDYKC_<3G/d3GZ"bd7Y@BX`M=D`G.28JTB-BV,Rm?;$aB57jDA95%!$*/f.1Di7u\T %b@1$X*erT&$=TNm^C9Skm"5T?c_hlCje7d[h;IaR>91n9=[3bk#0Z(;pMf#l@`oA#@Kubm8&$TEi]\Z0X1@#)Nd41X7Q5ij!bW,5'm7!KjM4oomG&s6#UP04 %HT=n85(OjGeKk^27mRRL;@r%_%LDoA=+W\-E^6VuNBe&b0@VWLY$!R`_=Y?E*H`IK5Tg:7eVu(FTHcH>_n$Nb3g'S#XHapTE$1*k %5Y#i[BJ_uqgpnPH4_pp?R1fPZ64i?O%L?6R$UGo"_&"[,JWAfA;ZDYP&89^SAqE9+a&1G^&B?+]f3?TU4\.Sp* %_AIf1k^&>h1Ps%j5]i$s'*L@jjVU&;)/J;`N(sr:IS7Ir.r&m!+>qLh\_K8-?WqT>KG1.tQ\,"fnQhqu@&^SW`HRHM?#lk4$K'CJ %-fM[.fe+Qq@L_4[*#-fII6EZLO\TgS#ebQB]1CU-`Y%)SMUb7+O6bDIG4iXU_fdW$Ap5QO+++CpAJ2jK9=sCrFddkij9KOA/n.,> %&O %5o1RmC$Kc1n?(%25)j6+/BKQ#:dDnHRT-@C$t[,\^AEik2X\YZ^:C:la4Ne3HX$$+*ZoQdZ$ %\U/\NTe6fun`oPejZrR0:Q*@sAPmsq/Z?^&l0?=@8QbfFFf9>n;gi?!"7\I,i%QggKh7+l1O.i@'%=@^rM%5J2VHg]rcJE.?g?1\ %STI.i+NGrlha=7^p*NniB[LaO`QBX'IXKHSBBknHBT2L#^QX:R4J0r6(aO_g-rR`s\qF[r8`71>=j%9qnT>7UEWWf8^pW@T5hEK: %<@bJ<_d7BWA7!JdG3Cr!%lc`k*Otg5)R,qm3cO'2FMmcXrgNBp)D)qn_/g?bEOF>IC6TEY]Y@FnXLC1[S@'J8Yl5N4jQo0I`[;`$ %Tr&pbXT4K6&Ce%)PWH*NjG2rjlrAR,!6?:6b+esa8c+RPJ.,^:2?H9'8J(H.p?W](\K^%bq"qm!(!;#MSY,Uf^"!U0=p-0(h5\>< %IM;elDCC7.S[9[Y!sNheJ?(r9i"T=F@'!e-Y#edP;@&1C2>J)=(l-SN"nPi1^B99&cL5e;lf[[S_Y'GDn?Kf$=fdWF2BkGN/XgO; %@El5o+qj6-&k/"24Sc(2h@c@\o55Gmee%g\L6'(")a^;4LM_t%L"kT.q2Gb5&Oc@JH6PXJM4h<)^p?SY;BcBBA9*f?_pUtbn"E'l %(k4ogZ%iZLpH?$bg'=&!FSE:d*,`M3I6ZZ9\7U3iVOdW+:[j]uBRYbd=5s'=!f^BhKDN?5BV(SH6(s7Jg?8)4$-,aX7pek6'Sm5=c/s/$&!bVEaB-@C\SXA:Yu@n[MW?dU+K+>%!N+_rh49tVZ[o=8E_stRA!&7HsRc8 %9'l^e$t`iWmBr]b[sWNV.&.;Sok6?*(;sqj3/#t-N_V,3\2er@#9*:o6c0tT:hL\fR(b!2EWLt2sr3h`m)Q6^DoXZD0Rt#"6-Wr2+BOVIU[J?hVgPqJTSX? %`eC`$@B9/'M8Xs+*udmhE21@#qDLPErWn7J2(2HQCsi/mh<.QPHmd2+_0_;^n2DqtFNMDe)ZMtr/Tj='mp<8[;eB,:h(,Z,&M%R!Nl71GcitcVCS*l<\7c.kh@C%H^(H/H"EeF4N[^!I7s7jr-5Hh"KlCF$3LpQD'' %n;jj)oS^#^.#CHTbn>>[T@XLt>YS'r3Ln`T\ASO*Ynt^Sdh[@'V0TUaGFpL3'!jL-kWj$GDfoO^HT&_c0Ef.7pdq<0!-cL@++;u6 %T_EJV".iufZ.e.PQeU!EVrcJ3qIk2hell %.'Rsi*1i+PI+_<\?35T5YPk9"I7sEImjt%nLBi#?)D%ICLUUe_4gK<%%^4+Nj4\rm3\6jcLBgm,%2R9]_c'KIW78rVG.Bm%jZRD; %n6d<4_;^l'G`(3SG&hk=nHRCR4bj7KmI")hjU3B=:84X''c,,[_gAo>D(@VJ<*280%aWf'BZoC,A=R0#06="5UO-G>lo@2-.?@Zr %U]lNd8=R)!nW(M&Z&0!GB>"XBZ\TQ+0>;.:oj)9rWkN:/4>^>?@I`\E4S7F,_W'6iGZZn"J]4s&$jO//#!TG%?[t![)D%ICLPPR? %'c,-pN0irdhH;u<`F/;O,j-_MrF.Hk&^XqUlo@2<>LHpLlo@1_V8Mr3hUA$PaH']>mOaia"+^/PJ8gYZVae7i-nk@;U@jlNHEobJH5o %A@(,Z2q"ldQn<(:Kc]R_XG>)r8e_."].;s076;"R0X'QUd!/fWbnd(TSe+(&UsY`_/7tql/bHPCbhZE=$uKb3iB*_`MAM9M*P6T[N\tc)a-%bjS5>f:([&?PH)T0/O74Uk@ZSoB1[u*Zf!dqGZ_2qFe$,a=bqu=f+*Hm'c["J+)n'B[j9XHXfpn/6ffe_]X5^Kjs %g#SIbDsoX3,;IV*--'W&h5V0mfjOst1%bE(=EC*hm=@mSnJ4i_9d594%-L@L0D&Kl](;]e]E-pWY-NUrP"j/@9dG.mo44%^e1uNi %,hE1kA$hCne73A)l"B49'@qj/Y9m%C%-cZ@-LN%&nlY1ZjoaA/mjj3dS3eW8!TGQc"6&4X*IRPi^O?KkehJI]6_R0njXAR<>0N?L %ko?J?[?r[#bPYl]>YAf'kL2U&"fIjD-Mu336G['N:@s<_QYXB"`X6nP41dNI\O1L39a\s8'"5lC\Ea'bI%_=SSRpYQEaeI,jnnnBj>F?MHL)">*pmi.&pU? %ECZq*g9A'JUJJM#g9>;lM?puf>-pg"+5i<6Z;-7";7-Fd0s!#seM`;&MFH'MRVK4M*#)D&\--=Nlb9=oGS^hUPnlofKn#'APMYBP %nk+n?Cu1a$5j)bVoNG#5Y)?GK(K`$JJIL;VSIflp0,sZ`5qSDL`2rn"[nE$hFHhbdrNPcjE %oesd)t8,l_&sUdEde)%i@o`:M#ENc0F0N;_=0r[rkVGB)RWi<,V*;Cm^U %`q`?YXAZk!jiK/n<6XiOa1&``9)&D$FJ!Sn!Mf._g6W,@pSY$Qp$@'XHE_n2m=XX9N$8*e3jtTAC!D;,8 %qRuq_D#sFq'D2NRBaXq6+B`%O@9\7:Fq;&cK=6P3C#u&=>/JA3^"2E!ZeO\YRhalJhi]Y6Zg0-T7n%o5Xn6"2?(^jeWbfU#= %6(5@PJmpGm*\b")1gc-F0h;BMOV+J@U[.1I,#.Q5J0GFco(i";]nRTOKgWKgr=:.p=F`7#HuW40i4H>P3CoA%Q8DgZbs32b\uZE] %"ObeiX*"aY0-H6_S['kc5ao%eB+!+XJ@'+haoLph3@G=ZW=7GVfEPPZU%8f'AgiNuH=A]?=^:)*8LPW!i=glQ9mJOn[&-dPVV,Hk %g&JO/m-1K#L.&;WWon-b-(Z4-73OcRc`QEAJbHJ8i.bE\Aq %Y"ndHN@kU;n\IHZLrs6kN,=8l7gq9POL@C@6^W@$%*aMi@6>O(KT%,._0oV= %o3FI8r3c=PZT&T@-g?R9haP\20s!%E,DK3D`h20$NV0)l;B3KVldS7335FBT_Q^c(@2n?'`].egf>J9FS$p%4$(%_$7!'<%W93^b"X:NW %J4]RYe4ipI99jnH5^\'ZFH.I1_S0N2:qK+TBm]K/6S[]'%Qk#RP>>a]Ukt\mV7B#9<<20ab5NY.;g_Pun %Kk@"26J*F;a6>k`)55H'Wh\hY$uu?$,!+Oa2'KUGJ6V0t!9()MY&a*4+[6l1U=l9op+R,ggu9e/6%>(c46rlc:C[bHoG>Prn@ePC %^8n%0V"EatHG5pdfu6`-dr+T%YNoE3e4qaF>ch]T]5)Zu#f+MI;6'E=.].BHiT(c0X^\8gbn@GY_G/SF&l/j*f$a!o!+M5OGk]jQS;n<.'u)[oA$d>[(\j:KeMF$M_H2BZ(PDPEO:[t-@&W@"'Z@'!TZVFQK5>YYpVT_YX&85*+VdaCDFEG4kQC&.BiB?hdlr3'),J]'JE"$I^b,a'JGh/,L-El"F'rQ0-1Z,.:,8`9+Qi0'JE!YV-Cl'MAP=k`[,(:`=$@6EJGC,^h!IC!fZT4!&#`a5'Mg6'JD/3 %&;*,P:`"-!HguV'Iaq90C8bJs'KKVF`="Y\`&2!H]i*C8.6!'6'JHs^Hn&SJ`='3Mbr&rQ`='I^H_9cYi<>aDll%U?iWY)0Jf%&K %!kRuM5RaH5_0HNI)hroP]c[Lo0B=e\2QE%\4OQJ^kPY0`e7=f4pZKNHm9:c2aYi[bC,Xt1$dD5B/OP$jo^It28Y`j_i$)FPF)'Fb %)4'YLnlEX2O8d/Q`hNG+Rfuej,u8rhljeN2J%-@Z7n`5@%0&B"b8h[<1d_&N4CEe&*21-44Eh^.i5;M_?#!GZb!GOVNu9kK*r.em %r[nrS)s-8q)FV'4Qe_?u^^6@&nNB(lSERoW!qL-bAg^$iVJoG:^Od@;VNdP8*CkQcc1:+h`n]N5@8u?m9]Q9F;hV'r9/fb?s\%A.6O8%D@e\TfPmQ=?*prG%=Tajq9^[Jd.;XrgV!Etg_-[4 %XLOM"dVN\r4BTocp8%WuGsE=aDX^nEs%o91;arj1e#bV6JBOsO(XkIq+%a>VN/MrJ_dG?u]9cj6%6G3bPk5(8WC]_FM50;b"5;Q`=NYk(AU[$4,(>rIK7I',(I!f.&e34'L? %%DO:PEtr'M]?U4tV5lJ=F.[e%gQoR/28,u2X76rUWO&`DquVV>SA@OCAkRWS/+HA7CEj-$ %$h`b]Y%f0f]GGNejqGAm7[6CtN@#:P`qB-h%d]#%`%8o0K^`Gs:V]1KCO?t@'MCD/`2=)7FV9r0qUS\GH$!I+,uAl1@=SHscA+^+ %K`TLlf=A+,M[a8=J/JdCpnY1R'`(gY0/5&3(=dMFECVZZa(%(#p_,,lr9PuRjc9FNL<8ZnL]uKsqoo;eb8f>kTgC&ZhVGOoE %&Ol1U*%#86k7(\FM!cr-p\RB&*.7$B8DU$:L3SWrm6RfiSB6Ln06&s>f*5RoCS@kn/q*OD$](a?+Q_Y:C7;J'XHsDuY-5QZ)=)uh %)"Qr2Qa'l>UneCldY%gdp6=6G9I5`7Bi!D#OG<0.UBC^-4b>Q"fBA3D6ENSDa4_RpXo`+8jE8V+q0_3n'=48_Yg_rET$J?k@D %c6Z?Q?^70htL(mBo*Xl4X2cj,VANf,jA/VOL2q6;MHZt!_H%t!%q%@Lk-6n^_>Ba@N`?^dG<4Q@\A_UbRjph?Jth&jW"o"Lk-6n %0WZ)/5`-ANB>crB+N4`8/En31OQ$Fuon"#OnH+h'bqm6;#up=)K+9Qq2_=KNd`1L+;aeS4J<=P*7I9OG_5]?rL&m=K?VV1J0;,51 %Db^me`/!C4*\ic9"lLmo4%7`["l.#]P>alg$d`D6/15jcMO5cDd<:DGGQB02qrAGg?Rnh1,`&.aoYNZX%GQC]"k\?:)n,g6=\sam#]E%_\XsV7! %0A*'$;e-^RqCr>G,W!(5Z_\I4de>$o_dK)?9oEGqf*bSQP1_)9W3l<%8Qrq]U[@(^@Xn %W+qL>n,dKoUT-m@_[C/?VlWHF_[DF.,gWeD8V\+^6&ZW,og2fFA;1mc$V+9^A;1nrXu)T9,W!)`h1AT`8S33u@;0M?bj^54qaOAF %A;1o]Ak@lK,dSp<<7#_E8S335EXSJF5+U2+aT,n+gKb)YNqUflZlP-FZoc9Spt%l^TQc"T^0/6-@T7H^TQc"):u4Mh"L&[rcLC(\t1@\T&7]*Y%R%&kI:#clhT0*r9J\. %FZocf>gF21D837:?e=naeFi14\aA#Ar9J\.FZiq_%(4GbqUbC6h=V2gp"/m7l[&PQ4o`*bs)Y>UmVi$Tp&+-%rZ?/D8&'OZcbHXG %?e7(Cf5iNcRJCtg;g(=A:Ao;us14eO?-g9gkPq(JeB*F.@Os>,3,=(VU`XO4+:#@=FAAqY*.D72Mk; %!U":%4C=nrjknO%+gu(>\$h@@6=YrRhEos<$FSL!pg!jf&*5aaFhE:^l(]B)TA4n%I%*@"EP9sCJa]B:2.8hu1X:T_.o;:;l;W:Z-Q"!W2`s:9S/kS_@d?EYg%9q572Hcb=/_qkYS4=?eI3 %?d?CdbfW&q->`e=u>s"?2ao]6OnQ_i>nHf5PD7$4`R95?3(jnD.0/)P"j4^)2sRH3._7Xnc$9e/YPR*[%u9c %qsEreT@r&*0Ts$Ee>ZAHB\tB%TLlMK%]IVol!V3ZgBtl3CO7$NhLpub9[Q0Gb6QuCh+6C!6iL]bVkkC/NS<_J)6\6Fa1kLkaMrPZ %-2j:t=a?=9h]GIeOMA77eHRZl1,<:X>4foR?9"M=,(-S*4EJG2:RT,P>,n;p9m1,Qi)^)cbcoG`Kc2Mp3p>Ia8&L2Qg8(/`,c!W3@eN6R!%>fSfaR!mo25k-JS&naOOift*q?/1j%(>B$!W?\o9VAnV:I#rq\D>Wu.t@Cil'N0:%u5:, %iI**/P"0u)\p!jiI;"engL12QDt8C %_I_G[)/5h[pQg[NJ)7nmd)HhS<)9)aclN&cGG$LBrd;/gcJO*?4CDOQ%3e\#oY`o-G,k-1G?`>8MpP#n/j_oFTOmZ=Qc3]IZ^Bt< %2UL\DmIel#G*!<=71l5QLQ;q^,3s7-Wr7ng:H>\>570!"N>]=JPHIrSio5hKp"i,!<.3n)hXQ4e>KXi@5=rS`4hb/f,tm_d.<F@Q+C[fIqei.V^kW^@r$hE>]Niq%2Hg$\ %**d\B836l&TEq1rSbr)dk1b/;rHenkgM!^/F+(PqcFpua:`tKQ?I8W&.1%j+3"-a(8$TJXk4NU7-,2M`'snBn8fQlQn'9\#"np?@R/^'UFJi9BMB[Mi0_iFR&>8,%rd39t6iNR782tme/3Ma3)Rltl7lma>g[T8pR/#=9N%8hpImZ;$1=`J@7#Pg-mEXm0 %TtpRRpg!2,DrN*9K"kRR&0SSU2f"]9)mo3dI.Oip\R"0 %gF9)dgKW!?j7dERj`VP-YMA@ZcOgNMn*M-Xg\KNU_W_I\JM%qO(WAk>^XWO#3`ql"kBXR?20`Np')3qGlS$[9Qli4ZBSW")mI[Ha %>V=dD$D!fgd*1k8$t8=d;SVD7ks;KQ=nFs@eHpB(J@;M2n&iKC[oA53fDF#qkeko>rc%Qd+bkUmW;\l'[mXFdCDRJlhs.OEn2L8jQi(1UckPP4lH/8MVK\%QESqbB"eQ:/Lo%//;qd[>=]L_Su%,Y(b9m9D_S_Z!!?q5"WH=VDUgK^_] %g#/j7q3L>SSdjhG.rT:VosT"NNHQ/SDm*@"-qn*UYu]/A"D8!W^ANQZS]a-mB*f$r`2?66=mSW-#,BlR %*]J`9W?7ZQ>;P6Sq8IN)G5JP6kg`QI\tKE>qdd>`l$;7T\fFekcZdRle-;7&-qBV/,H;fT4t)JGGRU>r/qN%c6etFrUsC^p\rKcY/CQsa[%L@78L[_\GAcC2U4L,B>*'g %_RLZ_9I9V#(.2c43)AfV*S/S2mO5*nbS+ZErF"l&p`M:>YL>i!2C]sOl%=,H%_Y'&i0AaDESHCM)bHMgJ=eI)9_.eEG@ %&GhsSY-?OcMqPpUl=?51(2LY+K3j+BcRfo2gX(Oo,):<*b$W"p8&AkHYDNq0S(f;1YD,c^m"1e?iFTAR]B]` %>A'5=NTj1*/i,]1LV)WGA,4FEp\8G%YTsDkNIaG,hT+:kJX'DgK?^e_R1in!DYe1rRsU>>"?mn'f&R[Z2hDSi:'0`JrV&E'<)4RA %n0[&,rU?#u@8^^\Sf^1*`,5hYlWlPLHjQmj^M\Z`$2sL7FBo0[Rlfi]h8.(]fD+)nNp(>WlAiY)Jjt$-I]>MiZg,_>,@$]J!a"t6 %o\iCN**6p4?LY7onl-5pF`kD!D"[/gW=)f[JbJ0B8tpZZ=Z9D'+[D>`kk.%ceBc)SJ?T+YaS%]Pqoqn>p25Y2Yo:.023;L71Dks< %Zi9X/n_$Y\a59'K6jaQD?B%n3BF[Tj-2!=Z7WV+piDjS]US6ti5bg=bd7j4uA/`]9M2)!*k\2l,g&)YSl\!$"W`KO7VVAWnbs8%b %o2td@9+2nTCS]A:5biX+;N3Ne(hh-ak`PY`:VQOim,-2cd`m8NGcEMI=[)3pi0ci\3$n7Xd=U,d!(WU9UNFs,5);Mt(k>QO=T27n %rjc>0,OWI8&hsr4[cfP-pDji\[cfQIDeY8/df;=dO[+)sAW#/W41=B+Q<_b-*&K"iI&o)N(nkeh(4.2f?);aRT`[A79Y];RAX)BR %.Adt7B,R>hS\8m-c8&;Z^#I2aCmNKD:%:3'L<,"1%6RYOU+M20MSt4u8LkmKB?fbd`J$'s7.a-FS\m5JpFWJd;>#M7LS]p!Tn6'j?5MFc+.mpJ(*(hbqT;gTfZ^1UKeY^V`g3<)&M$ESA=p6u6KUq<#7c[b^aH^D4IY$63Q#U[,#e,Q, %deK_3$eKpd?OGGO_mOo#.@UUG[8Wl<7e5_T0&88g\(n,Yh=H9h]Ge^u*>o&Z;*BX7PZ/LWhL7_DRhRfeOW=5L]2/@.r6HNH\)'2)0&5L-&aZ!@O-F"1(9p\/l'id/(nBguP4SDm1V1*HA)j+%Fj#e`.m_Sm%P1u^e_FIJ^TPKKHhS!DL5p/:"%?d>A#Y=1_T?B=")"*c$"S<"[tJ[jfM^8$0s-;aH3pTL/0b`rgsfA,i.E.e-e %]IOEur74K^`CS+I"[9A&O!\/X*q3;BHOaFE])W:'aEbNBO7Hs)S:tbQKuZ@?:=LRiZq6ItJPUu\UG0+90?+l\%t*QD,P4/7&m<3D %iTa??R^ar2iaq70:QBlk-Tlf@-?JM %%e;RN@/Xk]6aQZ5MK^oMNlW7RkWjtgcKS'M)spFcU?sqm%#op4q6MoW_=U*D^.26%B\cBi/),oYm[Tgl^WrJi;/n]tID]7]'].## %U\h[^S(\Ht_4.NiG.H`_W-oE9$+nPYN>Y>(]T6d'>qeED(@((PFgPm*PDT1[Vi"T9ruS[OV9tATs!5X!E_U4hS>O,@p?P+O.61uG %Bn]jhfq,+f#$YLPT+r:?#t!Von*OnfE`?J61a_pb?XhY_+m]9NKDoFV*q7!=mUsOl)>oSiYRBD^]sPs2lmcT@IUpHnFRa"HHG4`] %"6HnQ.!As_)5+!/EKh,<]5pMC4pM3"]tW&nj@oR*AM6kO#UQC.6ne>_ZaJ'Q>^8K\E`^bkE_ZH/>,,2IG.M$Hqt0S?9UkHZ%lCtb %`L0CmNV_Bn:?JMe5QVuWNIEReY0J(8f:#d9AiQ%;lb2.fFg7rr(_W6m;KfE/+258>6?qB9ipuj;;>EAV_WJF^OT.!ZK`,OnoO_*H %&>i#Wq0"b&NMV^BUOdie?B-=+79oV634mbX'hRc@,m$u(*Zsdaf&8"O`8+anNaV!/"a[HCnIUW_RmLe/P3#o'%j`''*+Ap3>/Z-J %-eMii'ld[U$,'gW79o+6kGu(Q9s1,2k,O2&ZsH!6dBh]rQ>Ld-@M3u:NsM?aB.=V&J]6!i:S;Ll][`nPQXP%"#b=`(cJ":.(mUQ+ %0?qm.\dpT%SqL;aVh(VH0B&hk?`R2XA6i(nqgJ6Qg-@%7,FT]I>an$5*@s%ahR9`>./a_m^8oTQbt!H+[Q4/2`QHb>BSOg.g9HZ< %3^^)>XF6ca#L(^[PJWI]mqkGgcepfh3J]k;-nRT-E,b2dHPaKc"7@V'Z]4a"rP!S^;Ms`tqQ]TqD)OJi/W]YTOuXNO]$_@rH<4dW %eC:AlSjW)X;sOj:0$MNq9W^)N=YMYX0X]3qEJf%]YNG9ucTp=UgSIGn`1ak@PkbWj?jWc]]diJMRHq^(lqo,:BE%LHSj$j.][ %MsOeBbkWXF(VB#IH7gfs*,4(RT1`fd3q`k@n94UTqs5!cQ$2sNqs9M.A3nC&5osA]>DHif@Q5uRG^Yh4;Th9FZXI*QI2&6N[Rb>G %13K?<%C1nUSsoJj*qg2T"f15PZ8g@Afi4Zp!g!aj47QG][_e)A'"u6H"X/!EfL<%4/Z\<%)#!I.rPKuWNB]NN/>/6`.k90"!%HhV %kC\/0Zo0Hc5Js8JrMC_Bo'J:1W5^OjGTSB.D0r%6JCLsI:X6!]/5r8C;Q.1r@Z\n9Up0#9qa!CJOM\>CMpGW=V6#1]fac)2#)%E_ %_%+Nn9">.(noHO:;Vtj\:ugISe[jc[J$AS9i=G[g_ON$B5,(LBYte/`@DN9d3uj8-nkV3po4I`mcpG

PCs:=U7hf`G7?b`tnIV$C'.s(82k0EkPI.9>;YVXVaZE1adL4RgEn"mZG#&\uq\68oduQ#9(= %Zf+)Xc0rnrTDb`.-c:@R:Is`YNdhOPiKZ!6j`:d4Ck4*^L?*8eh`MqI6^(##-)I"hJ601pQ'm--b"l+GaSG$e+\qQ$I7rL` %`eaf8/"NL<27Sf]i#TT`>Jkm9+*.Rg#iKIA8"TV>6n`f&)n$VLHsZWSX2B@+=2?aVei^^ZgJ3d$`'11T[jPWK$bQ_H(bInCPsMlr %leOas,u**_1Kna3U_e3]G/a4G14KY$?c]ZRG>0,ficU,s3Z(?hP$/tQo<)4gteBINuF`6%ij>&=IclHVtV]qCLO>4[S:IP=idWE&ZNZBV- %no:c(<$]6_GDrYqMSs0'37`C*dPD%a3a4`^$#iJ$dLsX_Ra6SUGFO];!M9O.V,IkjT$O-1$ejOFd-WE7)LrOU@I0$Zg?,_lZ_6k(tF'S/9>`J2\?[ml^ZJJ:@A1T0;U1lqc0q)E\MGNX>hHMWqd()oFF.oICJ"qp^4E@"!S="r+h_76-=>f$61JQHgcZPXK8J1J_^ %M#"QR!F3aG9Nj5DkB?mA,: %O0-`9K]"TkT;$uI=(^'0:EkN.[mo2%FQ5/JEZ$^6T9pAm3gW-h(Sg^B/ELn+^M>8I>BG5teGrh"G>\U"Sr76[`Gn'sQ&OlJQ&k:S %B9;10.%Ofu4l8hkmnsV4dds$jp^T)]CjcKo/q\r-*@l@n32j'"3c5>:+_>cNL.-h0`?k,t7cOi25Ztp4#&`c&UkF9DP=uWQU4-eI+,M80^8@fl',[+H8/D.O[oiLtQiBrAcD]L!'b8&"3=1G'S>Nf#<$+e.*AH9Gk?RiH97V:jHSnhdi$G:1pfkO:`>oF0+Rf1/&ZC![CX!%-`.ZD"9c6l!*//JY%d: %Nsp@F)54D8ZB)?\O[8;pTmfpS[`;DC0h#[@F&6)qGK9cdW22ug\uiVfpb@Ii#4.X._iH5d12o._]C9=^%Yn$Ba8[QC6^QcP'Fl#/ %cL37\Qm2B/@M2t#+&bQL9,X_3_N,M-O25U)muW+t0K)'LCcQ$^guL?$`&jO;0Ho0Gfg.6RekZ2sH>ZWMYZ7ZpCg0!);u3ZKeSOkL %U)E+N@sXd>,l4A2/+XNU%(uCjD8*\\:)`gsa]uT$hLorJ-R %>qH3=p7"rn1O?[.jm5QV?0Y7Iq_uY[9_92P_(YU:5&`1H`fY(e-I!oVi\V]:lfL5BO>\@t"CPU^j!A@O.Wo%fkMpq8D%G&VAeO*U %]@(B%<2qX\#))/^'hH/^EULJ7CHsEj;;Nr^S4MRfFld:RnuKTE.UZ3!q(q)G$RjZ5cKI %##]LWV^7RJ%A\):S=S?+!D(&&MD^V:oh2H='_F#D67LMOC3ct\,EdZBfB:Fq&Dbih23:-^N#-)Y"s=(fZ3OuoL6C.(4rPj2)G%\$e5@^V)FuGGiY%Jr%A\BA6dp0^D`@%\9;.RRO?/gW.=`+Y0$BrQCES=S %bN2RC23>]?Ve&]I23>\QfJ4l:)Fu=GQkbj+%A\A.:s(YW6LU;N&QUZ"6-DhO3k;.$KlQ5IS,uprO6dTWV.L883:D)A'jSkY(i,_c %0]Rl[qc)gtDX9$,8R.EBbeX3Eb9a]=(UUWcOLh2fC+L1p(WoS.4IO//=g`^\)rb-ni9J%sQh.&u!BuGf?'>(67&YQg`\`&3XcD?e %fDF#q#UurekEbIG64=)d:t9dZk))'Qeh5mn?YnWJoLJYFRLr.OcRRuLe/;=NTkeW*Q"2)"=EQGEQ- %WkMa7[/9sR];W4BYcnsdR`3Ci"%2?$RnL$e)%Tu!?oV-:gD"2C'gl<#(A/b5Q55+MUQ+Jb@:q<._7q\2(c2t;p"5WhYc,ePn`fUQ/#q;N70)&fhWljolS5Li+"tMGTX#CJYUheDX(/qct`*15C;oknR^MeJ-@]^Y7aaOE4oQ0 %[Pl!a*N5q/>FMNG&h8fOq8dWTLbR?;(1='j_GDV.r&[1,l?Lei"4n?!E?i)\iM21k%C,I])HrgiM^ssn#Le=s.hY]^,@%@GTDkd` %4*J!%kjIt$(^Sn!<)sR@WS$@.[0H_/=Z\gZrRaj:C8hRC.YE"q)[)KpG)%]-V>u1t9APX&% %%0ut\]mP8b1*G(n,cLKrhQb=b!?pSV8-nQkJo==D4W@Y6MpjmJ<1uPFi<>'hNTn#@a3scc-_rMnA-1K%Y>Y)QD=\lBBkQKq*'D"-n\3dU&"%$Dkdl\2@R %0o8SQkV\2t(L$lHL?/MC"WOo?,afF%85#DZFsYVcM6t9:P"87+46feBA[5:.D#PD#bT,A,+b+VGkaoXL]%<;p6X#&\flTAg^TpmP %8F4EP:m%5M;HZY?f')1$btGp_HM!,6X*&gn3pO.SZJC#4nhDc3cSmJj>GeX?8+Xo&_1G,#PH&j/QN43G:MT]^eUf]\&tC[sGS61I %p\t<'S\(BVd-V$TF=@j:=/G^-Oq4GRk6)/5k&%?tM1NuFIb%ga\*Tr-=/Q>Y\D=HdVaD&%a^(0J;@ZF'dX9&V4t]V!G/MUU+\jornUl>ZYgo=nUmZ&["h5JL`S[@Yr]iDN?W!9dg)] %ifA=X\t7u,6%;?&+V;Kl5M9+'g8D'S2;0KDkf"n1r+OJ]j3E_Bg?,J:S/oT]FuYs>N/(H:##W?3lR8sHSFn1frER)Y:hQo('p.I. %F703E&h8%[Yb)oWgOo-YBuTldBg1rW[tAVb\-bUbp!m>Zs1L)eD0>('TZ+=MGdJr!^IS$pEq&)g!bN^;#HH8_GPO$B!\(o.(dSqTRQb+1ZKkd"::s(YWno5@? %au,9dp?Rp9P\VCqTDgSojVg\g:])h7.<#/;XIten+D"BEZQ^h,5YC/4/YJ=<8<&qR^QO*].(GU1.G$i-a&,)Nf0IJkX=.A@Pp@L6 %j1J2C'g,F%AY-FLBT&:%A_pm&>3!%B^VUpm(!7K)ShuV^f0(*TD%3X*SBq$T4^AC %Yo(t.%)TV2a#WqM[nRaJY.jPg.B4>m!S!(]>gV>YUhLJp3:pf$qd\R"tTm\>rmHZ5L`_^ %38#+@Me^dT12Nl%WBSVpYh^<'hr?-*C@UPX&)6&?45e(?)R`;=#"_q=`I-<5IhsCXdF2Mc2C]XqpN,-W+V3>DDVDF+V`l`Ob&n"[ %1QKM=Um)A<*c#9K_i'ETd\$b'R$qIm-_3rW2Z9nI>S8NFqffWQJpB"nMtplDPMRo1IZ-Wfb+D!%ll`magWle7/ZsZ %2*QMA)HDu?SX\chA^``>#*5oYs#LTgd#fLf0j8BuSqa%,79LS!t&WAgGO)2o`Pl*-.Rqor$5]@Y75 %=6KR?YZZ3m!!X?'?o]ke\u-oe1%=kA00(3@Sb^X] %pWP?tFlnOpq#p;.>q3$A6Ga]=*Rg5cU+W/=-oKW'pQ4bUE/j-Q, %_\+AiUq#qs!X68WYH7Sbr#XC6lG/&Kt %*.bfqnNTJ@[,\Ff8c)6D`(u+Ol(jci1;22":HI`a<@@3j53Y/PqX]V/kp2U;F]*pY:HAgAaLS#RIF:[ua2cs_SO@Qc8't6C'(lrK %lB=t`8bXt68LM'EgZDh/qP9o59;u0H-@k,9?`Uj"9(c3`9g6FD*#hDOV*:6.5(Unn>!* %F'o+o@c&5ZU.?;ZLplYWEUe@jo!GoLEMJ]>m(]=?i"$%oWZ2)K[1#8[+644@<.dc7^]!g!YSbM2aLW=OGO#de(tW*O$>:b`5aS:/ %MIh-LVbF5mA:=?SYU3'K_*?lOIPl#`i;b@(1Z>lOP$7^!n"O+\7dHe:0bMFcWLG8Q?Do1$b=A&<5HlVu/*"[6%I'6B90W8>HW'_C %&7;O3'=s]*F'j/fel3H_cQ)6Ij7ITVoh?KX3Bdc&f6F%_U8U1_0A=Q2IGX<Hk9Na %j@0Z7>f6DD\FD"$_r'8eg2#;nYHMDPRa4K^P>l#Olm#S(U`WM/B:J(pheDo-)MYAa-to/"T'fK,-]3DT'?.d,9.,T9n!kfe?hAi/ %`R4pnSL?==nNZ)&0b[4?T7`CB`QF$Hj[A'q'?/F+n?4oN2#N3!NtVWpdb_aZM;g&jQ?X.Lo(ZYY6ij54QphSEbKo'PE]da7*Z6"Ho3"%G.&$IQ6/^\J"A];qkeWm-K>mBnr80]JFquQG[l;nu*uP>]E)+C,@jP0F)d`_qD*a%_!TmB(2=j]RLuWk5Y)u:`aOTmM[g0lt0QE8)Gi#mgm1Xb4#-t+o!SCU$>L"M9cO:AY7Y0Y!4jCtRE65Oi7kE,h>OK_NN?gY,\o@0ur*=a_;+GPGjU:uJ+(I*@mFKoB>$;-(fMWkpIOj6S1p2DI2rpe6n69OUda %b^+HOO;[C-d;h?0J?D3q+0,el7[M[>Z^.VnKh,sl%D/Fs@V!DpC;UPLVPQinL7'OJ-!Hu_`Yb8jU %I4A(KkJ/%-@U@3X %Z7ceI]2h:`Gs[_2A=#]Korsun&Y`nAehie/C,o4]ba?"NdW=,rJ(bPO"*T9'7bM#3mg+/>h#OEE"MYSBG0[&sprKENY9"r:SKGhYuaVrAT*aet]+O"dW&",1_ %8=8@7N(fWo,g;p525/6[6qDrm6Bg`5ZFT7/OFqFlcQmpjc[tjbg4kK5@Z[510S2d?,MEZ^1Y&GN7]%k+[g@0DS[[=[r\CSC*2-*A %f3-j*"e>?BAR:h#rS$r9%#8bU>8O2g,:JKurp]((`#gPDI/$(fb(W(4rjk$:YgE2TVkS:3^d@5-Jd)UC19.kT`hTZCY8gD_baAOnIM(_MagI.I8tXg0T4,.I?'!(6H\^kHBrAoac.SH6MgD3rd"]ZQ*c0$b\dKJk\D' %iC3AcH^5tY%PNG.TQqPl3kUj*fc"1]d^"\hM[Y@WTkj%#U#i7XU[@#/]^rH7P(nJ]>bsI0%PM;ZPrue%E-MuH0]_amL;Sp!0BOAZ %NI#hHl<>=H*@jZUiA+G,SL;>q[tcC@SW"Qj(B7pNRd45K>A'5=NTlFWV-C)om#T+X3*,(7=0XTO`*nP&:'QQmqC-)@ja$TJ;A'(@ %W?Z:k,GGr^@uU)F9;XCRbHGfhm,4h(FMKX/F_sqkf^C0bfdB.#B>u@jiV?D_bHf[T#epg@[*4 %Ost*JeBOq%3#?B[\(S^00Q)lu4@^;mPj:'Ufu2GdMs-0UaX4G;=bQ$*(>6XW,E$eEKg@W%[;l]Q.PSpj[SA0h=e#o+M62tu %nXdrIS(Kci(tC<6ZAG]IM8@`475hDn1,3`qSl0$b&-LP;;TF2DZ#qh,/qqtI2R.C9D0.XZ1I5QC9WX^+16#lXXJo+^pL-Cn46N,u(nq-FQYrj-MDFqY%XA"/E\7ic6eQRAme2KZMSHIlO5n?;RiJmXo<>JUi7EqVY\J"OA_GX.k'Kt83oJnL'`W&+Q_W3TTj47"k+JbTp0=8L&I4%5q1DN8uc9c5Uk;MC(Z:9TTj47 %2=J@b67IAHX;0Ok.@=";$Dgu0.I;/`$qdcuAMT$=<'Vp91MU\L#5>YS:s(YW_Wuo(Um*56]4F57ZTQF(P\VE'j':&d'L9f2"/T6) %.=%NB)G7OE;G-Dp$;.i5;DKn;%Ad;3.2jIQZGE*aB&K>QZG.*QT-k\HYrH(8jZB_AGhg %>ld*H'371rbFk)8+GK79E[^#f8BIA*2(/';J4gKD5RKXj[Pf$l+Jj5-AS@iI!)diSl'dgA##^Vf!_YI>&s.](R0=sL%AZ8d`e'D[ %##\:6ZJ_O[JJ=(jObT(*##Zd#1q#CnCEVa!fPjad,ZZ=\!\%Bl0]8b.JWuJ^EPkAQ9P&5OUsRC?6)dspb7,h1%A\B13%8VcjZ^AB %#"V%&_1IlVY(J1:e(N#N3p*6>JX#/dm#mQQRa,<%PHkBj]$,I:S<>H,mPYUo]+]S1cEQ %.;L%0dt922.;L%Pq'`i;Uo]-3loXL$PHkBjJ1OfA;V")?Z>3T^;V"*jO=BO>\;pWc^upRY-Y3a_E.iJGd-Y8X %8Qc-E@r:JTE$(ZOn1n1+i83DBE$+FV/3#(o+9`EH/3#(o+GCOA$of\O+GJB1'2FDhM7_rHXP\9hCs5jS706B6LSQQ@QqH.]7 %ej'S7a:($WCETJ8`Om/XPB'.JF&LRS9!4@@*puu(0O>7`iJ\oaS@F]D$)u/7]Bn<],`WS2"]`O@a'Q %P+.bQ]6?sb1:He7.DZIuji)ISham(/f_Q%_meHcK(3^GBj&lasTP2m)"cQG:)m5\'uqj5W7f,[nmueV+6ZaG*oZeK!oX %OY-AFAqA#-ZhO9#*tu81-hCjAmG:R"^Qu"1C%m't[J@9L.j=O7[Y7QK]0Y`E5W/j']6@2[GP=5jReD/DN>(hbPg9_sghYd)6_^i4 %DkRh+NQRF=a03&0qdUNlEUgLK&KW*Wo,e^H-.eSeULlKMk#!Su=^ADSHVg7)/=[,>W%=D!,L?6=OtSo8FJCV)S4O[ts.m15'2QG` %[4YJ^?fd!_XQ*01O+)h1_Sm%P2E1]"!#bRLQsX[<.tmV[/KFFPS%hBI'9jkD)dif0t2N3`?o&?M(&lVpd((n]<+( %&YPmKYMKj_06UBEcLh=."pOup_^/#,Jbo=8Lr\-JHi+aO/i:c.KF:1dZ@^9(1Rd=,r5X,_fZMeIk+*CN1'LobQc'5Oc#7@(B:UO< %%WY]Jgp)H9Ir"&h"E=<\*=hK"COn6p)<=s$>[$e6)02:f+5b7aoX:lU?.1#^c(pa1\TIJ"A#Fc=hu[P$/'%n?T]FfZ&DXTd$j-fZ %J]A8XGY%jSO==hk^YQp^CFEl\K.MD0YjttfkRgi+h;7]M#t&.q3=?P/J>)ZpRhcKaiG(lPB2L`D#bgk00#B9lPIIWBNthEEra?I+ %]SD/o"/*aN8_6=JZL3Sq#J_iR=rWcmTAe2@Ia\i1q0![n3/6tDqa_$1gD`SqFZ:uDPOiMocfD&(J$QAOT`ZFZrsqjZ[LRg5s$(c) %'FoZ91T(IU>&k\ZI;=/c\M(Q%UsQ,`jNIORMVR`(nmr>MY'jL6.R8A&=L&lbQ-UCBFp"olc'ZV6ZS8F);a(Sk8kVWh$(k5WHSL-l43M`/A9@Elb\-hD%>aC_&\4$R-Whr+,Z_Zjm*T;IBR(E9n"c_qcl8AI[d$/V+G$8Q?\h4q!M1ZqYVIsn'@VJHrb&!L&.aVA!U@nTX(0< %OlH!(QQ[6)P`$j\/Zk5A]#nr<0s>gU %LsJh7g;;B55@l[-%pZTU6:2_$Xn.G#Zsm_j`gaVM26@_F:L<,tC\QoOcb'A+jh0GDjVjaBnb-D,`5(hTo6oEV9D=2PAmFZgTU0k8J6a,+UUYteLS8l'qDo7Nne%=E*gU=n0^9$^RC.FAQZ %U0E_cr2/g7"l*4s%<-Gl:siCYZlULP;9^6g4DYibPfEq`h["7]l_6#8pa\#*]qtc&>CM6Wp)F$(b!\XpJr8u>D$rfAF*Ifq#\ZNV %/-ak?)86X,ROo\B&2'AK@l-LXCENO,Nt>Vkn;X]6[]H_LI#8lMeNAdhKG*=u*XQ\;'UdO7D7$]`NO>'p's'%-EdH+%!h#]5CTN4G %m+e>;j0QBUecIJG"km-^.V,VXf((@e(21l0CVdQBDQ@Q[AR3.J(niNsXQ;(HQ?I^LbtIWUk0V/R6!MoB9/?h=$>ipU/N5_1 %qHBG[!haWY/enoNdu[XhobmD-:@#[#_ae>D$BFq\M&u%5WWQSb#MPDp0?,df^5KEcJjaNG]3%Q34+t %-'1ID\0Y"JgER.q&K++OM'oYX;d>FjUb$erG041S-ft8^`/BbOP\VE'j!^RbCEOqr/s\c%jj/;\OA\s(ekEuAPN2P/Dt5e"Lt6DD %.7NoG"f8/Ke4)Tlf2,VDlamCOE.@iAa8&)0T.u*q`G(f,g.S48R&lkpM4` %^l";s6$Q'FhpTfbE)Tc=,lFWgs4f7)&J*7?9bi?+_HtJpKE9;QVrm?u#Qs$X;bt6FGQ'WiDhK;(=WANd4uEd=)!JR_o+YHEF\QUb %';b@c%ZT3/.2f=53lf"`RC)kaoAmu'A,Xuo^+l/r<$qn3Y-mB8i1mfEXnD&,$u2&4Q8=02s.i#/45&du%dbd%p:o_9^7\_5FD.#J %$a9@?6]mGX]27KLs/&.F3fIpL/ShF6Gsa/P>LEC).^7<)-,E9ebSJo@m,&Z7ba-Qb2d,$)n&@jFEM%XjoR]/a3,H\k;`o^/![ %rSVsk1CToHr:pF9W_hL$dJn]!pG9Wu25L@>-Z]4[m-(@;l_]#4H'Q-DkG/!R2S+H^5pt:tG2Q#f$H\o3)?a7V1V"97XINTO+)Gr_ %i^P5ZfmcNhmiO5VN+NWABGM1098KT[$X>RCKl(q&4@m9G/R"Bhfhu[L1g?UeAujW0BssfW/!d3;`811ZZ!l//a0AZ^O[]cdhLdF\ %>9qH/_IAI(>GTq=XF"NYg*4cWqO"=l8@+$A"@I@4/^eI/Os\LK[7/M[8\GLtW\'BG$b^&/=O[c(4G4#Rm7)frc7sVW'76__>)-OYg:F][Wls12pj=;q9GDN1Q(YCbe9U_H+'5@U`jnc;:o;JhpMq`)O-5dVML8D(J[kUpA[_ %KF>2kg*17>n6*k4[1siu[\Qi\V.tpafg<(mA(;>dZN^4C>LaK\Z\:SsZ"f3h`qqaHWibBO6l)dSP%G(tG;*$6d:fW:X0tQf/`;fE %WjYHe/^WsmNd);XP+k4[Kpau/lc+$+Q_WcX0tPa9#b>iWi]\"rlQ>.Cb:ce)61T"`XlYEQ9i"a]flt&>6]$MfhY;<>=7Ms %d[7^@mhd:]G>khlKsMoT^$ct[$MFAMG(RJ6k7H^c82k=Lh]%E:Q56G;[u;BM95Stp4iRImRYB4/oq?8LPY&?QPu6ogDTi,8?eKc" %q`65:7ddBk[]p_4cHGT3:d8`eN['tZm9`'H]pTGTUL6nWXa!_8.HWOP?u>V.k8!!(?*YXW^.VWAo,]4S*PZdoeQ=Gje_':mRRPAu %j\@[6#1#Q@n18^.OP]SW_:u-P'])crRR_7iXVJfT@j[;_IBn'X@L8h\5H"Kbm$t'c*pqJQGlq^g2=URBZhO^ %eh&D(`":.RNV<_.peB5KXm[jm5QXL-Y4N++2dR*n.HKAqZ7AQ`@8r1q:`+Z9b[0(n/h)4oV4e.$cVUAP93t %\t4s=o?t,_lEB.b\t?L9%2G/e5/3MPL;nk/g*N==>1Fu:/+i`=34X9uk./P_ %\TjBE]Lje_,o=mkMd%:VeEZ]?6pC,J5kp1o27791>g()7J#mu@S"\J(UIZ\;CP/, %(pas*8)N7`[orMi5ER:bg10(f4tGEciB**#l-a%o/0([6;9BVrWh#ka:;L)D9KTX8e77YR"$L1Q*5_;$VY!^G$\=L>;Q,Rn3m]-']l'Vkm,[XM_+i]HZ\*b+@`Wg-'f^ek8lh(>.;VK?$j1[O:A//8c7iYh2IF[=`6L&EkMnZBYu:noK^-Zn:%hCp4^r'H %MtQgtqNenA7r($if$'29ZNWa%X@h:^jBIru2>!g:(R"t*K#QAVDRJ#jj^q4gFrVuFJTqs'g3U^*eeShteKmMOdPfqB@!O0%L5.Zd5f %l(C2mX\_M@e+rM=SmKnF^mWPLANFi=Z\;5Rq%uG2`"B0blB"#aSKilZL$iD$3=A7^o=sE=d,qmln<1+3Iae<$B*#J!BmI".KLYaH %-YsQi1W$OJ2JimWTc1p,VW+df0tIZ87_m%,+]G'9)n]K>@Ofmf>FnjaKW.e?.F^%X0bl`n;d2pa.9QVEAL^ZN!d>>!1DP;%YEd&A %T[EYG\Bbn.?_Tl#.Q5Zf.Rpf5Jb/[k4JDUnKkfFK!'I@3ke5btkG+N-;&2:6;b'i`/k4?V6:+/Ol>4uGaaQF-mejR2TC&3Dd$n98 %$O=ui,W@_D:6.>?hrJeKj-,R-3jt$>7-g%d5*#WXKUZP9UWHs^`\NH1U %?sbn\Ga-m#PUf*Y+(mY"PdipI-\Sh>lW`[PVe(KU#URQNPob/:ZV(Fil]LSH<%fIFDT.]';<$X&]2[NdPfW\;NM`M?r[P3K"Hk5\ %POHXF&P->"=L=&^4f\$uZ0>/GDs@srlKe@m%#gs3Np:?mSM-J/7*!QU9[W%C(n"]riD>cTZr/Zu1d93N_4*ec!tHJ4kSf6%eEFM@ %H;hFqVKV,]:?tR_/<;s&aHeW)m0]2bTLi\QQ=fNL-MR?+=6EeK)a..ere[l)!E+8:mbH6VX\.C_Hql/6CVicVha(Jh*\.(TCHo1D %BUZJO&r4h=_BCc6M5h+ZIQ%NQs'^:uHJZZtHg"X3EX7n21gU\0"Bh(ek7I@6c.Xek]RuM;8:gK1,ut61I0pHMAIrr5)_Zeme._m9 %K7E"s6rqX(3r$bLXVr]4*;`ab\lHZ?i,ZTtW6hV;h/?qlBM&`O:pn&O%4t9bd`(Z;B>W6i4/Uq.FU)@e^I&@c_(df2NdYm2Fsd=/ %77N9bR6MLgi)3I;cA89B*'d"&1l_WK*A"#RU4u%(g)[[0t4# %07N/Sroef0U]-$T:hBQr3lC:u*l?;5'Qq.In!hr-hp"\@f?1)[%7LBOf=bZeOmrE$Y5[3b'g6$,Dn9G?\/VT_Wgbf-U35/1sAon8fk %qs9M;&mM#Q%/767F42,?Clq4fG4:iT9=*?)4Tg`NdVRBSUW#b#2\cCO(kG)f$4ik%Mb:cLg"@*7-CZ-[;SJ="'JA/Er%]Sau_fUJifL,8q!n<(`a>+6N/Km)9LT_C6#n^8Krq4J`3shc'%I?3"X\o2bd> %n#((1jDlVsQsWIWk@Z/k3$9N\pq.A,W0:L*n\_EnX;=d_M^C1!pg)R/+)l-q6@9i3+-t+uRu/:o+[UIHOr("-u+fI'2+[+.-ef9uRX_]Hm41LX!\Ba38%Jq*oml>g7GU<4HI*[e@4LDRN)#cC&oW:4++ZF+c?[bm %#:/.kWg$U@#://6SrM$U3?[hrkS/*X*9\cg1s>t,2_+FsAl_O8M`K%5P]hL=EtCKR_]4b_"!?]b3QRXE#:).&nh7AoJao3JR0+(? %!#V+UF$OKXqj9/E$?)#c/9>QK_&SPc@@W_&PW:G"PaF32bC+`MR_FrsUCQXN.nQQL)'i[:,2RL/Jo;KNcLUE0$98Z&@VE5']O-J^Lqqp0#3-%-b#gE]_H %,Wl[Tau7Ak1^Wr*[`ec/2iq8G(tg7(RO/'NUG=B=ua/W4[\Hrl#ar5iN6[Y3'Pf!uKh&2OFRZ %DZJ"]71or)uqS6L-KQ\1c %kQ:p4+O+1GV[j3sJWF$>9e$RS*SMj.RO6u3L6ZV=WG.OCH.%sp;T-d9$,'j8Cm.OePL+M^B:EFHRY96U452%0RTJYHf[qO=l5G$i %6e`kbdj4`0UUEms*).r\[Rm=r#h>7-Cm.OePFt:[bVmS7#E_s>,fqkLh,M40Y2^OWQ#2]Egc&HG8KM@r]'8j:Orl4a:I@$7o!,Pr %1-NA7DC8+oP>"\pk%YAQ[Rm?n8U.qQZ;!)39p-m8g"7X>Y#HdOZ_k0&:048TgEa(=;W98TpQX=_-:Q-PPJDI,R;J+dBbGRlAS%?A %C75:l)d=;U`;hJYYV_GtYS,K`B)/_L`8+`?r*,':q!gG&2b*d_M#?+R0O;-Z"B24lnaHZ3^d99f<$`SpMtG %@DsRpfEAX!JtbX-Memu2L%$a'',21524NMlLHlb:6Ic6L*jg;L5_Y89.*uIF.G1Zq6Y6nZG)4Q^L@E9eZ0#j&K&5.fWr]c!/#ja`S]jqe8 %ht0.L-D6hX/n#E>I#L_Jd4*X.J2,V#+2,<9\>Bu$*j!DHJra-mIWf'S_1X;m,R,SZ=,n[4:^XO'@ZV,kK23)m8=:&(co@;)nL-p# %iCQP<:TGB-Peu8DG1sune\M&a?>ZU\$*j&DZ-Sk:!$lHN`/rgP@7)J/AdVNNK<*(5ql[9tM?LUcJ;#1uMpKtD/_HLi+u]sT'DG#% %[/+YW'FA7,kVWlG7bam(NV\@p@t,(d+$nF)lteA\2X6]*+5p5qE?SAc95U>-;>haC5X4d8iM6c\pS47QIY:_4F@Oqoe'Dp!OIHZWt008Hl`QTD*?6jNA&1oB8nl>!gpS0:V1DS\[h:P?i!@ %:CU&h:+XR;`62n9Ys%WX4n8*+4?cuXVrluMp_4\HO<6H:jOah`'4\4#puT$#skRiR"/iR1SO.+&5T/,ULCf)&$k&f6KP"k/=53inWV4C"%O5'B7g._tc:G %KK):^S6h7mOUnA&A(9LM-i%`F\Lc?Bj+KBNq/GQ0:aX+4jMSsoWUo(Bd]j)bE>IGRBg*MCPuJ'0DCT8UP*m(C+jNYC*4i,Z<=I?/ %F9ur)o&66:VDSHumSF%Y_R.B3NeCnd+SPAc-2GUj-cn4@E0s.m8r.PP%u8GYb(Ma/q-k*GEGk@+J?`:@&D+I\2pEB+_a1^R>sd=/ %+)WSR4=$_i]>I?@\X0#->ZC7s@9ip:;$raPlBt=Ybac+d(,d$c&"+m(IS&B0:SY*/jS"sGHn%s7^MDSUm %V[1N/X1lGFqt!g`kpiXOfrDGOdoGgVGU[Fk+k<*G`I-3;3+Y\N86TlOX_+Wb-N1g8Y(A%_4tcPgoDD;%d2*"f1`>'i$:in4nWDAU %Uqs),PSuWk2X1"&HfGObg*Ef/$XV%FX\B_8JtbV2=BfW8X\HBuO(5Bl9*,Dr?M9#+*XOZ#M*^`!_=fSl$4GJol;ethL)TUCaDDh&AC1'N+G0sT68'jmh.*$i.?#+=ffpn5f#@29fo@1P:m"QsuOgsT+ %ZN%k2X"/+$Y*t+pIpdN8mEs.CiO6=]EOYppP2HF](+oX+_UDj;3+,b?TK!o(*&)0!#ukRe%OVAa\r0a!3:@'T-l&^6#HnR#f]K^V %Q">SL3?\V7d=uUgHs[QirbtO/X^P3jr4Qr@?f=r-8U(AB/r@^B's@DcMg#U&+&$i<$BMDKIAJ%o]'p!tQQp)#H>o0+RD)!H=dh2! %KcE/&]P@cN\)E#M`b22FI=@jKl)/ec3TU+S& %^M%C1;Z%7hiAu(D5r\a<"u@<&YJGuEj\Of*o&<-)c]_tI^jjRGZihA/V^)=3&rmN&&\u0*FV-r-bkKIkC(D+\&S(s]>%aO8O/0*) %&KoZ1P&VT3HW:@M:(%H8P*[>jCY9:BVXt*A;OJ+>VY#Y)UF/<'R:&,+6J@8=>B'=&,W!)jI*?H+"o9h_CZ-ts!b%P0I=u=Sc"?hH %AlgmdMVOe(g<"=NrO5uq/q(Ndb/Bg-Tf(AJk@Ym!/HoG)IE-l?Y`+Y6Tn(_urHn+#GS]qpntj^=Y-sEiAVbGKbg;QF6CO=;q2Z %=DJSKbdSQ%9UVcD1DQh6ePDbC"u*RZEGgpGBu-X,VUTc0!A6Ct:n)A`[,/Y;h"9`5%^!3fp<9uc>&W@"F'VBk/f'OSh,2' %cg/HUE4Is`2J^fqqL37MPUB4,b*ZHcNGor2Ks&P#WTt>Ra4L^^9aAPt/t04=_JCsLZHe&F,g:RVf/U9eJ,*'[/M2)41X8?6[Bsn^ %a&X6rLl]m5p;XO'$>&AU]8[GAPHaZ)2bIc12-=d]pthZ>1"dsF69TJoh2/,pg2DbTf/NSHj&&A2NU*1/&5#^@@\D*c=EkMaJ'ar% %%PuJj8th5rqo,u`0`11V,J:=CU=1:B'&W#Ep9;mj1dHE>3j:`pa2/gt=S[8'P..<\:5-I]R'pC<.S(SXd!f*$)WI$c8@fl7P:`q. %*o[WoSk@p[fUm)CjgnP'>b`mWd;GZsV9k;^okO>4M!je9Dn_:cO%6UQ09eNep(W8Ton>B5gnqq"p[E"ho"\>\<>aHQjV>f<)[\rq %^9H$\k,YBH/)7b@n5a2N^4Mr>Q++?Jp6F^?5"$7@`S<1bq[+YoSBN#.CL?&`icsmY[XA$"39k7=p%D(jUE'8&B.Keegg %IF\,agpCs+l1C6!g/eqlm48*?4L'FO\4C_27ltbZS*T$Cioi,*/ooqX\WO#e*6p,85P9\G,e>RVe'Minp+^JbQ"kM3r[se@.b/n4 %F&1Xk<:,3C4<:d%`h/k/c!Wlg.oiFGWDmt2*iLPg7#S::B<"R(;^ngbJuZ,%m93MhC+ADQ$;4?`#G7a;#a]]H."$s++#uTBcSJQI %rMnB?,bB:cY:2an->fTZ`"B@"^DOKWcH+K!0#ON_/^&.qXN4*LQq%XEihDu9]:QP$5IBsB")SPV?]fFnoHmdKOZ9N!n..Qh5\tXA %@<%_k\Ao]ls3qge#PTOP-g'GO%[Y&*#ee=oiDRfAj)A6@@kjmcBP9&[YDJA2B&]Gp>IIktI(9%&[-e`'RWj,8=S?C6A1!EmSb4@> %k)Es0),$Dn?g`nRMT0;pWC#VDZHW?VPSor2s5ii^g,C@t8"OKRI_pf&(=$#ScA&(d5bEXt=tZn^850O\mpDNl"XQU7`^c*f]6I?b %2R=_i;!ghHMVuB>"83OArUq&=o.GUC(AB:&da'shr:-hbS^geo(I>*YU`uWm\bc>W?8f,8)_2C3NV\,3H3?i %/',5-rqPVoPoR*FS9pOtRQ3P[]DQ-\>+lmjrT$N+6_m%Km;UmO=.egGq-F0'fQQb$>oK*nX&jM1rV+1)h@6$K)Q(K]]"%F&WS_X& %':"1ds&ZO-("9\=VH0p5Y0!]tZND`@]\Z?D)Nm?cktt$D.LmI!lfDC2YZ#s1/aQZ%@*Q+0])PdT%f#l/DK$3T-Gq]4#H$mJJ+'+= %ZlMMQFC4;q@]=t/1a0^o8,jgCZ %,*?>VmfQ`\-^m.*U7=V)I8&B-]N6gtcT6UoY*oH?#AH+UO9eP&lKA@@?gTWX5p@4O^YJP2om=:mFK4(kLME[0Ec9`!pjucS\![ULEY3 %hBetspDE0M%g'ZY2d2iA_CRt-;#!@Qab'S5K8'C`]H.33;^t^N#)HKW='G^bFu0W3>I"MG([>6(3mN!FCD_>*1tV,pe-Cf=/l-6G %:ZpO;`2dE72IqVfTI\jpGBhj`r$T0p^LTrFP4$`DR-KjPXhASJnR=uE[^qAOoX;_\dm(\'2OEX9;B[sL<%p7+18fHD %KPdQ(=D)PSCD'd8K9@G/C&/$aYO%Ed$HNABERq+>Cg5e%4f#npN5_l;@Z1ee;pJm^#]`q;g"IDOQ1XE?:CW_-^,k!,OMU %6te.S#h+bK+77rb%-9UO`_dmC68)WQ$4ikE%1t"k8@fk6*F/^Y#4^C2@1C9mE<.2h,$D2!k[dGE"AC%j,1TU9!I+LH3tTk$;,SJ; %3`hmc$(+2DAk4J0KUWub1`))f'Q;Jf3MXHO`p(UZ:_);9)cA](_4!k_FoRK1j"4!*^s?AYiK(K% %e77YR(r:^$9ol'"`9.lJIeO1le"]UJeZ=^EkBLnM?6NPAIU?_6->dZaZ]0sVG$]'aJbiO@F<&D=8&"b5VN_d0j',9LB9Jc4MfVn_ %"MGK+H!VBf>F3\;YR/bDA[&BrX%!QT[?-GcbIpr#1%a%g*&K"iI&o)N(gWSj\^@5P*S<;I1?d%pD)DD!g@nCo2#K[;5.Xae=UN9X %*CYk\$\t"?cWCBTa'VYBJg;KW?nk5F"1C>fm\f(,b&Q_W[FFnW2u$U_%]6^bo4,)P+`5K+=6&dq_pD3 %p>[=1-mTb@'DMIoSh2+RO)oP7'-UMd+U1>6\V;V]8TiGecMc,8%_C3F[D`#P2U*A4:FAfNU'/#Jj\1u568N[c!cC;SB:#O%"N %:mUU1AI3B<[`>ZV4I@@;'tf_Vi#=MF;Y*SJ5]@#!5aHph$.-0R<0i&m@4du,M(A[79#HO4,>5hH"RHE%mk4q0*-"p=*$X#gU/S5>)'^'kIA-m=<#]F8\pj0aFH7DS_T<\c^AI8Af2Skq860eXASLaf"&qI7X<0i&]ho\?r %=0_r[9(6gAb7a;,PPe[uP9o.P8C\Z',>5hu9'X<=-qh@M"B<8mP9lGaZ39Q@nP5B8RYP<)9>EEYIQH9e=TT?bi+XTBQ2p%$Lp\d" %Fk,tZQ@SEYoTVJ'-.'qC0URr2Q""@MfZ[:<4Hh)48ZWuV&uZeJ?-`iLVCruY!+_`sV@Vk]O+dE:^0[F8"CVtg(sSW5tcN(sN)I0N'!iOff)ih1],=NpNE?J!5st)i$ZhK755@Vp5"*O&h2n:%i*6Xop_5r\Frh^Ip^JEPduO\ %XS)?_5(I#"E^"Yo"mXNkq2`W4\st7N,BFp[[c=?RbW#AXh1VQ8G\Y]HC/C`YNMipcmiL*MPl&4L9e[&pYLj!0Cr-3G2W;G-2SgO# %rEli:AWPLIUB]nr_BqNCir4g0=Kr/_2M!HLYZ]VZrbXQE^[7XP+_WY*Dda;g)rELr'`2cPZO+L'-G=t%=G&*@6L0=6&]j#4\=c>& %U0k_IJefIo4m)Bo-3/UiF\nW45Oo)>Uc"pIcW_SZdi2rbD\T7.HiE6V`@39&g/hCJ/*W3Z1c`F)?WFke %guM!^[Oir=4>](8YQsT`V^=pdiX!5-9;488?ISnhRF$'iUac36/IKDgPQ/p&NprmPD_atL,FsMI(`X#K2*&Mh7o1QH9of&V2C:rh %%*.Ts3g1f%$HKQrO`d6T/!D2/'O."WBk;;fJb7,ZNj-J7jM#nSEeI)'ZmraH3PtN8;8pZ0j9U[HJZn^qjN'G.Q)2S7[Q'F,M&r** %i@ZikQ!Tn!WP*:)9oe/8SE$s(99UURmm8,b[Y_`p9a;]!>?bq%nQa>tXiZ]SW*hO]5?A3Lm;82Dd$A%7AeQ`W"GZ6iYR+?FL\!nC,S+I.mt/*"+If#r6iMdU6LCN=;D7c"ho4;^;OEbpkO/V;78p>,46kVRZ9&+XS^#9A9=pt$N*+2[%8MpP#nD+Wdfb4'mQXF0]pdKJ2hcX+MGGI9NIM^uNkHPc'G %opJ$ia,c7VF[/$I7d\Q9[*ZMBDt<:T1/#q5P>cO`pj14O^@%eFCKK8>G>::nRgc %f\H/@4+W!E;dGHso/tI-$!qlu+iLj71$5&toA.i!JV#up@jY"XUB:%qiEDlS/i7Y$,O[aUgcN!le:`q(2g7E*-r9nJD3#o%cWFtg]^JV"&OALLB:S6Cgl7kpc7=aYdfHQH$mACgkdj/QYK %H*mAa20^1YV`6A$[HVr>I=<]-+uZ#_TLiD$U'&`:i57o&=4SYC,FH!1],o@F*iWH$Zd!NnfDC\'U[(`Ag8og3_K/9=>Wc&_WdJFL %kMpq8D'.3/X,KE?lLChDrk?pL[O14?W\`QIA-R-G:$<"?A;6/?l\;no1JjoY7V=D#1U$tHop>pc1';\mX7QTSA-SW'ZUA"Ka:,^c %>,4*]+Z%Jh0r$NAOr7A18#A'ZOr4P=>,F6_+Yuq(A!u2hLlmQ=#"(-J\dBd+L7ZV&TK@MWQ9WMER5%J%O>^m[-`9^S^B?"^YCE^';\TaS)_ %!*k&\5gUg$2h!bfqB?Yfkh[i]kBV\<_nIl.4GRd@4Lt-@YbB=GYKW*#$a%O76O(Nf%7QO$@@ogdk8#!`:C\6V-#(4cDM3EB7@f1- %c],/>:f@;.n9j!+TV1IWa5k@9`R@`WC3;7G#":?$7:YoLO?p^Q\BWe7!eV+`BHeXQ,#<@8b)NWDnYDRPU!AYe375MrK7[n1X^p.:2p%&`c_+[+cUMf*1Q*X),MUG%Y]''=OC.5V %R%#iZ:048TM^QV6Q.k<@TuE4pJt(V[M,qI[n;?iR:PsancK**@-j/&7%9\EQM^LG^Sb,#K@HP^)QJmqG^h_h>$FP:'6ci$,O[Z(J7hb6QSVX#J46,iK2+,cGIu+:tt.f?rboTTsi9WW9Mqq=iNV>AtD>+T>sdja67%O%XAJdo8t=? %A#W\-3KLFHUX#Neo>PSS[0mKh)_'9C-[e)<0mjtY5WhtQ6dd4.(hq[`0mjI/W9k\aper%'_9"eD+cgPU$FP:'"1TVg.Fe':%&h0_ %a>+b+(t`]^AdYs+FZ11pROFU't"^3K'W?--?3X*?29mLS>4LN]E#l[O')3HEed%N1+8moP\.O %%$%"\#r]UF0S113T_$cXb9lF*`fa%M)Pm?Cf`Z(RL3ki;i'5@2gjMDB9ZB$oJ.[)Wn2loEM]3GFX!7@m9__)!n=V9+sS'37S)bPe<(?mJIr9MTQVM(*!SlGPO^+G,9-nW %@$`ZiA-?8aP`io[Hg`GY6q/^:N0#=>+bcp9)?!sf7)I[!#hpC"6f"5*)&Y_-;Aedu?TrsfS?9j=#]$ohKuaNG0HpW8bIb-4&Qi=3*uSKJZ#:(fcu-t.kVg,p5*#UpdkmN8hR/GV_ns+<\cn%a^'!&Fh7s:< %B.GaS@:4bLF!kh&$]ORp%bMt0JIr.ueIesk',fa_0ESACH"=i!C;C*4$Y9U)nOiIo[NZr$X@dnO`+7o*,$^[W<(W2aC1)]3\GCr" %UHKYJKho(XFhUt^$0Vfa=g89c4]IsF.q50#A*ElDG=Qk<:J30`HE^ds7FLjpZ3d4=XGu/u;k(QLo[-0O$8?[mqBrQTSJ@Wu@M;dY %_MV'lUJ7,*aVC;\l4!fRt!/^l1u9Xk3aefE?l1HT'h:)dfiV.lLhT-EPjQ'q;F:'38qdhddD/^/o-fMG73X$-_%TlAA=*J5$SJj.Cr=S$6?8 %$nN@XP!_?RWr$s*NdtI'q;F:'38qdItg\=T,kpaX\LUuX/2,LTi(oE`CMr? %@9ePu;+.u=ADoGrNVL`jO`!AWTl(R,DL0UF;5fsqUg"bcgq#\p+7#eB!2b_65BQfBp!f=XXn'lXs.Ae1^FfKS%ghDa=+N7]_)]e, %eHI8ITu&glUNa606UQo;l<Y`7>>5! %H%%fdPs3JNBV`/'GjS-_dl\,qFbg6taY/VUO,u[b'&V;lqX*ce+PFHSZ$f+oGkbrhQj4]#(TP4,cETtUl"fUGSY*TT]@OsSm8N[( %]q35o1UH]9liis8VZHE!pk[E9f_d];8::NOBEI)KBn'M)mD*?,%_2mdT#Zu!]Bu>H^%ilngNS!K!Pjti;W`_@8'Gu7@YRJk %JR$B+/`r5;^fG`HS$$2%^!mIgYkER5R\AgDfYC[/=j]72[:Vj1_-1s$b^_94==`tr2IV_R=DO17@1Uq`S]EYM"6qU:!mBK-fgL%& %^PSU[-0TEcUcQBi*X7r1"H2fjqd9SU8h\6lAjIMEFDl4,K\qBr@UQX,,uS4>l`GAH]SfNq)T7OTmJQ(8TXpD$R`kk0#%`_Z:A/\&VW?0L3A9"=/ZMbWp:WQ!6#ZY2@GP$=8t %MK/YcK3tA!E703W!;M+lR:e7R"m4KM3S3Tqa=P,L-m3A8^u8c#.Do>Vktkc)o&o%\1p:>`SQI'#8)a);jo'V.05XdPQ)7;(OXBh( %kP!ih2kSke3FkLsi<2M"*CiQ<8[T,sr5/+9F@b!V!j4VKef-TM(It#f#rYU,2;q,lKrcWP8PNko?H?m(^C:(\,@*:,dNA":+ma(i:"76B@0$!)9*@4_IX2th-JoHc_e9XQRnS;u_,U7GK4MVR:#/6;>QG4FQ=mcC-,jT9u,?i"KLHNOQfdnE!u@u37*HWJK4GUO,LDnF1/o3(bJXq=.eFZKe5c#<+#(#SkTU7$psJS4>pHja#UXRrt#IpOVt^m+D(#LdDigTXPhh`KO,TlZ1@R.,gTccd>*LC:nLe9 %7O"XPco-!o&OQA'!T!B05C,\dZW;'h(e8r(fgMN4[0aC*0<5Luj^F3$Jr=Ohkl+d+Canm-JU-2_ASdA;cMJf999]m"fM@Og5m4/e %Y*>A.2s8`SH@$\G\,Q;2D[51N-/'35.8U36@\,nN9i9rgeYf94,ig:"a6E-6lPgne`#RZ+aS"n#k3;JL+.ZMH2bNOL$%FJ %bb6IaBEr3fGI!T':lu+Aq&.DM=\kaM)%m-pBSIrm<)aAHI(LBai3rhElpu22!r!pVf$cl7%?]FpLmlVaZBG*=%3C8os*XMH$PY4S.n!.?B'=58m7;b<:bFTMIOZOH>+r>[8@8UW^`5(mC/Z&>\9t9u#p8kamq$*GI6&4/a?*'o9\V1K??`YW$ %Famc#^nEi);1fg;4`(XGpuSS:-WDHlZ;,9s-WKb9Z;,9s-hJ`ii3$YV);7g2a15'nct[4OHs*>f.mbVhqm.*o0W83ZB%g=M*hU?KY?"BuX-Yg#+PQJCD>aL=GJGp9VT_q-lE+gjV/kf*Uej.\"4gI*Z:TM,'CJ0--PaYcuNgg0?Z- %o^/N.g[@*n9VS)"nCj0+CiIVe4!tIAX_&;JY_2qiAeqQB&f3n3@S\NqntPA"grUH1s1rREf4PE*.P7J+G#_*];lCg"*ClTYo]XTQ %*)UgFk]D6`_8e"=:F[:&J-;aBooQ!.+*E:]ms649PQ=P\MLY[Bn1Oj#',hi[^n/&$9?!%tXRIf*C&'TQ1"W\Al@WaHG %0?(,r[oL\Mi<[^2UKTr8T:\m]b:91GNJa][JjQ/a-18'?[sC[pZL[g_;*tA[JOo& %CHrBM/,-e>&$*Tlk_$0nYLM68^Nn`7AaCA`fDONn.D;5)lG*lUY7J*`^oFsJotagUmG]qTY7@pbRoG=#OKIs<6LU!2Ujd5mdCSj8 %s7j;VSSFLJgR=iL/\aCo5HJ@\Q=#N4+'368lE&TJ.JY]1@;>W".JX^DB_fQ1r9[MOFLQ7YVH<=-ig`#VG:T[`SeG/m1Fr89Fo#L_ %Pl,^2@sf%Zb:cZ5%kGDkje#TE2d9aUr'h.U6Y>nthHW[%?9L%aB*DeKVO!iKahIi.j[s6/nXM,ns'%Z=8>Rkj9NX8l9We23G?N5o%PrH-\cYtCoK/WX9CaAZKf)R^F=M3*:NQ59#U_-r %lN2/Sa^c^U_n;U8,a4M_arbLW7]na-:h"FIK\24e![YX8N+k'P5fm:h(/SI9H>R*#%%ma*Q>WWh$;b1\\Dnu&iWCLjfloe0;LfBK %ofsg$J.b^ %:l,mZ"Km3DP*HJ)JU+P?T7a,Oc^1OT*%:XGQsI)cI!21$Nsd_[)L"Vij[Fbm0K+eM>5<=@^o\&[Cu=8i,eo2J&1B8Y8q*YX!eCt\4\qOgMZuc^(.#I_KHDW6junDj&He7GC:L-/$r@"(Kcj*H31pC[ %(Wphj*h^IDk7?(,L]L+%Q:-uJaTIbel`or$804El;8Y7;@XsX:C315aKV/Vpm1)'OJj'QR3oi+o187g6TN@g\LZAJ.5g)N]%`ng; %.$6lE5+j//j4mA!1dRB:aTId#1Ie@\joJ(.gK(Q1/022i4A^XpA2[64=?q_^\qs1;j8hjeQ$2U3ROook-ikSJ1*)Ms-in][VCNGb %:nmGOWMk=[P$](YRplUp'K',o+pKHPY5(Kd-$TJeF[R:D"J\(V#.WGRM2Am#)rP`=,uDEI)W5W<-.pt/oq%b2OU.hKA8,u7U2*.l8(*cYM`&$:["A5mNae^F(B)<%b5Y3@o;&E,= %o(ckL690Q/=Hd6^Dj`l4eY*`d."Ua=)!5%]'f3T#o]BA:5`&;JU-PA>;'e_ki3j0+ehPCX(kE=l=lPfe0`iZ*=,P+H#Qm]Yo9<@- %&p.F=Qu=\\-"`SPXn`amD/[b@kfgLQJJ-$;O(#b6"!r7ETEIBh@[M'g![W:Q^NcD>;.H#40`iYm1m9?Z/OlB9'LOV![hsZ/!u%Rj %hdQ^\!#(E%^;UABTP?TLq%b2O@b!/sk$*d0$$\kV0]-=B9'hBYSbX$G:]gMe%.c&?TZ"Jq[,tSO5RFnrV)7(="A2LO*63GbESQKN/`R90R=Gp/N#5A_)FGfKJ.d5WZe3gJ!_OR;6E7j>/[n4M:u]F4jL'Dn)U!Md&L]qXN/cm0 %lcF],>R^3U5+WChq%b2O!r!O=HjL6YU8U0[+Y?NbW6G6]0n9n#F[KrY`<_^$=,CG$`<_]YRhjHb@f[k[b!U$[`<_\F0$WpL!ojA/ %TLP!3'Gqo?JS>XA8dR(G'!6HB#>-%QMTV,\649$Nlb\c^649"p'6oAmlhKQrZ\pi?KGGt%.mHNr#q\uJW&uLTHtmcN5`)4iCJ)MF %-0S)62r>OD/QTB4&l@8cVj,O0-.2OR,(L:n0?0GY@K@cggC>6@Jf?Cj8dT@RCo>B2V3E[s=\&QcYaZDL8dR(GU;SkF@K]6Vf %_O)u'/f<=HPh<-5&oqu_cTY,s#q]!5T)^&R-m;LmQBW$9>MS1&`K3u,"!oJV5RGZ!fMbCUJJ+a?B2'hK"\Od %M8GNU649$NX3Zo+649"XK8;[eKGGt%.h#o[8ak_APnkcf9R7RS8n`bgFBpk(8n`bg!uYNA.A6o;@'sN@.A6o;'U:&BKGGt5m&,gh %V1]U4Tg]XiJ.b<48LXrL8t&LL,#:f;/Pq%ep<4s3[,YKI&X79k:C!+$q(I2cP-dDSgYNPFPUM-(rPF*uVnQ&8&km[j%gu4nEB/rF %;F9.3=\KR=PS./m`:/Lj9dub>8ea/JWepdKr-:o/JJ-p%n%M&D&!eIA."RhZ4f*fI-iqS>TVeOWPn=+_i&O#C8dR(GimNa)*&/E] %6"c-$V1]U40mHdM4'jKQr66YPi-j]<1J:X:u\#:F2tfr![WTe/@G9h,>\HRR'8RE5bQ'b*to@O*XJ"'X"Q*N4V0#=<.T&W %JO#'sS-s""!0a(Dl6U#a?2#(k##u?uJ4gc9:Zl=ZffpPS./m"=EWTinOWKRFm9_<1LQ(P`37`m`&3l:n2l?`GBu=0lcX* %Gnr_0Lr@6B#6H4.N_^-]!^=<7inPFC`C'_QW#cTgk8jnn(se,53;5\2`*s;aM/s3?m1iW/S9s0GY)&$X&%(2F3PVdXpHYCi\)nJ: %P[J*iW&XN:TYsN5'bfaO#a>mJ?U1-.+AdYE$W1p3JO#&rrPTT:*i4/FO)ki>hQjEjKuCM,![Zb7,V75(&1CCTJT:+/5`(oP,::]! %&1BijMmtb@5bQ%KJR(B7K(aV4EUJBC#u!mC`OQ3T-0TWb^$=4g`46*S-!lTU=.FWq\C]*u#ZEef!$r]b9dC]?-!%= %lpN`DEUNB[Lo>ieE0i@X5`)3BN,oL48edD-mX[V0IMG_"mX.,CDP.,1R=rPi#6H40E[E?_4n,mM/&/SRpHYAS=6%LR-+#po=c\Dr %Et45bJ60=CH4;JNsOG %DM6!>#6H3CHAjN&4V0$XpR%m=pHYC)7?&?1-uksfgi;b55RFGBH/dV7NL^gg:]bjHYW2ABTL;W\`jl?"1)5Zi4tf`QLAf/G`OQ4S %bilWoMfTC38n-pc#k];Q%@#cc7T>n)+AbC,2Zi!o`T2q35<7lt+stSu&1GA^Kr@!*5bQ'V.#Nk&&%q9EIOQ!8:kCQ*U>jr1'd]6p %/Lo%/&1F6Oq>#RS726[&*XJ!t.$'`TpHYCin@9/Gk8jnnT\<:KS9lAT@a=eg`46,]+o[pSDP/8)UTTjg:kIseEH1Dt5`(%:$]9!9 %XO^bq',KaP#aE+c-7mG*&1G@e/l?WVJO#'K^57\fVbj,rLiX(08eb95S9lAT@d9+]RZ`,$1f+h$;%s.tT^"kC,/""\KJ/@%;RO`JdhjEH1FHQj8a<:]ecR@<(^dD'-@cio8_qJJ(Bd)!;s'0.&Bu4V0#Mi@2_N8eb95S9s2]6P;We`46-0p5\qc %J"1lD/Zu=UPfu9AciPMN.PT.2&CsZWJT:+/5RI-'(DZ*S#a?1)W1Z-E5bJ7-XbFa)#6H3/a>iq0@1/[DM2H?b"A7%`:M7C!C^jHl %4]L=9qMibRGdVbB8Y7h\?^"&kZTd.4ml!Yum@IXq7WmMX=sBG/4saffSbY\EAYuH*M1thf8`A^tXMt^U"G/1^8dVi>/Z4*mY)dA. %ESWpI[e`:u+Op3&$@!0hGNGt.ntS*!Mgs(2_&C)A9/!C%XjirF7_Pj=F+f%LE];50[^Pbq)c4Tnha8@Fb%e]gP,XZ941qDA8T/9@ %Q+=*KS[C=;D3Moc4`,OZV4!t]A1+$/7-FFsT/DMEWKXpm$tHI&RIPd/Qa\(#)I/f+V-qeBIp8B1?0sgVTrCOXV)`'s84/#hoa1?c.-7Rqm1^h.?0Mq4HU&3[VbL,O90YFr#q[B4#jlAjFW %r>b_;S1@@6NM=Q_ON?*uB%P1hg3B$IEhkUD]h1VQ1/JHuB\0Sk=]kLu&>ZL"XjBh7DMsV1BJ>#+oC# %c``\C?e.dh<,kukerl#XF@2]#epI7A"go[q'pt$HbHlo``dPBO>@&eWlee+u6F(V5?YVIJYiKEe[njInpp,d,3Ib,%c_EYdY)$E[ %i@BDepOr8=cfZjjI27Sjd.\kk_$sf!&cI`Fen"LeI2]mE3^g]]G>IA4pi#_=gKFbdX)E*^^6`Uh+[Ng6lZsHI?3+m`=77+(p!2hO %B`QPe0.s+WYQ9E'9NXu"?ip[l+W=:1P8!gr*5TGOUt]7Yo['VM;05U:G5LmMRflnR(*E5@;.@5c]%C7fge6qq:[=?:^WdLqoXs%^ %jS).2Q_W7=IICfk$0=m`qhS;PpJ7oO:>=>1r!?YmUsBMB7Yf[JlKO=+;-).mPn.,!VlO"%P-1,JcP?uVjoH3=mk_6$:ur_<*sNoM %;oGsGHA5=c7DRF0lj75<g.sAC$[<";f]peDmS@9"qM).RieP&`Y.Yk7BA[sPm8GHU>MpL(_-Rcpm9T>l!W($Bq4FiKr!"2//. %0@=j'?EuY=d<5rXb"_H*)[O:=2&Y>+5Eia0+[/IDg7-3l,?TW-He0dI\mq[dHo&*$0q;8=V&D$7-q.`3)Wu9aG\>Rb(oNgMkARPm %m>1&,OjYa6)hn[]_)?8p%X:hl^rcVS:`al6bG&2sM+coM%_#rR):$:m%8-#h8-97LA*^2H#dSr6f7(N %m&'H6hXM@bLY#F9C,so*6?1aa=e(QK(Me"&kaq`L7)eu3U\?7A'l_]B>Xh5qe'TfY&g^N@<:mu?KXNBc(u7!P*t0ah`9h%6lngRC %DcFKM:4ApaC^V!Wh^9.%Fcp[:miCki.V4+;OSm`O)O*\?6WMO3=s\-V6)fC&;XSj*a:Vdjl_hX"qcQ#YNN\d:-0S@`ld3D20*gu* %AQ5=E0UPkYLP=#nTFGP'7F[ilg).(M=GZgsen_=2IJec/7/c0pqs>VUWfur^hI!?-\,Og'kWCDe^R7b9p]jPJg]G5uaITZH/Mc/= %BYU'B^RGZ?bT,u7#Se:3#7_ip(0!29FobY20!N_m\ZIN:$iQ!^Ig_th$Qi:M# %SVK]k"(G\XHBd4bps?eHM2^7)M9>$0),*6HLZCJ&X@I/"4W&Gg$m';]!J][;`@fYl&Mo^qsN?GC6gfNMl8FXT#FqC %e#UptX*u$?D#f$0O6_a:\X,DAhR0O*G54:3CoIjArq).T/D&4#Mbs[qDBI*eh41YikA=u,!oa7?a2X]3FQr+.@ahMiF/VW7G[>j,183],FebR8;l%L[e58L4l+pBn+`+:aDm;B-IV %YI,Ib#B^u:*&8!fFh@JZ"`T=dUHL4/rktfVBfP[aF*Sc`Y$9PAtRs&iWb9!0'TVTuX(/.[Lqj'(pm->QnPL!U:X5']H %:2C#Nb6I$MY[qjX=Si`\B"f3_>@7R+18gVPG.(@Ei1%_m"]"PjA)dCV_K$p*0N?loj-N&_YZDZJ:@J"68k/ATVK5cg,W@Z5#5=uT %JOP?ol0/>j8[F+]C29Y">>A8Jol"+>7&l+[Y1n!.;:0mO"pj%47qIW]'ik3!5?gJ+]X;2N=Nfp[:VPV3`&ucE>FG7aWIW3=['cJ0 %2h53U5\I-n0-lR%iGGa_h:I?53Z77^>t_"$W!.FbLfH7Cinb[,G`HGZcd;`E-`#,khOgQ4)%JPgl+l1iVu`uB$a#KGlMHgg6e*TQ/$+TKkVr4p]X5fD[9I(nn\s&sF'+$<(mk9ikM1h5Zj\$>6HYo#qln@aXkZSo03r57"PDBhG>tpM1eBtW:H=4jEROPTG1u^i?],$8#A,far6?l9lm%IU7$jK6%u47(,M*B'%*buAL:Gl %R>K3L^H?*P!R]9EQc;]Em3q=1ZC$K%Q`,^VLAY8L8S3Y=ac`$JV!UH\9H#^L>Ut2_8Ra"Z?6\IFLh7tt+6JOnC%Dr<)3Mm3,eV'g %r(7RF7)H*Ijm`Xh-5'W/el[3bM>`_WAtn%T>8B#Wn.L]eM&^+O3QL9X]-b7/SO`bf&AADLn:F36b?b_+Z,Y'\\\G0bXjH&[FE-0b_Zb)m:rYR#(s3_DtY[R#-K_ %LouXmAg6Ju@O/4uAgS-sU8%34'=H]=YA,19Omj!Wk*O%\,eQN6+u>AN&lCe=NL<AN&co>#`CqOo %%ktS+0b[-.#2-DiR#1i

Sbt0Ji76MXmu*'+$>>FO-8i9I/FJ.-tJ! %'+$<(=?!OQM1h3$.uZ#kU43N#BP&II,m%"6(,JhE$:E@W$=tOs?6WoEa^QS0?6\*1JshIlY7(ptOmj"";ahHXOmiu<(JYT!Omiu, %?VD4kOYhTG.Z]ug)F0(uSO@1\a\S5>9I.8=R.X#[QbpC'\AtD"94;_3U.Po^_V%[rd^Ql..GTb`3cSlm;P$!78`C#1*3*OJL;2c/@PrW'N;1qU$O(L2'AVEcc.\?$J-7`>Y-NAeO,]G7MI$FB_^T.Dj)$6KfU>KRA@139NBLJ-T>.EmU0 %)(pWis@Mn'.Bc1\:n?_1LF'P]FjcAmn#Re;%%hp"C1mj_-VB&-kFC?tVd]p/3' %dq!NDZ$"gE-F/uJ)TUqu`mrg48"+52k5Cd0L-?`Rn/4Y9kh5&Qr&lSlR>B^L0'`Y;P8R1<]3U.]O4lY;^/Jkf0; %#"*:j'9bB&4.FuWD017&C[:>qH]RH449I$MD4QVM54m1E7-=DZ(]AE'S4NAJi81^%!2qZ1foJ'l?SnIc?-;F4S %'KhfO$co1b\0-6]X8=R1JHpZ2e`CV`/E@"B*7Ba"K1?XS=\(ksKRelA3/D:$f\KLHEU`6]pCIQaD%P&Q0uUmWc[&+0Q>p24ZaOQ1 %Z5BoUcJ#!eg+o[JP-pR8bhDWfUNIt$7YTp`C&&juo),sn*qn*cE&U8Mpr'HZrOUr1*c0W]XmjOddi6FoFc-5gr[#fDQG^MDQ4(I) %MFreE(if_K\n-Cu-\W;\XQN]b>OYe>m&.kf05K1Pr=)nh8$./em1j5]At@I1WfLckI)A!?o)rs#KC7YJI;GWd9QrVR$:AmT46*d= %$H![ijW;M+[DCO)7o,*WI56O9[62HC`QYMT9)[j](45ZFkFZQf#fBFE8SEu6i%5M][g!Ef4[F;s\9NJN"/ %2o$+Y[=H!glShk#>-7PM>,P3OXlE&`c'+]e++)$XFpC\;a(W6%?\B*FePEs7l_FQ7Ic&f[L9$H:qY^:p?V`NqQDW2'^($`T4E/hY %39##^(b38:mL9ur'aqorFK5ABHKABu)F2N"FLH]t)F/CMgasXM"%](U[pu-Fb"SUan^36Va%UT$WQAWs&mh<,`b-Wm]AuJ7JsdH= %JJZ-r,eQNe?)01g#qs\*5Y,<1rqGuGfpR["N.]DB(,M(pQj*e%%Ps7>Co6C"'P='F:]"g;,2jib)3`$5bhl`LW_NdK.Ek1]!kU:$ %,'B1\(GjI&>TCaWK]sX)1Qe=1n5RP>-5,g+B]$`a'?NIr6tRXBCNqXhl0a%T4'?NoZWc;1c7)DU8r%XV:q3[KS0$Wr\o.=:CU<6sm&mf#U %H6) %12bGo'?NbN>ao7X'+$<(p(plU7+*obl9[Hdn`rl,W\"B0'+#:]IMU&VJ;Qa,,!!^%%jTWMhM^qqZj$Y6V^uF(i?_[!>r%e(KU8X9 %nsG8eQY8K7EgV]ZcS8E%;OE=@^#WW&eH-? %;e.TraU`3SAe&G4pI4=G>A4#;"EFliRRram1,lZREia6O$)9IP-Zi];FDnSL!d-cE/HOGmJ3'&$m=o`ff,=MPBZ](S/Z,ni>$ %%WmVIbtTD`r+)deh4@3[F6:)Leu2f4\H(n`9Hudnm[gqJ %r1*RlmW'C6D:`."HA@$r_6bg"`Z;O6\]kF1C3M)iLuGQqUYSo(868h?-U&t#cnD7^_N;C2R?_t'G$h.D*4DsQ2hHW*J1s34HI#'8uZSg+uh_-Pg=Br^\H_O#Ro'h=:n43pk^t![YW*M>$AbTam %>l'CKbCE:WDeX_qF9bT3tr&7;=`3dk_AO"gO4JLskS;t#$6Zrpp!a!A*RbuFqSF),]cJlkC'&M^!d&FZD4jDZ, %@CjFGneUt@('i/E4;j!%#GIi`5J9""!*"?a>B/e_?#1Mr/J9g-9qm;a5Y`*0ENO)N]_0r+;QC$YNT=]!%!0b\tBZb5`(?3 %KpDN:J.bK0O8eb:L`&J_b %!QTgHY6$FD$+fu,?3Oeg&k*9(.M)]Hn7m74J.`Wh;LG-*;*@a4'VGRl05d^V$;f`LNs-Ijg#F(>5,oX$u#>1k`NMQV$Afbr!D7;h3Xa%QersT;'gb8M"TTj%VrY$1&He8JD\&ahScU<;]_B&QTS,7hM%1qb]Hek(;NLsE %TH6*m;^)DoiGm2@#>3@DKPF,t!%$R!(T&Vn"-aX;oO(CM(n_#F8uSUT$rB9eH05B(^tJMD=-_1:RMI;+&u?iOW]>VCh!^#39#L]U %3%ZXK;^)Do0rg.>9o0^["O:,:VF1hh&u\89$C!Mti$7$jG^pES?,GF2qDE/``6duXCJ)MF-%I3rffR6CAYL)tc/.+UPe\?E*]VjV %2rHAaM3s1RlGR0OAApUMd#1JgepDo[,E7i>e_uM+Qm"]:I_uM+IcqC&!>G8Bi5>;8K2a6DtfR8S$j[K8*`37A[Mogd"FR:Ius2!nE!, %P@6\K`#hVb%?r8U/FtG_TELdF68TuW0gLSP@K]<=ff4`^(*cWWqb%@h/OlC$M.aQA#aC_L(p3TL,>`u[_t<(q %N'I^#MM>e:_uM+'/f$Cu1G2L5qiB-mD_V;>BWmA)^;UAB-u(=)/OlB9/*uKE[hsZ/=uA>_:kG1qB[^i1>VKB!(pXjbas8T$^>&&:3uL`7\BmqU_r5uN'N6m %]MP&80`iX2('0Ej(*cWWf7c!^P6*.0e0m.MKVAV#j;@#`N'Ks2bqBh\!G5CAo.B!D4>Q988ZD)^lT4L+BqYWc(i7`b')#g,nMo:R\htaeZ1ETC&E>ZJ-4e[sNGcg'Y)Y4saffSbY[ZIU#Gqgj`!)+*V?T$CE+N %AAQQTr%JN6Er("KqRD8!f,]&XjTna?g4]U""lc%CA+)a$B%HRC7O2R4l"\_[au2aZG1YP(\(fWZ^Mc@TB7(5,Qn,69mRsGFj=,)j %oXt9Xn>o=s8,&VK:f.<67.Y=4ME:iV"6_LGjg.F53-A-NT>-=i+Z!W,p%%eY?%\%kZl"bUkc[YN]rTu0.^\kik+ptooY_b'jQ9M. %hjoPkd/dsH>Qrq.\s&Jq[V'L`VoMk7m?cg+0sB\N5"j)6NaKAMYG5Xk@7+#q&J&F5:6sCBSj0i>kIl(@0,E-PDZg7q`p1lDANb/=-E:/>hG*h/-NX6J %B#Zc"0ZE8L'+'nRFQcd([ZX*N+,L#P;.Bm7=^p?(a)&!VgD)og/i'uR^Zghg8bGs)5SD*oPE3:C]2Fa^J*!D+gD'Ng]%Y@)D\V]lJQJ*17 %4#mQZ_2mN"@1?O)h%kOS\mdBuo4WV&VO\lc1"pW.^L\r!WV0nI17.-N#jn(gjQ:h*.dJ@ZZ4(n;Y!*oKEK&Z7.!;lHqRQOrCrB9P %@k5dOUhN(!*b`i:okLT.Cdjb=gr=rAuf686/LD915 %p?=I??WQ\MkO6RbH*lbi(""NRrQaoiDrfM3X/D[2 %5g.WJc$c"g!E<#>pLUB+4?9[=`=WMP::gDS8e8&7)b'5VC:?E7]Lec]A+>]"[CWrfc_&dlN..6H>3U=G=ip,lg+Pt(NMuakT-(Ja %Rp,Ou6K@CqZu,aqEd4.=UsBMB7Yf[JlKO=+;-).mPn0Xg[bA=!`8%k[5"d)J^">tgc>V'eP;uu=5FOZb?^ecs?23Y[eFrjtf%T6G %>[jk+HaNQX2\2i"I%Q7\?s)9*r*c71Ar;`%5S%3OZNssoRiQHO`T&^Y/E2B8i*,T&bOQF\_]"5&(fgC1SLG`TJ-qtn]mnOu#(K?eZ-c4?CSjn3I0GD*B, %oK&%//%P(]FRX/6aDO[2?=.soM_dm@K2s%c36n1gH9#bfbSALT(W[K-ZJpaIS;93]T%eX-p*ZbU0EqUWHX^]d?4Md]VHCY?QbH0UcpJ[bJ$YV5KBm$.,!^ %JJ_MncF0nDi)fV\bA.>LFm+d@ccHd/_GK%X#(uA!s$Ba'maP7b[LX/HDYCf$qSDn-qS1W>e6/<6'NR=U*HZ[*>s+I(bk$Bh_<)j< %r+3MJ&/@5Thn#h3^J@Itc\'!2UYf9[2HiTBb9^gOTS3170"U)TrT*2;*j=2eCX645rU``7$L.?&NYoCgX.np#df>?q@;b1Fa%&2) %U]84P?b38F9'L*$s,9#@S7P(F\hQ*\0]?las8?ZHDUk*FGFcW$"oK)@I\C&+#6('%7MP?Y$%?:m+pau\nB9d+*@.e1EHJ$-I*iFh'(!!;[Qo3akZ:lXpKlOL>\Hp9L9d<='M %Y2n3KD@4C=FB\4u(&N95^(#G2mc[*o_)*=B>2CNc\fmkBX4-%lErrc"U>d56T7b^*b"g!Tcfmn5-&n-q!B(MMnKg+)[Qu9`^rPaK %lYc]c]KX@'#(;g$L`l-R`k;/!rJd34#'[6orCqN\j7#n7hmrW&=SRK?aq+f?fI;tE<&4n?amfq7(3"-tlYhGu2huX]Ur'QbO=b[n %eBDf6^ZZ\VTp9jS`P8q8[lmKTLh^t?>9(DjUk^-DcGps==*^pX/gEQd#/&L60+JW)6ci8K,o3+;U+a&,$n\X[m:-+^1c6Fp<55A, %I\M1*WsP=q78KK8>NgFS4/bX%?S*NfG)+FIJ4pFF;cT4R&dfqYdBCMMU>PL"/=W!oqWT]aIb#!Yj6L<=a*ZA1\s=dP%cD9JW'KTT %nmW1Q(Adt1=L/e9e8)%C3JrRV9Rk`AD&'78TK]+"4]l4AW!`DtBhR3]^BqtWIErBls %'EMhV(jEH^Y.:kHY\JB%Fm^$_n#0E,+*B3-]0DumHgbN<$Utr^].%B!]Ba7M41o>gF@dY-*.Ws]3aOC>g3`E@&9HEnOF4@JK?"G( %48!?XOKd[b)u%DJQO&-Xpra3(IS2mP]b.Yl6[`N%O,gpOf"(%ZCpfW(nJl.hoOF;F/.FA\97O7"cGUsig+3Y-O-9C==\/KH(kk18 %XWNoUf.;F>4iC$(FT#YI+p\?Tp.1$tmhu)1rS3rj5_]0"C6C5T:_"b!`r^=peXA^bcVm(rB-DiIB@6KLYH84hrQ30ab>Q0iA>1+J %pPZ!?RG.hD`;K2Xf%Fp75!/duT=a+6f#d^I6iXe%Ui7.KF+'QLp@hT$afUaQ36.,K6=?EP@]9KK?iqu^j0/H-B"r.W#0st^[QnTb %CY'+umVfqJFotnh!PO+Vr5G]RU?:=#.h$%IM;d;/4bS17jF1G1\9D8'$G=?HH_jMh163K[r2Hq02>,D6bpT$[tVLbn(mt)2r->kkVW=L#dsmDZ+Ec0`_#(`dXO3qP9=u2APP1*m;/bj^pf=%m%9XcaHcbZ %<9Q/6Ip#Lbm;G8\O';AUg8cg5DW>$hos3K!T5RgMX6'^&;$Ypn=8LQsd3q.c!sCMl/F<,CmCi6ro\r2WgHU-)"E1o]'q:P3GP6]- %Mc!p+EtL"sP>P#bBQBIPCq4+nX`XuYh)[`Nf$r82n[HPD`U7,JrtoUNpP\N!q[UB!j7^Z5DkV6YR67t8BR%dOYa9^,C%aff[PCkS %gMTB4YJL<(T&nMEGXUp_RDLAD=n!:]4&[^@F@gY>dsCA?$E\rS:XaET5b2opEDV/?bB4k,O0@rF`+a>p7M5?-W+lj&a6;3+s4"2f %'<@pOHbh:1dH7R*'XfS4&(ql)9[#MN_=T!b%[SQAQ5s.N?5VK.kMH80`W_a\5/1t%r2s=Lf2@Ag#O5\+_igkah:s^AqY?dKI8A)#n(o@&]>Xi!q3kD6jaJK;:K!&E1cRT:2Ui^u %BQ/Kue3,WJ]Smc/B8JH)r0Ao44r4ZGnDFn^GhqfG*g93K_\f90dQANYF>fo&?aidgrD)\UdWf_j=[LIK)![/pH$$APjJ>)JjC`VC %d%&>+L\p*L]9qiELXf29Ko9umo3@)B$qO75g7fHc\WbqBig)Z#h(]=Y-VqXVW/N<0Ts6Nt#KiT"Vp1@H7,)a!'kYX[ol.I*8*jc5 %Fc)GG`Tpl5j\D,ol"N.MRt.sAog/"cH)HYd,Pg)pAe>cb2hOG,Is9opaQ!+.n])WtNtD:-GHqcSB-A["(5n^l:O>+D69GTmhFoQL %a[/D^"M(8VEi1\#grTX)iU2t*mPH_&aup4q9cFNLmc"t1>8@Qi$9t_`GbAA/^Z[P$B`6WMGrdY-J&+9kFnMnCB57[XAY_t$hZSbU %1?o1SolU/rm9B$;"7g7$d$ZPHFbj2]i%[Fk!k'c6D4B9^VejE*Tej,SMc>h %")l`^eEm,fY\U!sU>PLV*QY-olP5/lguHf\)Gn8:oBVZEFA6])a3_/,q6d8,9tRudde%V1=QCOh[9B9S4Zj)t\,Cf=Oa7ifBSt?H %5rJsRf>c:GH.]RtoX96PQfLYSK/l.0]e(#1NT=0\Upn;e[fI/*M;B#+g]e+'-@/lIEgt66SIt=I-F\Q\#nt!((:amP!3ji)!m#5* %Mgj_Fa7Bq)hA2%)B!OJZa`uU"DHS_9>[rua-\L:,TV]-:,.B"A`&f#\)trY20Ac5h@tShK>eIu6CE6cpj(Z2sb"%$B*=o[i\g6E` %.lFl^o]_?2Di4de3)X>JdG&,Q1?_Kq2f=Es[n0tMqN0J,P)F%rD%?;pGkAFHj>QYsZdIN:OkVS4_g4^cEgrdYdbA5ngRoTtU:8)c %[i&s:"2-9%\P5p=l#!]HD8@]k#^RFQ\P<+()86IF7!eE6PfU"mNYC)H6%rM:,K^iAs/eA5aUWgB[S;iY!J1r-1MW#ZdC?r'LZlk=%b4D-m_I"R?0^IHU %8ecc62QJ7=#XUD->j0-sRih`X_<9IB.`d3JM"4CioR_W1/!EUEoRbg&7?n:p"KFJ868'1#6"c,dH?j"R?LUf+Q)S2+0BO=:[VGZX %`qp)HJPqU>^"A@0*'N0o[iRq,J$6\6BO0:RqIYH.Kp.r(?pD[IFm=E-fVWPOLVa,3e8]Jpe139,nr9euR7AFqh&k\lUr?',uQHC.'VkVF?H3$;A`gV;oM<9UbKY6/@qYP %0FI/U0n9s!(o;:kNU-Ngc)#U\3EQ5-KFQSQ55GY.fB9RO_'L_-MS&/PC:u%L*(+Y:gub9e[bS6#i.qDKg:`](_Vo3h0>H3X2%+/n\.flXVtC`l;U%j,s-MR1RlYEkM^1Ej/dXZ4)!O>F;sJe\G(">][P)Q;HoD@c70tZ?=;H3:\mb2-!mOmnYhh^N7'NIiXC3\/V`l&$kXbMHlYj[?ZXUb'ebOI1<49fY99bqKkk+B!f$>pGYX5Re5R#d*F %=q+82`JUAQXOX)H5qCsSG]cVf^c@QYD=7t[XOZg](7;mqaBB$kgnllC %,.fa'f';^8FPCUhE@@h7CXq#$X?lGdV!+J0]p=;j/R`VWh"e!X(!MBL>WF$bVif."-m\OoX86)g[VQ*:SA1"abco[JO"^J0\t;L# %5j\ZhW^TSf-PSVK>-_AUog1*LNfY3%-[T0GYPhg3&Ep`L=_Y<&#\ADcE`;+s+tZ=%D+jh35%FSXf)hd39!IEb5\Ub3a8@Nm"WC\d.u\H=1llbt^+TEIBo-YDDDRE( %=_bh?rrah-UVr\2OA$pdL?GfMe\'T=3JM9^Ko)983\B3KPl#\iMm)&o>OH"fPnATiDRg:lqGDj:fQ&([8VJT58$;t#c:&8UcAu1" %eK[RhrFf7iE&cne%J=jD>Hc6cM5qPrA"96d;m'k6Sd`f(@n!P6T7!?;qt2b(VbaMl;$:>6_:?;?ok@Ai %4OlZ,ElB!WZY4es/%CuaN$O0;9(g)sq(^H2)V#@ZjsO?Sj\C&/e,0>.;>@)=!]<3H0W2c$HGJi9Cr;tVZgWPEg7[=N@#]a+$O8(C %?k$9kAPhaANDr[%]8`_KhEH;k-OP?\hVf4(0\81h>D-aC$m,J!(P%tiFJ!cs %/O]gfKdroGLusMBa2S6(YtHN\#6_A,A8[\V@T%=8?IUWqB_UtY/V %pYS_B3IGsK3#J!F>4U"i;E0^ibbpe/-U^p#L>OtG:<;JZjmN^#r`MYb6Q=l&?AE4Arm6Pfk7B5r++!(l1Zt\,0;*,A**K&&MN\p( %RC`59Yn33.Tj:?p=9rC>B]W=17l>R$+l!b]C7n;n<$fV'&rkB%7+JDj-IJud7(5m4g1_25du<4iKUP+eGDQY.,B8MlF-7P'be4_Q8`*X`)>*+gr\TX6E*dEb=u;o0#Ls$uPpJ:(4L[b^BTj"D0V %C_\>(TJ&*X6Lo-)JaTGP.U$dTI\7bkZ@Pmtcm/gOM>YF^YZi)L*^"ledd&-1AXOuq'aXB(W:9M<5ce`>/LRBOFPmc0Ne_n.;'s`F %ebrg\cn7M"9L1hToelC:N'"beQ;&/oj:K62o@E_(T6WZL@0]on-P_:b%kR?6D-55WG(=Hm"A29:MK4jgj,$E[u9[&Ks.<(O> %!CVQ(I-,fer%t2C2\YFo@&GA-WFjUIF>E#m)aBp4,SoftDl8(L28@VTT:\mZ)eW*/n9`pYYZ^Mo+ %\lD4bmc_6jn,CS.ApO!Yf_V"]T!\fPVT.i?&\:P2'7,_+k[qAl46YP/Y8VR]4bTm)$L3J#.S\92rnOD:Q,jr"b!qC'<$>TSjgW,HXSq&Vbda6d]>;Kf:a]OJ(N`CdZ3"1U;:H9WD*I`0D,+l0Ve=9Yu%gi&G)OUenPe"1Z$ %*U._OiJr"LhJ9VY@]1MWlB[#qk=>S]V:/:8BY>f)".bI(9P:tPS:4El9)NJT=6C>Pn'r^V_:u8hUSnMRU(>u>X&)\n>GJ!F;ccs&_R!fn2J9Q2#+n)-'-(;P<*fGQrf]]g?Joa.3M4?6FM(]a@:'.4nCm;0fHCBj3&3,F(.`PSVrhaXkZhVmOM\ %GcIu\T@+offLq2aqioK0+_LEs/cTbC(G8JV.4n'9p9kECl"TV0IbCX+*'M2XS2L2.(=[pr%"%[s9.j$-We:O-]4o:HZe?YZo[d6rHjO6q)1c"rmp9locCK[u>BlA!@p)n5G %.;eW)]#Qe9:MH"gEI''Tp*jkL.I<>dfr)4!Vi&W\I7h]"F#^W_A=q;Un5,1iOaTh0>G8+DOaTh0>@CTSk3Q%#jAS1KB$NT:7@t9Z %-i9,dq%S1T0k[-,\ogA4-@>G8X]m`1.QOe1C#-@caO;':=7KeCOh%;:%lh>b;uGtiomlWi5d9fch:\]Pqad2c?#pi*Qk_/^p*m+T %2fM8ud]Eo_32eH3ZVOqpBJ$jDR`pnB8o*+^W+):SW)>AS$7l%I,t4*^fg*RDq!&6+ILGmu;n0,/Be?seX)L/879Odi-K`7Pln6'3 %cQ^)3#u1;VRsdnuTS<)3ED]'MBj"-_VmORDJ;^[FT@,'Y)W$+Jfr)4!VpN2_B:mU!T>JasSpa4HO$Gh>=L(_:m1E_rB$WZ;2=re) %AluB8Baqb8)MU-He<>9[/MqrXr/simI3hhc.;eW)>%'Cr:MH"gXkJpiqimDRVPlW1VmKJ1J69'hT@-md-n8$d.;eW)lM(L)/Rcc! %L7])op*hT>$rgpFdql'(5Pp\2B83EMNpK\J(Bj5-&F7[(kCR)H(Y\6)S3C$/hMUcRJEnrPlr.)f(9/rHZ;52\Z'`c3-qMEu#nX(X %$CQl0AtRM_+P=(J;t_ZB$Nf&VH"A?;/dR3@/Sk&/D=XZgB>L$b8t14.W'&b2[(!`(UF<-Nn['g()Dh7Is->"bVmORD8otPT8G4KL %nu8ASA=q9sT3Ae"CtY_naeq$AJgpS]QM4se0XG>_ddk-=HAj1H%eAfa.ASEaJu5p^id;6a[`\]_PGS'p %KRXb74pQ`K#0ng+Hk$Du9MspI*4RtcdX2O\b5laHbi!P->Rp79OlUSV?_e1$k#=X5U1VSi-m/+)9%L=5:oIo3P%UqMQ0_l]M%bgR>Q/ZjMg(e_LV"kuAQ\/\bO@W*)U<<'f %+>*nVf.K1ocU!:01)8sLZ@!.<.fgd*Z@!/'nVk+^3Bd\djhP-AV"bo@QNII_;7OpQEB16DW$M-XO?no$b4@V9F>8aF`:Z-Xm1rXi %cc#H4W'@I4ZGl/J3#_.6mD1cUhJ+^^jT*iQl-+Djk[m3KF'p>r2IHI5pJ)7F`+WUF=jLtmD8I3)IDoE^-R6$>pG08![fGc[Yfn#4 %)nO*h^POaE9:r.%g$KP+;SimUG4b:g@Cq57h5p5j?FF&dfBoKpW<+!Tm1)0)'7a#B %(HQcJLM\/gFq#?Z!5F^9B`]&,KC*jH,R2]HI=YNCN__Npe;:^fX1Q!7qtn]m>Ku0qku)`4k``%`$g?h%I^)2D6A*KfCq?P9][<[L %0"drHCGJ[]f;lQ-.@f_^ZS;&o0X\%2ML9A`Z%/Du]\Dp&I^8Zh@3+0K&C"/EWabSc\]:-;Y`PrVSC[_lB4tO#JQR0XZ %=\Ctt%196*iG)b9Vpa_)k3k?h&=!$hK[r4j[9.Zhb@YWAl4sbe4]TNPS"^8h0Qh=saEo[A\IqjniX38\__Y8?&l8,QebB\5 %G$d=6g&tEG0ZA9)q?0eh@`A$I=/3'MENhOCj@6m.'dFhVpg_,XWgGYUUNijA,!b#& %1/u4QSR@M2XS*=hlb]O=,>8uAC[:u-U/9Me0M-#R),OJ$@D@o8)\]EtU2jU'+,'pG;jW)=m-*eBEl\.^D*nd'nB %2+P#ALatbk;58,XrWH4iAMdg'2s#3eEgHg3npja-qO?\l`gVtp2WaX7EZ6!CiMPBOs#@n4Nn0GAgD7\*8%iBe&,$fb;6Q932lt+6 %9Y!;u%Z2aTPhT]iD6Z03R;urc#DaXGG]cF6='=l+0@c:H&jD`A]ammJdo.cQ]t0\XV>Bjl&#jKH70YeeOAc-9S#dGrcUNhi@TXkgGEu6K!u#4 %lE=UP@W.r!bWQHU%;kT@7_P0Ik\QOVKuEL63/Xo6s!t59h:D_.H;c9^]6G@^h.CgVR()9CU>PJ@9CbT8X\@,mF\r.TkD %a]c1#qUf(BfB%69pM`&ue%=497;]8QhZ2GIX3fMVh8&uIJ)ICnUH>4hpC3W-BQRn2P^ERGrJg6l!YARjQ%:s1M6^dmKin%X`Z`5T %45EkS!hh1;]MLYQo0?H9)@0r[5[!ih\f[/*l_EZpZC\g@6!;Q;cm:2fhInGgbL!rn %qu58FFE$u*Y_?"&15U_P1Ko$+IR4A]TQ\H0rlF_?5DWA')B^@<&@42M+(-u>o5U]8KnuA3>Gu[p1 %rGJePVfTBEPk(jNpMp^#5"cVRp"CqEb,b%%!3oum,/(Vr`)THl.\$@ge5N^B4oA3Pj]/ek7*iSPGnk2sd<-$LYAUCX/t5+i$_&a2uQr#`L)ghk_u3+1CFO?$Us/7Z_.VB1?OmM%8q:eP>PUR6oT)j2]:F%V>23SE"chN77B.Tl`Q1Z59d\\7sC5Z %V7Ud?Q,1jBgqc_CFV>YK`!os"1so%A_+j$<%@:'KJWGb-iXTj`j3c->j'X1o$?PJ'[E-?]'q%rSSdIAfE"b^uU8".*]YRsm9Sd5li$OhN7n,FW#<+(]78k;ZpME"d>@OjQnY_+j-P`R\V> %=(S(2/@I/]IW1LF;FEH`#<+(]V'LsL\-[Ko6q'%S#<0J6)&_8K*S_@q76iGAU-O>R08WQ['I1*omE!]&:#*QZcm;+M2fT']RS/S@>U0KiG;W+Jt(+M(*25L*S`JW %o7mN%0a9S1RQijEM*&5h@+n+=2fT']=^8J`kU,`U-;uK5*o4aTgk<#^W,f8oIhb>#'gmHc6iVWaL!*9nA:-2Q,A[;Ntl9)@ghngp63S=o,i$GA-2_M6N#\j:JhBL0t_DZMX7Pe>YbG8;?Ft_F,h!oIb]C6&?a', %qJf$O`^TZBq[$cjfb`tpmH;J0_GOk9j7[QS<`IIqgjX.r0]s8<`uXN:0@Gp9n$_sh$OUQL4RJ"MglL3NpZ:<_#kI#QF3j"Aj7[QS %#1ec95Ai^BQRdhmL`a)JmgDo+K_f]cn\,E*>biINh_57UY(ZXkqmg^!;er`^[qT-0r'M,Gla8UK5?C/NE]h+*ID"i0k:[>!?NRQE %$2Y':(J.c8,Y;%!QmGBd/4GP\-%#O*.)0btR0_-%,tYCU8!]Ge9;ld-(R(.299NhFIQpl!ltq-3#nj(eZ=J:B3aJ)1>G+];a2d.c)"*-N^N`$rRT$IFjaR7U+iL>@USURP,.6[t>[PEqg %3BdZN[K8W$GDtnAic-qoKmI9D4pPuFSTpcZ\e3A$_cDk&/g3^8"'_0LV.nQhQLu**9Aroo0XhaY]+f-_B@P&>&YEM>#RI]=_hK>]aD/J*) %c=/q#iO9>8jqNZB6.4!9?HhLdNqVFVm2SPN(TQMRFCh-EK.)2M3AT0G]Q+Mc.&jX"#`]//)E3)4sXE-DLKJa]*bVCg16e4np!7b)_1gDlu"D(R&GMLefW %+[$kE;sClF%kF=1l>,#)g(GQ[>5Z-$'s?(*Zt<=nMhSWCpj(iD`P"J@XLG%(DDjFmp^ei=H\H!Q=N'MPk[0@qqLs)FMjD]&S%FE/SS;H]tSZ4J+&<5JObBp>[2lu):MGC\[Vct %;cJ%Q\7F]Rl):[g>_9jr\Snjc\/#R`*Xb%#,_#TBB+3-)3Z0dVSXHXeiSYS4F9Zg08FVRnSqtLF2D->7SnP0?_rurrioB1sY^Z2E %e#]W6De&a>1&2*<&c*(X?1h;VV(n4]W!*ePZ/YioV6Q$;j6HWeGi1;NTWjOYQ5Y6/'P/KicGjl$[t!9AI,'qP"E^N1jQk/^01]aiDjc2g^X`"o*#@#AIrBrt*35l!o?"^&Ue47RIJL/P'_-_.Y6jW"anF8+FK/.,j*G %cr`mo)G1R4&rT*"8"[0uTEc<+]^)@ra.7o4_IF_Ed>>ODZigF";&B"s,?H6VV9gF;h^;b6jTF[`-N1^?m.Rj\\bQqDprcMK_bke6/bh2,'Q"WENAELs'Q'/1E]7/9D&-=SUIERB);H9Aq*b=$epl;`,JJ4@lscKE(.F^hW8*A5>[gkmD=rON-<7=%<^OU0.>gklWc)FD6'U9H/k:u@F %.(K(Hq``&r;elUSeZY.q^)=qCt#(7P>5"2jgqR4jR\,pQSGML]`&O;E]:H&IFmTIm))8s>Ee((C@Q#2QNn%l@9pKdUh%B.=+ %mm7hug@)adlD0;tmq#62:k0e6nhMRfk.jo)nM7;g&qCkK;$I>/$j##'1#DY=-"&q)kB$bZ7@cb?,*SOq>rCtF>NdU>@Vt-EJJbjl %pI4P_DMB%A=t\&@[%C[e(1:[beXmr>T0dOJStUPkLU"m:Y.Yk7--Ud4JEi_OYhF*TYjG]MHhbF)5;ghmbs.3R$G-*"o-]4?@5HX1 %MLDZtY70'U5he"14#b9VXp;=Tb`qlS"p=055SM)8Ob0rIDM0rNrAAI^'guKa0?]&=Yh>\I>u=SC/t0@%Do=$bs;^S7714.@0>FACoq=N#)?\I27&!nE]7VS1Y@p/gS`aP(:M,'/\;q %?]C)R^&,c+%JB=^KdKp*m\1Z/X1Oi<=?$*tmJ:A"MOPIX/?"Q5R[=(\Atd.?8FAM'ZIm]`Tr*.[X9V[H2j#3]2P)&6c, %M^<9X(ok`!UgqHO'9&d1!i?gl2aU!YOCgXW %ab\khZmaWZ94c#gB\?.$_/344IuLDTU1gkIQ+PGZrs=K %j))/"Rru4XhIb`sP,$FqU;$VDQD/CY>!b$"GYC"d5jn?8^2r0RBt;8aqPVi6o9[5F$JMTW7_fC_6f!Pg2d'&$D,6AC'NgCBBh4kc^lUT4LodOY^J<.d(Qd^c:o+./R_&g %JnTY%U'j!sWuc;RSpE!\nnV=%H8o3WF$/[*=H;T<(N_GE*+V?(75)*[$'stW"4PT=@d&CbZCkJPM5:T+aF^'X&kEhGYIU,RW5tY? %H?pu.PsQ;ZO9H@VOmMOCMP^c-H3:5c&l0>9O9H*M\8]$PLF`_sQit!nLF`_[;$h>1%p9ID4pcXh2L(R,roT05rDKRX=Yg,cUoT07DH*UP`TSG(SH80+p+k!/g#p:40_+5^4rZ(f@Lo1W,aF\ugq4`Ii/WU1J6,3FWoSk6^ %(R##^M5%q]?Tdr!kaTeh?aI)#*;#02K"0\S:D`Yb"oh4o"^]XcV_1O@?*Nt/k`BT5A3nGN&Pj58OSdC>.>'8:3?G!p8tZQW5,++Qfq!Y7h5%`Yp4)iT?DCdWW%i8hiF_ZD?9iGeothZc@p!N[?!Ucu %>[VH2nQqln&f0uuNqZ_a:%:;)q+F]&=$Y5M0^aStHj*8c'p/N(Jam'V*qKp;d_!Pp>\G]N[8l+T4gbXah"OTn^HNPo %gOIDMO"]eAdhIDoJ^c"d,DD")-0iYeoVJKaU:rbA'L.lBUV>_Kl,ASWH7lq$jh<8/92VNRIJjOPKp>e0(!RH"lW3A%4j;gNB8bUf %3IiQgIDf^VNip+X1e63h^@$T(5`so-=J+Xq1KjrC52FOh&9rWPmXhN1o_0+0a2PVKZ`'kW?Pl_O$\j!9RVE=`.:7NmTS:(:9DM1U %HOC<'l6ekH?[gj`JFACjq==+m1jp*d;nh&O_`T:6cFhcuoO/dSGO2:AA`M'Qif:V%BH-^8_ND^R*HJ2*D;;Zrgi3c:A`M'QiXU3E %Ul@IFM7`^cL=s(l6];^+mN*0=J&$oq`8-mai4X^@]hC&lqm+h*XJI^mLX_8R)g?2INC%.8c=Gp`UITtE8[0eZAL[+",m)I, %K4i/N.N.b-GUgTB/MVL9m6^E8>='@Qc(NFp33Gp_T:?!58j(::4Rft=EC=.rlhk9'IE'=>*?9ptdLB& %%+,]?B;&T^'[[PGB3AqO@AQ+OT&l?WE$ZW^j&rrS&;@K/9W_J;)B*%HF%+,EuZ`^e.[!3A?O[B^4 %0mK"8]M!'HnC`QLKcEa$-_?%cI9rB&5GZceAXIT+r51LqU6 %08i/Tor3nJd.6D,["VQPO.STDEi[k.>1<>L.c^]hN1n6D&_%*Bad2ldJZ't3>5h%a4.`1p(qQn6GM;m[@XX`nc5l%$lj>=JI?p"X %b,Wg_eRu_KB3/colE^KP@97-ilEejOc_Ae_]M6W-jK9/;n%160eDp.5,'@mPT1Ds@0&b!#pq_5b^@D,X9764POepqZ9`sln!q]\N %P-+?>[to><>o.5O/Y_+m8]Vq-If8ZQBR6rULR.k>XqmIiq0D73Cn[\XLo^D>H8.XC$Yr2e(P9hWE9?"QXp*,Z[pX":IdrR-_7N'$ %oAs]"n/7^/L6%%uk0)S,D5"Z6oW,VO-*N[El!]((PuesR^P"jXSL6!=YIM0(Vk7i)r+3O0^V+AK^<=bd;%&B^h$kfY`MCr$Gbq4K %@S&0QJ_d&g`[HQ@8@h7Znn?#,td=koe/9E]h!m`B'`->3N7Ce5m$[L&AN*]pN*QcVFn; %kV%*Kq7F1%>+o7"5d+'Vp=]Uj*`n9`fCiDD[B$VdKkXsHb)r>]V.eB1#":W %i1CHtebE"b-@W>YGHC89rdc`3m9eT/Ah0U@hrZGpZP?p?$Y(\RSS[g2jfoPo'=[aoZ.Y$3jPkjQN.J,MdE9#ej=;h-8@3:dauNXq %;,Q@'kO^plGE[=W!00)p,2X5M!'V:U&j0D!)52k6qeDpP4BsEHYI)A0m,8lT:af!`'[tb>lUs_ZFD*+;% %j5R>0AqVE7AEFq6`NW^_r\0p&b%d4[BU,QqoOaNICl'm1!8V-!Asj*F4_mpej*5D"`shq"[-oEf+3)Pj0N^9NbrM]4E&,Wto=%eJ %CS[L%`(GVAB4s?70QYNh-6:in%gJk?Mk-:RWb:;QS/uH@B*tt1F&%ema-HNKcCE@):$kPEX?!3!RM2nN.W`mBkr@gqSe6W5\Vb%F %3R_(q&*ZtrbIi$UM@kLc8D=tFJr'A)3j7F56+r[,lJ:'80j*+b>3dKEqF=V:[,/!Y`H6Otn4eMt3-i!:CP6niG3!?bR3g?c]FM>8 %k>IfCI2V_dab/nboY1$cBR.(c[U_I/!:Mi'd>#o2^5$oJ,SufToQ..2V\TpL.D/mOTh=Dl_o')T]V:](+-_::,4rE %>CSM#Lm.Df,mUPM2jVXRR5MdIm6L".A[lD#_/h4^>([m0,KJ6*J(=RP1NjI4YQc,ued&#/GaCb %LTXH:%Jc:'S=TCQ(dNOX\k`7mXLZ9U:.(@Y4LOq$:rfbNm:nau!842^/p5nrCO0_N?I^\E2FluEk-kaV_tEA-)m--0lXZQ@C!Y:$ %c$DeXFo!H>_RXTOCT*(O?\Ys/h&V3k(;*TQD1=JrD6WcKKO1Y];ReNi6ej>c`*]E^Qc/7c7CuGmOr+^f99%pZ$SXH1\g0moPcAImcJGohhp:!>Y8q"'F)NrUl_`Du7eCLeQ\MYf;c2\U\0=TBuqEZcHXOQ-Q %[(%)L4I=H?;+ud]<79[&b$<+UZrdC3@jbWjhY/u[/VmX,eQ<4><]8;[3n*?ZmDD/hY\s0]gDk+h2%Y2M->G?B92!u89f)keqm[RY %b7HnUOSnKIZWp%->ZAsjoBLe+A^4>C;(5dc(#$dA%A67pU,j.AfN2^P3=i+;]TXQN[YZL+Ap/jnEkOP[m@j3e2l&n,N-%(:d:*U" %V8R%%N7+Dtd`1PDp2Oe@FL2lkf!)Kcb\/^>E#@1Q-sE_%9p_0S;sD`QnZDV:9CmY_]_6F$qSCsiq1$T^)hG__Q:l`fSXU_tA1)fG %^n9V]:Oj^Je[\DL:GWgL"C@t?-$BLihtFOL\T%5,PjU%ahCFs"8`d[Lk3u].?B!0XL!k>0"(DC6'$9J!3q6N2Sp_OO'c-8'mJSuV %'%pA"(G@Xk)'1#qW6DnRl]"f0>[g13,[P5s51iSCn[(deQC2)'b- %m-K[TcuiLYBS/PF+pBc+&Yc(Lr%]N3p5S-Ib]+*0*$YK+ecp5`Rpf$0/qNFFX6lIo1J2Mg2kP^gHU8-LeX8#QT<`nC?3TAS*FJ:8 %1cf!hTjq3E[_WsG32.L'2$]spZ`RU,G0:_q!^@t4;,n.X9U=e,>)\`P*DT]?(AC9ca%(,?R:HdM#)#F2F^LPZ/a*?JP %#e^f4G&4DgI5Ykl'251dF$MNZ-C>:MH7NNX=j+2gf/l(?Xl2mGd66pT*hr\(X.XrKG+,tF`d55'dQ9g'2EL5`:&S_>2"SB946S6p %69eR;21N@tgH;fkBm6\EH-\Er#OU9:DBiF)j'P.1lO@%8_SZNVMKt$Od:Vj?=ZAdPdb@#W=ZYurgjJkCs8CSehX/$Y3i?c4Xhi1u %$a%P8P5_sO=T0rAUI/:&ie-2WTNBN2pj;5lc"sge:Fa#to5U\Apj:Bb32rKn^Ft*8D!!p"d&1'ISc9WbfKPXOnue[NNV8bMeqna= %)_5:]?a]n/9.nUCpF=q";Ipl=2HC%E9na'mFU9`2EDrF7Z_OBZ=ctq:P_.Bp1Y?)=]-p63qCKq-S+MKe/i?]%cL-t?@h7]>rL(_t %]"\,)&Yu&O__h0sqZQ*$RAkKb/7-oOA4\M,X+=5u7HGi]:],%WbW2-2!LMjMNiJN'$$ki8fIP`)*O%#@CKC$'Zc9,S?2^]4>%`gt %GRkT@Y7&)U5!J8>/$oT\h!I#^DiXE*LP`Zm]R=dR3=TLiN

bUhQ %kVA#2VP^-V2gV.+O0fM.BEV0e11Sno]SU4W%T"G8R++R^jXN;top(N)Q_7uN=,h2\k5;/pZD.ko+%_#fiU5L2&og`@[[*d->GdQR:NSe%o %'asEin(lo:r%RkIDmo>gb?9BX[MF:MFAos,4KdTQ"AN&%3kiJ,+tpA?%h*u`BZJ]t;O7P9(3KRA-5U99EsiL,LAeQ-[Q3\U!LOdU %QeX@]eG!^3f&dN,nOEhg=.\i)LW/q]bW@:%7N[@bbOD7/@F&leEWl_B/*P1-4SW+GpGMT&Rr:90"]A`*iK;Q$X]-Wi(&oG)=YtVI %r`R9k+bXojlHKlXm,5AReUJOpD$'uT%5"=qk43`M::6bO,XtsLIs.ZMr:i7iP@!9H\I9B\(ot-VFseq.Jrj[1F1$EJ^GZqZZsg;F %L'eg#M1$'.GN7#SLDFY[Bm+(?pE@TdB"f(,4id;LP&$SD*^8_#g*Wr`&a+/F-DY5o; %VX#lQ*E'V[dH+Cd4gd72.a1rEa)3u[F7f7+kV5_IXeJ.aCHdgrQ('7N=Winn_]L4M(0GB_sYL(au*5%F,T %0XF:3#BN5(0UQ%aIE(82@CBXdnVj%*_NS!9St?UIG"6s;3*s`jr'o5Sq=i04md]LTXBeWq0$*Wn"C-mnDd,[A>%J2P\q9n%(!0J\ %5:C!h0])`cp8Xl0A.f(=HaIU[3.Q[#=)[$aG5M+;?qGsZuI^EOV? %`D*&#$AVoX]>92Uf#?0'lseeo(!h>:mfr+AZrX7k_!#[)J#r\)f$P"WHs+(t6OBl$oABC5l>RXej!h'Z<0 %69Gc*.PP@ZDNDDY")c8]/C]+FqGKOh;eBSL`\FQ@%g'1A!00j==F$P3e.,XjO^!t)M+tbeD3"F")BncNDn*(B\1qh^0QQ@s.c_8 %TJZRZ>r@"JG+;m]B>I7B6D1?>f7MZm*Bi2SC\`*)Xlgb/Si1""Z>;*;XuT/\>r(f,(*Em8#NklS=f.Ia %JDk*;Z!:SPmnp\\5,k8[p1)"A%fIcBqh=+Iko'OJ^bhZ&.]T($JU&dtY34F*IJr0`F;M-bq"97$QJUX]NcIuKNJr.fI2&2U*HPEK %?ne>2I"R$eW!JiCKMOkKgG\I.`)?e;Pe`#;;)K&)XIELd`2iDaa7g10*:1.0 %i]XC!KDLDci\<"rQkYS]ZHs&38be4nppLc:iWfT%[keU9PeaSjEiY'!#d%V0/[ad`(7"Ocp/5W*B@Q,o*R8*BHsVuAH*;Q_ZaRK$ %5DS)e[7tQ^Yk+i53L&^sa>DMr@3u^0>`^GecK71(4j>e=Bf)Id()muM#R]IhMdJ?6cn'*L<>5G=^$&H2+G33n %=&FX87'OgT5Z&eGZbPe`/c-/(WZYCon:S@h/[@N(T*!71OInP,?C&%^\=$>9qaL"khe[:a?eFI(\RGG@d^5qV(hEF8gp\bo7,abD %6:3cL;TG2-lKGX70s$]98IYe_,*YJRKBI9ZH>WP*on0FCQ\UeM3@nCG95F@QV$b=kT#tE61)SU06VKFO'``X,r(JbD"0`SW(U+_N %N3Q1=!_OBnah/W3LpqiP?.U>!0psP$f@kDo=t^dIGpgi`AG@oGm#7EBOs).I:47CD#IX %6mSTlCWI]]m*kAHnMPJ@(8sQep?_0LPHT7)IXeKbSY>r":?k(p^WXW,Pt,%/0A1TT"k+BfEf9@`*=3]%Y#>X^?'.E\cIK5Vb2e-J %-mN-mD*p-H(WcsTq\u7A4!c+@`A>gN]uL6T'ME(u_B7jSDjA*m\i@:qG]a_[&XNa(:8gSK3s'[sCVl;Y16X^m+?]BP*on<7C0p?7Y=Pg*]q %(Fch/A-6rAbCD%WP7#lMD8htVI3U10fY)q5etV/Fq/N@]pPZ#p %E"SQjQfIA;p@[4cbK!]H/'j8WD9b_W2&B>%6SQ:0BAT@cTpm1T0!mk7jF\cL!15)/J.//CdCD-O$B4uR.hgokfX*/c67bgt,V:tppEZgKHqqg[.I1ap[j^lgYM#[$fEPnU4le'jPk#Df %p0uRJp-Fju,].3K,OMDC0AH*J"ZTT)UO.nQ[P8*rs+-TT4*^o)=TYVR['ZB0H\a5FCg'Oc)V8dZ2Ta[iWDpkNa=T-+\%S6b>[86+ %q!)c4Hs[e$VN>/*jB-al^m3eW3NAie %E(eM1mmlob/=lGMK,YqTK11mA6/AUup2[0m]Nn^`3$GI&So\?\`__]@,b)Z[$rQZndQ;Fp1Q6:D$S'C\)9dkBEHfF%>_g9J`osKc %*Ki0QB__]#huIA\mW[BAXdkS5)5htkcQ^&\@t5]S23]/d>K6aYhGC=8!+/l=DHYfO^U7]"(I*5,hjX>8:68IJa78oq1aY>57X+6V[&CY.B %[+8gFh)"E+`(HQ?8sKtcEhJ/H&s[&@;Am]Y5h1FI8fOpbHu!/JOHf:JR+k213ET69cDq8N\PP&uK[),,*005,#Q'3..WsgHVYr,K %?9uSPm9"tALkcCND(7+6lRQA`A1B-Ik7If&\&Q$P^@I$[Y7MA-4Ga0>)$]][`>&R>e"D9td3%#?LZc$C[X_*`r(/!s#VWkk6%M1B %QuKr8A8PEF?]G_qKcE8F)"Y[*@XWaic;FC2)J)d6F6"DdgGg6b/`l:RMKl"4fD,9h.AMU&IDoLD,:nFP=8^nY#bMF>BA@2^)t4*j %'=FiaE`G,4HDU@W1?t.4Y^DbIS(f.V?]Kf,(I/d0C).%iD^uPjfhuS89!2SqX9$Y*$FpB*R4FVCKhVo1:Q'8g&%**,C#Z$F<-olq %A%>IDQ*hQBKhY,YAMEF4>`('T5(3'%a2j0V"MV!D*8r!Ff#J/30%B$kAdRqc#fBEgQmKD',E0r[UGP7TD\$INDHoesNU]24-t[ndrY.j(tibLpGPn]Vu_,.\42'QkRa+iYCH8`3NZ#'8`kf?pY@QF/6T&Shrp\U_pML0?tc#hX*.VU>](SLq%5W %V_dTe^I5n&Qh'k?I*"QZ;[I,oeV:L/g$lmu5-rk!m-jl=%W:oL."r?3!saH]4$mRK2J0b'D\Y-k[9ZFj'B3rl0nk<1qu.^iksZO# %/@I=l/,;$\g;k_OBpd`6+O,e7>T-0ub-&!89BerL2"`416#Ts7'LA!W5D$Ed3)RPb=W_)_-5[pQd0NC_JhhN[gbC+#nIpVh2@R10 %a!r'P5L!tOL^]m-#]8072QAWLX8aTI5@VqW\![&iIU\E8GsR,<;li;r)Ci&Jk=]'<:%\t%/[1VBM*^F!T4.*ndb09ga1D,j>BK7T %&]fG$SZr^Z61$#[p=\drNn<^q"BHnEYg;e/J@)L1UcJMnH+cBbbOJJZ`Qd_**&$B4YB=LG/b#Q67JJ>P6*Z>G]T;)a0Md+t&45b*/kCSQ(eT218/\CFS:A(Xn(6Bg5@_$a$JXUNWi;1_,&t)_KSYQ]6nL#6*jM!JgM>BepuVZ,cQ;C(aR=[Bp9$CnhDTe5^m)lCgh* %;'[KgTMDhpM'%,aSTUAWKKXTqA8?K^SH_)"X%H*ID<0r1k<4McaO.+^c$qi#FLl]D2f,n&@N&)n@RV003Xn5Q4OOg!#3:g"b %.H8d)a]pXY8Z\>t5r8V$`]"fF2VMSK_=`p;ZWAC>h[mfm5uGpV;m/V*nXrTWJU&O4\/XsKVbu)omMpY)dLStF"S\;>(LkXA)&B9I %._'1J=57p]4>/p-*ZmM(E0Ls3;?&O5XiD24N;Y(KdbnXJO$Q9RRY5no3c`[p_uieB$0DQKY)fR[@%Xr4bbH6LJ;$j[GnBM)N%QG_ %"E`\,+jNYe]r-PCRs!6G]FbN;-epdRTTI"&>psaE:*QF*kHWZ1qAff6F!R"k77`do0!R"l:;_k;Rd)b_\/;'A9'Mh%#c>_WE^fn?EdI//<_c^[S$dO\.fRr@o;k!h(W]08_H][L<'[1OqY(Em3 %TGKa\)nMfEB/opJrYOZZ7]RC%Oe$N`>fs[;eVRjrAI?+t8bu!/+,cfpZ5WH;I`JmQ&d[nO81qk<96;mW[-N-:bO%-g+n6GT.nu_;GL\X)g>rM\[,]bn/@Fc/Fel:Gm>N/2r %"hI?SO?sfD]RVeUS'T/P1R.J>DTKGlZi1BqK82.2$^..0N8P&8$\2C'.#J\k[c!DQL"UL?.]H]j_lI'Q.Q=Q@l[$'M109]026R3A %".IH%E.Vo7p:\qs(Ik+-3)uWLB3XSaGd69uPURGG[[d)<`/$/P"3O.CUM<2"qs':-%,**W/7f?8'-#<5Cf;:!I8Q@&LudDnC(JUJ %*m$QmFB4NJn^hR4KKiG@)mK5(-[l0f)q?%3I"kCde!]@qfafmK[HjdjB&a>4D681IL(i"DD>]]#k>MU^0OnFK#S1fd1Cq7/-5)7' %#Dj`M-cNa<:R2`*DZ:j!4A*$qoH4aGIb2T@'tf`4OiNlNTfN!E*E,^lq<'9r\fS$,:2([h53#9_d7;-``'>3PW=9Y:5,H#PJaO;n %&S"In`0b+iENm<\R2E930[>hMYW&V`Wr$n)+XB2qRWb=kl9.S]Q/_5\jqHp(:M%$eqcMmarm(f+/,L7S?bLLFo=Fn^Pgf7M3f8eo %4ce"_Pb.kMWh0)E4\l=['lt)e(.FZPq\=/\Ao0AGp+,8Bbh?amlrVD^kX&ff>id'2o!I?FsI,d,oKKVacVHDRD %5[dIXq[7,ajLG>+cNAkaiOS=-mKX*^aJQ>#%_U@eLu2*648["j#j8ujG,S2N*EUgb.4q9oYm,D)88g!O2?l$4C$j7>BpI*jh6l.u%Q7pbB`N/[`FSDh %Q.nhk\-nUu\QDLKFtSmo%.Z4ZbP^"d`,4g1>60T>YfSG28IXJoh+&$c2qh>q`%^]AEIqj=iafOM>1S"]kZ4r.Sr4YB7(6q1;BOf` %LGmThG1HL"B!%sIm&KkKbcgR/JmC6`4>4jT(K:mo#0!+\/i5neKJfk,YBST9b:dR2o9XcKp9^r>eGLgVe7"$HnrqhR:u'9rhF>4)kGLQ$+bs1u`??B5FWlp2"cX)fCmu8L]0L&<3lGS16m@oM#"ULrqi@^9q"mT8P_8V&XaVb@44^ %Ikc_%Kl^ZRH.K]fi0;Cb.[h=m:*[BJ*+7+ipL;FA=57*(8S&4'4.IQ`laA-UiZPuQbI(6%USf)fo8tm[k/`j/QM`I3ME.up(,5;f %;PL1E6k*`;M`J)>S<_u=/*>(<>h2->3^`o;^$sQ0h?mWaY?/S`=t$4NHmp_=p.sOU.ln$s0b#Tn]BVB\Zg*Fn2K)O1%"tb?U-V4\ %=$6d=]\6D.G1CY%/>cuIB)t`D[`H%ScB/j4N@%Q)kj5>4M"MRl'qL='I]K%BhkHUo.+WGl0gU7`P`DoS %XQ]$>HIe:U9K;P/-oe),*q2hZ/ONDWhCSG:h&4B,`2kpNfgk+I#_rl>Gg6TI+X,Te(6*sI_GIn`8jDa6\> %P"dQ.A\"/Z';>VYf-O'1BQhhurn.*BH1_>$o!`#eQ>c<>QJc"!.)l*2CKbtOgr$"o9mCk-&gi=:Fe:H26_NQPft]mJU>e9Cl_4U9 %]":61=G.>BFl?,sMND!-28fo"\70g#gf$\6e[R4WE:Z>pLE[P;6@OjM'F9]>h@[4+!apNTrhCX%-)J:'r@M9I]jC3G4aL7g>`s^B %f:=SNNH+^f/U+>48o'bm4,r;^iCQpl>\NM6^lWhu?)@C9=Z9EqIOi7\aFk_m(Y?k'OM" %P1UtLenSV2inBU,]=!?V%if%]`/M^q@T)!3oon/oT#ii'AiAWl] %h?&8We'6lKGYMJ&a%i8eWuJ;'jpYbSZ#d%U"2DX^gg4Or^6F*n#$e`,E'/7rk''$e"rWJMN>4p1.juk3>SXLfi(+em2XBAr::nh[ %35&,I5O!1G%IQ-"](Ua`f9s+US)8(W^jiZ0'?%t`b+h5qQtS'e`iJWU3[/]q#;GN'L%cru+..6Vp\&e'P).o$k?N^a?S!AWHVJm0 %i`l3W6fN.9Ck:uZ(*Oa"?"KtrEfAo_eu'>KgMHCg2/qOFgC%L@0BQYZDH@?8aCZXPGq`O?a`3V8jKXQLSbqrW=DjY[p9At5C@V@?(/[W[hLWZE7(a=T#u"rG:eZ&+eBM9m%M=&\4n!l;mGc3`?[h9KR8&1 %^Yf@#?QJYCjS;(l*M;/N);M.;;`p-JIQVkciY %*a)oa[euIq:cus4g&WY[IIjK'_-kRD>mJCo*5b*h3dXT860NaX+/_?X^r=\,>Er7qV+DbRqk`[D5d_=+^1b*h`DLSD@RZ$mR4FnpIFuX)?YF %`=#-/osImN`Xn"Y.eS$IT*Psfq?bJ%03*"'n^YuhAD0<%pK'(e!E0P\'n\@O^g@=fgh:-KVB0g>+`)TBs7u:lXF^sRcEV=._gg7T %,q"%l3L>?]QKIYEf_Op1c)ol3[Vl1*6!9%Y7>C*M\8J2K4\r2VKUL)tB#='5VNVg'*ut/oW\5pIW"ds5?pjp)pbbi2qJFklq>DK2 %V:VPF(JtGe_?Aj?@A`LaJ>MWLVGr1-6Q"#)!a2lqmGRBt:0'-0X:/WLF];(%F;4"Qc3PP3cVQ6R`ZYZ%(9o#H3Qg_j19dYk%p_YhRahaCeT:]JW;.YdQ8YffSqU?o'fOZV(j=ufLiHR60)6@Y4)=2,OiL4ZXjs0GkaLEiGJ'AI<_=_0Dn$fGEL,2Jm]>uDo7A1M$f;];ds?WT*U/K@'j=I %n/\!o7nHD5Q9aD(dDB2EVJH5(HJr3IX?h>HL1O!spY$^-=!.db.FmE"l3Zq7+aC>`,9gBj0C#(nNAdV#VqkhQ0(1A=7ZB3>eEm-) %/t?UpBN`q>;0lm?mgEsh[lZ[\D;E@^2a[*"MO#[?]5Vgd8Z$R2c69XPZ9-6m=a@nmKp=`>2%9"m]O;'%rUB%r-!Be'!Jl %NQh4XlY#6+XM]/]f&?0$mY6$lh+1#H&^kC_e#fR`&`65Go`MUWrJhcSupepR$beLeoh4h#_mB$@m0f0CO^3DNW>%-3I/7Dg %P5@9GcX&Z;6MR!E"mb-t?Mrg]SDQmJ(\ni^_%92K_9!24(F@/WHl'SOahHo=cQ\p]oZosDaq!shnd!jrSWWQ6f;(K$fE!1U6UEos %FtcB7P$FtG-eFMu(qt\RQfC]LF8PZ#G#<5TFd!JZe*6*X3ORn.Of,h4Fb2]X,V^RU'_-4E+1@*NYsQPOWk7TdRCj++0ZD.^Pt4f' %YMJt<',SbWSZC+:AYJ`ar5Ns!It(%Mk)(^/Zb-G@KG1<<].c;Lq8+Nl\`NC?3\-U7[CUNhCDa'-DA,2GZ]A%nPKU4m2NRE%Y0iu^ %iGVHXDh-NuqcI4*Xc5.aoOu8;n[OS8ZQf*-V5]ciFRdSl5)Gd,?ZjBu=k#.SbJh7C`b1df7\2FGOfb %;2YJS3do_5g$S:+89Yq/>Pu-a-MOrX6u=/BO=2gB)1GLd'8p9gRfSUi&X='Spu%2>q?>MGW+\B:MC2(9.ri! %ek"OV_*ormWGC(AFpB2QPEeS@o86Z"n+brFTo*!+lRt3:.@Bt:K*tr!7'P;uj*gXfOF.f=-_S^d5T&=Eg<4sQ_+i*K5lZO[LE]+; %'J>FkPN;KnFLPgd\!n;a(AmKC\;na*Ig-N-GNo!1.8ge>_'>Edh*Z-YNY=*1L"*Ser*Hqin`mLrFQ1/fo6]t*M %Oa)EJU.=KW/+Fa&!B!Y9CaC.<=6boofLe86<^hen_cGatj('0.%pOkqN0JET4_uDcLk!f9ors^+=D2,YSU/p\4;c;_V&krlM3PDG %Y2IM+B"Ks`l1n[rJhk;'p,;S."Uh,)HVO-L:1D,po:b6B2\#L8[dG)kn"`IQ#@9-j?/YG3l(;qrpR)U!i %^ErOEl+Z>YiP,7pl<`8kG7;sF3AT+JdN)kEd9;j]RZ49M=2EB>JpHR7@E"NMc4EAc24ouEI=)fECLUS6A6H%Jf!9&U/3u[XA1\)0 %`)P"C9//f.?Z[E%ceH-i&]S=r+D$aH>n>SI@G9G#T`c8S.>_iq9F/`0Ta=U'$@2ZQoc=&5DeX3CA@5#-I$!NO)**6T"U_&Q'(HafVD7_]BSUVnUC0 %/T=5O?L"k!Gqma(=\G*C*=uTNAk9`Bl-cel?f.E/d`gP&7S8RnQCIN@KXr^nSTeuk3u)P<1RphF[C$eq.]bsPdG@1$Zcf4^@uk0g %83%E[6\,q4nRLotGAUnAG$`g3s7p`=[7YMkKnm*h=cU$n^0tU1,&s&?k1@Qj>U>4Z9R_D.fG=kP-!9es/^rpf^25Psr])IBkIm)3 %3U1s3QbtN#7BJ]$]qKiN(\kf-L%D$NJIc!l1+?&q!["qb(r7\*i&!!(-,jo$:5BLfj)`d\oGQqBG=lN61,RGotqh@uTo"UX$n'(>J$6 %[./.S=75U!gA&1cl$>G)S2qbDF(@(ch)*@&WS>TP*9rY6F",)-m2?-?ZHI#;CD]I\/hbo"=p5MDbA/g#?JoiSb6U*u_&8;Q61;`\ %LTgsTrkRX7*3:`Bf/n#XKduBGEqVL(G2+lC-o[+b[[ZGRuUF6k9$@K7TcTn'C^`ZL;#lt#i^"CB\,a&/;rOBCTW4$hD2p*I'V$_)4la-7X3/\ %5KqRrSsNP?M:-J7<%$cA";^+32VC^E"<5S]ALmLdHF:ps8g\eV`1bB\?[M!cnNK=P*n_*?8S(h"^0aYa^it9dt#5gKoLEIprUR:6=(g1.MQ'.1AUHX+3Q0XiErN_]OO2Hfrnm8JiKubg366QCpM@YC)bkj6!hT$eO6a(=&jPqBF %f.C2Uq7'Fcg%!b<(<)_t`[jBb3'PtuMB7!^))cr#1W]74<_>R$@+Hu8WA"FX):1()GBc+QQ+m[E_%KN]b8_=UaI_9N)jpN+?pufUJNYXln%>quK/EZ9\UhdQ:oFi?R_i_->pU^u*4HtpkX+T<`;D[FHDGiO %HI.!%Vn@5:WM^?K"UnuP91H3HNqA:oPc[%r"+LGr'n2&ZDC#c$&S+O(Z>m*7a)%S_Jlcrt%bXIr">@MY4)X.@ZdSR/-RK\&^(*VW %b64#B>c2D7\d\N,Zj;d_n2%Q%m)-b06E(RR1;O1$/k1*/"QMm2*K9KR#puYrRW9p@=c!k&Io\>@#.#pOGfp6iW2lR_s1l>W]QX5U %S'rgB&cT(k]ouAjOQF&L5!U'@%%t4Ujqo1QcnSc#YP#YH/2(,b8qcUs)U&.Ks%D_%(P(hu4LgN#MWkV1*.!\LA,dIaU8HR&4h1"u %:qDn2N(]NfK\oG4`t%s=cA:r7_fW4\EL+*+_UKu]'D"E%f`53"&fk+^#W>gIP+\m0>Z904Sg5`]((lC=6k\;6$_?2[NCic`d2Mqm %Y>ZM[mWMo"an6J?m9X0*CMES1)p@N9Na#JV7'/b\YEH.Z6U?Oj^q*;BsFEVTP3jhNB#&'pk6KRN#7-a_LB1U&REm9_/sD-D[,47S6kiL*!O5fbMGDcQGf %Wp#1_pi1Qg3pp?hH/ZF"[XWM`0(ac4*m@is$@0WToOED`$$do40[Fd#msPZ$g]+m6ih#i)S\M]9Z)9S^nBN,3Xf0mL.m,0%.o$K$ %&K[.t?,SG.lsFIPEK@f'Z8hG37_;"Y[P$Ols(fj;NW&`:TtHT<7#K9KcP.&!J!n3$8O!aa@[)1`DK9R+C%F-hEAN1=rOVmmQT;,V %F1@i+-d6"rB5b+-DlKS46Lt)*HLie2GW4jlVsKpp&-pg=3,(;\9AUB(Yc_?qYU7S&43NoB"BaK"##jqRn)K4ad=YWockP1e7[?!M %AflE,;4o_+LDd>tAOqo4q_")Fm!,n":%L=\PWSVS703RKO[]")@^?h1a'BVg'FUNKoC68X7K$ZV&3>4(-7X!B#%n$9t,V,$?:G'QM&a#4.d0p %=Ot+U>p!&81!*O-DHpBQ/7Y<<9AW5kQ_aLgVjlog;]0s8`^3fJE;Q[EG-j"Aj+V/!*2E)rMLa0+_jD02:o!%'m;H!(")DA$XkS[d %6>`$?;pHOlp:Rok+AA3D'ESEH'aeh#O_>>p[QL%31>;^9=]=oE0EGL-BGJJF\Q)%J.>G>Y%\7Vcn/k, %*1++t^L>h?+OGbPhoFAjVDu#5A0hQADb@.C1lSS\Z8s3m^/sFeNqJ[(NKO?Q/a?N?-IhqJXSHW9]0"qA@J^,DRYQnCdrQ4H8d,*9 %5-"(!UpD,CTG/OJG!;qh_-VPqYgeMs.X:aCq5Dq8G\PlC4%IP(2$!05#HO@"CD4ZB%tfZ;H06EqPoCJ,,h'uC]EL3&ri0uK:Q8jd %Xr#FDau3Yn>%f\(B)e@>m\dJ%lXH4t;4k>I3"tdc,,j-0TO$Mr;+%1/]bs4@5d(m$=5I$_Zk@h&e9U%UhYVHSN.#sRBGBLVaG+T\ %8/8e$dr^n`6uIV;K;q+i2=\a^=2t`kW+8V2^![b$^_+(ai42O&FQS2_rX0SV7k+mn\ekYh('ZK4Zi",T\nHL&D %h$uO&@El'Ca^'/C#8MV[cO:,7jE^3iJ!4HTK/D]n.i^bOBWA(>P;%ho(,_#Fig$.F]sd)mB9WN\Jked+>Q^WB/he`_:m)M5ISnN8 %6:hS[&)snuS;dRiUeK#Beu=k+o$sQ%?U.3'3+tF>qqeJs*bLpmLRdC5+8CGdFWF=JJ,0[+mffrUP^o1`$_1)S#K1h9mYjZ'#i./j %U`c6Cq6A15a'i]B\2*9fP+R<=bFK=&Y^_7GV7Na%(u6+[U\F5*`+#ao$Cep/8$$F*q"jUAp@ibrBWM#TRFGMqmQ(lRY#)i&C"/Rl43@P&6l:r0Du4VS+,c9b^8aXlbuU8rFZLO9LT %fNfT3Rq4G#r>W30*+G+CpVrYD`_N9eOqIge1:[60'Ql7XK^S[Rc5-=4-):h\Ec;qMS"er%0_M&`9+>M8jlTI"_cR1Y'/&6;@GU.[ %X1aQ07d]VFIq\JEO\5@0m3m5I-AT@4BsXRdE8EZr'bOe#e5;e9Mn3#6fA6anX@N(oX*C:_-^UC/f,Y0R@&YoM-jsN,\l8B/3`@&q %/Ut+X],,Je1`M';+G'[!J1D!JQZOknom$N2m0g2E*02+"LkWpU\03Zs)%K#OV'AYRe %>!>.i^W>D1,E)QB`H8H(-rgfu6#UIZL'21&9LCNI*G9Ap*=B%R6:WL63>=NSC91PcGktg?goPcTj(MNGFFXM#Jh.W3(-SWN"K=[D %XtLNE!'JYeBb'YK!&*,fY["50L>S_2l_/,1b+NrEP[saN]]`Q2eRlZ4F%0dU8) %d7Y'3F?$)I4;oXR!q%>fc'kY_et=>IQ8MNtSe5f>\*V-@VcPCa/Sh)(9EDXAdC:EGVT5P8hGV62_sphHH4[;%3YrRbK=[)K %+E8*cb.Wq%2K9GYle<(EC!*f\>p!t:'@lt(L>,TMmRJ+e^Kam%?3:cnMVQmr+m0dmk@Fub+e,'0rebou1fJ0K3282'ZKpMbS %6aLkO#.#AAoN^[rTnNOZ51:4+GF?hMpjh[E*"k%DepNP5( %!&)&T9"MeG4>/o?$ec?@`Q;2tZ,h618hl&6PN]cs:Y+5Ys--C1[52CC>L8!A5##ZQe=iDo?Y#i>Z2hWO9iHb%[7]6Jd7tW\R^H]6 %m]oU+,AYF9PWLPP1'P/NZ]*_r8W)fd(sVVH'NE)2E@^V7_turNG[4U!`VVW8L06^],3jQrhLpJg/ZG1,qk&"OrSY'EGd,oAZJ'D@ %H/3^<0dN]+:9\mG.%cMj,Ii3U:k+?3AHftNb:pX#TZkCpY9(]$C+&8Ig$u8MTaiOTiQ"Ji6-mrDWnC5!cS/s@PGIHa>ADe'BXlu< %-G:L1fl'%B]#:n4gpkYS()Xr&gOllVX-3lp#ntAmc*a"8W5:o!#9Z:&".S^V.a8UQ4Li3Od%&t%V%6BX4;iakMHh&BW^"]AGJ1R>;UX;h+oe@:B5n3 %@(k[N8fe-F'@bBTTDHfls2!K8pX;TkP3iC"Q/g(mHHW.(W1!.97'Q\-nbGrg1i".9o$=AcZd`&lY'=!bA!C>+>R!Z'M1q>5Y;PX+o<[jcl/j-unF/_Dqn"R%EfcC_]eXF;%cYeuN^n3YVe)IXTskr^F#,/D@AsVk"F* %irj/nHtu8IO`[Jr[*r6XpD'EgRQbs_neE#5l\-^^O+F^g%8WWkE\`5nQA2=+ZB;$*:)\""E"4gg3.=isDl9i1,iB"%0M_pff;5n! %gs'_BKJ+jUc738HroV3Xb`.8(cVV,DDSu2h3U87YL8B@=pQ1]D/[].I6+= %5^b=!f9:=Z^b1b&>=rO1maK6,BX.?UAo\pLV5g\Zmnga"Ot"WEE;E.F)3<>][TK'!Do_`dh.X^;TcTeHEUT^Wal)eD48=dQ#QDB, %gJ:;&p"WXed8^s>G](r>V5Gl/S>)#RnA6:WNhP]dYoR=+]h'2tLr/"?^QW*mrp]G&+b'7bC?F]RF[BWDYYWc"EX';"ij]6PJaZ6% %EK1dRZ=WBa4H!]uluK'#K@kJYjA]mo+L]j"9-c->*fcj@m9o;6pE\>U.^Js`X&uJP5[Oq=_IOR@\"WneQ72jZ%"dj?].h_I^W%!RTgJ.-TICfQ7Ic6K(G^T\RNm1 %d@*18OLJ#i%uM@t%15cY1*%@p[)%de4(Np_ML@T5m@pL9R%+7&5Ple)RL+:8W'aqn-Z2s6.;=K[Jq.ij=<(Y2Js@8h##]CmSm%Hc]27J.Q&-!6Zb %R14JcYmsRA_Th.B8&`%L]RI-PP!,`K#>09E:RbH%@MlMT7W9oQ'Z\klm_$t;,D0.^EEjcBJiHoBrnrFZZh9iU6bAd_=mtBT+@-`Y %Ad<$-@X6.&7;8NZ<(kYr#Xo5W_5oF)8g+i!+sfmL.QbbX?7Ohs8&iTm"UUm\0dSe'(&s1Cr[b>T3/94eVOhCGp9s_Zra=tF(sMjL %#>:+D@huo[o:i!N^WVB.r8(#QOsHG+D0d[T78LuGe.kqre7#7#HG[7\etAbkF+K[,b0g15NS@Z$:%DC$*THGA2& %YL\[S=uQqMARk?Tk:_uL\U%Pg?e13+XIE(,aEo:9j"_jl1qbI7H&Z90pPB"JZG3K1_c\oN#LdH'$B4q<053D)NHf?jA_beI,`f[lOc0+ghJR`-&TE6qao5=9&sU#JCil>N;a %n:%9CGk5@MT'tEc.d+%'aJQ24_@>G7&uJ.C.6PP"4Uh+SNme)[no"I.pa[[b'u5Q#!g>AT/ss8]btkr4pZKhHKSe(Si_9c-gaL0G %N/e;igW@/Ip=T,Kf*!'%E %J65IhkoAF_!'.^t*3ghit`)0M)]=7gZA&,HsVFItmH;25<)hRl=NI=cTI\39&FIbWCf(jq]mu!j1@q$HaPk+oZ#k@d/<=k*X''kY%a;KOSqLn`LR-S(`/a:M^TNZ@_pN( %Za;5Cr':bk0@>JX?ZQ&[*DF.a$G(=B!ESVL]PGX(.>$hO]3Ef9FdTun=V]/tkr")jH46NgMu!\;!:Mu0^^&*+&Gjo3YTl3Mqs%"i %beHG^JH00YZ2UJu5QLTs7MiWC";(/Xi^tL':K0&$;Yb&[%SO`"nYE%];9;[4&H-)dQOZ?$>L>YZ$QZ%%[m#Pm70b:%Xlpk$ES7E\ %S;G2C*g0+M)^3W3b&jQ4SXS"(P<\PAoS$]]Ss%AQN-l&sMs1Sd7-E$Ts-0C@nWM]oh$/HWF0]Sn6=]_B2Z`_RL"3=p!^57&$mqp@;5KP?%XET%+!#urg$,+^G8MTlJ_!d;X=7gp:S@+9BGA2Z,sg6j_6iQ;=N@Nmr'4LfBGMN,YnB]0R'kT!)AM@mZqRcC@@q$ %e13_Gp-./>3lOT]H?ll^^G(&ir@WE;!DmA9%,ZO-Z^`8)UU,g,;6poZ[a]Ms.,"J&:G+hUepr3$K1&:l+ube,H!!87O]7ptFA:k( %*KiXf6ZR=i^l"X0Yip_gYoUi#RcQo&RYKq4hs!@_";e`/YuhL/Jj6XMP#Bs&IkCAPknkZX2mLKheWt%qd3h>OX:O&PEX="0WJGDB %h>ebKi]%&60^+%8OG*3s2r+gG_R^56IP"BP`:[$=:cX=*BU<*\bHic)#o7F$QV5eF;_CTO9_VD!e90jOOXcDePPJ`'FEO_VoY:6j$(@@8D(d?D:M9T"h,WI2)Zd;!e:^a>/1Ca5T= %Db1-'(r5V+/#dKdVYpNe%E/p\NO;1Qn@3C7-"<=IoT5kS9j5YtJD]X]G1AN%CJ!(7#F/Lnk&0l4Jd7Er.X_lCeMllqD\b;E]Kcu/ %/AZFqo6,1SIf>T32g@r#m61#H`2D4C7&$N.qI?TO.2""<=$84pXio[@%(<,V`-7^^7RHU1K-?QdeK@-RqBC)"BXmOHd=e/EHV_IJ"$`<%-k]U0^>Z,"EP,B#3=0q3`-h3$*(P.?&?aQq"W %4'B&kHd&:BNTCmmg`-IVXK]I[ria_%4a@!!Do'OHHL5'ZH+D6f!V7uT$6(hY4CEYUOe\tf]9X9&^2EgLmd+`$Ih1dnJ`m][U6'aU %/D;^Ue7emJ$p:P![gK?sc`i9XRt`&QM'+?W+UDscE>@`1hpTq/Es7,R.03k';d`=.>CbA2+]%4#kDk$7F1'U@.(@L.>[Hr)Zr0Y)?f!C^D4CXVmf`Zbhu8n,G,J1_r0!D3?UQ_qHC@*^` %<3a4D0(34simeeH4#tDMAEF>I-e4^1I\kK--ei]iA1$$kQ>ZM/.pt7Kl*'G2C05I>o1o.!J]^3j[^B_KCYiF/F*U@Wb94,1G!bU)'S0,5X/%"_$1oAX!A?PAu03[KJf?)T':NfDY?60 %EhB+J^i@g_`,3uqAH-o]+Sh#\1%Q%ktk)-5^p3*_(Ct"Cm]e#:$8P %OI/n,Maic/&;*Wa7$iaH4qD-^[H"KT7kJ@irlLlTM\Qn!0/C2l %3X42`,23X=BZ7LPW.Hq-S*mNoG*`#q'WFs]SHH>@NanhV>ePgaJ"tPn:U4?N\^e4&f,:+8?3M!iGt&?,,>@pk0,IA&/faZA<"Y)+ %GmkF"UPr$=Scb-iV@W<=E*i1%;'S77:ShA4=38K7-@Hu&llXlTn.=nWLh=X`4YVkj>D"=&l<.gNI@M:85hh+JYiY!%N0#(O9Zi_0 %ZBih?$I6*mN\5#Fp5:MT#Ya=@^rQ8/E">7/8'UL;a88;Q#9c95i;U5(V$D,mMdW+[clYg*Y,(mYY=EtU+U%4D?&M^<:<7QSU[Spe %B:;V!_AH\*6Yh^eqnqtk9>@Q'(!B7^RdV4kQ`IG=Lsg/AaVEQM\h*=d_=jS@B43*ln^gR& %e1O5>:"B.Zh@..U$m>b7qNcbaK."eCJ%Ml#:[X3QHZ\OsPh[5"-d0O@?@(P%K)I:P'@,7\aG9Ul*0kI:e]i.1`Q3':fi#O75i?uj %fim6^5R1Wco)=`[eB#>*.8d/u0^\.acfonVP6T'kB9@0N4iY0DQ]8004lY>6o'9N:,OS9*D*!\Whg_80ES"f)95,B^D_@.YB`H#8 %bQHl[N=tVN("t%f$^-3Q=6r %s.G5J>=V^T3@Rs!_bj"eRCh,WbF/\)C"0Epai8"5p@W9K,V^4CD09]A>dqiO2*KAjO/%Lmq99o!iJ!57dVl"4F[n=+aBgN8EL=P@ %7K)J)mc\@?9*PV#@Uop%ZAig'ktL8(#5<(pZdI$M=VgmXIW\.<;$WgOO/=*h%8Rk3>fRnq]`/^9epP.*r^fS*.YQ1InX+ru.WS4? %))Kd@CZH=Zh2scG=;I/LFTd'0=Hb@49tO2FI>g9)9tO24fn54kfn2!^/7;@OZOCUj\cqHHqto'!s#9V/fl7@H"D7u%_"*s]%rNkh %3=hhLWVdDabjIjgF)U`&ena;B/?<]X'jNX-7FY'q4GWH+('JDUkCha0=rrsuqg%WT923%WS%'9(gAgo\kNCeHI[-lp(:4Z2BE!kb&Gil\a&6p7`is8JjJkb/cg4do_!`Za.F.o&FWFq5URDa.$#%a$W?+SC#7mb %mhXD*Q;r[XO,[]OM=8h/SZkYAi`V2e8qGG$,S$'rq/:T:N]Ip\+RoPoL#SN;(=j,["aUaLB-FF_3*>%l.KRgF])IQ.?i#A3Db+,G %A`HpJJ-mc5\MYo,(;D^7rArtq?+#o"rQVJ`Oc3K.Y$E(gPc2:)Q6N!qn/'o<7]CS+.R`d$q\bbN0#rJFo?LF_qq-&fcd;e-"h]+]9!fb!*i02D\pu:sNHYFHq %B5k$XRd_r2jl@'cG,WAX6YELH]Ude`+qo4t@q4MN4&$upY2KqAg-[(T:7hf;S*b9:!$[INGbKMN#a_/NI&6['8UPu@/^Et!s3YLP %FaOl\'0]9c?ati/*0+g8MZl9#R4h2rSG9`i90<8[4+2=NS.>S?IoU_F,f5i-;sJ\u5^e)N$SCVWnZMIfhe+V^/V@G>[=>CTW_boO %gTRVuY**nI+EGYri;Vh%5FIqq_\PU=Eq8;c$FsF-leD0)pXZR>Zm)I(ZG%[HB0=2&>t9eMpfduh?,(O&0?pr[&C3.shoJWPRgU7o]-Drq?_6?K`GKdiGmEDkfPsNe8;:SmYk''l]HrtoatLY1KuMo%rQehn9FjeJ,B6*N1X-[ %54></D@'Xj6(ApgiZf]"aFAnAKBJ:,`Op:V;hI8F&k8Y],M0I'$H5>7dh=i.@4('+N`5qY`Pg],AW"*e]jAM+Hb[M"'O%Kb %c`^ZBL0*bL_WWW0(.N4R#BHrE(ZTUX:f"qA[,9gU"M\;m)h;e+T5;6q``JShjICG206MDFNH7J")^!b%G$Fn,A\%9\DCJ?SR-[Nn %fWCXsr6imI>Iou8$!'a=9dO=gBm,X\H=_$:@)ead,ORZK(+'DRmK`&Qcn>59WGPbVif#\6$-rQJ#U1[fittihemYHYuHC?-#4ojZ:K>'($k* %7JTY0Ds==%lB[_O7c@&^FA$i6rFc/"5s!@4WB9us[(fc:Hf&4sNZ:'@EaO,?*lscpEm+=_pZ:+]LqGRf]+-*>jaS#7s %o>n9k55i\fnF5g<#F3`sl/tG.jQUPFI<`IVj0NWL1>P_0LJRX-Xe*6BLMsT"#$Y;Hf1so4TklmJ`RC10<3.P@>WUB---a:[(9gTAX3Y9I7o/%W7%hKN-&WMr'm3kI#VIq@TLr-5^F7itfpCV=n!Bt#N]bID-`.JZlpj%,%gL0+MM\W$[MWVK)tA6CPhj:\\V?>^lEo6Q16IV_Lj*+YrHUi-GXOIbi`VT2@iV2FqAM%WoHY*1QFo` %P\]21o9Dd!)]:cUX8\eKFS7uq?LFHRI4r94GN??n)]Hq/bH((H?Kuj^)gj4@T,HM$B;fV:K))K!eAC6I^;g&pknCf'3Ib5pAj0o. %l%edQo59H^`U&'4qDg.(c_Z\R7kS!uRTuUrDW/p?!q`XDiM6@eK[C$4RPmS'q=u>N>"nZCYKj]1rdA\sNE7]1s1C$M:Np0Y`^Dd$ %WH+\'_9JbqrleijC8<3hdBo.i",$79cMI\gMU%Y'Z*W,OMl]#_),2>&Y%G%?(#hn1X:qPLXf=WBmrN?_*]V\n>k:QPlN;A_2noDY%GbUk[id)1eAg %Y3WGS]Y^JMJD;29\3mM2RiSh\3O2!cOaO$j4ftWsph/aEQo;P@l#bO+F1khB!Q?qQ!nS^X7S6,q;mosEMcC#SJtYfbI.5TZP>pF$ %.'@F*T70tRN!Z[3(u\8@R2MbgFqoiM]++o9NLmp8*NDt0hM++GBZpp!0#;&<%.5b:TFHfIYV9; %KBlC4!akX\QPEj)^ZBOCStp_A*eQDtD^M4#s3u$MJ+,,Rk[eMeb8Sk'08k=Baej`HjJ/V2-eI4d=-?@NbfJMt?f.$cf1Sl_[h`/\ %5(.pD.Dr2^0()Ht//$?(pY:]WDONpQf`%qem@=f--*D[>3fkQN#t(Ug"W5qfin&K\Z(P8utV6od07Z[RQc!XRrD* %""T+U0"L/7X&r^S#-Ejuq!U9UqnqD`+!E*rT//]#9mi*s@aGkKX$Z"b=e1e8=_:iV:OB90UJ=GFLq3;Lj7ZV\ %@+o?;MokHTlh[%qLq.iLfu#XY(3\uRS"dHJPInmET>4pf5Og>a?sle6,gP#AM2$669.!caV]uau#RrC"T3l<5OLE*m`;=f&^+`0& %O&L9Jp>f`!nV)2AiYnZg'Wpu'GLF7bd3Ep\4]nGSVsr)W5FpY&[DL>EGb$.fma\`6A9R(bjm)+!fpD4*I8A2-Q\:qoNAk6CC(!rg %V'e?irWqE0@efXsOr.X-FhlC[AII9iCr?a[1(btBa%jH^r^tqN\Mi09]ND8!Y1'41f3Hc]]SH/r>V1C!qC_WYLPfs&q0^Ib"aYKl %NJ1LdbRYJ$:4B(Iqirdcl_bQKr]qYSI3phcru7nS".DsblV,f %\>Ya@ibjUN&U,X+':*q5UcWeo)L6_W<628HK'mSQL.@i8u:3c %@pTtH&H!FFGqiT09J-N2;!66a1)/bqIMC3MEt)IIh7O*hhq%p"Ymdnt"\_t4[=,7#U$tr_(.h;LM+A4?;V)O70BlX\oN?/Ei\@=4Rt\CDfOX<`88:7:4o)^;,VH`h(>`ZPK#XRKl:=$'QF %FG_LN#ob&`pm#V@-g.c(G=OT;pW]b9LWnRss+u43Sd$XtHTDQ1DQdE#bl#TbaI[RldjIRBl[.)iF?MfFi;!R@NL"\8:J-S!Q*Q!R %Q`K.FK"YZb'Dj#;kU1#P`/%"@*l(02I^P!5R60eI+[jkV@?;8'i7)I%mWWiur %/?C=JXgIT7Uqr_rl4WFFoIDM`R9KO;Mq*A5GU74MNUP6_^B3aZSqru?S:A4E$a+AHHtph^iM6?efAgln+HN?_=9WshXNie1HbLoN %k@VD#pjM\sqJ#dFl'pQCB^OA>p,C*55P3;T%j6H:E+9\XPb?^%r][b;jTPcfJnWicK!ZnG(__qarDc/0D3ma,mZ%9&aY< %btM\6d>`tl/%gqf"Z_T77A^[cj'+jC1W>RO&uK36poIBOX?7*%=XL#t1XLW+:kg0`VWZ&.l-Z2j=kmrINc]@ %\T\gP#f0;@'9PUi^19PSs,g"0!Frg^SWo'E`l[[.2:4[F&ah-J"&\2,p\*_uP5$_QeoT_#=T!,a"-MnYRL:s800K4+El22Tnk$]h %'YO0;$Xot\U@)%u,*T&^SbOl_/hFb%nUW2V %Wa(l%8k3?d<$5GDIG(FX&OMj^ZVab"#Vqb^P_+oG";-nT"f3?p64i)RE.0BL71d26D?+KS7#89-0j/CragCg:eIHT80N'YnMk %(.^_TLA9#3Pn@HSFIDsIr-fuAR[W@$r&@n2-DG<6%r^]d\4Yqe+Zh7P1JMYq1\??78%@eTtK)81jZ>^!aFk3b`K*C^f/D#emZ-1/7C,k74KuPk(c6Me)G9KMq00b\QN\1GH0;]YB %W@\5jbW&-85?;bfb[HCps9)fE;%J#Hh2!>'t]06O>fqkFOd*fmdmT1FA2$Q?$rl`gDm4J %f(07Sl?qF.5]OeT7'L`meVaDe %`;,A"FD%:!,_MX:9.Zh>aZS\Y+INKKJWk);+qe57c'lN;g1i6p%GuUSXd`]rls1XN=3kQh$+o8a^L0!`q0p:gf+TN*D-q8fOt"0Y %TEHTQ/6p!Uf_f]Z3`"k@&om[r5V`l#o*A>-*.VRYN]_'4(?n,efcs#lG4H!`k_E^"lS&)X)9flLZ-88"7XF3SOc3u.d)(1>DVo>%=&*Kl&BV$"jO+R\Lt0!57%rY'%*$C^/>F;M6-HI!e93O/_;DQ:1AW.3K3@nW)BtT/DF**?bbCOK#2!reL)O6u %KO^+&_(8fZd1FDNoe(^UZQ0]l@)Y_UT5?fU_5(j42R4[P`X=>m+-KdfPEhF;&XCr[Y9\PoIZOti>J*os"(P/3`PI94o&ae/^c'$KKoA2YW6 %h2i%?Q2P$Sd2L-":#;57d0@]0be'l1lB+bj3k]6\q6T!95aee4_fqC(1T[5#*pV:^@/7]a`K.T$W4MFT9o6sG[&o_MZgk<$[:#,R %I8%WZBB,O_^o82U'WlT)"$7]E9"`JjY=jn,-j)gBLimrWdE`QN0UGQ*/5,bt\E+X'<(UWIG"_9;]i\$/6o]\]k>H_P652;6N3_:E %=/"JDP0aLjgB)*J`>+TRiSutROLuJ1lT0b9]XM9f;XS.,_qQGQUus3fXp_(,flO&#;[t"J]j/,(9Y'l1cY3+e8kPLlQr?&FU8S]7 %ho1l8TXUI%2]r*=9F[ME\H:j!W:+ZaM9:]I7ZM7V'$:cVObs?&ObH=!fWH1D'U=OA_@S:5qXkh5+ %h'bC7c!E%3n,2M^GtRNQ__mDe4igJ)o+jK(.1Gh^3D*Q0[IBY>'.].%pR)Mt'gdbjePZsd7nN010Y;&K^Kq27A^aehi/0K"5IW.X5A!,6FGih(5m_[!s]B0pO@-.Jc,KgN`?Xu).3BU'C0P-l;Zfi29#?VVd0Fd:V5QX=Cf'?mM\.Q1(R]P %:%YUr"f>24I4u#eJ?L4FXODiAk^=U%XODiAJ1Fb6GC(RI=WNlW`q1%lG4FWcrL@Cn+b.Gsf@[HDQ5Pj6D!Li_.pQ/E-k.>i4M?JE:-m*;KAD/Xkciq%#P_Zf["mfrG2"E?Hj>/tnH1cEP&RIk8%i %hsr6M0h.tJj]?QNh_ji'7jl9D)bO>#bV^pd>A'T!G5aUU-N.TTqQO,KHe9&3D`DYrQ+ebn9L!<96Z;.b1-YDl?#qZ0pZ3F.4YF70 %rSc+-r>aUjS$gC^$DV:S2=lZi_T-b'IBU+iK'DYU\mtIq.&k=q0DU\ZW\(OZ[+'BM.X`BdjR,b=ecjhaj[smM"MVHZ(^s\_fGXuQM0ZVK^0^"HE4b;'dhiGPTY&U?Ej39!.@F7 %(;#]o-U2Qrp:)SI]s4Hq%g(@Od,jr]Fd)13-DT/g2Jf$g-p\nqKD^k8-j2_2L$,LoS$T8D@6YB5/I4,.J9+-Zf`" %\QQ5T*tJRLfg'+^6Ip\7(:T@e%u6jAX\C$fIi>FY13kg-)?M3Ck"TR85"/oi<,.FO5&m-Sd?Bn`SdG`!"]U:Z!i-d-GfKo!)kZVE %!QGJ-QjjPP9U2RG'uaiQ2b65o,%qbaE2F0;_ZOWp.E'U`FdLHsFF\2D>u(]"7gE-TY-]2i)U-G+@cj/%p%CATqimSW@N %1:<$mD?B=;h3Eo%E(_%n#Zj`<>#b9`3=V5TgE\K**QET*IG1&"McSh<+f7P_%a* %!JoG=\uNA0^0c)K7ZY!+0B_;7p!13h/cRtMh4B@,\F@+#:r[Q=gqd:o7.@bUQEuS7:&UnL.g]`V)uWq8X0u9ibf[h]1p3C)oOE6m %m_XNunqu8%'6ACEi'nSI]_dmD0H0K6g5GfhZT(rtS/IaTt_DE]N2Q+bt`H]Gqs).!5t519_:a\)49jeMX-C4j4.MQOV\/:;ba+ai]#^IWfHa %Is?^q2Yt#eOBP^AqD2^S#@5ZqNW-)skFb3Ja2s"6$&A3:[ru8?$R8f?a+2R0PV[`]5&7FkXBD4p"a%9fit74chf.@35<=TTj$a)j!5p`DXmf/ngAB5_'4`9U8(ZUG*7(Kn=5AeGHt`6L%TQnI900NI#R %aY'H[>b]uba\f14C_C5=I7+<']K2rl!^E,9p@tsb]O=3`Af,0;2iQtIIrUd!_h\f+Q+&"$Lc::V^ph?]iXI+nFN;lb?"aqn]-A&f %Dr-sZ%C:V(%p[fmY'K %)*C%5(MLq2?nXY[N;I"t3-BuuT8)RIHj%PunIFs[%E<+P3[!D#\;\0!'/ZKW2pKD4Fd@AQ+/)Bk\?"R`)POh:%N^WudqalM&u9cP %H:,%`RoUO"L`ebVB=OD>Q8+/#c)"L!l`j.ceUgqbL.(A*TNMd7Vg'siXd5l'%KBM4,K,nUs/KfReq!_L3#bhA.BjH"pf=`1FjGO- %2OZr??+CYr$%N8`44XM-4'H9Uk(0Qm#E1d3,Lo3RM:apZo_4TV< %im@Vp",3cM"D@ %Jdt6kf]F]oA&0:?nBGU\6%2G_D'54C'TlC@F.r["-\pb%d;1s/L8D@&HHF\)T$i\lt?Fh;/XG3'l#8 %*&qqP,FpWfj.&bm_kuJ,W`/MWK1`91mAI8#l;bWXb>7_N)lHKoB"'LYFMr8@eeaqXeh\?(TU!"]hF!Zb55?S)#N>L?'H@\MT<-9= %aZ6"e`?mKVe!:1fCN.R3j\P7#]P7)C8cJ[k:Ic@SEY43PiNll2qMKtI+g*1i%VQi51QYom"#L!jU2GIrP;`SVK%SBN9ZO?ei/Gj[ %KgA8H)-$:^D4iWaB/iqV%%3jsB4-4J"Z5t!&]k@`A %3_\cf?4<+_ZrbMKc_B=l;bO;G.LHpU:P4OLr=#2HL*:E\s0:k*=IH=QrH6h$GYM)pr`+fS9\MOVj17`[4!)$fr"2rA/_[.HN`=CJ %141gK]Mlic%M-D7P!)j(h.PHYQb[LnA`n.=<8>[D)3]$tXKZJAL@o'3\!;80I8R,5Q<*^[l9MQU$fX0Kb*7/L@[dZi,UK!A8INp7JK1,@`sjRO5V189EUV]%c+RHuX@7^??eOn),hfL'%f#^"+W[>.S\@-uW7TUQkW %K>lQ%[1jP_0\,C\nulI8m+=[E\dO;\+g=]Hp;\/\LQFS=3+WU4JsK23>ADhY5UD['am:1r\@GgQ%rm)PMU'NhKWks9llfd&]a,Vi %T;A?<6DOQJ#?.n1m2$)lnke#l9D5:&ramVK9qe"1P-F<^+o4NUmR#5;68OYQ6'^.8ib/^Es8ILOV+*\X(KJIF?R[r&EH=YjI+u111B(pPc %=;a0ZLC-iK!)_`-KP;L]R&<6Z17O?t!Y7O&29qr>ejZ"s/NlPJ'p.r?m4Qr!?ao[f@J+l6llSrn#-D?HiaFG01bPu2GZa?GY059: %PU'mV\@G)bok'.JC97M!:=GHo9[NL#'qUhVSRMJaPKcFaT@0n3$mlcP%L]nS1N3W),Wmk/3tld.KJBYASe3]gF*S4J_Q"I/Xki2h %Mn=B^\nf+FNq;Rp/oNZlV9p<-NYaWfq0NB>]smYUKUNi?)InNVARl$%j[RNWkA/]t-qQR[^3;35d:=O4hn/9m!,\K\a,K?2oP#8W %mM!s@l-hOC696r?g8:+06/Afd3T6pa7Z/<=U-IS=o>?!)@i8MRqG\(]#[&KjdmZ0h9Zm`$l@*M`KsR %ZZuh#T8Lo#=Q?b55RYW5oHa1,n/JjBphMgE.2Y(J,?:Q@-QIR5Nn;Wk9Dd,?kJAcVZGt/"]QVe;7^Zk7=5$KCZ.cP;i[RHPCKK6D %1RE.?45tEr?ThN0n5jWr119suXY24FGap]+N$h75Ylp&gb;l_Ad&f$V@1hB^I[='W3j@'t?6NPClVTO-=rbG:LfUH!Gk[gL8%#6n %h]k?k0-6KQhHu36Z>VR].lB0;W%;3rF`tllLM;AJs10.qA5,%ET1_9S`-B915Z3:lRO)%hY,p5 %:X[<76\3p^\5gH>?oPP:\S$E_XO=_ulO.koL(A6`/+iIpI*GhPF2W">M9]8o'D.;Z`PiuNbX?s-J.)^Smarl]c-*R`K=bjng)p(l %)_Yk7H+imTlf'>'pk'o[p(+s:88Ald=L.X5Ghp_e_k?t)=GM;@F7\.Uo[*4*L%j,#hk$M'5)lgQRXI;X92C=TgOn;A^<]J*:XL1U %oh%^bl#uLmfg%[$`CM;Af6BD/[-hG[D'`),Wgn@s-PDb,1sL7`oBF;bbjchVj/(\u@jiEmG$gje"&k>X-.i[9K"Mq$jp5D(AOJTEL(T(=*DkqbQb%F>`Wa %\a>Rr(.Y(oPKjKE8sLoZh&Zm+MtbMr$WaE^F/?7Ie:_NV+?iH,Ff$E8lM/>KD4Q]$*P/6I<&[9`lV-P]3+jqni(F*ai4h5O^(fZV %f.TT3HmqZcd#L-e^(ep%^O`Z!2h'/+ZC65J(C>L;UE`IL2<3VSYKf/a]qJ)'G>P?JFj4Ra54aRF$"0e.-#$WnV@pOucEBC^2`B%"rss2Fl+MdWJ'O %HZLqX#7@?MjY^gn@"i%:s@`%DOisDJs(-P8se/(eXN_hgP?Yl25_;g^^Pib %D8CE7Ld32?:U4-I-Ts(N5qZA$h?BMU_ET(/dhX"5_4u@&R&\)N[8b@1Y=%e%P)Ok`14P#6M'KW5I4SYp;&,=O5A766?^ %:l.YWc/V;YK,3iTb*7+>ORoWl5ZC7A/fuZb]g2fo\gKP@5qI8A$3r1ui$+bI'Y6+YHW\dARk0s;4I<[\(.9;$L:"VJ9H?uR]R6C6 %4_-fDPfd6Y,EVa,4Mepbbi5"fu:2l4>;A1$\EZ(F^g:In(Rn2_lUI6r]&oMXUX.r@nbu:0(Er5LoY/s0[1,[j+T9?fLp#C!1OJC3H+5sr*k787"O:5TAHgmE1D%B3 %iO%oqi.UIu\e\qRP-d$!8_Y<1TcT-l$-6onD?=k5K54G)hUWS%ok.NX=7c!L6%C8&%Y4CTD-%Bs'<'Xq?%8kdC`@nU"+-K9qS%a? %"l8"QR*+^n_QI7<0aSleO6n8)Og[EWMYPEg_s+eX)t+(gT(\(;5#eC,VkY4h+3,:unkQX3-Rc5U@/&:URl(1W*mSS90??-Ed-"1J %Y`nR4-j]PC/8ONcibY=jEI);?a6L1B#PsTAJRn*nHbgZ(jUs"!RgsJDkP)"obb\V7ETdM\1spn7Os?tI&%sVW8)upq"QIL8FS$CK %7W`q,.AF]aP#UbtO5A__qikjn\YH-[#Em!DpVjGB%aF_P+:akg:.SKb$#s>uRhaLG@\sS1\H,pJGI!E-FdDs\>[H/!%M1V?lkVg' %((/O8;g2o(I/8oG(kU":@_o.Im_XRgc'5_4E1GLC[o&jnPi%L#%A&KKR+5DbN#nNaB)5C_:_?5<&Qk.TVktMbgM"g2!IHaK+kM%a %We&44iI*dBWs/tDi9=I'=f(HI[=V6X">0'P'/?NloP1>5Zl?>d@"7%@YPbi*=0"L'p?DC@b3GRUh[+Y-'P>Uq!K=2l:7-W%LaV2o%U7EG0$SW>lqdk[8F*ae'ZU39.T'7c:+tk*7_@TphL4DU=d/\3il]8WQlC#j>$JkO%JA:!fmcr`3\SN"I=&JVLNoi[U,0_bBE$aj;jmc)(b9Qc6"pI3Ld)XI=0PYZ.5[)\F'_7oh4QffX %G3;>iY5pb]clHm,^(/hUBWCq(>e0V^bj4*Cm:FJqlGg@?8:N^%\bpEM&@,cn(l!mRZN4n.nerirbY3/I\)6F=Eq;)U9&-`^AFT*M %@/DJ^^<\H?\(e$/-Ym'FhkC1h]RgH[62gVXn]T0jgQMndSiiZIX3t4`3]X#iNEX#`14"RshicNZ.AJi1QUeCTRh2eicc(@jcl+]@7<4(5M3[k*6Z&'VL!464q"FXbmnr]I>FnC2\I3W$g`kuQ-(f*DDo)=$\o.f %!WL'FOfW7j,NeOsW^4,E&H`0&Od!6`Cr?`DLJ7>Z\I3a#AfSRe!?9[B-bf&`")PLG1!MkA>s8%.+'.Z!bW*NDKC/QGM%-^:qOd>`;Bo>bH`0 %`X0L^?Wi)&!B'1M26#8<&`_A;=rBF+!/L*E,'UW1qoO#mMXZ_"a\8!U&8E,g[t@p0E2@/f61mA[#Dm_DbCmLHCKf;?-!G20GU3kqX!Nac$N %&6o:ns/=bpbRd6WlpTS%W&2`%KX$Z?GNOTpqCp./B#g\;Qu06u^!,`lm%)oVVUcSWs=*jgH?Wa@nkG@)k;F %lc2]?[U:HhrJc!G&_q6>p+sJ$Mht+Wr[dgAE:taa:D?\!F:OcOUSHO9iUmW9ffCWBfB@J&^b6e=mf*Eq[HG`>/'s<^g:V9W[<>'$ %m%a8r'>>'II,oW_#`G6dd]I-C]Jdb2Dh)WVH?VNoZJA;hLRC,&;'nJ=:VQ\(H&&E6:aR5ed>-WH"QN3mr%e*)I?CFGk6TJ=o9?J9 %El^-MJPcLGqC%M\Uhnq)/a[sBA\5Wk\pa@JM9jOQC"ak!EMO>tU&4%s_S[K]h$X1/ZkR!&u %;r+mU.Ik4#C`9l&H"Zt%-X\b\qQm/=n`S&jtRf-%s_K!VA %oHj?]4rS'IIpp!`k+39HB"i'QHQS#\3nS=*S:8[7-Zu?-81c/@0,RbI@kY5Y'q5lXX9g6:ck_o,rFk9C">W_E4JLR"5R"k$Lano/ %":YgeX4"2fSY[&r%#f*^lm%J1YR?$*/+[5SbXq%T;U?pdJs4VqUt@]\.OSf7]a.V1Op3.N9WN54GJXnU;K,P1N7kq\JF>mKe,aL6^(>Bo5MK:q=79.4Vc-+$(u.[_IoVZjo2i#!YM7SFBD[O!u:P*rGRiQr\I$FW.SW\V#AfpX5'3 %.tcL#$$8nGhZJR>W`f?-(IbbX\`mr)m+brV@'!)-r!o<iXLMD:;!BH\Q3*p$n^6^t\3+bp\bMkqq*$6T+ZCL[5);PTH#M"P!oL=q?e1Uo"^5F9Cm/&\ %DRu1cP*/u[=tCi)c>NPp'U=9CK%+fG.&mjTc8sN)puAXBK/fY\)l0DL:ZaO7TW#@V>UB6s81p6oYVYjji:>#4`1CQirDkBCTd6jt %=*L#95$D^M^PT2sh)kZ)POjE';\X8o/>dg.bps-tb_WB7H6p,B',0[bS5i"DMH*#(_c$jmeKs'LU`bh5*<"(M4t0D978,9%0D&72]HF>L %=J.T'8YJd,D$na2qu"&Oe5M:?GOnr.M#*,[,*5J%+E:YL?:O:,++]d\*9'"shVJ`(5N%[Jg=tk^?G#QBd6XtJ^RNP[Ljd,trso'^ %[lOe<7(Fl<:Zg=XQWGJ#Wro,:>]6K[%=Y).Snf]%mO[$TR$&#l]NV`S=a-h;>6D3eOulR8:\]+*VcP^Er#D0A!>hu4/Gu3=`bhW) %W.a$$@/(T6ZS/#,a_D1U\9^hMWcr%2e4sFd#Wsk44]/ZVps`G$WCP),l%ud]*3t&K]rsJuG<4R[Y=uIRS<0&K*FHn=b>6f!A@&b(OmjDm^&-Wt8c"DF6oBHn;GdV5omn23hlOs/275V2$l.8D\UT:!FEo(eS(bk@m-MUbb05T2hQnp0nZJ6h$bJ_`!kCgUAi@G2aa#* %l?!BTE&ETGJ_g1UI2!(5h8/2Cd-^iN:>E\7];[k'REXK\nACSSfXP0Q8(7l0>JU!anC]1r8q#`lU,j1j*&glCmGK+8'Ei\Q`c)In %&:!dO05:iN?1-gL[:"Cj`V`h_YZr9BoJa%n0!d1("hN"#P%Id@[[i$KhR<=h/cfb]Ph;\(B=iq#A6n6/]>pQD;J#kE;J"29)D\:Xm*Y+5Y)tAf,SiI?,KKU/@sTXo:pUX$4L.1eL'E]FJ0=m6qfaU1N5\I<@=0B\EF`qYmu&qWpYoE[ir% %ULf_4?d;'_@W,I,[MEP-2Xa;amdqE;-"dH02Y#B-ehi0)8V#1Mf]3qW&9[(RcY-a/>\:Ssn3P'FN'pk=u'c"91^E.4:P %X1.OhTOSJ2[\oW\ldQroG#>Z2r=l9@T@9kU&!V@tQ'"LjrS;EZ^!-TSEq[5%0.Epkk6)rdc0lP`F2VG#qqC$c,LL`.E%T6-?rpc, %aS/41gHY@5p[(W1eT=O5%NpP-D]TfP6*sgm3qb^)2=rAcVT[fD%3,9i2b[X53e-X6Pdq4Uc!O7$9lj=JWtmb:$j6H#9ou&;cE1j];$8_5':@m4W6LA"eQtf %c_?/T2jl(d#6JWI5$Z"lg.Y0Nl4H^9mB`4BH-U+n3(\/J$sWCma%H\>)KHY$f;?Kh@MXT1T,CG5ehb[MjRQI^VH$s%^:sf"/+!Mh %)N`@VCcP2UpQn-(2=l9jhnO(XR+=MKO1dUA"k+CRq/J;EMm!fee$;N@::]^!3Xrl%=HT^I9GmGh@(@P`%MM;j*k:#IM[gCi`L3HA %M`HQL]9#.G<^3&hr%@?6e!?$03r,#/7g`,L:+f&1&kRk?3&U"t]9"b3P4tEYES_]e#ajDW$Y[YT$BD,J/EGeY@^S0q@[[a&^;JO"*Wis.KEeIT[R^Id."VSCJ-5X_Xn'eW0/WX_"!Oimgm!d\L3YqP4mc0sYLkC8;X2"hf]BZ;#)m[rNRmAWbK:Hu&I2]mZMH\?oUQ2XQ5jXapI4=Ak(E %I'b@qN4iJ-MZuG8OCMkW!a]l@7S#+aOn[=.VFdmP;gEbkMPM"uU[P%ebiMXBn"QJ/F/lQ]Ir.d.WuX5CGA/X"E(o]kC,\FnREVhA %88A*_fsSc3g)\I0jaaRa7OfjjG$qEFdTX(N/Xp&L#"^D"?:i3rsLTt"B.;X:]7!U2hN>/.q!11(XjXdiS("\,dWjl"0(U*.h.h+E %_/-ZY;lDm+W&)urG'KH-dgQ7644RQ*2^@KM[9,_dgG[%t(p< %&!-/:C3@H=_r0U$_a;19pu0+28A5KA35WSi33c:e9h0GIDm0>]m_8D1Yl30?!f#[[5]:?pqoV$sEdVk%^+RQXUu`FGri+QmI0RI\CB(g!FNB-+%R-A %bAb!_#=fT;7Fi9g08,O;9f'F;I38SYM`RllRmf2_+P3;S-TpbX:OA7_E>_lZUCs'iMdY">GV&tK=B/`59f"Q$?p$*@%,j0fSFp9n %DoZRrA<1al6M@=6W1ZFe==f4+qC^2/DT?65SP1%_lZ^6cZ]RG$<`2Cj`Anq.?EM,hjlP\h-IYB`MQ-_M9[U[rXF_ebd05&j$lt9h %eBitn)t""lQWi?P@is1LPqbUQH\MgQ'7,)`[&XThQQ%2moedH+f1%fbYN!A3c4R4@tHSrsj!o'/MRKnFW=">9iR %_SNFXVJm)&Bl%^>K>Kn`/4N#e=?8$[RZ3g%h.cKXH?7/O5<3?$Na9Rh2bl7q=QU5]?R]7^#iu;l@45A.X.lOC3L+`$VqVQu(a3AR %AYti&a#FhQKPVQbQ6G;uZU(2LB!5c?jP7:MP/c!eoZ6?]Tc]"WdJIbh(gXm]Xqs&"_S:j3a5k"oT]R=S=6_33fWEj8q&V:p;# %4hN%bWh$LURHHS260l%PPOUcuek.a[^'2i(!PJtL)fT#HY3-tW%Y.UYPO3^goD+[4Y_j>s6-k7h"/+@"LRr_"C7Lq^U!8oubT9c1)8<1!YpN_a'cB_@0rf&dJK`&-c;4iilA=ID^6hR!#[0CSu/]ECea9o9C#XGE!TRM6_)/r5X+RM;7@+,7F3&M;@s@Y6\/(s03>pFU]3TUhaB^Y;-6*Sl`VoEg%Kmeu9Q\pHD'!u:0#:q-"E]gr:S6$!IG^\N,B8TNo0*Z3*J;<^ %M3c^XS3-(_57'>V;=ru/!W4dnr>2Q,4RXZ5q;WXoGZPj:Q./D/7CH>(_.S@qS>1QOh^I=]XD=,%A\%gPU-%Y46LJl8=]:\5Bb?.*oY8tCF/Cdmf`ZrlY`oG^M(76+7I*(b"S1)%rA/uYg]'\5E[@S %'W96"4q]Wsd&m.\[a5l7CZ7mDZ3(u?4E;=1RE,DBmLiHdZo^n[.YC5j4!)$fr"7CFhu+BcA/6`>KsB%cPJ;cY %b%DM'OAiFPVGj3.9^`\Anr.el=[?DT$BY1>\)Nj]([:u_C.;Vg!TX`q3?%P&pSYl'YLFmF7P27pqueBbdZ==f>d(WqMPNhja"@ZP %7:X2nj5FAp';cg98O)6VG$89tQNSOpo:tr#jnnqbcY<^#-r&JM:ZY(EAgK=9I8m35`u&?22-`Z&UXQjd6eHECEq9R5joQp:@."Y>gV\rdM)qkqoMmHLIRPaf\qpViIiO*i?D_jYtoe%Y/Q.h %cm\HBj3_^,He;n&HY?B(W,OXQWBE)<49T!7](XLLnkc9KpSJJUaWBSfH4?Y\gW:L;o,T]k4Z'0$gn-5HeK.o=*p3&E/K:r6arY/= %H]4a2gW:MVM:..,L[AU_A'VrsIA,'T@@)E>63HA(n@mP^0/R'CkjfWd+1=P\i#9Uq_8Z89'aY)a_)NCH(%@/OmQg#b/b1aNGEce? %Q5WPOYD$ZhQC@FVB@[a@hbo[;Z*gE9U\Ph*.QJ6NRZ`^$h=U!^h!:r7(%RKQkh_1&Z8.]?(]m&F%qS^1#Dg^k&QSc8F2/(uk^$r;M)m]M])]I]b%f?j+3k,\Y8G]: %K]"h,>tJ[.7u-D@b=Xfq5=/=%>Uso>%I3.rD/!-E\"f]K%$'/XofAend@kbk:Iu?7i/Zl!j)[n"J+Qqb5/Rf,StOIW]Vb:[`TAH!1Hf!KY %eZm1ZZ(/0*n7Q\0O(k..q/$S2V+CTN-YshJ3_UTG^4OOAJTsH=/4JIkB6p^m9$$ %ZpBCqh$jiqC1uo)-mR3<(SJ:e5.u-/Y(+I&k`-Zr'W5RNdr;JPU:A9fGE<`?&_7b-h*GeC`oRpeF&TXFm7hojq>B5rgM_^&]mMdo %*Nif;als4ikudnO6r&N>r5pZor_dlZR_,`0POh'g'7ZjAVq'+K>U^G[QVR.sYA?';?D>dB5P^f"fcobZ8poS>A/_G:Be&985N]D4 %oMKXShac:]gV2$5LP(;#S\/=&#EfH6_89l?Bh+U<=Y6$4<6j,"V,*(gP3KbRP]JQS54X6GMDg]B8d2WnPi6]b@f:0$IljZG)TidtK/F %qWYjn.IA.V]'7(h];ROhgi8p-`"8$"P8uOa'N!69[0b9H\8HH>6*n[-%k[)8)1'.R:&E#K^('"-M_$hBdN2pb8;cSN`Wf8APKUHF %+;SG/V0E*&jHiF-L43m/MO\'K%PA`/(J[ggLkZ?'@-CA8033G4f+'S50t,nq\N3Ktm992rt2K95I92&ZO_4Q^8+)68dIq %JaqQdGLaR1+a6W@KZ=qGc]mFRQ[4dZgA-d8JP@f^dBLmq:3GGo]U%a7GPETU:'?lb(ceP`SctK40S&_EFC/!!3&AS,- %TuN`/Hj)1="iOE[i3PFkmho@2+ku:+$1V*?IoMFCB''33-!E!<2s@:0"O;"O7ZY!+Nuh5K-.q_MlCE4Z>5im=Eq],g?+CBYHVd!i %)Stlb)PNqe9Ch!nI_oRT"kHj%,T".n^JnhlTd4P\,f6da9.Xr5D"KlM=LQtgn62g>LkWtaYn9WB<%aoai>gpkUSHO9iUmWG6gH9' %e4;T-)n0'Y7p3csS]PSZ+D;@O:&KOiXDFqcu5g5nSOqVq$Dq'0o/\+:i/ehP.\=MulAQH;r`G,=B:)%?u=biOr'_`23 %*`Uuec:Q[oM)8rJ[C]*:VRf.#`qNMMU0sZ=!o,G&Bt1_'A+g\ef^gYcALdLj#Noi"U%^>1 %9fTg>OIS(XT(!)$mA@f5!HFT.pire-08pGG4G3+rM[fZ4T?ZdLCN"754AEcOMA#5feQp.0jL+`ne* %_fp(#g<2:cPN[&\ejVs=*gLO>M?s)cAEirX8XN?cjr4c,l?bhYIUJXU]MJM:k0afiRp;[,]ZFU,".IUB"b_gND)G#-W?a;q%];!. %8g#\/a'Pnnl.sfEK^&+@*Q%\A0V(D%F*Yl83Zc])NmnU\p9l8tl1>RYb[Cp=%Amh)VWp.# %;5'-K>BmF>*uQ^iH2-->Yu!%?p*IGBApCT89o+Kg+tps,j2F_QqstA`;F1_7HeDnJH1>Zb)7@NqVV*fF\t%Fb,oWN"TJ&l+P`_W\ %mN9iNp"gBs1@Vo;&S6-"1?FdA41td5OTc1s:UY6hn+XW3bPmkYWs6TqNGq9C245X&`7MH[0EdoVb)"Q^8g3dY's& %M\-%YRSZPWJgJcAB;R3(3#LqRb.87N6(u/n#_`h9A\4n>IK;%YYuAmS^j)cdh-C2@qMaOYUp^NZ=]*'r#a9a)ANf-5A'gSppeCo' %pb1Z^:SRf='r3Q+'p^'.c;MQ(_5DkR:P\fqW5D(9+hgc*em3427(Cj^@is$,7"*Kp_U&'5^*$5aX>^Qc/JY+5/-L8<@Efp^n`:Wa %p>E_qA/9=o&H\3R1EF0M/01o#4f8Uc#%$FDhT31l?n'K$$+Q/_\E*`mWgF!]*.%HbVhZU?VA&:W4K7/c1PofkM)eY5Gq'ETYTqg= %Sk?@>E=&t.@5C)UQmR-Zbu">>6YG8)V\ePh7oR&.a(BK4@&NcOl1S6o>)?Qn#J+..:=d-k^-r2.WZ?HT%I280NF+t;Zos8==ndGQ %X\*NrlK"2DCo4ZtGDKK4Ycs#P"p#Br!>`NEObNF[ln0_(:&oqcgS7dL$]p8M2jJXiO1,d;f]88a^/;:.DH*mouS,Ei3j87Hnss6D6`WqDtN6?hYedjjiq\Rt7*t'?#&q+L*F`<:>f.csGNn<:ATVA&J%D32*Yl2`n+nRKi"_X6McK*qaD+hN?PC*@i6e[l8gdDMG4*oWNK1[Tsu+fC[/JMU]")('dKf_ %e*p*[W3-N#gt(;DFQ>`=e6j=BX0,AgC'a8A:64Y&9FC=e(13Rfoipa"l=VU\*p*E=/bH7Zun@!_3F8=S,kI$ %GQ@:$:SNiNlRUV\6,;YtI0XHGa-=!BFq-/sqf0o0:,F*F[3*_g76?_kDa2P1M$jOKReGc'iFoiX':O(XO>T;IE5J,lK2oeqfYqO> %9arPE)4NH+Jhq%;T\thj?p12iooZ\S:r!<:UIa0d6FY:XW>$cYoZ:<5.#]OH*co,C6EtZ`GMpSI:FM/Lpf+-hee<5$TMTd9^TC&' %WTY>+5o5fkm?E/<^h*0R0\'-uS72+@?"M=mEl`!/r`PgAJ1J7[@,+Tdk5:=15VEJCDVsNsoEgB2Cnes0oXtS=\ArTb$Au2S[,TGi %"Bi:4:7`T/hBsQi&%_t33hi(dGVkH;e=Qp[nbS[0^t_BeG'i)d*R9dC*l2XDAR+lfj!l?F>fK-_+!5$7ODs:0pZ%J!-[C@Ubp%*ol\gIdAJVe\]*_S;I'l*>d0t(Il3LOR %#]80Y1-.b#P;fs>oY99eS:Ne*Z3jAe0!E0''rIuB(?'ieQ)3X+6Dn$m=uP[NNO^Jb`XcVb-F0J+!]f=OFt\D$i(' %\5.LYKtjM3cX0O`q#:,Jr]qFag1Uol%,rffo3Qr^^2RT076o+fr=PakA;uIk3Z7-]C='ep?6@mh-j7*;d$H2*'-$UpSuG&abH\RU %9*DZ);OKL,M_5O>WmWZ^EU6!Dn*IIe^)4j@,PXXB%_V@?IPc+nV\$`=q2;7`>fF_42NMZV/hFNgR.o/ch\,HhlbQhlKRJmMkgsBQb37,_"$Xb8'k>UP$:)G$/N,R8Pj$3>c42Qr34Jl>'*,qdIZj1rcVb %Y#F<3=5'U\K_i)YUq\b.0AL&[s%%nDdNlRMBu6%t\gbgF:-YV-G\?lMlXkIJcLCh#,gY)Hl2"^@U%C1P[F2_P\g]9=R)`1^,X*J8 %PI?JDi*'[BHFo5kJ?b[tSW[D7#pVW8>/kk1DgNt(;NSn %=H.rRp,9-C_rl@Vg7J)35Ur>K:O/m\'7a_W(%B^qFBQ8Y6iTea?06A,b>8dhjrB2M;`0sb<^Y\dkk\48A&!ZZGns2N1@BM1?-qD% %N2`oH03gE-Zn[sj?nj5)41kA:PI[_@o2EsRLn5Z"1K<+Ue3`hO-"%ZPYqF9H1O%@R4+#"YfL[i-Xs;Gts%m2c0O^44KM[ZN#nXQ\ %YhM30:=H]h$du#;^kLlhc+dD6Mb++Y9h`(X;o_Z-`:[2lF%$kg.iBSb$@YcQX\N2cf&-".^.#tn:F*Vq1#A;:mX15g" %em;:M\Zh8J,o_E8_t,n^LMoW^*>J5j1ojc#^/XgK2D-.aTTO"F5CG%6S2K]%ZWs0uGJL %3?Zq9lA3Wn\0ZZ;(g[bu)1+QB+PV#Y-*< %Ydu4$"t]nqpRXHEThkGerTP%k,X7&RPte>Pm6^B!R\gBQeUIn=5/H_C!4"7d(Fl?Fr8@,aoR9X5,)^J&"6D/EcYl##-!,1DL#f^9J*2o+g1HJ.,X0cgGpBF-_P-BWBk$MFmc:'&LY<%aQC??CJFCr9HOW0L[]ZJXf!7OtcSgl>M8\fBdS6tQ['"HFB%i\DMI/f`ko?=CUgLRB/>O)\9Up#m!u %SH7fMPRogr-Z"](811Z+_mq+SUpb*jIGdU]Sn:QeWU>O&!!@@+f/1FJ$m)Q.-c!DV`U0UN%n9@_O40&+[2MrlK5QdD.Se<,St%9j %gOY\S_=op*D4ffq,;J^\!FhGE`^#K3a&&jrl7l]X8D,_nma&-+Lhaujpe!Dn#5si<`]O4%TJ&fhh$0i! %G6U=9,lAPPh&-br,3$o[dWK2Q)+Mq$gpBkelJ.-^fR>9=D'9kMbG-_%'8:8%R&@2_Hq^_5g&")-2&/2d;6`T>&IE$9buZ;,h^#MA %cP89#NF$\\V_VKQ@/ja=NoKm@]h\'p#b\#l8> %fA9r]WBpiD*I)Ge$/a7@p>(-9rjiV0^`sM1$:6Lh#/m;hTnG;.+s+G,EDTdN]T%pi> %HZ5h?2C=>U'i7jgSJnn)rj9aVVKV&2@r$i.&HOO\qfD&:*UNbbp$U1>]H+3C_"#^F/H>o3)AQp=ZQ+J@InDLKm %>h#28)630&p"`rNb7'hf,8Ifh'PZT6-$BN"fr_VKL_``P6Uo0efJr@\@ohVmW'+h@2akqkUdi8EB7I?a#^nk\JIdqeml-.qD4X4PF7.)?qYoqrr":4_i# %ME_8!GDa:NR1G-g6Hp48L0%naKUNX"$Kt1:oqrp,_7@3nrY20a.AVE@Z'T8L-\?;amM)eDQ.1N-[]uLfBo;5Y/n+O@/Rn) %>eL7E@7REKd25fmO/.%\dr&?TGW6IsWLU(;%lXjajl$j18Oc]i4_bl;#Mf`/fn?=[*S`j'rp-icQh=Io_UI\939PNG71J8g&'&fX %=NmQub/6N>1q0%J)q#)Z[2md*I7^GI]fh%$mSLS[3Vc8#SoEVu(qDBpU3]hf)5JL3_:lP(pT.NHFr/(.%Y6Hk.:%W_+Jq5R^J+cA %6a6"=cjdY?G+:nfF>:f7qWu%FCo'4VMlESg$bHo9b8sK*g.4tq %j0VPkg`#bt!0*OQX?1j,aB24dE#_p7OLLfXi&LACOL1TEeUnd#KCi%HX=*^dV\?A-&91tB^@P2lfF+-Z1+.&D)Q$\H=5LsINCj^OGb[)thB,'m?lb5C'UOdY^7tOPj9#R@Z/E4M&:aRoXmdl?p#4^-#<2He: %jMkJ54B\\7];TZ[3A::MFDFQY=N#k8hpN[5ctU#nZm<>ZWr@:K?=6U+>$($e8p%3e+C,SM.s(iF080+*X<1OAqco)%;;"Nqdd^(6q17(,-o@*lMCT7+N89&_kf=dgT7"14olLN"IHU$n %=CAtArC/+EmNBu)E?Fue^>YDsh>X&*'L$kq5P&Z6@'L]D5'F0fJH`Xmgeq4l4f>g6;eQ\_0-@;"CS*7X<05\Do6XSbQs#d&KN`"V %.LZ+IbH!a0gp,bmQ=#1J=L0BocDu+tXj4Z:b5N2][MG=/(7_F[QEA,K87lXW_9#[u%_^E=_0rmtX)+^#)pReFBY9cdD(?$H7Mr'F %;mX?>Ag6F>]oO4$`f2ZS`_'ir+Ym(*nJbY8C-=>C@oW6$( %CF/.k_>D-3dj(ll&RgI5U`QcKq5`\ik\UYb79QLNYBDlg$l+(AB,TUkIDMej:C"Ra$JNmH.=#54al7FJ]ntSd7%UmP\u_O/TLVKkGj?4lY-M'jW0_9fb8F %887<#)e_G0AjaPjf*:!11SlTO$d-?r-kBJLo\YXAV@GgoTt^oP6cHV)&1\U6<1Q*=45!D[#C?f-8I%E!0jqm/oeV6r1r_\X_5MD' %m7PQq&o(UH_YjWaB;B55%UBf7U\J!:i(RH[,-OJ[etd<7Tu'lh3k>ucZm=\@'\Ga\nj?D/0%f8cD+N,;(^!eb3GP/V1V5$4*Z'd- %^69"?Hmb8e%;E==GA/q1NW5BTf$KpB`Cs^`J\_OU+aPb1"+p^CeJPOJY<08j/Ha:f_e7c*BAM%7K2j"On< %gIgIY@3"3+h*>q90M(S#VG%u+dA(R9bPTS*p!13h/cRu89MAM?_s\YZFL$8RCkl3bi%BH[FQ3GKg#[#pH;fU-W2UX79VT<\r+QBdQ[dq#$APeJ<:>sl,$-A?@D/<5t454F?M0Y2ab&,bL"5BFkS5H+C'o]I4fj-(g[ %%2O[[At?OiMZ&2r2Q)L/A8WdG\3$J<%j;<"gmuhZ#*=O]m`m6S@l\P0gmq=/#=s5t]=WZcQ9%=uB7P9r?_^h2cCq_VPdEF/J;/_n %(:)ZkkqX<:p-Lp-&M@4=ci%!7l2ZII\[Pf^rRpgt")4U;crUuP-QTZ:SBPUR^@^H8oK(?F!sE&% %-'1i5Q2P1+HjgEN1)FQNZ7I(p?+8IHr#ipJ#ER]3?!6:M-G#^A>OW-M[WRKfo9!\kR[S,VI:#NgT^D"[T/U6"OHYf0kiicK5Z?,` %Z;'3M2E$$Z4kGGVM/q!]qoQmcpcpkel90Vq^F@=K^)gNsCD)SiF44',bP?#270P6EYQJ]5-Z6Q\.kn/1W&P@-N+32X6q^u8m55N;at*tr>ccIS*- %Qq.0:SHtL43C!K;d>+UDe.4_WT?X&rA/h8J&HLCZYtI)<#E=uXa@U&i:Ah(tn'3jqnCMd_%-Y!68?#BhdGX\J:na_Jrf<1r>^#%7*rXN"7a&&gDX;;XO,h&itehJUs:_"K7$HUC$+ %J']Hfei>XMc&:EpFriX?Nm\B6d7<IBV<1-K!ELkNbV6i*]k.ZN<#e-.;2=#B$D04a5D@W)Dh%#^TCqV["tK9[7VKR?$RnA-<_>p%G;k/atA %W!GTFICX]1g["RK;BKr48$+\Y`Ac@(=imaY/@B(R@mm;=b2^`X>V %9<]q4!Wd!Tk<6bTfC'=CKbNW<+I?898:p*n]\bsF\01-dcFkWSN,$WSR*q0>NimIT#T$$gX8]]69'soj^-V&mbK_f6*rgj %?=,UGVIlZC&]&'1r.l#EhT11=+Mpe3!Meg"&@&p(WZ#Y %5$C6H$b$eP?nbbm%1\n"\$,17/#!b`?Cc%hp`D_97C+XN+o%iTXT4b<`Z#E6dF9sfR#b;+n!K,;$-4\WY7Yb:oT.ph0,LYjQ)S3s+FWMH':oUDq;[>8lpoY*n3'7<)i2_h28]"bI_Xt'5?Ho-=42C7&11rB!bd:sqj %GN5/F9E8R?R^npdRYngHpr-G3SL"("1iZO85)G`UG7M..W^Pa\Ch^pHP"c!&jKe##CEJ@5rs6:!!H+:S^_nZhoBDdr]pWSgfB'*YLlqbdW&5l1lJW*'6aLP_>nB^6Q+M\Mpi@% %Zq[sAOZ"?&"?j<[[Da;l^9*-MLCg)c,H>R\Ta+G@bJX$Y$gqhsY(%LtgM.S=-???HP"+?m+2\F@N%W$H(4^rB)>]-EkI8g^BSue/ %GqCp1C2B_1go,(j6$BB,NAZu,..(k/Q\!e.Wt%().3/a[2I0X5,jIU:7kT]%MdbQKN+tTcB/;*oE4=cP&M9oZPf"t.PM/AR*%7UV %.HRc@R\Z8@f^2nH1CBru.(aT.EY4S4Jgrt)eFc>HV3$PU_2dS2Lg6+b=?CbP: %8-Kg.?R`!&d>H`Z4ccSoalbs6p!hU,KA#Rl0i&"MVL>5;_j""!#k-MXZ)WSMZ@+#nDt=/cc0)PhHr5N7p%]B\'@86I);Nn-KNmA')&tkb_[a?+)>JjLUNdO=;&M/A@]1H87>9Gk95D:bN*obiJa1hGM;gsU %I=@A`Wc7V'4'k:L/aWeo+\W,>Z*$8_i1@[.\24A]2T9#\$4>%D:+>*nFKkBAn>Y#\=W%,"a$0.1fJJ(TKtf;>LE[c:/1'fi@H[Pp %02r:+;eR),,a?lNp$F^DXA_aLS1KJ8e@;;C>L0,lS;$b*#'ci[5]0Og6]OJ]@as(*qL4g+htqOT\>4&&/-7=l<'rTLXsfaZLYZ&c %]4aO6-j.#SBkm@GW3b19Pp<..I=iui%dufPG?6@-ptQcV2o*,pi0u5!nhsG1#0ehs=LBR(%FiMBB5Y5S:RGo14ghC8.+;s*jn]9H %(Pc]M9Hlc0Ot)I`QEEtXl-![b4*-0fh.@E8_-r,;==1OYP8[+IqjQ$]J'j*iM[mk=?c":ikC73brGpN3&reW_?C#>$QKYH@goR8E %T%ZA`N-e^5h*6AT#-@%f;7!qPqd+,jQqMi=__NI&r(LW%#PoPIek374CJk_MBcceM2MBQ2e?2biU2Ugbk^'-?"#7;]*.09e5Rb6+ %A3e@g]fc=T?Cm3+4LKd:QNtAb'tl`_:U!fs_<-)D"2p"0BX9MFeR%a4[u^;p-AZn#a:c*!6^.,L2O(O\$H]rYJ,\G6Se?AG0+W!b %5'EW7reT"=$`40SP`1?^akI5K%M'+0"Z465gdZQ-^:RF2WHlg3FM(2*8hH/!=0[sFdcFi%jhfrW1stJn %.imB_&`q&3:WIq&I&$jRh^5pi[MbL-0Sp$TjoIa %C/=M`5rEYAk4i9G+FtDA:8,gVG^hQr0@67l@Z0WKf);0.HF9J+"n2[E_2!b,E`otm8(-?d80Sn&e`8**p;80gjA.r.jT7Vr)s->j %V\lqVOrT*Npu*0@I]qm2Bucp1G66[j;7Y^`Bd+G1[@7VEpU)<<%,g\;LQ+]4KI\@(YS#u$HN4p8V_5.df]\j.hGIb:_#RB#D>=%< %4lrDhPVs:[R)3-d'4lUkoj.Qj"+l3PIn8_mT8+]QRV7b4m[+lE"=*UGo"4ZM@%WXWT %-pg_e0lBL_$#ql76em]J7k/4jB9.tJI9<9F7?Ca@!%_$,9!/8J1b:DWKJ]Tfqq>fMj.M"[QpK10qSDlUGOLT&]K_nan0n>oRq<*`-)hq-!7BEc %dKTV]g8J.".(_>&,4Qo^CXTmS+Ib(\QIp,8OAi64-L9%_W;\R%4Sd[)g;iV2eB'PU.7g^^Q8TjAGXRhWJOBnC5mZnN)LZdE;_)Vb@=[1KD#K^H'h'MhKn-'/A)S!?""J'/A)S!?'5RmDpTg[KOi!+^`G]bdBmG8@2D9N4D^&4RW*jj?/o' %[r^q>iaZ.2VIBc^.U.n15LK47UTEo7nYOfa,\Z+-Zlc7Qd+IJ*F=m(W,Bg,f&ue#oc91\38^JEV!'H8:o]&[.plD"Mr*e*ArSD!f %r[i'[0G/V!QN/o_+BA7:]aF=[IIA\]anrU\ECZlg?")0V;'`p'qP%G/rjV+fPR_qCrK%>YAS[]h\'iTJ1>LZGjf^"HXru5[`*Do` %P^oE'h<15n0]SVb=&B$jo13-:f?oasSsiTm/G5'[CS'6o!gc=+2,B2hA$lZUY'K\S`M..>)CQ;)2)MJ$$u;`.b!`>)#=.6SSWXb( %"uhguh03cnPm2l,Rk]"JK4oo>d7?1HbPn"kdb;%6")ecgl!l;QhCYBP,I[*)_ucn5al_-Q2Df")CCZG$i]i,hAgIK%9?g< %()4P1@2"NR[n92/6G`'J#ppA*f$I4;;iq`lRC]E#ee5J>PQ"u9cAMYi"I&g0HT+T8+4%6e,5?8uKE>@S+C$?STtnrA"AL<65]V/E %-ibXj9SX+DPF]I-LVtBPjt[/1>E]oBLfIjW+e]YMf&Z<<"M$DhS8b)DQkd[5=?V7gi4.Q$AO;p#!!%CFJZmiF!76@%^;9U.X7VEX %s.nJHk/Tu/bl@a&keO`_^_,*!!*ToBFt]!,3b!s%I"i(6d3`SGONFoVM3F?'0>aT)="kh$o##6OtED@S#r!&1.28h$KlsRs,03`7ipiM-r8C* %K+Q;(h],hb/=6?=)GNV05a%)Q0u_"*/X1,-!iHRH!%6U^*/P=?Fe:pgBX!WT7(1a>I-Ao'5/iTVGSq.)r4Cn.D:PVItW %T4LZ;n2$]@=PUF!ZLZ#lc'$J7cZ$%D,:ol_ZR%-'Z^U2=$M'-\JhH58Vuqjn_p_JX3]R">U8uH5:^t;g]+n?JJ=(B<+F8MF^=,=M %RW$fVU!ZK?&BlE2Abmt?# %M'55fDkGE^0FrIPdZ%Ztf`UTe&#K6=YO%J^p.TB@Q4Er_isp@*:]bLdjGHs %jjQou\#h#qNJU6DA=T-_@n=#o,jO.n4,S&N(Y)LFs0m9=gZ?0(Y3#hE?j7oF?goF+cCG4cG>Pek)Y,KM;04MQ)b5:n%Z-r(h[8OoLI/^p`&B(f*=_haF?fP+ %a?mVWY,joCj;SUTbTpqYI,CT$h(4-N0(hHr2D5O8Y5M>a?tA*M(\3Q^SK*ZJ,96Hl`bZaHQ3[Q?_=N,-j7r&V[eNLGGVKsV6JjFL %fH#'L9OV&A`%'ZM,5&B@bEQE)9+CdVo0!T8)mglfHbu=l1Hq\`Ur'NZ$]Xb(Pjp>$]<"c5\4r4GRVQT64\bBS0lH_!eM%eHi>.7p %Ep-8QmH>665MmqC0,=$RR2pD$U0qL2XU<@;#ug%_%GM3"4N,V&hil7TEg=0*F"2/J':(pRtii:?gQ:uDPl2]$i* %>[Gk7FD=V`hA133m-'HF$-Fjm- %8T`FLE1=>a9h3QI?Dj:<.C],:+dIh1VE057>)fr1*o3VN'R"feoF[_KDS"N\WX*+0VKe9&)CO<7Vq+N(o((;a21f9*^Dm18JBBEc %e#=cL3H^+^DRp8?,TiJj&>g/TDs1ABoB;555Y/tp+'l;r3rC=Ve8n^na?"Fil`S["`[Si/cI-gJ]r9m*2fokb&@rn)JJ^5?m!Ve= %9#W._be*$%NVuRdp@HbhD9XjSPfiF04-TCbVL!?dm,6+2;K21p1)>_I8n`0J60pcU[_K-sM>[9jA3$H*?lE=+SHB-E)haDX+U!4&SPSmcc`b:=BggXVBDSHe_C9'4RWDe0*msBK9Qm<28P[ %?56p%JY#0B_,5Ib>4/P]7Hf+VKR^rXV<%]lBFo4fBfWh`W=s=UBfXbtGfN=0Yiq8!_Ds0Y"Qt.A@ST\AA_mC,hKeiAY=)Ui'C[/A %5nK+lHLG.D@=8:n'X?9YIqMQ'R"U^G3VVD%ro;=$nC\)n]-5.p %aq+DIXu1mi*5Z%n`+62Jlq6&LQ&"4p`;oo,NupNI"b5S_e<%Fh.Vo+`hLnkQ"5c)oH60&S#Od(@4V-*h>h/H6^LRqZnrsG!GscD; %jj5o!S05@,"\6$*s6'4]g4oK'3#4%D:V6$j+ZrbDEh[Qt1G>Zcj@%-WkN/4>n0tMhH5EgPji#Qt:j^];3L+qYmMC5,mSNLq`a57TLin4M2J__0%]dC5u/YHd1nMV4':TF*Pf[PPYOg9Id'&4L>_:X#cce],6 %S)!B.TnFaJHYrX#Mgs3\s/'<+Vphp>^]*JD-,gJ9S`^YlI:qjMWYjZL`XWVCk=7]!fjhtihgBpHGWp-7p%8jJ*/!%JnPk'Yd( %1CrLV%W9AsHM^+>E2p=5SW+<@VV`\A0>9^q1ZjI+\-+F/MQti>e.:[8%!Vtl7/,]AbGTn*5>BY'II-6@\A`Tskh9f][i&NnG"]W^abBi9N;6IRL.[O:rR3_elICf7+<7Sj1]Wp\oR%"s(;#:3TX">j%4H7;[<-*5S%nW"NkAuYdeaW=P#6L#`5^o?9# %d-1ZlmfW:f>]bRiPO_P`b2h9h&.'B4Ng:lk?+Mii]qR0qfA`i_Ef9.I,5L051+tUeb$9bFs1L=n`mCdX4cj)uh`j^+mc1_!c1p6Pg/7JHR`C_*1oak&)s;smp2DXFP:c'_ %6V4I-[U!f_d7^9;Je9?%8b(=oVTW&eqe>]+R!*kbh.hMC#@8X@P!]PdU%hb(E^TADT0dRsH#BQ65USQkapl%uP]-(Eb^-E2X`V8` %e6/KR:2ZP!9o-/n;pqkBa&3bpZHrJASf)`f0:0W[h=@>e_THC@2e3jX0`@6_BcCmq1L5-Ydedfc!alLIp;=>p''Z])4Gc!UY1?ZrpTOJn,"3T %MP4U]\ZYsZWEV/8?SOsh@L!oj\7TEg@L2eN1tE)3mdKlQWV[X+9'?01AnOuSoLI,!Tt^0^ck0]-ktgY9QM\E=2GP(=rSLYf^TFXg %=>A;EGCL!<>O$AASXBT.Z(:W=>ODCof8U#.QF`Y!.;-S%s0pPHDfdN_qS0.UIj87`UArt_pU<.a@8m38Y59/1a:2&A2cP$mpOAZU %J"OOq:72JsVij4n^kkc9J[dJp%fR77dUg)=ruipUm>#98YOfO;.+\koBZU@aV+,:7qM]6E9pMFhh-,ph1'A&^+YMprnpF`@,67'pp5nH %A8Ia^qX<%lp[M0@IL.%&8[C-taCA?-MMBY9+a)DRbH#V./@ %DWYR]kS:bbJ;)kp[U/R5q!SN[])8G.!BS6tIrO!%&ZJEk$2O_c>)eR4hP[j>HXaW(AkF$=$=-GsIAC863o`@;okLY7 %=0SE4?2,B_iH*c6K?]E>lkR5eoIUWm&]UF3@AAHp*=?)--D@?rr%?U^Q:7s"nUo:`Br':HHf`);H6'&[d?5T%=?nh!:U^`6@L,o; %1n#Reb36j#hJ,:4Nj"Vd/Jrsj%@%?9Hg&4Hg*-i4'i1JMoqNu2lY$26#aScjmg %9-CbX,aIH7Q_7T)o8[Nl^eN.^eW/n%MNt<8l*ZQ9nl)DD)fd=.bjV)e,.B;E3fMPhm9T`JeAS0nBY"-\7U7sP0A9"j$U"]VIWQSnePPE's*QPgMisV7<>\YFQ''%7o^-s'j\_:cO=#0%sk+.Zd:18c% %@^!*ugaJQk<;M[#WsQru)K5pmo\mBAAdDfT(@f$#C>@lTB0`sWiE20F(2$5lGrsrrE*:&_:r#B^eSPW563.=hB"0AM==E+[>IS\] %n.CuM8NY\qX: %oi:D@^:@JM)C^7E]a9q %OJi18.u,J*f0q<>h)mr8kq0r!df'T".d*)6&c=.#idP(th/_b1raa<'o#WNgGP!8(p(MQ#;4p.]c"f'g:Nfg2[Si;$B1g[%G1rAn %4I)MTF)anYGjLJ)9E>!f#?pg-A.>4:mI_[PEFY/G.G//VUmk%>#dD&bP@EYEM8)8E78Wf,BoK:/:VW>Ht[ubgl7ccp%5WF8^3!@`3=4a*A^3n<1pXq?oT_u %]2X8>%%`CeUkCr-IaFOS>o'JZGIKB5"%%7s\_tW9m;XQK^X8l9rHDO^hu7#XS+6eG_2]lq[ID$B,?@T!4[Oe@?'@/k(7h_<*PKVB %B#FaFCRl*McA6moG*C9$b`bbJFOlK%IR59(8#bHm%-K%c@mp^MK2/G/H@tAaj*ALH*`c5@8Ul0pjl1?=dr\U!T_gV`_aS)*H1A$L %*QoL2J.A!f>\j0aOa50]4?cAJ*chU>p_IpFjrliN.P?cej`*lS1$A+`cE;:FceYKN164G^8'9mJ:D+Nl`t`:23(,Ep?J'_!f38$3 %-W!q&L>-"W@c3?.]l)eU_iVgP9s6#qOhASsFtn:D=*ZtC^bcK#QW/&=s`=i^lSI&)MCmVn^Ve.$e1XKJ.t%\-P5SD9d.X'cMMAA%?\u0fck-WTTT_l8Dl:s$W2@&!0=#e %B/[df?M>_d:H4bT,L>T_qJreNmuPrm.QV6QaNo@JQY1@,UmHiHTA^mVjVe!`jn[ZSo=((LTC(b)Z]W,^?678&4QrT\rq>p\mH+/u %bObb@Qfh1"N;Z!*jafK)?+MXQgV2(`7E;^F\JXMQbh8n&.EHWTa;;'W$;q3s6E!^<)ODVA[/X^?X7cC:)YIOQE(_;@?m2G:"dGO$Wa,?n&=nC_IAF]:t*RE=+nH4j9_GVXI$rIQ-D %o:'N?^LRbE]0/"2l?A:RPR@ %.SKVj\'$&<@ntSL`;:3N_$A/)K:g^OHBscjQ;^&B72mnAFa0o%AS+ltScR7LXcAIaaqk\_[TR105&(RYTVTfNBYBE3.HnAaJ6"Ipg073H0ZKP0=IqLjJ<_?&h^Y7P1+EN=NIJ$(T %YS4C+#utlqO0@uS)rM[pR=9U_ab:Q0!SW;BUmHg1FB:*1GSK"hd)#0#e<2:T6L3@h\_3^i]pD4gVA$*qZPW)75).o?ckA9(-OXcB %3`sl;S@W2U!!bi?PFb[m]o69uRJGAHSlW7Nh3b^Pa_$`4'u#"g/WQ-sJQqC$i*Imo^`7e:S%R\^]^fGro+0%_j7:r"R4KE/?EWH5 %.O,a/WM!a7%9?_f$.4CV]3K^r2cOc,rrW7Q4W@6cpD\WQHS&k-1@; %K6I5,VD$P>HLX;mCQb0s;/3gqCX\l"V4g9)aKd2>@*MAlDPHpeIUq_@Hif+.L"/Y:ZF<\Y(orX%SJ\FKq-o!6Ket`6Ih#A8ifeH@ %1c7N+R`@hdBJu.0c'D05*#eNEYQ5qd3LZHhhS9G3Dp>)gVf/Y8o;^K/7M %k3cHf/'^hgD]SF0RP1mZq:4b`(09+I-FDu3(ACi@Osb9%;&n_Qc0!M%8q+4J!&W^3OFFZdLL=WBRRi %T7IXLb00%"G@;,V,coom5Nd9+J0(/G3*`k#p+`m_,^Qo/SeXDSq$aH?`q4+P1F6gWa5Q]DHV>`0?K,5bR.'Y.1!:NO[%Hd)W2-cO,.bhOr"`b&'^)]_Z0jX,2,Q-+YQGbV,B+C) %YQH*r@r7-Wm6PWtXCYog@nqq!Tmme+"7rIu7Z/rs19_65Bc6B(%*Xq]/`WCb&Q][+YPJ49"SV9ha>EaDLncVQkW56<'moSVA>=&M %5&qKeK\[["K9%"l*e?C9]GU0#\U*.mg+q8`,#uOKg9M]F,l#A2#9PtUB>/nui$4#^7tO*n&:F-F9._WAqbb71E=9uHgeD.ks]5>AfZ=RZ6'_N1F8D.9jqdlET&JgHp[BpZ543$.hVHSV$UC %PnUA_8NTOG3FP.ee]?BC`h@E>=5Qo,96V.g.OX^i\r;TU0Tj2"8a[d4[=PRj^3ocu@SR#SRR0qn02gqqGut`>e'Uf-Z8a;t-.DZ, %28(8Wf6Te%=!W@Wqo.kT*`9ol]nEQ&B9[C)0>US$65`"?(=_V6ggbJXVOD=`koFsAs53HNNB\n/H[J[[pI6T@ %<8"jCPX@[mI#o:[Ti8JrQpgQGkdF0bi:*';KSb'JP2S.sr$CP:UnQKiDp81SF%k-022Esr0H!m<[2@FClN3GcA/-bNef5Ffck-Wd)dSPOb>9XnOFtsL4!E^tN!14qQ)fkMnL5%:tFtFHZgjR)+@CqgYi!AsVO#2<(h_(t#eB>*# %_k/U?*MlOdr'AJaF%RNU]4AMh8l."+(/7pWMB]j/#ks]7M[n'W]dkMIS:@jrJq=VV^QnT%.Z=(mlsj9L.*9\A]T6FA5qSDKk>]tG %ZO8L>>5#fnDd9V'pWu+Ge(ZnE`rA,";Yt.RA!NiS;L9`U?bhs:d%LaW7S=[Y^^VVUHr:7d3aY-hU=6S81]@)`]@Gkmqb'51C%Q3S'aZ[!djAmF=Dm_\Trs]jJ,H^PEfcpU.fj8<*'Oa)2(<2e)4[a$m]X>SW5Ls%uUrmtj)s!>-,HVk%`_ %RlahnDV6%DWf8pFXMMiCL#7j/=/C4A/0?i',$osX6kB--3H3f%YZmbInM&Ek&e-*he@g!!mXt>&`9ss"mb9AVfM3R>ZUO:;s&d+R"rT!\56b:Kq;n40BINP>Kar]0-2_'eDe8C``#Q+\OUW><%hbDnjjR%=[bm)9@K]%@W9g$tN8= %\M72^kSI/L"Nb-_6gSA6LYc/l(5O8Rq>]$Fk&tK-KF1Qg$:/7uckNNHRHW-:n;#.>Vr7H!L!Ms\U"F2@%i9s^nDt9HJ2Qh3cQ?IV %0>K%3"5fUF,LOVk5EpIR25KjnAjIR(Gt$srb_"K@l@RH.q=^k[%MhSa[AM"(.&WAq;@>Z7\iI0oPZm^.fpl!a#/>@)Vfm2%fpku6 %8u^?#mafR)7h0*m:))[`rW<8,SJ%n`b&)']Ya`@W8k=;[lBAp4-E+W[XT,gtp#5Ra=Aq!560QUgEgVb5R*[lrDEcej#?5"%Qi#NV>)ND.=q#JF'(atcO8j)>1+8OZg*rPZLc_S_=[/!,nilmQe[/_:E"(3c\Pk)?[H@[/G?*!J;8r0 %UE@H8d?[k:^^-A0*lRL_(Z*hXq!pCqDX>!I%k]uZJF.<48Ej^?%rFoVJ5!o/hgYPq56]pc&nLM2i-bXuf+CW;;R"+Z;F?b[6Gh"B %CbPe_cIU@!.AjMlS1GJ::$UB&\6dB6BZSV>%upKF[eR/bOS(F2.pe@/*uFch[B&9:8URpOCqtOGR2"5P@2n/<[MlG>]l+uF@B1Qp %(N9YHd*V1;Ia-7Q!eJJp>f%7[_C/i-,@&)*/Q%LVlkEXVmHFUPRP]s/H5JnQV$RE,No1PYck6D`O*\F%Y0qtdn0YOi3gD%gZed$6 %_H*MT(GN$MfrHrD(`t5!,pXA]A!CafAu3pd>ST+&j0`0,Ji-ZB]hCnd9WV[!ag--?$?3kddKIJjC;:.n"`eHk`$KB>YgS2m?+AI- %b&5WRc7;W'NB9q2dU]&@K;*\"(_u./$i2gH4hf"76.G+Tt."6XbffLBf!;R7\rZnPDs?P)_4XbR0?0Yng[`RECI`.%7-?&0aVXG:Y!N;AXND&)'SRNmK[?u+0+']LDN]?9bbCS3#<1V,hG)Blpn$(?2pE\XJt##.ClE8;)/gIn-iCgAHV4Z_'&I)0 %d7kEA&HTtG"?227G^PN`$Bq]_'k`W$-"Y\S_9Z%07+Q'"pA&t@4V(nJ:\]2oGKT^@$`J[T<6s4:>8PW?Ua\e$O84oqDe(e?"q.Kd %55/^p$ggBWINb@%mP]rRj]'E0gP^+(jd0pf'I_L>V$;;ng+dM+(boeq`Fcf_hL,Fr[ %`E,0FUNs/nC@o:OMTiu&)&fq%=a-6H*[G/f[Tb-u9M/Rb[@@k;iK@0/)7IsqTUhHH)$iApQh$sKWZR",B@$`rh% %C!No>.n(3[F2lDm@O2!&dnN_K],=*0i(+oVOP`9"O5'#c'h'K-,1?m]XF(uafP_YL_ZB:B'M&AQ*-;UWm2d1iq(>L`e%4@nfEnU2?D"D0^[:2Zl??ggrR/Kk;HqDlLlt)D#s;7.hd3AhLhRdI4\8VN^Jpo=kg4qg:F'4%5e76[>cebCW: %p"FEjrGGX&7L#Nu_ %LODnbWQ>2%DF(n:9cM8M\K?2MCC6'051B3NDBHjXX6gmM<&,0\)7mj:Hh^.XVu0Momhd+F%Aq*,jITPp*kp(Yr?k_;=KZi;SAa8G %G.s/07r\4r_p5HgZeTGt %3nkj`)2dkkdI!,G!*CnL"@Zbmi#0`1g6!*$=R6WoU)Z*Z.B!L1?"k2Mi34(+emWC1*]>rEWAo_Al2_o`*S?!3e:WnDNb13<2gSfY %bkC]Yeo.PX#lKQ"*Ze3F[sl'_HJ$UF[sl'3:3'4\g(oN %0j0[6\jP1h0<*EDi)$8NmRZ&,7;ee:>Xa_$D8SlBA3['C?.+_D1SP$!_0$J8q-g6h_F/F[sl'ijpF)F[sl'5bXmPmRZ%A %c!W!$]?U2+L:SUd(nd>Hq(#a"XQq)Cf@G9h%'nL.:4G9h#1 %>&84`ie(UQ@tGIX5tAV%JS-[1kD_"C'@k5$jjIBY2JMZgb^34GQc".?mO&D"m;oW*df]3o?<([BiQb0$50?Fi77p8Bp6!<\&ULNp %`:c6N]#*dT*d(L4*^j7YGNM4[1C:*N4.MPu;.l.TbD'J=Q!n>Z)YlP^XAX]jb[A-LXA\npCsBs?1]52c^;jo.?bfNOQ-IZ^_9[$[ %[b"r$YQts7,s.q7*'XNl6B>l`n,5%<8mRgj3e?6TTq8@RW)Z<"TbQ=4DP4Y=%6" %2m,n=SH?;.2I_"RdOAQ^DBlUA+e:q:P:aiK3i#^4F\D&*]adDVd62(h[b"r$0881r$_b9!&]Q/)`("FD046<=f3r?r`/&@RZ>1bn %(QF`(@XB,Mp;.]R&_m3_T+S=_Zkn^fDM+K25l5ri+1['uAV&HW/4;Jb1boa.Z't-Br)'V>"eSdWBsdF7m*bX$Htg(;aqrDUD?'F= %5i8oohGa**=eP5C`Qoh'*ZKB"moj,fi@Gq;oK@!V]i:.F-VnBbd\QGG%-bBg_2i`)>V6)I1dOCH#1gE=EmU)dCp! %2m/k;7Gk]MoU>FXYIL1P]!eSX%A-7SN(W-!8ht/6l'ZU=+i4Um&/M2i8g2(JB2&Qd&?e:b&7HT("'.qm]i!pdIdcWb3)`q/XOQX! %fK\Ln1g6!",YETLBLF5uHqM[cLSlAQ9BkrRi,4tI?&jeO-PpWg+\=9^!hR3UFd$AYFdaIF/c#OUBndn@Ln5F*1dahdhI'5q)662J %-O\U/BGRVqMka'ccX0&Fjl1;K2#Z4e,r4[bH9X8BrER9BV+M3dB"TeTDW,1'"fF+R!H)'^*tXlD?^)_Z-a-cf1l&>cV3O_(2!]L, %7_\\kpc`1+2j2J@582&*#BgK7Q>Z>hX2.jJ-:p&;^..ib2jMs#5sY\6`u10kdQf>,+[m+?jb!e2.u$O7 %9\E87>'?]SER(rbf_:bJDp*DYO*9d!aj&*Q8po"#gPiXP!ZPgR6Jk[2;Do"t\@B6'o=i9\ndWmU66o*%[uC:$(QI)K>Kbr$mCfrE%,EhHec9?=;"Z_pC-+^p'm\0X"V %Ij`%@\EPjQ!0^($g=)k0`RW]F(UVj2M,0?/$.M.53O[1mcndaGasp2N_!3b*SrB8KL$V(BKQQaRh"iL5om;hD`*OG.Wu6YhXm'o[spj(PdR"3X3,[%C:q@ %-%;Pp:5Z#.R;u$dY<:WPkNUV":5O#I4/BJ=jb,'%b6Y+1B$@iKM`um=77s:2X^qW[`C>!.#l)0]?UdkLcJ5L_m=VJ2b^]*mqCX=` %SK/K:nOi8/M6AO_b("Q(emtQ9d^BaiF-(M7Mf&Nk$=d*&*ck"P>=XCH!KI+].nte*bJnZZBS>HIHOM=mq0jlkZpIBEO:NA?;^if02a;kXe^d@*7FLlP1W=0gUjr\6aS.beXu-IR(J-g# %)YU\oE7ff/q_C+tmP`b^Qq]%=*`,G"[T6j+VojAZVR7$e3]-ChBrt@;\W+1fLTQh@lXJ-1g?#R00]"D5B#FOL[?I&?,2'mZRi9ja %-YN\lEiqMU[,*Jr#CSN*.%IaWQau$YndVY81pb*Gnb;Tc2Af&gDD&r^B(B=X<.f($j./gArUn#=pF+C=[Al[gLR3bDAZ`]=;;Fb: %96mH+n_JVWjs-W"!f!]W"W"O5\1p2`=pdsN?dN"/.'QElb)MhkG)$C-#4&7I*>W?k2D^sSC<@>8kp]nK[6#-QH4ag=R\kDRQC?7h %-@/uLl7"Z,8i>q`n7nj""@_o6?6@YeC=%7%D8&I5)!-cPP53Z1>,O;f12+2YO.mN$jXiE]R3>&ZbeUmLgE %BIlTmie:B72s1o3+RCUY>DsJf_4"59kV-a.8`-*O8>TI]itr>#N#M2F$g%0kO]"Q%;$6-M6qU/sMG?L@`&1k:))l/F]TV1\=BeG& %B-FXtm*\F5[_5o]O\XeN+@UAh1D!HYH]X_'Ap_!YgN.W^LQ!M(K3IEaTLFMoJ(X8IU#MX0L'gUhM2F*&]Kbku,V,mV!@bVMbM&\,>13[]]o*#f3ZY\%CIl`YM'(KAScTP0KA!Dtm=tVU@afVqo^QB\H6ZdnQ@I9BT^r0s0\640:KFU?ZLUM1&QhSa2sLrSqEm\)S0o>O %aq$ns3/nEqmsBOt&YJrE5>GSD_pfd"h,!urrERefn;!%5n,;5-ad56ip%eBtUfS6=X#Pbh'OIKFUjfHqVd1H/+7%^TgT^/n/+u*d %=3c_:g>BgP[7p6=qRe&.06NbH^!oDalOr$$800GSPbsUZ`m5S7[C`a2@I'RNX1ZtaX7NsGl#B2VL@jH7,@Tt6V6SVK-:d8;X7pa! %*ij$Cm^$lNj4R,d6*ftOW.:pe=*sUqio;2`V)/>$Uqr58^Qsj3&q'Js;(,s<)dUMse7PJ>#sLCZVHHD90ptJ^PH!++gY_]d16(K_ %CM6Lj@Hb:_9HYB9$q!7,kH&-?e@O't)#>-QfK;5,]V@=3"3kIo^A07U8feTRhVr`+*RZaa##pGUi"K6&k0hlH)>[j!HW:ep'pL$i-p %rUOp3dpSqe\'EiJ?1'66&9OaoV+n%f-'6F:nWD8GgDAAp"Hk4ZZN.ChIdc_#>FeF^39o&iib:u[2G&!#FXr`2\,oQi3ZmF.a^lq+[1&e)kRiN@ph-IWPra!/lpS1"!(_WfmYs[n,3oXS/U$\?>7mG));^X2TeA41r"Fa"b8N--(^LbGO45d+&2/DghH6r %kN,c2Ql$1fqlMtIOl]g"-/hme=@Ho1ZkEg#Pr5E\[TGsXL"R*@a:>97/>?\jJNFn,E$j=jg?[rLe#HK!DfGc:=@Y[W(9K@I0;F?KjuJUb[IgN&[([B1MP:dmHAhrn\V[jO4j5FX-)$pYQ/Dg.T$)3)o2$rb`)S=[ja!GCW:(OE/ka/n.9ER@].A);;/o_g1M6,) %HKDGS?EpfrZ;`rP0S;MOqF)(jj1)WtjdLmP42+<.f3i/1@]_*t[U!7Iq=<5'J[mW-\JHV/33ErNlmu8_@-*7MRE+(ul3kr^o9eiZ %W:)eoo2t1c664aS]CW#7SQe3PcC>*M"fX&0 %hSZ4'#G('L5/(d`/$e_/G+1!sV/VmWJN:J8.2GLN0o@tJ&riAErO(-c']+7'JW#:9\L]Au_-a**1a[0P+nX#j5QL4fC4(e!r`f/3 %)VkXp)#c0TrGZ,F+!Q7ar:TI.8HQpUih*g(]`>'eJ?YE2R3l97\aV-,j+G6EIk=j`3nB0Q5(KPT;TY"u%=n_rQ>>]/Mo8T4^&AW; %_(L(d$WG>.`2SJ&5ghqOSoN"tWZfY\>0Ae!SSBR40\Tc!b,L+idArq`25HdXpoe8[QUc$8Io5U/:4'+E^H&>WN14*0krq3qhrDn^ %m*6B8IRis]82aJX`Y7n)f?N-MH!X9BdBCcKs'&AWX8u!gn0K1LZ4:5nSkq---FWCik]sE@0Ni,@5V1ke %i-@$WQtVD[H@Ui(I#5Z,0\TB-d2BgT\/g+AbL1.M9j+.*lIBXoD='m=CMlb`%9DH#WjsRBC5&]RZ0(bcN,6Y@PHC2dNL1KoUD1jO %^;-V&*"=,>?6>r(nR8R/l18=S7SKHXOKFmk(u%@q,Na8BCW&>nY=]T?i9)E-1@+"bB4HKDRZDI#`PWijBX)FJU<>D0[B/\+-lA-_ %!['\"bB&EAIbc!m$-^1?$i45SL">4phcshtOBKrLBh)hGPP#pMg#$S<'7I0!o`=Qmo-+PI\RJm@Pm6g(%[BG_s %*mF6)paS=3UE5R`gkFX$/D`R;>V`&#d9#bs(lE^f=#9'0/e$ %Q5d,h'aWD(3c1WD@@U7X!PT)kNcnl&[N>m"1#2"=9VA-c(B].<':TiM-nVT])u(h`\gXg&.Nt5#m:L6(N:Q1SBLf%2jb5TjPS'?g %g4;=H6p&8QCgA!.6)Ro?++,LHCnVk($eg1jdUq.b9o.0\(X9t`26"D37[l>N],YCU(o:nVdrJD?PW(-`=a8jMc]q?fC+WT;&_.J+ %$sDRN\g`[?6e*+,d?NqKKTd<3Zj@%&V%,HU1DR'4]aOG5`tZNWn?r&[$(\TpNEcW:)1=[u[@L#U/9EGgTHCVT=gU!NaiG!b;s8ug %jG,EfEWH'BARtBmKmqZ@INXnd$N0rf=L2a21c-D.lc-LNnIQHn3paLWcI#dMU"ZKCG=#K>+t>U07Wg,1lBkom\D"nt!KQ7serE:\ %K%"H]Q/6F:/l/7EB'/;`?gKJPQuT`LVJBiqKV";0qMd]9g-bo61X5Q@\n(m4%q-plQG,s/h>#>*k3$`4^BN".Q\Mq8de7XK]S.r# %Ck_C)UmRFWVSA=K8ha?d7ic9$K#2K5NDAq"5T][+5Qi*dbC"H`nZZ^9'<'!l6Ai3<8L6B4)H3fLH%cNe01Qhg:p+No[=[bV"8, %JL<:T4PGcTl)[eZWjKm23h8nQ[ir:D/E.&*qn'\YIG>$qO',/g>?CH4`]?Ik*AHo[)=%^s%oQtlMQop`eY/2,dfDdbV8cX#5sW"P %T^k&bh>2H')g7^d[\YUjF>H^k=&Lj*);=A;7]'h"1UP^.!YgW:uR"@+cQ+!P9W"4F$6P.(JVk]rl?Qo>CD %a/]Pb9u@nhUh'0Aoml]'DeO;TKsmlon1ITLN6j9orqa8D:`/E&(&g36qus1q3%E_9_I().S-FN&$2t"9$5ro!-hn'X[++c4;9*&% %Vc!u>n-"4AUSS0Fi=^XFs33BY]*YogdG@dj(IFaJ$@q(Ark_9ecTV9EO:abnIfX=$/gJIar5D=[d#+_FKU?sV]#%hni%OG@ %UH>a?q#W;Oj.7orrg\4b^TbNATRacg(B+B[hiA.=TD_NA>0Q$4/$:mhKQ`,u`(`+eL;1P^b"n+/%iKPUp06H9*jTFR5#5nq4pP@`*<`C-"oM4 %+OJ=,$^b.5!#ThJ(UYU]E5il-Vok7Qi@<3nRrkoDNmu6?k[^-edE-53l.Fmu^6>O!R%HWNdc$o(hLU>;d(Hl8qOL".hIl6e',b\6 %]u0-f*<0lrh8Qc8a.8dkYjjA-mNP`+Jj3;t#CdbNF!L"!/(r'5NhUg1ZMmBH1ablM*cIO3I%C?>iM:(XO7A/9*K,ImRVJ0[3LCJT %QgEuak;pY@4qQ)q*%R!i1uH\^?QH\"$7p*f/GM8blC"18ojuMg0*""(PEr$c'1Ta//nu8 %P4!+5>Kjum;W>QsAO.!F!b7e)Sh4R"kPS*fGkS7tU!&6J<4qGZ22B-iT]2GL,l8d2VYC$&28Am61f4g=+:,MRga3@0mJM=*NpbuJ %^3i1.RXWkXC1s5AZ+?)K$t_SVL2n>U'DhNqo_Ru9eMLd!V@i'i3`SOOe"Bhc6.OW<1lJefGS]@sY@V+_[qW-D/65?;%VO=88$5t)[,$`$ %NN:X`8aEaR];j*ccKf.sM>u'0[Fm5n,%2<4=oR>[q+u>R(L$#5DjlZ+jR1H2AhnWq7PQ\:,9"qMmh!po*f"cjZH1J!\<]Rp2C.W4 %T`o-a6o:QVN#ne2&CDW3e-J'G$iBW\6[Tp*@WtO-O9WVY'\AQ55T1&2&3*[G3p;!#=;eDO(W,i;?"HQN8ZY8t$rmkMa1R5HeYs\\ %oK(MgkbS2PbPI]o[4*\C%dV6d+:X']#.uuh$drF=BQ2';YfOZpk/fm+]DH[ZBeVq35W8o[dP-Dnr7N6>*VI:PX,ArAO;=Y.n7G`P %$Nd,Tj$LrT(;;_$+UsgW^dcIOBc!N\TT(a)9gB#Rq>b]4gkfrhV %19W1$dF,BEC0FV@4&R<3K.gV-GG)is=JMB(2(5tC47mKtAEgm'QTS"$XkJDQ7NNQAn\;K-s'..T"3hT9Xh4!q=%`Tb:S2nlgJ-q< %LXG];Xh5iX[bY]9jHV+DOq]Gfjk2VThe)D?38)CI#7g&H,)O0'qQMg#']86nPgF)X0n%]IT[\gkH#(+=7dC*8Js%-@M"?4]@C=f] %5tSUoP"b>T/p0Qri.]VV7:800I_O3KjY)1B8n$*M.LN/NnCEX'HU./%bXMJ4(84%/_;[\sC.k\:emkRFc]oNC>sk;U'7=soM]D]]At5iCM``#R,H?qnaq&7HRg!ijcl %KF$mW&AE\V&7IC;P851@`_>&2K"?o/!iEZ[/ug!M!gK;R8.9JCjr%%chRAd`jX)3E=RF4o,'kha.-V10+:D4.B&h=s4;hT[<<%E\ %9\,=lq'DQKHhgfk*L2dcT/"d\rI-,R:;Z]gR_d!iioq"Y2WTV*"nmtPumE03-qE.[g3Z3"g6k6=/QC%Nr(/o"(0_m0V1e(0[-*G!)d,>''d!XOe`lPlU#:_HnS'"u+ud]Rkj&^G_\ %BJh:&PM>eV&0r.s\8LO$+@n-40kD4@J.12h3jJo'X!u[ %i#UKG=Z[?(+l8=J'G%sgWo+3::>sn5'jbh"G03#aSpg2_UE_$hDgQl9fcc+:g0_Ib9"%[t^!H6aAbOH6IdgS$]j$Qntg^-$"Q6aE8M8p'c1`:oWhA34qJ(`FgGmJ,^/U'=c+3>uG?[I"!M %`!+i^rhkqSLeiCY]u+dL=+3%&PtF9/B1KL5gqF7>Od#3GeEjrN`]ea&9Oq;7(,kmXnH][1,?)LMIS,Ek>-LX<:; %HuIfb:Td2BG6m$HNkB'0E#-s)jpoN!r&X(ZRQI<,d`otg,FB#^fj>Qb %"nWi,X7kV)SaWBKiM[siAY85MfKUu\E&NOXfCfYgY)*Ckh=rJRWc?umMtt+^4HQ^Q!^4c<$9,Y1P$B7*g-_M&.:'OrbkX?&[!@b5 %;b^1#2>d/"U,,882+T:jO+>B'`'Cl&7CoPHie.6$(0!DRd!V/A)TVh,pj'ZCT63#3B=A!<[gJq6Q=Hu7@)l;hc<:I+CBbcX3B8C=*met$]`(E\Mq)_3.&AKjHiZS^BdPCq]ng@ZI-o_qDH)ME-Ef*6_BUufQ[#17@igh]@)3q(NRq?'CG=6L%pgs_]#8&s!IU<`[cF4ei^'0S3Pa_iZ"5;Qhdu5Jme>(F?hq&^T?o]' %?Q_W.JJm)_?9h#'S7`lI:XG)Bg5iEIYP[N+_*:ua1r0lRN3j+"hug_Z&6&"-"0d??/X!=B6;M'Wg[bq;9^aZ:_$ZBAFI%&+dm"p@ %lV@Oe0K';2221*i[YB8S,.ju!-XXYi;95GYJos^*73RHW8a7*j?ZRtgNkg]SR/JSHMbu?l_$F"e8JR:/@->sYO,ikRSMXj(LJT;S %9=AW^#Om%,K^H(cT'?(;8PN_;WPS;QPe*jg8*K^->?jHcrT;*A@to0cNh$ %:4[E3Rp^c*Esdka%O-0=0Fmqc%?PQDJT9,,&cijTh(s+5^c:Q>EDo0/#)pH;>;@tZTRmljVj[8d@%a,MSc0\W@`CK%$Q(6jGjU$f %B+(,bB*FeWXn1:5*,*ZmPqisni*`D5dk]>UVi&)A;WF^iYLGJW*6-_g&hYBeOl+>;&tVO,o..LH:Jn.B*gMlWMSD&(a+H-F7+3Tt %?:L[Ag&nJsC\Ds2XZ]Jud0@sBdFn]/$Vb[QWO2t;Z;EQ83:o\K*VIP[B:U*mYCH0nVP,bp3J_R6Ff %!=r5p20$FIliJ]7K4Q*PUR)Z<#2D1rDU*"6#_c)OMlZ=qNII;M6iZuKSJL`\?=5&m&,,q/"s@+ncE(E(PPh %E:='7Z?%k%5.uX]f`cbAf,$+g,1*UNJPXCHLk,G=\:YDi#Oum;O3.0^Q[a6o0842!72$`:i2Z$j%m2,.ph=l8r@Xi_?@s&\*FG,I %Q-[TS6/VqThtsN<6:]/,YY2i]?k#bae$97EYP.o*74b"n;KH.>&gmgGm6L&]FH^FhX1u,o*P@TBSlI@i\(A%N7Rqh4rG14bD"-2o %ci$&RAi=C8N>Lf-_KNcL;p2QFBr(F!frLC?dm1uUYpk,,0'#%&40->`Ra,0c$!j(h24_:P6VjP[l!P.oa.]@d*sf]^6:94i.lq[qn![]uY1YWp<\>eDjpX=#+kJYef@VSm*$>j5\m/]Yqp%Fq#YXdG302pTP)`HfU4J\,/7%=UK`VH3Vbsg?KdaZ%:tTh5N^ZF\C#;/9X2b_a":-SbSbS> %hB%Fd47bcTeme8;$FXu"X]+T1$XMu-:ncO0(V3uY97p\d?KdOmh(C."k(PGJ5!F<-47bcT,dYjjfU4P^ctH")@VSm*(`RjLV$dSK]L#@==)HFc)u*":p?9MOjRq-;`"C;s_^GG.rJQMI#KD %#KOTfhQK8dc1CMi-UL)O):#@7G]$PcN]6*0)="oU?T.UMTu$ %V7npMT$,,7mJAs"b8b(Lm8inYIZ5:hTtlk-oY+ruaeO*jSPa=S>!))]YpEPZMFV/Z`3&POb_I %0gt#PNKdLl;VOQCWC/qZ]5/p]8BOKr(2cjOkM7DK8FTlp$Dt4&34,,IA20@JMl+IW-<;n9J?3;lnK89.FBR!Mn=)"IqO5ri'<+=W %V,%",g!p&.K$9H_nE/**nQ"%j%<[V4"tGfq#<8/Cc:<%s\ZJ@8@G\u]cF_(Dnd#mnGR,VKcMh.::=LdHi,%hbFP6GBY9._dLfa)! %5rrW5B)6K1!a3L5K]s6XaZXSVItf$^RH1905n&@&(4r==)cH@-)KWkkK(>!7&;,)EUYQ!N,H#>Qe]:*7<]?il\ot* %_.("5CI\"q%nOGLTC0;8]3(m[>4o*#O81c6SlXa%mt%#^h.jSj9?P3*GPL_8:aEN@uHS*#,t:.24Sh^Ma)>@X?@Zb %#\Dt7KrG*7Nn1Ou>rPdJ>,pM?9F]0X#j(YL0-'#LWbhu8nPS$m7(_'HRm`#V&:oM#; %,hi^<`$UhhYs(PD(P4uKXj>@D+Xf1Zq@&qEN@qWr,ck"P2)HhpA^FZ:?]D7`CkW8s0(.N6YtEOX@&Z.!5.5!_O$\,1ZcNKV.X29L %Ya6eTV5T09/X4_bmbjCC5g?E'mNT#)\'k-uN,ugW-<7R@l:^^s>_AOjda36+.s'\$6IJ3`[EQ*:ke3i:daZ"FHe@*6SsiPO9r*@+ %`]-7BpDIrTkgSMd<)gZXJA,Fpc.W8F37XP$)Q"JHC'*TDe]"TiqNO'rBC@1B4EH!2DAq,s8p>J$>^1\u9T&!IgrYo107G:XKk:ec %m4Hsc&fB\DoRl$Qi81;l/iioSKC>","RYH?0n5qib@T(L\R0p],C\HXGLPRFr'pisARtES2HZSQRo!5L2iJ_33JJUE[@f<%&csQ2"=eY'9R>$:1b6)Vt %b_$Hm!hd!_5mdpflQ]j-&=3=VFXDA`.C]Y,n.N7Z/!8+a%9hFeLE)SDq#3+?%SI$F01OGbC@clMN=m6QFPgF+`D$dnDl6>us!SYdnXI?j`h@f!]fV^%>N[%W! %Jj3;t#I]G9jubgEa.*e=E)igaD@0IE+SCd^SP!hBe>XS_Y4SejV5PO/]HB'pYn*2*K9eK";g];F<8Q$/aXThOcSj9=pnT5AAh%7MeV8EiI!'A: %MdDB%\\Al[s('*K)eRaf.;!Z0%7\<<@J&-$b):d/*ZE<(TW>a1c2J,K"dMID//nu8P+X=2;u-]^&eLC.K'dI0JY)VB`D!fmm:W4Y %7I1T.0-a)8W@J9c5le_p8WZ3^0Yjg^9^hj+lIs7W]D%$92cgX5_L:hc)4!er_:jkl&i.X[?HoYg@*%#/3@\ppt!Vi/&n %e84m+@*Wti3@VYUF!d=[f)!rtNN?j6F>OFTnT@i!>LSDHBoT,qZu%VljI8!Z2rK]gist7/faa@F"J:ikAF+*?')ssQMI_oH_eOsV %4DLJ>/r/slmI@%DE;G^#ht4?=e`c>kYh%mLL?PQ0`uXU>BneWpk\p26^&\#+l(<3:BCUjR?2.&L'g08$8&LUH5K^CfnC\,P-E_l@ %IOsF&d?c*Q5m9;S#4T;<$.XeImPQFL?D.-KW"6S\<2`!j)r71`3]iUi,Uq=X5:JT+7hMMP>p(1jE@(l+DAoWV3EB)uXWS0-+u`\6 %6HJl7a,O-0a(fTD2Hghc8Up5QRASeRL#0m#VSW,b60EV&"Pog2)5VCM&SN[P9htOCC,6:u0']U'T[C$3AjKWlK'!0Mh4cn6"fF(Y%h5c>6A]C1#k>7)D'W?ohFJi5 %QeO6^[3'7n)NiKQXOP[*X5QuupFY8;H\\V>*Ojj#<](*L9&$;KKhHG11GV/anj]G!"b+\G,$u@^NmIoTgqcb,h(kE/O,C++UP9s3 %\cq>q7rRtkGo&F_4I$sG4lY3diJr4%2uruTI=i,'AJI6p*8hQRb30MkI-=&7\/Z)$C%lh.%(_SX:J$!liVdeJ`)ieTKjQ1>lOGan %(m,.a)d_Xr!O6j$M_aKgr[:PIQ>+u;#h:jOQAJ)-\Eid#&hLlEFIo.pe,# %<+8k)pH0jS9:/.'27LoO!_e5^qYMYqbtfaA[W5V?UOAsI\h]>q"9M`ABC2CB's#Fel)jo!/ub.plhaY^ %\YO?Y?\!/S=$bo;/)qXr?7_+]](&P1cs_g,"h1U:6G*!o?Su&tCNPd7jlDV\>@7SIfi3>6buOQ(oI0mb6?T-T<*Gr-VhC:p=aj3N %(2H71c9b$9)*__\ojBP7Qo=L:;e;`g*V@OciNaY74hhn#%XO0"?/2\Yn$&)?VUtesg_.?U&Ob0/XTh)*'&lNF$A=4Dl=YZbB.nnLe!9qWp>h2o47TcQC#FSl"8K %k\ZD1!'I!m#DY7WosXsAO^?ZaBm]XR@_P8t$V.ClfD4cgMN;%dBV?lrI\>K_j789+5(+BZkOJXr2ZTji+JZ35@ohGEq5WM2;$*1)UlCgBjU$DEQLB1(,6(n*AD`TPVkFX6fT %KtcZVr$A?.RG32iDKJ3`gOdt2X\J8ba7$umUDLX(BabV_ci`=/cLr`7 %7o_sCqP&GfM[sbtF=Zs0kE"8h9Tn$Yi3fFTR3XL60qY'fA^Y@ZF3B8`NbsRQZ"nN]l<[e*Yg5bmm$Bd-]L2FmR6=(MZ*[,S>pca/Dl_ %8W64UH'/eOP/N`Pngis%-B5;8kY`a!N6-Q7-/Bhe:ot5oFc[U<'Ch+@UN*51ThLWP+&;erA?fV'VXmj:LbdYJCc:&Y/h!FlDPsIr %o/BJm?aFl3TtP,*JL@X4671+f[EKW1?jghT4YO8 %:NNp3FHp&..5@5c^-BsD5*YL,jnS9YIF_W]TDicnYXA/Ki!?L*lAOrdcMTqmiJc:-:31m]nl/?@>fnu2ZVsRlXp1?P_[4W'"aCpR %aHcML)=tmdV4%')a^lm1d!Vp9])ChRVp)e6aVSof;jIldVfGdfVdrkVE6iI*[GDq_q,8\S<#`bt %m7a_kB@>/6mgjksgM.;S`VL!NCeBANS-#A(JrXmu>)8I;UR_6n]:m?Z9W$Q=@!=SFBX616V!?i=2)MSc:F8djhMfgJK[/V-XY6Yq %pn$>!R?D6Ik_sf,RoFQ:W*+A_RoJOMk_sf,RoJZlQjr-hDc6Dho8ko1cmF/Ams(%"pRkU#8VK'Zt'Rm>e_2u3CCbMGqpqae5N&s:U)]RuuMiJ`$nmVH"1\hL6g/SAmAEa.OU?bbVl %3V3\kFb!T]nN>C#ka3/<-/@/\Gr!W%@Zq#[K]7;!o6[+!SY$sjLHDQ2SRL\H$?K%bMuKioM: %ob>'if"BmXSDV0jM&#Kg;s1VD+1"[U+c_<^ULF%tp6$o"\L!^;"thLj3_Qs@8M_-1#Z^H/A/c!9n6SBV75a]CcY'9K#ot<:iJi3h %QEUuSB@Lk209,,G,W?l<2i#6ZmUR9b9eG..33n?0_,l*qNhU*mTApmA:/LUcp^>d8Ku[^u7^\]0Z"r)s#JEqh&t;mV3] %B]'j(W_O;N-6cf5n@OeU"h;\OF3nrul?93?_nNhoFXes[dMJQNR3XL6AU4G9as;fuM=+pNFfLp8^-!GFejk18PXuKt;KUW>;Q!Em %<;=%L<2WWoC8!ucCp%7Fc+_C4_`TfZhZ0K-TB/!mpG49o/N(Gkh(N9i0\NCZl0))^\[154GIGOi.>W>6>0Gumc-[T2Q$uX>5 %1RU-s(H&2@5/)OpW(BSXPkX1uMA>W$b %1odhJnTPAi+ebpnjF`.]At9FB.'`C0=r/1e3<*"HFLCkgaVKTtBt\^SM)VtHkeVPG!ZO?+PRAa=Y+#Z$mG]_'?kom=tfnL[`)N]pn&P3Lqerq+(,0@=G\nH$HoT1^k5nRDZBt.jG=LXpC+3Npkc2+LHKnZo_c0]F+0CQ72AF0lsCVoR] %$>7RVDK(`/.!coI7m!PLXU>s#C^/[aC.Y2o^f]_D_dr^UM$2kJ!5.X`JLqE5,Ab/0cL!bk!Jkc8Mi,47'-&?3Mtj4(%VFmX/s@Z+->`\ECA3hs#[`bd8S/Nt6p4of@9G-4,j,eafaP[$U'W:$#GN/Om6 %K/VL(.JYTa7H?i=&YCAW0a3%$i+f.uA;Fcl*;]KnRbY3ih>@EH1AZbrT4J':1?,j#S"Y?VPf@u[dYF23D)@<[CE48oc0^%#K3To( %/TgZ.@/jB'g]WO@$$]h],[q*T2B(irTMU:tUMI`3#'2Y/h:q8;[lBMbKsuhah]-Hp:cE]h1;-&`KK]g5\7l9V[u1=MDZL`WH%$G8Dl8,)j.-iR%d0[DFCKCTf\ZSh$?_586$mKS_p)XUi-ii2ce,s2;S1G[2Gi(NchRY9rGuNDh"[-jPY-hmF"WaM8%K1^ck<6^U*'kG9PnebbY\q++:']Q*M6C$Ulsg)o2[>$Ap2jr %-\AXsL4\p)pMH*n_S'l2:_8D'F<>H8:@4HJL?M=A-MckCp>CB[^j64iK,kepO?#u@I>>RF38[&F#17Y3$KmW)'V_E&Q,.cX3o"jqh!PjcFqCWtt(XBu8$/BElBaX($ %jL2$%HT)cUdJ(fJosUk"C^Tc4f7=a`@OpX;k[4)$[BeOO-TJ3/nh=s)Z*4g"%U":&f!oHp#E`i&5H?ZP=f;(gg0?-XN3 %?"]El,KUJV2VUki[,"FX=]2#WW5WTLm-a:*Cc*-)Vp[&W:V3C1U_:m'*OQfJU_<9<[Z_t.,p?F>6*&C:)d>uQ1,&([i2YUaUNEa2>$6AgO`qUkFg#>^1g=2NI)M%N!5el-emrBZJT.;kO?o_Gf1Yu[5l!U/gL8gETg-D!6@=>O8Au:9,%)N %jHWf)h..-E^_Jm@%5'[iKFS:hCDV)d&>XC=InM)eWe(aoHVJZ)qg`*:'?9flFH6`1%oo(ilReRsa1%c5_rFo5,_frc)N[cN$BHr5 %\A%dt#8s_Jfao>f)8q5Q(2^#qDjtC)W4-mET]+X:mT!6ERP.<4WnUP2"`76KnY!Ona.p(#!k!B]](Yqlu*AqGs.jT0Y %*dGLVDu`f@;45CR9\Pg3EY6'Pl52Ae./7A:Tm'>pY(:s@6Z-3r*"&Gap/9Bo@6WMVdQFSc/Q<&@F %@$rMjF)V\9`A1N_9!Ol'':-0Qa@uKMC^DlhMDZ)Y0SB%OdW`907G"89!5i$p[)PV2nHgkCW06^6Bm`OYmI>0*3k5=(4VO,AUh#AX %nN8$G-]qGi4ac.K$cZVt"1ll00S3n]U$`ZPfk3QY'egllmXknn046kH,#Wa?p;9NO`UDjh3Ir<(k0@u=lYI&8V?&<#J!m'#"b_*J %NM.KTApg9mIsadDJF1-f;;t`%SpG7[SUGtsk/hq:\<.6Ig(k"LHN@42RLO3;:LFt&l="UjSNa\I!-WYt/l#u;`bo/c"Ac31)k]P3 %+C'>]_1<@qJ.cpJbm*t:9+`4rFJTR5JmuP)]dk\g!&<`n+Zr*8Y'&"f1P\Ic3jpmNTGr-/Wg[=l=iqmM!k^ZSR\_"48dTr>,!LT& %4Mhnj(_Ii<_BY_ob!85FQ;>Ni#cYg6^dh4S8&3XknI[R!DL^B35gI4%@=XE3#`nIcT"G8g+O-)Z+m8Wr[YOS8&Q#ef^dh4FW=eY4 %']BXI]$d+d,J]r"O(9_n.?An&`?SC^dh4S8)Q,T@3*BL4@1/0'CcYKi=U`\_7U%-T%s4WK5!jikPd*-HiFFKpn-C0%ClE7P%?CJj %e]-f"fC0&Q?upFRH[#ZS(,IcW-$TPt(B]%Q`#'P8'e028@UQS^UnO6Heq;aWK0U_cWs>%KfnB2"OoKGnRNed0A#`+ppc!Pf@fo#o %r;66O2:J6Mi:1I1Qa\POjdAiiZeDNaFm7TRkWqi'-C8&U++/Crh;H)&Fag&X:TGXE-/50A;RM7]]h0ejB(A:>5]n#`m(+.QP0X-S,B0h7]#7(YqB$l3_b&ZP!fs7Iqnl#DHf/>$i+Mo5IG3Y4q%I-9S8m88(4_Hrp;'=(# %&Fa$b;BXV*W0l_EMk-lcd\nfaLB?G7O)I\I"a;m91Crh@"^Rg:<#riPEpGko!>mlu#.t#PPM=g.M?hE&E)YFjCO4La$YNQu]D/HV %c7`l7?&luVp!;6IYmHl]?<53N0d(K,3oCpA=N\-7,B&^O4nRSigEHsl4b]/U!nShR %n_+\8`qEkoYC<%>dD+t!?1+[DMOj:CN6_.ca;5HTsOhduFLDXa*&Vlt]V67mTR\+0fa.c8)q$+GW.NsG?+>70_9WWS8an`*2DBh"+F3ds1n\"%7>C9OD%9WMLu %]bM;0KSS2nIDI+W6BP5_>ltR"I*CqdQXar/qmRgUT:!X^Jj472*p2XO\Rr1qr=l@=EY^cbUg!iEQq7l^\"ctdHmAq=\s$EGq!t'j %.Z0"BjPY[g(De,Vm9(]#..D&t([r8.Z0m>;!^\'9DO?4L2o!2Hf.?RKnQ#.i-9,N'mj`k&?*s.Vgd7"=kFnA@;*iQsig$!/RBS.u %$SQK6<]Yuj(]*'KH0+0e]R7GDGA]T+F+3:i53:@[1UnI:q9TN']Y-qnRm>0AGOh.*"l0EuRL3M!+<8f\`JSdde_11$N&f@jhq$IU %-.^%:&itb<+\p[DpUeLc[>W'VqT\1Vq!/Xj=8VI1_Z\`gi3W8D3i[IE)p+L)O+-mb-!9lf),$VUmka`38Gfef678!T)L*c%H+b5s %n,%Aef"US&q!pD8k(B^C:UIrlcr;^+]E"cdfS;.Dcud5N+NYuCK=p%NBmW+nZa.P:8>"LlUbH?W0'c%.??=hZ-k6q:<64ok&9s_b %WILAl.FVlXLTOJ,h-n!"b$h?8\3aZ4=\A/&7'heE$ec-;@@W=>2RK);nWS_$qq25:q2%>eb?k">>cWn)^ZPVqI-C0a:^)[qD7/Ub*\.X>%F"[onEpkaDjL;tdf$<3$Qc(1,(^3-Ts61H=Bds1Z?=t"Qaa?N.d)b$jTk6+GMb/K'1 %p#rZm0coUob0A6/f\W2iDrf:92ZD=[pL!ObJ_qiPp[u5aI!q*Hfk2AOG#N9T^+`=u@(pM'EE-l2-[X2R'>gsU>We.TTBJc(l2ktq %8oNhO?h!^t3?X7if]XFjqnML`;sp"u(I%QE`-XiR*`;Z$ade76XH^_D563"VR:VQ6lR.iDTNR.N0^%b`F+o:-4r=p]9ppS/?626e %:a3tTcHV<#-E(p%ec`9uHkibBfI6@2XeEak`kbAR,]-=(KFj)pk,e9rd;/9%fK8Q8e@D[h?NCso!ePrud!P3__&g!qd%mWnh7=1)*19er_3h'1RJ?% %l%-ZM4F:"qotF3V>B#Q+/>.:t]s?I$,6fMY$k1'J5liA.H2ZR:j&Mr&8(;93n+ponBtOf6[K^%YH[:OgX1#NW7]&T@cU-BN#\X'; %Gdrgo05s_$n7D419`),&NlF6a=HK[[Y2$&J]P7m%JY\efq2-a/T#\kLMF`RGHsQNu_.8BE %n0=gc^/ahC<8cqOId;%'qE@Bks'R9gnacZ2,l=O<5p[nY3,/B!L>YSRIrS,1Jg0`]68HK7Qfr#7WkT4%="=mDT#4>-f]l"faNba*17D62".'f]6@27 %]R8<6I.>"!-qND2LkQHk\c+?]ekEY$F"I?3N!m')7bQ %!m8(p`k(Eq@S:$4*KHl@oNu!ICb;f/0U9FUcO$UE(qKKa*j37q+>O/KN,pbcD?"K^T"SuqQaiq@o:=S9/\#D8s2%VL';!+_EZ=?Wlf]D[ehH/[=g9EWi-*CDbj9"WXG57UlpL%k9 %"`*-S"T?=Crh$sp2FD'Nq7T#sI";5[E%^_5j`SNl#eTFt>Pl=_\fg56['q4.pG`^V)mV+0#3W%pPoRJ!qhO#u"YPcTqG;\M7[buc(8".I%%W%pQR1qF.^ %@kZ`cZ(Xhb1&=-I*t>D2_&T)=:pfRh:n02b0iV)aPdnM'4Jmhj&>u,Qku3[44#dGC_XAce39eF:7@p'(F1d;L`9t]5OTWL2!^d:G %%)_#;Zph(t\+RtdNY+3lbk2X]ngc>D7.3bTh2)YeV2p`"bK2^0;*=4;dA(j.X*oZL&uh9NC2Hao^1_g9NX0\MB9`n:c,>'3C %&NVoN/3COl@^g3<>M9RsUNG%WQF904$Y=IYVufR).`R;EjS %du?Ptg+[SnF^&GlTnL5HeA2bqKG(#oU5($O"!sHUpEX-`>R*nm&P<>\MkqbbW>=4fBEasKeYC@oi_fMWWQF>0rc@E9pIQ1>5T+e'/u),;3fsQ9:mE.oCBP:-MCbn`)PBp0JpR#m %>V4\u3m[,0@+#5uHqe7ANrP-U-pmDOb$]lU7AO+UD/i?bTa97g:[?9!><1SM3Z1^[p#^(5X=jM,4&uk$o-qVfPDE#`=@[FlB78C: %AL>>YEOhXeUm\IVP/J]`H?(lc#PF73EUoIXXC0JP?r26f3hqtA?p4@T\e2<=&jTsfC6QJN,*g=KaH\H=:.DT-rkcb,lB.aAUDg[0 %pT^9g<+iWKIo),?DJ]=hmBI.ZDIEc5+hZ2,X'Ip2AL]%Z<(O64oSm=3rS=,I9X(LX@.7Fc`WW>R4]+^>X.P$NdA_;2N3[59FEI"I %h8NCHUA&igbG_MdSk;B'(2ZH;ASmh6@m,'<[9d\,UI[^Yqe(0gaZDOerL>`FK3h&#;]'6Oc;j %?A%&C+CsVY05*#IpqHQi-Mf:E/celN6F*\*=[rsmJR%,tmm'['(RMWT`(2%\VOKF"*)6Z\H&_\W;uhR\\1705jbacq-*gbt5cBN) %8,))8>LWZb)A(X"kYD?i&7Cg]-F>i=+9X")1EaguJ.U%.mL"cU%3W%/XYpP0<37P&Jl!_C06-+aQagOjX\S(_:bpVdg?Obl;B"lZ %#\H\AU#JRRYo$5okGLmVhk#Jo'CLf5.Wloi4EhOjUEih5$eZNWmNPO'SJPQt-N!DWJLlAEgt^*Uk2EB0np7aPD?ZD$LOe6QB4K,STu\hmonf"!V_l<(f;&_2#KlF.@`4EXeaR>e(>S#;:HE=JX'mI:mMePTGiZHQ6; %4*@I-9>-]`Ml49a0XO;\+DkoP?BRZ3*)_1m>0I$;V5cXHf+%*J0bmL?jjbQTYBfE*ceuV3-'Ifb]eHLo%e<7cj%SZa8JenPHT%`? %"psV;3cU89@??e1@)P*/;-c<$]8[iRMdW"k$-\4X"d/k,ai(hN9ld+fZYsGCFq`POiP0S)DumJM?37!YQqVfrQ/8n/-LWE/V0oCl %5`I<7Wtq9N_Qu?rgm(GKEurE"Lns]h\^,*0]3%L20ZTOCC@5[@hCU(J2^'=\hE4`tW](/_R&l1OU$b@#027le,G1BOHf.dXYsg7: %))m"(-nl\8]oAi7GCjN^>6V1LGBuSO`]JN#_9*KWb!B)5)j9O2SDCfcd?DuMRCTu+:,=sp)5P1WSS!%k1/dfZ;:M_eT\F=HSmg,# %C!^]GKW;h6C4G$X,R/?jRV":A-S[ku]nr[lMa=hV!cK:JemcuX*.=rf>k1'p&NQpTSl):'pUT89C.;$MD;VD]2r(Qr!eaFoORMA\DtO&Xb.k)Fkrke^X!F!;OlY@OJHKFMNZ;rBIig`:!urb;T-e+qu!"$Ntq!7g8lb_R7! %(YDpn,pC=b0))Z%:M=RgDrX_NSiE`OYKoT/>4U`ONF:4F7RJ)(JSFA3_MrtPqQ;Lu)$-d>+nYJg04bYD9IKeUJYk`P`[@8)_A*=sM]:$'Z($!MNthKAhYlWRdS)]+(Y_&60] %1G1?M^GG<)nQ"HeCj`/>gD[:.qEPCk_@N+'i99)&riZG(Q\A;+7!S7Kp&)Qra;ms(80J._T7nm-*1b33H.+$O)QNUW+U9FR^g1:F %[&*Z5A]&mc7lqk1YceolAntpqF01Rq`IVOVKf3t%$cLLs;oeuFi.0`\hbIBRlpWu?2/H(+b/27e*'Z<6Rbol@+E[.\_u@PJZKLDT %!hYq`+LYOA.KJ53[/ZH;#`0p!AP/.^fhf&PWD%#(p(LG1R`^kLR4@iGBe$A4\iXT[dT!)#GqKWp>[5C8-;<'/17"e%G+(G&M?iQZ %\tFW,9pn(bT:^/cX$=G8V"\^;l%J5XEAJubQOZ/QHu(qTp+s9`l&P<#bS?s0`e1P0pfVH^0e?Gk4D %QUMdHhr[.5Q3YK=H.u4'eRSGt2T6j8T:"_kSJj6FG,+=hKA925EUhAQS<7m)?!c\,T4iH+G&b-&>&]td9q0n>@M$WeZS]5K68(o) %m\\7rL5_fX%)E*kO;jE5EkD?k>u:i+P)S/oS:W/f#5GoW`UT-rhLM@A'3.le.OAK1"Y.@Y;\%t:'u*$>jZs-jYVhG5dVM?U4`Yg* %3_8Q&"8&BLKcjL='?X_]P(<9'`K:L7*Rl5ICu:FNCiMON[ZKH'm'M+<6fN*W8&'%?M_#(74J\:@dJ^e)`$5Tp.nXY.[CXu8//F8jgC<4HWh:4uXS^W4_<9C/TAWA:8_b<]Z&VT>0sKfZ)e+J]:?35q8Z3p]mW\^Q/KM@Mc4;VZrg %l_HS^ASV:"<9G+"NS>f78_*8V=4C),ghpa@WC>6+k=Em,nq83S,UgP4\g[6*A@H4UDQST;QZ?0#2X(4n>4)l-Re.4RE>krTY*Qcg %6hBMp#."]faiEblP;n.i'ngKe9IJ*a+Vd(:*hUuMU7:(Yjr.3If$e*;R;7Kf,^rcZ+>D4m"_Y,>`50]Rr0F;DQK-8Q!cqe+mJOOOoHL=d,U9/S1d05_MY8_cd4N]tb>E0)]B'VuLGjciP$,Jgmh? %NSh&K>Y=%kZAgK@^-rKM_93\JK8#XSgN`F6iHJ2`>!/aX4o-,\-FIG)r_sr7@N$);<<+DT\_C,pA',];Au(Ta$S5KAn:VfB]"k$t %%dL=D1#IsCOK-`Z?!n7LYU3-YU'iNpR8#PVWI$u>/qBtJHM<.. %>Q@?s-I;o3_$.]uPqAaM_.\luQ"4pB#`tr2 %*f4o,Mo`!-L^bm((-PJ@m!4n<7SIsGE3:TL]"fN"5b>ndJ1e&3/m,$;>98/>!Z-A&1P%0_38YtQ?gPD\%-DnSO3k4rp\k#[ZhJh6 %^gCPp:sNF5NZY:@Dgu,hd#7*R3_n01>nG7b";g:5e?mU,)peT7W*_D*ct54K!;r.pcirR?W!+f(4E1[5E"ai+Q(SMu.o$IX?kHYJ %XtD+mjJ]itnD&41,"DehfW=[K`^uBLgX^7H6?IcIE5AF:dm4cq3X,7PVSHGcB3((b@^;EdbVH5Er\7?-XN'J)p**e&L)(VBTSkZm %cUrLk"'r!Z83.CQPbi?\Teu8_Nb(5Kkb7.X[3F-3i>k"h%2i8C"^"3BJa$.6k!pfm"obGf68rpBa %4++fO9\FI/4c*rHN\ler=pqM^RSm?=5It>XZEV&^J/bP^F)I5#%*JS5+^RsAl`S^bB984U;J6fXhmB4@Q.GLY7/P`b8;3^N>o6`Q.ObU%U$@FjDObWjm3PO;,LYjQ/@L7-pA'7Q$ %]k8JHXorf;+h#GqVqjbuVHWaXK+@_W&J-]nPJ[QA0RLj@u`i!/&)m53Hu_VG4K>?$n=MXJ'$[__YFI+e6mgs-YjZJ>h2IN)MH[b^%H>`p$b^M9^!qhjAM*NlJh<5sPoEKYYD*@_8?/$C&PF#.&4WV%"QabRa?[jo/D7d]NP0#nQH/"m7lP@R6G?82_s"m)TYSr8!i$G+q\"q7*KD-3!'s\:`1Ta?-0bSWNck6:P<3trni1[q6['X?5j`@g?[]Hq)?5m^O?NS.hi7eV %J)P5krnh8SGPgFl':7;kq"_WOL"0i@!*5^Fmsdhrc+.=l7A[pTRo$%X0[V^e"5LKL"5QUeWj'AL)US>eYkNqf+b;]%omhJ %V2\10n>[UHc#C@(*`],_*]/8>(/T-E^![ci$@%TZ])2__$ta9#8[TABp^9][g.kc+?g:crj"FeI+,8>%*tcDF:]l:Qe\ppXp %DF!9:UI0rY;4404KrTdD:D9rnMl8[YNnISB,suIXbe`QqU?[upr_?Rd**%b8Z)"BldZN$eFE9/IJ7T@,gDNJ><;eg.T_!Ah5Y!'kMgc4'b3ATp)kCY2\:Z,RoRk[84Cf;us.L*Q3rS%>ZRaZ8#Ls!" %QiQH<6r1A:#lUR$ro;R><'!V0eOI"U.*iH+ommCh- %VRp#pY107/=P2VZHh&KsgljJK+V93h=*+R4rb`#?c?TX8d$kO3GuX>D4&l9CGBcoPbp#UR>EQ'aJgQ\cG+h]UT[RG'422B`JPMD# %FK1.:Z:;ZP)53WlZN$0tdkE*,)SYr)7ZlcO-Tj:hX3]HPKr)(;^LV?Ig^-5kJq.t/:6CWBk^\t`KZ-td6HIVp&ihClP'P$@14Jk"`^aT'Q@71 %_kcR6@<]ccB3!sbCr>s?VTE%qm:gchjV-i(B!9Bim!F]hMNrDb0_M['a!VL %D8dap4n/-d[\u(,AB_Za2:1d)B`Z:.V;bcO9dZ3,KXe!.PKPFBgf0ID*W=g#9[YZ)R%XZWjR'Pum0k;.k1EF+g6J@2$l@)Em^sH3 %`SUL%I8E`,^CI8ti:K'tMJ$j"ZekF*qS2,pH.(`7(.8++pk)o+mc,+KRdir[rSQR&mH5fX7PEKaeN^7PH^3?/Ug"1S7.6)f(;#e7 %*O^Z@$7n9^>^cMcE>R*3$o%'GBbBKBLHqoY4&a_q5mKa/![4*a371&+g?CGr$&?.gJTa(Kkh7EF#O3=NP"lZs[3iJgDXOMFo:74R(8n.j/9Rl4hu("c&)T<>;\e-fLWBnCkgd#EF0o\u_tZ@.G9&gNQK&XmXWo,.)-5q^Bjjr' %2g$-pU3f]eHtlU6p2)ku@81Ij;b4l)Qq'r.':>a=*C>3dmWedE#$&L]U6EK8YU=b05lp2=j"JQ89-WL18 %E0gr0KrWn\582h)HMU>=7hW\=6&X-0+W@Ou]-t3$2*?\9=Ous$ %!YadpRcX:m4nCXmVYO,ugd6/0IKYLY@[d&aDKFqVjABbcfoN).[2br!.boikZpq(26h/Gtd>t6f7RTb=Z6)reN@=U2B_`5ld,utT %&bRO<9_f8RN;\Q9nkbJBCWVW^M0skYl2JcImss`%3d]#oJs1;33gB0&0)H#mL#VR%JgY_*8_>1ggaRl\N4>poeJCpV2NQ-[7SW@_k% %:Zs$=6sMlLfOjoZ_?GtTkg&X(`Hgpi6&YIXniU!s:54nMoY(@X&;Qhgr>ZXC4>fPQaEGALL',12ECDV?C8:R4,H`F!>[`DfG/P,u %RHS&;EK6;"2 %G-)-/=*9t)^].;#f4qDF6,L&&Z!N%u=KM9[3E:sH(>r/:Hl?I"KcamQ/e+jf-V1c&bHqH=A)Ul)^G7T`7a=YTk3EkGBu9n$OYK_: %^4l,U+%Oks,A>s`H/f_*]_MaQ62Ssh[;BtY-5X@81]QsBJki>t!FCm#RcU#"!`p3/V%lL(IP*9N%WS]cFo.WA-@*d1O[AF*)W_P! %5LX?B_0l_@HJXjgF@`Be-Hr'lO&Q0u8pC^lZ,[1&:P?`mds'@VUeEpisK;iXM-;6hKFHNaRGXK1C*U8d4'QMcZIN]Xnuk'SC"W=Zj!' %<3fb:FILPq1M_esN]#,bh8]j=_(8#tVkrc7ZV.:c0%.3ulE5Dk5!c=P,BFa1(+W)d/Tg_=a&OC/JInR?W8rAS\]2iHR8``$a./;% %?XTef],!1uqkImXVU;T":87aB]0m0]!=M<7S'nb;,_mg8B1-"lEY,)R'1::sj"O/(>j'-J:cj\0j1?J7@&Z+8NW#),!nVHljspu( %)E2A2DHj.G&pF)!oDV7Z.!'ZJq&eQ]V^J+fe6,0=j&Z-Q&*f(pHE`3VN %&D^b'$&H31Q'Y\*8!OEJG8M^/NsZUY^DG4,dKZ&kp/Z4D-;Z]7O/8l2'I4%+15r&_.D9u-l/T6ioV"i[UIFh6IkY;gW#R^je6m^K %B$6Bg@04Tg5c[aK++eghJKIcX*t$h=l[/mloH@WMJ/RufJSkFeA.PhNXU$"Hf`Uh/OH822XqrP85BgZJ360X$4Z3[u3KAZ,@[:)< %[+>2W]A&VR7Xi2N+C(2)d5m=nFcKj-&3!:4C?V5Fe*+Zi>+;ZpBGM>FgDEgo?Ar(@4oj6C%G&pZ*$mg %0JAaIin&*-X#Ac:8"3NLlrrS@[F^ZNUP8T_[iqUl#?o- %Dq)A9:F*F%i!`']";(@KX@aVc?8QWr$/Q_lS3a8t=7*S=`8QL:A0@B6-uoOlp%A:Llhf;c-hI":_A-,JbJ(\62f?1LHtbRar4hdp %FaqSNLqR_H#5&[E^!;/:M2muAu7`bb2.a"X2ekGk:X;PhN4iI=[86PhCm8X5.FEUtnhVYWX;\$QjUAZ@Bd^'cGG %>LcFl&4p5"Qk_L1))C(cP%P,cG)!C$6A9la(g.n\/%;Y,=u#UFOK"I3X^Q3urfqJK/%=nV^XS4_Mu9fKneHJ]DP@jA$5`7Lk@_[W %k$T60](mnE!!W*>YmjOM";ptd]mi5JlD<%UQ*=NN4QkR/of!2Dla]-uC>7FL:9'ds'K0T[I%NE?)<:8+\qd)-\mIGYRorOf2FES+oei1CRS8t7TAp%@s/"pq80.W*tb[W67a?GnfR;Pj6 %I:,FFYUK7MC8B"!m&&\1.t)#ObBSiomXI\2D!9:\?XN\N.fl!iW2/84.eX=VVh2D>_0928g5Gu8]qiJ,^8!'^4(hYec_fdng/94N %/SJFVfLu4\-gJEcQ0Sq#'Y57E?T[[pM*#mV[A:lm %g)XT*O6V]"erkugG"+t6C$?e-QaS*ddR1$f.11sRm>JEW*m.*$B^Hb:U55&0DcsldVP+/VR0MI=#Eo1#*78kZGHu:J7O%VeSGg7n=k3` %,6Auq8g^!#[tJ.D=(hq(2"ZErG+m1B!>]FW3K2.m]]pUg)dCgJOV14QcqDeq\b"\2HO5*^b&+KD9u?jJJ"Kc'PV1a04o%Vp84och %ps>*L;XI=(N#<2jHD*ZV0P3QU[AAf`O^L;Z7I9F@@[+Uo8"LCig1b'<6Ut.2D_,kbj*SSCn)ae&*Vcn/6,=Omk^`a %oN,h6BL=`73Ep$,Z3X_hb1RuTQ!=Yt*_HO\lr[r9$XLZZV5H5`IsY$(rm9V_hMo+(f0-6nho/S2l3P]sol&(V9U%`U0*:Is^@`5e %O%PJ@YWI6ImSE1a9^0!^cuZsImX'+PL1(Z@9QF:"@4=FPPqTGI&9&bp9akrYP\+$+O^[iL-Bi<_Kpt'DV'k(Y\$(9kWg.^WJU^MO %8/h:lcA7SVLn8X4C9=ShQ(l/h0/lPs2Bf\5VjTuYPpNJqABcZmG"khMA`3q$0'A+$p&>jA;J",;2tQ;Dg`9U9 %Xei&"A\4qLRmOHR"VA\#Mt]q`p&0H=4M@'ZJ];n$(U62d%C+_'?Q,O1op],O.e)^Had''$d9Z25o`rdN3'R1/T9'r3ZaE$"+&nmQ %Tu0%Jhnt=jbm+[GUPh;*"olUf.f0Q.u"MIp?NhRUZse9dFf/a?l_huOuch,.\%_T>Z,3-5/Fq_gNq#u %dM]EDF,[30AZ)kg4c2Y@/a.$4@$IYks4#i_Zbi\'S.(D5rkdDM+Pu#7X"UqH4LoMYg`Rg"\C"X2uf[2(&4dlIr4?In>@Jd$#-hoAU^,$OjBNf %C\Qoq-AK<0.6:Rdn2rZpOXVJc,lo5l'j)IN-t\i>:Cp<5%C/4o7d7)6!HC,V^E7n7It$t!BseL76T6Fn_[,)=I(u6YT4Ji5=S>=n %5A=7)k(k)_BS%pF.CR>.2O<)2-'(ijI66E1f5+)/(8g\?5sRH,ZTb]PgTKk3M\UXM@S3kk>%qr_'!\QUL?sM8C\S %"[$6oD).g&.r1BsDj-_63WHP6?Cgk.>'PCCXB&6]5ik(+t]"PGu*.``o7@kIM(LIV"%h/4@/a"nBV*q-_/:(dE&O\"-DDncdq$+.tM$dPnR"DfOHL/NL^fj-fj=r %UFg4t:R\Q:_R.)5M1_4MhoaM@=`8u3hXmcW#H)6/^-Ll6L4/##q#[qURXO-7q*JO$l=&DorPE`1cK-?cdFiEa_.;CnL@Z88J;H/+=\8/Zlh-hSHVj\u9H %#/A3N=LT9qAC<6>*MELr5Z2GGL9)=*$1*GW.r*C\874XbhZ\i;EC>Dd0[AabB0[_U?t!E74TcloR025ARg-fR!t4MGSR+;A#"4%I %(.%\S63E.7H8Ve4fBUn@!KfM5Ptl;*D?C9m=)&TaIia8R%p9!-]Q_O;=RXtpRorXG^!M)6f7=#^?lKgT&,qUTJq'u"O3L(hAf4ciO>`&o@p6YdXMNZc.^RIa7H($C![OHOQWODBjO^i;b\U*i\]2? %:u$kNSNlq]q)DgY9!>?ViS_eL"]Si1[j<;]o5+X8'=!fEl6et-XE8"OBFps;tYr;4%,eRo7a/j,9.2\gQ_E^4GVTkE;#qHmRdruA5GKsXH&T]#M)hUT9Q3SVf0l),?IkOi[K#,=2";"/t?CtK\eRD4j! %7A+B0Fmnm+i*B$Nh+4B!c6YoBaVBJET,cC*D:+5r=*cG2->EQ\#mW7[qf`pPP5IbCo*dZJRlLk?4X*2hU,0?+[.uu">a*<4jY%jg %p/`6*U<<%uo\LViUO8DJDH#G1qD?!COWp.I-XDO+.RPF,$>FZTG'`m^h-LKK>EQnt70EB>RSX9T!eELH7NcDroaK^t\s;k=n60He %M=%cbEf+VlpULQEbYYj_FJc!qB;eYW7qIS#\4$LII[qc'Jd!&jVV])!e>Kro[V80)RtG.L8+)l^^a4RgobDTlYd$P'YrUTq]G\d;D"DTZF6=5<.G=6fS-PT)DM)-?J^$tKs@Gp9W99Z-Cfa5uQJWHk5_ %WWFUh:G(mhb\b4Fb_!OQ<-uDle_XnSDSnPYQfi,LJ_>H)UTuY%MBA5J.r06,g,6GRoJTr\-^\siS(je]F"//Rr=lSRFT.[isT7qa(HcO=#Y*?WiK'd2#A'I!iLE92fK':F^Cr>ZgI@0.C,MObMao4'\Q7HZN3;D.C'u-]VNP>;413phL2c %F#(&BG:QoMo:D)SG*7>K,25C#&e2.;(?J5RC_pT6YDGACF#R%[a`\<;?uoSSDc*!?pM`r:3p_248YPSUW)on,4/jS0a2KL5SMW7"W5^9MmA.!)Qe.%0pE!J$m=M=mH1`nD.<_*\oB/'hWuT@_),iG/RN8se;s)a:2/%.cl9%/$ffc:0(Zb-H %+MLh'9Ba.;jOn7pm!tX%QY33Bf8pWCbd5c]CG%7ZWd*"BG]r+c/Xd\@PO7u.'Q6pNqZKN]0$d:nqh1Ooo1O;Wd:fEI[kd^&WG!Wp %F%):*7o3FToBc+iJQ+`n/XkLA.ZGLq:.qq(]X2s->+//KRp_k$Vkr(nh9n#5KV[;ZSkPJ`Vkr)9F=gLaSQ9#`]B7_rCbYfUQY33^ %Zhon[VGQ:*mI%[UB>*Z=HWS6dm53H9U:8L:h-l"MB:-u;in=.rclK&%D^,#Ib%NZ+d')9#,P2cAK#EN:T!U^/5jP:khBV5n\_0eo %$"$DVE@TEl\lUFII\>5T'VT]Rhb,RU3fUsoVi7;U"Hu:)gUXh_>M;.oCQaW6fP6e/-PYk %YUX!hRmeYRX^sh[:Y!Lk]LAqTec_dT$#16ShKSG,3tS,/60\a^+k*ZA)hDK>Z?@ihQH*#J*,279(`"C3RkG$toM5g[I_BIC6] %$+mcN\@VJ89Ju8Qgc%dQ?%-:$3C]*o9nYb2fMRdpT1P(OPCR//M>*(44cfJ/u0g%NJr"]E+[K4&=nQVZKfDZ2'beaHN %LMFM*^r$=N\hQ/T,+)Yj^I@u&8N[4WS4`9gKtCWU4"=cobQln`IG%AJSL*&#BUM;#k\kRpbp.)[0CWQ1:D*$+d$r5?pepeM/uU^= %-#Lui27pipi8+@GSb+l5J#VUa:rgISnKff7Dk_l3sPuc %QTHmHr'>J2s!A9\eG.6.q"]AlruK!Y$[C(Y+2f,=AdQCCR2S3^(Q@6AEbZ;lIh+-[q`as %pcQ97ND;Y_ZCc(b;G>[d_s4ls/Ski69l-IjFg<;$AY8^m/"Q]"Y7EIqK%DA6pQ=)i5KNu6n$"Rn4V(phVCG88lPP;3$%GdhQt?1- %&H:>Ylbi%sJ6VXV;\dS7]r&@q7CZ&Pnh<,56I %gRXAb"3;;r9d$)_$3iur8'SgL1bqnQ:(-H^P(Fi30Vk;!6Mp_QX^>!+&B0theBpEDPo8@=@G;n43-_ofMD3ai+:OT<(PQ9%KQ.%E %>"tAp'#e2:L>arF!S\d,kTJu!aZ[3@dj!A=P[\*4/aa5X#o1%l#_'!J@prHe_*d\VLeR@eVI+](#W"ld(QlS,Zf3U/S].KjYbbdVRfEno(/\' %j;P(?X;WW@gqT(>7`MlWX=1)1/Sul:>gZMp>1sHeXj*oYMmU%Y.@6C0]$o)Nd^="/pakDo(KM@No9.ZC4X7,M8;>H48'et%5#2Ken"d-,t];\JuR"@)I*5J1`L0".DLXrj[A0mqK6a[&B+]!R[=JfGeY#!G,_2GMGc`K8`flE/kf0M,DCW %7H^$R#@B,6b$n23b=`ZeQ%>@eMT)6e%Iq4^.Van:&*pMV.&!@WJBmEA8A(?BUUSeLfA;-BMpo6)L!-M:0^9iS+jk8[EoJQi!Ka&n\0b"9RSp %MT]cA#[$QsNZlG*^,uT*('7b')I+'4>Hl[k)@3i:I]31)q9s..I2_+FiV,5EkAc?D+ZT8:Z[0jWjZR<9O3rJW3`_6b9lF![H`S5g %*dYOT?5j]RjC;9laE#hJ'*_^GW%Q.kq9mT7!aQ3TE"obObWP9RZAjd?!ae^*qL%8mr)aJM0&)sg"XMs!-5H$SJ4J7Ld-F*7;@84E&?/@hRsaR3QpK&^lMXX>m3Fnn$) %@$S*AG9ac0*Q,HZLOaKL5F#iAF<:5QIYJ'W'-uKkd'7Vu=bU'[qPgcbRT6jtKmD]R2QO(?!fs)/AefO%9XdT_kmBUK^R:_`ID-_",G<@.:V*,JXfk)7o/+*9$mLsYRc^V/I*@6OYu]o.^A5$['WdUkS>"cNb[>6=q"g5m@%*O%qs?sL0dnC?..F0p: %h3]W8F;&gr7BT,"Ra1[t-nnV[DhV2LkuEn@6T'hQoW"+g(/4%!6aNcq?a\_KLp-ErkZD7<]T%qO?]NH6a=#un@S8n9K1Jp+%K.!I %H%Dr(:(.;UfQ*u'k:5Xn053YhB$O1Ycp`klt2mSXOs_;F/at)qEjr^&ADqi$t!!Je^]p*<_2_YYk^SW,rRb?l`2l %*Q7V_Z+PVB7/(6KGPoBp:LdZ@)8>`aHYU1c$\"JLDk7Db;^Z$$m3L]SI6VYJfMG!aN#,McG"lJ[fkFLGF`j&&A@'EV@pC:2;ImLG %m3D)9&kiq'p7LO+UuU+)pTO\H,q)!,o&-N`FE\)&+a"oa_g$0f#8$BUIKEd`K=GcML?MFD+(#k(i;$:>]H:95/t2"K*u(+9TUru- %$?QK$,a%/6K)\I[n\(/?*N&[0r+ %["Gj3^g+BlU=]>&STP(@Yu.]^rC@m5iE/FL!j\L]o<(kgA9ScCgQ2lC/ejZ^7j&cN8'C7I=q %6h"9Kj5?D^Cq..?3V__[)_h;$Q@j)sZ@Qa-;:lUJD$rF2=U-JHRP)NpJ8MNPrUe@e-Ruu4RY_68`V,T%[mrkdr+9]V%m>\jA%b:) %iq-a&c:0`!aM:Db^.!qJpH+D]YpH!XMMf;SStcSFiXn#W69j[XT$tORBRaCKFDudt0oCGLQk[:Mk.H_8FO_Rs_+a&]U#W01&j,HN %7%WR3-".X*6V#'nBpUAsHS9M"e9rb2&f8#u_mHnO[69k#2fWhr[MUZm9uJ"*]Z"h)4Z_"khH.Bdlgbg"O'1(mUhUK?2(\&^;RHcF %/:h+q[>,dZU6==u7b]lJ>Ju`un*K80]^.1jp$l8)>tij*"&tk8_Jncu`;39\M*a^La2j-uO&20f %5h/@17t9nOUt>rO[DAM2hVAJ/rFQ_uh<1i"Zk90MK8FJMm7*HeF4ZFc_KUJ)`o?m[X0^M2PRWuU:FC@`4LVh2IH&ItFaaqnas8k9 %gKp2Q$h-X=+CI:HAc\"YB>!5MTd$P$i,q*Kcr'T %YbsGYa*<9b<"D['!sWsB\ihaL%N%Jb8\YK74#MM(BEoO;XA,(.(=P0%Y_8]_i8QY3]+INl\Y;7mAV6ak_@H@ei$_cFKW3[5OSi\3 %&892r#W9@C6_GkiT[4F]?jJT##=M?ub#;MJH>,=qE^+oXM:mbj>bEfICU=-hFHIV1*h@jUPFWErBka)E4gd-b](8JF/2P*DQgmos %;.r^Aa_.^+&]4duAnS.S %5Cq7!DedI&G[%Zg^^1o0YJN:[`2/`cA9!DUpquKK2IjBY[QMp"CP(Tlq@JuKl:]I4W3>r\^-u%0S4VV4C6$UgPO(N%ot56)lZk"(:KOlr %cf4:&Q^ZOhbRbRQiuVKVL5C&D)re_Q?(u'n1rP)*)pH&V3lJF4+*2U]Mf:;*L3_2.Fa/]mW'?8:EJVeCc#7`\99VGPC5D0g<_/+f %6X7.NJt*EV6X0`#O"3Z%Q6#Zu]g-fd>Ckk&ZSB=fJ#AEk`5Xe2f8E15>h.22BuhGD>-A#`K#:(kY:8F?.1:O+6U*A]EJ!QDju-#^L\[MeN\d'kr,XC"A4(uMBT:[3^d,[9YX^<>7V4nL#MbE+JON94S% %0/s7gkUO1&[MXLHHA2mb4b7273ND5N.l3rs/S],5B&@cL;(FGkpUU)T2h!tB6_8Hf2VhC&YCJZ7X?`7+K;Z=H=)Q?.d@Tb-/Ogs@ %g3C3P-0?.Lac*qOP%m4+MHRJ[RaZ_#-_rom(G>7@nB]H%S;$R_9Ga_L2H*o,c#hq),#3:.UCa$sUJmPh@^\u+s'XC2;TtH]=20R' %I96/_!rj@67Md%p5pV?m?]deUq+BAkpcTrVhms8^q9A+g?rZ?+.BO/SVjN;fe@A#I[$u9E/-H8W[uB^)3&eZkl;m!jA8DLhMU+cW %QKj[n,5:tfdAnip!q(*Tf=m!Of:Y$[#NV`/k[?\a2e@`jTEYc241Z40L%+/<^';pB*IY618`(=-iu3ZAAC&T>7i&@U"m0MC %Ouij)a/ijqR&I)Dkm`O()P7FqHm\H.ccrlt[1?2ll=^3E4J@HY$)p@/1r1gm8\HQZ(AD,X1[]+TS\C>.U7;X;!,?t+pV)FdY@+W^bYg\Y4r]bYA#S+ZEHZ>our0rdaB,&Ypk%2`[ZS=r"d$.n"YiDq"s!@V[R][]gKuK?2%J\+/bI2q"WcHmg-QoS\r( %n%8c!AT6*!F(61d(u=l[gi\5CY'qnLne5',IaG\e %0"g6Dp1Am<0_P!bIu8@'k[)+W\;2U"W14\m5ShRPRCZ[@:O[`bCkMD!mO$SNf<7@Zf"T,HF`eZnpZXgNk$JHKamu7JS^iq)W>gmW %TGu11VjR:-^G6r:AA<;i;?WAa-#/%MAU*[R4ur<_6n/%66C2,^i'Gemos)6K=;ck1)Hd16rO0pNT&\Wsnt)??)uXP(@\V&X%ImJu;;HdY?HtO[\og!Uc/PVOEGP@<)s4T?*=hFJL+80O[R^rA-*9>[CU] %_>a;)Y)"5q!AG3BW_^2X@[**5VaQKs.3!%H#5lS6`o,[a6c>qJ-/J;N)tml>Z0gX+prEA23P6WfS/jU7-5f[%E,*Q6FjIqbLn"JY %KgO-G,%nuQ#Bo2;XB]J1S>PAkC\#YNc9S\26I=AO1\83pZklqo?b-5j?BT_*D_,O_7ODYHQooi]%-.JfHj>]gl14[WVP9TkI*\L- %m)*\<:P1ihd&D:b[>a7-N#ZfpF5FEsAI^]A^OVq0Wd,hi>L]0$_M1:J!bts=qWL]Y$bUE:a_t;fc-e%K4k]\E&a?Zbi46-SDaZF! %KTkq*BdL-.4@,UX"7T:O_UpS>R?J:bnQ]D*+$%q-#p'o8ZX2]4VQ,K@7]Kb'CPcDbWR`ERei3T %F9Z%1JOr%XZ'3>Mr/60Q?qb25=/VM50F[?s!NS`mg^'i.nq2kXc#eI[eDu%GS$A7gbiL.#o->JKg,:We]5V/&B3-b.,+mgYek;1R %)%:g_VYCS>F9\]?B^cmukmT0t*Bo*1SUnSO8Ao.C]@?,0F\'p!:fpIY]+(<@R:\0W0#'mH/#`X`D=e(>nO=,Hj#-;d\[Ri0s3\cE %YtBflh]=(`*s;+BgB$&(8@"8@n1ba'gKMg"jD2CpY3=mAV2''L$3R$H[+7Q9-^kP]\>0qP1F`6Q6m3F[W\C_a6?iD::89(!(8j1$ %rC7A-,L9Ld2'Gs8]iuJte7>&?@U'YU#@VBO^,0Q4eu>t/Shhm$e8h&c:U)5H'$BDSq(<5t3MsK+'nA'r_fpC_4*rWSDaug4 %8L(NsS^s2h]6@!73.n+G%ALA;isabaW"?q-*G7&^U-@^?a9fl\2QSGXO;!S`$#h6WO:tO"7,^1N?B$SDg!FaS9Z:2#A2=n5:<]nk %Y;3/6i[&Y&SJ;L-7aBjkg8XCs<,$%IIoUglfYbpEr.1'R7;pu*5Q%LR;sAFT03=j$Wos"R %`V6+e@P,CI<.(mm.gGcTh8eA>V0@b=>Uq)>+d+Nik1@=BqRd$W_NpX#RPE=TG/OmR3B&'h7m;C^@!!7>f %6/`PIb:10$g)\u5el-s=1OO1o1O;XR9!6-$:I)3^?4445"*Tt9+2a)DD;/-$2u-+7/-P-eOs-KhN_S#%Pid>&f^!0%priQQB-C3e %?$D*b/d3h]*mhar4djYXB[C'=;^U&Lg1sE:P?sbdAF&@!nSPC3#YqRcH@,,@iHoZO$Gfg`rVX<0T(M`'jhQfK9Us:e %2ohb,I+#'FNr5f_@A1HCkf:SuO.sSAp>`u(%gei_\$4?#&m8u37u_\6Z(QFpFg5?Q1&qpkWL\=4SB(77Kj,BQ_<*4ELe-5Uu2)/+^R(GV=\q&sM]9gb%+9BXE-:5W( %8X(Z?O"IL\E3\;@IE'LaX"61iX>Tgj7?BB_Ns]D-\4Pg+")1W&8Bq$Qa\'*Ad)A<.qNnsA!X[ETjf;r4rF0FNAo#bGT(B/DX!IO+ %mg;g_X>$MNi*macOp^"s'r%^chn8ri;RLaO6"SDC9=XX=]o/]cFg6JR;Ci98ZN08C*qI&%n3!u^FW:+o(:jfUU<;a:[3V$!aVEpN %ZS0PraM>/\+'ia"'JiP^UZb"kXE-8uU^_Z/btWq`V@\i"Al]6*0o]lng9XC2SRH;;M>""`]#.p54=W)R9KN)^d/rulFMp7Lb[\H>(R@Io4<)&LS!d]SbTON7)s]P&q[nO]9)<89C'KYo2a8&8V3Fi_MH %=6d7kSY&u/7DdPMuDjnPa)GSpfg_:D(kB(_9FTN)'b,9P8n@DVpBE %gMO6&.BW"A=Ji>#TuXgq)nA;-76,HYJ)on[J3u3';DgQA7kM-gI@7YgGVWP&."'T^q!paIc=*2`ikjh2hqp>NrYSS*b5-b9.7?'/N#Mb3`jUoe*k6TuZb1qZ^ %9Bs&&iH7d!J;SSoHXL#t%8pc^p:tW?8@Jg.5gg,YLqbl+4'#L#m,^m(;22^g[_5,3m6UFZ;%G2e[.tUr+#?K2&$5CZn*n'5Xi?hD %*K9br8X5aBj^83l-XCJYQ@fe#/P2md=6J_&ku(.qC)Ek)kn5eujg@_*$S:-YmVq5pljh=$HH$rs?'I,s'"W>u\nb#,[iph?r`Vj( %(K?e+G9n&0ZjWnXK'Sgmd4RDhM_#dKEmQF":Y!e.ZYtM<=^jTGANi.V8=%a6c]sJfh(I/nBeITAfTG@d.Q=4hQY"bE(V:CF5k^&o %``$#,?d*19CG=oXLuQEQ=b;M49[%'b9kD.9h;qKb"Lnk&#^KP7*'fF0838>'3;V-ugo>f.\rSj+MP:_o %dd3HeK$7f@@7W)1Kq=Rh1tKu?A21T''ccc!qt_'[P;lpbheKEi]>Thl`*q+c4O;<'Xkgr/#::RX,,Z?.Dfat5Ck;_WTR0c!bK8)H %`bi=mY^G+_m+XVW3YFq.kGq$H_-d/7B_WhBNY[_\X(RMPaBCJ!=`Hcs2uL4BO!$K*T0[@8fPI7Zh&ZgX[,^P&f#*JJ$]:+NY@Wq" %on)I>G':c&d+OIdM>h=K)n-ItgTt8O#E\7Mf+AiD):o70a>,7TV:'*ojb2#?uZ^9%d1p'RDr(XkJrduKc&6H'nJJXTA %_.7&&_+k,R`oY_\G-]Tc;1lab;:A=@=XNa(9W/jg4j,*G11:gj/D226A4"n+0[#,PGn=c'CR.Q61scP";XJL(>nEYO^meuWRAWkQ %WjH9R`f6t+NPnX>CYZ"([EK(7anD+l(mD'a>?HNSRuO5O.M#^AAiA(JW`<@Uk4]lp1=5-&1gYuA?Yjq#M`ZbB\J"%ibSI&.&LFc_ %q+YfSbYoen1@(pBo945AbYof1)r3&H_L.s[4M@OqM0"/uWuZ?fW)EHtS%8UN<"8Hac:jjbBSoa1Pt4=ZTjjT$N(t%tK.O?$e4An?ae74Mn(u`R\E*a*UJIe1[[*H*laAlmWf7B0gBj9!j%\AC]8@D,I[N2A+U+NI+/N(+J`+Rb6hcQu3nY423: %kE+>6iTS!M$*F9".hfb$(?#Vi=/='8m_.ZpcjXg"R!8aLYhT'&N[%7k"_#A?J!=99Jon!S\rO.#A4MoadDadL5YuNtBk\ZUQaS,5 %X7T>o-eij@Bk\Z2-9Eq+Us_I%HD0Upe'^FIE^la`6U9"p8=.oY4rUI/QMNR1g'?9=lPdHc0.t)6X#B/,q86%-qIE%5@\pJ4k$Fto^8]YR[k)@%:4SjBED8q">a3n7T"R.>P+gKECb(l %UT]h8$t0-I0m)S5?k_@]IK6Ni#+1+X-2^LJHuE.r@dSIjN$<*GE/S\GB@#sj@B9>XCWl*@Bms-O)_j%Z&G'"&s$V4$M\(IS0;obanF;ZD`^diE<)`l$`R+a)pg>G/,_UN2FdO%)= %X&@_5:4]74!K55XN>,LK)6go/h+iP"q8rXh'9%^=AVZ8];l4O+Pg>:LZ%o^TI<:en[D!"<`GP>pZ^Pt0850hWkq^l8TPkdq$"gBW %`d?g&Rq+=mN7,G$fS@Z9NV9A"+<+(uEGp9ObT_LBp1lhKfnGHaN;EftO'IK_iH!5/5,S&f=VK0e(n>GJpsZMg?HlUp3n?:DD5f23!\\_qfe2=hY1DB'ua?dP;j[!e22l_C7`]tS[_m;*#nUhGFKD'7hG"/!j#Jp?jor=t!Fk&"mi?Zf4C9\@? %7#M?JQT36#"+K-,,b/R$rTW_2OX*C`Pe,L3Q1?ku?M"3d2Em*Ff)O6c[.Y[SAl4;6KcR.J(9kEYgkE:)GmR %^8e1Y'jUX>b8"P'0E.FG?NnZg7NOnJ:Il"\l#VXomjf7UYU:h$"(Zu99,([90tkU-gaW<-j"YPK^H!XOD0]6 %RN.ZWn\e;=d>Fm`S]h'MXUBB^)LY*jkp9`7Qi1\V/VdBsW@7#mD!=t2S[>8!l"!5&I.7Ma\Z:_TCV'6sOb>Q"R2h#E) %I,THuWX5m;^7LYLrlPfinC/+=[N]IO#.tqK&.7n;deiJ%=lIjN:56c+J)Tc7aEI%AeX,#4T%pjYfq&G_I=csgm_I/p+oL7&\9B1i %e)Ls_0Qd'R5571R8,o*-C(]sd'MZV!IFumO's*pVQaL8d4&M%#&+Kg2m^$.(^SCZ\jK`\g]/=(EOWa0qRE)qUo4G8WK'q&b>tA+c %e6PSZ89aTD[XQcZe'_N*WXH/_J5R%qJ*bZj5AgPYV5:bVj.at-$Tkpm96G*_4K:@:TC_^b((l=MI/u2cs*nH0ks;A/K0);'h5-sZ %TUS2JGA3=c0'^#@96CQB:?kX]Q0NBef3MR[$hO5'F;J:F4CAl7/,^\dNIFsc%g8ofj(g]n"\oHm+<@%Oa'QMYkoSpDh&\&)@$\cu %8pXodMh1YT;2)#qnYMCTG`mteHk!UUkbX1%ha;I<"a_4X;Sn%/CBXfb]nh1SWu;Hq6/^14%!T.1V=rJ7!44d?EYg@cP?WiMUKP#qWr0L#qii*6+X??l!VFH]%\I71hs^"S+F.?:"mQP'.)Ql%m#J)rD];KAul?\ANr=!+'-nh%s-7IXU>k$pXKFXm#* %pUX,N*fQ!G8/iT#\_:IPXr<3bhps8nkkPdW'`JNW=;3+I=Pfe7=B**%/u-lLIOpIIM:58a:F.gT>\rr,bD2%fTk7Ak_=L*.0T)SS %6h`=K_'nWL9K_I#.W]ka`pN&[$'hJ`2WJt'c%I]fD-4O?($?AM?8 %5=j<;_tsSs3>cC0:W^N,gO8oD^:5'2-*s8fCF[9EU<=*[hb8\_Ogtl&c`0=]jY[e4AC4roIMai4TcKIClnK.s:)7,iGaa7I`(=W. %2Ef$l.@6`Ja6I/'#8FH:O6O>T(CE%9H1 %@Q(Zn/]be)=a$)jW'Vb1!bjALW?R`rL\@U]L;$T#oVY17aJ*\+>0Ca*dp3#lhAe]6r,e:KCRuSB2ViM",B5/l+?-J4A28IE;2Ugk!RW?>PhqNOerU@.+b8HmNmPcrUbICBqGE:]g+&_3PpULkuu\>-Um<6_PVE=XOuB<[cJUe#hb9 %b@7/soKo8@ZVik#MIIuu90X2L@OMqjPVcjCfQ&I#%aaP*/k@9&8p!F;qPOF;f<'/]E72/"H.SWoQh5/%qJ-,aAbI-7UXRQS>s_9WptrB.3"*]fK6 %p[bc'GqQ:$"u,EI@,64kmXT.:hcV81^8@RCr-?Um+Ic$L)T\,GeA6E0E"E2c<6o$=.t`nE,e&81E(@;^/SINKd=t6?HI'na"gj %)1$bBK!-rti5o:5g+cTO3#V/-ZDN5IECsVaUS#!RFZl)CIJEFpaC!_/h3lRr-5D5"U*.bh[d''0";"O5l8g6Upa!ZdA)rlMj-,-X %^QDHXN_`Q?7b;iVP5?L0Y:EnN,bEsPPo&P/2Xcio:"^@]7:'&=I$.;RP@[VYSkhGrogodCH4>:c5';3Ujc^C!GkIVjFF97gEA8\: %XS='WT=galgKD?rp.:.P4Jn@.H!LU"(T6i<,[Ih/0?td)?!]Qd6t9L+4BSr4b.Oki]@AgjN_+>X+eN+3=ddlAl>*"[=\62^e0c[j %Ya\Ql]"3c5&(j#!\@=#eFHq7MaimYC3F)g;*+kJd:0f^c72Cl@)Un5'3L*("_[iFOa+tT,j/3=^[Oi=DGoq6m6>'=JMSY*8QgQ!j %RbOW>V3M>],`i)D73MO%pc!d'K*tQq9aa,GDPb`;F %iUC*k'ELNkmIhN*Hl#MSrO\$:2F1d[jE`<#g!MWI@A[^i6ku!cl9c_[jCYpL!9X?=I42?=2sNd;^;U3JhK.%CFeY*0SkDLD??Xq4_:_^iLG@C4 %\o^Oj("c:6Nc,M08iHI#P&Cr`)iO#.SM^R#b.P+5IS5jQ'PbL6V0i_bgP)Ym8'lhh*iu1bPSMN0q'M?*()5R"qp1?2F$4IPi1W%* %7N^PsN=nLC$hk1SjB53Wi<' %G#g/iV5PNlr^"jHGeaW[UD`NPL%%*ViJ635@Ys\d+8UO/aXIj.h%\jHu[CSfo %W8?BNAMW3YSuSjq1Xn8RbfjnJ1I#h5S8;D+F9%>rRLH %^"ZDtE;qfS_K1imp"JO?_OZ0h=Kh+j?7$L>)>eXPkPgqL7F=7GnM#j\l=eVgSY68F:dW*VU.7;gY^(tC.`Zu"F[P\.K6=2&:s %k4,i\_1nM@+KBYA96.Jk"38B4,L'c"#pSLL`!F4"$E::AJ==2LH/<4/@ZdGc1hK?lCE,%Bb %gq3"M#qCcMmbOU`22-B9Lq82`Ll'bjMc!Q*/[sG-Cp1gV/!lSFm)jM$Q&qf4*6p`4.T/]6Fr_0UCe)N6>ZM;DVf"cG2>$RR!t %VdPX!@-PtNd/l77pDdH8/bbOL'J.]&U.m"43FE!_)QJHd3`Oh"")3fV"E)TQ]^J.X;N5OP4`NBEIOK5f;l5TKB0O+tHA)Q)*i7Qt %jPRl"-M]+uCd(VPqUPQR\.+!PNn7^La9LqMYkNLB^MmXM`Jgnad#Wt`"S+UdKR*(K3=LGr%WZ'AcsHUuNbq=<8bBVb;>_@m5mo'H %>VhbuDVMl1H_eAa6\/1rEetj=ac:1u[?17,efZ9Ioq\GcYTFU6Q[QX7c9PuTNDg5,> %<(`r]5LBf0#:&)(kgAp"!C6pJGNU@;qRf2l/6ku&*^lV(rV!lWr2E8kemq/7I9SCo4J&/e=._ffJ5Z8TeVo*AOm`,hHe5fi]!AcJ %J;ZZ!8s9tR]iP4L/?ffk7'RQ.m+]9B5!ud&D,@keuSEJh&sanRnY?uH[)5B1Eh16^H+FT_m_FpL$e]U_s`ElUJHBdMHBfZ$WO(5o%btp83"6sVeJLcQe>2;i/6"H %.b0P*;oQR-KaA">cCh_lhUaWO=`KQ]JCJ[=!KGYCX!>%-9>!7KYaqpt*F5kC=.9 %@7-3(7P#L@Y(+>oRTViZZi]c&PRSk#>VIK^+t5_HmB]^2Lid>M887U'$>HD4mL$WDCITSP0RbHc)NbGV@erP>V,2/](>a3T,AT^$ %BpitZL]fW31XK?Lo[C1=`_u9);&r/E8G[W(nF8^]WAq)qN[!p %[D=uKbXTPU*YL:hVl)8nr76n,`]7&s\Q\cREEWJa;Ne#E7Mu>o.VQ7YT@6;nWQ3e>oWb:>iE($CZot?Ce#+Ro7O/0#`35KFNCXE% %$"ci)7O7Mo95I/_)KRIQ>f80GeIGtB=m!A$`IDusF&@<=SYmGLJ9L6ZaJm@sVVIjHfB:s@G&9k0k)^IG/D67q>gTf+D6TCN>^5XU %ANOi3e/cPjN^91V#n1a,4j*E&,&7>\IBpMJ)JeE.Pj*9#^V*"0]Fh`e=W\+Sf?^>3S;$m)\&B:,5,j)RFH+u:NHQoc-#812$c9Q= %)Jd98$Qbb'l5:E'Tm*M1c8R<)1F:OLVU*qc_)6mlYU8h*lG87U^V@DP?u1UU+k?;L7hUkk<_ThenSQKUF%Z4i>Z@5i)^t$%(!-aW@BBY\:4aIDhF)6DlXRcP8B*^,nOteGc-5EYP-^oNj)?DNW=T,Hm`)^b=jcp*JtoSZj0":9O)dKW5aO!J/D5N2S1m0Vpo0@W@eF)Pi16O<+c8p`a %'=sH>[OE$*CT/X'*[,b\#-)/DcCAD5<`BKPE0$[X6d':(.X[ctY`!oABRE-B(")#om`HQ6;_X7$>H#Ki^AV/5>(g^F2I!=s:-#L> %Pio]ECT,!2j-\b4<8e0Kk?Z=>?@4l*cYqp$WmT\bpJqC4Sp;2;YrDk-VU-2_@jZ3?7[_&-1;O\T\HnRmd">g(F[ii4Z+GOG`i$W' %ijA+4FJ/.q\nb$Kn`aY!"XQak-Zt['pgbo>]/++3B`/05&ct<(=h'*`Fqs1_#?%bt+lK1=Omn25en0IL(A>>ce,CVqO%pL8_&1'!qO'IJ^a>o>_EXuQg50Y0Xaj8Fs,fNb4:d3OSXcpX@&NEr8LOf*)t %3Jj@\,aGkBS!1dWaX=P7%XYDso`/-0l,b/q"#q.rtI<\7a]A.*6/gCB`AZb]r?-!MN6>I@uSAAcL)oH,9qGOJu7!gCf=>R3XH2^G.FG8 %W`EMZbY8p$lP>(=,qL?:_/@Td9jVj#X0YR@O/P/^E)(A3a]Kpnd-5bnFDuo2W[W*REYm(cp5rbJq4f]DVkQo`XFROk/mFn`'De44 %9X&&u:26:4^64=6S^]Ws9nKObl#aBe[`gb&,WEO,mLl_f^#%TSXDOl!RX,H,`=2"o*[9.QiG5WE3$$g1`IoUL.aWO33D:V(68JlK %XY2>$',ie^:oU;j#oP"2+ktU3mlo2QES-%q;\Qg/3HfUg3Kg7%pAC\<9AiKYEJ,:C*)Z5VNutdaXG< %dWr#u#k`U@X,iP/5'O9lD;N.XgT/Pm5,id=3'WAd]*@VuZUs]o@)^,1NJl4+JpB%lI^@[g*VcBn?fMZ>&%+5cp\V1RYcMbL6r,Pb %cg#?+[%i`j4'[qiKG&04giRa"7OVEd.%29CC2[N?CDdqRG`FFk?8*`0o`QqV;!C-UN)WHSFWXZ7b"FN.VEN$dY\I7opfjs^$JajU %?^bY<%_`cjaT:[%/jicsDq-LleqqsYQ/Gpq>RVq,DL=@NT#B$rq3XhKtglb+VV4T$d&mh^Sq+AH(%!l*AD#&2eC!*P[C#)VNu<.k?qEoB[Cd0Ku% %8ct'gdp)H_r?aE1@AJMHq40>MiL,-N.?SBtP+.0:@MZ?@&mC2.Zj?,i.A>SbjUi.$oKR1]b*h?Z55dT- %HrgqOjO;H86^*[J,%#I(F*kMDc=eCDjREBb(@-C&Qdt78UGmG3 %R)O"+d2RPKR)Eo$dMbj<2tTc'?`)0hRP%:o2[+M[D=KHO`Y2WER?6PLCIRl-.oAgn=?Ap3LSsl-65JcDbL%8t/N*:3#d$#O>mnu/X;\@jc?E%0!#ifmafcU6lPX"ti4JKb %s5PS\VOB!hNcPpc+Ur]um:`dK-"+J;4"rbW62A.OP@*hcr:t:b3eFJ%gT/(!BKjc:"J-Z@Y3u4b)RHGg0poV6>aiLTejZ.pKec$k)=uf^m])=79o@3l:VWV]l..t %?r:t&1+,,e+uqW(6Rnb8RoVTkG)gBB3S7c<7-s1ZFp'b+[.e!"DH^H_KKW@2DH^INL\(>4gpGMVoFg#fg>;_(2Qb=nd:+oE=V^lmMEZ]36"Z*/cD]OYRYHEO"TQ`V?5n<6 %'`I]L%5m2XJBA'a$j@P<4VX`RU#7(Mg^lRtqd8.SAU#'qf/&kM*gBCV#i`N3flHMWCifnU4JLR"5c^Q!7("&>Hd97ie@WP`;M@A;^/IKVSE-747FM=_"@B9cnoWK#7N0aVAfA;PkbeRo*p.$n\-g7iFfm@cUI5EpsJoc?/t@pm=4sm2qfROh^!cu %5*7H(r?_j0.AkfFYqnOHmOq)FKh.P`IXenY.lUkmRJuba(Zk@^2PP)-h-5)r^YJ^bcs#0:DC`LtV6kW,LWdgpP:(Mj&[%j0s.IVl:paGf0e$lp(J$7+L$! %p)aae$(Ro8jZ[`r00t$DP)O]k%1(u>]a:'0mn9a#GS/Ek0:1;^AV<*ckk1F8I3lgd5JH$9QO:s:$oCNqK%>628j^WYK+C74^-)60 %Ij+hd5XhoFVt&Htm6T(ofM_nfX!MBSob:HlW[D&PL;*0-i&jRXXjC(K70I$0YN7"/6j,@Yi-N_R^3Qj^HsIH0aoBg13qN>4Xl#JSHth0JVjPJUfUj:4?2Pl]e>G!tPO#Z,Yp2^n&6W*EC0 %]O?:`=h1+`7LT,L%])'0d[5l_Qg9eY3AU,h/5eGCaWd.P&TV$,EgBQ.ga8Q %">cckfaBZ@FFi6fp-dk3HZ"Z!@L@H79G_6G?e(:H@W5'XAc$iYcI[)T3gR@i.fKMR3N^-\n;l!XA"3lkhmQu.9AFcg? %4eLG&cJP9,o6'G>=#sO(VlicRADm@jWRE/D>">-d>r/<4Ze)iAnIa\.D.noeVJAa9j3"4^`CJO?A %UhfrDDI2PfEhMPjiTA+)j&Tpo?tT81=n>-O7A(e7f4;r:NRAgc*BWghR[;pC`Q6U*$8!M.&WsB^GJrC=k8+E^0(F\(^NOhe]g?f2 %l@c'%63XOZ%^OUpY:0=HW!A#9=3KmF>4;D3W?/D[k";HBDf8[=/bNLQl:\Ug*i'l"`_gBuK8LKAT2Q8t?tV7TUj>l-.K3,A#LV9( %7.4%bm_nkUFu'8_`P9.=s*qc74+)tL,SEH--Bh",]AK\3h%tqQ%(*kg9IWqO'\_AC)#qC,)9ASPE1"L\#gJ#]ND73a'mljo,F`/V %?u\4'bJ%%&'WR'rPd(\uZBj,i:&]j`#_.j,7=Q3Nq30I/>a3Z%"l'kA"f%5=%"j,4RW5EV42[oV5h>7%$b`T+*)#WTj&j\9@lTQM %pP::FJDtnCU/V1sj36l,hdC%DTn]O3<_XeR^Gep/8eo].;Ro>%WRS/S[#(&A+KK)o/&!N*"gVm?(?+HU2Rb*(T9Y2>K6o@g5*;>o %dnZE1o8-YbSJ3!=lNOd/'8-IhD=A50r$(>CfHqG,?bg)R;7n&]Hi0ekj*gBA]5a2L)ue@`r@ghfg@2T9pC$mQ`C)?$QMOO;mh[e0 %n:u^FJ8XuurW:b%k9J%).BlL),@?KK%;'DPu`eP5]8IG87[f$dNeUeKnfbO',hl3"$,L":#=cdl[O4);39S/>PS%sO'r5\Xq %4kBdC04T0Gh1E<08.+X(_Zg<^QgIZ)Lap\=fcKAd%!7"Mc*gQr4nT3P>c!_ph'("M4F_3MS#7qYhcW[G@ER:P#IS.ohBXD5$.l1bK/, %AM]F_:h4u%DGEE8oKB,k+T9LQ$e$s_Wb %P+7+V(qAKL$4L2qe+3@oq7:\"%(EL.WLE;ro^UEMl87/tp+i>VVOE3"(Oc]./=?dB,_D14RD@60(M-eJ[epB-Rkhh?9EqlT""'gU %=X%N]_@>ksQ6jAOF<5682_6!A.)*f.DHPog^@!@ebHTLXEeAO>io3EPtd?olp7_aN1*e;V-W5-Sd]%P!.O:CBh %3n1boB6gS*_i+rU>SOc6IcbW]Lu=e-seW>##4UY4SWbqGp0j0p3?.JoZaias&*U' %_KI8N^&YWprZTNb4Wn4m]N=QAChSDIo/Q2BZ@S@8^JYb*h<477'-A^l@MdiRo/?)2.5Wc''Tu<69K3\d-41Ktkp^&EmaDoMEVn\\_-,``BTq"9#5h*^2;ZfsYc&0>Uq.WM76D?J6kQbZ7]1_Fo:IjLnDf %S,T.lZQu9'*D>*o)E/gSZRBNTe&AJg/I#+]96[>MSo#`VS&PXG*/UKT!OnJ!Y'PUU.4&"XBGNc#%>JUt&!uFpO2jTYr; %p+&>7D?(QMTkp6"DIraIZ=h$UqM#n,+f?NO($Ocg5oISubY6eQTOf/C?#_eO@cdFJG@OR$F?e]N%)[T!.; %=rj'kG/S)/oD=3NSR+Q3f"a]lj*'(+W<.&C_n`0/fId^W"D!gg9E%f%[H+!mdYS$FKd?su(XbimpBeH\?'m&P^\SPP*MI*JJ'^o7 %L&KHKe#s^S;3F+_]b:G;db=$Fb7Y4l#<\>`,dkE-E[op$%8l?qX/0s"N_tRl`0Vb>kg7T3,6Q-<1_d8r+!)-:iJ1RFt-`l1p>]GCAmegb^ %HuCHm3`5uLq`]o<:bJcp[6Z_VYAA!(Ys(!sOdM/s,[]D[^Fsg/M.RSO7"lhn3op#sFUFjE_S]gVKEK"?GmDRO!Z)FX`T\YI=C=QaAi.D`mDuWcCt8s8j':T%fKEfYFjj^PIX\RW-1:n5,UN;.T=5[3gDJ` %j`5Lfdid_99[g-(Hh=B:Q!S]<]?#'MV'jI9"pjO?\U"no2rI@iBOJ<2.[U'C+IQHXPQOt9WFTm$;[ssj_l7\2F)H`1_/#$.djlp& %7L5fU._t(DD7:IX:J@VBa@NqjEUKB?,G`l,B`n37"1kXJ'57RF9gs$igIW?/:&#/#CqD(t&_j_r[a>F,6u5Ze2\HDeQ/$'82jV2o %#+d/ML8U00YK?V(2C(/2>jk+cBIT]OO/`sm6N.nhuYN+=%Q %7d8<7HpTJtGHZ)3Lr1GC*elIIh0el8`st7k;KR%ULVfIZdE(F/T*]]0;kQpj;ue49kp>R-(?u(eRQRj %5ra?FHi3M6@tLO)*N@cbT&PE>D)P-$b#/ntb:3f#:LeK(NIZFmY.E^8;4#%?#5hAa/YA@@+<*H)\70jAj`4H$1Wdq41grX/U>#,[ %f37p).N&?P-dliCQ5/>`O30=r&Tj93MU92QdBLI0c`>^"A.0;L(k=X"HH(K_KE9_&[$!-dSoZ,fXk"u-@3D66IeTg8PSWG]cO#c?K&WrN?ZEUTP)QE6U1esFJUra-"9#%?j9M[0fmcu^;P3HZa23aq`)H/f$0$92EB=Fd]r2o,. %5q@n8!jte3R\ZFVh'uHKJMth'JK"Mi>a3,-23=_)p_L1E)VJ=$[AI"&K:M\V&+-a),dub623Hi[acd](Dqsh0o^k_[#9\)?iOg$A %8=s%M`D?m=ql*F4^6=Ukj66uAaJk,Z+pK$;E`aB&J:L1[RDlZS(lVq05_;Oi/,8?I';?*GrJ1QpnSkY=q'2n.*/)f)-UK\D2*HmB %huI#PktV]D=gKX/p*1b1eEH6\&TOHtm%Er:0]E)W'XqgFO@toI,*bL.[q!Kk$?ac;W-t!D8d`d;EWgePC9AQnA_=HoU1j_D*AuFY %k`gJd!C>V'RTbd@9/>bd&Md(?ZU*eX8_1@<]=fld8i?sF.7APFS('/m2TTE=Nr3:>fq;%DOU`HI\ME:$;.G7RVJj)\SOHXF]n"G= %Zf0Y9^=.n,CI`30+Bl]nUW^YF&Waf:K,Y6Ha/VA2T[=q%9\ZlHGr4,r"V %lkcf;>[a__5;qq%C$]pMbUX!G_7Z;<`D2&@(ZQW]&-KC:RU7,s*5$bL+cs,lh[OV_OgJu^ %MtJ[ZHU^^*9`^Oa!-#IVH73mN2M\/gUWO6RZa[j)Oc64&j(@6p5=gp\YekqMi %k^IN'ekqMi6:-JPVcZmIAl7!bnKf%e[;@1+G;DG)e6iEKMm=2:VA6r@j7ZLY;7C`bDi#'Br#VqG#TIAt+Db4&_RAdR$!qBCE\M-7 %8pD[EQpG)>TjAdO#.\GT%XK=_@!"/.C.[^=Pki:gb*a"u.G0>q.VDqT]Ng\XXa?6ldpi.l:'R1^pYco1Rt@b,#WBBa!NgE[KiUj0)H9[a?UOM>X5,TX?KT>CB-1:`9K]IW;rM'-WD1&TI&&dg-B@g.W,\X,PKRjW$kSkp4+a[:I+:Of]?FV`t#+G %3Nu[",'.(c>JbqlA.@H'<_+/@C3+b-.j?6tW+6`s.nqI#HPs.)2dM)'T*gZH8TY?)0TQfY-g;d@+Le+,>@*@gkdF"r0pfaaI-U:1 %QSGGgX;t/4^,AQTpX"\R#m#Ma\aJl2]f5PoE\q&%I %I"#3s^?.24TOq!6(1aHl?DZ4s%_CS*je<`L/f;+63bHTsA&jR]TDMAM(CXQu)@_Kh(CXOoGi&^IOb\&G7LHXRX4_)s+pB['1`XPJ %[It99r3i5'0X+#AOH5iriX8To5^X`^/ei^h&8H^6?nI:PWWKEu)?'dAs%h"j_$0hKK7:kY1">TaSRL[X(TETF1rV %3-3_Dk^l#K5Y6u&(OTp(:164MBa/%p,`1"$TZ]'uIe5TqiZk7E!uTXMg.@11S>d]f/rB'QR*W(PiC-El-B4X])\<0rM?`UD)s!*N %m>=\.9H)h]Gu,EdcnNrB6]%4[4b\)AB_ljtdJe!^$FJ;ldbo?U=]db[(mMIg8V>0V@YODoko.@KW2N5(=Tf>XRQ)mM9e3p[YH5&_ %,3ORRI>:o@O`Q(37WPR<)MT42[JI/cR60WUf)`XVh:,iV?2_8%00,mEqNl^-bPY$2RNVVS3uCQg"g+)eej"\7a_oLj6i>-Xs!%KK %Gl3nXq3QU,Q[a"8J*G8X56#YI''BU9Y(Du"VXM9OJ,)inQabe&>1U$5J#Rr)-3\1NLRh\^ZflPP^6i;;F^c<8i(X%BVKVA`qP=K$ %5&P+#HR+m7@lufp1Xl4u*k-?._AO.Yk(p$VVYm#+=8Eo(n$^2't+Qi!kMqTS,.ON`,R979:q(ua7_)2&aM %31aN7k!#iB5+Bo[)9dM0979:UrGCtDZroq#'lP:$L$MXU:rai3!YSISCZd5Ur@,&[uF&*Qf[ %H.)RNmKHSLUA6fp^\>ZQ>Vs`['?`Z:#SrAS0@6[ms(l+^""6,=")b3t`RbU,\:t^T7SVU-93?Bh)Bs&Q:FQ#=<`q"5lj\3bm:u9?"<*p5%Eg=D(J8fP$_l% %k$%fRj]^\0^jmuf\gt_N891j08'EM"3eN-lBr]f*ZClEBc0]p]iu^l;E8_g)E^.5niRTt%&j(>kE,0\`dmfln7X[NS9)$ec_QB:9 %'.gguof9"$IXA%n:<-4Q:E;`a@U(],JZ2/o?ig+a#-u_B(Gd"j''rJ-["9X"H521582u]Zo,U/B*6hI^1k+@q@d"1N(Wan7LHp/S %\_Q*G%3)eB"),o8TL4Z6d1$$P%7c@k,/\8aN=i1+oLD,[%RIT-HBU(-239n+_n/-Ji#$8%?4`:#,/hhs%mo/^(gPr%VOj\]FY^<% %kNCgc@5?$M6CB7X8pSdiDVf,\XH#UHp/GWjSjn<\S9?]icgt++.u^>t:\S7u06EguAg^(u05a:T#AZ*"O?$$phDTYB7*(mq7aFNf %Wq=Hd?H(gb#Xr"=qk!PC:!2(IcfgMuCU,cQ>I%cd?G7L6&.0IBD!FuP!6RJ_B3ko+WU?(Wefm$8alQ#C)B %>b?_s@!09ar+,E*o!!:V:Ru[OkMZ;'01Mr+Jc6e741HU.RcF]8hTLHS,Z1EF[,DM='L&B)'+(/=`DtiC22eQ#((qa$oqNS4Ip_1t %+7MLig!2)GonR5b?RLS\i'4%ZmsEB*"'%ko7X)f?UiuLq3*CR?ljYipa#_%T1,,ib\'k18GeF88nqXu`)*^p8CXp:IBnV+5+[dqc %DZ3Co(_m^I0Z?F4b*Mm&8s[MGQeg_\bg?%RRqB)fkonAh5t1p*nSO[Gf5=Q[bgV8iBh[T'4E]0a %--Z:%O`AsfQdTu.iK;;tJ0ZmN&qKV)Sl>#76%C6UO\H^P/CIbJ-%eeR/^7f[9pHcIW;Y8C?F&ApH8]->RNOmlTi'koXR/Kd&8%er %1!k:#U($3=L5VQj>_eG/.u\!:X6LA"TgV(8:R"-,m1@[V*Y./:(=>/`QiM>_0XC_7VO9b8!9pAgq$YtC5PuRg(m=jmRS:!#Md4`> %%NjgfDm3e3,[9&;B&U/oA^#t7X$A-[>:Uop#4IP8$H^kXaECFdODOjG*uadGFE1hS,[9jE5\H]o8@I[VgTkbG1O'85Fe*DFWrX5/ %'WNM,[=?:a3*^=tP/`3#1j2bKhtD]Q9)ST!:Z.n!gs4iHM-lb==$G_?RIOf\,Afr4!),U %e5G/U,X`diRFt"i[O_-BS[%56Dk=XH*N'IcB*`eA_\dKq2/ZNpCMoSLEanr#fFMLP&t;U,HC\#(:0!QGs,B,(/k6,DrjAU0jRMU2Fo*>K8a*#)OPA$:!EQ5ngdW)ar(6=u)ri"#Q-coq:;u$91Qu"eg:8#S*#kTXU=5-4Zq38V?#= %`l.8W;iH<]g`G30aLNoBj"`iu1M)2kd)Sa\k!u;lAtR;.h]ZtN<+&6?4HYV>Mqa?h_/CJh*?&GF*(bs=bi)8cS9#!V/o(DEK)L?^ %/Q\C?bj=)`C1an&o7L[%l-/M8+HM948PbTHD>)#?aNPEF+g`S[bflAX03:sb1ofPN_aUQ$`UO':KYr?iLC*%olk()#@_@1>]4THe %3W@9R_@;[6O4Opi*QORg&4W"@Lq*YKd)L_Nc6?s"i;^T$,OkAbnEmr-S4j&+XSh8pd8^^KU?SD@V&*e4#U#OQG^1,sd#6uT.6HKL %Fa>e)"OK!9DUl^!>['@)on_nu_;%\Po=But>P6pd^IU;%o/TVXVBFnPNrI`rJL`AmFkT*Tp83sh\*ulO"gO8i]i@GA,`NQP %[=nYiogEYa@')Ah)GS_);/2NQA.l:=q%eOA+h8@^'e5%i2=!`4rJB6i2f?<;<@:Xj\os#1Wp!'`dBKY)YI\3MUcr(K_t?>AAf-1! %Wo/5(W>D#b)RM-_dXW1c()g1Z'BgU^JH;XgF.YKaWQ43M+I:>imT379HR-6+:&\; %!dUSSYF<'ZSC_+aiEp01+GaB5Lm(=9l3M0Oacf4%l:=GP:n2U]jH3o:j3Ko/njl%en`N>n4N`.I.Qc'=0M%XV>Q*5;+rf;4ZqkR7AU2;u[7j)75aANeac(4on8^2dM,]I;qEWAa`&oP^!uU!>fnj)5M>;7u9qY4LF3 %qCRsgFI^fgq/F'NTKaIho8ETLWcZjOGAD-q_KR-=/j$J^)EYK[_SQPqLHrV.D;]n20CQ,DoY")j)TV5Cn`7#Wq&-$Ljn6N`bC')/ %No&<#Ao*"S6IUW+JnmTaa@`4(!qtV$\Ys6"gNg-$XqYQ)R6a$-]?KC7fTQ\p/r2C["$Y%qs;mDV9qNN_n#_o %^A;]\\5uY;caU*7X3IDSgm1C%WCe74_fO]PY,39_`mN%3N`420.6A_Sb_tkPZ.]tu9(HAtAZRs;f!h;B5AG5"$dLHC\3ZJ[UDI#XoJRLFHgh["cJdD^0JgJo9g-%)fj %\:5/uB(JIBpNFmMn\,kA`=fT^h@Lg@*'<-);`cl7LNg@DqK%;\+PLhOX-XV*#<$.s=o>:mnm2Dm%LN)(X^)b(,et7<+#Rk7U6kP);Uj %c?Lk)Ls]lc(N.;cC7^0pC?sBCd6M3J;=.9d&2V[LnCtWt4tjdr?3AG^+EoeRVY49 %qkVk9\e5/mV"0?(oM/N/;qAFsj1CJ%H&]ZVO78(Pnf#X'f;&WOM-EIY](COOtJ\WOs(-Je#L&[d.mO1/[BFH%!WlY*r%g[LUl3G?Ms,(`o%"Jb+MYMfOR[gs@&KHgfdaG\Dn6`Rg>90FMI6878\&(7^GG8mq0YQ10XP3O^VF %]O`"Y;H*3D;t)h;+>lSP1BebA,Z7S5kpEc@&kPgNTpofG?YQ-d!Q%EhDE;#>TURjQDrq[8A2!R>WIsToSVjohn&"H:SBTDUMGFg^ %1^QXLB[.$pK/hmd2*,;X5!$Z+,FbCj'MW-f^H5%MSl)tZc";(?helt'cuN=H2bVOIR_^H:]o\.Id0rc91CUhX'MZh"bV5ie %;[.aq957ptLbTV9VQQ)VJQQ%WK[,jTZ=8ao:_9dF-NQU(/=^:G"Hdr?DpPe,c %?oK24=!AsOU+@2_nH2_ArYJ!Rke)K)`?5;18ocfS`#UEb[F2\l]4)Y1D.o(WWZ;WBQ5W7m2ZR0;T]<-(6?cfh+rB.Vd4,^00sgci %X-VO-'G7>'+o!X"&WmtQ!mcZ_7!*LNO,2:$65N(fbunC1/#YOG+X5h7Fmert*`qdigtU'?.EAdaV`t#kkkqIfEKb/;QpL^CNQ[-/h^j!AeEC7jN%01O<)RIk/dbi]5]EhNG_QcIb)ZL^sSqFEIH %[7oPS/kupj9dW![9;d,]VX2W_j$2;AXiTcH6Rm38c0.=ffCIQ/d)/s8M)H*\_RGh8J0^ul$/(&#>"WY#D,rKuQ,BS3Q? %@p%<6/kQbh!fOFEF_Z:ZZP.Nr0_pD@kJWB"SdJDo4IjF8OEoppSK+9YE8.^uhD[Q$r;[9ETh!+f*JCAHD0 %,^H]AKpT8ER&&^?+"'jAB95a&]F!1"*Ff/S(LWJT@[2d#>(QR$-bsgEAqc?G;!&Ht@s>]FkT=,4OM9.KD,^6BjI5m,nC&bT-[D4I %5P)-hI@_)j]o^%g-LlT)nNVrH%j51^l+$KGlch-`Z]"GYiNmXH:UM0-a^P,41V7sd, %T.O%V/:#oi+]OmHHCie-O'6d.b1k';R6A3r+IIGd]e!hmiUhTOQ@7Z>3rbaXVpT79eiqFB4,9a0AEPgNq"u3.2ZIs`c1b!@O-Peg %oWXbKK:h@in?f>6etX0JW"@/u0Qb9B+R"_aZ#-AOPQt#S#MMb'&`$KtLY$]!9]?oFMp!s4)b7d4H@7^b46"e\_W1`jM_aL@A)6#0 %-uK4hU,=B%IY3qE.:9(BGZuj,8_X5aduBs$rV8A/X_e%U(o&Np_7QF5faq25sRp?+?[VR %&C;$i6t:a".Y72sNl9<0`Y@YQo0>\25U!cK13qH[SkmHn62fK"'GPYOXP26YJiMMN<7SE('Qi$Ni%tcE\'m0'SdPql&Wmf3)U)[)^<>!6o9]E0D3I!":Mi]`-^\ %Frt?<%PD8TM=pe!Td'I;OVCO^(t!>(Xk)Lab"0m;Z)bLh22u+iHt2+I3JJ*"WU_EWH@'iKGZ@O^>>Gl'JN'a3&X\6/R(7!%o..;.OGH(/&YZ85p!)NB&7@KBti: %m&531NUpFF_%,&5=m!>TJfVLJZ%Y7qT1<8DaA11^5&@^4XD_FHZ:?pd@/qsjm)Md:^^HgGEe$8M\4l\!)d>$1#!sYq,j3pKAAT^+ %+_K^c$th.:nQ6*E=GYM4'IV:ClU92nls+ %+@ji-/R[K@&<0`F#'RUJ/'7V!rB+M#Gu#):?#NNII=+Yti;FZ-/r/@r:I-EpgjEq8JrUCIBmWCLME=[GK&b2qR'U7ZL,>QKX&p:; %fsh7baNDdcMap`b>b`BfVccOs=SCc:Z'hA^4Q)\Y30)JM@l+-H1Eu<+hqXLBJf*:16U!D,!Fi;);;/Q]\nd&T6D10e1+<@@dcJWt %h4HJcs-@_W82J!toK/N`[_N]NHI0McnDmN?ml,!.kb:+DZ.1E$_->1N\t'26Y6):@,<69$_i9]dX:9WQqo&sm,TH?f;koS=k'Pbt %_.SW<6E;CZK`ol16OH'9OnB$P9K2<%3qepbGa(Vt4.20Cl!0>LLm(^2_7eab"bkarJr]A%X9!;7^!=o*go#sna+J\D,l[K%:<@%]*e72bJ#YX:CcF.X;"d%%&!C%Fa0dW[fZ&se;`*O`d) %GU(IU`nLR1-dK*Hn1O#7JA.g(8RF`C=gMA,dcq%DHia(-BtU2hECsTj:1r<.lC>^13lZ^RctL3"e6"l_7LW2YhVVG2XoLn%2>[IA %(o2BcM7Q,*n=%\0^?@4[)aQi(]s59O3sI.DP'*N3+/dZM"tb=XKr[TZk4NcZIR*t[)&e*&1@1h7P$rd6FG1#B2q!e8O[OhA]>0`i@Fps-JBZa)gm6&RS\e)F7o[V-H5T'SdF2$SWBGU^ %n2&ElI?VZ26L:Mrkod?UdpRb0-Hc2ISL.:]kK\`SZFB7K+[-jZi$k_lD1mRZ9I:?sa`E1#0><0O\YEUH3;]"k/j5he5D67Xp^]Ih %@8#ns5aUuK/18/#6taKJdHjNC!c3^."Pf[9)/d/7r(I.RUW'Yb2dJV(*BiELSOCe.]IciabEn;[r`'7Or4Gb)1/A)dC2)68)iBLX %.;BhER`@=q*:51#R*6t)*MclOZ/9<7hDQ#Pp/sWi,n0k/"-Bl4D#ah*UEGs#m,=V/!GNP?NGIPsj`WRNZF:p8ef9SkmdQ)#NH*PWE?>I9C+`iYR6TIQ5JsFQie,:oAh:ZI:jdBR %H[jj!m.tjL+#"ao%jn3,*l[o40@fFph1Sk^00MJs\pm0Er;FfWQB %V`T.%UC3B2*sharc&Z)q[$6%eYcS[ghNT8#k^G8@%ec!X>4nGmL&?.4Q3%pkSd[/JJ0IhEWc=a4rH[E^$\tqu40Cd_3A3IMMJibW=!b"g %2-2'-f"o!4jV.@qjdUpP-a\u5A1/.$Q"t-0Ru4h#$'ibLei13,i1kCVK_2f!!b@WPgm6J[aJ(gITi^C:fQ-2b_Kl*M6IjF>H:51$ %!TFcQW.JrZmNMV.7Q4ECFncgYI?_i1h)`8?^WKpJ+`qc+3T6P\;]?k+ioTH"hT7'62s?+"Mf3.i-Mb\+\q-8V&)WI72e[fn`A`s$ %DUaXk=_fp"6h"EX<7!&+ba'aB1hNd(o,uQ2+9[IjR=r5e4"ra15SSn+I8DC5a?$l-\fl'pP4e=5.J$H,* %cLRt.d7Qt!m[\TV^+YSTn^j>!hQRA:,?MgF9]V)o?\f@XHkkI\\qahV%@1uDa[hf;j"6Ec$S>`(ONal-;uU+F+;rOf3%;>rOUS=W %\nVo'js9Sm*Z;)4"p]gV"OFjXje%B:"S6!N.\R%4`6FDF0j?!P %;%Ou(oI:3A4V%^>4Rs2ol_$1"7i@t5(hckE7Sfh!3$hbei0<23*0O5!T[.KDY=oDP//SQ)%X?t/CKJR(U %oaWjcKekag8lhaW9(&Ri(TE>@XF^U#dZm/.BedsR?--\&]ko]W)N+1<#kVFUoXDMR_j!!7d[0KQb"QYZ_SkU1rl4%F(% %jj"PF&dZGR!Pjsq,nO`IZB7j(&G$.2WmdXE!\o0)p[K[F#eDeo'hBYYODnjGmc"jC]/tjjKeujsbAl!D;%\`3^8Y=eJ!3P%D$,h. %SNiIW1\dLJ05nH+[ZYr4a`?&\S4j)YN)G&"h;m:\7B\cG`<6jT'>Z7KpnU5u)'$p*o]R:!.WbER7WS*I;`Cg?JNLD[C'\pO-e1mE %bk-@K8#Kl92ji0e:cf`fQ$\RjT%NmdRchTcX)89I"eiA^i %:>%_>#K^d#5YMR3e7<3GHBcUdH/-#GgqSs\@mr#2>O>?'H`Ka"ENAJ<\gWJ@ %pSRKf`5YU?4RU:^;.VrlP349VaQ$;'5`jef2NM'Zr^/)jE#uJ,!-4Og4#b+JRE=L?#!af`2?Yc8J-6U<*=-0U!5YI!4Hqq&N*mp?\nCZ<_Wa33g_/fb'[:V=HMb50+3Q %jJ"3JgJ"k,1(8EYqpiE/GLcUqFs:\.*V-D$Cmr&4a:4b1fUH %gNN"5;]ZsSi\l6\-<'E6/T([0SHB&!$?7#2+qlSR<>2j`=<:1^S%QGbI-e4uZ7'WI-#S?!ED,j\;rT^*6XiL@AkLj5T.`sZ&7BJs %TA/C6$irQPS)$rjnhsG+2S;Cd7G_WKgkKHj;;S_g,E2-G7fRa*Rd+),Dd!krga9X6iV]OjY#YFt4hRkIjn1,A"_W+C#uTppCetl;qCK@*US62Ms2Dem %S"2/N>J:SQ<49mkqHHQ_SQKVWU"$bY!%ter%])Wn+2h&qPnbTF"57D)q\)4 %REM@SNITmn*.;;-M:?),W;5er*&E!]UmPP(:`pFn*\`h%Z;%,AP=H)2pa3.1nqL[@'%6d0nZ3X[9][g)d\ul5WjSN-mmX9_V7-?h %<%+35H`iGo.abBZ$O]mM$!hCAOt@1`;+5j?Un$7*<1)UQ]:uEIbH?JJBGB^enWUcWbu?13m'&= %N<@%4M[luA]0/3N>BHNhICD_%FGgWt`j\)lm,;S?_WB+)O%HhE!(N7T"+*p'fqH>"*>bR'ULP;[WOM)aeP`56LMVmoh#_m9!,pLD %lKHrD/nI(G)b(hM2B@C?.69@-YqnhtW,oFu6*6tB*BoJE%nr9>pl?>`GBoP1E8jV,^*radFRRsl4H/hO/us"5;][048!1=":&tn$ %g`Br*&bnsi-H0$7dCLA/iO'HKMB/(7(on-ZT;J#C5Cek'hM"W%n.b_Cl2?EVfm.s>VHD_EY";$>dB\g?7"$$_YLP;tH3fiaqCPH1 %9Q($1Dm>C^Y9oZFXd4\[3.ER")*DK-m>!%OXjgjLV4h;HaT..=#f4r95n*N=2j,V*+D+'PT5MND=Fb(q3.aRDLn1]=6+L`nWQ3e>AsQ5b@p"CJ %j$=ER`@"iq'U8>nm\pAt>m^r(NkMin[S&n4)L0MJc7@0+kff^agR-F5Nm8'h01KI$N^F<^+?"#I"2gn*gO!*G)l76CZbM9kYt39X %7?b_*%=7I2-YZO.)Pu\%T;($$.QCFoK.._kLX@g6&@C=#=A59]3Gm,\n&p'p[f+37W>T[9T)L?]VK7Y2)13ihMmH;b^-ojE:L(+! %r@nsfqb/@YiGHQn*0SKP;&U<8CsR$nT;mjQd,[@7q2]qX0fLfEcDR,=1O-R7Z2S`ieqP-"2kpcZce&e9#C,[V:S^]k?fUm%;4Y)G %BL[FA*Km:0jEaI1rWXf47P3k\4<4P%Mtrs7faV^hB;X]'-53//pN/ijNC,F8&tP2<0kqPJiG9niA(:"pM11Ah0ksg'-?\!$&u124 %##`Bf;]TkYItN[co,c]09UMm!TL_2$h>!%TZ9b:G&NrGlrp0'*Y(SQ,EPRg@_*g %`dS`3[J!)j,%U0ld4>Q'eq<6V"\=XY=jVm16<03XKH,V)!e=U,Z%[[m>!49U$^rIL[9*qH1V\cu:lE8NM_\HI.\:_Qoq6]1Yi111 %MtNaY^6pATQ.CS")iI*12LEYjdPn5FjJ"hs/T-&VcsOEBkR5uQah-uh)\9)%1\=)\dIF-Yk;]eCH9WSqOgg+(><@e()P=pB,dWF> %4RKKm*Ap#n-UF(*hT%CIXZ!]\d;kC,]"HV#bu.pK^sCtY-^aNVC3/>"[pOS(Y0B9,4r!2,P8cI*%XXCR^j']+%u-,6:5^iL@Y"e4FY7tD]4ND(bNbqQ/>:5e6Jks#]4bF5Xe(!-$8Scf-EPk^`C1C$RoZ=."L2Kc@3Q5]s,,4>o$TOe-k=GkUkcZ'YW/6M. %+odtJ?\K>K(coVb%Y'c:KhaZ'l7%R,,64lYUK;QPTJ(ERE^fQ-2VK[,lF!bgm>h<,'9eO.kH %47O-7C&E.`q-Q#D<9d/=H"\+X_+E8^qe/VECB5sNW!lFt%CYJ'Mc %FEC/#&An[QA[gXq7Il)VA@FjFb9jns0=ssHQoEbRb.BY/N_p`)UK7J!_rufY3Os]5BH#cON&h3/!$uJC7[[^0(M++A>@S=CWV7-6 %`&0-gpc)oAZ,=:'@6l1ZF2l:=R%h.-D:`G.C[a$97S(FAYd]i'r:4T@fGkK'.UOTg:>(-R\p7M/?+3m<$MW %.THR3$FnSJNRi(V9hHt5bo8LLi]MYM[E(?j\,GZ&*&";BOo/JKlNTJRKN=6h)NAY`RC:k/:c8%2f8B5le[HS;c %*rbo1!Ic#+^1Z]TF+qiV1C"cae>X8.E\VUdUM-;F<44+#CbQQ0-$m3rs-C\n7N9K%X%_"X:hb_&f[!$`'Wo_0p/6.646>bDR9bEJa#R33T*r^:H:1gFO(:l].7M8,,L]n/=1J;[=-)]EBSG+p5'Han^8@rD1L5O7a#R33S:08GZ[<<+ %1>DN1[Y0FkCHh("6J*&3@V]kb#j'I`LLC-I%d&U\:BOrq6LU_B4g!:HUQn"@qYY2mlET,U@uBRI7s*DqU3cNUVN@Kt>SQuNK%aEG %c<<]5H:31e,_k5?]Sof_SCc@%'*oefbDRB3B*s#@aJ;aa.uRf#rVl[s"S?.WQbN.m[oijn)8,o1@:jd\'0T]@:S\T^R"'BQ`R28B %Itn7%n0,T8'UKcWiW_Z,0TYT%1&>uc`LSD4_/\ZI+fF(^%!&QiJ.GX^@1[`D$tAoP;=/UQ\kj-V6+#?[(.YF)eH4,+AmWGuMuaJ7 %E3Bb((l9Wf5nG9>U%H[AD%M>sE@8\C$4m==8e^3noQ@8u9;0PL(O:@PRO%>_T+B=El"HCKUoPTZibEEg:0CL@/=M?1>;fp(5JNrGg44^DK$piiqMueH_V5C7i0RsbHt-7L@PfOSZ,%@gb3d6Y;;R.pj[o= %lWCRm(5h_:ma]9qN,8X%QY_)5i(p/Ej13Z_XO`qA]r:C4.IY<YM9J28ljZ)mHF:c/T6;s9O9^Aa")4VqZpYGYt%08ho".T!@p:-/=l\n:+_beK[q %S9NY#U4;Pe"1dGLK:n\Ue8?'G0HF02bA8L-#n-K2:f)1#[H"eG]d)r3_OEZ%+GNu %hRLf3+\b-g`)VQ(CpXS'%,`U]I"[WF+;mjXoVp:QO754P?%[nbu-\0qM#,SlI3\m(mFmnH_bW@-,uOiu+3Cbmk9X-%YCF/s)4TnLM@tmK+7T*piQ^Fe5YM/BGGB.R-`,O3=tI %bD6iC?--8Z4G$Hnn0Vh)nH_bW>hWXLJl4_hOl^&b*7Ohn8EOS`3A*prb[H+j6()WIVH_uVLk%B.Dh5<_P[F#CmU\iPSo-ncG=mnO3)QV+E %+B4!$$-$_TQ/=q&l"PcmHb1N?Z.cEDWY)>7(99$R6l?Js6dJAi(cgbYC>llN=IW^"2P+=,K=,o4[;0]N73j,J^1l>Z<8OT7,_IGr %rO*p)8-X7>pY(L`,8p8Q<=j_>P%'#c3//K#q&C;(i;)Z8>N+[P[14d9@lo]!@IJeUmXXnSI9Mi;/?dA+(ksCXFD<_hNKrGFXg?4+j]&A.B&:l%gkoiT4CeME:qGpGTU5;%JoGiXQoDVVi8S9c&l[C*S2l3,CGb %A*ChPDR_>KJeksOjoEgTn6/a&q:H/L;Oo3;j\3Y8#mp"]!p._q:?%fJLpn,@=kQ$Ihh[h++BK]F4'HWhhEV %JWS)),Z3XT35p0`^BmKoS7O`n?;mV/[OI[2n0qnI?`5/JXNERc=!!D"7%)o)@F_ffNh*hE$n]knNE1%B"'KH1@cpW18X=Z?,L!/i['('7lp %8(i(MM6=Q^kPV'in',M_)=SEG(fqGF%GTE"XC$9p;+5*q2M/6\&jJm@+4=K.+-99RY/`525&IeT!Cc4CF4sP`0UYf13_6[R4`jf\ %+G4?OFYg;2)(If*1`;^a4k22K/P\?hI\@fGDr?V%(I^A6>E,#dR9`4EZM3NeRI*0q9$He=,cfb!7Yr!O$B<0qdg\%LXOptM0$YLc %DEVaQ$pT_%W>W-hF2d(a[sc2R/4N?tR$"c!)9ubK:X!X<>P?%Wfct+U$=gXDFL!S-B/Dh-I5mu14PU$OJ/'r2P2J_EV]@bGqfM:J %UD"nbb]Ii.7g.Sl7oF>QWk6],^83Um3,ti7p66OHPa)e93,dS_8qM=t`jBX=&htWQ*]0CM@%N`OpP[F`K\USCkARtKQlo>MESaHe %A`*c3&`P/1M&Cd"dQ4coI1)eBLT@.*PRV:;1G<6s?W(2APf5@#_ZZ$lK-ZQ&91)*&Yb/QQ/^qm@)uaH:i-2,sg;0PX/k]UPMj5Ne %9$FZ:j5:UB73_6%9(_005c)DT!0Y0F8ck;u%`u4/&^-8$1?(<\+rTT7hI%5aON_kdf48W4,+32_F#l_TfW][IO`)P;P*P?mL&n4JCo\`@N(ghIWo-Fm;E[i/HMLm@mO-G=%MLRS1,#OG3*V?k!K6J!VEs]C+LE'"4Q>h'5LA39.EB1;;RmsrgL-PC%)P+_p=F\1`IO/ %(-b.fe%@WY'h4ad+bOLU$DYejOMNdOUa/5`q8FI^/PaUZ.VSIFh?FUTpFb=J7t6LTd9$49ihUYJ.JdAL94=GW=s"RGd7L843BY#P %6U@T6?'bA7Yfhb$%bddk/cV4g[Du92rh!/hA\)=EdBP(eO@kK=I[+s9rALD48fiH;qfEL1$?/k20@W*$dY'rV*aXJ,L`I#tC%G1& %;TQjWaUbb\Q?;.K@#@5[4T=53l

V@!X$04j^GP$POL$6TjnWn[@mYC@e!-mQ2"`/T6?4?'tfljmAL"$,tTN;)\m<\5PAQ: %,"?!>2ZUSd/UfCs'u0.E'g1p+kVa(I+C6ed$G8s:'7Zj=+ARG!Y*)bb/a%:pq5=9Ih;J49*fI!=n>J#B9(I,bT[Q5W4^S)=L+NM3 %+GtV%GQ;1$kX!N9YMi8soP`4t/tXs[GS4C`nL."*?'N;F2>lHVC4YsT&fQ@>)L14`;$b2:MfePKT**REG*s$9T5!-mKr"\:1>&aH %/o7Xn+P@@WNX+7GW^g#_e3;umfiNWTSGHN5Y6>R2,'eQn*Y\2r>N*ks4Q)Z5\*@5WkO(Z]ME)ZOL'%bCR?1/I'(Co)'/=6/V0d7e %Ve;@Rct!ib''IWOf2:9e@VQ<4X6"U]@515g_^3up;4G+K^3gr1e7rks3I^JTP,5Un9E&jqg>BtLP7r$rZd`Lj,FPC*N2u_LAZ=e< %Z8ShP&"Al4@esN^=,Mt=4?,r,7C"*$(u9N1*PY_<#PhqRP.8,fplXU^28K8.P>!T1KDh"W0,D-UP7'#tCgA],HhCn46($X=IN%MD %Y'[D9Ec&#*82e%Ppe$_3*Q8$'X.Y<=G8/8eMfQbK@mR#'_7ZPIm^ScAmjL(j[p0PKo8^]aJS%P&bW?0t%_pVn@c$@pm$Mu2efF)o %11oAlUq)@[o?KQb9C4fpY\giLg%[!Jo1fHPW_QHr@X6Q %o&Pi!X_3jdO_+sll?&3#2`9,)\86>1DZdQRe2Xaoq:]JB^d;4AOVeSMKUG*'\upCC/Qm5';/#(IB5_?7Mf-k4Nd&QYKHf$#/FU.WK6"pHZUF %kiV0ENj4r^6,(r]RVj/'UL3,doFRP'aE-47-d1!D#jZcHHBY86a*1)6Bfh$c`U[o'KZ,9-U2j!;g*rUTmJY[`\p9GU(!,?15Z8O %(UFg8/9]e"E;Wr:pF3>sdl'ZF?##c9H%<]O-c+C2ojMZVqg3tp\iNS%:U?[U[tg<*)!r2i %EG9"t6!pR>Ujj_dgON=b!UPn-jkpaH*3i;pQ@ihQk27ue?7\0_7/m`tgI`JK>euK:22jBfT>UI8>#JuD[L72%IBp8N2WFs%r"E42 %Tjsl`-efSiS'nA-WTIAl89%Z>V&Q@E)rO:Z@2>$@:_MI1/kSg0%N*K_mbJ%?AP\5@#=cVbG4#eAU,A=&A?n'_6u2Xi.<\*pPDM7r %U%b9F;n\,u6a-lSp(Wr?+2YIS&L2"!s!22E6cu347Yp?r7$5kTgX]tlK^2@!b0Gq08:>n;_[C5Zcp%no6P<@?a,$P'oBBRB)-l]]'4d,Uk)V+9Fi".QcF4,+eup.^`2 %@(*#^c"Zp*bR-_[csm:K9@)KE]guIoR,IK74a;>:1_WR>Pa)4s4.UhO9F.aSci]_'s7!8p;b@`IU1Xsc*VsI/k`k_VJaD-b)_QjN %!i]ZJJVE#*3%e;=70*+i5%&eWpY);H>Le^lfSF.>Kl$,@_LGd_e+G6B=0H3ne52q+m<6p^q"@h[Qf]=WGk2N[N$30O]Pi]_f>=XK %&?+/jbG.IaSQ%XUKOb9%]%R$LZbC^c_+_W+Zcn)gese %n'!:`kiPA$o2 %8($4H!=<(^Z'ZK&8IT(tG$o(T-iMW8`fA#"t[!RRe1KI1' %YtA+,lJAHE2,a#[0@["1$!kY2fs!;7pi2Yn'-5G7BnHjnI#=AL%Zh7]BY9m0VrUsmS\S8^+Y(&.WNqe2$ZEEg+TjY-Y2;3;/'Vj7 %m](bK^^K,,#uccdh*GA>9fnGfPV:GUmUR;kS4RfPkRKd2':#R5KC3[oJal?4Ma;Q6Z9&_KQb<87nM8RqOq/AC+AVpdiM"1Il"mO.Z/Vid2o$Q>%_@.83#GSslUqkrA9Q-msR1U^gn0b).R1Uu^PpNhi %1sfD\/+*&E]PA=iU*m6/oZgFs*W>d((aIUBPc\5?fL^/bA>'%<'JIs2j;mUYgWBJ-\j=U=De$:T5Q=sX.I,J%r?$C<_3MU;[XS;*RH(+t(DQGF%hYn#Hr`FOCp5UH'H(..n&1%="SF<57[^GdLW %!ph?fN[%>.Qf72FJt4u/F`u?:;)CU.atQ'g9QCh=nh/uVq6bGI[[ih1P2nssI`XhV?688+PYpitK-Ea"%=*/C+DK3H,][r_]XJG' %C>I3i./t?>DHEEpH4XDCBD-:WPje;*ZY6\hpM-\7(r"u[kg,"(J1&cq-d"dJ.tbsD4SieAm0imPAer>l`T2gj4t,WD64iXk$tu]$ %.5UVoeo3B4=r]DGmJ,-t"Cp+[7tD4t'FYXgpdrn3P01-aFE.59CS%qe/[m3=[&"PfRkd]VI[2Go,V5LD7N&2U$p4 %Nil"Oq=.Y"SJscSINR%nWEr0-bE_kd,k62I3_W%nIt)LV??h_"'q`fh93k-eqo#nF[\^,d$!b"qj9C<1X>[1#DG9b7;1ZS_br6Q) %]@Z4N5F,2I.m`htSpc6Q2rT7PAg/*9:\-ohSq_+qka4DH8ronR(I(E7eDo@744*<1MVI25kGPDB`A0c&r@C-&GRB=L(FI%]; %FAl$;T3kqCT2]*R,^rfMa=VUjDun5o`8TMB,&(pT5e,&Bd<02UE9b06N`)ir=o-ooS()IILoC:g-F%r!*tq"$ZmITN/U)qgMFLGF %EG5&'^'<@-R`C)n[EF4SDB(l1<,N).P3n5aOCMN.s&Ta]8t_@^jo9)>/U'rA=4m^H[@^MfgQbXj\d?8bJ'f8't2m(qWu[7`At((`@34 %#"*SF;gRu.f#tBF?h>IIbZ@Q6jnIJFG!7ON*iF!&>BkH$4KMeYVt4K%l<5Kh<*C%<"'_-Ea+]`Kr<,Y.*X+NLQA_?pde>%*j1m6X %J>==-Gc4)^X3I6"nTq*Sr[Y&$(E3jk8K6gWA"O5=[mdVLC[/l*s0o(.Z;U`1k[!Ws %l"Ao;[)=:FUg>kaSYdNMe*6MVr%CH][/fBXng"4*E:r%23g"#^?t]F9$3of)%.rmBa\Zs%^jorLMB5j!$k08c#r:o(G<1j)^jpcs %;_Y(K\\-XW;DVnGB*3m)Y?sO*L*fuL(ZH@Ep)+_"[5AS8Z7t>U,,OcIVRH\@5"jad,E_GsWaTqh"@lN8?'7JS?]sMEE4[#8V^#@c %&'gPi7*?JqVbm&#Y^kY*[>06s3E4h%L*=1VRFa,]N+j,2Vo6<(acqM\r^s(N%.0L18](PJMOAk<uLTT1dV.+0t!jc4HirPP+DcXV.2UM]m6;sq\g!2Z]3aK"\fO_1q=l9b'?&%R]D>o3lgAh*nY'Qp_!jg %^P&V?U^RD(SZ#20q]3G,j876j[]M+grKc!]k8nJ;6.d+u*fe5Pa67Ss/P647S&4"$B%tuSV8[2mg)a%GaE1.YCf09l@^[AC^_VWJ %i@(1c88V4mCC0URjAi\M[OB$r>c=@K_BKXA$MX^]9V6Hi$>9HuU=hhKKe7&(5gKcO:..:EBJV<%cHd#DSjZ@T5_=?4d:]_pp9&3=Gh]K*dmX;mcgN=h&)m5SBdg6_6i[WOh'I@Qo0Gm!$kPN-oWOs2 %TRV.4Jcg!m$9?%W,7:Qi0/)3B-3H6*?%ea)It:eGaBVV8NmU+J@2Jn.=e&59#kNK?HgS&lqQj2ZM=7:uEt7J$GkLuS;@ceikfN)= %`,IK$2!7Y.2X]jX:UmB=q%IN>KS+Ttm1F3bK:k3*TYL*R=:Xg[3fMCZ[?;/o@1)N!+'&oH[=M@A\/uK)htX'J3h7?s0BtUH %b$/sngm-_/=5Gk7]JPm)!rC>LWlj'"s$Bq999gR._XgM^'7j+Zrkgc`(N^-8Si&o3I#V'`pSBK>bWleO.o=HHbV0W-k6lkR@>H5hMk^.GPH40<53,.LAU.q5foTlNJ2ScjS %]qqaAKpETXV70Eh\$?pp7HlCh+O6'dlC/nknab%nhGUIrL)'cXdT\1W'I^OoQJSM6NSnqkFL&ZQDWfa6`9U^r'PF>AHDU!JoOg\g %V>W_+.MG:d&)CB/^KN_C1_P04Oaf\bY3.q?qk^:<^N^%.L#KD&_N,]?4%oIkto^eR-i4@@fMg&r#S& %dcRN]#2Z,FDNUj2A"0C!W]O8$D`['\)pdLV*g4&ZQAETh&"/Ws]d"^O4;?_\7!4<5hK)"!Y4L/NoJuK,2u5XZ&"5!UX$"4gbeOf* %i7OtZS[l:"-DVe^STUMbG1eDmWjBuL[s+^RbZ!,)&*aeX8b1C"elig:4E]T$=Hqj'p"4=)>)IOWX>"O^7:*Bs`]WqkH+>=kDa&Lp %##Jm4N/?h[H0Qi3P&_37YE5@]/u"\k7MA)#qCYh2@Eo0\m)hLU_NN_k*F67YCA"\O_/q6Emc_;p?,DKUXr>/Dle!u4JmRAFKECb/ %&g3nnFA+hOI\SJ_ %KtAsc?'VNS&$;/alDe[^H0Epo='$\9qiRRm`uAc;!tN;^3YHi%]'1cl1Lq)BXfGW#f/nfK!?-A&*3rY'N%b3('R+.m!/OC=i:hg# %2sa4:0_=To^j=kUJSB:#A7_IMB74]-qX5nhhce>QHNi^!5X\d@A(+dH'#*I81rYG %*BZknTF%n/fm8`ZcnpVo/!3Rq?sc8i$_#;s1]_n>(ASC,VEW^]#3U(4R//@$p-pbp1_NM4TZ;jOFS5U/OY?jQ.04nG88ae,QThUl %ZgS]iV"g+#VNGO,G9.t%SC:4Mcq(l#me3f-ZY2J5.nc_Tg("Kbn*1,XpA'-4Olcs,`#et4ekYp;Fu3)%S_Klh:rLqg'Y=5lT]u5J %7/r\`1!3M[3]BPPh"=phakY(5FcA#bpBO^tiMN-]TlgWDk[NjoR\QgAW&ri[7=:6F/M!anqsi?c()I*)V=YpE$HFSAWG&+-p07dp %1_O-V!h@Rn&gi_V/&)OQeG-cWZe%1?X^0GZ]BOr?4#u#ma#S+"0al4Sh$ccCK2\4qOH)F:QNmCP4jMGd7'&X7Y&M\^efrT"ID7B` %cB3,.'%6T(RA>PKT>Pg7IU,i0aH1FCar]q($D'$p._np3.lk1sc;!q%rF$9!0FasE0DnUi?@?W3+a>.NG0ph[16mK]l^n#"G<2Q& %]S.\rQ:J&^*ac;Y90')fjEdP@*rnBR?!5>5WeB*RlTrUO%WD,^-DERW/Rs)>E7[!UnUBWPsWUsRtnAGsZc %4QiQ`p\"(!9RDr=puG'\@U/%dgant3UG!>=P!\'0a%Bnk]$?rknf_nr!,R[nMj`J%<66r#nR[FMO6%iV;Ku=am148)3u)Rh\'rQP %G'BasPa]X9Io[&T;f>U4`G9UA>[usPn>iiSajV#3VF,?^>&e57.qHO@2[h0mr %I-q)>22^%>/(brkl?HDoW#a9;]uc*koFP@ed#!#r6?HH7X@,L!fI_3LgL(K#RgT-p6>Y\[Xds-b]*W^kDb.F.J1(&FPe04_Il2SJ %?$#"EL&:CX>,m<@:@UXO/'JWQF2#.b,+ENT4S;RX2oXLXMJe2mmCMoD68NO@k_s66\+gjCXsf+=YW&B5%9b>HYW&AF##mPLfc*g_ %Kj=D;5ZT^NLS=*jV$#jr^tYUfO:5TV7%oaeZd%MWohH[C/dmu0X6nP;=QJ`ar(Laj+XE,Hc]Z%b)jUr56RYcn?-"6Mr7`_ %ASq!,2`Y:b)TU#L02[5;Kg",2oM`.URlMS=!f0-?JcqGTd4`0'V@t]qN!-'^Ai^cS]_@I %m(P&`O/cIG;=Q>._g)5Wjoc]j=("6jif8HpSCoP08W-pOc:2P3MP'o!:`&hd5&I%%(AH:B[iWE/<`9b %-CV3#S"Pj8CSVId;:)`ndAIf%=_`'S"n_$_kl!i=?_G$n7PU@6'J7*t2IRt>T'4W2[!@Tm^L1W!6$gG5?@^<H9m(VcS()N %V\_T6!OMR1Lg>>CK!1uk0;))o#]TG3"n_$_MKY46^OSM]5f`C,k82LC(YEABYD@M"8hZ;%IFA%FU2JMTTkO)"-u",24[fGjh(7>B %c5W^do!<<$W"dLoBVcW)8[kacm*&Ve_l=./YGlDe6X\XC).;=gC*brGjRk7nG-qrn"?=ugY#_hSll'9cm:sVc^n-]>i>E@l"3LAG %q$$ET"fa)4*p:qlc2nufnE_YqT3d%hi?5nnYoo1k(XT&rW;U0HdKU!*$P3rKc7bhd07_qHRpSFQ?D+CAoYNC6fbo*Bg^2<*A7t,k %HS':bOIbWWY$@:'>05'iU]&,FV4Ba66o)A7[#XtFXjPc=Z[\UD[g!AEiq5Fge`C!jpXX#m*ihAMo%%L@N2\2PV71("#CC6^o$Q$S %'g%'BPa;(^Bd3_:RF/?ZH>a8,&>jUmR$1g$CQ&M)o[XR0M+6Qj3-,s.TQI"bo@BFi>?nKC`N!dW9-o*M/LCo%$W4I@_Sl]TN0`en>U"&>*=d)@b[/BLZOa&BF(hVim_G`rlrdiNQhQXl0m8 %hs-t>p.n)'!78mW)p6bTNn2=k186?4T,!D;0QQb%ib2UUH>a6$ms29PEPH2Ln%cGTs$L@u0pud\+'H&&BT3K[[[Lp3bs)K[D$q"N %1Ho$HebP!S:=P+@`8URRHMes2]H8n$W*LUpA^=fJ,9Ff6fR(lmkH8kilnpl3M3Y1-EO)W6"B.lCn@"ZTlS8kilnJ7!]&.lETW"uouT %8kh^0mWn=W.KE`j5O(j8E!E[451GjtAYnj:2'Ko!\l'2Uq7kA$1Plii>h52:aX5Z+g]TV:oN[iR$e2UKe,W3NA./USR;na/\GPG!9C+:`FPA.es!K],)RG2IMAYiLMjeAoBY#K%r5fL17e5S%-aMN_D;H$^I %THkWE8kjaQh$V'*Y12O1JUL05l:Od")V@jZTrunPb!A+t%s=]q5E3nX&3FW3Ou6um!i(8G)mTZG2$iFb;jAU;=gQbk@NH)R-YidR %cN+'6X?fp[SXILK8u)5iMXs`!;*][%:tSABo,%Qcc)GPFJ=:9@Da4<2dU4tA2J-HrYp!_tJ[*>:U/)4q=IdYO4p*-t_@=R;$K@+7LrYCKu>T#a=gK(CEEO.*OM9+9k"+Nj/SodF95U1kHTu*,f>6#WZ1f%$3h-5iH;g"#?r"1P$#T %&4:\1.hI=[V<(NdTQPF9R+AOjYji5*e:)"`4=Q'mE5'6lQp;(kqL6?aQp?VCo%RMm2BYJd56&JY5i_53\/W20CgAU[4:=q6esf6qmX(]HrQngZ$VQXABPH!LCThGs6F %s84I@%cr.#LW/rY8B7#5QW=);2:)cGQZN)XL5]gVoA@MfjefBc1t!fJ[f(d6qZrf0`q<6jjKr7IRLY%u:N/i%I2UmL;Fn.WBPL7d %&)GDr[qp5GSpc5""$Lt\kN:blGMs4,efGo_JhUEogFo*MK_mr0I.[pRoBN:%iE^9@dLrH\3bkbo2!EW%ERa'&8Z>WdKs,7\jY$Sg %W!mV9h.m/-eu"ne"HV?B#KprI[[T5d1nV:AI2Cp4?+Lb_C_!$TE)Lu%+fUG* %;8*IQf;m0-\64&KiXL76)ZMtr4.4!^Lr#8sR9^Vb6Iqh(Mn`\;`l'c2ikAE'%A]JnF:HmKF%3b':g(J3\csaIf@s-;!o(DT#M'PR %s/(Tn@l76j\C#H1N;f^l:@VU*Z6^[;5@cu_W_0D#ocXSq/sc![@i]h5XLlh82<`.BXHGL#ORb6RHHZ9oRNmLpR^90V?I1HRMg9!Q %n_RfpM7;lmWY?'N$1/+Op]QT6B@Du7EJB!X-&LZO`J4/T2Haa%#Mt0&B%jPo!\OC@6(kWTPsW#3pi+8V^m2cV'g\"H'RC8c-1m8! %)M/c68Z]s])H(6QP3fLU)SmYO^tC?t]hG8Vn]bPa/CGth$HaYO5_Fh./^70@5._fApkR*I*AsV01_q0/pYjifc'B4/K)OdA %Vs)>98g76'Bf\&od8K5QeD8<,^5S&_%.[esoOYj8iF"#MqY<_0W69^OWP8M33RrK5nRkOd^%PY;%)ZDR %'c-r?3DASr\C0VL7%Ko[=_bpBbdK]!iq;WHp"QT4/3(Te\mQnP[APOrU_o"3q0)_FN8Nc:_p3&lU"k&@1<\QV1:_kPF@MqH7\'Id %1=\6j_'](nT+$\re(r%"pM^d?,ZA-Vrm3+>Zst_4YUKOj9K*58* %4WfYJII,P3h3Qnc5G!eU:l/KK)<<5,dkrfC:X@-qBMG@tCP;6<+=BQmK?@Q^.nRjO!(Tf9W7Y2GKaa>Jmb3oA_!Rqc!5\c-nm;uW %(GG1oMttr@47d\!8UC3W)W/_%Mnh]S$3!<5MY1C*M0FTZ]c\JEF4Utt?bqJF2LleLJa]lO+B_+'4l//H\9;)X^[YS8=30;1LOP0T %n_EhU2Lf)).2pjHB%sq37F;5tQbAlW)M*F5O`s;I[qKS9B\]uBke%4n@KC5qS_&2Jq^-Z",r$W^0_?VF6gmXMfaTT'2!?O231\F(4pSe@",F`*N`9J0;,=p:TE%/U'I5:V1I7a`:%eTi7%tISj8K1=+jo/'M,;':uXtEH^oB0#Q.j`NMF1796OW[\<(t+.R=jdKdQB]7V@2:B$D`MsZ79k7qV%uq@jg*rd#8e5B#kJ74MQibKA[*>'3+9m"8d6btL[LT<(C[ff+Ki1/Xn#h3d_j5Ir#1K;#\Z0h+]8b(D9s<^-nH'^#&Zm5W %)V]Q$i]OA7Q23of8?II\^2!"keVj/Qo_ar-8N@;UGlWcfg!QCV=#QPKH7TQI6M?"b)!)QU_4[]:; %!s#'B(\M/e*P9^nRaDP=A1m`seZ?u)b>HNgl?\8$2U9.koaJ[[^.'s^_lN%br/,6T4c,f6URDPqWF4qtfQW?j[b>`rJ(?[FbQ79S&-E9)PGFN4O.Ua2id']1*0bfqIBAZHfp/g#h#9JP09fT*q%0rP?geM%m:frJ7A0s;:cEtT@Y$6tgpbG,g %5^Y,'!1\aS=ostu*!#.9JAo7!`uG)J<'^1L6dl4N %?oD]GiN7cST^6]\c>B#GF1/o$&.t>>AX[-\7M0:[)ZS1E1E.X9is2D^aosb;XW4<<:5EcsZqWfl;GL!;nm#-"FF4glr(XtG-WKo5E5t>):F/2_$=tsi4!">1B?D^l7SYmbbMJ>$2`.+MpYnC3/PNidQ5FkgNUBI+1n+7H]61d) %:=D/.\;?cbc+'O+S^)[GdnOMe=A:d&dS9W/ph]lZ>juRlN?pT0;fS %0Agb%V'M<1O``W-rfJU(Gd4!>YToEnR&W0D+LItA^4FR'Cg)Er01cMqp7YQ0[(kLP"h,mt4l/$jqj/fF(0lAfK`Z3]2n!\NlA/K] %6bd3sLfSIi9EVV$k.?uY*<[+RIE;9QJB(3BWp'c\qdpA:B\(oO+K2lgGK2Xb%EsA^_'>Hp!-?MKl\!.$"Qfb*.@c$1l&)K8<*Pa: %Fn)S.<3m%m"q\7\UA)L+Bm^QKr&fB:L:8[W_=6gQ-Q%]sHj.EIPIKINl1I$G'cW\K3)e5'0AI:CVs@o0ehs3^]mhOp6[),hgjn79 %#^=5@fB>-:IkU)!F7mhSE2NS=5f7O)b";5:A"g^%1a:\rLZI/8](q(ZmL`56 %>&0:k3n%70TBJhZ^&t6Sh_]8fbcdMG*q/n$nSVC-jK"hB.D-]<+tmNKCqVHG@BfkRTfpF0Mo@Xjct8q.iI.=DKYF8a)C1!'j&:(_ %^.AS4*0&1^Xb:YEpjA>]HX@DNmpb5(]9TaE5+qoW>-JFc)ZmNtAG"7/lRlib_d33hN0[@$%/"D>ELVDQ6l#oD=[$ %Xl=aV;cR])6!V>q-q[%&iup+_K@Au]N/')5k^)32I\0]BU!0];^)*ED2qsG,FN^QT'0$BoH9G0#KLL+PC:,*h/\Ql.&KkGXh6j\+ %]`g3de*DEX1#11Boa];,9mSs2gcmD^e^1C*Vq,(*bp@\?gLDC);8\clTf3:^_(iOJruqpUprTItRYQT"DA?m:69TTh[ZKc38#cc0 %E%^I1d2C]^[EH/f&&sOBRUelbQu#N8(Hh4.Sf#qS>UPS^.Gj;XY?&[Y-GK3tTEf[i:dC--A=H#F-@o2trfT):<<^OGmdn5O4'`r9 %5(;-b^X/1;`=j.Dc.ZD\;I.W#FI5Nu%l1FgR5%D\hl]?)F\C"[&.jB5k5!lb%DNnAn6D8G;S+I:Ho@Z0Na[%Lh?6bX?MZL#I0J'F %8"'6.IQWN!GDJH<1&=GINM>[TiVg$6[n:s%I)_&9AuHC?[E(9[lF*(EDIfNfnQ#os"?Xp;9H8YNJ %2/Cp%IO[&,4=p2noC\[(juj436uV\^ASq';5Cl]&ZOtGIOrib<)UiL:+cC786%*[m:ne/(_S/-&a\'kqi5OnjG8+2N9eXFYJFf37 %5sidG'@Kq&-1X1QV,%fcBYg%g),%_V&f$*\-XG@`5QA9J-ODY<[a.a`)p$JGG:)Ml-):-503b+-? %+KUA:]Q_1K&&N'@Kk;*=Gn:EEWQs8TD@`D"FbJ%h,Fn-dc@Ks$X9_0C.L`(;qd1@`ZM&E?W-'C@r3ar_d%*k_VJ9^U %WgQa_>lX$D'!O0r_T;Z!iFdPhHjVONP=J)9U[A!jk_k2F(?X_Q+lgDO=`"51%d]Li)Gsk!L/\[:EI>VgaOA$Er>AfODl4q5]7;\f %/:MRS3=lbHZ&npDsJc?nA<8PJ3\:)ipIcV:'3@?hB?n2m3\,6F9YpG&8oY\WW14?$<:j4#D?j14\NMKaCFN9A4+)KbZN %NT\=,)OU=@]JWb&YOUC-/HP>KGs(gJqVl]>n8dto4TLE$I)"[Onb"^#_[toU,dCL.muEkLLNm^P0@t7T9hHW!a?no_/&j!jmeXEH %ZU-FQO09eZh\n'L5@Qe7DJbmZlg;`]fZ9]R,@m'i^=V2H(u>Qk;J:R4O3^ug*VD=t6o*ob!WPK6`+:2m$B#el[^/gI-HGorqAZ=q %FCq_&kU[o'F*kmX`7s5]YWUP/Xdm?.!Y)0(7+Omu:29GLfhOmiTX=H^Cq$q:[R^U8&bqT,B@/HP0\L>H@YXK=SF,n'b>_X^h`TIAfU5K^Fua5%=IV1F %Z1r:jAYX^eG'UCt'"%Z/a)g&uK]uVrO'+:M72Yb/iI.)ijrrJ3[b%<_KV.!)#AZjrbNM:!u1!B-s[P4[f@LO9;W*m-oql?qg)`oht#O"7Ss'&aj:G %OWc_pc4-eO";Vm5?< %^'%T.@]Y-aoHD<0"TRSOT6ZO+D*opUOEK`HarQ*]=@[iLOZV]I2^_"/Keg#4I$Wu\Urr(G`k\`+rYHH` %1dE:NK/IEH3`KOJ:46mD9ld@]Hdpg\VhKH#pJkKG(EO*g4VREb=&T\^8!o;,8)P=;1kFg\M;]u!K)TS2%,`?V``)3rA,_%H!/Ft+*%c*JQX2@H&bf8I@JYX`W1WB4J]YsD^S[V0]>*q)W03U^jHD7ekV8%a!3>b+=CH4QiQnCbB6]?f %31QNII?s[TLH;%-kH`H)Xn*\ckJ9b]/SUVE3R;Rj*o,Q)aD9m"lD3K?c3"s0h02+>B?oU$`Z>']GT`pZP`rN!3$#(tRlr.ZohO]J %=,%5$ie2=c^G9l@,[Y$)?3_A!.8dFX=riHHL$g/E([Oqb4&f$]GLT %/frO,6GclrVanL"kj30\?iK.ore3DMN5-fnY)Cm;1BO0WXj=kT:M,0?I3i=/$robBN+HoWhGNpk.]/:]\:NI?KGd'o._%M*S20GW %;cRA5_C=NM2\l,djlTOn]r;%XW]?>eDeago*+;=0/dlob0I-)/aN24sKGf?P$p,QE7@4[cbOE,ACJKm..$M25=ms!)>EGW>S]WqI$b#AM\'* %305?AX8V7*j^lbohWki8+^eQg\BdR#_tA/[$?_-6*QJMK.B4?b$`&beYOBhd3Z>HGqN]R9BI_9$8SD9BlQ%EceVtfObqHQd\36Qt %o4]7SZ#TfD.Y^k@P.CIs1-96,UO9IfgO2[$aP]g*OX]Z+aL"W3562XJ="^YdIt.t*a=K*CSH7DQ:=^;3T$u6;^3J("s,M^D_G'4U %I;ZaS#@T>6RF9A/84fEFS13iaJs=7pcT'!+ZN+8I-CN;jR"c]Rruf6-jb;Uh#^N;SbURH:G8m#g7nf[fo<]O$7`Y/OpehM>M,a/cI=5)?D^6K**aJ=)\qVrBH\?2qa>"L%at+7L2ZXRO3sgL:;bb'U1# %rcV)6W6/0AMU1UjH">lTh#[E0op>&"V;rl8*lm))%R4k1225Wo]H0cLZZ-V4"?nXS<:=l@sGiRDEIpg%)B$oCFp4`]_l2&9rZnCe<^an`'@Q %kS\C0r"qLnh07l2G^b[NGhNA1RRJTaZf`^O.B]9@]Kr>E1Vp4`YUMH\&F1Nf8g\K+RA&[@I@4V %IQK4ns7t^tqRZeijZ=Pb^]mRN'`O_&p1VdorNkAbCljj\U!8b_e\Se8B5+#%d./lURKWU3k9F.N&+fZKrBK8n9hlOTD=1j4O2:eD %m`&neAsMiab]dp[5G5H]p&EA@)k:m2;brDXCuFT^pA\gXg`F#X7Nc)sAAW8L@"EuAFP"_W@8E>;qJ"_YW5l9iOg$-lXoI-@V$des'VPESUk[2mS4L5`D.$>0?q %4+nFVn_&5g^d$V=PBLoB$U,FO;Tct2;X!g%A!Oc_GMjqAfBguYb*:?ECaSQ92[UO":4hG-$)jc&J5'J0e,T:;]I?cS %;c_oX#?Urfn7hEIbb/0X\C8%gZ^%ZKT,\?je+&oimjGL+^Xf:FdITdCVt"mCm\Z%#kuP-2<4g!sB98Zq5mR9Cb0#e-iHf)P?eWHa %(bL:u:dkII %CZ1$4qSOGUf0o0oh0J[uI>"8HF9lXW;5SAQF5<%PhG0tjJ9Se>l/PVkQcE0ETl_8T?ZJ;,\I[b30V)Q^;@1kq5/RH[`Ndebo?suT %@AA]f_g4ss#b)^P>D9:Y7BjUGO0>F,*5T)IZ_.b9;bq.Jcd=gqMrb?JDBW[)_*?>06F5u/)\&&*d8_Kg+$DV&>4fTVOj(<7-n`V7 %:QFS._$VBYH?)]9D*IXRB\jUen\Ccg*6gPI]*_4!R7gHP%&nG_29314g5aK3TD-/b&pLlp6I/brpZ/i'5OE3b$k>E\kJ;bWOVJ3_ %9H#Ej2.#XB>E]Dl76K2%)oMN7I!)gcYki\'fWIsC6au>`I(\Qf>6e0%2>Cn&H[eW+A^K_2<*TeiW&0jdXc@(;4P3Z<4/23]$KGY* %-)Xhq$g5-@(+Wdn8Xi.am8U;@9Zm/UP@tF&P$H%!_tqh,#a5aCO-:mrP6U[E0i"/[9KKu:3!8L.*'`Xd?S;e6jl%b>1dWP17bB+KF;Fq!25a7=&'\+A_*iE1L!3#MJ92DH3cN#\sB?jluI.%2dfZN0/]7%9%-0t#4:C!LB?RT$oZc6jG5qm$4= %d!'I7_j8O$2DEA+o?J&)@1]0F1U$8??6e0GfM"f4f4TF1FRD_pF9a-K(Inq4UsNP&rCZp#jLV$_*IN=e?UQi4YG@g4%9G %/=2$X+52lUgB[m=h:.\cbrGT.W<'r(liZ@.q-3q'pdIb=BXj;UH0@h1)ki8JaBg#$!W/[s4?c8KYNiE%';;O=GPE/O%>`?*SBb?q %35Z#=;dQ(l&_d#ZoHpKbfI&MB9-$JP%#HdcA..t"$#)):?&lf"rHo/8_6j9@!B)C6pR"=OmB8?MZf:;Zr"C[Zo[n>%s1rMK9=V![ %,Om*ncFU1&)E"dK*8;cQ1fZV8)o5EXWgo\&/?.IP@H1,o6:'BX]O]*>Vklc&H$qY3],@4eqJ@sWbU+23B4Km?E(RbJB4Knjb_l66 %S;i5DBX[Ol3*Y;>6YG=V_Ec5pC%N246hY>"VZY`&8r]sL8e`,;A/^&*CBhm;!RAUNg2Q`A=qm1cd)gE/(4<8nf1uBfht8.ijO'lSC^X'qX&9>Ag8 %]ZZ$i4pLn#cF[mrk-3;u>@b7O#GhYOfPEqTBRMaiO\+mFra.Q#MhcW(]5.M.bs%Wg/fRQ%>L.WJB0-[mf&eRI4ffCUL!^s-P+\jJ %$-p#-fu"/9g+Ls64fmP-8QrY$3F&JK&uZJF]p+&d*gZ)nL0ZA1p9=0P,Q@(=ah+;XI0dg0F5F5E>5!nW)EaA4U2)mm34M,;\e.d0 %kdPdgF[PVOd1&ds8%/!p]_>X&f2?0ZC5\)=F0p[X+T^at0pE;!Xu)cI"R<^t^JY+i?21;W?<.[5.j^;70=i9$+;nZY.D`Vf8g&-& %boZn([[FK)3uj^*Rk<8WO>,b:ObjnnnAJLLBU9+k]=jp4'oKp-BGL#Q<7kkk#iO0#EOdIK>1Yq;7>A1/`(SJ"4"Van?Q %.(e:'8e-r'!G&)bDImh!P5EksN):a:A+>E2/!-,;//"Q?$FE;E5]Ukkq-1rl/OP %J]ge#0QM=e.C=<-X(&RYCC6%cQ_G&Gph@p4VRrQ*;^s.?[JE^a&2C&&@f4)"QW#N.T\[.Vf-7._fsf\G63-6O@G>KRo,mA%T#UmP %TV#IC>!K%aV^I!g(&&S(Uc:li](*&r%9l!uSBmI=(ks.a`jYH_ddi6dI=Ed)n0s.R(1/TL0RU1UOKbg6_[m&397![e.is`1c4C5_ %0HMuc81gIf^87;-)cFjlJ0U]!QSWGK/YB9<_eK(Y\,,"=l@4/]II"#4[!]1DXkq/B*:SB6-N.iW^SA8a(Yq+#*lLP1meZ46%>H0H"S,']E>/XjS[cn77b.s[X3Y^Bo^[Hf'k0^nh+=>)hh+Q"Q)/Y<=;02/#%rFhegg\C!R^/ %a*_Y>d/!oR#Mtf%JVtX(%M)(iLn"an\7*1Y2%=`2h,lMu>19"p2cd%pEj@EpL&ku?/6W@?[6.P`amm-giIe$DHFI0$3\^lc\)QVa %f7g?O*&s#=s)t7;gQhJN=5#mM.h1:*j$?g]4mqb9GBBZ-5p=bm-KS.VTdriN-i4cp(!F\[e[L_h#Z8q)]l5aj/[h`UZ>b7ZaCY7T %-<3F>PN@nL7OLAmUiLEGQBf&FI>3)n:!QQ/8$qi8Nq3'oi"[hMFJ5i[B28-4+7C!@LVZc!3@0p3CKOb?cMe6DVuf>n^P3\Jq2ntCEl'*Q8q0=L+*9e-T@E`2rMk$X %#JI.#3P5A&jm/YR>n>!_mjQ0Y"cF:Q:o19`e5-m65kn4GnrYaP7/7eVBkY_q2M*.:VYp:OQR.$fOO<+g=*]4$K3NC@^G(Gbk<">c %njN[JcOQteM>&_'0"I3m;i/8sVr,e1L,P!jS'T%NE9"ZT4WH[f?dn=TbgU)8Itk0"f).:V@$hLfYO:Q9+9WMS1q6CYU%^`-80ih] %8\,/"l=1uU4'P,*mZhklc+,rh!cb4_)3CN5pRNAI(d%!qB6koPUOuH)R!^=]Vu@,V&&L0PT1aFNHihLO.caO@SnG[H+i""+2@Uqk %qJW^S]5_/*IbichE9O@3%[pUma(oq!,HT,pf+^eCp\b_CHH90)JaW*h@J!.)%q*C@Sh()Mo;uX"8?A&j8s@-OK-2`-3QT2a`b&Uf %-K-$;(hDYuG7`YaC`N3.VMN^>-hd;!F5#q+/BA4qE2793+ %N)d&HIr*RjoZu`=dpU@*`5(l?=Q?XEg4CkM)Q-\7SrC/gI4hcD?cE;*2;uB,ISfjoZ?JE@Q*sOYoU'\7@ %X%b+")j*_mq %W7bLa5\8kI;/r!s<+buo<[8>rbd"%5(m7R+*G[&"AVR`RS(oWNjGq)eMu#],GJ#Q%gJuWu>b5WIgnJY:W`m&fRUMP!/G> %mg4C916psJg!;edSJ":e(C"E3E(JOemDXGf=H.o(675hgA?bXR-DJpEAAGnkUL;mFIeTe4hSjm7r7-n*.>Q\I%1Y<^rqL=LncC_]XD=oROil5qAG(>m:Sf5M!!7>pDW.r[ZPm.1n6oRdaY8K0nVE@1']EhWI5;FIYZJ)L-MS %It1!H[dG7Go[X4Og#t<@SM9Gff5iPfKkC3fL`o#"k;Q7'pZ6H`R-_`k.Ku=3=g:eR0[Lb#o[^H3?@X7^ij(WO+kd>e)^Pbk.#>?6 %dQ[LH`uY.fo1P1FnOZr@%YOt75<^J\#K4VlRn]]Yn>R?b3IIl!%,QDgJ\U6Kpf0j(/JpWT$[Q5el*s'6Ga?XB(L`l: %X:?6*b_1,I"%[s=YYLD48Yso3M6kCF[BRqW<_&=MjZWLVJ7&:BcIG.X_p2ie!DK`AKQX_T'@=WN'@tiS(^*qJlYL-T!KNkXc;ms^ %i"ugeC`e0-94=BnX:AYnG/?:E=WM\=BYq?A+;6_EQIS:!0Jd..XfN#+,^.$c>?N!9aNT<[[^%r>9kGZPZ^'',)DEsUSZStgDO=lY %XL"2BknC!X$gZ$B\ujEHFYGASf)o8sCDn9"2a:)6iD2[j>OCkupp9j*,^R'C%$0gpKAlab>;3^>q%=+^?Dd?E4Qq2tf&2eKi^CLs.M@d)8?P2qH8f+LA:-cn+E7'p<$J#$a'03,CWU&UO13P?34hE_K*8YEVtR)Pe:W=8E#]U=4KX,kE5qa+4J;iYWtTW %GR1K,:5Ccij!3YG9AFQL*T''Uh90c]_?3bfr5HTaRu4 %^8[;QGol>GGRR:h!6P?2r#1,K&,)5%J_k6kFto'C"F?nL#fO:$@hg;45(q$QYR/@q=):h*;Kf8CB`Y@9Mgc",oNjIl.H;\<2/_-J5TEa0?R %[7AW'LrMAY>eL(3b+`l(\dl,oP-g?W9;C+eds$=ps"9s+lNs8\ancqRpKdE!=*?;+"=c8@r[[j"0CrNVOiHGoO8ekJP8$nHG-*^@ %kI&V2qJG?hocoHH88#t\kcTi5-,/E4qWl(7r52[=&"RukBWUJ!bEHjSPo_@A;E=NG"K]lr#UL5VO=N&.;#MsfdHYs9UYBlYMc@6k %#YMqRL(nBmk!8T`KQ-9P7qfr3#e4`D':CaFZ%\kH6[c-Pp9<-_4BpV=(18W-qaHYFL*u3W* %2f1>ddtmV%phY=X"]KU"Zg&'_Kp1rN8bL\\a>?eYqpKrm@\+GX[tgrH+5N3X %Jj:eG+KUm3$KJ)MiaL4?`7gXnYf@8=2 %N?*1[]=\[!iTt_'..gJj$-G17<1\RVA;^K65I$c&(7"X.IptL:rdA"US\`'Z/%.eu4jdC>K3lBlVZ8_CGcn&nqD5$0bs=]98T`\I&fdMF5dQ]W3"MRUB,&>2YE-dRNAqQ?c*KGWB?IZAkM0#jee$$RBoe=WC%A%d^W75L9CR %:_E$2:>B#]Ed36Y_sBhJlG?Hq`O)mI$,)7'H@FeQ=.?`"ulk?+NoVe`$;XaoW=9CkLub>G1\bKaduX].#K" %(0kkJ/*[V!l8l#KP;.@KFsG,dcT<#G+7$=/QVmaYZKMV1&>lBaZB:Y.VjeY8P(9&Jr*P"o8V>YJ0$E\01n"t7$b*d-b+bLc&SH4S %js.jgh_j>s;?51s1cUh,CYg*i\&2n\NR_B9$Udf]bPtVNqGr\C;^H95hOcio(+*.U %GBKTXVj#+fa@dkYDT%f5VI#LrK!AdLFr0'n=^LL,o3-'[hdgY-6R@!gQI\,$>=15DBt70pOS6>]>FW!b#i3TD]!Y,![H1^l\)#b5 %X[J:i+nUsoM)QM0kc(BH-!JhkoTIlcYtoE"ZmuZMiF"!7A-,3`\kp0dF-:nK@1_OBg/7jI40LiVO8@tNF9kL/;5SAQF59cA7QR*g %!Ig``&lJ9ZaQ)Tpd"Dn00=d[Qg]sJjdja3%Pu.G<1FrO\GIt@VFZH?h/K__*P\Ibe4d>qfDD(5OumoM8tQ4&9+A:639SCYR9 %JJ3KZ]G4WKIL5u5WeTAb@1fkL*V>B(cJ"-S**5.k>p8) %Vp&@r/#a`]/o>k^patp%W)_!QbNF:]>2fRt`MrV5^jG**QE]caj8N=#H[46hj0KLPUS$3bqN5JhQsYTmG6W%Ebg7/R(Xb)a,5r,N*1*aXForfSIAA>4pTmI34Q[e+K%j;2oFI"ntLMFJM3HIt?_GmhYh3H*hK>n&#\UN*P(p %)"#/BYSX9cYVl]\-CiX-7ki;@C=OAW4YI[m,Y:_2%id9Q=uJYR-H\_j04c0"?p\//"b;#_JdHRn8]f#OEE0.)SClsb8AQ"8Y[Db/ %"t>r-9)KH7+/E:R1pjW8<^@)>@9f-Z!bE`*FTie/3URGSS;-81S_Ma\RB-l,h$Q6]b$\_*Vu*o=bm&=KmMi%fjg` %b+!Q,>?Mb%Sm`1"J.j7KG89ZAC87g#S"$@J;HV_96FT/_88Js4;"Y3eXITl"SjmkS>'];YOOR24i:f=+4#o&M./Sc*.eG5@K4;p? %mN)^s/dDUm'7%5oC??OBSR0q0&WOhXXnT!Q@.S^7X %l41,j#!mI8aW4>?8-D9rG?Gi.&.gX1hgfEqPO3n(af*V+VQ*r6+!J %XYIoJ(8OT?@Q(\JgOcM32R^UJFAgrVFos8;bSXk`E6.u2bejZZgdZgj1!%o],U\1!Qe7]qEh(V%ar"ZYgC<%oXA.5i%*B]*!JTH*h1'^Cp:qJP#Y-_jQn.:F/S36>':# %OTSQr6Mo)TXcA.)*K$cuV^#@c&$10!RjW"'fe,Zbt5o+"Goq2-4[G%h7kc`%#RK_RD %_A_mJeIE/c3MX9Z`2I/$rBs*?J132;S;n%?="NpIp$(,*]+Y.JeLrU[@7]0hpe.>Cfd@##1G)#0Gf\2Ja,G9[qL%Wc,lln;O9+66 %!rZnJ*K3%k8h0OQF<0o`?nt:ZEgV%FW1Q?TR[3%&f'$U0^a:+i/hVY*`:3(e9#i(I@sf<0!Yoeb$q.-]k[^Ai.AkCN\'aln\'N!3 %]32MKFQbj"Q5BuheWLV-T,_6,"QuR2euphXKS]>_ij6hgRPR`gK[n[Y.M.o;,DW+cJ*I]!tB;3#]pf&h-9\5NB*4dtMt>nL%#$^%P[-/2cfMa;c:-i\l5AG(?>`gnrEP %rbENAdHmF^3FC&q>n4U5s'E_WS5_/H#GAWuBKIBqA0@T%f[N&' %lqs(7.>>'qRLhUiJnh]Y0G_eXKuaW_:.RdOF1!K8Oeh0F7EAUH#EodY(*RT>>! %07EJRk:@@Z!@Eqp)'V=)E;aeq\j6u\/MgoqC(m6Zn@X+L=Z)llp_j;Fh$DE167Q@q:%^pd(Z;Cb:#TIbLqj.q+O45[.\dr9pDreK %nqD%8DP1"\nmJWtKWL=KrYatRr;HOgni&_dO94AEh4T%0Ff_'FFJI,kNj3KIkQ[[/pq_II,PS %IWB`JrHKqEL/WKORjQPfi[Bh\V1?%AoI%QI<0A;/KPhh93?_QF<*Va02m'CX&1=[pjRdAJB\k?fF^M)Soc]ts.$cOl(YhcS#m`.3 %66E//(DU^"h,XhB#8c/dQ2G6Rmq&+[^bK]aB1"(#VD%D\l[_XmOn7(T> %[39GaTCT!L?&EAh?UK%CLJh*A^/jZ5IYtQ!juWX7qH?g')_/i\9`%Ygg/'Xq\!K9XET#UXZmrD?9d>`^_6WDp[7[<^h_-PX:p#n[ %5s;_-S,/?qIQ@'-^W]?5Ig1?6>(`rYkI:Rigt;iH<%irc8^um#de5WU*1m"'i=41YRLYs.iJl'i&(PEdQG#C3qbXEe@@Fc[C#i73 %R(9))h"bSSdU=krIAg27CX=`S[L^n^$GAH4q+Xa$HU=JdQPEGMM/NK4g0OGL&K;ZatJ]\lkR0<@d#A"n? %L47[W+.orY3qsST>@q,n85hrJ.nH0o7%,Sl>4K@(KLfn1SDU8UKYga[4Nd?$,2^te#Ym!]$_qJK,:c`!KLfl$VE3F,S6"@cUCL$; %[`X_=BR8L$mL\GMUNt(!l&L2%f#"Yd-Km4im+<5"!h>T&C!mu8ZmJ]u8IKSB@]n2>nAS4$t\]s5mZFOl6!lMUilKM69Z0@OEnB`L5-5m;"qGj48nIk#56qqh3fE %4!aFQEE8F"p\o#BUCK&hAMr-0V]\CB@P*N_8C_9Pa+Jg>Pt/2YQSht+m53D3fZ/YUi)eJ(qj.>EOUOqD.[KT8aiFs0:N\W"84M/' %\>dBnY5'Om'B!,LYtuV^UW^Y5P1_q#iCVW(@aI6WUcHpB_uRuuU,g`6%#:jN`ANHK:m0-I-G[0o_l76?8[3G"-7QipV[H:C3)k0O %Y3U&>W772d(jWP8bSZ`&\cab!KL86@'0l-k@M!uk*Ot5L`.7,bA`+I1M#$XN2/IfKMkV?d?iAW,]7.s/&-F]sR8\iscb``pKAQM! %/YUBVA87^aC(S9I#lV%gP4jt:@RDa_L`sosd"@_'DdI+*^,=9erk^aIR'$/pp3NA^RJN/]DhRML2OVtV`S,=SN'>sNRK%;(';Co* %ABZc$8X3/P-=;SjN+]cHkbER,j.SP[jUj)/AC%_oICdf=UA_]]7;Q0Q4tBsh6$ns=:^GJg(@]JKOpm=ic:Tj:,HG!'s-.'(_,/OB %q55L%]l/"tpmLDn1<"."T9rH@3oGuB.d@VCU)'>M:TcfoKJk:TtQ-hlBq %/bm:9U\P_@r!iQZ01FOP(W4'kig8,D#_!XSqM\e*MTYr"r,VSGp+Lmj(Vfm+?[TdFoA\BZa"QXWtQO:lt-:V1BcB %iKl:m^PIm))mnMhAT5dpXL/VNh,_tGe5!?!GoCNXdRX&o5VCfB(;e_RWj]6Z3S.""(8%u:DF&WSQ<8\$^lf82h=2hs<^^lkN4-)< %=re-&$cs"P>:j_ug8Lf&`ujNnrS^djdr)@@74GTLmGVE+n;E,JncQhgpP[l>isUZ?9L2dQMAccF@s,4W77ddF]q$^_+)%f&`(e((`1Ph0C$Vf">lS6)DhipOf'N\m/JQ-fAaQTLW.s#Ff %8#mq1>T&*`+#4uM9ck#_6j?#;06W]t4n"?r0Rp?Y?#PPh`=kkSc,l@XPGuaQV/'*1;L$7WEH/f=H840ei42BWIOA;1TR0 %[\UuL2Om$1&0pq-d:FpdF`;[/0q3m7"79SNI!iY[(m6^`mi]X.)=\0SBIf%6+D)M+p]4j^]t`q!B+8mFORM*XhNCTI[OLd?jC<@U?Kh)bja^,p4%*'d28R`@G3Y`=Rq>\O%Lm4`!YY(*K8',(I0M@8Rb %d;6\W+7>H6n4le(AmuOr_qfoD8$lf9/A3nj'>jpqF$':KUU.Fpo8e_opR#5C)+,`?hGpe=-DP'[(>%?!M)"M@^+h>P/MeH9R(Gc^ %@F45f93[NS4=OE'P;*ImKBL3#RZ'ZhR:67p&>)rZ)8fi;X'SX4]sA%m_^NVfROl<.Qn6&+7['qa-6j"$2Io5.'ZYG/<[Mk?GRc&f %ho/l@bb>ME^O9\F[Acfn+DojiH[bIoNu'U15mI1uphP!m.hBe/jsY;!]b$@&)>6<"*&.I.MQI`-Aj9BYVN'1_;!a`;*3SSh@'(]< %]@,n(A*B1g!RjR/7nKRb@Jj&eaUGBIj>U]t))P%7G/hlZalLrS]$;/ha%(SbkW35;Q"9['^ToZ8WtP]nA(7&(oM1d(G;1CpP"`&U %p!3pHCkCr+n]qMohNa,H'fJf(ggg&\AS0\@pZ74U0I1\drVN`K`tBAfa'f!:$E%Lr5(_95?sn"T`>mI[Xm.Q^hOpa%9!OI'-h(0.R5 %s&EC_f:Z)`,/6!jalg:Y+I"OR-0=Kd\smpT@jm!Gcb2/a&_*D$46MtZ;0Uq-)pt:7q;K>AlZtO>Y.gdbe$oW=PP?q]XgdGZU"WFC %Lg\@R\G8,j"f"l>Vnn@=l8oht%[+ZT,i&P\k[T11cj[6oMqooHqO;POHOCm#KnKJ#,N"Z1'#mIlX\YLUQrUg^7bhuk7&>mslo>qR %GiJX&hB]G>2(^hH4f8hU#1K4OehLO"d+CRG2R9`^/KFqWd`QpeOcD/e7E_8>r=6J];p;8p_hfrNR&L/-bu2#61#Na0G\RT5cPl6X %&^]ieqn+:o(1&cU8< %$<`rQ!^He3!Wo3k=gKSq#C@=E"<%G"2(=bc;_mBS417)O+5k&/g.SEQ[r7'g(WGJ^uf]$in4))^I7S1d[dfr]2na]XtOF7hS0 %$##^k#J]e)b#?]'oB<\BHC<`cA\3)5)*7Zo(?ao#;1-Ii,En[AE33/D_bd(tr>@^0m#nDN?iC/`?fX_#MQMQRAWm%OMEfXXqW8GX %6+`Ym-^q$-?e)=HjZ7cNKJa!KA(lPL)dE=$f!?]n,sf)!Qc^%F/U,Xe#H %[YI1"5Q=[^7S$q^e#Z8n/n#:VP?8=Z*,eo.'q:Se6gmX$Vd'1II'5d(_):?If6tEPjuW=O>^jLt3,3!YhEkJ_4i)*rcj4I%IDA=NbGA;6F)_CY?A'&nH5d>a$A%cUlmMP$^r"M-d[4ads! %'B&e((=MUV^b73(Nb=.]i!;T.B8?Y,N%RmA"iLG<$;G"A%E*gFN>g[9J[_#Z^QQ1fV&Y7sNkL@k83P,o2RhD2$[AV]e^m$RXH!Co %'m>=s_8c+BpIcN@5g52Z&&nB?Y`8u<"?Xcj),LgP"ZUc&Qpuhof>`el(%$p:=m,\fB'$h9][2X %]ZHo8[pIAMK22+4ZEQjQK;hT/fmTPXK@=&+4^B)0WB+/[C@\]d5%m$4DQdOfGNL-&gp]E,DO"P3K41am*o*4(a(XTu4bZ,t%#,]K %Dt%DW?oYpq*fNL*2rN"okeFk0@.srNr6aaB>(JlhC#iR?]"_jXnQNG"?lqje6;)]I3um&W`p.ugm,]`FdIMX$2EN"I:QNtF8ET8.-&l?`)G3$@,m(q79LaMCr]p+D;@NY+.]15)]fLLDah4btn?jTPDWLeh,SXeum>uae&-btif/(4a" %UjA\bI:\Zj.Fkc'8hs=.jP@5(<0-8pR].@0]$\hj^/-sFp0_0&4kTW9BG4<-"!Qe7eIu>DK:GdMW!HM`+Qjp;s'+K6'+3/#%k)DD %rHPeb`'NQ5%3%^YeqA4HR_oehS>p#abh`kg[r6X!KTgg7kD^$u3Nf+(rD=gD\,grB!:8,CTlmu0`':4Aq_,6;i1J[$gFSC&4q>$> %qD?e&J'IQJY2B1N/^6MM`Hl3S/r$4FI]8#gG"jO6*P/-rlYFAuBTPOo]Z%6&41)Qij2\#-B>qZ=bKtY/TK9"hZrR!O3l3I %>o`7(pT^kLg*5Vm-?ZJ9?c=4<++2M@56[$lT;)j %Hh?ZWrt(.re]Z\1V1&IJiFaC(fp5Rl)UiNpXkrBP+&iq&bL2\N>_demD,\tYRU5TKfp#+,oA`hDk"8t$g<8O#$k`(t;6bBZN)dg0 %!2j#frIdf$ZI)hLQ_4sr_41b/FCIdZJC,/QqD4"6"o3(!gI`k'=7L`SK0 %c\UF'=/Q8ObqKV(adT10i?/PddAPV:TX10@9$@f`md#q=XZ:hedg$+ZI<91QmXij@kpcJLA/GaBG2g?_Xc5GJ@Smqb+9csFGV]EW %acb;K2fGI(=XF"8p,BVi,WIS!HCXh.&)`#/>+K]9J_c0r0cZ-S!GBOE).AZgTXY@uW*W5OR %0\b<6GKMQc.cHAg>dpEL9htK+ksoKEmfQ6bkTU!f59CE\;?%HGpKJl!PS]KG()5DJ$f:[XK(KC27GLl[u6&p3t/:@Vd(UQrmK;]1\a4B4I&Db8a'[cG"8#DUOhBNLA6@n[:L!+#Borr9$RLHWVi"m.ahXfkU(;Rs##kdKShD>@YZXI%lmXAOqh(&2)7Al'U#EJj5GCS1FBcDK %DO1'hnCC$inLMS&kFE5Bk"*16]ZNn&jK4%5F]^oLQ^ps2*jf&T$t9jOc%IuP4$lG7!a65Z-1@)Us[h'W04MS!tV[X[$a:B/hj%J4[s+&Z6tCA5*_C\.ZJ/"Wb[O:#l[]DGVI %4Z"Njnl0C[+HR>UX"?mfJoE]Z/nC7n]kQ$2*6GCJP_Fp@5FP'Gs]Y0L%&P,"On.2!q!WloM%Q`t(&V.5o"MP(ZiG\!^+AL_% %FSpCH#NuKTcjc6+B=*_tHoNmm#u,iK#q+&@':N?1'2G.`-?LWYKN%4+NM+;3,tLst-V8*$>_4e7a)#-emCMmmDg^GQD`jpMW9JAV %0lkjE$a;MNR(<:T`Nd8"5ZbHqk2CZG4@[V-L`FY:'JXV?G9M"j*lB^QTq?^)]_QdY3QK4O$'BSVD!N![8Rga#6KAOmeYWng!(RbK %kF;lrMf.Ia:rLH&U7:H\7Q3r+%7('(Qi(X3_@S#$Hca#40U]COj^1C$]6s`=5-9[U;eFYA/K->?-1m6KZu1Q7,,C*i2rO$`X*o(q %T*=PZAfXiQ9M2IN%/sG"#n]OZSk@!_K-'U'D,TId1Zak75*r6hUmZ6/-$`%H,L)GTkG.oR3QFh(bK(l+:.?":;rpP+j`$D\BfeMj %I,5YdYsR64=@Fb',C-.CKWAMNGW[9DTAE&Hk3oI2S]ALSO\lJ(h;"_?T:h'Ym:$tRYgFOc$.^CcrbtTEJ%:#\O;dsu %1*b+IT+;gtenqYi^+G2toIRFs?+H$*;R"0%\&J?E:]3qL-kW`RNOMuP6r#G!aDI4gos\8p %Ski[U6pmo)]?QKa.S.GAVr8pnMfO0^q",Lm._$3)D*]WcGtOi!.b)&;1r,0Yop%*4GUQYr;QO.p"^:;]fp3cr-jE!D+eE5HM'*P' %W=Vl,.trU@.b(QT$;uF+h+o0<^G'DGGoaZI,]N&jQ1VBYQ+S49!QTq9ONcc[KTOIX1m=J+F3*0DDGYr<@Z7S[7V=@_]Q? %^UGQI^-'.ofRCX\T<"pc_ftTtn`Qk<88YJBT8'/7+5QKF,V@CJmb@oNTY%)`2YVMPfC"J(/;L?3W:c/*OE@99II0Q[gXai8FQ(.! %h<7+Og%@0I"Ztr)NN:Gm=/S3SFa_][nCql=?dLp+XMhSaJmZkeSZL''ke$$X7U56bMqi7K>O7]JDN+VK07P2FZM6,@rSgKcdXJ/S %ZoL;HAZ\u0Ab"aZ62P5Bo@JKcbCB6/J+cN.p'YoY[8Vmrm"cV4WHI=;`I:s;ZWFMl).:5'SuB2R]BQ7pMmZ^aBX"-Em1-F*mb`X! %X03<&dbMi5e_2%O/)K/c@Bkf[fqDG>_\oT,@VlnIOBYj>>A'^R\WHaGnj$\L\aoROeQ'/fYdZBfeREB]6L/Et#R7POg9OoKNgKTE %D9mi:/_4M_G/"cm`S)l^^@\a8o\%E'lJC45-a0.pCAV[_9].dl45(+>\iE5;XOq45CQE8]%ZQ"jMQ25)U";E'4ei"\&c1;Hctd+m %YCZYhT\%8,H+'(3KjO?NY?e_]D=QHn%)P-m$bV5E:Ha8grm5G?@jIqsT,d[">Z\).[-$/5J8bDQI %f7j7kQiHE=s6Q*Pi\/bt^PitYJY,tmrYL([0E1NLr8k]-UAsm$rNEEgl1YouB$QUUjnso<%;(+7Qk*KJ:L,_C_e8Y,o6\+Koe#?V %I;(C8)Q3k`C@,K+5\`Id_0U8(BmI_PJBt5q`#DEb'\)><.cP)qR>N4SjpoFj-7`dc!4rgO7GElAQo7,7Ai+cJ7RE*+">`(]k3rAp %BNVNoE".d\UMoKr'ffa'N.r66$"ihRCl'(dajo+&g&cGFF!2ZB3dh":!b*!]oOMWpc45N;Y`5=*fa(&@R6f?*&VC^AXuY6dsWPq[KI850%! %3(:5_o-QGVWpPe21e&.K7P/T+X"[QfS48VXcsV,4S;6!*M8[2$p4HKNNPlqh?lMgCgdk+'m@nMEk0(f]@*@CtN5*\0kXZ-IQ:!s( %-]Z-hN9c:;'T#+>()AjRB-UlMB4NN4lpqQENXc4qSi@?=1E4>t5<'931YWmB\9TD#bcHfCZknRMIAq8/g8j9fX<`jr,\//)F\??P %>H-\-d'QuWjMqZQDrlDo8q,3QMH^#Q.eudCd<<\UAC_:?-4!bB2r6.m)=li0LrJ;;r36'gOUS>P^\r!?m%p8FfANR)>Q531V=&a1 %c[I;uajRM:G@0XDlk_%\0q%u<9blB2EPk2BBtrI#qm]r/V&kEipY.?1nP.a5c[P]9Ieh<=C!1s.J+e9MceC*nZZC:g/8jfCrtbKC %kKU=Bq!$nb62&Lm"h>pD/S"P#S:2K;UeKK2:KJBo6>O8n*[Kiu!KNE]%hX:B:7$muQ*tW8Xng(O?g-rb%Z?IC[-]s[,XPG-W %O>"KjX%]$O2D[f4:%KVc`$$k+\_Be%6gTg;L!$A[[JK!utMq %O"c(MT_nU%[\m8*ZRf_,:hmR1>fP^7)[>5gO %P*tR^iS(MHi*G,iQrYaUYUmePG;Z[:E;,oTQrYaUg_Zk2VA2b$nlh+/]lYMm#-0^V>GaPV"tbbi396@ZYBN8ra]RW"rIj\^1qtRa+Hac)P %P3Fp#Da([h4/9iZfp-J_?=&Bp<>RQ5;ar^,Dd8W5lII!8nnRmsd2MrZi[PGk\ahb0YT4a?^T\C;Ma_"RbNGfNEV]OdU[DIMVWRu] %8:6jh//atH6\UT8Ope>6[r*3&9%(>*3?o/u7?_:[Qn'T-)#dWXr8Zme_\S2d^'`b!;gGlq %H1>8`Ws*F]42?l=bCce4Rc><8Tk>jB#4t'miJ*.?2fF;]g73qb0\;Nhb!QP/ZOK7UO@I"Qe1#@hCkODh;5lt %5-r:9c(SEgoAJs&eQ;$%Og"iZ%5@D*=0[kTjndTsQX=>b[[oV9--ZidoqVE.g2KK'o(_Lu#4CBXe`H#:Gnf[*_1&r(o'>#Tg7.Ek %d0tAg**rLAo[g9^=8+YW?[;u_AcBT*khWSOOaM0;h*-5q2Ul6OS<^d?K9)n+]^[urQHTMIP?Z"5GZB7.*5;*P>OO5Y599ii]*`r[ %Y=:bN)cl@KU&MVNF20to:be'r0*ut8Bff?URISe#=2Sdmkp`0&>#64DYpQaRZ\#Z=TU\Hq-pc,b\&L?,Ra0g<*H`>XT %qTMWejG/qiI/P]a.Q;gANun5-:BjGE#JIP>lc"SAi53gQA2n-/?:S@?Q=&+F'f0^Jmr#3k-f;nra$ZL-8/7u'oc,HcN-AVCI-OhK %hE:T'f*A@j>ai;HH,SL>],"+VJ@92Z0<>7;"hj@']d:*n?+W8@%f#Tq^3b1lVEr^7`r==d-4Crh=R)*>Ke(^gkGrm>MMhj$<_N"t %#R&^&^h@jp#R"2c/FgbcN>)7WbJR"+r#"(CW&034:LCcMB3g;QF6O\pkJ5-fg;OFs,h=#B>'mdNi*]O,Y2=&e1@FO6I;@i6mZgNjnQ@N.ies2A7eIc\E=eEYrpgdaaM[r!YHol2j3IFBW\cDkqetoj+5ie.V3\g.=1D,ck['gl1Og9B %brMYE?rFhlq\N=N*"gs6d#goYJjaP$isO850d\Wofh54:^B`It#3`"!IA0Va!sjs>LX-N(hPqZeKocjn'7G+N.>q!1Rji]C=,$_oI2rYj0Vo/q/ITf=pY@]lVQ`Nc,qFh0s]qjm;9\f((t#(N3TF>8NKo6;b?*'!'*O]sf^AAI*o& %24YOaClkRlZ+6`Mo.G'o8M=pdm+u^S1cT:Tff@RG`FZYtcpO7SOoC!Dkja\M]7o`=)6BQ0"q"$Z1B+Y'pi>(.WX81Z+kK"Jk"n;KMK?C&O](.lEoli!GpYNJ!]R$T@T6qba<=f3c9BD30h9dJm//is!Zh2S`3TLo %o(-EQ,Bq>-lgr03eXV#Wqms\\M@Jn_1F0B,%ij8n/"`Fuh@PV@Z(b-[R9:"Ap?qd3fn]iOAG$ggo6F3%qnS>B356[R]6e<733k-; %PM,Tj\p\tukVgGC(GF,&T'OTT-`F@f9=LuuaXV>S+"no6eo!X;Io2@lr>;7R(+A5hulDo6V^=[B;lEMZ`U %0'CQGnR6J4I[MdqYism-P7-ucd$O6DmEsh;c5WbX,5Lj<"SD*m9OGCo1V7_@nE0?9lDN067Y2&(E(H>Q5C8h^3e-e(oTqdH(gQ?= %qMYh3p<15Kgj9$eg5EWoV/:l0Qr5`n]lsX$HKQ@i?l$u2c("0NcY]lPM"upjOMPs]oAdflT>d.CEr.VrkeH2^?e>&3mJPbkH^j3l %?To9I5PKlpL8m=RuZhk+4JhTjhb7b+h5Z>NRN&M%&1t\3E#kKDUFRMs;KL*PP]7Y_i.$:.Y]%M*8VUfIUV'$3?95:'mehdXg1YXYn %FBQf9fLfs$KL$-jr;:HU5o;7m:[fJ8elT0TUR$KckdAEFr%\QLZBZQV^^0D>lPJL0pMPMLfpO5o;di)$)MBR!qZD$rJ[9EA1V1-3 %I;(qXB))O0:!S?f,\N0(kMNgdJ]VM9qa-L+!_i=aAGoPY@'\%PXW@62_rY)kA>EOTo'r;XV-Z;0"-Z_@qW=R@5CI2:!gDa:m>^_, %ir+LpZj2ubA[EW<^A,AKCH'#`;e8>)9RE(aQ"%1D5J/:p=_acb1U8<*mJ3]H$s#SMJ1VYfP,W10^m5kqOu^\:G*>ET[i_a-firrM %-[l35hS2@:qq4NYgRp"ks5*QGJ+)u1EBH4^1T[lG9N\2.e3T\]1ou=homcS[Z:C7SMQmFr8PJ4g3\het6i?HQTi %KsJR5GV/ehWOb-Ub<0JDOe%6asp:"ce;LL303hal[*Q5Gl[7@@1Y?(3?Cf+3W5'*sX_A-)DX\7pu`S:DU %654?W%'O)FdRa)b<7N:S&]G\/_t2Kp"G7"0S.)@hKo"`>"FPEuD[[/OD]tj"K4B.9@&eIHG_9LNUK%^3O5f[H*q5Fu+Ve"P\("QZ %.&?^R["PprpE".'*On!L]!G5J0$I`c$eb,,1Q09+[4?_KbcaIEk%A8?;Q?4jZHEgs_"/pgmdp6#?cuCcdeW=s2MBcJNP^%H[0+kk %;`N'@[`RW@X\Qgu-G/jt=p#H3i[rfVkNRfeM;B+uo?GL>P+K2Z;Jgq]*:8jTl^HM+>._:b;_C1'&motEs4JGF.k4ka>dG;1]F['7+"gTk1XP@J]@kdLDXIQZfEL;"r<_a_2)Dbas2N1M)gKFa*pXaQc %cEE2"1!TplkmqiK2F_EC%a?:Ni*98t/(^!!%S^>=2m?>I3\4O&f.Kl<"8oN"?/m^"j'jb>G'Pe6cNos$<11TeCbKn0f_P&G:!K5g %-lTH:p:DDieb\(5-2DHEf$,_;YH?f"XJU%0qN#E,mapV,2;hC-.UD8dEG+nGQgOp5Npj-=/EeCjE4!$Tep\W'+m;g?C'!,ekBV_5 %bp]Rk#4V>EZ>]bs_8)n%>>F%)@5)Zb9VD@mrI@O"`5VC&gP#mHH,<#q-RZeSZJNg;9u*Vl?=3\RA[#L$51m*mF[!JY25NUl=lTDQ %h]!g(Ff3s`P8J3U)$ptIH@e>I4$sRW+2W5N@u8X4r[!BLTPEB;'"b32D[\n$QF"VdD1@r-aY5Dk(2IA[W+$$84ZZbRrNI^"e;:R< %L\fG4.+ICs*Y>S+'jkHRX@0O`?=!`ap\fM#SfMq1ik@J,aQj%>pq#e#Bh:b!G*DnJn %59/:uSVJHGZ3SE%1l@d-?L'RgTi'T=:2_/nD#fG4Zc,Be)kqY`;&^O:>rH5&((VcA)]AbS^j&D)GP7CTm;?NZP3C/hfEWYs`[=Nn %1Y(\b>#)]I>_TG7*KZK??J8]b:(nf"mYp>o@`rJ0LdY)t_.aAU@!GFb#jd3+(>h)c %G;H#^i'c3&1UE9iUdi_&%)L)4%05+%aT"LLCj&Mmo3L5CkV_:T!fB1#Bf %Ali@+K2T;u>#mg!p-F7S5d/QVp&TOo(&C4CfE[X$>bE1GLODEGZ4""i!qq2]KrY<@LW2Nn3kc7*?m,0Za%1'njCe5jXL31Bt][pci+?e/8)@T2[Q+?m!%1E1GF00Wa/IMa83>r0*DmN.?>, %3m;8@mj(2d$Lse>+:Ru()l)Dg+nbrN98S,E*qhm.,7g4o5S0g2KgYKbp4>!fmCNqZ"+i4FQg;?+AR2q5d&-i#^i\)P#3#VEU:X)E\Q43GhmD3cMD98%+VCmm5B^CA>fnn108$HN9l:jVnZt-m]X&jc=/ZnCeGBRgK %#3>c&^k.Cf0ufhJ"L)9m8;s$-"'1QiLH9N&LAE.hi)#2h`0?'p/e7PfOVi'h:VOQh`89s0k6=Fc9K0sP%e[%sN0C(q66rGZ:%LnL]asSI85)1AEo]b"jsi3i?uI*C_/-'I($rg^1&%8e)ceEC8gL:4'5pjdhE2E,1Tm_0a:4.( %0MO(MRg0aAAgb^P)`861qr4_c%i^AAWe%#^m*-b0Y'77T8.8%o+[qI4f7$I7M#mLmK0qdE&d.SBh0crMg?8X+R4&n4C*]\G>r4ql %G^aT_jO:bF&,jRpYOo#6E[H(>h41d*\2tiu.N>Qk'[$!nMd;-Z/kf`Skjk4EamNU5sd*5`P %@a#_]Jl)b0@PHEF%iFu\7SL5QI>sULNngcL;rs'o1h-1]k %N5QFa`L,:bUUC6Cmq!L*YD8)]0t8l()r=7.M&DVU(+'ZHLi%R/JbG)A@'tF6-kb"8@RD=ooo.&@+u*4"d\dsr^dq.Km:)5Lb]_7k %>t(i@Rt1d&`)O1t!!R`?85)"-ZU&JBMfRCt$oD?;V@Acr6-(W@bs2A#@PEG5:G^@JOdLH_[3uc*??\Z;$/$tb:r0<6!\*b:M`>s"QfPCI?@[TC;Knk=t;8o_i\/,a,RSU(QS'/1.,g/ %/@BNtg3eQ54kbjDCmP(2Bj#P!kL,MsgU`Zrbk;4o$pk=)tu5m%2abl>#Bc*d""D!X'LZ+KR%S+FXH;CkND^H@:j+e"Yk&rfb6Y3AOD&'DO/l3+H49q(sqba %iZQGN=_[th0\BC6:G^@K6'ukUJhXnR)]XO1B2jm(KV<5:EF=G=WRh6[Mi!$>YC6nt[LF71+n+VS0Z&g$0_Ls:G(MEda2WZBDA6/+ %T&.S9'b(Yi@&NJ-0Z(YX0Ne!1(6%`"&Zb.]T"I8%q.l-9%%OSObs;.1@Dnnm\.1"Qeu_e6J=4M0_F=gJ:^5jnr>ZOdANl!b_MUJ9kX)#P7?s'K/_P@5(7qH$1!8MA12eD(hE-SQ4/3q %6Qq(PZXiEopK01.1uOZNR@a>]J$&1GaWK4]*IoCq[E'S)VKk3eE*C`5!7+TOj0'M*[)V&BG01h9a/2 %mb\U59I.X*PZj!`i//!/#T>$&6_&Wk8'irP)!!B'3eE*C`1X#P:e/kd^gmVc@Gd*<@=ZI3_NffaLrB'4]ZhWTUB$KTk@-Y4=[6@M %36D,laT;O-Jc.@\N/`A0E*rH,P6EdP9Ws"EqOUAi`.4FA@c*A@JB8-?Cs,;,5CY5W&X,]INa@5G1O!s@jeY)2ca)Bg(On*1Hrte0 %g70%e9;Z-OjApU-HaWFFK%7Sdr=0P37H0&D(i]6,5J(/>\TR.GEfaQ)Z@?A"s75Fa)S(7"Hf`Z/h<;mroJRX,Lr:RphE5&UAi4@2 %>R7CY7W!^epGVQL^`4N;AW^0:DLjgX!G7XG^@QM[G5'^G>X2e0KG8qq==0qQ^>2B]U.;n`9,LNk[/B*3/?-,Yp>t5.U45 %>"Kts&IZ/MjSof6h`LjXkOjc30C+DH\L\@pcMc&K="b%BGE/8s3L,ZcmBgj"-S7*tEW-e^4BB]f#]#G!E="BqE&@;Wr5 %d\eS_aT\'0($@e@YmuQu-e(!uod+*pDHjg.\0GD"Q][ue'@Xo/"S@CFj%JTg*=B;7 %8pk@InrGXZm(_[m33Y&Q+:cu^9;mmT"3^l=@5.gf"RLsQ=5hG)HjR,r=bLK"eB7`.a5[&UQRUQ0+&36i_;8PFoqcGZkK]*U1P[hg %:(nU_9mWH?G1GB[V`SAXVn-s6qYWpZAj9P1U#msW"ieoaqe5]iW4CZTQD9N.K,)(?TNUh%Gcgj54\H1X^G$(U!eu4hV51i%,k@UmosWY>GZION?H>_.hC#a8#JNBS+^3"V,RrSU3lOS)?+Y %d]gH+Xi0A'u(6&uiVqLYiR:G4u)dfl,0\XrlJJSS`;HSa;cIGNP,8mh`Ii^HZqIDEaFoBrf"oIJkQ%#G)olLZU'im!GeV5B9&.MSHlHnh*Q"dE9=@pYku-[gSNs"26N2$.Re=o?"R-^@W%knN0T_C[X*/f#Kbno?Dp>:XeU5;gI0O %U(ck@m7Z^jRUNZ4&Ua3@bp%\GpgAIGmD@%NamkENpL(2-04NQ/q46QT5PD.:]1]"o-93;gh:`%-l1VZJSHV%Rir"LNF#JO,X8h&5 %piuV2271M3I>3h@2a6.#8aT9>!LG$NBle:fA:&e"`f6fVlR+>OnR%h3)VbLqbFdkeYNrf]^\p"`P:+]((&?fAHQa;S08hLHb5&MN %n'?Eq?JU&2g!%n<`J)9(/7#E)8^_&88@\'`2Zh@5cNp/YK.Ensr^)?l^7"k5o3hN27Z7J1ddo)+qA7goaE):7Y,_.F?d,_5;u.N+ %FT]DWl=kf$m!NFVn+S)Y\u706Gh75Mq=?4[4JqHZ8UrqpfTY@hjE<@fHH*@fH!K\nSgpo9U9NJYr3eFo0G(o?T]C]QC&BMF"\RQ64DSIsQ,7an!9i]a[S( %.R)+rgYYTt<>02OJ!D&,VN&3+D==CfGs7bu%9Co4Xj&BBm\f3tX1>PYMt6W=f?F\QQ_3El=-5UO?SfC;OBNJDfXaU4hp#5cED^TJI*o("Ms)e/7moN;H0qZAPDKYp,qnncdn%UO2MraQuHPj*a@a4nbRaK#U %Oqce\K%B[.Tp1)Jn`Im"GnW %j?aHH^%M9bqX(3N4g90SnfjL)qEt#JM\i33#3@0`C\7A3j3O2:00]/H?-:'3Ao7(A\R%IGKE/L=N-cFE_(r[WlP+%$O7Akp_'/3i %/q7,prFUNWo!Ng_l1;p71%que"qhdZ%r.UVk*`u-p!r5l5d %^1M-k(VcQFif&S\(2SQVW+CCOh1-%(>9WQ'"3=:^pds`W@WfuBn%)6-h\l[)<#q"Wf:d`59)kCjS`0C %ZMaTb"14a5HJgtUGqT"Uft-hOdlF2^Jk17o,4Y!9qU).Mk@V#(f7,o9iSU!K3o;M_ml,$KfC,;9p^@epdnMM_\)oUJI\dgrUc_4? %;^cO+r8Rpf^=C-q^dpY=a&"A-?6:R1R@'`#R":=kc&11MH0.#BK$eq.X(O*#G4kNjoSVn#e(>eD+>'oo&dI41R %+-5TBn)2%`BP[.)cR9c?=*q=ZN9%(m\FXh.)ergQSG%3rroVIjmnk@Vn%aSR]_lJjrZHQ?aSG:"p=JcZrjZY;;gu7Tr`,QV/A+JK %r]T=7S*PiZIG7LuSgJAQ(&NrAp\rb'UOt)`\`ClthjDg^gR+DK?]hOSDRmC,_9&!/Jmr34oC!C0?\5&bqJG9ak=B9*e!s9a.(uDT,`:W#%kt.:`b'J55Ba3ij\4q %5CNO^h>?)j^LkD%o5=d3id]GTN0)^1)9;5>N7@:pbWLkJ,8SRH^Wk!:]s@@tGk:P(j3QVtmJZn=1J:8bG.[YH`o`\c1M5uX(qY0- %*hF^)$_uZV$YL5`*'E37RHVj5r9r>=^s1J[^e]/eU.tjk.!U:A5F?qmmD/r:hu]%A,g"uj,*&BWV&s0C;LW1XrU1W\dC^d\q1%@i %S++=^1SUZ97&VpAF%2e4IHKYWkfa9ZZj/CdP3JCX.S\2.bp8-D*NbSbKJ"JtSTU0U,nTWIjE&Y6s7duI6SWue>@]=eIlm0]F'4>F(,ilm\T?QVKrrq>;4lr\qUm2^Vfna467rs-;3R/G+Ej6sb^\"kS$biEF!(X>-i3qF1@ %rgt'3i=@_96,_emB:jSk3V+'%ZTHCFc#m!t7r`DL*2mf5^R\4GPJn!S>73Pg-cK5']Zt#Y.(_XIaAaNfYjZChF;uYc@[@bqT!6DO %`,TuoA:J!r,11YErq&\E7!6p7MU0@7aA*`t3;;!uE)>?0ilkWuHL[fq?$HG[HWM]-:dWeTQZ(+WC.>EUT+CSp0h; %4=>7;\Q$ATAAGb@?cXL6eTkZn>^uV9P%c+j5GdY(a@+U9Kp;@X,tZmS3Ym\.Ff<++OuQ0eb%L3Bm0jFgZIEqr"+FfEdguK&:)[q, %X@'cVXj.Q,7q_JYP)rok)udC9e!\4<`"SN6H'0WQ+d-duU(.I'7$ef5W-]O&K7">XW]Q&.jVa3!+AZKALGP-5XHPbZe1RYNQIJco %U"UC^<&VY_7OsjOsCI-t@6^O8.!^V7GU*it;*hiIMN %kQ:be.cl,t8)9rLVanlB>1jTRq`#8O5ugEC.P;fBUH7IpQ(9`JELg:Wd%*2\o2;fhE?]EddS#QG/Vg\4M)I6sQ5WEOfJJ2h`GLm& %K[g,m^EfB@T#1)LQB[#f,Z4Y$Q]*`lP]6E5BIP#:59W3IJrPf^3jkJ#pm-rL#6gTRdnV58*m\)7Eg`cBAlR1Z7ZfB>s.-[TBIcjQ %m&A.c_.$EV-cj^a96.TkHU9ob4Z=J]QjLlS"IFp,g9$.>2460@qAG.[2c'k6TSO'pP7o]LW/a:"iUVrM,QaIO:E,ElA/B %ATL0"]+kuq-kd8c$)UC-DuJHOb#r>*'i+$ErGU5E"h %s+LN3TEGruPb@$/eTU/p0`9F@Jjako(d>:7;*9b@[T4,I"Th?97Ia?)FT;Ms)eTU=n?ZCtRm %"T?)VM6e]rRO?=jU/B;0f@K@[^uV.TSpKh?d@f`FcYN*g%3lQCHF&n,9KN!,abm.=`(p5)lHR^=4B_$K#m( %P&-l[L\Y?(,Yb0u1,8VQh*dIO$\-1[4uoQ-Y[qgSg"65TVW]MC3?0S-l[+,KiD43Eju^Q6j$6&-d=q-1ETa&b:_a( %/tY??'[0uqiD&6QlI99tr`aI^`30<3/,nTNM(FCjM/m6iJ4Bt!"(^q:*51Z;?cOAdY8coHNGY6f%_2AG<02;9br$6ETQq.;4po'`ae1RYnY+NdkW-/A0Q-JgQHlQ&&k\,uRTnUsJGp'IY'f?3hT&c"o %8YpEa6;'bPUIB7(/SqVrf>%T.opPW3XcGQm1g`TEPYUi0t[WW#(9W %)cht(POB$W#2()p^u2"J-/ThdQc-9RUloE7X45rJcO?_`6_4geSK3SFqDi*R$Y%U.3s9p<((G\jI##pO:p]4E'^MOsF3!\YH"K%d %*D2)7q"XeTIluOiFqggjW#4);'dSkhYrPQ8_5LXpM?u+AC=IBT]#1*QX1Zn/+cm"jY18I'-Nej)W2JC#4!eC0GYjFWsX %LIKa(/qM4IeN-RH1P0pB)eFaQpf"%,Tt'MI_dg"./.*\tUm!&jQl&bn,oCo*0X;pe-tUn,hF`#BS+L3^hBMG$hh9,bf>SZ0LTMc:DJ0YUo<*JV]AYjn=JtQfkCB?I.Y?+GB1&IYm*"mR[C58T8o`= %A`\M1pIq#ia]U\M1)XIQpCbN3%/DmVq"WVIeO59s1Vo`;9KRO$`UjE?GbhF91SGiR!*$0Z@!QBd'BF9].-eTlO4.-k,sMC$^]`2V*`lcNI/m-5>UKa %0jFmNBOa?LG9dJk/g`7Y-PL(ac;]T+HmDi.&kN5h035&&,cZu-7.a_H<<=Aa3-QWh=$UFm0qruL(?@h?3G8-\NfJ4cO2hL3LCPaR %FDr0C)BQ8U6oq,8dRg3)3mn&X_kcT>Z8ur7#bA@*.&od:XTVd:,P`M6LZR3#0oIM)n4u=X!!sb#Mp5Mm>IOGKDV( %O.F5s;b;NYG7r#QG.eP_W7C1u3\_'paBMg4/-5'aLnWn2:#OccakkS>:9-n,`f,,! %GasHPd>E:756R9RaW.]XTLPJC':(pE[d0JmWg6_;q?n3f<+KA!dN"nc@E@G-1?p$\<_*"no5#/XR?gFM=d5:5@ifcW`r()Qpl^Xu %)[`I-Y*"UBV^icl.@Iu@kg\E0pnCJ;4l;ff(jpBepHs?_bDT7mrY1Y:r\9QEGu^0@c]L_*`5SIZ)O;<@3H/l,`9q\[$qD0?0RF:! %%K7?]42Q'3^QX$Sr%T[1pntp,%?:UAMDtgZ"&H;q(mZ*>3BVLRB!!"1d/%/(gF*jg`T&qZ9]Df0bPef%ALIF %O`GZ%8o*uSG'D"`_l<'#P@X=-4S,3I7k1Kd6&Z^mK+&:oH%aiTRCd"Hh4Q#d.1+ke+O:Io\j.1'e+,N4/Vb(E06@'(\*q_HOY[VCJ[$ki,b-"L+!6?quhZ>0;c0Zh$Es];H=nZ;8P3Zf_gdq2gQThjS(>ZjK7" %dB4+(^9!^KM".!-jWq8hU6Q#NE\DE;0qgc,DeifK7pm!t3ZoaqEj3S?':5.'.?T5t=f,\2.08e1FQP>-_8f_.iL/X]e)H,6`D*_C %Y\0Vb.T]/3%Ek#2;iM5LP),BDK`o6pkJBrOj$Tr-n6A1P1.%aW?6tGMA;#sUfnj:;>*0D5G/j4N4ZV+IT$W"(g^?63FR]j@MO([?pARZ7*t-63;C\>ZBZ:+lSB^KS48udkiB) %/[<\a6KX\.=%_[%/ffPm+sl`@UdPTO9*p7Vc>t:;0u:k51#\O.Wl,#aMe`l9Y*b;i#*VTeP=!N+kDZ%hdh*8e$2J9.gd/otB^NPQ %HqD3`r?m^?fNgC4\Plq3$/iAV0k*Nt&FALbin..rl^d]]>/25;F7S"emkTj%3=%H`5L!"N"$4/WA$45#];^E[p4]B=;R>od*f7Iiig(=s@G),J>HTFL14s;#mSpRu/.(u.< %Smi',=m1W"^bXeC:W)h)J"U;JsAgBc.t#?K!li[+f182,]9"!2oFm/6c6g)JT_=rh'(s`B/+HP__SA_F3Ll;hH5.NK3usL%7GQd,?o5(bRHJ]RN%h)VTR]8'UTQ&c6tJ-;?;*JLt\i^A@$=Z %K&+m12s_4KdHnD62)fUahjZO'O\?HFC(O74_RGR$[>lLj2c6`g6'XDum4smD]b?ng/8^SMc-qFnrUFBgu %)KfNeo"`$b/G_mn\-`X-906^%.a:B7$j[nKUY5iHRHgMn)Ef@g75cd;%ar:?4Vs`bJfG:32,1BI3N)rIdGS(ni5ZFY_BK%FTM4<0 %8Nl/UKh#%6e=(RP$5]7Z\O@Dh;lY.k8`GtoNBh&2MN)P/Bi:$)Oub?Y4K,aNpjSXNHud(E/W&Gn@ll]9rh2j<\YIGEM_D_QnSk`h %ee4OY'*BG5:?orV]edCc^XqDCNX^j)TbRBChZm.dQQ&/[&K:c>2^^Z[OBS#V;h%h5W!Z#`OV.drd.ZO!IRi9\9'7pTTU_O>a %N`EuoUMqY$fK^r+4BJ/LCe3;TkRm=N*GMOrQuE%h#5BTTWD8@j^dh;-6*.B/!HC5TTI.cS33]Y]3-]&&-K-'YQPpnpG/T#h0XjZo %8Ls@_c-D\?^F/4@jV-eEBM7_;,>P8V-BjJ:VS9Gn-9*l92$*F %/:iKc=L_gB$'7ACiYoXlap"r=_+u(U%&]k71kES!Jf^;XRh`h[^f,J&C]0d7*2Y)U'*=W0Jf(GRBb*(sBc8^WN3&]M#6Lk@aO30pQ&h2Wbh6^](b]md!BY`<4G#j03:Cr'1C0Y>_fQ]9P=c=c>]t4Re`#`L\f;T'bCK,?.qQOH+2s5?Sm)#fbX_J,Zb=t&U)ROJC- %5[(;r6lFUD@ecnnlA-'K9A980^!EWg2B+),d[V@>hm/#,pSOuC.oW0!a+MC#?qUf^mtg#OHn-s,=>^ %(EWmMjht7CBgMe#cJEMT\Mne(7(!3EJOu5:.GGd9oV+[bMi\WS"=K*`hoGBO*fN@Y1'!fGNA/8X6p;C51u)lP0KH)Mf[+m#Y$M6Hl+H@U$dLe$DOg:I0h'Ns+>bKN"0t&ag^nZ$_Tp %1Rod!BfnN>G3g=T>U0T6R..OX^\.ppgko>mC6qj*"["\*aNi_AZ5Eu`;?9SAM.BL,]>M[!iXQ\\L7^_b8/Mc75k*pAhaF;YEN7Qk %KE;/WL9p5>%BOXHh$!*><`t9-Ik^n3L>s-(NNbT$Ed^4\*aIUE@ftjE0QA(JT1WRZ'/cq6K!L_KmNpT1pW;gP3,u9l$ZjP]#1U`k %W;\>9Fe95IUQdH_q$__PSY9I9B"OTPA.KMe?2'8"g2hR8RW:T_!@JXCqJia1W)b6L)skY+-CB:JU;]`R>X"IH7J"/]/S>@MabB=0 %PpX7JP[a_2rdU6Gk9Z7iN]fVbnVOIi6D2aL0lp'dP\L_@K^hp+`%EFS3C5)&^')():ULiU1]jm$SfHAc2fO#oY2Q(1&R8TSK@(g_ %5fDWu`RGlq1'5iP$R-ItT8f["T]T2Dbn0)8S2B;c@nAZ,f.m.7h>[gf2H%KUk^_A2cn);t>u&pIg<&p(S<@Uk5F'Kt5P*@dgQ&p> %A+4l:K8q97`2V-F1(TAJV8+ucoDrI,EeKb8H9\g6OmWb+,monC(kW,Gi!m'qVNN7H85_9nnrS'S9pbqK(`<^Im[1iHdIF*llP2ac %J9Sq.(W%A2e/Pchnr+R\FkD:TUK(&-DQk&]a%^WdUSqq[i#;b+!WA95;'_)&hCs`6-W.7.Uk:poFMe4qU)9Gc$H*,7W=F/CWJRqo %j%[s29bYnNn7T6S(k\!GTYYN5(Y(aC(;S,S<6:>V)G6X)JA4sS.bkIJ.'>#$BdDYK&lT%$-3]]g68LM/\u*sc(m?*W(b.6]::qeW %D5CrDOX7qCaEPSk>TeD,#5?Q1S.]e]"HtU&hZ-GKn6#t-UXb&hO!Yl+_ELeqq(0;Yqmh2&L#r13m/'@uYLCFAXP[Xh]+@ %NVuqED\rp6+WsV\Crfj5@XP=.FcH;OlA5&JL4"o.0d#Op) %DX2fAR\XPjI1P"1;L9n7VGgC9%+2th/#Z+8/#O[qCZJoD"LZ&O!J:54N;^>E>!]$m7D%+m^pi][6Og>3tl=h*NBQ1tY%F4?J$&fZ;9\t@%XDp]El-qGJPKU+q>RE!nOlGVQ0s2J/)al3EFQ42h3cWQ7*Q;CB.j/i.Th)"uh&iL;#F:CBcJA&Lp(be=SFF\ZfPEgr_^uadE^I %/=R#/0=ARjCY="i[:i6MX\sD[DK[3RGNN^Jah3fCEWUu.o/X%,_Qd:LH*"8K"?#!:S&ZLB5q4'go*BIX'qWt&C`X %AE-f%cK@'T`]UF"3L'f&.l%H"BK!$tS^"O]k$ur(`j6SRc"fp)_Vuntc,7#U(S91(CgLWKF5pD7>X"8s*ZCWnCT0C`ENF15%i,XK %U"`uHE&9l4dB^dS;e_n!>@@%@$bd"p.V&'a@KQ:RL<]TQFt]?Q_pTK;lr1dbAVLcDFL\hEO"fnR`7I@4H3r@bPN9/bqRj[c7.T%: %BCruW&;)U=l157_o]^u;cKIQ20:MPp$9a[W$];-C=6P2?^amKp64]AU9^]gfqE/`-P`kDnUIWXpV#$`"oQffb7;[T9USl[p`h=2T %T>u?A6jf:0@j,H!4M%6:GtE.iREOe?g`*Nl>LDX(4"&rOcKO6N_Io%1>1bdHJoTo0%tX6cY-manM/)+bNq22tblI %24p?o\6"hNoXTs4B6Hm22\sQAHcSNVI(RS#Pp<4j`%aV^;<[F\_M?JS0U0Q-`eLeoiX?6,@H5Qubcst[K'DB=ESsA'4;Wn-\4V72 %9`M;l6tZ6^OfZ[!5Gko?P$iCL*q0Gs:9j.%=Yu$:=X&q"f^&K8*Wc*n_2/$TUFgU^::D]2]iY4t'F=;H5VbRitmRgAMVd9L$sq['%.$0Wc],O`$49GK2R=,F1aO_cmdN7>!l1br@@]&!bm %r%b=GbH+lLk,cWQGG=4kQB][<(,`R2H.^n._`oVgc39,cRr]``j5uZM,NO"P5P7u*M.3^LKVHmS<_9+7N\_bGkY`VR:+T/J>=o%e %=B'\Q0.#%K;+r-H?:bjK*Y]d]d$7"<_n67@o2;;"*=`3T)n_C@oFELF`c*@[-&U*L@Ud]898VS]W85(>7#5__7%cm`''U5R@haLV %Psd>nB::Zed$7"ke]1Xkg5S_3^K*sM*SC>U);aG]JtD:P/pMZ %/M$!rJ7[i.b*f]/_,"pIP0!5KrWfW0.aI87LMU_)9Qtq@PGl^)@mr.ol>XYHo&"Cjd6eo&WT.d=4'@$<*2PUAph,Sg%X,Vi:+H='=<2;)9RZ'BE4Y'D_JpROc%@(pi+8)5Y@-p<=U8#WH]njt^9[`ea>#g^]JpPM;ZE,_^C6k\"aHW=>B?2=M %!>A89e3GZ2AQdm,]VfGuJOV')HV^WhJ`=:Pb7g6c2$D1I0Q]lLjA_P!#*fa51-D'V_K()TT)g+q$X%5Ddo4VD-sP1$Ounre+Zg"a %09/uQ%V7i#hWq)9RN[U:ren/Db>.W,"6uk+I+ah,^"2n'5BTYU(EKg1+fc!)[Lg[,DulDZaT;YY&7Gi*MbUt>sje9;+@b[=L;5q31bbbVO`r3tUO8MdaN1=n5_mp%\#%.BQTZQ/ZQ0f-@M %#2>f//&__s;.e6l*7mjk.Pp`<#k",&KE>bL %B!,bn"^N9-KdOW!1Ds4*B2Qo0K<6,&;eZm"1R$dANaY/m1BSC+]Xdr-NgV`E"=c!.22*jd+&W[[k61D94NmGo6R6P@MW( %O@S/_Cg&gd;(nfg0uG7dMs`Amc(b)?IbQhGQcWS!BiMTF8^11CRA:=a&o/dN98R533d=85-)c)Y//-OL1LdJZjr(Et:^>=&[=Xi[ %`%jV!4=/QNC7Z'],^&U@==^@r8h?1U_,FgFUuj,2<`4]JM7&M8Vo1>^*BYX68SXP(CF+,uPZT93=\`cZWW,L]//)'CPr"!3=?.1M %Q>(D[kG:pZksGYNPfIbQat&0!.?7pXC`_>a,\cOE11OC-.G6("tKM7nG-&#B:;=JaGM6ocW&.;.qRN9%\lh8ONC3N.D/!Ni''_3 %_lUY`&N2pl6_Du7Or4"8(k%Rdk2pOEo9q_u`\+%,E.s+IhDdKi:Le+/1(L4[k&hs.Ji!6[#"BZcCRO.WR*R$?UJDQN8PR&YfB4B_ %eP&PJE(42X13M.C#Y[**#n>5D;uFoM*#Vi@KdoF!In$(!e_D+TB)63:5)Z'ScPnOXnD(J7H#lILMR01&DZ:R")bZ$nqoD[0pm,"7 %:L%(MLh!;Mq>)"(Q4apnP5%6?=^u6b;PMh'%'4Nn[-B'*/8m9k0`"tK5).@QJ@?t\.ncjM.49[FC-j1*^uK[nfYgYPBk,'$g(XeL %$r`>LJ?lqfND0gZ\u1Ms,P$RHp3JrGbT$jF]K3FACr;b%1i6`4$at:!)dDmPgXt/`]T%n`L4<*]6S(#h)]La_Si/Kcb.AYG)>r"5 %aDlb-H.poh,&XNBNKg"m2R,g,CL\TcVi;/@Z+W%R;Y@K'M+--))]Pb=D/A-jXgPErb1"?W(0Q!$Co$K9@fnZ+YDnOkSi/J]/8\U. %Cp8Z/Vi=E0]g1=e@mc7=lYUHI)7A)97OF]b2K6]$g;ZT3:E(649:e%"N9W*6j_JAdR5_(@ja.jEK+g5Yk95o!&)#I\RVigH/lA_o %bpBbTK,sc)],YdXm%p:?NWYKpbU:OYFmq:I<`3.g-l:CLgXoUoc!6uJ:^:oK;[I4$&`nU*GT.SPW0p;C$gQYeCojFE/l=7#K=A+b %,W51LE_.:aNK'4QbU(CXFm(_A<`1`?.$rH"gXn2OD1/-P;MT1#_^)Y_M)%[$8(uTL@DuApk%S>cLdB%fQ*61,BAR?ZIDNduA`XK` %o2<@N(l5'YN'7DW@#tXGUR0UQV5sn3biaQ58WgNnCiI;I<;X&=k;1N-<=RarjA"0-,WqiWe!QNV-H>6U)+R)3i:m?a#A0(Ji#Q6C %iF`6](nT.<8HEPE3B\@I:(k#;mhi)24r37WZ2si(*CWeX_&5CFou/XsXYE9uF_4m./MMJShmlE0F+c@G=;DY3i>FdfcUX,!nbF#( %O3[_9N,Kf'h92YlEV.XYp*ntl0NXYSan9p=_TF!c"R#@XoAg1NKIc\^5>sD\#gMQ:-H_`'),-[CoGIa.&tI8Ub`ahW1:TX]]XI%R %'qESX9U%&rA2&]Y:7F(714o+C!GeY@UVp$n@4h)F8OdAW0/-8+BTg1gHA1JPU5b]))#Jqs#,?ieoGSml81+_Hd:8nUQFf`3E'm$* %b1]BiL-)8D/?#MXCJaK5W;K0(W %C-ft\[>-_RP!]kr04h2o077V=?V7adK5k8X#W&mrB7Vs#qA@&(ZYFeP<7F91AXF5fG)[pNPeC$["#`M$L8#sua_#4"BDNF:Ot?/^OP97.7/oGti]ek*jB_4aWE7t%);;Y2KY#%NM8bZVb=e4_U^+fF>!TIQhu<$\akO^G:K8/P9IA>s!`ULI#XhVP1H %B/apE%gZoGpK.-.>MWZ^B7BBH35eAuU':9n#rF:JGTP"eM)1D&r.FrTL#%ZI7$H&X92_i),N^>f.RlQLb"^t*QjjA##Xg2Y$qo<$ %\/J!N9Lc$&$+.PrcdChtF-gKV?!M3&'Z"o=9MNhuF),'9.Z&m]j$REumZ-@H=NoFhf'`io9L\U"8DA1TEKFDUP94`\:l0 %1"[j2V3Arc)n<9#lMHa0=flLJ(e\4/K$hgiN,3KA.=5q`^(epMD`^Tn_c4EX;b7O&3 %bNEh6PRJ&(\@9Wn1!G@VApCH/`W)EVH:i0Gh_ %Xg(Q^NT@9FcIhaBe$h3#61D!be7rbM>I5neYslAaQA`#!'t:MR_eqe]k?V2*R %#F;HOmgH$nqdPD*?gNHrC0*OFfp@RDnr`WOm#:V(T"]WPGQZh>LKNn9`=^dDQQ4E+Q\p:_JP!8.e\4#MEaKZg>"(>X[Fu?_FS;P? %M!i@T?0mOCQ_(4*naJp6<>%[38fhnd?Fa0R1ZQsO!#8Y0/GTgLB3 %1T%(nOB/?3B6O2j\nj4j(72gpkd]JrW1"m>l`C`&Pl<\OKU#YeT'Mj06-1==cXgo]F(?gDaks@jZ1kr0MJ9Ref%D!3XnJWTZ@'V!.I1kG.2;Tn;L%c7Yr'0PS6BfiSZuAf9$B>#;i+X@P.tHdA'\pd %hptaNa4VA#XgY)>Zu!]S60i>],o?BmUftiSCD`%JNC,95P0I)\GU7'pXf3SJ44:iP3FgBN:Y"#i-u(n"\r`XeejXjK;;7oDK;W#5 %">N>@GD_t,rE1BrrCJOUTuqQ=fRKCe21ZMD7hO6;/8`BbT`K^H"Pb9!*'[,&`#]cXG.N4nOI-(t63:BtQ()0G^iFrM)"*E(M9%+l %bZt4D^a#50:Os5deD;b7*Ml&IOePD#_]-J;-,!`a4"7$6"MA)HeD<`iNOhkDPXT@#/F&#m-Lb\"/s:m#.YTRM?b0ZN1cl7_*Z4`B %J@:kEWsKXY%G^0-n/R\>+@*(VBcJ`qd>,XaFAcZ%iKm(QPJp*K>q.@>QW*DcA6@C:jYQ\2CkgdlV6PP*0Pj6!obBNf:afM"$**1qjpkCu`j-g>u9O-e6>B-L_Z$ohEe76ol;@V9*PKFQmO`.)9SNAL-YEa!QKS %(+o\4!c*]eKIM/V:2)T<=CBc(C?j;XL49j4$J=t&.Ma+5?k/T&FE0Y(+_AGe]+,SJ1C:Jm/O21EQY1/%B7Z.A4eZ(-[*,9a* %qFTYlYSWs:QYb/YLeY`Fj(4^dhqe2p(h0=m1fOOgNYbc`A?q19c\4MM^ZRFXW)1<&4j/ %*E5k#Peo^5ZjR4l.?/heTEauN9*E4/$+,`f%Q2Z:%KlR=nZ8#*.7,nUfS3)maAmnfNdKh:+)Bu7auZOT=$^hdZ1btuX3T?iY52c*-co@'`CZ3)c/`U\ac>SIX,Ld^.%A"Fm$4V3-J7t3k9uFJ9r,?fED=#SC_B.X %XeG>GS?E7eQl6r!\0IM=6lD^\jp">7Fui?/3#!\'j$V=)IffFUML9R\VuVHP%dl`234.5H?a%8=h7T9_L2']nBhc/F9bkk0Wk,"`G!WYV-V.i+CH %MD/jtIU?sAX\a3ePTp#@;'A>($+qFT'[`WV:In\AgOu>+1nSg,6sLqg4(?')\O,6pCa;L3k"mpdQT2.-PRVgf2#4(?6!nPB,:Vl`OUs%=f1+b0Xc;D0i?)VUagBYh;A_deZ&q#2aZ2G6Qe5dm.7>gIM\EF\u6lQ&VRn.3LJ`95#89iOWWT`DYA[$A7tSdqK>0,:T-;Od*joD'XfiF$V-GE"`No %9kg#8'1idT;.6__[ZN6K/i"3#[?2.)(F?q/s+IhC,W[^hMl!_A'I">BQ/lf78=2j]$VK0TCa=^,Ht4doi&25%.C-0[.N:r&E`$"B %/>6o+@e=39=;+7LE)@T$=W8]NN)@?bHqS6".9oK,amgIXOUT,B8PMqke';N!:08t^$$HM;22mq[*5(>hbbRiP1,Fd/;eG02.Ea7d %.o:Z4EQt;$1rPq31Uc!\LG'N$PO(==16WEHM"R-,T[gM`-HXbI-DA:9`F]_aD5N1/$SsRFope.(X/.Ua&g(o6,gQnJ@OC=Z;-7DS %:'+_)P=:jaaR(6GjX-+\_+u(5RP`g5e)W%OKSV"_P^pGhYZE6^P@?'V2V;*T:9l+HQ.0mJ5KZID3Ts48k'@:J(1=tB\fO15AR^\E %i2?:;8aln7qPeMen6o;:9EM'''2*q[Atp7:'[.it%LUNA2j4e/NY&$j0U"=AfL69)1QrMD7hO,u"?2N0dHel4P),NoUs^_;4h-o5 %eUGLqcHRUc204%lRL/A-h8_2-BW.Zgk]&jjuZ*NM(l %,b7=,G!@pJ1b>IoE)FNB8/a^5X]*h@17_TZdY#])YC%rNq)9Y6R,8kBgepM1dA*^cS-7kDi"?V7.)T5+._fJOI_a^r[ %O;gblSoQ'48QfX90mW&\Nh(1QWEu(<9H'V9DA"a^/K-F/fKp"RP7Tu<8rNgim3GZs8Y$6--g;UX.BW55@jo;WK27#XI>`j."E9!d %Vj:V=-.]`j"@5kZP/.G]=F)HHUN]!i9f-Sf?'4!i&CFm5o78>m)GsO/R).p?r]-qZ:>UjX+B %A'\pdNC0c?L/G":A2@7:NqZ!S=Ee]Q.gCD[nlIATm!7utg>Nr_jBKO#e^djJBNNu07_UgIO0Of^ %^U&:)BP_T,C9`q<`bNIEBB4DL3?oKbhm&]VkImd3D_-\%Hc)f4hH8':=57gc^,M@=Z&od9Z[9T'Ci:;.Z'&qCC;hc;jEkAsUGL?4 %@l\&FHV`2K[)*[qQL'N#\ssA33C4Q:cA2pA,W8B'S?X7uS<4=5q&N0XH:W-jLG>e;iGh87`gJM8/YX(lXCr)Rj>oMr5#PB2 %=`03dWj[XZX+b't+!gjhTkP6.b9Z8KLaYcALaq\`6e0g"8Vkhb+Jd&u:/D"u %4B$@['bS+\`=&;E7`n-fb+T[45S1-%n+tu3K2#Tm_gRuuiu9S'lemZT>=<71Gh`B*[T.HBp(,-,EpWh!7\6cE%E7)QU/).k,O,,kH2a9fUGU6)RZ*o*u2SOYW5KO %@L.J#\5lJ(O\':I>#MsB2$`*)e#DFbpo/E@>71aE6:Cdmb=dj8C3`BN$^kUpE(4mu+5Hp,^uK+#,)cQ:JqtJ&>licP.B2a\^`lDB %EB/C(V:le*K$HcU>e89a7`1mXdNl#5d.m"$A1iOd%OtSi@=#0]/Xq%l(W;D811ag)j=ho+M7b*4H,cf3PlGaWlJAMQsCnZc-[ %q.?!0Z"N[8R+Po:?;,#e.Mm&I#![68Z'Pk(a;d-KM[M\;Z,ME'23Ng/Su_lg!mcT^RD<<@;'rG*Q&.CWK:gjBn5sQD(L`9f#X"TG %`CD^6+8lF#[LrXQd0RVt:KD(D$-MF3R*_:XOSMhR=Wsuq'!]i;q&kk@X:RtY#*qa?6.;a-Bm0Vk5;*rs;SlI$.:NW@fF4nWJ9OE* %=%j3Yn#[7=SX0Xe(fN@4*FYd`d"JM\dY)h:)_8)4fIGW,Tp$bcWhN?9O^DeKfV7s#B5iYT7gst9'-.q4]RO0*r %2If,s9$jB9V!(,M5K,sU=^+d5JNg`JBpBGjCJ3b8&'eb&+@$7W.8NW7mts)8%MaHVVMT$lqe=c4;q=u9H"*/PT#O''&WS68M5a0j %FCl:'PI:nPP*0cp6[&@pQaW_7Q.BIL2Na?e8E@(n;Roc21\dqmL3hS)kpBRgRtHVbCG@dmdomPm%!nm_gDkM^<-f+F6Y,j.Pr=U3 %Q;(qM%T[Zag?>cO<8?]A\Q%r6*DN%d*mF@]&sQRQHjs;EQ\anU^fgr\,JrZ3coJsfK,oZBKm5s]<+:\"]Ki\_ %bU*jF6aT-6.lNM:MjnT$"4,R%VOPJM#=P8P0kO`!N$o&"Y*(:;!/r6?jp&^D0g)PTks,m!=s>>5i>C]8hgp`/A9sEU*OUI*$$aK- %O]q:.+B+L/`tXYfYnn&.:k4E@KbN(jntaM#`.$L=9d/:G2VFK"OWHjSPqiOe/N'(1>p-;u%C7h1)Y&qh^cZXo0t!PJLEO5h6':1J %$%@P.=t!>C&Fb]KL:j0+f]IAH&/fnQ!l9+Ma=f9cp+*ME;46nS2hYg7:spScMTE)BHF$*BOr,WCZ\6UPQm-3]($CC9V(K+@:j(Uq %AX$SbfF35/SKSCc4E*!UcTn\)TFuHc^q)h_AoYbg?&+=4B42XIBn<#(R'jRN5d2KPr!8F\!45XJ]2qLe(gC`FXWB %6BrG/"]/c]^RGK2fR[@N0YF5/n;_O&f/l9JLKC6(DA%FV4[85gfQIA3Ua&?nW1@Hj4@#+Bgb>6?^jiGjju4Z@1qOD.]fV@L'L02E %5`JC+*P:OL),>T1MAIDuM;8P/D07Y'plS(qXN*Ga=><;%6*S_218&9:TEc_SC/e^N.cWY[6S0W%YZt\,+al+MBN10M@g<()>9;:\ %"[ai\:Q,I-PUd%f/;[p=E`l8OS;Q,Vn7GriJX=H\+1"=(0j31]6b:TF'&CUOMuK_^G.!B3?/2eAL.=.UbT_q"8le_tN2D`+,R(kA %7Z.q4:6AE7@<4]!asl,(\GV2?eaTi:"_T/cj-a=Z@W!%u$<&gM6M%u,o;8epE%e1r:.<3Q$<@@/m0nFnS"W^'c'KA'IS!m/*-7fF %J`(JeRjK%YpnX>u$ipKo._M5_3DFSin0to-r.7P(p?W1kiNIs<;p>H]:2Ke[e1?O#0V*l8;jiN^'H>`$'[nM1?&+uA"`pJKTPT'[pZEOMXRUqRjc[&#gY %S$8I2&tD^44&k'fj/6YH;,WtP^f$E(&-QeR5Ln'+Ulnpd0BC^Oia&h>_>_o'A58+iLQ[OmVD)#U>_7MG(]6a50ni*%2+A@X$)8P^ %.\4>5@_upc7d[+O@lHP1Kke!a"L]/)1P?f+8rX-Q,\c%*$-KEF"q"."@*-9sR!$:?lQi>b/5S($7gVGZX<8dl2p:c\iVS?Oi54GRp4Ff]\:pdV2_n<"'OGAFSFl7"IREpV2C'5/u7 %O@H&GVkF$eRW+`g@[@Z]a+GLg]BjPkO^6hbU5OZt3pc+;3`-:W;%R(Q*N^<8->;otd4rh&C_64KlT>d!H9,>KdC5f&_:;F]H0&$9MmA.u;mEu5,t1Aj_'hl`J;(U&cr %B/_<7ZPs5]T_ZV'_L%+*nj^e$BSL8S4buR!dN2WGB1jJRns^W#ChZM9pj=57+RF7*&m6".?!ctAAQh_&=lI\_9p@,/F9!nR"9!f:Olr.a\?):!5.+b"n$B:63j(C.bJbK/GktUr:Cq@\*Zo*BaKSi"1QE'J:BM@1\N8j[[552l9V0po^MK#Hs(P&^pDb!N@:0rJ1Y %Ra9oip?:$>!IYCg.as\DQ0ZUk`[)>!1YPaIe?7iZ)BkW2G0LeaWRkqoR"F[@=/APO>Mu9:WFC3[1m@1VW`:(/099,=q==/mfb.L# %'sIsEcR+bu&]f*P'Q#:a/8B=JT3K">@JHq!LN`m2/\LI*@32KfR+dn %gK3X,&\F"Co]k^V+,sPgVP['d7Cf?Gg@dh"Sm;r16Hq.W'$"(Z#NkeVXCV&Ni3o=h9*I)84B.]o?`;Vm%7,ap[5kBHCc51W$?kmg %;kdW7Kr#A!3L+0P?7/j.&kb^\18;pc;N8,OH\q+[B''"XQ!n#4h"\3%_4/JY=J[u5\Lq$a=X.O1M@F)o>U\0NTITV)cdi%@[2LRN %dlc2.26YN0;q6FP75/2;'>`l\hqh]--/-Pc]G*rN7hU!]&LWk\:f^2W(tQod<]!"G8b8W)(O&fZkhSZR[EfDja<&qm]j\g2JE27'I>2on&7o'h[bY&'jM>JY:FdY,mMJoRKE(H7KWO"\a-I9kdVmg %mGl6R02eW*/*&QCZ52J<'kV8jX9uXe%5gi1gI)W$rZ8_n;qdXG%Z$ %.nD)0?-i3D,YJ-Tnss#!So^Ek65D[B\L:C"8nutO,5s'$mrb0=r)>aF@1F,&Um*^?nrb5Q>$ceI#faYl@$R*@g/@b1-75aj^ZcHk %E:P:X*Y*+fCKj_8h5uNt:0N&/HkX.l4$t5/HQ:h[T!XrmcBlRPZgi_tWP7M)6:JD^VJHE)KFuHW$p^]0N#E$f>O/6']JJo05V7N6 %A4jTig#L7imfj&["qd7Hk\a'23-&;Wf'qOjau"-i2;Sc?K7+bU#+:X$0>qPYiJR=UX=kH)UL$I)NU\]hqT'VOj/o3U:g'07^!t-u;K7F7E9)bt+Tn+TN^-\Z;Id%W*k:[g= %\i:oK^/T`CONX5_0L:JWWIqPHCK`BFE$N=PdP&UuPnlP;!J)LgW6'G]"$NmH(0K^ZNXI/A?jrI#2GO%)(qnr3UPJS:4qFi?85%hh %-8f57Q:6YO\;gEBbfOA*aZltUU,+`(Jmg'[foum/>H?ViKgub5?MMH`K-*GjTg/nC'0d)++daJX:W+3Fm)jc&TfJ:npRG0:%n'-/ %hM1_88#iH6P%o+VeqQ<5024Z#0mHW:-#+9.aE_&Y)10p/'9io!sue3g'XRil,"Aa?i]t$W=k^Po;irXZ=%c %e"7a,W]dJa39k_<,J8i9,KYNlcthpRE_'rT$3hgeNZirC7%_^<(SrQHF!SNe9%[SflS\?flTfZMX+4NF7aahPfmmSUsNP] %<;^RDUsKdP9?"Jc[>ph2AIPbfo!3YS<,@/Qc]]05/nLP=nDn0RCoQ>4M'jrk[Zk3`j:[IGjjU&X5:k/6S!ks@gs'`CQc7E"bVZZ% %Z)X]p)>gR2?<0jg$:O<9*NkrH1I],9,YB^C6P"7e"m*J %,IbdQ9UBe=]8X'Z@_.6'_r/o,3*e!<=)I0Fa%oBqf]Uub5SiFiCO@645rC5b%nbD@spJ7@(U_$V"5kL*b>FnV5])G^t3/g:SLDmM_?n`+S:;JA9 %\A/ce^S:Hj!ATHjjsV^mqdnB"m%1^bYfZJoMcWYl^;%/+[/:X1"n6`WF9rVGV*k$a)A\lFg`n/[<)WrR*I+\4^>0t'ILggLOU,57 %iX3X-&FbD;q37:;[<\9LibcgA2):Le$5TtC'&EA$0M4'^T*WXP0JCsfLZ\s[`pFNX6g,/!O7>d"3Ab&S^t/Qr;FO^a]ZBid_&%G+ %-@1+\9YPKf#*2E)j4M3RQCC0CD9A!:Wr_F@cj[W9)\[a;=;\GM,bms6UuM(^57^q[m3ZDjp\-4cSql34.1=Wl#Z:AR&O-s<3aF9f %cF<;"l"2?Ag0k8XA)Se%!:NMR*jV,N@01=b< %fop3D,*!IE0sGQSofBDs!mH5L*K'V,dY/WW*;N"kGXLp%MAMqi`kSZbN_0arXq?5o;f7`j=0om400ZL3GPrD=h?UFGEB$RFdl#?H %WSt1!7"-7F$]iX/.RKUF1g_r;HCJVO[5+XeOm[^@#.']T$c%8*bJ1n*o%RH`h.-kuiQbrp>RPH;A(>h/Zu2(X\n)@R1Urm#,LCfF %.eEC0Pg;bf(7lqXBhrp;5Mf#l^p%9RfN@]Tb56lo6q&I.F0oj4nEb&?lb/;P1O>g5P?Mp2i(ZcWg[tXsGTRek)7X#2:k5s@W_2,\ %k,7B&EU.K@"Z'c%g?`_Z;)='hYB1j]5_8(YTu!.Rs)3D'>?6=M[i[p1@.[>.6hqY709UXGH=oZD^>CU3=36RNGbiY0<0 %6^Jp+6SW+T_SfBX3Pr:AS6+ssDg_Cqoms(4PY6J:HV:Q'ddR(S@W:8$:o-J^;;QimffT&Xh6Dd.3;D37a;:S$=N\CU1@>h.Yj %MQ=>?OW`r2ni@g^`DmqjA6d[@L'k#na&.DQ.b>oGBA;a^*#2Xo0'BaclFVQEoSkCUmneps^H"*XjL4h2s/oE/]?q>jB\AJ_GuutP %BLQ/#;lEkEPR=;GmY/PMgph=Zd$7\q!BsjLFA(3ph3I9EZC3WcC8nIC;;0L*!sW6=4J?0Jsphr5q+MMhj-a(T\glr4ST/hl1T.5G.:[?=uUl)slQ=,i"[Q;=UeK*/SR* %NA'@/<6-TJ-"Gg"0N?7H+-$\SG7UmLU8s`4E*]`V5jslO#Y6Y8.l=k"6[HS@/1f()1I#qEBeiIHfD25a>][1A;5%$74Z_*XSk"K<:W=4A3]bdUi$Camc$?6Y %X*Yj%BM#HMB0BC(aR,o[X1=f$s/dlMP\pMhYN/)Q1ZHZO('\.YkUt5dR(/PZ5r%6.b/cH6>)uj!jHcJ2P?K7H:p27(r>aY,b\/@; %kEY@lk'b5'4WhPEItqt:fDdV@r\knLL%4UdB`M'F&mbSLn%+ljaI'3f_7P6Ji=5=Q2:/I7A5O6ZEpD"^5u\!ZE2;GX0ST'kne]!3.A1@F@3Tf(G+_.8P;WaH0KqnEYJ7/cE3@E9B] %H-sAfi&*:(NpfV;oaAD1%%I7]=<(q-]<-]*92qXT5T,.`h??l$GO$-DNV+rR,>qZn#FKS9Q^Q]$'!&51!1qN>^[5BPSm]%$GY[D? %S9="qf9FZ;`>PW!i/;7,hp$BQ.dK#Vo$Ji)pLoZg<)/"b_crA\Do($qaeLF5L6:>;4>'m*lb7Z-l]pqG%D)IIm!oY2@=UD %/>F1BlBp@lnJ"sRn,;hQU!6q,7.sRF/<+JO@JngU`#Me"@'+[M]k-X8K)t=*a6j:%<#AN-34@bj6bQbY6upVFq*Z'Ph_Y4>lb %*P7,ZK$+#[?VE0Rh>I]JLDs1n6cMi`9aEp"#(K6?^q0dsCJ^Ep5r&E:HZVGUX<2HfkJM%)#%;eB60NCCrQ5&XA%$Y6 %EHo/T[SKW4?3/TGm+*t/pWItG`c==RAprG@rp$o:8*Cm+Idgm\5&"_[`Sj#tn:bOGoNb8#ulf&qj`(>TdH]n2@MPQ\s5p<"WEFSmdg*&,oeMCM/iknt>-dqA^t];kQO#b'XQA %j1KTE+-o^fB5&b9eFoGSf:S'/K5'%a/\$[J8dKh3[u+ZVVEu%QSq>:.%/dR;c6<$-N^5roK=gM3Np32D=i>[pIM'WaKrs:3=r2;u %*)(?2^lj^g"]R4[QqtOA&8o88JHNau%6)U14K1]r[@ef\9YoNscbTXCH%1rl?aagY\2mOiYKfPiX)pPb;)&^f]IOO0GM5.Ieh]u;s'64q/&4h:A7"r/dG_gKbBU)t7=@4A %=!35rD4=#=Vk>g69*6lT=9fB$QDWF+^mK,W`[KbNJOj)mZ$KL6;c&ms\$Rr26L,Gq**s&83Dbj)NRFL>6Z2@=_t71#``$i$eaK=& %c%#PZdQ[X.GT1eF/b;Ra?_3GVXi2#&4?LZ-AG+JJ %iAH39B,mMHZrT[q2HpSPZAsZ#VSaacSthoJ;d>ZgD@!.DA'2<7Ueuu=F:E;5Da62'l!Cr:ppa5k^!5]c%KO>0qaQA1'cGY/TfX_m %3o-D9Qp$OG@`cN*4p;0Pq"O0,^aZce&FoH,bNe(%fa>,T2Xmk7ju>goP.U14G./h"NQ,\hYqQn6!#Lp^p"/KI-DfUWFp2C2V=! %mr1OIrXZ_fph\2.LK4UYMtl`n+G4[bkH=IrnJUjD]HZ@6UpufRQOgS %IAafE=&jt-8XN;O2_8'8@4]g]_0_*`P'e@7br8mk(%=D;2;UZ1V_7+1Ya[iee5nm0HNuDtMVWX=g_L]/.GB,U=M0PE$VImqMcJuo %lM\4,:RaZ,#JAh8)RN,?Mg1c;s;=dlYn#Ppft'qi>)g_ %E'Qd!q?<_)L*iM\9A*;>f[kOT_t'DtjIR*D18DZ_MK8(&o?D&fVlPH"P#h0T:]*R]Nn7:I1a>.GdR)]?j\%U5qfHQ&C0g[7p'S,N %Yoi@g#4m-GF'n"lGg2o>a`AA,SL>I!p86A&jlnYT3C0-1_7`5k4(!"F;*]6`BPDPGM$bu+M'ZG`-a61I`&dHWbo)rTo;I3f<*@0R %P8_a-$1j^G=[)%O]H[OA@094`Qn4R8o7^iZS)c.pBa:)GGjTlu,>4u0MBsSa>_saHSY&7Q;oKBpTX&M/iQ[HX_G^U:&mqJ(Q@:fe`"ui_O+Tu@?"o#=@e#`1j*LL:X5g#6>`]`*A$DW(AGcRh_B2Gjc#W]5!e]AVDIC %24R8PhaqkgTP$FDb"3#AGTt(FX74gq`"UcK&"PQJ6qB!7j!.F"ZAL%W2-c"en=IONqD=Wh>XDHX)@mtuWEd&aouM\4Uj]h]C@tK! %R&+5=2P$4PUF[[Jj;_h%BVGe%0)`])OTpLQPkc$K8JJ\_qL_1%kA.oMN^SF7<_!tDKnpr*!^kW%OXOTMHZQ%;OXO13721q(:0i)? %c>r@Y4e#9m`'-pEE8fYXp8JiO$M][kN-@l(7$1lS(jXY!&VV^8Lgj9"V2-=`1iPi2nRdu)LN%oGY._PqjM2AW1gQ3tqAqH*3*uBX %q):t?I"HdSQfbNiGOMBUFohhQY'MM?3cteK'8(N[rEo4E`>@`=_kQT0U-<7e7j"ZJVbq/_1S46"^&f*0%2V8QP#$=T,NV"57qoIO %7K.:Xq.9Sk_@RFAGrDTRZ?Tc,Lo9Zl\T&h`R=]&TnDL2Y^!H&3h^=@sg]+oHFI7d@r]C%Fi3K18/]D44R@E_$fBoAlUOVc7dQ.5] %JVD":X-W2j/U/]r:&50uZ2PpuiiNH='u+2HX-1@!5jPl=5Es*%VNDsBNSlU6<0&Bd%1N'p/2,[*&C8:gnde#D22mR/'1Nm4KK3%B %W9Bs0_ZD1IJP4!NblNd3;$]fD=N1uRGr9BKc%aSqpJhgVIS@N3[KI,T0!oZ5^BtM=5dEcl`f&l?_/@SMa&L%kWlYOtXE1K)Z"1uD %0c1]N'Q+*gfbho%EId"U2ACc]_HbkgH;bGdmG7&N"5gp&6o;]pgl,b9Ks@a;JmjDhp;StY>^7e:rRPr(6C:p)-+f*Zrt6YC]+&&] %C_UY%o$,mQg8n!T%193JEhNMoOG3[PmlNdC7,=u2lFA2*[P3rTJPp!b$>ZENnu,V9@9*_B?>F`F6#-6`:rb+JZM'[H9MPb@!3X9+ %D\Kb&dL0,Yil$jAVI)&=RXb=GJRkD:n/q/G5Q?A'mpGU7hf^*/`]S;bLk"DNaF:l;+nK>*1;[rkP%MG_Pr/Boc@kOKE$rnZYg,*RdLL]7h_pclO_QsBFZhtp9] %s7nnO5m$.u!6r/pe3*t$ndEO6!![Lg7j#KO!:9X;Rd;<<0^._]O\S*OJkode#S0LdSZb4Q>"U@-:r&D#jfc1)?7 %Gph>9&6_%+hqS]MmItF7a5OjFbHFf->XBH;2CM=UY`Q=nBFKPbX/ %[iD7[M8.?uE!W5/,]PdGefE$<9((gB,Bra020\YBP-\R*lOddI=F95eg$ipUK*L/^n@QJg^"q<0bC+=e"S.RYG;S*1pfk^a&8$l" %:`K7rLV=H*N-+O,c1&d7[mrA96f2@LrN,Eto_5mVR/uVKB(dPN:_Y^0,)#E/,@pe),9cr@.s\qfFsbI_[l\A:qWg]7h=\HaoYR"'&+L%R#olZioLbFBCK@b1qe[inC+5(46=$:N %Z7o/bIU':LZ!Cq=%glp#TY*8Uf3LVDC(MS=lBnCm$_L;%S%WDWCQJF,Zmh93,3:@3CTYj/6<.3c2PqgWcI %+/Ws/d#JGmW(^8XfFlX8\7uOe^[Hu`70*E/EA`m)2oGFLfS1>;:-t5!BHk&9[+TplI"(N*5G.R9h`&=a=oN+o+ZR)S2^(/5?Vqhf %'*@`1Z>nYpk[j4h$4b`aG[h-,s/AW7kAJqbaqf1Y/iY%jD2UsCQ/ak4`rZOTa!nN7(@#OM(pBJ[agMp$$@;SJ$G'XVrGVM-JMm+4 %0Og0MpLt'A%"JjpADAA9+:=0RrQr![TXGUA`9>^+Z\dgSDEpF2]eCbE=cS@/HA1^[4I_Y,$U1c9YCPeQ"P\gjV\NJ&m@%FkeR+5, %14bX4EK7tYW=Ag,7f/;H'-;GbU7V='Lp*>6%45=#jSS[TTsCb[%8T3L3;]^I\kLf^A@8(B3-[*rTqg8)7rG59=i2k'M-;ZllpmN-t='=`tr.n4Z'.rg`Dp++s59$&L%Z'belrH %cm:gXo7WSVlIA&9:N:+8Th(*4%l:e"%4?AICQ4'E%s-IXS[L%]P4"%TW&#a4s(:%a/I_ZM>BJc%n+EUO7W%+,#1BDA*NfIE`0f=& %eKO.)5V^730WJlTUJf"!q/tYCkpNOn3Zu4X:cS59Y!^RBe$-I:"uIdGX(=kR0%\JhRf";Pi@=7C<]XJMX5V:0M/[:bKZJ;GRc*A' %4G]!jBb3?8%2KP15Odi,BR2BfpRY2Y,R)`NRc#^V/3LT<<'m>g3_%A"dpiBa\X.'6u\mS;SeX>6<$$'=bqgP&S.SN(\b+1mJ]PJ@jnJ+V.;c1r %kmblQ,2T$H6C/FqR+6.*>C>lHVU*4C#.j$X*S7!C0"j!d72PD0pd1;^^6mDh.DG"$(^",e.?-^i6Ii4U5bS9eW"uD]$=,a(=FE87 %#flL)QeE;OU.]V;I%aBU%'#%B\sk?b\%VflL<%(G?,P\`I*iZg#/9:>*WocJZAL:^24V5poppfp'cJ+q?ZZaEi#)6`CNp88 %U!!dM9PV'O?XPYpWp#rdCg%TL9(;["%`O!%aK+j@-CnJ?$@pfD[7/<]OBV;N6*;8iW&0Z4(E>-HsZPUfigih;f!J@uP# %Y2_$OBu@<2LVj520OIiF)MGto9B_O+\#pt^E'bPigqki[^A'g\\a;iS'D%+gGW:mL"qq=#+snU]hH*7!%p'C4E+b<;B]uoJ<]5n3 %O9kObTD&l!k-8HMfiO&@N=[5nX<(*U)]7qdUpa,C+S8a6[2IG8%^D>*!uU.(&S>"%Pf;c52$Ipc,n,6F?n>H>;@lLn>6#"Uq^nf7 %]-*!J?!OW4(;QHQ%h=lPQD94R2IcO&U8sFW0u'?bctEpR-_d'^BTKV9\_>2rT(i;=H*+;\0Ru;&Jhq-V7kKS %d01^N:[b19;E(He.)K/'"G1R(aHHc:S=MNF54`"*(ktc2f'olOPpG8LZhi'dd!E@d(Y[T%H2"Onf:`TiIQ`C71iup[^:`4<.+DD:$:`Jnh#J;N'g\rJ-S*LI\)4C(8rnpSV,]4-7Of*Rdq(/d`TG%MRdj]k6K\0Y8Mf8i:H%gX*p(NC4eL0HGC,VKmW\Mmp*oA%/F=,,m9A_Fpkd+qr"V50:653- %\g$:3>E2p8f7Ug2O:m>AO5DU-WC_V!Z!SRFIBkD613d)gLQGhp'"tp0HiFIqEDZ[di!Zadj2N80>3T]9d:iKu-c@$]#iB:eEK"KEWkqnuDHoT^7Sc]H#Z^'2(sWc:?.Fc;jW+c$2,cp(-m'nV0qK[7#[AKM4G4RORSH3Unb/T8 %$k_SQ6m3_l8:O7A`J)aKKN('l+=3nFje+99l3tF^_YQVe4H!mBeTD'_/Gia/EjNs_@Y\PsbrlQ_a6):opLm*,fb%fX))5`p&_gdJ %#F'IgY[k?2k$MB&0ron/qB^AT\Y:+_81I<\%_^HS2hG_Z/9XW[TkMlJc7=1HG2!i?hPW)u,lnPunZ$-4O\URK%Xg\2+VN%_W'[.C %gDNM0QCW"0VP;bc#Q.NJm*p59I(/hmqu-MHbU4Im!Ir^V2"TO0K^AI1O_2>VPE>Hd?dd/BHP<^Bj\ONL^INRTJ((=&?bY9qZu4Xc %=5'V-lWMr>\D+L:5Om@Qll/M%06.Wdse9eHPl,`Z5V/ %0`Uid#=Q_kB,-r=3YEcP8sXp^NsF[*"MD%EAR'+dY,(2b %#1Xe='`InJHaGp\rkQ2tr3u!"/Z-lW>L9]0<7u":Cb,V^%WSph4OVq.O8_Oo-&=3bST"@,KNX2Y-7pL&46cr8qe1aBm%8XP[ %@"Qh64q,"I0TCTc[4>2/&\VGP6!5&nqBB:@9:*hGSuA49HZZLULl+tc\fs=pQ-h\r4/`M!gs."m>T@J">u?>]`C.O@#<+O@Y,i*YQj4h*WAIU:Y):_ms(6?HZ&jI.m2?c&qe\p:,O>,B9]_7slm^p/^M- %lS%R`g@FRJWK/o,U'^=+\2%fZFEGkLM$3tr7TBn=<,-Y6bp.]kB4e^:8-IgE(\A-),98p/M-L`^,2R+^<"VN>KH'1te3tS"QH<&l %a/k"Odld3+Bc]lf,fU/lG['M$RNih943^,,6R"A?jUao+&Sc!eG#T970WU"SbNXFY_j/Y4P]d;[02,uo$U;T"o5&RWSrCD98q %=,>kWA[k&06Sqkd`=YfZWi2YL8Hi1i$Df_VW'[J5*'b7MG4GP=e_XY)Ms/$0/u=Ff=\JRL.cTb3ar7r*9bjBRU8^JQMA0#!F*'?@ %V!l"@ja&///!So3F3M7Pn>* %g;mjX6F9'9>DV!hAd_U>Z,NMn9P!oB]-([&CXm''Z.,eZ1L]hE/d'Kin7/SfGbL[>Ej[;GF; %]%(bQV?^E-BWSf)N^-8h\"DKO-B]>lH2*$MNg2kVOT[[\,]JXSj3$f,@R_'-8@W=,C%/)nrH%#*0!`cso.B`%:g+^`pN&M#L\b$7"l`Z=Cn;bS#l2<[4h=Iu86822>ds(14U_ %F^3@9^(9peJ%N;RYoT<$ld2a'_Wsn_Z+W:=$\!H27QoVcpjbBFmm:M"j-D'.'>&DZo[Z_9h/OCJG_:)LCIY;?[m8V1+"1Q_FG<;*\GBjQ9$*gk]@Id %?[8<;5L=`"1tO%sp/S+21&]MP0tpYdMJl"L8I7-H(o&E(_P.?HHqS.t?;hJGn=lYS,fDYeP6q8CeG<)_'LG2N7>ro\g'IL-IZ".AtgpdV5E2!4R*+C*qHtPTO'#\N? %Tb6%rgC\!,U@o:Ec)1MY]+&*^hU:l/[5>ifoS0Br"@V^e)E0>]pJ&%]o+1S(YaSL("Jj:g$ZBaLo@R+jo;u+.2>\N)4_5">nZ.R" %aP+-oI@m'W1q&+IPOJ:E_V;$tC%uQn6M;M2&[J#gOsg0%=46GZ4-O9kgRU1uh$sVU5B&'rI(*#tq[_ISZet.PT'Y?V/^8aJF(qgr %[sMgr`D-Ze^<)ouB)\X1eGO9/ZGCa>kf8ksp1i!9JCAV_mT+nL!`oNe\?lcH;OfCk3Br0DU+.i-\[H>u*LKW;3*#W][Q1cQ8*'1K %p`Z@R%c09cXsQq2PC,t&hXpts]'KYRAC)ZI65NPq/dGJF/Qm1=gsXQHG#C4#m:>sI[Ml:uquM6u4R\FY;]"kb,Z?&%,g"'J/kI^C %T2fj9m"_-;6bW+jHp![CYj=lYT&/t0qE]*kBUdrg<'Me>_/O6frl$D)hLn0VkX$=.HB+90W9HmUA&@*f6Y''q@O.Idh5.#O,a^M+5;T8?-#;W4)iFq#9Fj/qE`@2a#;(e"@M(e,M4KUXQG<'+f4V# %H:XfhHUp_Wk[oX\LMhi5Y;/pBYecC7@3BDAQ$@DJfjf2G4)%[o'YIWTZCr4iD^`c/jL29\ot_mA8kE4?j"8%fG* %@:#J!RgX]/[<%&%CF %e`A6)osL=H)JtP\%SFX6qg!lM)(sL-j<.VIRN,:071PM"c6S293o"#9je94NZoftY%3icb\Y3ea %BPPm_Kc29Q>_sA`QA8:hP1f")jGNdkr_47s7_r;l'Y'bRTiEY)h3Y %RUb#:1cC"-7&*-%6*Nf_@e^)mAqqJ!3/CUjAd?`K\-tHTdY;?=dH]*FTZSa-R+-()4+(ZIGDT@UAd?`K\-tHTdY;?=dH]*FTZ[[( %9PV'O4-9Ao+pO1S3.MiFjiZ*]3YDNR9ber39fdNAgYSQ?fW5\NW%ZG$0,*Y*REjR;;60l'Thj'j;3p5MFK=@+Ymt"E.SWQ(TeS@7 %jrc-SkC$?sgj.3^hrEu$i>cScHCrkt9s"L.1UY1g]Jhc-AKCQ&I%.#'gThr2L%[;.bD\mZXn8YQ$ra2,c#eN;/t'MOooadA1?QCE %8!EHI]##?3pBT'#i0ppkZhB1m9,TF>A\=D\\BMsp`o?Kn>XY=nJP0$9[meN1b\B<=Y;YL`LA>HN#WACG:QprZ^Vf"V[es7+K&<8s %4-8c?*@Y3`:`#R4:i<_Pk"WmbZN?GFoXh/:Qe5/l?lAc@OYWR!k;&m[H"U-=R>M#*dY$>qQp+m`u?ED_L>r-gG]/rB(0'jN?Y %PK>0DgW`aEM7(kf&NRKsdU\H)OBX>W7thQ?sO:n=aYoJ\Om*2K&N7)Ajco %!<#&iGL\B40[OYPj+e0>VrGChcQIVMf-'\`IKRi-T&U-,ds!YGS_g,En+Ii6^Y=AtlaM9Jg$SGVc$6E6g!"YdOpCT&I7Z6Pm7l:R %hsF4n8$LaCZu:#h:RQ^d.toJ>dphE!65:%9*\:9Qn`K2$aiQiah)+X*[Djos;1tAi:/Z'=MY6eh=/POeE4it[('Rqk?R"ODhZeL' %070>BE2lk@b_6SQEHjUpI#(flW8QYeqFcUE%"-$<2":T/?)[mp`"IY3:YFc5Ked"@'A2B#Ek[MI7B%Eb?b9)a\?&M\/U=Wh!&NGr %3s8[Ao+$=-om)=c(VS/]:KFK_SCCa<)4&;Ved(M?)!H=-2_5G*'stnYe&TS'S'2#d8*b2J:^*HhVfdh^W1oWl:M[J+P_)G(Ql+dN %3^3mMfNN5@6&-aSW'[7PKITZKf7\_7+B2b^qT=s*To*1K5-"hOJbaNejsA^@bmT8?RHkZ"6KU/N?rTu'_S=!?P%;QEWVkcBAWPO7Zt %anCYB.Wc1-\u(6NDF4)ZkZ+Q&l>dWNK-p#I-?KKL@"mkgdAtVW1o]Eo*dXqgnF:($p=Rn84E0dq`JUPc %?TkR$)\f5/i8sHhkWSoRi;^H,q]5SFF?Yc-2pM?`0/fMF"Wm7iAr*PP%!&^/>%"Q`n?0TjfZE!Xq%OP7s*Sm5m8'pHqm]#A2bp-6 %%h^Ek?7FKgAf#MQSO@t&^2H!EGA;K,aL!V-/.O!_)8\CANC;b!hu8dP(F<(tmMa!L-4qtD42\YsHat6_Ru&q:-j+],_Th#3]tWE= %/n>BX;n)5"K.#ge@#M=cf,?3cc2oke'][*^9Nq0e-%3F+mZiY)M-1qb>J`Q#qm=.Lf9bFSf4N5?%d7k)2Cu3gi5pD)/IF4$C_<6V %1R=JtD\s4*bp:?49&c/9ol1*no./pL'GGBk3<4eB_V5oH^nR($[o'AP.3DH3J=+JI'&$@sZm[)*H.bR=VTPnCla!/F!N)8E_FJm% %l"Rt]Bc`qd'tDBgX&D>6nJ4jmg8um,]74Z["a?0I:L;m`WkUtEnj!O18!@t:f-,hL%N^s;#>tO?\:n>U5RONeOM\s6<)Rs(#Pi') %ceo6X3;:n'?qnJ4bTU5H(+cW8iaEQr$eEf-+-+GF0;tV^$PWCfnU`XD_`YJ19ahc7_:BXC$b^<:lK*$>drW^,X[?6F0'7l\4n;F`=F#a_AGtZ&3jQdN:h'6#]K5I@]CY=W3V:(-8f%c+rkKP]4SdU-NE2)m7*mfV4UI(jQ1;0pKt/j9\gen\h5X1O7tO\U#u+i5Ka3 %qa[66%UL!2bmX%E2@5bON'%\,R?*[p'Mk[5MC0`.>`'m1&4*TJ%m5D11ZqXGicKJERg0XZ\a%S?<*IZ4?pRBNMT8+q4(8\;k0)7C1'Gl4fEWFlLJSR$efe"R6KjV-jbt#K>$RV;RIZt;ItFM(l0,RC4(.QOTiA]> %][*Z4Qi;[^lm\UjJZ.i3N_\"AD.gK#K7*tW[W? %M5eOR];Qm\A;8fVNSEA"\Cf8(iE*r1))R^276f]!DZqQY>7-*SE1kUARO+R*!":N)Y+E5/^^t(S)p8Ws/9?"PK;fUT31GOVcjXSdD*l2H9XdmON&qkl+&+cORm)jTNE/&M/oXlTFn5ci7 %Ql,LZpR1j!aco;f]$*BYlSm\O'P[@%DT_Q]h`FReE\]RER01h*oouq(HunSMD#&1Pp!0:\F&c?Qs.3p`NbLUo!dj##J%WY1dT3,GNHP1p,S0d8XFH3c>hBH:!XF!I2lamDj'On8>Rc0INUu8Km*PBT5TpOD:XUGis %`#,6j-+^#`P?A'%VG:U/dQs42@d]u2:@i_$=nSSK;GFd,>JRiPSZAhYHIqk3<)q9X-`o+J7`=9;l7lA#U]qNj9&niPFQ0)*)23c" %5$XDf2(Hf)f#,CN_sIhRn`ol*r/#ESMaS59dZ$%BN@sH>?XZDcHkkC'.#cY=jDj:>(*7T/4]cTC#JE<9q>#L-jHRs<24>=; %`EcPm@j`kPHOI#AKXY-O?ME29[CnbepgI3pX"aF/OWoUq]e//JK6UV$+]+S&5r!l\#Z^_-0$E8(4G[ViPbj!j4Z-$NX/+lDM^#f8 %:-@6.o3*s7P`7.!Tk(6c`02kVOr;tF0Ka"0?.Mc2(Ph-1Qa/"N0pR;T1%R#pl\2rp8Y-KjX!$IiWO5$JsR*;eFBgA(O>iKE7abmZ`K:V1cR$41DC3P(h%p.Y3EcHt%qcnk;H_[ScJ:3/eK %d*pdC8d[LNbg5@)G\l*BAE[`JO:8hGYX?a@e*J1pHC>msd7t2cq^^'HAE[`VfQ-,7TEhH#4MG4WiCc)#0!!C-oWUH%4!'m'h=Kkf %4\.c.G4->L<1munU\b@,1,JiZ6p8d+P,NRBMNBYVbn6,;Vb'4A'pb6;E%4R%SB0M"o`glKM0ddIM4S<REn?f\2&g-?KV-BVfh+S6="U/VMO"jQ*> %U5TG2;IIFZeRcD=%"Er6[pjlQ#qFF;]G(Cm%NtsUR3@BlCbt0IPsQ916[]6J++]cc@X:_Eo0KXHZDF$+O%R=nJhMXpn59&L&XYD, %Ls)J!Jqg+-TVkG:MR(]icqfEf_r3b&>^Q@AGQkG05S'P36?M^^Th):;gPaR`XXLGJ^C"^fdu*m2"GXE,K"t#-m@bF,QmFOT51</&,7eK;(Y]uU %\!Lif>Q'tR%K<$h.*t-t^.[W>^fY$(In0_c[`I9I01GWoF>]MbP&'l:P/>O]G`k:cT\gZ^Gi?g`aWK_1Z8Fp1#a;rEPcX?*],@6HO/7q=QsB(TDDcV*9%BB)oh#k9OZ %6]\.!a)uqX;@'>&/O^I/hFaA[#ce>oi7U\TfHg;o]RfN)7in5Xn/VMa9Ub@LJsbs'!,]0rbTXnQnqL1> %`]90G][+etc63=R3VM3cO/Kc'9d4Z_:\XE*?%GO'@(.>:OD3V"74gZZ&3tU6M8,0)M,6h$T8bLhjX05D5R?kZ_KMr*6Z^4h(gi"C %6B/-=,,AjU4Ai;G#_C1ghVmCJ,XNr,T@Rt\f@uJp?,>9YX`Z[]:r'h\E#Zi1-]%FP5_fRs9;VOFH4jY%r0T0o)orS)RkTG`q,Oa, %Fmhl8T^Ek\0(5DaMf<@LQ7t;*6GTW1&kN/SUI;Bnoe=d)AXptZ3&Q[L]G1)BkIj %48CS+&\:[!OioS>:bR02Yci"=]&8q=dY7.\)sUk;6ZQuQTaF+$\0;@;dK!8Y.QN/3#aHAr'lQ8RT:>ip?69>VSjTH&7\_KF7V)S" %hGH:dWd@\TU$@S>%4?AI:L/mXZ3>@e.eQlC8frp(L9c&B9=,M&S)lKC*aWgp;irhGoQBYZ*5Yf-b):u4M4nBR9mT>R %<(-u?76a!,lb@Wuh)dL.4qP7OK2D)i,RZ*BY!AZ\D*LPb1W,g+hWGc0MA[[ln1)X).=d9n,_JoJK.biF@:F[81E;liXtg7t25gr# %X)N]%!%Mk_)2*ke<)FfoM>`^\6"LTWG3Bfl#EXSf/IoO*g>Ar15ugmX9?G"%:G6q4VO'rIT-=N*.B&cK7MQN6)Wp74HC2n`Ij0A= %nUnt+]F$s'lp&H#.Xt8l`)*m``2n\L8\uLR%sQ3i[:S&<;)tsMk3(V)7#@Z5>;oV4fHIhQPHfne8Qm?*1Ugtfn5_E,^]#9A0JL5ROf_2 %:m6S_X2naJ_kkF@ZLB\R81*4+A>*a>ra4$'/5u^O@6rcqMc[r;s)_md:%"[&UlU.K#6UQj8o8:;K/ma_gTj+"#<2898U>UpLTtm] %"@mVTTZ-MgGc;:M^c9(7U\bQ-M`=-.%,=Xq\P(!Bp^L>[FMef#SrHs>FCL$P'N9@'M)6RJiEe=Th'.J_rm5 %ru+#UL++PSEHV=jrDeNZ0H3.2q#mmYY\a(hJ44o'n6870$6s>R'EH79-"GsA`faoWe[/a=TJpYHbm;9?(W,AG.W-Q(Qlp3l\%:[` %:Vi`Ekf0IgS$8nQJd!fg(=YG7*_SP\m3@?u"J2_im+-D3).5r4lo'$$'T7,)j8hAl;k(2@r5o'3WA%p4abDL:LMn3QF#HG&6R;)i %:i!BAIh/Id.W7I>AULeEip+iE)RC;p5]l6#.(!-%%:#Gp?1;^W\q6'/KXa40n31[^]+c$UR(V/cguh(b55p %%iJkAI^bmQQGe'T$C423T.I.bEf5W8HjT'q.KR29+l!\q^He.+p$^,.r\VT/dJW;")1Rt3\8)`[VY%MPQ-^b?`9XHXKHALHo,F)# %BR);*H`8Q3ARYSu4A>!D91/S1UhkbtP2.A:C:IfCUPgul9Ic7*$R_4]PikUabiPHEQ+c7,Aq"od@la=]7/(q"mFW]):siR8+if]h %OjI,>5L"2D:^oOQ4tdhOfc\Q%Z'@)+0!W"l\X3j60-fBS%#N-TLBloNXlA#QZS66<&-&)BpZG %;2p^3lo%CH'qC`Lk['1`I[o9YF,&qX#t'#K#Bb?&YjJV;O`?D]$D,]c@Id2qV[qI?5$OQF\p8UsSm3[C9d:pInI'I/jC7SLs5^EQ %Ta?`/r"Ns9!891BFnjY=)g1r/di3G*q.+kjC6j3p:3C]*UZrX!Y36]o:"4S9ac3lQ,e6cr`N4f84(rdrhSIo;L__[10Op(QW3O;ak4GQA26K%%r[`>[!F&D2)C^VBb"&2Q'hl/h/>IR>Y/*!m*Q(>bEhg'cH50SI?k==!@a3\L;:@'+*9SJQ+6# %]jl\A="0$,X?m_e_=FsVF)5$lA/KJF:`5/HYq)o$IkcCVinp5l0OS4W(B91 %'e_o]P%U^r5r'04/*O9*$^2J]`=%k"-bQ+8#1kY`Y$CdL5t?)pm8Khb?-3Y^Y0LgDp"6p#aX@jHOGlS9#Jh;rLuB#OQQ=:G$=KjW %7*Q3)1\!6]+F/[0*$d=;PCk?caC.uaM<#66_.i8!RAe4n1(u<.%['nla[%Zq2*'m+64T1t/k$85ihsj`Oou:<#?A=VkEE]04R\i;)od:>:%2dU95d*Y6#L*X\t\=#"r9JjTUH@_S12)&qtgPL[2O-*mohH.7IK-m#EFRVQ15"405hIkD@ %925%ebBC^55FCd,WBNQtnd(rGkP>RjaGDj7jUJ8n3edN`ed6p`kJr_lPAr %16ua7j&i)0C94[VR,+k0c'6k^_8cHubaDcmR`*kPEcoRk[Nc'Vn()kJQ>s1=7q4/iY?[h\S#;DrF3=`&KC6Po:t)O\Tbk!$GLp^, %!g]igK?"?/op`AZ,r$0.M#>gZSYmhdk-Vhni+iG.otOZXgJ2VG\01HET"PU[/*%+]RQU( %?i7nI_qPF7qVbBPW(MWY^5=5&cGS7#EEr9<.gp+FU=[sr,\J$4WA %?c?=ndltq1?=s2AT:)QI+'BrJ+[Mbj=2][@_u)$^=GK/'T2K?DU.9h-I_\\S+mPOsE9`.21G-V##KC4uSF7P>?Qm'tb[&3uE9PC= %:)KAf5(KQoo>/qiV5ZNNk!I/%FIcZ0iT>mciC,2QajrA7#B[$)Rd#2bGE4O7n/j/n@T_I89FN98:G]7^n340B4.e/JHP],PO7aTa %c\EIm5XK?ZkTefal-kjgSM!qE.1@AZPE(k4KV+H6D$`6,kRL\&OD4_6D$j5)bV(_ %qKgil["_5ehO`),CW3o\.B03-mKog*qYE084'tX$nr1BfDHh3P?YfS$]E]8`ni0rdfWD?GdAK&rEqa\EW/SI`h6WsM%F*P2pP)`@ %PeP>"&XANW#)VF5WDOj.oe;e6E+Vie2!+4s5$KfGNB'M"djLg6ksLeA@M=[ffm?Xs=7Da/LW'>=L5)Kf>@GrVSZD@X5.0%G;-@"& %l$Hd1Mq?_XDN@T=]cNZmVh._GQ\;&:AtB>r-*9sp:s&!$n`H&&WEDf[YP$pYIB$ck\tit<H+JVRYtoM(jRqaIHF?&KIpSc+r*7nJk]N=1dmTJRa'ES`8*(6U,6CGKqBL;muAj`4^P=>&Djir?p.DG7K&8;;^`En-?(BrEK#MPJ97u&tpSXpGPm- %%AP]ZK1&XqJG0(t^cOpcQ2)-\k3nka\#uQL#LdH[0$-IW&mO!g` %bgueg8OURY496NPb@Ot7-a60a*b!t5mpKDPO@Pm=AJJ!7C,hD)b-;c"r5JkuP_eW?:I("YZLo$.$/.(bIN)B5_YE_Bj9R35.,rqV %;@I"(`)2A:?jIRkbrMC+@0ii;qgA(XJK_OO^5Sll?-7ch:ua6[6;lo$P8Rh!^&JTEP`&esK:;6OPS8i&r#R$T;/]7[b,m8`>A[q3?2u!&[gk#$*u$ %rBMr@:C=f'@33c;W1AtYFGP;C*lSZr^h!/&NoEn5>?'-7uB_nqMP]'EG+1Meujr8aRbm`iOHF//n3CeWt`;[$t,9J".f %63l)qS'T@iCnOB-)beK%A:nekh0m_LhKhB6Xm#icoJO\Td"0O*7)(&\Kg*q="R!eZ^SNo/FU92ih0j*n/ZQ$P^o;'HB6/TBmm( %`fUlb/j-X;q'&+rioqaK;UNL0P6##p;H-*RdgFA`O?Zs)>e.$T?XN/R1sO^kG:59%'Hl#P%`.F?XdK9-8OUYjX(Qu(^cWC$?o %>ZA@V/gc%Qb9WoM:PMXO3=^+N'>@Y*M,60Gl36W4lV"qCh[VG#d)8"FDGGa`jaF.N2FsNkeS$&KB:lp;m1S\UD7]R*n#;h*U)MZ^PL@mn,u$k[:(k&&W[5t*-W8lnAJ'idV3;Sf=;oUdaM %>]uj!DI19i`&n/)5TVZNSeB3CK$+o$Y#4tADVe7mR&XSTWZ'S'rSKM45(X;-(&>Y^h_^2t6,"1a6m'"<*J./;0*TK\bGO&1H04&E %\_#+1db2SB7i]h[T&5:.%S.>G,TsK@ZtMc2V">@Y7s%"R"+oPF*KX$23;8q_po/>mjMYOG3_6Iih1N2#UGden*-sq(6e=;&r#$jh %c_fn!9)>Ob#mXDVD6mNZ7DKZ:iW>^b04F2aH:CS8IkO/R9[$<#S9Jj=g3YZ+Z=psmQM@87\`D&,o_K2]GE,.?BB.p0qS$sI %h`HkiodSRb_2?-'qX=WZX*>C5EnoSoi=gTjh?ObiL9bjg6Oe*9C3]Jdh]>,AIsN=Y3nahdN.\E`!"Ac-+70a6m,K%9,W7221r>`! %LK`YT=uC4-j[3FU/-M-HngUe7%;5+^V.98dIQMp#GdPejLdDN9ic1G4TC!4;Rlg.E=@mIF/T>emGonL7IeutoSBp_ %Y-`3C)g/4GI%RH!1%C!h%A$M7#XHb%LH21(MUFGnk?j_8gNL$I).+6c=sYNA,Zh':6r-e*r>+^.SU(,*MDo6^XC %-reTG<%nLM;oL#:4cV".FF;MTi!P7NppfO7*Nm1)d94/6/"A2=eo0IR"CX[UZZh09KW8=gI"dR`d2T%[Tn?#&_0sY/]edhlo]A'UH`%O'RN>r!ds]r\$RREtN2PTOC+);mSS-\4 %dDQT@g&Eh/&8BfUN1=9oa^nFB:m<(+Kb0i8:X'qDp**:Fg)?'M!uD=epU^hU?r@o6f@,E2;W-SaRLsY`:'hU*.rg0CT$GYr9$!#g %h]4ug;R^mq_6ei]Q:XZahP5Ze?_Vl[+[+bf?[f7PpYfOFphq^2mD,EZ_"?MR&>onm\&^@tXniB8o5t<:]MCIZ2m&@$1<_=Q;UB4s %rFeF9j7XMLJQri1^Vp*_;RS3&>hkQ;$Z3W5C:.3%hIlP[*qQ_E%FgZD`q`,bq>'5O>4Iq<0ZQt\O871spAmDTR%Hm.GZ:0QdqE.$ %ND[`OF';3mYL?*Hgg5HJ2Z"_Zq7UoIo]^VjiXll2+(&>n3mAV]qnB5+XAe_,$H6e4n8=hY]E^jD]U'$!PoGb^rY16cMmq'JXfm`I %h-_[YT@Rt\;cFN^JL=Ndi/Ioo\J#O%s"2$f!P-!7a/@BCqMCeFi9`gVZ:-pap>j$W+'p=$kDkmk'fqm4"n+859>+DoSJj]gjGL?( %K:)fqFRX)H*]t&(Y8Z2Nnu@=4^[_4n`HqVb,:j713p<@YTto355507C,kn];gNkO %h1+c?s"`.g'FNg\M]h`E'pWQ&'WFJEa07t3j8AHMl<&!jPL9Z6l)5o$X]*FCOTs0mO %S7h//qo6A,ls1?$pi`f2oo0#SoSqtcgXnI_$p8@%q?CW+*B$go0JPf&F,iJ$1qR4AA^#)-0*D&1>C!Ups*Eb?;qlN!OaX.n?>obU %;4Bd$3q*\4Q\sBM6k`\=Pk6;2FrHH=4*i!qJoLdcWeNM`28$IuOFL;P'!H&crrBACLk6Tg98N\?'e\6ao^#:_<0p:0?7j)rU$[+o %#fhNSDJLXHjU>]`/tJe.[+0-XY(8f\fAO-Y7*:Z8Wf7UoFlu1>Ql_tOG?3q\4mOM*^^3\f8D3+?&S<2+j3S]J/L;L>Z5Bt/)Y\Y` %_j0p*@"MfqMMD#f&X*?=DPC)?VB'n@Z(igL-`)!*@%"2\=(nP";OEp:Ubkm_(/u+LGXL.;5B#Tnh,+*1l6=X6eUO#>*5'E4nM542 %((+'STPBjh]@eD+k`I)[=)>f1ZA$?s.nm1Y%U3>)cuG"\i?A1X[`4F]FBN%18I_T'`U!/Pc]/uR8jXiD=)=",ra"43?A'l8i;kiU %7Ikhqlp):`;DH.sq5&naH;*tO1NAj3TWp2!`kr`c&;@,iq0kU7U/2:uK`umc-sgJ<9Sd0NI^=BLYFk1Mm8NKSRt))#lb.Vth08qPaS4:Wg&&.2C[J-*g@]F;^]^jB#!PN0;4-Y+>buuK[g/qT3Rn0/,W34=&mKlV %6\319J00aieffUf`LSb^WkjZ7YKPd8'jU(dU6]=/O"`en"?\^sL6j!/YL(#oBH,-]%HjQpl1Vl$e-a?bmQa.9)!`0Y;$4fItUj %OjL=JN(u;#69u&DlKqt7F[=LbPu)33N+!$=knuIA:#OEGd#6LH(j%XKm!VpN\Jnm3S[;nXEGUWmH,ne+fTOObeZn>`co_/a1j0@D %HZA2=m[QiPkOsr5!=a_"0>i-A./dmfo'>f;eVTmL9tGm/i;lnSc3GSTm[(4TQS8b@J[&j %R4#lt"h:LY$(eYb0G>p>mCUO$9Q[Q.66/m80l0jZ#WN?B!70Lh^t$Y.o!!c)0RT`T@C:ZZ$MNk>BB*J[%mH+BKOJ[nBLGn['t.Q` %*p'd]D7?H$G^]ioK.Oi#?eWY^>&0at0D?j_bkR3%JTNbXl:rB9+Ap6Dj+`V$4VU^E1lD)CHsV3=X/EXP?EZL!2Cq!$Zai8914?+, %HmI@%jWj,8?DLW&8,NX_ql/*ja%HSc^Ri:1#^RT>P&;RKR`26Ek,?f!T5Sl%9]L2&8,7)I43@fK2uW)jqX-3t9WDC/_WS\=K^hNKolUbr %hA&4:1Pm3=1N\g0%aUSYUW%uD2.gp,A\;pU"E^^=QM(/S[!1T:Sc]V?H!KgC&9rO1ORT1&_V_#ZB?St-$TpnVF"JC9V:>i:;1o*K %DG`bWCY,MjkY)?NT?_12EHMe(/dJTJ@JUht*T:hQ3s*LdHU"D_a3RRZq^@3Qhj`n2jf(GpQ6&K[,UB)E0Iee,g`K %=C!Y!LVOhf^?/W,lH#V:_Zm8JiR=(0`/\@TL.@\Iq1(FVnu;=SBn[%n5Ku+UAJ,f-P\o?n+bp!;.k4;q-O3qfEqb0Gj?W,(W6h83$bDWDB)3aEOi*B3h-+iT./SfZ0e%,K.(#5? %G4Q&V>Tebs^g;&[5<3Q\0!i#b9cD+SL!u"TmR$8j9o=eaZsj89(SIWdZ@aX-fO7[qRI!`\Aqq5=AMS6TG"t2l*r+7Q)E(Za@n&4'fBe:/J]Or2lpO!rIMufk$<";6%>YV)g$MejtcAroI#iB7tJ-@ %[,M"?q@HoslW0o:GgHZBBQ.)`Z&i4%baY+>Ms.#DZO'13=f:=3U[V(&]==Qo2&._oXB?p`)<@K%c7u[E:$>XY\Et_gZVJm&Xd+TYdK@_5?4u^N-#@q=]&b?1<@aiY>6A;2HX^oS`a%A,\OLEo %:F/`tQ4!ocY<6"kC:\O?Og4:tDs>l0V(1'7VMoiMhHGWbcWD`lh4p/@%p%c^VC(eXO[ou!,TcK:c!D;_`Jk4o8[o?[FZP5/2WhmZn45Q/XXM)9U`)^4hONeGV( %Y2fn=e!W&ih7J,+$Pa8bs(Om0(=lbEJrp]"fRrGTLOkPo5^9ES&l5m=EI"/3<-ilW#A[YI6k#4fqH1q"[fS(V.@a$9gR[cC">m>P6f %:1J^uiABDcp(U9rUA&@*LP4.6TBRAD22Han;!A7f'qe[u.(I-)T_El-qsY;UhA8*t53dN^J88V2mYFuG56QBHSqOs$NB;`hM9>Lc %pLsf_qM5c(?m)Wd;+6su.5o[Ve1:4!cA8::E[Me(i9dBKYE.OBCaUM)UFFV`35I5SEgVA,)D,l=n$=skK##?'q %N9G91"oJdOc%aqEijZ'?5op<$4f6"hJq%Fmjn'4c7,RifZ3aF]@)22*n2dFb)-ch1AORa;C+%+AiVAFA+a# %5;eW1>hT^&">qRPLO,eH"C9JB!V^AK)aX3/56OdTW"+E_'rUY3m%A"gF8I?bP_KjiFQI+*b$Fb&TPOBOj5#0kOfgd%T#0AWn"58k %*4542qe'AfD?lI$5+mCa4#!2Dp?jOA?G=L9/e(9'`;'O:6OS#BU6!,@&_j#i5S;?(&lp]B'^Q>e`pG^Oa--+];iSB*5]k^%Mj><8 %3j'/\$kTUd&s@+LGS(E?TMHh44GP&ed=mVaVA'XZ%%c1(V_Ink5J['N!Q;Y2jn(mkL!ijLTU8bM;#:h)R;*X@q=Po>]n0X]rW(A\ %/_k4OOT7TMBsfW/Gs/K"br5Ao*m3Tsa;LqjeQ+HmqB;/oWP\kn%E.%"_CTU9@KU=i))2pLS*[Qm_pn6T#n*_/;tAKR%H5!`buR)9 %%J[]tq'Z4F8@\e45qCd$H5YZ*lYSfOGD[VnrEEqG6WVdME91/8CjcsJsD!nL\`u5dhe[?90[Xoskb^Ea/YmP9a]^RVA %P+MLoDXF=+M'#K>8;?PMO2a7nGpsP9\#Hn(X$/u;.fOBJL@Q*sGOG:%rMfa]RCd/%?ACi/4'`'E4unT-n3+8.N-@@DB"ur?OSNeW %dB*)Q%l3#/5aq@@(XfC/4-:ofpY8:qhs3heCZ"GMg'=k:RC)F$[l^",emImIKXX`'4^BlBYZr@!hGq`e2O4GDC@+*WM87TYImX]=>(umkC:1C[!(s.8hVg-pqhTrQl/(:S9uS&OhR#:o1"-aahn"YMoSE@ %Fu]o\RIu#n[clotDS\ZIhN*7(?_C<7S!aTQ-a2)8TaR](X+W+.,%.H^.Th?^]2@dD)p0()\u`ZCn0ie6CH++)+hUim=X8+*P-ll; %]aJ+fo^'L!;6%u8[S>t;F_k9J\eHD5gQn]8Cjr@b"HeXVZF,.GS`o8\;AZE39,g&%AX1sd+/LShBn[%n5L3O1?:+'A289'Qejs'p %Y#)tNb0t-*Z%AuaNpc(fn(gmQ>l$dLKh,QUKe&C,L#NFcIA+/[.,2:A[%6?@iO?YI#IAJJKEC:Fs` %M"HCq$RJ2\!+"gB'`eS$dY5bIkgG'cV2O#<,G3B&C^k,&?&3$FV@/NtcubsX71?2N3P(\4_IW64'4MfI/jp-.1416C(7HmE$q'W? %/h;<(WSpgj3&p/*`%X#TL`"-CpnE[LBY"a0$r%O9<3aEKrM@S%PU/.hFE*0_\3_ZHcG+uV;lJiX_Leq%MRZn$,JF)8f#V95V@`8* %bnLLbS=jVaU\gJ=7qIlP*^_`;aCAJ0.7DrX1PNn[BVs-fKde?+SB2K&\-[#74GIGTOiOs?;i%r;V@&I+cr?^].^#/gE%/((Ta=F/ %,$&[d>H$6j!sgsYKkd;2/a/[On`$/35J:`CNBfsYI80AQJW+d&M]2gTpf86(7k'BMd&i$k+!QBaGU4+d7GTqW8i++3j^ukVIYBCl %gnBE&%.u&&d65f7X-R=i4rr2K$!<,?b*O/9/f6@F;ttJM?*/%fLsuq;ttf %A&4,58Ck%4#TP7*]K_jd46j_c,'n`,_3`ed:NJY:D"8&,JZj=gCu+A%s%d.7bo*bDjk563kFY@-8$?C;/4NcXEdMHiT3]PSN5&>A/[7B".O%$P*Q]s-7rX %jCXlZXk_M3FgV?f_nPWE=!_qB[cD&l&5E*PGkTHO[Z7gjH[GP)9hAmO^J4&5b%88bCXEA..&aFDATE<"OXpLI9OP1U)gSh5>1IsH@7a79$n-_RB[6j*D:9^<0A2J[phs^ %Ad;\fkj#,"d>QkZ'jU&L'$ZGu0YJdd6*nK)JpS&POR,g%$H8$UD_CR:?W$.qQrXWX_5Q#6bMHkH>jKp``=?9]'XB2s;!\a8;!cg= %oB@_5U:1_.Aq&*Y*SgR'_Pk]k%,F2f+44-,<>@TM/eW"2h*hZVgdNF>0f27n3HR%kHBjW@"ZQ'=l$=Af5Z's]S35Pu.bG=C([U)7 %AmM150$Vek6*Q!FWss1_m$NCIr`QIX0c1(tKGjTVAmd-N<\ipbnclm*.f0lDY\=k.q0%cj";Glf- %!U6D3Es2g.la2i:MB09\"C9JD?#`5UO=5;9*YQR)h*]L'SD-?gog\=haU[,mK!+>\Oke;He0R1u#Dm&Jm\!,TkP!8,f4Qbbm&14l %?1PEnC(9'78ZN#/>AL46j9leV`,3\k.*n@![McP_W8W\QN#*mBa`rFRKX&OA.jTT!T2!lWj^hB9]bsXM1hDV$R+n?L@]Y_HF'CKg %Fg;?o?SVcn'nEXJQ;$iG7Ej3.MQE3Y8?7'B@S0c"3P8f>).OiE[cU[MCJMb/PtZ(?C6MG""/Q>\KNd%XN/TPTg-(^S4tX'D8l4I+ %;mKS!B]LS*f1IQ[bVk`'XjdTq[TBNaSbo]:Xd"ukC$4@,8niamg.LT39'`8`)#Pl\Lp_BR#F&7\)<4.lZi00p%:**^j^2NmQ*ho9 %IM3l)[7&0@2C,mdO[AfOhPq`G[7&/#Ll7g_j_^ZPW-3sM.,,O"V'*onVpO$c;u;a36i-X-Tr\pa=%Dr8\ZLl%=Bcf:IDnFJRQbd8 %%H$P>aSl8h6M;'Onq=dB8=KK`=$l$k30Rshf:A$!IYZ@qGIs)O^Y>`Lr$(V/#2beNb7\fP`% %SXuP@nYClP>1]P#$6Ql%2i]`+k1GdKd[J_3;0rXem)dgU]/IHaRmaS$/u._ee*^JPp[OV&GDNC,Xnbq$L/#`WKo]/Y8t$[Fe!3)/ %$-Zre*(hu@G>Kd97`)!ADJ8+M5q.]k\[VmKfj@n6,>Srl(SdEt82 %UDEcc:gLsYPoAN'W0gHC&'0&r#Sp>3AX)lOk]LE!WlM/lC)UYH\=p0d!Zi(T\Z:2[[gLF)Vm*@iFVh$'?p#>&"q)%9fYFi".7BC& %UN)Z]Au4b.NV%?mn#-Qe?`e`ES,&mY.7>*Wrg0h2)Y>mJHAJF'?]*A:E!-?12Pnnn9b16-UUp*_OSj,)7?LVaoMAed %`&/%_$=1:7rX'[U6DQ\bBn`_OMWKF2r`H<7i=4$H,2Js'6D98O<"3njs.j+uAb$Ld*h"TId,Qll+`\Qk/4@iPPD(J:A21(A<3eJc %s%2iF'Np6^a&U3TX)VgU&2b!C'rn3/`O#N>QpQH\1fJL5N?a6G.T`3K^k!h3o2K.P/u8l`>UIh35+f)LbsTs5k]UX.:oGQ@&u7U;`g?6I\+S9rP?a'9`bu?$uK'0b6\dU?-A0RLgVPbnD;_Tm8tk'r%)FE%.Xq8IWiX,-,\d4Rl8?4^up$Mg"%k[Z-X4Mp;;f`-%E/W %4[:/]Sg.ehi[l(5Q9Jh%p9OF,%9Jb`^ge[tc!)Ca6LoLV)_'.,-U]cp9KM$LM)]Xt6s?0)`%k\=n.i %%\i\0KcUUZ2#FZ9XQ6YT!/idGA%ShaoK!#LoNo7AV^=#&0.JbIgdW-ai?C`]/"3ldA+G"9eQ/pQ*.Z+`0ZrfPaS+3sgBo^0QleXs %/_a2ToEf!]l*?>3FeXdQ*XXZh0ubjJ7Uo14k58i7_'=O+9*m,O(Q@/9m;18(mbAGGn@#%?XRj\W'2*7!-p'r+E:&DMYODPIpcBir?+IYN";F5\dbJqL9Aq*i130AProSYRD;O$PUd2len(k>_1=^u:T!%BR6hqd9iZ?M'&Y3\8UqUr+OZ*Q*T6Hda@E0/O5@%i7IS\4QH+3A/FZ-u %>7%XFF:>A#*j,aS$+5-]*Z)_@A'B!&n%gmW9ZHuQa6@"%4A34P_7:C5$a:oXGTQJnEE=["rS"nD8q!oZ+Huc&Ec$T %/@VR/jqCh,^b*V3;83PsMXX%lURk&fE`$ThB]F'*9%4W%3]54k,`bL)tZDi+/C9fA]E'Psg?:;Ws8Rl9ZU\%rFo_6O.`[OeICS(&Yi6 %^$DsL\WJ64"SE8f&'_%1SIk4UeLsf^P)V"o,;!Q)0q08lm[D^GA6gI9c/.-!Hau3LJ0P/A1*[EoRE%A@$?VGVP:>6c1;I?_46ik3SH0*;<7etr!eIUlj\cGUs"asI_^rZFLd'eIj9FF6Bjek %1JKK1A/JW1\I-fW#;[lNFc,RG3HgRG-`M*&.[YuioXK^F1mRD^"]:$]ZC)UIZ(MP-bsHV%i=/l?;IoqX-2R4r=U17W\1qDpp.S*6 %;VP(^pSu,"N/V_C%MuB4[nXn?HS,cZi5.f,+cr[B3CZ'br,%H@*H$c]-#SX74jC9Udc.!K1FmG9ORpI<%;pJ-TqUQ53pLX3ShNg? %@T@nNPF0nTod'mq-,m'jg07aqUd1JnZF'CuX(h/@bL[;+:o:Tb9R0:O."A!U"X0m4dalaE>BViemaa64HOT0ZieKsBn'MZan"Ck' %rsfr6ofH.6$su_!ErE,)KW#()u91Nf7]f@Oa>%gkpB\KUi@6c88H'*EADHX'Bd4'"oWS>9?LCmYlOVtgF`4;6'LbL"i&UmuX%Mc0o9W[R9a<2j$WqHoI6DW%f %cpSHpi2H`%^6"*s>0$lO<+"h-!@7FX&O\lB%;>.hRg:2QI@1?bjF$DB1"$t+,^2)T-,@(4OK&h%@A1M6:>>IE>OUP %@Ye"UfmXne$4(_[jQho!PuA6Vge4Q7E$8CH=DXB^7@i]sjht#JEPPn&PdZLjo-iN<+[e/WN(M70G3UG$k,4C-/;+9^c$R].hs9a/ %_XQpJ@UFW"''b*(M&Imt;0`XPI__t-_9GY_9:YtXUPEe@;5/iY%$RX+5<+k*d6fmWi+4F&kdBnZ-F'nX?O7h&0SpE,jE6hX$3/C, %M%W(Li=i:DitIt!?A_OC!$[@te6!bRn-RZ*Vu5nF%A,&"6CQ=;*Qfb:(`kk/>e`c;#p7%[7#;Soq#gdM946;^i+>0X`JW[Sa<;"b %.$6l'LJa;O*t=tnO[C$V_9+N&d:qR-N$;NAF,pVJdP-Ok461N$`>nfNi=dM^8Acfi;8srKojb]1+fRloJ`]<9rT55?5m2n"+HG,>9>^:/Rj]!0>2aj0cA#Hg[)IsL0S4kIO)R?+g %NtHC=SQjaa[1BC+iD/T@f08;%63k'p.;qLKpSN*#6_arIBru#T.=18;n7p?2SB5*q>$9)%A!;uS@g&Ce1)a#W6Hmp-#@]tH%')dXcoEE,K':u*@bY:XSFD8]RVEWQ)jcDhE>5PU!n@I-C&0ku#+b/qL5Cut;li\(!2@7]*AGKdTbB%e^e7qL&j\e,.;S,#1$4'7 %=Sb^]LBEnR+NP.ldS-+rQVWm/b'T[UfJ+k@KLYQG.,bMAJ_DPTY+9D#=\1-L?C`c?/HQ.)b`)@&)c642EQdc(N-"?K, %ZCY9_?P\n-RBP*E)+5gQp1MBq4Qnoh%@W;HMci4;]OJnQC2 %U#ebM41q#Y7?f-/54+W&"g`gB]ctq^B-m)ee&U6`S+`g3?dUQ,X&XF4(qaJHZidm>bmEfb-W`I8";'[f/`_$fK/f;lS9U+0hk?&QE %$d_T;RZ]DM!c'M\c"Y+$L,(KMUGHC(b^.R$&0eaU7`m"kNTV0\64>)40rBV#AR;^)MeGpVELqhc*_kTb#$+gJRJ,r%(DqS:cJ417 %&n9p2^pje^?CK55\VMT7ITnQH_&%Q20Q4HW1ZmlSAs-#WDrZ:89ZstWi^SaKF3Aojq@pnO&OHt;>;0*rYq"hCBOX@]Q5EJWbsH<+ %-8n7/-73;?Lp0#'XcSI>2(!>Z6u/0#[DGrUUH4Br9=m=XqH?bu;_jLl+?E0k.oj[0Z^BMl/,Nc< %Z`kO36h %CaLn4XDT@?rNgrY`a'0ZqMH*)UYM!MPsASu#k2!$<&Qs4ETs!e6c=&H6:rfcM!+"Q=uPBN:R6R(64&#"m4&)k+PMG=s %h$.1C,%@lH-2(cR6kp`V6o?/tduP.=Yj"YH?Y?F`&Ik5#;Bd=USPi+dNO#Ybb^bL!?B6^]B0\l[J':,fD%dJcU-'PB9M/!eln%j= %+(Y$\!>0lg_/@'p^-!M^<.R,R&@!/cZ-f7$P\J<6nA@o_?lf)EMq9PP_0:T$jC2g,LIe7!U*5jq91VH'Ph(qP>U\trnD&8+@U2+* %+X%Hn!\nf<$C-F%I"?$'7(tuF,U-ThAHP_6+;M*Ck>a#PFWd3qDFC#hK#Q %5T+l6N>d3oi.i&7$l"1nXmq0ss(RnY511NTqm7YNeuS'#rf*Cd2h]Ko9hnZM_U'`(6rNdIMaG^E)jOVR9V %;Nbka?0Jh>%CrM>$Of&iN<$CXl5:hgdi,%X)*;h3;ANA8E<2;-lQ!%D@`Rj"BOrIO0;@N7;PAMH5S:p?T=qieqIFdik`UK92U+)T %$<^l;UEJBjN*Fe/0C[uGb=X#r5+JJW#tYO$m$38Tg(Z+#d#usS;CP0X`=ut[QCBs. %,ekcYd`S2n/\I7A'eG&2ed>#Yr67oB0Y@d)kaTD.N`Nf4]Nmh4g/!SSe,9]ians+N=0sE)Y=EKo?%DD7aRqKFP.SUV(W[huookDW %#P?Q*!j`,4mSL14$u3`bY`V$B?51-P\:[8?Es`#l\V!54-r8lN(%-TXZ4W9:EUJ?SGKDV@i=;q?isqUqT#_rM%Ijkq>$2^9U`?84 %k1fu,%>6R,(ZGqW,t_:^R=hoO"4?J5@1KAPjUKE00?"igO3&)nZNdr$9HFk\n%]fUgPjVuYiQ7lEu5%M(Tusu^>O?a[laE&ouk`G %I)/aCAB_noq#]D@UN`6F1G#k`>&aRZjpN2pfRA4a3XgUH#]&Q1(A!!K2q.*^"mf,ZPfrlS'f+tDja;WEAUL3#_Gg9I^@=IJ(FEdm %k'Y#*dgG1JIMokM?(t"V%:el[Ua/89A)LoKBBZ_l;QKod6QGI3L,E)?FJP#s47EI*32?3_D7Kc7+"LXE_;+!-[E+dPY@#*6i=6th %:B>kO)0bR(Q+GKU0e>,5>&aRZjpnk+\H[$YbZ.2WJ.6_lb"Pi+q*NlQ.gn:@B3O`]AXKi$^?#j+/E752(7rVgG)l"q3t^aSC)"r6 %U5'&m(TlLm$u5b1aH'2lq7*//+8kgLBI+\a8_s6%M>kSM12#Z]AoN,kW?G?hF\+Uk!J/!MQ2 %8k7bSUgUU06'3(M.7Q_BjBPn98%XFhfGT@)pKYS:E!`#sQ?O=/,l3oAW_719`;u>XrS\TP.a5:N._SrKUr70\Amd8DCE'Y-b-`fI %,=ehq47?Lk>cb=jF?QCFY"d:n#dXPD--\'=PU"Cu2pXKf_'T^,#3RiXF(IB#Q&)$8(!BfGAWGdsd1k35\`4m0K9JNO_RB3<1+,[07-D/hj1o>cPT,=p_*@4FEK1UV&*?k\[X/],Z97c^I6Ni$uJVGMuZsqt!r_*&Z%C`O; %-s]H:](M]^asgUd!BAO,EtQuM%pr)!BFH(Tq\W@@)tHkb-k]l4@s9Lh)NLR+"uSn%X*d=o7khuO,DR1&?#jMUAP]uD?L&"'idd.$ %\OFtC;FD662Dp@mUgc.b+0,g3G)kE6\\X`q[gCs;$'44eH]k`U?EVCOec]@qR4HTp:YcdmCO.jmUd:D=7O/M3&K/[qVWu+X/f">I %TlijigIKRdM@LeLWsb=H)p>&TjjCuC=e^M.?Qs1<-+/3NO+=296u9IiK.jT/ %.,moE]PO@97hXLsnVpG(2B/LA^bbpLI4m29(`R2L22L?+a7&,CcW5.bS5'ZO.XGPPYSt%:f_!Tl>3M`oL$[4opDu.Jn0hAuWs`7e %^+iSV&-d]^EL0E66%k!+L*(&sqM8%/FD>?0Zu)VfAc8P'U\Rph %BQm=%UuW[^Xg7W!ka;$_3[>NhAqAB3JnZ"Ako:&3=eJLl:L9a\Ai%=M;k3uI1b2PQ0e3ql2[;LCo+al)EOo;HJD(K25k,TS2"9Q@ %lO9nl[!,f9?.7MM6f>R>#Hbd_W-.Df=O>'7citcF$"Y^\dFuH0X"XKLS)ER'BU)5O:5pW06(`!5 %<;ceK-M%jV[@W&NUY<(=K,B3'_Q]WC/NhMIbO96\>WiBJ[QLOq)Ge5%5'pkA+/!``KUu`#=$6khUG8ko.r-l$@^:@E[.$so?e$OM %@b0QbYds\g%-Mh6mIca;E938JLICE4\+)Vh[pU(@2*e9bf<6mkU0,Vhk")FTkDW_fH[1]XVKq)LLhnk`=(Y(=' %o8Dmum>PU^cKkKt77AQ%$Hj_sLW4ms=__6mc+D2M@[udqS>*O#bAc7s)(=fmU1Q18Y[g0+8NAKR$^m7nu5=/\dU163;]?P>A %9oHXGJS%)sS5WBo6I%"sb'3u'ToX*R'YR'4O75'gS>(;Q(s4f?CS?f,k8+YgBiY*B3PVNlLG-Ou %WqRY!(Y/PIo*\m5nr$6N:ZWBSa0_lGLR_^Ns212^(Y*koo8Dm`aS>uibP4N(KpUd8eWZ'cMs:b]#JXZK1Cd7/Q=$j;ZI0InaY0fb %Vg]ISEf:C#]CO*(bQSSgo]m2USYI7.h6h0l%54Aq$\M3K_:>h,W?UdN6Wl?)-:L9`cV*K[c>ikTbV(5P[#IqlE@-6hN4KJP=%/r( %UMc0j;gQ$pWk/s.FW5Q_#>+;;9=)u)OZ'`UTa&?VAAXg41drUIQm6$?6QO%,Ti/_@@VpL\3\RJj;Dsl3>L\KXf5FUTJngM7SBb!a %L,.:c?,'ZBXn8>5]k!XA&nS.5 %D#rH`,q8:*@%n,mmp%H-;c^&kSeVk1_;nB";?mj>X-_t2'%&(#cL[SW!d2RW"lphVPnkdMIF>:C=PiU'D0]/[j]BXTkHmB`q?3B9 %@8g1i4h^1?<+6=6j,ohTq5rttD*Q3TqGK@f+?UmA%oo14BfA9+fW;7NF,hLpG8>uA*Ua4RL9MBL* %c/`D4IiUhseMiYU4SRTd8j3[rV=fg`:^S)KG; %'q:a"9p5'gR[d[WITK(7lc?(E=%IuCQBK\410;Opp=*m9[>n(+Kf&SC&?TbR %+dENILo>,P+W38X&^k&Z:m]CRX!8m=c>.,t8'"U%e8=0P-FYs$.O3;f+dg7]ZD*='jLh%UmbV"#(le$AZ>i+Me9r].3q#Nf_KuM!#A[!l50DT>aj&+[OBaKAkSVFKpb?g*[/*(/ag=)qEliFV^iQ'Vm%[H+17(MF %5SYB@pj==1m+o)If>'TTN>rV!cmKq"%W1mdfW&c^)-*!PuI#4jR,[[9@$Vt*'Fmd0uj65j!fFiJV"$@`h=aK]U<"?=6 %+h^&Y1c0'sVu&e!)^e).)Q,;&RRe5kX!WI:rOJgaM,p^Z`t6qh*6g(JZ8Z=?Oa$!n]016#RPWPU(>DQsbUjV(CYB`mX(e^U0&Q%* %)'tePCOPLX=jY/-1;_j5$[\1(nH)lu=DVOV(3`=J_!-AEp(QXj^d%Yh8aCHKqs.;?ggbV(eVk)8=BRDM\PQ`>'"q5fIQDa\W"iD@#df'p=nq-ng"X %_/_19_0lO2Am^2PlE\L!7ZeOITIXZB\R7)L*a8]l-KpUd5eX;M?MX$;5#HM771\/l=L0:`% %ZI0.%at32SPe;>"Pe>OLOY_p\m`:e"6Q'*9/bIHXbi5>T\>g2fB,9#(nn"1WF^a@TU,kS\B#2VjB$k>NWQ\i7BO''mOthm[!r4=i %UA?N`Al1]63O@XT/$nHHn5@K)H4k71;8!S9?l#hd7fF:Z0FQH!P^]-P*JVUD=)WS>4hGo0`7aj>*DTTiA97?[c%;be`/SO(R-)aL]g\5n3Jo@7SGP&ehDRl.p(4kpn_[O3=;g!U<3(*#XM#Ane!-%.2H?D2(9sj>0nD%LmUE0W/CX9$#GKlUa\_@(oa,X)_5u$4Vpe% %_),,Yi0U+tKn,P\-R+GLV^3%:fDq,!'_>BO/5*je_2#7H;/N]8pA2F4iYVtpo)LQb0e$3#MOl=G&WK'CHn(MhG7eFca43;W9ug8> %aUB('3*-8@oi30eNPuQjk:h';/K!;kOORW1;H?faLb*4+l*f?:7!D& %=#WIRMeQHa1imMSDF2PbjVX:BI^[hGagF&@'<8gp2Ro.1]G=$VAiBW4W!;Z7@/>+2o6Q'3WOS*fVg`.=:>;n657+ea"qLQn[Q9C.:Ne;.>'u\'C'D*T@Nbhj/5[ %>&VL?22[`oonG#/:YcdmCO3$?A<<1\>5HehZCm19AD,@+GB9h1N$'!h.$@N]'mIaKJ*gI\a++]%-l\ei/\J/H,[[>3prM'CTqg4q %q*X_%'\>k3N=*DD:9!Z?I&Br!8A8#)=gh6i/NhQ,;I;A%^Y9nEhjioXZ>k[OB]BX1,!?LLm,:cEkbG55V*ee/Q_9l0Z(c2M9r+fT %&BVmUNYY3iH9PX8a,5?cT4_0Enn)6Qa@8.#kRd!#p1A,oe)Ckj8>jEIZB7nK%6W7)93lbr)!qgd/.b1(/5U=uCf[LE6T-Gog``.% %lEp'A-+\!J1YNkT=X&S1=eap"fITm>LMW9T\3i/Ie7mm`9=3!DG\(L.SJ+AjF/+e%g`a?2!+h0_-QarfOUBB3M%OS^!IY/#:2S1G0U%pd/$Rfdg93 %))Xjt$qW'MK#[,P$jgX/mf)0?AlFYd03bFBWo=UY+71\[Xp`N2$)5^(-p**>oe[;&g_u5#I4n2R0@` %;I#qU6?4\5HR8*r,YHg]lIQP)/>>*d2MEYBQphEZ*%^hY**h863K#=@D\0HlWu"*#KV1;*5s? %(;\-K(=?jTR4L\kS27[b5W10fpcuP'M^U3:%?Do4O:@7YAJp]q[.$suU,Wg,/lDNYpL"ZBEDHA`-Q>NPqo;@9?4UT]@X-a;Z#ALW %ii:';7IbN]N.QVG-a;lAE%@[p%h69R]H8(^;7muXLJ\cK`J.5(n&L/[Yd03bFBWo=UY%U+#dA>p'>Q<7O++^.s%AL-Lpk;FF4(*j_(emIEX>aR=Sj!^\4TLkdBiYZ>qLqa1258FF/_UP!iG.apf\X:21HQ'!b"jJ-++"2@IrRNT%j1O#U>&J3S1-m?\Hu/ %bSX$fT')W=%R,>Jdd"C+'uQ]hbM!k5AL*3k_MH`^kO"3'>]$V16F7%6+m.J_(i%&aXt2HtEg+b3nq)SfAP=J,^-]2]2U+4YSt#IH %'$:QIGFD-.T9W@u3GY&[D::D.o1*2(UAs$#FQt:O&5=bs>H1rR-SCBP'4*D[o#,tDT&`Ce6$A(jiHL@qWdb6sU&#d-Ee^bD-Frtb %E^KHf+=Of"As,LRmiX*jrarI!lYe+$\c-3hZDbO$\E*Kja\,sSXTU!>^9&Y-T?5>GVLR0hkmL'qbS05KEZd`)#_G?%39Ot;`Wa3N %'rMsA&Ed+aRWg(bFrGV2Vd.R7B;?iB\2?7hIJ85J8T$[T';7'S9^+`+(iR6g)`j]H$i0B]Q[hp=X&DMgI[!VKV4GIq`oP$blIOkA %b]-/h:Uk&Ljin4)#"ROo$u1YgQj&/>!I3esB?Tp82F %>'sCefi,)*f5e#F?E1dp2!Y$]j1D=2=5-7qlfu+)d1O*noPN\iop\D!-fB/m(J+?uMskC4Hg8'/>16]'=1(BP+dZ(H(,+3qEo5EY %US$t:=?KAFd"TFm0f6VF\c8gP;?[W@H?Qu+2Xm`LX3D7l-e2gc.QVs6Wp=EKO4d16ksb\\B;60]dq5?hf2]O^=AcM(3Xn4%F&hSq %\Z-s9)%@%bkA!Grk:4\JKH$,ZNKQp^Q\)NX;F %]^I-ZmiJrbYi;D##WDp70T]=CpiQFB[Dj9irhj=V:IotCn^F(7=m\.T1u*G.]K5k#4XsiJZY8;4XD3Ga%!"[/1)Q7'C=Oq=.Y#3J %-/?3b&Jc7uc<%kEdlI(3?]tK<`ga=`E,%nDU@:>M104KP*"6T-Fip_._-29Cb4MudNa.u@`no25W*^7LVlZ%GoS %G/909V3_[#jI.X4+*V(UF^4V,+8)+MUPB:19q8$"(I3p>)X/<;V6\33[X]_0>%s2iIq$s?+KPM?(QDa^Oe/\.a77PH5YEMBS?Lk- %K,Vb,]dBs_mt.r.rtP/LCVX_d"lu;M!Mg.Z[<`X"e\>aLjeF;H`CEoo2LnuE$h@0NcMYQ`e)Bkd[F'Laggl=M/;.\,gZTAC\aVu' %XV81>'d!=f:jkW*Q=;W2&+!s][@ZF5'BAWq'LA*2`8^B_`!Ea65#i`* %R4#a$Vh38i@t$2UKX6`6]GNNp)t4gjg&^sTBSEDfbr$05JINL&GA]]God%JkjB2p^9Xt!($MK/bmmsh\=TFFKV[a$"#p9_WSCTSA %&q^]>6A>M?1Va(.DZkXiku:Df+D-:7#X1QBbZpDGeI\+Z)^ZA+qPI(42b#I>"j/\IC:/;s#YQC?kCcU4`RL[4^&G8c([ %VCmmj^UK7F:J;.ZCF'#@;0r4 %Au^Vjb;AAk'#V?mc:C4*0&#ak0JIH9=I@!dEhk\Tc:aJrm>Sa(I&tL]qL#Zf#(M5#4&ecc*mrqthp,e`bS[t9Y/cpAI.aBjs8&R# %(cU@-2i+22rMl,A.4L7aC/V!@-fq^drk5hKY: %:,MU$_!-d[1+NTI:->-\'m`m^"\E]l[B_3a@GlWjXs-mWr16m7,4#^gd:,=9VmS3jJW]Y7Q[0"a3p_34k)duJQl[F8F2.htc6aT^ %1NGDD<+EEoTQi/P4IaVAl,UU8\&t.Jhr>MD/HZ9`(/?sf.L2M_E[\:#UpqV:`ss&gUmqj4r2e@=HmC`.,jSWlG)L-0\&>TIgrH"S&U0gn@6]7F_&35Cmga`-6e%TU-P92^,NIJY,:[;2=n"OKs8\pH\Y7`0!<.O!Egc_/97uM&aXQ:]_Y(dW'gH %!AkbV4WO+0mfCakFA2ad)&8_74eOo,+HO=K`=>Y!^a^f*FcFcD!0NTs!Y70-rcg#j!6^@j9I=Sjt_rsoi6]hoSpL\B*mpTr@JRQ-C85`Da>A0/*T9!&XTIDD52b\.`U*]>A]\5]) %=APA]Y-u-MHmH@a='K?[ajTDkV5PtR\4JY#YI;fVSX2np/SYY.A.lVslRar"3Uq"'obQbK7GQ %0Sen-aRp;U.6uAbDhLQ!JP8h4,:-Dr@(91IqX1DociIDlKkrR^0^A;K0OAgo0m8KJVU8Z,";%%?XLZ\kR]DXdX(X,Ia3,Sp;RKYK %Jam!>9^9Ni]$O>QA>Sgb$OqGOia1T4$S<@pdZ,SgZfXSYI!X8Hd9L@D[N\5A%u]QO7PT1PoS5kVTd%2ULOj![kjZg'lPHZdR(3NFdZN]RYL2](!J?M5qU,-JLR!EFtbUo%qY?!uS?1?DuV$Oe_aj$:<:a-&&6&F!;ACjEp.e^&@SgPp*=^-i!u %FO<"`\Q(*.m#OgKmpip!FcTXS,9`nM7M2)<0sL;DC4WtKn:!qcWPGUNgkZ;[:%ZL\K0M+Ffh6%C^g*F](OMHc$0!kHQeF95'[4D< %HWEDgZa.o%cPSX=B0RbA&:@)%4?73KZY0R5P!bkUa06MC^WP[R%XE$hJ0B*;*9GR@Q]-_1C/jK*W&NLrqd3R.pq&A:E0F'u2D>IF %a7*rcZDL49%u$p(\cX>eB-YRmF#02t2tC`:qkDQk>lIn2pDBIDVI%OA1:Y6rO=5fjgY&)_qO[JDql]l;7S0lQluO'"@sBJY?g#lu %K0+Gk*G&iZGo>KJmdWGEPihX[Lm_P_-EGS-biT?%n3-F7,D?dQ*e@aT_q,Qn$?J]AjRAn^3BhF`6a$/r7`X\"WIF-?\W<3Kk=8a! %_j\em@icj'8MkD-TpAN*,G'FH7l,DL+C#]d-AFMMl@0FJU@[Zd`7BG6XO.f3-qeb\n_h8O)r/]4KDl-+*!JZjl]_3;:t65(J-2eme^"j`P67,Vc$7VYT)p&i&7(D-E_^?N-e'7-s#JcdtAT$<@& %4QqpKVR$MkQm%0<]M2k"riDr5h;Kdn:"qtA\.!N;pnJ-"umo`bSoC3Q7 %o_5per^#!(q(BAqP450ZlN3j5-i\\gX+I#qZtW9)QO,]-aAGc9PF^BJeLjrRYIgb_oAN^:ISjW&n7'ZCPHk(QeYnm3M5)5H"/S>^%.6<7%m`?i-LRA %?L%UH^`_rBqK!- %Bk.5kT,3jL?I=5OB?2@-=.OC0bXX(l]u"D"2U*FD/mpdoWFI`/@NaB@WUuK^X*6j1rMP@!XJ1Akae:PHA&V5JO:RM8#,i(QM^/dFnAIUCJR_:RC\9;^X09u+9@r^9habYe[RA\L's?dgD>DuiOPrf:m&l6A:9?oi %@NEkX2Yq%?'X67K_P`%ubmruhX?+s*4RAh9Xi,BXp8IS:IJsQLr*e+&hQIZA^R'$#%OpC`,huDo1O37U\\im@CRr[E/I!LUa`E#a %&P+WFKnk)P-K0Ti"Qo!E=Q--B<1W[^U?n-RE[cMQ?a0t]pL#KW$RN"OF[jeZjB%b^3\:X\#0SK`"C'J`j#*+g8[umds-_;3" %(A6n1+6fEbW`D];;%G])nQ@.#!D!/8:GdrBA@B5iq;9D6f\-8$git49$),3.3mWQd)f.)/@Q!8]nBr %ptVGFC/Ds< %3cALH;,1%i^`ARACc*SqEuS$H`Xjg-,8iCAJM'9.c9oC7Kll6U5p%FfN,?DAp_WTe)gCnZc@VSXB^?-V1#9P=?Lq3j) %'4?nKNu&L%+a`M)I\fKKhP91VZNr?HHkFrVZjrA9:DR!_Y97WWf9%sTOu,'.?6=3n;,2@a:aq8>-aMUL$%;A?^"Q9>DO'^gcHDOC %(3&.e^IH_jOK./6V?W(pYG-K((aL7"7iH^8DSQnj6#\.ec4dD<"`*dR1(_T&]*gq$r4lPMJi7NVp9XlX$$58YQkM30kpr.;<5OIM %()aZs=a=[,B(aM'2QIfPcVXe93*6u]YVLq43:W0_,ld(,YPRil!UU=F>^>VJ8ohR!a]u*$:R0s%%lr7KEZ5K'3X>YWVu`@/I*eKhR<`j %J9r:f\CWd/'0*SS@\O*i:'o\].:j_.'W6j6g_MUgOHgO-2-N?-S2)<4?U7j&0t3H'5_'qaS72k=Mo('%#S#\8>]U+s'*n[HZc4\* %X>Yf_F,%E+)n3e*?EBYR0WPC]_gigU&;7Y`9)8Oh%Y"(pgB`]GH#$QAV*Z=p!/rAHJ@-i/dO@n#1@2?)B&hCAr/pH_E`"^AH+LJSZqXBEIfq+UC47 %GD6jP@-c/o%)dl=HTYbY_#gooV(rgn3#mf@1lqW?`QD;fj9jUTFqSi>d&6_H+)gArPYUHprS(GaV6(CFNBQW2QPSJr(9H,F;5!P-84B#,IDeJP&QP4"^9Ac/1#WILkIKi>*l=!dlt0%/tdV %cS6UFN">VbTXLUC]?j8?#tQ%01rU2Ol!ot0GqoS6dL)DJ"edOmi]K[[7musuWJ_R]9-hW5(t@:6e=W4!79a!VhB\1u$&tdN5AIGP %2dW;i+qCd3kQN;A[8A-c3VUDD!oO3nPX;756!mB',u>ZHo%t9Q9*D8X&1'$g5[$*]6G_Wh(j'0bbREG+LD1N1PX0)"mDuTK@hO'> %[d"XL"u^5uEM[NQk]HBrQ,1nH^$F/cC=] %Le=j(^qU6]j&3h00asaULh,gq7Tt^5]S0,h*I'#4JRW61g/:5hpF9cr)Ca<]A>bE^8V*&_LVe:Z&iHd.p%7QM)hZljYUon]9Qo]? %hWMsp<8p^+57/9UU1,C`@Iu:F/huNH0COdB6#X@&[M8/]1V8+[7*qk))ABYC5IM7KmfW0t9.PgGO^_QbMoj7q_DmnqMTpCGQpo>7 %70Khq`l&qHf`ir9mObt;iDMp@LOGC!Uk@nJUNB!-ePJ=Iir)i/4XXIbF0O/-oTKPNJH:r[iW0]OCPAHi0E>X>UgF0N+bt3"o0l+e_)Za2S&Q: %QPaJo#oI"5n2CQsI9V'Bq\E'k*HR&LN%#8DApU1nIlIWEPBjRTdtC>CM6]"<2(cd270/B6.X<+brPCgNGmZ-(Q,r7\?8#!`>4Y>. %&6@=2q\[n))MAG+h8!2E&H?JKD$n!"0ops/0mSa,kG]rb5bZr!N3dH[df]f1;0Ps2k'0;R'GEWTR3Z@8If";KZZPCupi%*P4!g1t8-?7BIOWRp.I"9hL;2CVj2'bl0SO[=e3>m_:q1#.OT*fdm@WJr2sRr`^#M0_FS %:.):'Pp,%fF[W3Ik]*eh,PL!DG*?GjL:<;)+G7^/.VQ*n1)^FS!0U2iMZQjDVO!W='F^5/nWgO,Qs*SE^]bTT3uNuP?Q,Z_4ct// %#+-N3$dF83L00('-HKSrF[_1D,0*MBq"2Y8X?'ULfg$bHl3iR/NrJ<_>%07&M/\1Nk5)rq5=L]qQo>!c %PVMeC1;Pq_`[_=t#c?<0JX6_b-1J!eE"X?b0OR"tanbde@F,0g@^RN+^PhrrqRmc_I02Q]SC1%ZkVsm=_Z88`fS9p!dQ/mPbtI>b %D&Y_gr.LeYU2PITW=pW-%[:NB,H>3'j$XXCXJf+]XD$;LrkbbW1iBVX0Et=e^rWaM_amJq %!\C0V0h%gP=A4Fl4RfXfaD9I+a1$-r41_S9^L,tiaoIBoTh*7W0XNY]8H!f*U*3@(l7^,Ol6Qk0FKB2Z@$nM-UJ'++Q,M$fkfV!j#M4]D %Ri<2ZT;)k^!eraZ'c"?1bm;(5ePc"@WjYk=p;%)FSpOi^p%!gM7n8__ohq.h#iik;`7:oY)1M7q7A/7\Ie?T*V!IQM=+/u,f.&Sa %Sq#`bB6=WNrLo(:;(C@:U/nqVK>Y_g&`;FkVBQ:(i8Ft:>f*1U9>hPj5HN84DZ.R9Q.h[mYjD0aqXIOeX@"0RD// %7]^aS=tNVt-+JB;P9>O+n\d_sk$TaA^;1fKps+$I[Q7ZVl?=8h"_8W-r>n#Jd-Y4e$Rq[JFT %R+(V3>6jLLd'FA)k40Xp^8$f.#3UT_j[(^.:BaUW4nWQ>5k+q?i9M>ad-;dcqs6kDm$O$_0Y!2rSdUj=lYsA$4q8GIK<.]m:1"rD %RY^a,iNO"5$NY+>hD*GnLbe:k_?>6*^k`:*UW`K^Rqrks0m0;='TOVOHn4Kb9DR+=?3%h\I8ik;[M^eh<3W#ihg=uYL_a?u-$3Lg!fHmW*88Y_`LsDZgJ23B %.u0EG\6.+H9/_;CVGB7)Pk?ZnqI@FrNhZ^`c//.Cpt@g,aGf1oL"dt7Xl%ti%%U0![pf@j1X[X#1fq[\;'r&:YK8rKlE]0keVIgO %JbPXd0@b'$B'9)Gg$X%F_YDCp*5i&adjR%06^ihLgJc6^f[Di&0'kb*PUB\M(TeJ9'XNlQhrjZO;ur_FfKq9G=KmYZ.;TtUE14]0]M&@GA9m!#t(u^q4N6N"():\m!lL[XO3;l628;a/1k?A %AO[(BWj*E-.15\CXtZ3M`PukWd)bVqm7h5_[56OfQlP&53,iWj$S$#[D[gI.gelD?f*iTg;+TH)Qm-'(\jc,"T9_K0U%")Q %X)m8L3%u\YalruK$'Pk+-P)Ri9%.P1H!T.(?G$3b[)J4^L?g1tX83^;LNqV(cZi_A\uqZ@ %'VT]/lj/VZ)th@]T''Rf\Sfmj%c#1KDqs3j41kL9J$VgnOdrPtAAr1DkqrSPBgpdb,Fp[A(g"S;M_s8'W/M+#4) %rpnm>eCQq_bE)\qQQIt#Kq7bCJ,F*\>Q!)[s8C8.Uqcjc0XP1A9$Bs,\*neDGqSg>TDn(^rX=;Uj,a62`ufd,o64Q8oS%%0KPAXE %r9Zhas7-(saUa/LI6bRE^]1e#s8=&=jeolhnV;$Ir:-u"N+Gj4pZ&`4qU:MiDuZ0=r:&NLJ,#r!rqkT%qt$HZo%+seK*+,TVoA*" %eaJ"En.l`S\c;5uYV=h3pn.2h?i@]fn:PTS?iTga^&?!\?iLjeU4=3\%rX.FkaM90'SjHHCNSq+?hSr?+$;hOZl99e]M;l7GPL_. %]qOXuhYqR.5Q9WV*45ImX3[]WkE=%A[.diHeG%VCj/F]eM\#B*Ct;BUIP1gg*_1[%d-`$ja+"#TpmOpq\#ZVkM!qTO57-kn&>jFm %nJ2%/^70`T++&;r!FG-MKDlp=p%-Pf-lsN/$@U:X@mBE)r:ZL;d*g0#I'CI#n4gT(r#B&g+LTfW1Wup+FS$G#CFB %eG%VC4&Fh;OkN*LO1kB]W:0Q]h1>F6KD$A`GmE'X9C[&LhIEa<)VTN]"5[G-2]U?Af[8`YDr3/0TYAHQr>a=2@B;Y_qAS`3@u"PY %n+#<_\it\.AF_m+"luJ'VU>lt5Y^Ib:/2]D?+H]M\oQ8AW>qrPVZ[&UA0t.NArkn$/Lg %csOIP!`lTGmcYe-a(G8q`-6E\2l"WkIQ7&m%`Hs>Q4M#BrPZ'e&__.>_=pbh*'8HWlDkGVMdrr>B'T6nNshbtn+NEha.C#!rq:De %YbX`DC?NGQr3-6D?/cBq2?(D,mi'*!L[sUM^AF';Mm'5US+G*panR,E<*KuV)n_cD[Yb]$;u5ct?`Z$N$p8OVqakO^_;nbl/m,0( %^PY7D:4VLg^DJ&A5tBL]/%C`t&XHI?&gj]9kL#8eI0==LW6X^JdO9>&U_kfXp[\%`,<`L-%M;(iEK`C@lY!*0%gps::uGh^mh7GU %:ui^FoeR9>LP0J-aR?C1p[P#`8'(U/K`EdS5TBq%fW1X$ %!'ePur7rD>pt4/AGr>0+/ZooqO0jqWl&o]>&MEG&h.ql@W_In/gouc"pE7`$k$>`If508\Rd85#F_0tO%b?mm7+K[n,l %CKgP*O6_/[5'0gId-D'JhH6u!lbQAY`+!,_&DHdPn`mWFkJ9H6O"J$QrEVCE+8#<[XIk@K4s0h,\K2_)pt4*.:uE9J4WG12fW;8LJTjm8 %>'phj)LQAe;8*:e;F>Q-;n7`p02L"rqRkp3>mN!%T@Kq0(nm!Ii)CN"P':'"9!rlH0=\9m?L&&Ah9g2$m'XQrMTW!m]oF,jS"XnO %iU)a">-./"h:\0!?*H:sSX(3g^j!5af&t(cfk\(2f=(9i2RM)f$/bScmsGfc"DZ"OpQB%qmIbVBL+W;_$3RtgIpD^[fG'MEL>:e/ %Sa-h^TD\!OJ:JTu#e+eil.[e.s.Y`mFQ:UJ,95oK@hm0ijH9GSqh!hL7-V3jY)Lm?[WN)flA.P:M?%q#@:V/q&O,kAdfrVF,jI.ueGrk=m@RZjAYr1e^^ %DmX5C<-hG]nU.[[9\t&M6dieF0EJ>.-O+=d-YER5V0WqgeScHB?HY5:C*$3%D[,rJ@[NC6?GM)!SgOd+Z@XG6=uRm?AEs%s]aNEV %2\&BG\91';XJW2@$LW.!*`C_.dN1$;RJl"iUD8Q?G3nCQ7'p):i/7$31-n\],=19n-rWa,$.t#MGu=bW_>)[RU]N=F;lb,Y/Ni:l %rk^7!/6e;*?q\NprX3c36*\gReBOPJun4r %\NBNW076P[ldfVF'Oio7>fuVZ`-_n:q6tbg++#)Gmo>j %#@ft8e8^paMa9eD^TAt@W(Y2!f[@P(/U\jr>3"=U`=M?%p8dJAkO!]kX#h\Q:ffdu\c(f>e((pBnL7siPI"T/8JL1.sU'HOH\%C0&NLK&$(ssLcambPJHAiq6^puLV.[^LDQ%reA?9S %+*m&/\NBNW076P[8QS$\&\)Gnk[hYuArO&BX/6`@i>ecueXC:?C*)tkW>9c_&"[m5h\Y?F9*;DhltVRTb@=>_,#9t3MC,?X-db7Scq)7TJ'ZC?7><]>r]kb[F7fSDhf0 %Q7f#**j*+;f[@%$+7iYR?fSOL\gtT12n`6E`Q5mCFr%n3a1bS`*(;qlY;D3q9fa,599d6e-XlO>D?`lFHk0]/GLB[.$aT',LYCE4 %'K(/<+BK:CMX&DXoO/:eUI6aJuFgH+c_rq8[b[ERI2N2_"Y=A2#tm(Es`R($nmS=GJ#X:VG(sHPifq %7a:lSiD"E'_&gJJ_i-4"2H(S1f-ui^-HN?^`^pKBBa.Ca3;5N(K*>#@BO;n>G2;%gm)kQinFV %qN^i=%s!ie[P]/MV/Ok'ms8K42/a6n4/Ctq]GY1)4R&OU5.!A_ %%T]X5\Lp%b1e92rV&oR!36X%tT,nY^kMj$6p@L"c:Hr'Ca-b;VZ"$J,./"J[.LNct[Z)_!.#btdV;B%QNW]3:9Z^U3ZT4I'*H;LJ %4oIuHWT`1U;aQ`i@nCN]m=Khp\d)_NT$2b.,G,01/EepTDK26BmJDXp`h'CKT)= %*gmcuIh!6:*9WZ!;&=g_NFl&./(:c$?g5:(X$PPe1T,K%lJKKfWEH;GlO,Q$<%VdG945:EuXGp`ob/&)Us<-DP`:]MYO0@6ORn %>'jR3PWtKO>fSp36$!_/0E%aL[&'$3D4pB^[D>l4`'EYE'YI'^<-%@I`[ZJQILP,qQ>AD-\i$f[%!d[WuM4G9c;Z`&Jif&7(EAj(oS`sXmB+QfC!(Knd9%0XhK,:g#(Nj3X!&t %Qq9hE_I_5*Oofjl%%\<7XdVQj8OG^Dmt.Y;$>9C`UWOgu1EV9t1GQbOp*hDBes"Z><:IgkD*9G\aR9)=H5C,Bf8.]_P+7Ru9o"u' %)'ikd+FC1WE'C`&6NT+sF3Hfq:fFmbXis9$2Mc9Q7X''[0@5@KH>W?b0,<9-'L(8tXnEM!_^/O>]6Z('T'JgSUW^?b1[u#])&8BU %(q_Xu5m.Pd)2"GAk.<5'M1a2Oar3n.;lb,Y>5^qdd9Crfpo?97U-@@W8?HJrFmj0!?9:-_g_H.bVVAqp+"j,Q/l#Fb]XOqL`FNM8 %'g-IiRRuP%54RoDYZAM]$(\dXY0%YAp(-WF*V"XXl:J8%S8mdEhX`dk((tP!?CK4lAFs:C&`5M!6<92M=fpNa[k-UP]]1oZAgK[# %r&A45A%Z3+]#-i=CF3QMJr5bpK;EC%;+7GHI0ECd`14$Rj^U>Qmt.tDXU?$E6^CS$U71JSN#/)))*'ie`d8Mdo1SDd'Ve';(b#j1 %oKl;V8^5U\K/ul>,AX!6eeV:?c0`iBCY&6tKSor#VA/eeV:_h8_)/LUWCCMg8Tc]hET>&muiLPLTjCV6kQS7cR*VBd`.NW8NMb %8t.85S[5oPp%rE>?j64WjaG(J>]tbGT^1f*0-jjkHA!ER"(A0B0k5]+?!-aRX=[$I\/a,hd6Z@N+=gXO\sX/KcF1[=04R7SFnE=4*'RVYZ18 %_4AMD.m&G5h&/*CDXnjec^("8PS;?r66G#Q:[cB6]dC_s,7^N`DK0Y,4lu:m>JZ&e<`F9EY`EZGWTkX9c/M4-$VA$3NH[3M_#8a?!LHu%='&L-Ka`nt0e %b3$IJJt/Vl<-MEJO)?2A%oEYOLIeCGdNf8HW#A$QCC>Q4,;FTT;r%Ce$WccNUW@l%Pg=ht"Z\;KW:$fr+5KC[+*/&ZZj.MWK%KFHUQjl"X9r`39'pi\IZja=8PE#))0M7= %-]Z(:SiC/X]Du'I20AL7X>)j,hLA7Z'9!sGVOkFdgt;d@5]_+m3n6>h16apjZ53<#V?b92;.nH2DC9Dq:5^X+^I-oU5j;-i.bj\h %Nt2uQq"B-!U$O56eF-i#?7-h8s6+#e)ZQIQX7U`FY><2Fd)^_S&q7cl0,q5\g`XB^eC=%K:>[nA9j-5JqZDe7A&4eQB6rZnZEa %poNJVCX(KbTXBJ2'_ihd#J\"f*96'QoVs&q?d*9+c52\T0&l;5kg"IHRB1JlN/Ptp_aTj;PJGP[%DV8)XG%BooJ%]#&*0J:`MR'K'V@qu7@`?7E^h!#8e3MnfTon< %;:`T&0)?-)B]3d>b>Gt'4D6,^AZNoi-+com#4i&9guKZm(MdaO)0fV`NWgr@HPif2 %)k@&0dr'>Ej\mZn>dU^X+KOKq@2Ql][!K0M#V'QROh-J/d<@fM!N$[2?A3>&SiDO%"Z'8\GJRI2`T1sf?*9QBF'#7842Vc1M)WRD %"1Fcq$F8pGg4'72-!IafC>pm,.fK5"J.SW#Lb,RQDh%YRY?ueYp0[gkfC,s"iCh[!/pBg+HgaQPXp6R8'!*W=ag0,]SQbO$6+3Mq %H5E[5="NsopXqFelV?HJ7aSXXlK=qPC[7gWl^Z>'+2U>j1RNZ!MA18AY8=pCK6t:V.NHq'%rZarH@=ViDF:TD;6i^dqYH,L.5Z%X %glY$b?m^S'ls.[`+;B`]'E1ncP!@iC/[*G35WFP,I(IHEin\ %I7G,r%lYR*Rr7[$'kGb-Fljp1h'eS+Y$1*`VUa#'%X(V?UR-:d^ih#gkLa"\Fe?]+1?XFRPll-%=%F^m+`HT;c5PKWj2-UYb=)uY %d;s`T.U@=tf$CbWq,Xe7ImgL%a,f]lG0#pfi3p1&"NhXr6a")"Cn'a]Dqjhd&DV-9r]&iOh7Zk@,1lo*Yo>M=qsG#MmkTG*:iHI1r)B,3tX!p":;cVDu=[1#? %;&I5QYL`*9)qOWn*`hj3M:96t]etsQ>uR>K%8LkaY_p:h/LgK6XFqg/:.PQs**r#'8^4\)2CJdDQGKh;`E`K\DJ.u)YqB_G/#@Os %@WfHCH37:urHGMu\K3DZ'A'?X_lRs'dRpQ!V6lg<0&3ohPETMn',S/,@W(iH[hR!3E\/4XaW$pR;#/-1[Hsmbl1,'k+8%3*obPo %PO(m],eA8GBj4VFd8P[42gI^ZRWo3g['m2Jj1292YLdtn*82!)PkD^ScL.4():;JtLgJt!EG.h[:u:sG3.#_PAjfk:,WE(+Nm5d% %ic*G&nW))RHX"+[\a,ErWoc>H+8aKT&G>+KC'B`W2Q&-/3B7[TOlI'X>?J.km<5qOm!D*8RLrPaot$-sB]^ao3FH[kQ?gbh_`k_SPEcjAKXK/s=UQa?KbRb;7Bc;7pZ+[k %..;P5T\W1B0r2<:b[%F@/b`d#WbBlUr]#7GZ=ZL/h^pI#:HlA4.JW*6b/_mOF*E)aN,Gt*\C:2(20]$2!'S\@%qR#e2?:#Gj.m*3Y@&T*gd3dkpk %EAO>@o"Ok=fq" %RoP-4^,N.,),W\FhtuI#cH2LeD&66=I;`4L+&PIr^A#\$S!,]S)PJAANMBqLc0,MWa3buMGCESOc>QaAFSajuG!;XX2LY%TZSs7I %7^Q<#l1DYtmELFob5:$;B6R,%N+f8rdd4cp3+-hDIT-$lAonc)`mGlLDgp8rDR3NBdrud/PS5B[C^2eL]]]5jG%Y@1GW%cK/pe)G %EQ1[!g+s@=dAH6c;0M)3c#=_@/C\`.q,"6LqOq5Oa\ahU,1sk4YSeV8KK(DSXfJRS$=5+WF/()BV.]"KUW/$;g.4/eg-Qlm/Zc5. %hCdAU09pHGKKel>(V1J]7=!d+$[m-WLc0$"BJ-]C\^]J0;+oN$W1Xqs<*SR]XG&MV)POEX2F"CQ)N-^\?![U)?fgS'?a=b55LLkbB(eZrO>9ZY=`:MQ_`c=OmED@le^1Q3I&, %C&9Va@utN/c8K5UXY$VW_X6K[b:WDSde70!lT8mUO)>oaAldfWiGY&`US9rfmEi=XdDK)R25Aj-]i`SJ[nA5KdG"1q^P?YGc(g8f %H=8p+&s$AQUHPGgi1]Al*EoGRTT)o&S=bC)c5a6G50@&2Etc08F#G8CdO$&57=!d+$[m-OLtl#P]kZ#<($Yl[jn6[cTpr>=^pctk %O.j]k5s'.r.Jmdq@EfF&GFi,YWGe-3+%'2g=UTY"gP@aP%b18f;Fc=qe0hSc0cRef%=r/Au-!8K"U-OINRB(S?5-0WpOh$D/ere]WUcA\fJulJ%N)\ %(olYmUQfC1ZB*QPei3igY<$>deDGZ_AUS2Co[.M#gQk\g&-jW4Q3Qk/'?$89f_$E-jn\LEt7o&2s:$n50@&2@m7HZ&[6!ffSGnYJrQ_']^N7^5.Y`%S+U7P)+U]dTW0S!/b@TQ`:Qeo#u"nb^Vo`qnaJ_Sk0d)Fe2+B4!5%<%YdnjiYA2CWiu3D5P)t3(?3*9nA*6C`,D?BEn`H_QhB#Leg;g=/V^uiHjZC[USISu3,9iX#+pJKnL7l- %ar!`dbH^%@XhOOFmjpA"*2M$q=@.B](/%f$FfHBo>gPbREIk='c#.nSdKc6#iFX@*KL;Ujk(/1G!80#+*/7:3,QrGuFa=I(5 %^0@g?`O'Y!>g3O)Q+J0>rB5piR'a3"q9Y)*%k.sh^sH4pQ+LG+bs*I"Yjs'=PXZsWFA:dOX+S"\'rlDm!AN`S;5a$UjK=;<^]*fiePm$kp %ShK3f`?K?h]n..F(^!9tU/"%LLFYKiJhdAX.Uj(nLU)AfcqZ$7lIEV]7aSJLFUTeOBMWri=Ag'?K0d;S>;?tnQq':COM`0Tr:VZr %..qQ>Cr<>LE7p4u[O#`BR3'H7CmTaO?L?'$gChCukofeVjuQYu@RcB:e?10kHM^-5n`C/uUK< %*BY[B[:-AFW;)d2q.`dc#:PCI>,I4%.L%\E,5^h6mIC\#^[;d@O9gC,aEaFh5OC/aBZ0*d'ubI40Y18[rnb'R6HBiVTNSK99mY:H %$eCQ5=0:)iVd-eM@Hj;#['in7]qrZ3X3 %U;8XgKLsKSI)_G9+NXBP:/["A\da&P)-6kmHka2R/OR=CTj#b;J+smbER=o*Sk(j=T9<5YpgN-[8GnDBVf2cD6Q6C"\"5!VK1]YD %jW?2!M?oT;]S?Lfk$Y'GA(]BdKLRIl>8!PuI29bt(@`BfcZTc_-BK_6RKh`'&UpQPUPc*]?W5"%$8a'p?qQ'0;1JOPY6b!^9mbtd %r7<*or;=NLJ^-eP[O]h$Bk9-fGLDMUq*rRGde^566$EpHQtT+GFL,L.dphpkE&:?9DfD:dqR#mp>oDq'Fh0/-#?)OGN;E3J7\1We %!p'$9C=:hFlN(+Lk'T=fSlBNm"/'r5b&T=@=Up23ZWGm3Ess/aq1?dj"1tLj3\/l?os1K*Ofs1uY5+Br#qOG*pS(*89Iqj#-'edr %Eh9Z7"@DEmrmq)JDuTN-VsjW`LVLL:J,.Wurm1'4q1l`bbBO!Wit$Y8o$9OKpYUFEqsKMp`6%u:cgWl3s883*IY+d$nFkUIkO1S0~> %AI9_PrivateDataEnd \ No newline at end of file diff --git a/doc/img/prog_flow.png b/doc/img/prog_flow.png new file mode 100644 index 0000000000000000000000000000000000000000..20892e3cbd40e2df6ad74f358f8fb21cf2e0aa74 GIT binary patch literal 24099 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 z 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 +Vendor: %{?_vendorinfo:%{_vendorinfo}}%{!?_vendorinfo:The Enlightenment Project (http://www.enlightenment.org/)} +Distribution: %{?_distribution:%{_distribution}}%{!?_distribution:%{_vendor}} +#BuildSuggests: xorg-x11-devel, XFree86-devel, libX11-devel, c-ares-devel +BuildRequires: libjpeg-devel, openssl-devel %{?breq_lib_ecore_directfb} +BuildRequires: curl-devel, evas-devel, eet-devel %{?breq_lib_ecore_sdl} +BuildRoot: %{_tmppath}/%{name}-%{version}-root + +%description +Ecore is the event/X abstraction layer that makes doing selections, +Xdnd, general X stuff, event loops, timeouts and idle handlers fast, +optimized, and convenient. It's a separate library so anyone can make +use of the work put into Ecore to make this job easy for applications. + +%package devel +Summary: Ecore headers and development libraries. +Group: Development/Libraries +Requires: %{name} = %{version} +Requires: curl-devel, openssl-devel, evas-devel, eet-devel +Requires: ecore-con, ecore-evas, ecore-file, ecore-ipc +Requires: ecore-x %{?with_lib_ecore_fb:ecore-fb} %{?with_lib_ecore_directfb:ecore-directfb} + +%description devel +Ecore development files + +%package con +Summary: Ecore Connection Library +Group: Development/Libraries +Requires: %{name} = %{version} + +%description con +Ecore Connection Library + +%if %{with lib_ecore_directfb} +%package directfb +Summary: Ecore DirectFB system functions +Group: Development/Libraries +Requires: %{name} = %{version} +%description directfb +Ecore DirectFB system functions +%endif + +%package evas +Summary: Ecore Evas Wrapper Library +Group: Development/Libraries +Requires: %{name} = %{version} + +%description evas +Ecore Evas Wrapper Library + +%if %{with lib_ecore_fb} +%package fb +Summary: Ecore frame buffer system functions +Group: Development/Libraries +Requires: %{name} = %{version} +%description fb +Ecore frame buffer system functions +%endif + +%package file +Summary: Ecore File Library +Group: Development/Libraries +Requires: %{name} = %{version} + +%description file +Ecore File Library + +%if %{with lib_ecore_imf} +%package imf +Summary: Ecore IMF functions +Group: Development/Libraries +Requires: %{name} = %{version} +%description imf +Ecore IMF functions +%endif + +%package input +Summary: Ecore input functions +Group: Development/Libraries +Requires: %{name} = %{version} + +%description input +Ecore input functions + +%package ipc +Summary: Ecore inter-process communication functions +Group: Development/Libraries +Requires: %{name} = %{version} + +%description ipc +Ecore inter-process communication functions + +%package x +Summary: Ecore functions for dealing with the X Windows System +Group: Development/Libraries +Requires: %{name} = %{version} + +%description x +Ecore functions for dealing with the X Windows System + +%prep +%setup -q + +%build +CFLAGS="-I/usr/kerberos/include -I/usr/X11R6/include/X11/extensions" +LDFLAGS="-L/usr/kerberos/lib -L/usr/X11R6/%{_lib}" +export CFLAGS LDFLAGS +%{configure} --prefix=%{_prefix} \ + %{?ac_with_lib_ecore_directfb} \ + %{?ac_with_lib_ecore_fb} \ + %{?ac_with_lib_ecore_imf} \ + %{?ac_with_lib_ecore_sdl} + +%{__make} %{?_smp_mflags} %{?mflags} + +%install +%{__make} %{?mflags_install} DESTDIR=$RPM_BUILD_ROOT install +%{find_lang} %{name} + +%post +/sbin/ldconfig || : + +%postun +/sbin/ldconfig || : + +%clean +test "x$RPM_BUILD_ROOT" != "x/" && rm -rf $RPM_BUILD_ROOT + +%files -f %{name}.lang +%defattr(-, root, root) +%doc AUTHORS COPYING* README* +%{_libdir}/libecore*.so.* + +%files devel +%defattr(-, root, root) +%doc doc/html +%{_libdir}/*.so +%{_libdir}/ecore/immodules/*.so +%{_libdir}/ecore/immodules/*.la +%{_libdir}/*.la +%{_libdir}/*.a +%{_libdir}/pkgconfig/* +#%{_datadir}/aclocal/* +%{_includedir}/ecore-1/*.h + +%files con +%defattr(-, root, root) +%{_libdir}/libecore_con*.so.* + +%if %{with lib_ecore_directfb} +%files directfb +%defattr(-, root, root) +%{_libdir}/libecore_directfb*.so.* +%endif + +%files evas +%defattr(-, root, root) +%{_libdir}/libecore_evas*.so.* + +%if %{with lib_ecore_fb} +%files fb +%defattr(-, root, root) +%{_libdir}/libecore_fb*.so.* +%endif + +%files file +%defattr(-, root, root) +%{_libdir}/libecore_file*.so.* + +%if %{with lib_ecore_imf} +%files imf +%defattr(-, root, root) +%{_libdir}/libecore_imf*.so.* +%endif + +%files input +%defattr(-, root, root) +%{_libdir}/libecore_input*.so.* + +%files ipc +%defattr(-, root, root) +%{_libdir}/libecore_ipc*.so.* + +%files x +%defattr(-, root, root) +%{_libdir}/libecore_x*.so.* diff --git a/ecore.supp b/ecore.supp new file mode 100644 index 0000000..ff7bb0a --- /dev/null +++ b/ecore.supp @@ -0,0 +1,46 @@ +# $Id$ +# valgrind suppression file for Ecore +# +{ + BogusLeakError + Memcheck:Leak + fun:malloc + obj:/usr/X11R6/lib/libX11.so.6.2 + fun:_XmbTextPropertyToTextList + fun:XmbTextPropertyToTextList +} +{ + bogus2 + Memcheck:Param + write(buf) + obj:/lib/ld-2.3.3.so + fun:_X11TransWrite + obj:/usr/X11R6/lib/libX11.so.6.2 + fun:_XReply +} +{ + bogus3 + Memcheck:Cond + obj:/usr/X11R6/lib/libX11.so.6.2 + obj:/usr/X11R6/lib/libX11.so.6.2 + obj:/usr/X11R6/lib/libX11.so.6.2 + fun:_XlcCreateLocaleDataBase +} +{ + bogus4 + Memcheck:Param + write(buf) + obj:/lib/ld-2.3.3.so + fun:_X11TransWrite + obj:/usr/X11R6/lib/libX11.so.6.2 + fun:_XFlush +} +{ + blah, blah, xlib sucks + Memcheck:Param + writev(vector[...]) + obj:/lib/ld-2.3.3.so + obj:/usr/X11R6/lib/libX11.so.6.2 + fun:_X11TransWritev + fun:_XSend +} diff --git a/m4/ac_abstract_socket.m4 b/m4/ac_abstract_socket.m4 new file mode 100644 index 0000000..c4f0b74 --- /dev/null +++ b/m4/ac_abstract_socket.m4 @@ -0,0 +1,41 @@ +dnl AC_ABSTRACT_SOCKET_TEST(ACTION_IF_FOUND, ACTION_IF_NOT_FOUND) +dnl test if a system supports the abstract socket namespace +dnl by rephorm +AC_DEFUN([AC_ABSTRACT_SOCKET_TEST], [ +AC_MSG_CHECKING(abstract sockets) +AC_LANG_PUSH(C) +AC_RUN_IFELSE([AC_LANG_PROGRAM( +[[ +// headers +#include +#include +#include +#include +#include +#include +]], +[[ +// main fn +#define ABS_SUN_LEN(s, path) (strlen(path) + 1 + (size_t)(((struct sockaddr_un *)NULL)->sun_path)) + int fd; + struct sockaddr_un sock; + char *tmp; + char *name = "/ecore/dbus/abstract/test"; + + sock.sun_family = AF_UNIX; + snprintf(sock.sun_path, sizeof(sock.sun_path), ".%s", name); + sock.sun_path[0] = '\0'; + fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (bind(fd, (struct sockaddr *)&sock, ABS_SUN_LEN(&sock, name)) < 0) + { + printf("Failed to bind to abstract socket.\n"); + exit(1); + } + + printf ("connected\n"); + exit(0); +]])], +[$1], +[$2]) +]) + diff --git a/m4/ac_attribute.m4 b/m4/ac_attribute.m4 new file mode 100644 index 0000000..23479a9 --- /dev/null +++ b/m4/ac_attribute.m4 @@ -0,0 +1,47 @@ +dnl Copyright (C) 2004-2008 Kim Woelders +dnl Copyright (C) 2008 Vincent Torri +dnl That code is public domain and can be freely used or copied. +dnl Originally snatched from somewhere... + +dnl Macro for checking if the compiler supports __attribute__ + +dnl Usage: AC_C___ATTRIBUTE__ +dnl call AC_DEFINE for HAVE___ATTRIBUTE__ and __UNUSED__ +dnl if the compiler supports __attribute__, HAVE___ATTRIBUTE__ is +dnl defined to 1 and __UNUSED__ is defined to __attribute__((unused)) +dnl otherwise, HAVE___ATTRIBUTE__ is not defined and __UNUSED__ is +dnl defined to nothing. + +AC_DEFUN([AC_C___ATTRIBUTE__], +[ + +AC_MSG_CHECKING([for __attribute__]) + +AC_CACHE_VAL([ac_cv___attribute__], + [AC_TRY_COMPILE( + [ +#include + +int func(int x); +int foo(int x __attribute__ ((unused))) +{ + exit(1); +} + ], + [], + [ac_cv___attribute__="yes"], + [ac_cv___attribute__="no"] + )]) + +AC_MSG_RESULT($ac_cv___attribute__) + +if test "x${ac_cv___attribute__}" = "xyes" ; then + AC_DEFINE([HAVE___ATTRIBUTE__], [1], [Define to 1 if your compiler has __attribute__]) + AC_DEFINE([__UNUSED__], [__attribute__((unused))], [Macro declaring a function argument to be unused]) + else + AC_DEFINE([__UNUSED__], [], [Macro declaring a function argument to be unused]) +fi + +]) + +dnl End of ac_attribute.m4 diff --git a/m4/ac_path_generic.m4 b/m4/ac_path_generic.m4 new file mode 100644 index 0000000..d427241 --- /dev/null +++ b/m4/ac_path_generic.m4 @@ -0,0 +1,137 @@ +dnl @synopsis AC_PATH_GENERIC(LIBRARY [, MINIMUM-VERSION [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +dnl +dnl Runs a LIBRARY-config script and defines LIBRARY_CFLAGS and LIBRARY_LIBS +dnl +dnl The script must support `--cflags' and `--libs' args. +dnl If MINIMUM-VERSION is specified, the script must also support the +dnl `--version' arg. +dnl If the `--with-library-[exec-]prefix' arguments to ./configure are given, +dnl it must also support `--prefix' and `--exec-prefix'. +dnl (In other words, it must be like gtk-config.) +dnl +dnl For example: +dnl +dnl AC_PATH_GENERIC(Foo, 1.0.0) +dnl +dnl would run `foo-config --version' and check that it is at least 1.0.0 +dnl +dnl If so, the following would then be defined: +dnl +dnl FOO_CFLAGS to `foo-config --cflags` +dnl FOO_LIBS to `foo-config --libs` +dnl +dnl At present there is no support for additional "MODULES" (see AM_PATH_GTK) +dnl (shamelessly stolen from gtk.m4 and then hacked around a fair amount) +dnl +dnl @author Angus Lees + +AC_DEFUN([AC_PATH_GENERIC], +[dnl +dnl we're going to need uppercase, lowercase and user-friendly versions of the +dnl string `LIBRARY' +pushdef([UP], translit([$1], [a-z], [A-Z]))dnl +pushdef([DOWN], translit([$1], [A-Z], [a-z]))dnl + +dnl +dnl Get the cflags and libraries from the LIBRARY-config script +dnl +AC_ARG_WITH(DOWN-prefix, + [ --with-]DOWN[-prefix=PFX Prefix where $1 is installed (optional)], + DOWN[]_config_prefix="$withval", DOWN[]_config_prefix="") +AC_ARG_WITH(DOWN-exec-prefix, + [ --with-]DOWN[-exec-prefix=PFX Exec prefix where $1 is installed (optional)], + DOWN[]_config_exec_prefix="$withval", DOWN[]_config_exec_prefix="") + + if test x$DOWN[]_config_exec_prefix != x ; then + DOWN[]_config_args="$DOWN[]_config_args --exec-prefix=$DOWN[]_config_exec_prefix" + if test x${UP[]_CONFIG+set} != xset ; then + UP[]_CONFIG=$DOWN[]_config_exec_prefix/bin/DOWN-config + fi + fi + if test x$DOWN[]_config_prefix != x ; then + DOWN[]_config_args="$DOWN[]_config_args --prefix=$DOWN[]_config_prefix" + if test x${UP[]_CONFIG+set} != xset ; then + UP[]_CONFIG=$DOWN[]_config_prefix/bin/DOWN-config + fi + fi + + AC_PATH_PROG(UP[]_CONFIG, DOWN-config, no) + ifelse([$2], , + AC_MSG_CHECKING(for $1), + AC_MSG_CHECKING(for $1 - version >= $2) + ) + no_[]DOWN="" + if test "$UP[]_CONFIG" = "no" ; then + no_[]DOWN=yes + else + UP[]_CFLAGS="`$UP[]_CONFIG $DOWN[]_config_args --cflags`" + UP[]_LIBS="`$UP[]_CONFIG $DOWN[]_config_args --libs`" + ifelse([$2], , ,[ + DOWN[]_config_major_version=`$UP[]_CONFIG $DOWN[]_config_args \ + --version | sed 's/[[^0-9]]*\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\).*/\1/'` + DOWN[]_config_minor_version=`$UP[]_CONFIG $DOWN[]_config_args \ + --version | sed 's/[[^0-9]]*\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\).*/\2/'` + DOWN[]_config_micro_version=`$UP[]_CONFIG $DOWN[]_config_args \ + --version | sed 's/[[^0-9]]*\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\).*/\3/'` + DOWN[]_wanted_major_version="regexp($2, [\<\([0-9]*\)], [\1])" + DOWN[]_wanted_minor_version="regexp($2, [\<\([0-9]*\)\.\([0-9]*\)], [\2])" + DOWN[]_wanted_micro_version="regexp($2, [\<\([0-9]*\).\([0-9]*\).\([0-9]*\)], [\3])" + + # Compare wanted version to what config script returned. + # If I knew what library was being run, i'd probably also compile + # a test program at this point (which also extracted and tested + # the version in some library-specific way) + if test "$DOWN[]_config_major_version" -lt \ + "$DOWN[]_wanted_major_version" \ + -o \( "$DOWN[]_config_major_version" -eq \ + "$DOWN[]_wanted_major_version" \ + -a "$DOWN[]_config_minor_version" -lt \ + "$DOWN[]_wanted_minor_version" \) \ + -o \( "$DOWN[]_config_major_version" -eq \ + "$DOWN[]_wanted_major_version" \ + -a "$DOWN[]_config_minor_version" -eq \ + "$DOWN[]_wanted_minor_version" \ + -a "$DOWN[]_config_micro_version" -lt \ + "$DOWN[]_wanted_micro_version" \) ; then + # older version found + no_[]DOWN=yes + echo -n "*** An old version of $1 " + echo -n "($DOWN[]_config_major_version" + echo -n ".$DOWN[]_config_minor_version" + echo ".$DOWN[]_config_micro_version) was found." + echo -n "*** You need a version of $1 newer than " + echo -n "$DOWN[]_wanted_major_version" + echo -n ".$DOWN[]_wanted_minor_version" + echo ".$DOWN[]_wanted_micro_version." + echo "***" + echo "*** If you have already installed a sufficiently new version, this error" + echo "*** probably means that the wrong copy of the DOWN-config shell script is" + echo "*** being found. The easiest way to fix this is to remove the old version" + echo "*** of $1, but you can also set the UP[]_CONFIG environment to point to the" + echo "*** correct copy of DOWN-config. (In this case, you will have to" + echo "*** modify your LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf" + echo "*** so that the correct libraries are found at run-time)" + fi + ]) + fi + if test "x$no_[]DOWN" = x ; then + AC_MSG_RESULT(yes) + ifelse([$3], , :, [$3]) + else + AC_MSG_RESULT(no) + if test "$UP[]_CONFIG" = "no" ; then + echo "*** The DOWN-config script installed by $1 could not be found" + echo "*** If $1 was installed in PREFIX, make sure PREFIX/bin is in" + echo "*** your path, or set the UP[]_CONFIG environment variable to the" + echo "*** full path to DOWN-config." + fi + UP[]_CFLAGS="" + UP[]_LIBS="" + ifelse([$4], , :, [$4]) + fi + AC_SUBST(UP[]_CFLAGS) + AC_SUBST(UP[]_LIBS) + + popdef([UP]) + popdef([DOWN]) +]) diff --git a/m4/check_x_extension.m4 b/m4/check_x_extension.m4 new file mode 100644 index 0000000..a15120c --- /dev/null +++ b/m4/check_x_extension.m4 @@ -0,0 +1,40 @@ +dnl use: ECORE_CHECK_X_EXTENSION(Foo, header, lib, func, want) +AC_DEFUN([ECORE_CHECK_X_EXTENSION], +[ +pushdef([UP], translit([$1], [a-z], [A-Z]))dnl +pushdef([DOWN], translit([$1], [A-Z], [a-z]))dnl + +UP[]_CFLAGS="" +UP[]_LIBS="" +use_[]DOWN="no" + +if test "x$5" != "xno"; then + SAVE_CFLAGS=$CFLAGS + CFLAGS="$x_cflags $x_includes" + AC_CHECK_HEADER(X11/extensions/$2, + [ + AC_CHECK_LIB($3, $4, + [ + AC_DEFINE(ECORE_[]UP, 1, [Build support for $1]) + UP[]_LIBS="-l$3" + use_[]DOWN="yes" + ], + [ use_[]DOWN="no" ], + [ $x_libs ] + ) + ], + [ use_[]DOWN="no" ], + [ #include ] + ) + CFLAGS=$SAVE_CFLAGS +else + use_[]DOWN="no" + AC_MSG_NOTICE([$1 support disabled]) +fi + +AC_SUBST(UP[]_CFLAGS) +AC_SUBST(UP[]_LIBS) + +popdef([UP]) +popdef([DOWN]) +]) diff --git a/m4/ecore_check_module.m4 b/m4/ecore_check_module.m4 new file mode 100644 index 0000000..01c4e0e --- /dev/null +++ b/m4/ecore_check_module.m4 @@ -0,0 +1,97 @@ +dnl use: ECORE_CHECK_MODULE(Foo, default-enabled, description[, dependency[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]]) +AC_DEFUN([ECORE_CHECK_MODULE], +[ +m4_pushdef([UP], m4_translit([[$1]], [-a-z], [_A-Z]))dnl +m4_pushdef([DOWN], m4_translit([[$1]], [-A-Z], [_a-z]))dnl + +have_ecore_[]m4_defn([DOWN])=no +ecore_[]m4_defn([DOWN])[]_cflags= +ecore_[]m4_defn([DOWN])[]_libs= +want_module=$2 + +AC_ARG_ENABLE(ecore-$1, + [AC_HELP_STRING( + [--enable-ecore-$1], + [enable the ecore_]m4_defn([DOWN])[ module])], + [ + if test "x${enableval}" = "xyes" ; then + want_module="yes" + else + want_module="no" + fi + ], + []) + +AC_MSG_CHECKING([whether Ecore_$3 module is to be built]) + +if test "x${want_module}" = "xyes" ; then + if test "x$4" = "x" || test "x$4" = "xyes" ; then + AC_DEFINE([BUILD_ECORE_]m4_defn([UP]), [1], [Build Ecore_$3 Module]) + have_ecore_[]m4_defn([DOWN])="yes" + ecore_[]m4_defn([DOWN])[]_libs="-lecore_[]m4_defn([DOWN])" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no (dependency failed)]) + fi +else + AC_MSG_RESULT([no]) +fi + +AM_CONDITIONAL([BUILD_ECORE_]UP, [test "x$have_ecore_]DOWN[" = "xyes"]) + +AS_IF([test "x$have_ecore_[]m4_defn([DOWN])" = "xyes"], [$5], [$6]) + +AC_SUBST(ecore_[]m4_defn([DOWN])[]_cflags) +AC_SUBST(ecore_[]m4_defn([DOWN])[]_libs) + +m4_popdef([UP]) +m4_popdef([DOWN]) +]) + +dnl use: ECORE_EVAS_CHECK_MODULE_FULL(foo-bar, evas-module, want, description, backend[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +AC_DEFUN([ECORE_EVAS_CHECK_MODULE_FULL], +[ +m4_pushdef([UP], m4_translit([[$1]], [-a-z], [_A-Z]))dnl +m4_pushdef([DOWN], m4_translit([[$1]], [-A-Z], [_a-z]))dnl + +have_ecore_evas_[]m4_defn([DOWN])="no" +want_module="$3" + +AC_ARG_ENABLE(ecore-evas-$1, + [AC_HELP_STRING( + [--enable-ecore-evas-$1], + [enable $4 support in the ecore_evas module.])], + [ + if test "x${enableval}" = "xyes" ; then + want_module="yes" + else + want_module="no" + fi + ], + []) + +AC_MSG_CHECKING([whether ecore_evas $4 support is to be built]) +AC_MSG_RESULT([${want_module}]) + +if test "x$5" = "xyes" && \ + test "x$have_ecore_evas" = "xyes" && \ + test "x$want_module" = "xyes" ; then + PKG_CHECK_EXISTS([evas-$2], + [ + AC_DEFINE([BUILD_ECORE_EVAS_]m4_defn([UP]), [1], [Support for $4 Engine in Ecore_Evas]) + have_ecore_evas_[]m4_defn([DOWN])="yes" + ]) +fi + +AC_MSG_CHECKING([whether ecore_evas $4 support is built]) +AC_MSG_RESULT([$have_ecore_evas_]m4_defn([DOWN])) + +AS_IF([test "x$have_ecore_evas_[]m4_defn([DOWN])" = "xyes"], [$6], [$7]) + +m4_popdef([UP]) +m4_popdef([DOWN]) +]) + +dnl use: ECORE_EVAS_CHECK_MODULE(foo-bar, want, description, backend[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +AC_DEFUN([ECORE_EVAS_CHECK_MODULE], +[ECORE_EVAS_CHECK_MODULE_FULL([$1], [$1], [$2], [$3], [$4], [$5], [$6])]) diff --git a/m4/ecore_check_options.m4 b/m4/ecore_check_options.m4 new file mode 100644 index 0000000..d20adca --- /dev/null +++ b/m4/ecore_check_options.m4 @@ -0,0 +1,331 @@ +dnl use: ECORE_CHECK_POLL(default-enabled[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +AC_DEFUN([ECORE_CHECK_POLL], +[ +_ecore_want_poll=$1 +_ecore_have_poll="no" + +AC_ARG_ENABLE(poll, + [AC_HELP_STRING([--disable-poll], [disable poll in the ecore_file module])], + [ + if test "x${enableval}" = "xyes" ; then + _ecore_want_poll="yes" + else + _ecore_want_poll="no" + fi + ]) + +AC_MSG_CHECKING(whether polling is to be used for filemonitoring) +AC_MSG_RESULT(${_ecore_want_poll}) + +if test "x${_ecore_want_poll}" = "xyes" ; then + AC_DEFINE([HAVE_POLL], [1], [ File monitoring with polling ]) + _ecore_have_poll="yes" +fi + +if test "x${_ecore_have_poll}" = "xyes" ; then + m4_default([$2], [:]) +else + m4_default([$3], [:]) +fi +]) + +dnl use: ECORE_CHECK_INOTIFY(default-enabled[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +AC_DEFUN([ECORE_CHECK_INOTIFY], +[ +_ecore_want_inotify=$1 +_ecore_have_inotify="no" + +dnl We need to check if the right inotify version is accessible +_ecore_want_inotify="yes" +AC_ARG_ENABLE(inotify, + [AC_HELP_STRING([--disable-inotify], [disable inotify in the ecore_file module])], + [ + if test "x${enableval}" = "xyes" ; then + _ecore_want_inotify="yes" + else + _ecore_want_inotify="no" + fi + ]) + +AC_MSG_CHECKING(whether inotify is to be used for filemonitoring) +AC_MSG_RESULT($_ecore_want_inotify) + +dnl It is hard to find a good test on how to check the correct +dnl inotify version. They changed the headers a lot. +dnl in kernel 2.6.13 __NR_inotify_init was added to the defined syscalls +dnl in asm/unistd.h and IN_MOVE_SELF was added to linux/inotify.h +dnl so with this check you need a very new kernel and kernel-headers! + +if test "x${_ecore_want_inotify}" = "xyes" ; then + AC_CHECK_LIB([c], [inotify_init], + [ + AC_DEFINE(HAVE_INOTIFY, 1, [ File monitoring with Inotify ]) + AC_DEFINE(HAVE_SYS_INOTIFY, 1, [ File monitoring with Inotify - sys/inotify.h ]) + _ecore_have_inotify="yes" + ], + [ + AC_TRY_COMPILE( + [ + #include + #include + ], + [int a = __NR_inotify_init; int b = IN_MOVE_SELF;], + [ + AC_DEFINE([HAVE_INOTIFY], [1], [ File monitoring with Inotify ]) + _ecore_have_inotify="yes" + ], + [_ecore_have_inotify="no"]) + ]) +fi + +if test "x$_ecore_have_inotify" = "xyes" ; then + m4_default([$2], [:]) +else + m4_default([$3], [:]) +fi +]) + +dnl use: ECORE_CHECK_NOTIFY_WIN32(default-enabled[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +AC_DEFUN([ECORE_CHECK_NOTIFY_WIN32], +[ +_ecore_want_notify_win32=$1 +_ecore_have_notify_win32="no" + +AC_ARG_ENABLE(notify-win32, + [AC_HELP_STRING([--disable-notify-win32], [disable Windows notification in the ecore_file module])], + [ + if test "x${enableval}" = "xyes" ; then + _ecore_want_notify_win32="yes" + else + _ecore_want_notify_win32="no" + fi + ]) + +AC_MSG_CHECKING(whether Windows notification is to be used for filemonitoring) +AC_MSG_RESULT(${_ecore_want_notify_win32}) + +if test "x${_ecore_want_notify_win32}" = "xyes" ; then + AC_DEFINE([HAVE_NOTIFY_WIN32], [1], [ File monitoring with Windows notification ]) + _ecore_have_notify_win32="yes" +fi + +if test "x${_ecore_have_notify_win32}" = "xyes" ; then + m4_default([$2], [:]) +else + m4_default([$3], [:]) +fi +]) + +dnl use: ECORE_CHECK_CURL(default-enabled[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +AC_DEFUN([ECORE_CHECK_CURL], +[ +_ecore_want_curl=$1 +_ecore_have_curl="no" + +AC_ARG_ENABLE([curl], + [AC_HELP_STRING([--disable-curl], [disable curl support])], + [ + if test "x${enableval}" = "xyes" ; then + _ecore_want_curl="yes" + else + _ecore_want_curl="no" + fi + ]) + +if test "x${_ecore_want_curl}" = "xyes" ; then + PKG_CHECK_MODULES(CURL, libcurl, + [ + AC_DEFINE(HAVE_CURL, 1, [ Downloading with CURL ]) + _ecore_have_curl="yes" + ], + [_ecore_have_curl="no"]) +fi + +if test "x$_ecore_have_curl" = "xyes" ; then + m4_default([$2], [:]) +else + m4_default([$3], [:]) +fi +]) + +dnl use: ECORE_CHECK_GNUTLS(default-enabled[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +AC_DEFUN([ECORE_CHECK_GNUTLS], +[ +_ecore_want_gnutls=$1 +_ecore_have_gnutls="no" + +AC_ARG_ENABLE([gnutls], + [AC_HELP_STRING([--disable-gnutls], [disable gnutls support])], + [ + if test "x${enableval}" = "xyes" ; then + _ecore_want_gnutls="yes" + else + _ecore_want_gnutls="no" + fi + ]) + +if test "x${_ecore_want_gnutls}" = "xyes" -o "x${_ecore_want_gnutls}" = "xauto" ; then + PKG_CHECK_MODULES([TLS], [gnutls >= 2.10.2], + [ + AC_DEFINE([USE_GNUTLS], [1], [Use GnuTLS]) + _ecore_have_gnutls="yes" + ], + [_ecore_have_gnutls="no"]) + # for ecore_con_ssl.c + PKG_CHECK_MODULES([TLS2], [gnutls >= 2.10.2], + [AC_DEFINE(USE_GNUTLS2, 1, [Use GnuTLS 2 or higher])], + [dummy="no"]) + if test "x$_ecore_have_gnutls" = "xyes";then + AC_PATH_GENERIC([libgcrypt], [], [_ecore_have_gnutls="yes"], [_ecore_have_gnutls="no"]) + if test "x${_ecore_have_gnutls}" = "xyes" ; then + TLS_CFLAGS="${TLS_CFLAGS} ${LIBGCRYPT_CFLAGS}" + TLS_LIBS="${TLS_LIBS} ${LIBGCRYPT_LIBS}" + fi + fi + +fi + +if test "x$_ecore_have_gnutls" = "xyes" ; then + ifelse([$2], , :, [$2]) +else + ifelse([$3], , :, [$3]) +fi +]) + +dnl use: ECORE_CHECK_OPENSSL(default-enabled[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +AC_DEFUN([ECORE_CHECK_OPENSSL], +[ +_ecore_want_openssl=$1 +_ecore_have_openssl="no" + +AC_ARG_ENABLE(openssl, + [AC_HELP_STRING([--disable-openssl], [disable openssl support])], + [ + if test "x${enableval}" = "xyes" ; then + _ecore_want_openssl="yes" + else + _ecore_want_openssl="no" + fi + ]) + +if test "x${_ecore_have_gnutls}" = "xyes";then + _ecore_want_openssl=no +fi + +if test "x${_ecore_want_openssl}" = "xyes" -o "x${_ecore_want_openssl}" = "xauto"; then + PKG_CHECK_MODULES([SSL], + [openssl], + [ + AC_DEFINE(USE_OPENSSL, 1, [Use OpenSSL]) + _ecore_have_openssl="yes" + ], + [_ecore_have_openssl="no"]) +fi + +if test "x$_ecore_have_openssl" = "xyes" ; then + m4_default([$2], [:]) +else + m4_default([$3], [:]) +fi +]) + +dnl use: ECORE_CHECK_TSLIB(default-enabled[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +AC_DEFUN([ECORE_CHECK_TSLIB], +[ +_tslib_requirement="" +_ecore_want_tslib=$1 +_ecore_have_tslib="no" +TSLIB_LIBS="" +TSLIB_CFLAGS="" + +AC_ARG_ENABLE([tslib], + [AC_HELP_STRING([--disable-tslib], + [disable the tslib support in ecore (currently ecore-fb). + @<:@default=detect@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + _ecore_want_tslib="yes" + else + _ecore_want_tslib="no" + fi + ]) + +if test "x${_ecore_want_tslib}" = "xyes" -o "x${_ecore_want_tslib}" = "xauto" ; then + PKG_CHECK_MODULES([TSLIB], [tslib-1.0], + [ + AC_DEFINE(HAVE_TSLIB, 1, [Build Ecore_FB Touchscreen Code]) + _ecore_have_tslib="yes" + _tslib_requirement="tslib-1.0" + ],[ + PKG_CHECK_MODULES([TSLIB], [tslib], + [ + AC_DEFINE(HAVE_TSLIB, 1, [Build Ecore_FB Touchscreen Code]) + _ecore_have_tslib="yes" + _tslib_requirement="tslib" + ],[ + AC_CHECK_HEADER([tslib.h], + [ + AC_CHECK_LIB([ts], [ts_open], + [ + TSLIB_LIBS="-lts" + TSLIB_CFLAGS="" + AC_DEFINE(HAVE_TSLIB, 1, [Build Ecore_FB Touchscreen Code]) + _ecore_have_tslib="yes" + ],[ + AC_CHECK_LIB([tslib], [ts_open], + [ + TSLIB_LIBS="-ltslib" + TSLIB_CFLAGS="" + AC_DEFINE(HAVE_TSLIB, 1, [Build Ecore_FB Touchscreen Code]) + _ecore_have_tslib="yes" + ],[ + _ecore_have_tslib="no" + ]) + ]) + ]) + ]) + ]) +fi + +AC_SUBST(TSLIB_LIBS) +AC_SUBST(TSLIB_CFLAGS) + +if test "x$_ecore_have_tslib" = "xyes" ; then + m4_default([$2], [:]) +else + m4_default([$3], [:]) +fi +]) + +dnl use: ECORE_CHECK_CARES(default-enabled[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +AC_DEFUN([ECORE_CHECK_CARES], +[ +_ecore_want_cares=$1 +_ecore_have_cares="no" + +AC_ARG_ENABLE(cares, + [AC_HELP_STRING([--disable-cares], [disable cares support])], + [ + if test "x${enableval}" = "xyes" ; then + _ecore_want_cares="yes" + else + _ecore_want_cares="no" + fi + ]) + +if test "x${_ecore_want_cares}" = "xyes" -o "x${_ecore_want_cares}" = "xauto" ; then + PKG_CHECK_MODULES([CARES], [libcares >= 1.6.1], + [_ecore_have_cares="yes"], + [_ecore_have_cares="no"]) +fi + +if test "x${_ecore_have_cares}" = "xyes" ; then + AC_DEFINE([HAVE_CARES], [1], [Build Ecore_Con_Info with c-ares support]) +fi + +if test "x$_ecore_have_cares" = "xyes" ; then + m4_default([$2], [:]) +else + m4_default([$3], [:]) +fi +]) diff --git a/m4/efl_compiler.m4 b/m4/efl_compiler.m4 new file mode 100644 index 0000000..5f17be4 --- /dev/null +++ b/m4/efl_compiler.m4 @@ -0,0 +1,56 @@ +dnl Copyright (C) 2012 Vincent Torri +dnl This code is public domain and can be freely used or copied. + +dnl Macro that check if compiler of linker flags are available + + +dnl Macro that checks for a compiler flag availability +dnl +dnl EFL_CHECK_COMPILER_FLAG(EFL, FLAG[, ACTION-IF-FOUND[ ,ACTION-IF-NOT-FOUND]]) +dnl AC_SUBST : EFL_CFLAGS (EFL being replaced by its value) +dnl AM_CONDITIONAL : EFL_HAVE_FLAG (FLAG being replaced by its value) + +AC_DEFUN([EFL_CHECK_COMPILER_FLAG], +[ +m4_pushdef([UPEFL], m4_translit([[$1]], [-a-z], [_A-Z])) +m4_pushdef([UP], m4_translit([[$2]], [-a-z], [_A-Z])) + +dnl store in options -Wfoo if -Wno-foo is passed +option=m4_bpatsubst([[$2]], [-Wno-], [-W]) + +CFLAGS_save="${CFLAGS}" +CFLAGS="${CFLAGS} ${option}" + +AC_LANG_PUSH([C]) +AC_MSG_CHECKING([whether the compiler supports $2]) + +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[]])], + [have_flag="yes"], + [have_flag="no"]) +AC_MSG_RESULT([${have_flag}]) + +CFLAGS="${CFLAGS_save}" +AC_LANG_POP([C]) + +if test "x${have_flag}" = "xyes" ; then + UPEFL[_CFLAGS]="${UPEFL[_CFLAGS]} [$2]" +fi +AC_ARG_VAR(UPEFL[_CFLAGS], [preprocessor flags for $2]) +AC_SUBST(UPEFL[_CFLAGS]) + +AM_CONDITIONAL([EFL_HAVE]UP, [test "x${have_flag}" = "xyes"]) + +m4_popdef([UP]) +m4_popdef([UPEFL]) +]) + +dnl Macro that iterates over a sequence of white separated flags +dnl and that call EFL_CHECK_COMPILER_FLAG() for each of these flags +dnl +dnl EFL_CHECK_COMPILER_FLAGS(EFL, FLAGS) + +AC_DEFUN([EFL_CHECK_COMPILER_FLAGS], +[ +m4_foreach_w([flag], [$2], [EFL_CHECK_COMPILER_FLAG([$1], m4_defn([flag]))]) +]) diff --git a/m4/efl_compiler_flag.m4 b/m4/efl_compiler_flag.m4 new file mode 100644 index 0000000..25c285d --- /dev/null +++ b/m4/efl_compiler_flag.m4 @@ -0,0 +1,57 @@ +dnl Copyright (C) 2010 Vincent Torri +dnl and Albin Tonnerre +dnl That code is public domain and can be freely used or copied. + +dnl Macro that checks if a compiler flag is supported by the compiler. + +dnl Usage: EFL_COMPILER_FLAG(flag) +dnl flag is added to CFLAGS if supported. + +AC_DEFUN([EFL_COMPILER_FLAG], +[ + +CFLAGS_save="${CFLAGS}" +CFLAGS="${CFLAGS} $1" + +AC_LANG_PUSH([C]) +AC_MSG_CHECKING([whether the compiler supports $1]) + +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[]])], + [have_flag="yes"], + [have_flag="no"]) +AC_MSG_RESULT([${have_flag}]) + +if test "x${have_flag}" = "xno" ; then + CFLAGS="${CFLAGS_save}" +fi +AC_LANG_POP([C]) + +]) + +dnl Macro that checks if a linker flag is supported by the compiler. + +dnl Usage: EFL_LINKER_FLAG(flag) +dnl flag is added to LDFLAGS if supported (will be passed to ld anyway). + +AC_DEFUN([EFL_LINKER_FLAG], +[ + +LDFLAGS_save="${LDFLAGS}" +LDFLAGS="${LDFLAGS} $1" + +AC_LANG_PUSH([C]) +AC_MSG_CHECKING([whether the compiler supports $1]) + +AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[]])], + [have_flag="yes"], + [have_flag="no"]) +AC_MSG_RESULT([${have_flag}]) + +if test "x${have_flag}" = "xno" ; then + LDFLAGS="${LDFLAGS_save}" +fi +AC_LANG_POP([C]) + +]) diff --git a/m4/efl_coverage.m4 b/m4/efl_coverage.m4 new file mode 100644 index 0000000..85d0321 --- /dev/null +++ b/m4/efl_coverage.m4 @@ -0,0 +1,62 @@ +dnl Copyright (C) 2008 Vincent Torri +dnl That code is public domain and can be freely used or copied. + +dnl Macro that check if coverage support is wanted and, if yes, if +dnl lcov is available. + +dnl Usage: EFL_CHECK_COVERAGE(tests [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl The parameter 'tests' is used if a dependency is needed. If set to "yes", +dnl the dependency is available. +dnl Defines EFL_COVERAGE_CFLAGS and EFL_COVERAGE_LIBS variables +dnl Defines the automake conditionnal EFL_ENABLE_COVERAGE + +AC_DEFUN([EFL_CHECK_COVERAGE], +[ + +dnl configure option + +AC_ARG_ENABLE([coverage], + [AC_HELP_STRING([--enable-coverage], [enable coverage profiling instrumentation @<:@default=disabled@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + _efl_enable_coverage="yes" + else + _efl_enable_coverage="no" + fi + ], + [_efl_enable_coverage="no"]) + +AC_MSG_CHECKING([whether to use profiling instrumentation]) +AC_MSG_RESULT([$_efl_enable_coverage]) + +dnl lcov check + +if test "x$_efl_enable_coverage" = "xyes" && test ! "x$1" = "xyes" ; then + AC_MSG_WARN([Coverage report requested but tests not being built, disable profiling instrumentation.]) + AC_MSG_WARN([Run configure with --enable-tests]) + _efl_enable_coverage="no" +fi + +if test "x$_efl_enable_coverage" = "xyes" ; then + AC_CHECK_PROG(have_lcov, [lcov], [yes], [no]) + if test "x$have_lcov" = "xyes" ; then + EFL_COVERAGE_CFLAGS="-fprofile-arcs -ftest-coverage" + EFL_COVERAGE_LIBS="-lgcov" +# remove any optimisation flag and force debug symbols + EFL_DEBUG_CFLAGS="-g -O0 -DDEBUG" + else + AC_MSG_WARN([lcov is not found, disable profiling instrumentation]) + _efl_enable_coverage="no" + fi +fi + +dnl Substitution +AC_SUBST(EFL_COVERAGE_CFLAGS) +AC_SUBST(EFL_COVERAGE_LIBS) + +AM_CONDITIONAL(EFL_ENABLE_COVERAGE, test "x${_efl_enable_coverage}" = "xyes") + +AS_IF([test "x$_efl_enable_coverage" = "xyes"], [$2], [$3]) +]) + +dnl End of efl_coverage.m4 diff --git a/m4/efl_doxygen.m4 b/m4/efl_doxygen.m4 new file mode 100644 index 0000000..d83ed68 --- /dev/null +++ b/m4/efl_doxygen.m4 @@ -0,0 +1,97 @@ +dnl Copyright (C) 2008 Vincent Torri +dnl That code is public domain and can be freely used or copied. + +dnl Macro that check if doxygen is available or not. + +dnl EFL_CHECK_DOXYGEN([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl Test for the doxygen program +dnl Defines efl_doxygen +dnl Defines the automake conditionnal EFL_BUILD_DOC +dnl +AC_DEFUN([EFL_CHECK_DOXYGEN], +[ + +dnl +dnl Disable the build of the documentation +dnl +AC_ARG_ENABLE([doc], + [AC_HELP_STRING( + [--disable-doc], + [Disable documentation build @<:@default=enabled@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + efl_enable_doc="yes" + else + efl_enable_doc="no" + fi + ], + [efl_enable_doc="yes"]) + +AC_MSG_CHECKING([whether to build documentation]) +AC_MSG_RESULT([${efl_enable_doc}]) + +if test "x${efl_enable_doc}" = "xyes" ; then + +dnl Specify the file name, without path + + efl_doxygen="doxygen" + + AC_ARG_WITH([doxygen], + [AC_HELP_STRING( + [--with-doxygen=FILE], + [doxygen program to use @<:@default=doxygen@:>@])], + +dnl Check the given doxygen program. + + [efl_doxygen=${withval} + AC_CHECK_PROG([efl_have_doxygen], + [${efl_doxygen}], + [yes], + [no]) + if test "x${efl_have_doxygen}" = "xno" ; then + echo "WARNING:" + echo "The doxygen program you specified:" + echo "${efl_doxygen}" + echo "was not found. Please check the path and make sure " + echo "the program exists and is executable." + AC_MSG_WARN([no doxygen detected. Documentation will not be built]) + fi + ], + [AC_CHECK_PROG([efl_have_doxygen], + [${efl_doxygen}], + [yes], + [no]) + if test "x${efl_have_doxygen}" = "xno" ; then + echo "WARNING:" + echo "The doxygen program was not found in your execute path." + echo "You may have doxygen installed somewhere not covered by your path." + echo "" + echo "If this is the case make sure you have the packages installed, AND" + echo "that the doxygen program is in your execute path (see your" + echo "shell manual page on setting the \$PATH environment variable), OR" + echo "alternatively, specify the program to use with --with-doxygen." + AC_MSG_WARN([no doxygen detected. Documentation will not be built]) + fi + ]) +fi + +dnl +dnl Substitution +dnl +AC_SUBST([efl_doxygen]) + +if ! test "x${efl_have_doxygen}" = "xyes" ; then + efl_enable_doc="no" +fi + +AM_CONDITIONAL(EFL_BUILD_DOC, test "x${efl_enable_doc}" = "xyes") + +if test "x${efl_enable_doc}" = "xyes" ; then + m4_default([$1], [:]) +else + m4_default([$2], [:]) +fi + +]) + +dnl End of efl_doxygen.m4 diff --git a/m4/efl_examples.m4 b/m4/efl_examples.m4 new file mode 100644 index 0000000..2a809ad --- /dev/null +++ b/m4/efl_examples.m4 @@ -0,0 +1,63 @@ +dnl Copyright (C) 2008 Vincent Torri +dnl That code is public domain and can be freely used or copied. + +dnl Macro that check if building examples is wanted. + +dnl Usage: EFL_CHECK_BUILD_EXAMPLES([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl Defines the automake conditionnal EFL_ENABLE_BUILD_EXAMPLES + +AC_DEFUN([EFL_CHECK_BUILD_EXAMPLES], +[ + +dnl configure option + +AC_ARG_ENABLE([build-examples], + [AC_HELP_STRING([--enable-build-examples], [enable building examples @<:@default=disabled@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + _efl_enable_build_examples="yes" + else + _efl_enable_build_examples="no" + fi + ], + [_efl_enable_build_examples="no"]) + +AC_MSG_CHECKING([whether examples are built]) +AC_MSG_RESULT([${_efl_enable_build_examples}]) + +AM_CONDITIONAL(EFL_BUILD_EXAMPLES, test "x${_efl_enable_build_examples}" = "xyes") + +AS_IF([test "x$_efl_enable_build_examples" = "xyes"], [$1], [$2]) +]) + + +dnl Macro that check if installing examples is wanted. + +dnl Usage: EFL_CHECK_INSTALL_EXAMPLES([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl Defines the automake conditionnal EFL_ENABLE_INSTALL_EXAMPLES + +AC_DEFUN([EFL_CHECK_INSTALL_EXAMPLES], +[ + +dnl configure option + +AC_ARG_ENABLE([install-examples], + [AC_HELP_STRING([--enable-install-examples], [enable installing example source files @<:@default=disabled@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + _efl_enable_install_examples="yes" + else + _efl_enable_install_examples="no" + fi + ], + [_efl_enable_install_examples="no"]) + +AC_MSG_CHECKING([whether examples are installed]) +AC_MSG_RESULT([${_efl_enable_install_examples}]) + +AM_CONDITIONAL(EFL_INSTALL_EXAMPLES, test "x${_efl_enable_install_examples}" = "xyes") + +AS_IF([test "x$_efl_enable_install_examples" = "xyes"], [$1], [$2]) +]) + +dnl End of efl_examples.m4 diff --git a/m4/efl_gettimeofday.m4 b/m4/efl_gettimeofday.m4 new file mode 100644 index 0000000..9b767e5 --- /dev/null +++ b/m4/efl_gettimeofday.m4 @@ -0,0 +1,48 @@ +dnl Copyright (C) 2011 Cedric Bail +dnl This code is public domain and can be freely used or copied. + +dnl Macro that check for gettimeofday definition + +dnl Usage: EFL_CHECK_GETTIMEOFDAY(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]) +dnl Define EFL_HAVE_GETTIMEOFDAY + +AC_DEFUN([EFL_CHECK_GETTIMEOFDAY], +[ + +_efl_have_gettimeofday="no" + +AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ +#include +#include + ]], + [[ +int res; +res = gettimeofday(NULL, NULL); + ]])], + [_efl_have_gettimeofday="yes"], + [_efl_have_gettimeofday="no"]) + +if test "x${_efl_have_gettimeofday}" = "xno" -a "x${enable_exotic}" = "xyes"; then + SAVE_LIBS="${LIBS}" + SAVE_CFLAGS="${CFLAGS}" + LIBS="${LIBS} ${EXOTIC_LIBS}" + CFLAGS="${CFLAGS} ${EXOTIC_CFLAGS}" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ +#include + ]], + [[ +int res; +res = gettimeofday(NULL, NULL); + ]])], + [_efl_have_gettimeofday="yes"], + [_efl_have_gettimeofday="no"]) +fi + +if test "x${_efl_have_gettimeofday}" = "xyes"; then + AC_DEFINE([EFL_HAVE_GETTIMEOFDAY], [1], [Defined if gettimeofday is available.]) +fi + +AS_IF([test "x${_efl_have_gettimeofday}" = "xyes"], [$1], [$2]) +]) diff --git a/m4/efl_path_max.m4 b/m4/efl_path_max.m4 new file mode 100644 index 0000000..f57bfd2 --- /dev/null +++ b/m4/efl_path_max.m4 @@ -0,0 +1,36 @@ +dnl Check for PATH_MAX in limits.h, and define a default value if not found +dnl This is a workaround for systems not providing PATH_MAX, like GNU/Hurd + +dnl EFL_CHECK_PATH_MAX([DEFAULT_VALUE_IF_NOT_FOUND]) +dnl +dnl If PATH_MAX is not defined in , defines it +dnl to DEFAULT_VALUE_IF_NOT_FOUND if it exists, or fallback +dnl to using 4096 + +AC_DEFUN([EFL_CHECK_PATH_MAX], +[ + +default_max=m4_default([$1], "4096") +AC_LANG_PUSH([C]) + +AC_MSG_CHECKING([for PATH_MAX in limits.h]) +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include + ]], + [[ +int i = PATH_MAX; + ]])], + [AC_MSG_RESULT([yes])], + [ + AC_DEFINE_UNQUOTED([PATH_MAX], + [${default_max}], + [default value since PATH_MAX is not defined]) + AC_MSG_RESULT([no: using ${default_max}]) + ]) + +AC_LANG_POP([C]) + +]) +dnl end of efl_path_max.m4 diff --git a/m4/efl_shm_open.m4 b/m4/efl_shm_open.m4 new file mode 100644 index 0000000..0bf1b0b --- /dev/null +++ b/m4/efl_shm_open.m4 @@ -0,0 +1,69 @@ +dnl Copyright (C) 2010 Vincent Torri +dnl That code is public domain and can be freely used or copied. + +dnl Macro that check if shm_open function is available or not. + +dnl Usage: EFL_CHECK_SHM_OPEN([, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl Call AC_SUBST(EFL_SHM_OPEN_LIBS) +dnl Define HAVE_SHM_OPEN to 1if shm_open is available + +AC_DEFUN([EFL_CHECK_SHM_OPEN], +[ +_efl_have_shm_open="no" + +dnl Check is shm_open is in libc + +AC_MSG_CHECKING([for shm_open in libc]) +AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include +#include /* For mode constants */ +#include /* For O_* constants */ + ]], + [[ +int fd; + +fd = shm_open("/dev/null", O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO); + ]])], + [_efl_have_shm_open="yes"], + [_efl_have_shm_open="no"]) + +AC_MSG_RESULT([${_efl_have_shm_open}]) + +if test "x$_efl_have_shm_open" = "xno" ; then + AC_MSG_CHECKING([for shm_open in librt]) + + LIBS_save="${LIBS}" + LIBS="${LIBS} -lrt" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include +#include /* For mode constants */ +#include /* For O_* constants */ + ]], + [[ +int fd; + +fd = shm_open("/dev/null", O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO); + ]])], + [ + EFL_SHM_OPEN_LIBS="-lrt" + _efl_have_shm_open="yes"], + [_efl_have_shm_open="no"]) + + LIBS="${LIBS_save}" + + AC_MSG_RESULT([${_efl_have_shm_open}]) +fi + +AC_SUBST([EFL_SHM_OPEN_LIBS]) + +if test "x$_efl_have_shm_open" = "xyes" ; then + AC_DEFINE([HAVE_SHM_OPEN], [1], [Define to 1 if you have the `shm_open' function.]) +fi + +AS_IF([test "x$_efl_have_shm_open" = "xyes"], [$1], [$2]) + +]) diff --git a/m4/efl_tests.m4 b/m4/efl_tests.m4 new file mode 100644 index 0000000..3a4dfe2 --- /dev/null +++ b/m4/efl_tests.m4 @@ -0,0 +1,43 @@ +dnl Copyright (C) 2008 Vincent Torri +dnl That code is public domain and can be freely used or copied. + +dnl Macro that check if tests programs are wanted and if yes, if +dnl the Check library is available. + +dnl Usage: EFL_CHECK_TESTS([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl Define the automake conditionnal EFL_ENABLE_TESTS + +AC_DEFUN([EFL_CHECK_TESTS], +[ + +dnl configure option + +AC_ARG_ENABLE([tests], + [AC_HELP_STRING([--enable-tests], [enable tests @<:@default=disabled@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + _efl_enable_tests="yes" + else + _efl_enable_tests="no" + fi + ], + [_efl_enable_tests="no"]) + +AC_MSG_CHECKING([whether tests are built]) +AC_MSG_RESULT([${_efl_enable_tests}]) + +AC_REQUIRE([PKG_PROG_PKG_CONFIG]) + +if test "x${_efl_enable_tests}" = "xyes" ; then + PKG_CHECK_MODULES([CHECK], + [check >= 0.9.5], + [dummy="yes"], + [_efl_enable_tests="no"]) +fi + +AM_CONDITIONAL(EFL_ENABLE_TESTS, test "x${_efl_enable_tests}" = "xyes") + +AS_IF([test "x$_efl_enable_tests" = "xyes"], [$1], [$2]) +]) + +dnl End of efl_tests.m4 diff --git a/m4/efl_threads.m4 b/m4/efl_threads.m4 new file mode 100644 index 0000000..33d15a3 --- /dev/null +++ b/m4/efl_threads.m4 @@ -0,0 +1,206 @@ +dnl Copyright (C) 2010 Vincent Torri +dnl rwlock code added by Mike Blumenkrantz +dnl This code is public domain and can be freely used or copied. + +dnl Macro that check if POSIX or Win32 threads library is available or not. + +dnl Usage: EFL_CHECK_THREADS(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]) +dnl Call AC_SUBST(EFL_PTHREAD_CFLAGS) +dnl Call AC_SUBST(EFL_PTHREAD_LIBS) +dnl Defines EFL_HAVE_POSIX_THREADS or EFL_HAVE_WIN32_THREADS, and EFL_HAVE_THREADS + +AC_DEFUN([EFL_CHECK_THREADS], +[ + +dnl configure option + +AC_ARG_ENABLE([posix-threads], + [AC_HELP_STRING([--disable-posix-threads], [enable POSIX threads code @<:@default=auto@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + _efl_enable_posix_threads="yes" + else + _efl_enable_posix_threads="no" + fi + ], + [_efl_enable_posix_threads="auto"]) + +AC_MSG_CHECKING([whether to build POSIX threads code]) +AC_MSG_RESULT([${_efl_enable_posix_threads}]) + +AC_ARG_ENABLE([win32-threads], + [AC_HELP_STRING([--disable-win32-threads], [enable Win32 threads code @<:@default=no@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + _efl_enable_win32_threads="yes" + else + _efl_enable_win32_threads="no" + fi + ], + [_efl_enable_win32_threads="no"]) + +AC_MSG_CHECKING([whether to build Windows threads code]) +AC_MSG_RESULT([${_efl_enable_win32_threads}]) + +dnl +dnl * no + no +dnl * yes + no : win32: error, other : pthread +dnl * yes + yes : win32 : wthread, other : pthread +dnl * no + yes : win32 : wthread, other : error + +if test "x${_efl_enable_posix_threads}" = "xyes" && test "x${_efl_enable_win32_threads}" = "xyes" ; then + case "$host_os" in + mingw*) + _efl_enable_posix_threads=no + ;; + *) + _efl_enable_win32_threads=no + ;; + esac +fi + +if test "x${_efl_enable_win32_threads}" = "xyes" ; then + case "$host_os" in + mingw*) + ;; + *) + AC_MSG_ERROR([Win32 threads support requested but non Windows system found.]) + ;; + esac +fi + +if test "x${_efl_enable_posix_threads}" = "xyes" ; then + case "$host_os" in + mingw*) + AC_MSG_ERROR([POSIX threads support requested but Windows system found.]) + ;; + *) + ;; + esac +fi + +dnl check if the compiler supports POSIX threads + +case "$host_os" in + mingw*) + ;; + solaris*) + _efl_threads_cflags="-mt" + _efl_threads_libs="-mt" + ;; + *) + _efl_threads_cflags="-pthread" + _efl_threads_libs="-pthread" + ;; +esac + +_efl_have_posix_threads="no" +_efl_have_win32_threads="no" + +if test "x${_efl_enable_posix_threads}" = "xyes" || test "x${_efl_enable_posix_threads}" = "xauto" ; then + + SAVE_CFLAGS=${CFLAGS} + CFLAGS="${CFLAGS} ${_efl_threads_cflags}" + SAVE_LIBS=${LIBS} + LIBS="${LIBS} ${_efl_threads_libs}" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ +#include + ]], + [[ +pthread_t id; +id = pthread_self(); + ]])], + [_efl_have_posix_threads="yes"], + [_efl_have_posix_threads="no"]) + CFLAGS=${SAVE_CFLAGS} + LIBS=${SAVE_LIBS} + +fi + +AC_MSG_CHECKING([whether system support POSIX threads]) +AC_MSG_RESULT([${_efl_have_posix_threads}]) +if test "$x{_efl_enable_posix_threads}" = "xyes" && test "x${_efl_have_posix_threads}" = "xno"; then + AC_MSG_ERROR([POSIX threads support requested but not found.]) +fi + +EFL_PTHREAD_CFLAGS="" +EFL_PTHREAD_LIBS="" +if test "x${_efl_have_posix_threads}" = "xyes" ; then + EFL_PTHREAD_CFLAGS=${_efl_threads_cflags} + EFL_PTHREAD_LIBS=${_efl_threads_libs} +fi + +AC_SUBST(EFL_PTHREAD_CFLAGS) +AC_SUBST(EFL_PTHREAD_LIBS) + +_efl_enable_debug_threads="no" +AC_ARG_ENABLE([debug-threads], + [AC_HELP_STRING([--enable-debug-threads], [disable assert when you forgot to call eina_threads_init])], + [_efl_enable_debug_threads="${enableval}"]) + +have_debug_threads="no" +if test "x${_efl_have_posix_threads}" = "xyes" -a "x${_efl_enable_debug_threads}" = "xyes"; then + have_debug_threads="yes" + AC_DEFINE([EFL_DEBUG_THREADS], [1], [Assert when forgot to call eina_threads_init]) +fi + +if test "x${_efl_have_posix_threads}" = "xyes" ; then + AC_DEFINE([EFL_HAVE_POSIX_THREADS], [1], [Define to mention that POSIX threads are supported]) +fi + +if test "x${_efl_enable_win32_threads}" = "xyes" ; then + _efl_have_win32_threads="yes" + AC_DEFINE([EFL_HAVE_WIN32_THREADS], [1], [Define to mention that Win32 threads are supported]) +fi + +if test "x${_efl_have_posix_threads}" = "xyes" || test "x${_efl_have_win32_threads}" = "xyes" ; then + AC_DEFINE([EFL_HAVE_THREADS], [1], [Define to mention that POSIX or Win32 threads are supported]) +fi + +AS_IF([test "x$_efl_have_posix_threads" = "xyes" || test "x$_efl_have_win32_threads" = "xyes"], [$1], [$2]) +]) + +dnl Usage: EFL_CHECK_SPINLOCK(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]) +dnl Defines EFL_HAVE_POSIX_THREADS_SPINLOCK +AC_DEFUN([EFL_CHECK_SPINLOCK], +[ + +dnl check if the compiler supports pthreads spinlock + +_efl_have_posix_threads_spinlock="no" + +if test "x${_efl_have_posix_threads}" = "xyes" ; then + + SAVE_CFLAGS=${CFLAGS} + CFLAGS="${CFLAGS} ${EFL_PTHREAD_CFLAGS}" + SAVE_LIBS=${LIBS} + LIBS="${LIBS} ${EFL_PTHREAD_LIBS}" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ +#include + ]], + [[ +pthread_spinlock_t lock; +int res; +res = pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE); + ]])], + [_efl_have_posix_threads_spinlock="yes"], + [_efl_have_posix_threads_spinlock="no"]) + CFLAGS=${SAVE_CFLAGS} + LIBS=${SAVE_LIBS} + +fi + +AC_MSG_CHECKING([whether to build POSIX threads spinlock code]) +AC_MSG_RESULT([${_efl_have_posix_threads_spinlock}]) +if test "x${_efl_enable_posix_threads}" = "xyes" && test "x${_efl_have_posix_threads_spinlock}" = "xno" ; then + AC_MSG_WARN([POSIX threads support requested but spinlocks are not supported]) +fi + +if test "x${_efl_have_posix_threads_spinlock}" = "xyes" ; then + AC_DEFINE([EFL_HAVE_POSIX_THREADS_SPINLOCK], [1], [Define to mention that POSIX threads spinlocks are supported]) +fi +AS_IF([test "x$_efl_have_posix_threads_spinlock" = "xyes"], [$1], [$2]) +]) + diff --git a/po/ChangeLog b/po/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/po/LINGUAS b/po/LINGUAS new file mode 100644 index 0000000..3665c31 --- /dev/null +++ b/po/LINGUAS @@ -0,0 +1,2 @@ +cs de el fr it nl pt sl + diff --git a/po/Makevars b/po/Makevars new file mode 100644 index 0000000..22837ab --- /dev/null +++ b/po/Makevars @@ -0,0 +1,41 @@ +# Makefile variables for PO directory in any package using GNU gettext. + +# Usually the message domain is the same as the package name. +DOMAIN = $(PACKAGE) + +# These two variables depend on the location of this directory. +subdir = po +top_builddir = .. + +# These options get passed to xgettext. +XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ --from-code=UTF-8 --foreign-user + +# This is the copyright holder that gets inserted into the header of the +# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding +# package. (Note that the msgstr strings, extracted from the package's +# sources, belong to the copyright holder of the package.) Translators are +# expected to transfer the copyright for their translations to this person +# or entity, or to disclaim their copyright. The empty string stands for +# the public domain; in this case the translators are expected to disclaim +# their copyright. +COPYRIGHT_HOLDER = Enlightenment development team + +# This is the email address or URL to which the translators shall report +# bugs in the untranslated strings: +# - Strings which are not entire sentences, see the maintainer guidelines +# in the GNU gettext documentation, section 'Preparing Strings'. +# - Strings which use unclear terms or require additional context to be +# understood. +# - Strings which make invalid assumptions about notation of date, time or +# money. +# - Pluralisation problems. +# - Incorrect English spelling. +# - Incorrect formatting. +# It can be your email address, or a mailing list address where translators +# can write to without being subscribed, or the URL of a web page through +# which the translators can contact you. +MSGID_BUGS_ADDRESS = enlightenment-devel@lists.sourceforge.net + +# This is the list of locale categories, beyond LC_MESSAGES, for which the +# message catalogs shall be used. It is usually empty. +EXTRA_LOCALE_CATEGORIES = diff --git a/po/POTFILES.in b/po/POTFILES.in new file mode 100644 index 0000000..5014aa2 --- /dev/null +++ b/po/POTFILES.in @@ -0,0 +1 @@ +src/lib/ecore/ecore_getopt.c diff --git a/po/cs.po b/po/cs.po new file mode 100644 index 0000000..2d3ec63 --- /dev/null +++ b/po/cs.po @@ -0,0 +1,174 @@ +# ecore czech translation +# quaker66@gmail.com +# Vít Pelčák , 2011. +msgid "" +msgstr "" +"Project-Id-Version: ecore\n" +"Report-Msgid-Bugs-To: enlightenment-devel@lists.sourceforge.net\n" +"POT-Creation-Date: 2012-08-27 19:14+0900\n" +"PO-Revision-Date: 2011-10-23 01:28+0100\n" +"Last-Translator: Daniel Kolesa \n" +"Language-Team: Czech \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.2\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" + +#: src/lib/ecore/ecore_getopt.c:95 +msgid "Version:" +msgstr "Verze:" + +#: src/lib/ecore/ecore_getopt.c:104 +msgid "Usage:" +msgstr "Použití:" + +#: src/lib/ecore/ecore_getopt.c:109 +#, c-format +msgid "%s [options]\n" +msgstr "%s [volby]\n" + +#: src/lib/ecore/ecore_getopt.c:264 +msgid "Copyright:" +msgstr "Copyright:" + +#: src/lib/ecore/ecore_getopt.c:276 +msgid "License:" +msgstr "Licence:" + +#: src/lib/ecore/ecore_getopt.c:457 +msgid "Type: " +msgstr "Typ: " + +#: src/lib/ecore/ecore_getopt.c:533 +msgid "Default: " +msgstr "Výchozí: " + +#: src/lib/ecore/ecore_getopt.c:560 +msgid "Choices: " +msgstr "Možnosti: " + +#: src/lib/ecore/ecore_getopt.c:661 +msgid "Options:\n" +msgstr "Volby:\n" + +#: src/lib/ecore/ecore_getopt.c:788 +#, c-format +msgid "ERROR: unknown option --%s.\n" +msgstr "CHYBA: neznámá volba --%s.\n" + +#: src/lib/ecore/ecore_getopt.c:790 +#, c-format +msgid "ERROR: unknown option -%c.\n" +msgstr "CHYBA: neznámá volba -%c.\n" + +#: src/lib/ecore/ecore_getopt.c:848 +msgid "ERROR: " +msgstr "CHYBA: " + +#: src/lib/ecore/ecore_getopt.c:931 src/lib/ecore/ecore_getopt.c:1068 +#: src/lib/ecore/ecore_getopt.c:1084 src/lib/ecore/ecore_getopt.c:1099 +#: src/lib/ecore/ecore_getopt.c:1116 src/lib/ecore/ecore_getopt.c:1163 +#: src/lib/ecore/ecore_getopt.c:1283 src/lib/ecore/ecore_getopt.c:1324 +msgid "value has no pointer set.\n" +msgstr "hodnota nemá nastaven pointer.\n" + +#: src/lib/ecore/ecore_getopt.c:963 src/lib/ecore/ecore_getopt.c:1183 +#, c-format +msgid "unknown boolean value %s.\n" +msgstr "neznámá boolean hodnota %s.\n" + +#: src/lib/ecore/ecore_getopt.c:1014 src/lib/ecore/ecore_getopt.c:1271 +#, c-format +msgid "invalid number format %s\n" +msgstr "neznámý číselný formát %s\n" + +#: src/lib/ecore/ecore_getopt.c:1129 +#, c-format +msgid "invalid choice \"%s\". Valid values are: " +msgstr "neznámá volba \"%s\". Možné hodnoty jsou: " + +#: src/lib/ecore/ecore_getopt.c:1157 +msgid "missing parameter to append.\n" +msgstr "chybějící parametr k připojení.\n" + +#: src/lib/ecore/ecore_getopt.c:1261 +msgid "could not parse value.\n" +msgstr "nemůžu parsovat hodnotu.\n" + +#: src/lib/ecore/ecore_getopt.c:1318 +msgid "missing parameter.\n" +msgstr "chybějící parametr.\n" + +#: src/lib/ecore/ecore_getopt.c:1331 +msgid "missing callback function!\n" +msgstr "chybějící callback funkce!\n" + +#: src/lib/ecore/ecore_getopt.c:1360 +msgid "no version was defined.\n" +msgstr "nebyla definována verze.\n" + +#: src/lib/ecore/ecore_getopt.c:1377 +msgid "no copyright was defined.\n" +msgstr "nebyl definován copyright.\n" + +#: src/lib/ecore/ecore_getopt.c:1394 +msgid "no license was defined.\n" +msgstr "nebyla definována licence.\n" + +#: src/lib/ecore/ecore_getopt.c:1469 +#, c-format +msgid "ERROR: unknown option --%s, ignored.\n" +msgstr "CHYBA: neznámá volba --%s, ignoruji.\n" + +#: src/lib/ecore/ecore_getopt.c:1502 +#, c-format +msgid "ERROR: option --%s requires an argument!\n" +msgstr "CHYBA: volba --%s vyžaduje argument!\n" + +#: src/lib/ecore/ecore_getopt.c:1544 +#, c-format +msgid "ERROR: unknown option -%c, ignored.\n" +msgstr "CHYBA: neznámá volba -%c, ignoruji.\n" + +#: src/lib/ecore/ecore_getopt.c:1582 +#, c-format +msgid "ERROR: option -%c requires an argument!\n" +msgstr "CHYBA: volba -%c vyžaduje argument!\n" + +#: src/lib/ecore/ecore_getopt.c:1793 +msgid "ERROR: no parser provided.\n" +msgstr "CHYBA: nebyl poskytnut parser.\n" + +#: src/lib/ecore/ecore_getopt.c:1798 +msgid "ERROR: no values provided.\n" +msgstr "CHYBA: nebyly poskytnuty hodnoty.\n" + +#: src/lib/ecore/ecore_getopt.c:1807 +msgid "ERROR: no arguments provided.\n" +msgstr "CHYBA: nebyly poskytnuty argumenty.\n" + +#: src/lib/ecore/ecore_getopt.c:1833 +msgid "ERROR: invalid options found." +msgstr "CHYBA: nalezeny neplatné volby." + +#: src/lib/ecore/ecore_getopt.c:1839 +#, c-format +msgid " See --%s.\n" +msgstr " Viz --%s.\n" + +#: src/lib/ecore/ecore_getopt.c:1841 +#, c-format +msgid " See -%c.\n" +msgstr " Viz -%c.\n" + +#: src/lib/ecore/ecore_getopt.c:1887 +#, c-format +msgid "ERROR: incorrect geometry value '%s'\n" +msgstr "CHYBA: neplatná hodnota geometrie '%s'\n" + +#: src/lib/ecore/ecore_getopt.c:1919 +#, c-format +msgid "ERROR: incorrect size value '%s'\n" +msgstr "CHYBA: neplatná hodnota velikosti '%s'\n" diff --git a/po/de.po b/po/de.po new file mode 100644 index 0000000..b00169e --- /dev/null +++ b/po/de.po @@ -0,0 +1,175 @@ +# Translation of ecore to German +# Copyright (C) 2000 Carsten Haitzler and others. +# This file is distributed under the same license as the ecore package. +# Chris Leick , 2009. +# Fabian Nowak , 2010. +# +msgid "" +msgstr "" +"Project-Id-Version: ecore 0.9.9.063-2\n" +"Report-Msgid-Bugs-To: enlightenment-devel@lists.sourceforge.net\n" +"POT-Creation-Date: 2012-08-27 19:14+0900\n" +"PO-Revision-Date: 2010-01-03 21:52+GMT\n" +"Last-Translator: Fabian Nowak \n" +"Language-Team: German \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/lib/ecore/ecore_getopt.c:95 +msgid "Version:" +msgstr "Version:" + +#: src/lib/ecore/ecore_getopt.c:104 +msgid "Usage:" +msgstr "Aufruf:" + +#: src/lib/ecore/ecore_getopt.c:109 +#, c-format +msgid "%s [options]\n" +msgstr "%s [Optionen]\n" + +#: src/lib/ecore/ecore_getopt.c:264 +msgid "Copyright:" +msgstr "Copyright:" + +#: src/lib/ecore/ecore_getopt.c:276 +msgid "License:" +msgstr "Lizenz:" + +#: src/lib/ecore/ecore_getopt.c:457 +msgid "Type: " +msgstr "Typ: " + +#: src/lib/ecore/ecore_getopt.c:533 +msgid "Default: " +msgstr "Standard: " + +#: src/lib/ecore/ecore_getopt.c:560 +msgid "Choices: " +msgstr "Auswahlmöglichkeiten: " + +#: src/lib/ecore/ecore_getopt.c:661 +msgid "Options:\n" +msgstr "Optionen:\n" + +#: src/lib/ecore/ecore_getopt.c:788 +#, c-format +msgid "ERROR: unknown option --%s.\n" +msgstr "FEHLER: Unbekannte Option --%s\n" + +#: src/lib/ecore/ecore_getopt.c:790 +#, c-format +msgid "ERROR: unknown option -%c.\n" +msgstr "FEHLER: Unbekannte Option -%c\n" + +#: src/lib/ecore/ecore_getopt.c:848 +msgid "ERROR: " +msgstr "FEHLER: " + +#: src/lib/ecore/ecore_getopt.c:931 src/lib/ecore/ecore_getopt.c:1068 +#: src/lib/ecore/ecore_getopt.c:1084 src/lib/ecore/ecore_getopt.c:1099 +#: src/lib/ecore/ecore_getopt.c:1116 src/lib/ecore/ecore_getopt.c:1163 +#: src/lib/ecore/ecore_getopt.c:1283 src/lib/ecore/ecore_getopt.c:1324 +msgid "value has no pointer set.\n" +msgstr "kein Zeiger auf Wert gesetzt\n" + +#: src/lib/ecore/ecore_getopt.c:963 src/lib/ecore/ecore_getopt.c:1183 +#, c-format +msgid "unknown boolean value %s.\n" +msgstr "unbekannter boolescher Wert %s\n" + +#: src/lib/ecore/ecore_getopt.c:1014 src/lib/ecore/ecore_getopt.c:1271 +#, c-format +msgid "invalid number format %s\n" +msgstr "ungültiges Zahlenformat %s\n" + +#: src/lib/ecore/ecore_getopt.c:1129 +#, c-format +msgid "invalid choice \"%s\". Valid values are: " +msgstr "ungültige Auswahl \"%s\". Gültige Werte sind: " + +#: src/lib/ecore/ecore_getopt.c:1157 +msgid "missing parameter to append.\n" +msgstr "fehlender Parameter zum Anhängen.\n" + +#: src/lib/ecore/ecore_getopt.c:1261 +msgid "could not parse value.\n" +msgstr "Wert kann nicht ausgewertet werden.\n" + +#: src/lib/ecore/ecore_getopt.c:1318 +msgid "missing parameter.\n" +msgstr "fehlender Parameter.\n" + +#: src/lib/ecore/ecore_getopt.c:1331 +msgid "missing callback function!\n" +msgstr "fehlende Rückruffunktion!\n" + +#: src/lib/ecore/ecore_getopt.c:1360 +msgid "no version was defined.\n" +msgstr "es wurde keine Version angegeben.\n" + +#: src/lib/ecore/ecore_getopt.c:1377 +msgid "no copyright was defined.\n" +msgstr "es wurde kein Copyright angegeben.\n" + +#: src/lib/ecore/ecore_getopt.c:1394 +msgid "no license was defined.\n" +msgstr "es wurde keine Lizenz angegeben.\n" + +#: src/lib/ecore/ecore_getopt.c:1469 +#, c-format +msgid "ERROR: unknown option --%s, ignored.\n" +msgstr "FEHLER: Unbekannte Option --%s, ignoriert\n" + +#: src/lib/ecore/ecore_getopt.c:1502 +#, c-format +msgid "ERROR: option --%s requires an argument!\n" +msgstr "FEHLER: Option --%s benötigt ein Argument!\n" + +#: src/lib/ecore/ecore_getopt.c:1544 +#, c-format +msgid "ERROR: unknown option -%c, ignored.\n" +msgstr "FEHLER: Unbekannte Option -%c, ignoriert\n" + +#: src/lib/ecore/ecore_getopt.c:1582 +#, c-format +msgid "ERROR: option -%c requires an argument!\n" +msgstr "FEHLER: Option -%c benötigt ein Argument!\n" + +#: src/lib/ecore/ecore_getopt.c:1793 +msgid "ERROR: no parser provided.\n" +msgstr "FEHLER: Kein Parser bereitgestellt.\n" + +#: src/lib/ecore/ecore_getopt.c:1798 +msgid "ERROR: no values provided.\n" +msgstr "FEHLER: Keine Werte bereitgestellt.\n" + +#: src/lib/ecore/ecore_getopt.c:1807 +msgid "ERROR: no arguments provided.\n" +msgstr "FEHLER: Keine Argumente bereitgestellt.\n" + +#: src/lib/ecore/ecore_getopt.c:1833 +msgid "ERROR: invalid options found." +msgstr "FEHLER: Ungültige Optionen gefunden." + +#: src/lib/ecore/ecore_getopt.c:1839 +#, c-format +msgid " See --%s.\n" +msgstr " Siehe --%s\n" + +#: src/lib/ecore/ecore_getopt.c:1841 +#, c-format +msgid " See -%c.\n" +msgstr " Siehe -%c\n" + +#: src/lib/ecore/ecore_getopt.c:1887 +#, c-format +msgid "ERROR: incorrect geometry value '%s'\n" +msgstr "FEHLER: Falscher Geometriewert \"%s\"\n" + +#: src/lib/ecore/ecore_getopt.c:1919 +#, c-format +msgid "ERROR: incorrect size value '%s'\n" +msgstr "FEHLER: Falscher Größenwert \"%s\"\n" diff --git a/po/el.po b/po/el.po new file mode 100644 index 0000000..f0dc8fb --- /dev/null +++ b/po/el.po @@ -0,0 +1,205 @@ +# Greek translation for Ecore. +# This file is put in the public domain. +# ragecryx , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: Ecore\n" +"Report-Msgid-Bugs-To: enlightenment-devel@lists.sourceforge.net\n" +"POT-Creation-Date: 2012-08-27 19:14+0900\n" +"PO-Revision-Date: 2011-11-20 22:42+0200\n" +"Last-Translator: George Rizopoulos \n" +"Language-Team: Greek\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/lib/ecore/ecore_getopt.c:95 +msgid "Version:" +msgstr "Έκδοση:" + +#: src/lib/ecore/ecore_getopt.c:104 +msgid "Usage:" +msgstr "Χρήση:" + +#: src/lib/ecore/ecore_getopt.c:109 +#, c-format +msgid "%s [options]\n" +msgstr "%s [επιλογές]\n" + +#: src/lib/ecore/ecore_getopt.c:264 +msgid "Copyright:" +msgstr "Πνευματικά δικαιώματα:" + +#: src/lib/ecore/ecore_getopt.c:276 +msgid "License:" +msgstr "Άδεια:" + +#: src/lib/ecore/ecore_getopt.c:457 +msgid "Type: " +msgstr "Τύπος:" + +#: src/lib/ecore/ecore_getopt.c:533 +msgid "Default: " +msgstr "Προκαθορισμένο:" + +#: src/lib/ecore/ecore_getopt.c:560 +msgid "Choices: " +msgstr "Επιλογές:" + +#: src/lib/ecore/ecore_getopt.c:661 +msgid "Options:\n" +msgstr "Επιλογές:\n" + +#: src/lib/ecore/ecore_getopt.c:788 +#, c-format +msgid "ERROR: unknown option --%s.\n" +msgstr "ΣΦΑΛΜΑ: άγνωστη επιλογή --%s.\n" + +#: src/lib/ecore/ecore_getopt.c:790 +#, c-format +msgid "ERROR: unknown option -%c.\n" +msgstr "ΣΦΑΛΜΑ: άγνωστη επιλογή -%c.\n" + +#: src/lib/ecore/ecore_getopt.c:848 +msgid "ERROR: " +msgstr "ΣΦΑΛΜΑ:" + +#: src/lib/ecore/ecore_getopt.c:931 src/lib/ecore/ecore_getopt.c:1068 +#: src/lib/ecore/ecore_getopt.c:1084 src/lib/ecore/ecore_getopt.c:1099 +#: src/lib/ecore/ecore_getopt.c:1116 src/lib/ecore/ecore_getopt.c:1163 +#: src/lib/ecore/ecore_getopt.c:1283 src/lib/ecore/ecore_getopt.c:1324 +msgid "value has no pointer set.\n" +msgstr "η τιμή δεν έχει δείκτη ορισμένο.\n" + +#: src/lib/ecore/ecore_getopt.c:963 src/lib/ecore/ecore_getopt.c:1183 +#, c-format +msgid "unknown boolean value %s.\n" +msgstr "άγνωστη τιμή boolean %s.\n" + +#: src/lib/ecore/ecore_getopt.c:1014 src/lib/ecore/ecore_getopt.c:1271 +#, c-format +msgid "invalid number format %s\n" +msgstr "άγνωστη μορφή αριθμού %s\n" + +#: src/lib/ecore/ecore_getopt.c:1129 +#, c-format +msgid "invalid choice \"%s\". Valid values are: " +msgstr "μη έγκυρη επιλογή \"%s\". Οι έγκυρες τιμές είναι: " + +#: src/lib/ecore/ecore_getopt.c:1157 +msgid "missing parameter to append.\n" +msgstr "ελλιπής παράμετρος προς επισύναψη.\n" + +#: src/lib/ecore/ecore_getopt.c:1261 +msgid "could not parse value.\n" +msgstr "αδυναμία ανάλυσης τιμών.\n" + +#: src/lib/ecore/ecore_getopt.c:1318 +msgid "missing parameter.\n" +msgstr "ελλιπής παράμετρος.\n" + +#: src/lib/ecore/ecore_getopt.c:1331 +msgid "missing callback function!\n" +msgstr "λείπει η λειτουργία επανάκλησης!\n" + +#: src/lib/ecore/ecore_getopt.c:1360 +msgid "no version was defined.\n" +msgstr "δεν έχει οριστεί έκδοση.\n" + +#: src/lib/ecore/ecore_getopt.c:1377 +msgid "no copyright was defined.\n" +msgstr "δεν έχουν οριστεί πνευματικά δικαιώματα.\n" + +#: src/lib/ecore/ecore_getopt.c:1394 +msgid "no license was defined.\n" +msgstr "δεν έχει οριστεί άδεια.\n" + +#: src/lib/ecore/ecore_getopt.c:1469 +#, c-format +msgid "ERROR: unknown option --%s, ignored.\n" +msgstr "ΣΦΑΛΜΑ:άγνωστη επιλογή --%s, αγνοήθηκε.\n" + +#: src/lib/ecore/ecore_getopt.c:1502 +#, c-format +msgid "ERROR: option --%s requires an argument!\n" +msgstr "ΣΦΑΛΜΑ: η επιλογή --%s απαιτεί παραμέτρους!\n" + +#: src/lib/ecore/ecore_getopt.c:1544 +#, c-format +msgid "ERROR: unknown option -%c, ignored.\n" +msgstr "ΣΦΑΛΜΑ: άγνωστη επιλογή -%c, αγνοήθηκε.\n" + +#: src/lib/ecore/ecore_getopt.c:1582 +#, c-format +msgid "ERROR: option -%c requires an argument!\n" +msgstr "ΣΦAΛΜΑ: η επιλογή -%c απαιτεί μία παράμετρο!\n" + +#: src/lib/ecore/ecore_getopt.c:1793 +#, fuzzy +msgid "ERROR: no parser provided.\n" +msgstr "ΣΦΑΛΜΑ:δεν παρέχεται αναλυτής.\n" + +#: src/lib/ecore/ecore_getopt.c:1798 +msgid "ERROR: no values provided.\n" +msgstr "ΣΦΑΛΜΑ:δεν έχουν δοθεί τιμές.\n" + +#: src/lib/ecore/ecore_getopt.c:1807 +msgid "ERROR: no arguments provided.\n" +msgstr "ΣΦΑΛΜΑ:δεν έχουν δοθεί παράμετροι.\n" + +#: src/lib/ecore/ecore_getopt.c:1833 +msgid "ERROR: invalid options found." +msgstr "ΣΦΑΛΜΑ: βρέθηκαν μη έγκυρες επιλογές." + +#: src/lib/ecore/ecore_getopt.c:1839 +#, c-format +msgid " See --%s.\n" +msgstr " Δείτε --%s.\n" + +#: src/lib/ecore/ecore_getopt.c:1841 +#, c-format +msgid " See -%c.\n" +msgstr " Δείτε -%c.\n" + +#: src/lib/ecore/ecore_getopt.c:1887 +#, c-format +msgid "ERROR: incorrect geometry value '%s'\n" +msgstr "ΣΦΑΛΜΑ: μη έγκυρη γεωμετρική τιμή '%s'\n" + +#: src/lib/ecore/ecore_getopt.c:1919 +#, c-format +msgid "ERROR: incorrect size value '%s'\n" +msgstr "ΣΦΑΛΜΑ: μη έγκυρη τιμή μεγέθους '%s'\n" + +#~ msgid "" +#~ "\n" +#~ " " +#~ msgstr "" +#~ "\n" +#~ " " + +#~ msgid "true" +#~ msgstr "true" + +#~ msgid "false" +#~ msgstr "false" + +#~ msgid "f" +#~ msgstr "f" + +#~ msgid "no" +#~ msgstr "no" + +#~ msgid "off" +#~ msgstr "off" + +#~ msgid "t" +#~ msgstr "t" + +#~ msgid "yes" +#~ msgstr "yes" + +#~ msgid "on" +#~ msgstr "on" diff --git a/po/fr.po b/po/fr.po new file mode 100644 index 0000000..8d7f719 --- /dev/null +++ b/po/fr.po @@ -0,0 +1,208 @@ +# French translation for Ecore. +# This file is put in the public domain. +# batden , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: Ecore\n" +"Report-Msgid-Bugs-To: enlightenment-devel@lists.sourceforge.net\n" +"POT-Creation-Date: 2012-08-27 19:14+0900\n" +"PO-Revision-Date: 2010-07-11 11:01+0400\n" +"Last-Translator: batden \n" +"Language-Team: Enlightenment French Team \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n>1;\n" +"X-Poedit-Language: French\n" +"X-Poedit-Country: FRANCE\n" +"X-Poedit-SourceCharset: utf-8\n" + +#: src/lib/ecore/ecore_getopt.c:95 +msgid "Version:" +msgstr "Version :" + +#: src/lib/ecore/ecore_getopt.c:104 +msgid "Usage:" +msgstr "Usage :" + +#: src/lib/ecore/ecore_getopt.c:109 +#, c-format +msgid "%s [options]\n" +msgstr "%s [options]\n" + +#: src/lib/ecore/ecore_getopt.c:264 +msgid "Copyright:" +msgstr "Copyright :" + +#: src/lib/ecore/ecore_getopt.c:276 +msgid "License:" +msgstr "Licence :" + +#: src/lib/ecore/ecore_getopt.c:457 +msgid "Type: " +msgstr "Type : " + +#: src/lib/ecore/ecore_getopt.c:533 +msgid "Default: " +msgstr "Par défaut :" + +#: src/lib/ecore/ecore_getopt.c:560 +msgid "Choices: " +msgstr "Choix :" + +#: src/lib/ecore/ecore_getopt.c:661 +msgid "Options:\n" +msgstr "Options :\n" + +#: src/lib/ecore/ecore_getopt.c:788 +#, c-format +msgid "ERROR: unknown option --%s.\n" +msgstr "ERREUR : option inconnue --%s.\n" + +#: src/lib/ecore/ecore_getopt.c:790 +#, c-format +msgid "ERROR: unknown option -%c.\n" +msgstr "ERREUR : option inconnue -%c.\n" + +#: src/lib/ecore/ecore_getopt.c:848 +msgid "ERROR: " +msgstr "ERREUR :" + +#: src/lib/ecore/ecore_getopt.c:931 src/lib/ecore/ecore_getopt.c:1068 +#: src/lib/ecore/ecore_getopt.c:1084 src/lib/ecore/ecore_getopt.c:1099 +#: src/lib/ecore/ecore_getopt.c:1116 src/lib/ecore/ecore_getopt.c:1163 +#: src/lib/ecore/ecore_getopt.c:1283 src/lib/ecore/ecore_getopt.c:1324 +msgid "value has no pointer set.\n" +msgstr "la valeur n'a aucun pointeur défini.\n" + +#: src/lib/ecore/ecore_getopt.c:963 src/lib/ecore/ecore_getopt.c:1183 +#, c-format +msgid "unknown boolean value %s.\n" +msgstr "valeur booléenne inconnue %s.\n" + +#: src/lib/ecore/ecore_getopt.c:1014 src/lib/ecore/ecore_getopt.c:1271 +#, c-format +msgid "invalid number format %s\n" +msgstr "format du nombre non valide %s\n" + +#: src/lib/ecore/ecore_getopt.c:1129 +#, c-format +msgid "invalid choice \"%s\". Valid values are: " +msgstr "choix non valide « %s ». Les valeurs valides sont : " + +#: src/lib/ecore/ecore_getopt.c:1157 +msgid "missing parameter to append.\n" +msgstr "paramètre manquant à ajouter.\n" + +#: src/lib/ecore/ecore_getopt.c:1261 +msgid "could not parse value.\n" +msgstr "analyse de la valeur impossible.\n" + +#: src/lib/ecore/ecore_getopt.c:1318 +msgid "missing parameter.\n" +msgstr "paramètre manquant.\n" + +#: src/lib/ecore/ecore_getopt.c:1331 +msgid "missing callback function!\n" +msgstr "fonction de rappel manquante !\n" + +#: src/lib/ecore/ecore_getopt.c:1360 +msgid "no version was defined.\n" +msgstr "aucune version n'est définie.\n" + +#: src/lib/ecore/ecore_getopt.c:1377 +msgid "no copyright was defined.\n" +msgstr "aucun copyright n'est défini.\n" + +#: src/lib/ecore/ecore_getopt.c:1394 +msgid "no license was defined.\n" +msgstr "aucune licence n'est définie.\n" + +#: src/lib/ecore/ecore_getopt.c:1469 +#, c-format +msgid "ERROR: unknown option --%s, ignored.\n" +msgstr "ERREUR : option inconnue --%s, non prise en compte.\n" + +#: src/lib/ecore/ecore_getopt.c:1502 +#, c-format +msgid "ERROR: option --%s requires an argument!\n" +msgstr "ERREUR : l'option --%s requiert un argument !\n" + +#: src/lib/ecore/ecore_getopt.c:1544 +#, c-format +msgid "ERROR: unknown option -%c, ignored.\n" +msgstr "ERREUR : option inconnue -%c, non prise en compte.\n" + +#: src/lib/ecore/ecore_getopt.c:1582 +#, c-format +msgid "ERROR: option -%c requires an argument!\n" +msgstr "ERREUR : l'option -%c requiert un argument !\n" + +#: src/lib/ecore/ecore_getopt.c:1793 +msgid "ERROR: no parser provided.\n" +msgstr "ERREUR : aucun analyseur n'est fourni.\n" + +#: src/lib/ecore/ecore_getopt.c:1798 +msgid "ERROR: no values provided.\n" +msgstr "ERREUR : aucune valeur n'est fournie.\n" + +#: src/lib/ecore/ecore_getopt.c:1807 +msgid "ERROR: no arguments provided.\n" +msgstr "ERREUR : aucun argument n'est fourni.\n" + +#: src/lib/ecore/ecore_getopt.c:1833 +msgid "ERROR: invalid options found." +msgstr "ERREUR : options non valides détectées." + +#: src/lib/ecore/ecore_getopt.c:1839 +#, c-format +msgid " See --%s.\n" +msgstr " Voir --%s.\n" + +#: src/lib/ecore/ecore_getopt.c:1841 +#, c-format +msgid " See -%c.\n" +msgstr " Voir -%c.\n" + +#: src/lib/ecore/ecore_getopt.c:1887 +#, c-format +msgid "ERROR: incorrect geometry value '%s'\n" +msgstr "ERREUR : valeur géométrique incorrecte « %s »\n" + +#: src/lib/ecore/ecore_getopt.c:1919 +#, c-format +msgid "ERROR: incorrect size value '%s'\n" +msgstr "ERREUR : valeur de taille incorrecte « %s »\n" + +#~ msgid "" +#~ "\n" +#~ " " +#~ msgstr "" +#~ "\n" +#~ " " + +#~ msgid "true" +#~ msgstr "true" + +#~ msgid "false" +#~ msgstr "false" + +#~ msgid "f" +#~ msgstr "f" + +#~ msgid "no" +#~ msgstr "no" + +#~ msgid "off" +#~ msgstr "off" + +#~ msgid "t" +#~ msgstr "t" + +#~ msgid "yes" +#~ msgstr "yes" + +#~ msgid "on" +#~ msgstr "on" diff --git a/po/it.po b/po/it.po new file mode 100644 index 0000000..ae044da --- /dev/null +++ b/po/it.po @@ -0,0 +1,204 @@ +# Italian translation for Ecore. +# This file is put in the public domain. +# Massimo Maiurana , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: Ecore\n" +"Report-Msgid-Bugs-To: enlightenment-devel@lists.sourceforge.net\n" +"POT-Creation-Date: 2012-08-27 19:14+0900\n" +"PO-Revision-Date: 2009-10-27 19:36+0100\n" +"Last-Translator: quaker66 \n" +"Language-Team: none\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/lib/ecore/ecore_getopt.c:95 +msgid "Version:" +msgstr "Versione:" + +#: src/lib/ecore/ecore_getopt.c:104 +msgid "Usage:" +msgstr "Uso:" + +#: src/lib/ecore/ecore_getopt.c:109 +#, c-format +msgid "%s [options]\n" +msgstr "%s [opzioni]\n" + +#: src/lib/ecore/ecore_getopt.c:264 +msgid "Copyright:" +msgstr "Copyright:" + +#: src/lib/ecore/ecore_getopt.c:276 +msgid "License:" +msgstr "Licenza:" + +#: src/lib/ecore/ecore_getopt.c:457 +msgid "Type: " +msgstr "Tipo: " + +#: src/lib/ecore/ecore_getopt.c:533 +msgid "Default: " +msgstr "Predefinito:" + +#: src/lib/ecore/ecore_getopt.c:560 +msgid "Choices: " +msgstr "Scelte:" + +#: src/lib/ecore/ecore_getopt.c:661 +msgid "Options:\n" +msgstr "Opzioni:\n" + +#: src/lib/ecore/ecore_getopt.c:788 +#, c-format +msgid "ERROR: unknown option --%s.\n" +msgstr "ERRORE: opzione sconosciuta --%s.\n" + +#: src/lib/ecore/ecore_getopt.c:790 +#, c-format +msgid "ERROR: unknown option -%c.\n" +msgstr "ERRORE: opzione sconosciuta -%c.\n" + +#: src/lib/ecore/ecore_getopt.c:848 +msgid "ERROR: " +msgstr "ERRORE:" + +#: src/lib/ecore/ecore_getopt.c:931 src/lib/ecore/ecore_getopt.c:1068 +#: src/lib/ecore/ecore_getopt.c:1084 src/lib/ecore/ecore_getopt.c:1099 +#: src/lib/ecore/ecore_getopt.c:1116 src/lib/ecore/ecore_getopt.c:1163 +#: src/lib/ecore/ecore_getopt.c:1283 src/lib/ecore/ecore_getopt.c:1324 +msgid "value has no pointer set.\n" +msgstr "il valore non ha puntatori impostati.\n" + +#: src/lib/ecore/ecore_getopt.c:963 src/lib/ecore/ecore_getopt.c:1183 +#, c-format +msgid "unknown boolean value %s.\n" +msgstr "valore booleano sconosciuto %s.\n" + +#: src/lib/ecore/ecore_getopt.c:1014 src/lib/ecore/ecore_getopt.c:1271 +#, c-format +msgid "invalid number format %s\n" +msgstr "formato numero non valido %s\n" + +#: src/lib/ecore/ecore_getopt.c:1129 +#, c-format +msgid "invalid choice \"%s\". Valid values are: " +msgstr "scelta non valida \"%s\". I valori ammessi sono: " + +#: src/lib/ecore/ecore_getopt.c:1157 +msgid "missing parameter to append.\n" +msgstr "parametro da appendere mancante.\n" + +#: src/lib/ecore/ecore_getopt.c:1261 +msgid "could not parse value.\n" +msgstr "impossibile il parsing del valore.\n" + +#: src/lib/ecore/ecore_getopt.c:1318 +msgid "missing parameter.\n" +msgstr "parametro mancante.\n" + +#: src/lib/ecore/ecore_getopt.c:1331 +msgid "missing callback function!\n" +msgstr "funzione callback mancante!\n" + +#: src/lib/ecore/ecore_getopt.c:1360 +msgid "no version was defined.\n" +msgstr "nessuna versione definita.\n" + +#: src/lib/ecore/ecore_getopt.c:1377 +msgid "no copyright was defined.\n" +msgstr "nessun copyright definito.\n" + +#: src/lib/ecore/ecore_getopt.c:1394 +msgid "no license was defined.\n" +msgstr "nessuna licenza definita.\n" + +#: src/lib/ecore/ecore_getopt.c:1469 +#, c-format +msgid "ERROR: unknown option --%s, ignored.\n" +msgstr "ERRORE: opzione sconosciuta --%s, ignorata.\n" + +#: src/lib/ecore/ecore_getopt.c:1502 +#, c-format +msgid "ERROR: option --%s requires an argument!\n" +msgstr "ERRORE: l'opzione --%s richiede un argomento!\n" + +#: src/lib/ecore/ecore_getopt.c:1544 +#, c-format +msgid "ERROR: unknown option -%c, ignored.\n" +msgstr "ERRORE: opzione sconosciuta -%c, ignorata.\n" + +#: src/lib/ecore/ecore_getopt.c:1582 +#, c-format +msgid "ERROR: option -%c requires an argument!\n" +msgstr "ERRORE: l'opzione -%c richiede un argomento!\n" + +#: src/lib/ecore/ecore_getopt.c:1793 +msgid "ERROR: no parser provided.\n" +msgstr "ERRORE: nessun parser fornito.\n" + +#: src/lib/ecore/ecore_getopt.c:1798 +msgid "ERROR: no values provided.\n" +msgstr "ERRORE: nessun valore fornito.\n" + +#: src/lib/ecore/ecore_getopt.c:1807 +msgid "ERROR: no arguments provided.\n" +msgstr "ERRORE: nessun argomento fornito.\n" + +#: src/lib/ecore/ecore_getopt.c:1833 +msgid "ERROR: invalid options found." +msgstr "ERRORE: trovate opzioni non valide." + +#: src/lib/ecore/ecore_getopt.c:1839 +#, c-format +msgid " See --%s.\n" +msgstr " Vedere --%s.\n" + +#: src/lib/ecore/ecore_getopt.c:1841 +#, c-format +msgid " See -%c.\n" +msgstr " Vedere -%c.\n" + +#: src/lib/ecore/ecore_getopt.c:1887 +#, c-format +msgid "ERROR: incorrect geometry value '%s'\n" +msgstr "ERRORE: valore geometrico non corretto '%s'\n" + +#: src/lib/ecore/ecore_getopt.c:1919 +#, c-format +msgid "ERROR: incorrect size value '%s'\n" +msgstr "ERRORE: valore dimensione non corretto '%s'\n" + +#~ msgid "" +#~ "\n" +#~ " " +#~ msgstr "" +#~ "\n" +#~ " " + +#~ msgid "true" +#~ msgstr "vero" + +#~ msgid "false" +#~ msgstr "falso" + +#~ msgid "f" +#~ msgstr "f" + +#~ msgid "no" +#~ msgstr "no" + +#~ msgid "off" +#~ msgstr "off" + +#~ msgid "t" +#~ msgstr "t" + +#~ msgid "yes" +#~ msgstr "sì" + +#~ msgid "on" +#~ msgstr "on" diff --git a/po/nl.po b/po/nl.po new file mode 100644 index 0000000..4dc3b6e --- /dev/null +++ b/po/nl.po @@ -0,0 +1,175 @@ +# SOME DESCRIPTIVE TITLE. +# This file is put in the public domain. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: Ecore\n" +"Report-Msgid-Bugs-To: enlightenment-devel@lists.sourceforge.net\n" +"POT-Creation-Date: 2012-08-27 19:14+0900\n" +"PO-Revision-Date: 2011-09-03 15:48+0100\n" +"Last-Translator: Heimen Stoffels \n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: NL\n" +"X-Poedit-Country: Nederland\n" + +#: src/lib/ecore/ecore_getopt.c:95 +msgid "Version:" +msgstr "Versie:" + +#: src/lib/ecore/ecore_getopt.c:104 +msgid "Usage:" +msgstr "Gebruik:" + +#: src/lib/ecore/ecore_getopt.c:109 +#, c-format +msgid "%s [options]\n" +msgstr "%s [opties]\n" + +#: src/lib/ecore/ecore_getopt.c:264 +msgid "Copyright:" +msgstr "Copyright:" + +#: src/lib/ecore/ecore_getopt.c:276 +msgid "License:" +msgstr "Licentie:" + +#: src/lib/ecore/ecore_getopt.c:457 +msgid "Type: " +msgstr "Type:" + +#: src/lib/ecore/ecore_getopt.c:533 +msgid "Default: " +msgstr "Standaard:" + +#: src/lib/ecore/ecore_getopt.c:560 +msgid "Choices: " +msgstr "Keuzes:" + +#: src/lib/ecore/ecore_getopt.c:661 +msgid "Options:\n" +msgstr "Opties:\n" + +#: src/lib/ecore/ecore_getopt.c:788 +#, c-format +msgid "ERROR: unknown option --%s.\n" +msgstr "FOUT: onbekende optie --%s.\n" + +#: src/lib/ecore/ecore_getopt.c:790 +#, c-format +msgid "ERROR: unknown option -%c.\n" +msgstr "FOUT: onbekende optie -%c.\n" + +#: src/lib/ecore/ecore_getopt.c:848 +msgid "ERROR: " +msgstr "FOUT:" + +#: src/lib/ecore/ecore_getopt.c:931 src/lib/ecore/ecore_getopt.c:1068 +#: src/lib/ecore/ecore_getopt.c:1084 src/lib/ecore/ecore_getopt.c:1099 +#: src/lib/ecore/ecore_getopt.c:1116 src/lib/ecore/ecore_getopt.c:1163 +#: src/lib/ecore/ecore_getopt.c:1283 src/lib/ecore/ecore_getopt.c:1324 +msgid "value has no pointer set.\n" +msgstr "waarde heeft geen pointer ingsteld.\n" + +#: src/lib/ecore/ecore_getopt.c:963 src/lib/ecore/ecore_getopt.c:1183 +#, c-format +msgid "unknown boolean value %s.\n" +msgstr "onbekende boolean-waarde %s.\n" + +#: src/lib/ecore/ecore_getopt.c:1014 src/lib/ecore/ecore_getopt.c:1271 +#, c-format +msgid "invalid number format %s\n" +msgstr "ongeldig nummerformaat %s\n" + +#: src/lib/ecore/ecore_getopt.c:1129 +#, c-format +msgid "invalid choice \"%s\". Valid values are: " +msgstr "ongeldige keuze \"%s\". Geldige waardes zijn:" + +#: src/lib/ecore/ecore_getopt.c:1157 +msgid "missing parameter to append.\n" +msgstr "parameter om toe te wijzen ontbreekt.\n" + +#: src/lib/ecore/ecore_getopt.c:1261 +msgid "could not parse value.\n" +msgstr "kon waarde niet doorvoeren.\n" + +#: src/lib/ecore/ecore_getopt.c:1318 +msgid "missing parameter.\n" +msgstr "paramater ontbreekt.\n" + +#: src/lib/ecore/ecore_getopt.c:1331 +msgid "missing callback function!\n" +msgstr "ontbrekende terugroep-functie!\n" + +#: src/lib/ecore/ecore_getopt.c:1360 +msgid "no version was defined.\n" +msgstr "geen versie was gedefinieerd.\n" + +#: src/lib/ecore/ecore_getopt.c:1377 +msgid "no copyright was defined.\n" +msgstr "geen copyright was gedefinieerd.\n" + +#: src/lib/ecore/ecore_getopt.c:1394 +msgid "no license was defined.\n" +msgstr "geen licentie was gedefinieerd.\n" + +#: src/lib/ecore/ecore_getopt.c:1469 +#, c-format +msgid "ERROR: unknown option --%s, ignored.\n" +msgstr "FOUT: onbekende optie --%s, genegeerd.\n" + +#: src/lib/ecore/ecore_getopt.c:1502 +#, c-format +msgid "ERROR: option --%s requires an argument!\n" +msgstr "FOUT: optie --%s vereist een argument!\n" + +#: src/lib/ecore/ecore_getopt.c:1544 +#, c-format +msgid "ERROR: unknown option -%c, ignored.\n" +msgstr "FOUT: onbekende opties -%c, genegeerd.\n" + +#: src/lib/ecore/ecore_getopt.c:1582 +#, c-format +msgid "ERROR: option -%c requires an argument!\n" +msgstr "FOUT: optie -%c vereist een argument!\n" + +#: src/lib/ecore/ecore_getopt.c:1793 +msgid "ERROR: no parser provided.\n" +msgstr "FOUT: geen doorvoerder beschikbaar gesteld.\n" + +#: src/lib/ecore/ecore_getopt.c:1798 +msgid "ERROR: no values provided.\n" +msgstr "FOUT: geen waarden beschikbaar gesteld.\n" + +#: src/lib/ecore/ecore_getopt.c:1807 +msgid "ERROR: no arguments provided.\n" +msgstr "FOUT: geen argumenten beschibaar gesteld.\n" + +#: src/lib/ecore/ecore_getopt.c:1833 +msgid "ERROR: invalid options found." +msgstr "FOUT: ongeldige opties gevonden." + +#: src/lib/ecore/ecore_getopt.c:1839 +#, c-format +msgid " See --%s.\n" +msgstr "Zie --%s.\n" + +#: src/lib/ecore/ecore_getopt.c:1841 +#, c-format +msgid " See -%c.\n" +msgstr "Zie -%c.\n" + +#: src/lib/ecore/ecore_getopt.c:1887 +#, c-format +msgid "ERROR: incorrect geometry value '%s'\n" +msgstr "Fout: foutieve wiskundige waarde '%s'\n" + +#: src/lib/ecore/ecore_getopt.c:1919 +#, c-format +msgid "ERROR: incorrect size value '%s'\n" +msgstr "FOUT: foutieve grootte-waarden '%s'\n" diff --git a/po/pt.po b/po/pt.po new file mode 100644 index 0000000..01475f8 --- /dev/null +++ b/po/pt.po @@ -0,0 +1,176 @@ +# Portuguese translation for ecore +# This file is distributed under the same license as the enlightenment package. +# Sérgio Marques , 2010 +# +msgid "" +msgstr "" +"Project-Id-Version: ecore\n" +"Report-Msgid-Bugs-To: enlightenment-devel@lists.sourceforge.net\n" +"POT-Creation-Date: 2012-08-27 19:14+0900\n" +"PO-Revision-Date: 2012-08-23 00:30+0100\n" +"Last-Translator: Sérgio Marques \n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Poedit-Language: Portuguese\n" +"X-Poedit-Country: Portugal\n" + +#: src/lib/ecore/ecore_getopt.c:95 +msgid "Version:" +msgstr "Versão:" + +#: src/lib/ecore/ecore_getopt.c:104 +msgid "Usage:" +msgstr "Utilização:" + +#: src/lib/ecore/ecore_getopt.c:109 +#, c-format +msgid "%s [options]\n" +msgstr "%s [opções]\n" + +#: src/lib/ecore/ecore_getopt.c:264 +msgid "Copyright:" +msgstr "Direitos de autor:" + +#: src/lib/ecore/ecore_getopt.c:276 +msgid "License:" +msgstr "Licença:" + +#: src/lib/ecore/ecore_getopt.c:457 +msgid "Type: " +msgstr "Tipo:" + +#: src/lib/ecore/ecore_getopt.c:533 +msgid "Default: " +msgstr "Padrão:" + +#: src/lib/ecore/ecore_getopt.c:560 +msgid "Choices: " +msgstr "Escolhas:" + +#: src/lib/ecore/ecore_getopt.c:661 +msgid "Options:\n" +msgstr "Opções:\n" + +#: src/lib/ecore/ecore_getopt.c:788 +#, c-format +msgid "ERROR: unknown option --%s.\n" +msgstr "ERRO: opção desconhecida --%s.\n" + +#: src/lib/ecore/ecore_getopt.c:790 +#, c-format +msgid "ERROR: unknown option -%c.\n" +msgstr "ERRO: opção desconhecida -%c.\n" + +#: src/lib/ecore/ecore_getopt.c:848 +msgid "ERROR: " +msgstr "ERRO: " + +#: src/lib/ecore/ecore_getopt.c:931 src/lib/ecore/ecore_getopt.c:1068 +#: src/lib/ecore/ecore_getopt.c:1084 src/lib/ecore/ecore_getopt.c:1099 +#: src/lib/ecore/ecore_getopt.c:1116 src/lib/ecore/ecore_getopt.c:1163 +#: src/lib/ecore/ecore_getopt.c:1283 src/lib/ecore/ecore_getopt.c:1324 +msgid "value has no pointer set.\n" +msgstr "o valor não está definido.\n" + +#: src/lib/ecore/ecore_getopt.c:963 src/lib/ecore/ecore_getopt.c:1183 +#, c-format +msgid "unknown boolean value %s.\n" +msgstr "valor booleano desconhecido %s.\n" + +#: src/lib/ecore/ecore_getopt.c:1014 src/lib/ecore/ecore_getopt.c:1271 +#, c-format +msgid "invalid number format %s\n" +msgstr "formato numérico inválido %s\n" + +#: src/lib/ecore/ecore_getopt.c:1129 +#, c-format +msgid "invalid choice \"%s\". Valid values are: " +msgstr "escolha inválida \"%s\". O valores possíveis são:" + +#: src/lib/ecore/ecore_getopt.c:1157 +msgid "missing parameter to append.\n" +msgstr "faltam os parâmetros a anexar.\n" + +#: src/lib/ecore/ecore_getopt.c:1261 +msgid "could not parse value.\n" +msgstr "incapaz de processar o valor.\n" + +#: src/lib/ecore/ecore_getopt.c:1318 +msgid "missing parameter.\n" +msgstr "parâmetro em falta.\n" + +#: src/lib/ecore/ecore_getopt.c:1331 +msgid "missing callback function!\n" +msgstr "função de invocação em falta!\n" + +#: src/lib/ecore/ecore_getopt.c:1360 +msgid "no version was defined.\n" +msgstr "nenhuma versão definida.\n" + +#: src/lib/ecore/ecore_getopt.c:1377 +msgid "no copyright was defined.\n" +msgstr "direitos de autor não definidos.\n" + +#: src/lib/ecore/ecore_getopt.c:1394 +msgid "no license was defined.\n" +msgstr "licença não definida.\n" + +#: src/lib/ecore/ecore_getopt.c:1469 +#, c-format +msgid "ERROR: unknown option --%s, ignored.\n" +msgstr "ERRO: opção desconhecida --%s, ignorada.\n" + +#: src/lib/ecore/ecore_getopt.c:1502 +#, c-format +msgid "ERROR: option --%s requires an argument!\n" +msgstr "ERRO: a opção --%s requer um argumento!\n" + +#: src/lib/ecore/ecore_getopt.c:1544 +#, c-format +msgid "ERROR: unknown option -%c, ignored.\n" +msgstr "ERRO: opção desconhecida --%c, ignorada.\n" + +#: src/lib/ecore/ecore_getopt.c:1582 +#, c-format +msgid "ERROR: option -%c requires an argument!\n" +msgstr "ERRO: a opção --%c requer um argumento!\n" + +#: src/lib/ecore/ecore_getopt.c:1793 +msgid "ERROR: no parser provided.\n" +msgstr "ERRO: nenhum processador fornecido.\n" + +#: src/lib/ecore/ecore_getopt.c:1798 +msgid "ERROR: no values provided.\n" +msgstr "ERRO: nenhum valor fornecido.\n" + +#: src/lib/ecore/ecore_getopt.c:1807 +msgid "ERROR: no arguments provided.\n" +msgstr "ERRO: nenhum argumento fornecido.\n" + +#: src/lib/ecore/ecore_getopt.c:1833 +msgid "ERROR: invalid options found." +msgstr "ERRO: encontradas opções inválidas." + +#: src/lib/ecore/ecore_getopt.c:1839 +#, c-format +msgid " See --%s.\n" +msgstr "Consulte --%s.\n" + +#: src/lib/ecore/ecore_getopt.c:1841 +#, c-format +msgid " See -%c.\n" +msgstr "Consulte -%c.\n" + +#: src/lib/ecore/ecore_getopt.c:1887 +#, c-format +msgid "ERROR: incorrect geometry value '%s'\n" +msgstr "ERRO: valor geométrico incorreto \"%s\"\n" + +#: src/lib/ecore/ecore_getopt.c:1919 +#, c-format +msgid "ERROR: incorrect size value '%s'\n" +msgstr "ERRO: tamanho incorreto \"%s\"\n" diff --git a/po/sl.po b/po/sl.po new file mode 100644 index 0000000..e5224d5 --- /dev/null +++ b/po/sl.po @@ -0,0 +1,175 @@ +# Slovenian translation of ecore. +# This file is put in the public domain. +# r1to , 2011. +# , fuzzy +# +# +msgid "" +msgstr "" +"Project-Id-Version: ecore 1.0\n" +"Report-Msgid-Bugs-To: enlightenment-devel@lists.sourceforge.net\n" +"POT-Creation-Date: 2012-08-27 19:14+0900\n" +"PO-Revision-Date: 2011-02-24 16:54+0100\n" +"Last-Translator: r1to \n" +"Language-Team: Slovenian \n" +"Language: sl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/lib/ecore/ecore_getopt.c:95 +msgid "Version:" +msgstr "Različica" + +#: src/lib/ecore/ecore_getopt.c:104 +msgid "Usage:" +msgstr "Uporaba:" + +#: src/lib/ecore/ecore_getopt.c:109 +#, c-format +msgid "%s [options]\n" +msgstr "%s·[možnosti]\n" + +#: src/lib/ecore/ecore_getopt.c:264 +msgid "Copyright:" +msgstr "Avtorstvo:" + +#: src/lib/ecore/ecore_getopt.c:276 +msgid "License:" +msgstr "Licenca:" + +#: src/lib/ecore/ecore_getopt.c:457 +msgid "Type: " +msgstr "Vrsta:·" + +#: src/lib/ecore/ecore_getopt.c:533 +msgid "Default: " +msgstr "Privzeto:·" + +#: src/lib/ecore/ecore_getopt.c:560 +msgid "Choices: " +msgstr "Izbire:·" + +#: src/lib/ecore/ecore_getopt.c:661 +msgid "Options:\n" +msgstr "Možnosti:\n" + +#: src/lib/ecore/ecore_getopt.c:788 +#, c-format +msgid "ERROR: unknown option --%s.\n" +msgstr "NAPAKA:·Neznana možnost·--%s.\n" + +#: src/lib/ecore/ecore_getopt.c:790 +#, c-format +msgid "ERROR: unknown option -%c.\n" +msgstr "NAPAKA:·neznana možnost·-%c.\n" + +#: src/lib/ecore/ecore_getopt.c:848 +msgid "ERROR: " +msgstr "NAPAKA:" + +#: src/lib/ecore/ecore_getopt.c:931 src/lib/ecore/ecore_getopt.c:1068 +#: src/lib/ecore/ecore_getopt.c:1084 src/lib/ecore/ecore_getopt.c:1099 +#: src/lib/ecore/ecore_getopt.c:1116 src/lib/ecore/ecore_getopt.c:1163 +#: src/lib/ecore/ecore_getopt.c:1283 src/lib/ecore/ecore_getopt.c:1324 +msgid "value has no pointer set.\n" +msgstr "vrednost nima nastavljenega kazalnika.\n" + +#: src/lib/ecore/ecore_getopt.c:963 src/lib/ecore/ecore_getopt.c:1183 +#, c-format +msgid "unknown boolean value %s.\n" +msgstr "neznana Boolova vrednost·%s.\n" + +#: src/lib/ecore/ecore_getopt.c:1014 src/lib/ecore/ecore_getopt.c:1271 +#, c-format +msgid "invalid number format %s\n" +msgstr "napačen·format števila·%s\n" + +#: src/lib/ecore/ecore_getopt.c:1129 +#, c-format +msgid "invalid choice \"%s\". Valid values are: " +msgstr "napačna izbira·\"%s\".·Pravilne izbire so:·" + +#: src/lib/ecore/ecore_getopt.c:1157 +msgid "missing parameter to append.\n" +msgstr "manjka·parameter·za dodajo.\n" + +#: src/lib/ecore/ecore_getopt.c:1261 +msgid "could not parse value.\n" +msgstr "vrednosti ni bilo možno razčleniti.\n" + +#: src/lib/ecore/ecore_getopt.c:1318 +msgid "missing parameter.\n" +msgstr "manjkajoči·parameter.\n" + +#: src/lib/ecore/ecore_getopt.c:1331 +msgid "missing callback function!\n" +msgstr "manjkajoča povratno-zasilna funkcija !\n" + +#: src/lib/ecore/ecore_getopt.c:1360 +msgid "no version was defined.\n" +msgstr "definirana ni bila nobena različica.\n" + +#: src/lib/ecore/ecore_getopt.c:1377 +msgid "no copyright was defined.\n" +msgstr "definirano ni bilo nobeno avtorstvo.\n" + +#: src/lib/ecore/ecore_getopt.c:1394 +msgid "no license was defined.\n" +msgstr "definirana ni bila nobena licenca.\n" + +#: src/lib/ecore/ecore_getopt.c:1469 +#, c-format +msgid "ERROR: unknown option --%s, ignored.\n" +msgstr "NAPAKA:·neznana možnost·--%s,·prezrto.\n" + +#: src/lib/ecore/ecore_getopt.c:1502 +#, c-format +msgid "ERROR: option --%s requires an argument!\n" +msgstr "NAPAKA:·možnost·--%s·zahteva argument!\n" + +#: src/lib/ecore/ecore_getopt.c:1544 +#, c-format +msgid "ERROR: unknown option -%c, ignored.\n" +msgstr "NAPAKA:·neznana možnost·-%c,·prezrto.\n" + +#: src/lib/ecore/ecore_getopt.c:1582 +#, c-format +msgid "ERROR: option -%c requires an argument!\n" +msgstr "NAPAKA:·možnost·-%c zahteva argument!\n" + +#: src/lib/ecore/ecore_getopt.c:1793 +msgid "ERROR: no parser provided.\n" +msgstr "NAPAKA:·ni podan razčlenjevalnik.\n" + +#: src/lib/ecore/ecore_getopt.c:1798 +msgid "ERROR: no values provided.\n" +msgstr "NAPAKA::·ni podanih vrednosti.\n" + +#: src/lib/ecore/ecore_getopt.c:1807 +msgid "ERROR: no arguments provided.\n" +msgstr "NAPAKA::·ni podanih argumentov.\n" + +#: src/lib/ecore/ecore_getopt.c:1833 +msgid "ERROR: invalid options found." +msgstr "NAPAKA::·najdene nepravilne možnosti" + +#: src/lib/ecore/ecore_getopt.c:1839 +#, c-format +msgid " See --%s.\n" +msgstr "·Glej·--%s.\n" + +#: src/lib/ecore/ecore_getopt.c:1841 +#, c-format +msgid " See -%c.\n" +msgstr "·Glej·-%c.\n" + +#: src/lib/ecore/ecore_getopt.c:1887 +#, c-format +msgid "ERROR: incorrect geometry value '%s'\n" +msgstr "NAPAKA::·nepravilna geometrijska vrednost·'%s'\n" + +#: src/lib/ecore/ecore_getopt.c:1919 +#, c-format +msgid "ERROR: incorrect size value '%s'\n" +msgstr "NAPAKA::·nepravilna vrednost velikosti·'%s'\n" diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..b8dab4f --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,26 @@ +MAINTAINERCLEANFILES = Makefile.in + +SUBDIRS = lib bin tests examples modules + +if BUILD_ECORE_X_XCB + MAINTAINERCLEANFILES += ecore_xcb_keysym_table.h ecore_xcb_keysym_table_h + CLEANFILES = ecore_xcb_keysym_table.h ecore_xcb_keysym_table_h + + SUBDIRS += util + + BUILT_SOURCES=ecore_xcb_keysym_table.h + + # + # Building ecore_xcb_keysym_table.h requires the makekeys utility + # + + ecore_xcb_keysym_table.h: $(KEYSYMDEFS) $(top_builddir)/src/util/makekeys$(EXEEXT) + $(top_builddir)/src/util/makekeys $(KEYSYMDEFS) > ecore_xcb_keysym_table_h + mv -f ecore_xcb_keysym_table_h ./lib/ecore_x/xcb/$@ + + $(top_builddir)/src/util/makekeys$(EXEEXT): force + cd util && $(MAKE) + + force: + +endif diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am new file mode 100644 index 0000000..79110e4 --- /dev/null +++ b/src/bin/Makefile.am @@ -0,0 +1,51 @@ +MAINTAINERCLEANFILES = Makefile.in + +if BUILD_ECORE_CONFIG +ECORE_CONFIG_PROG = ecore_config +ECORE_CONFIG_LIB = $(top_builddir)/src/lib/ecore_config/libecore_config.la +else +ECORE_CONFIG_PROG = +ECORE_CONFIG_LIB = +endif + +if EFL_ENABLE_TESTS +ECORE_TEST_PROG = ecore_test +endif + +AM_CPPFLAGS = \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore_config \ +-I$(top_builddir)/src/lib/ecore \ +-I$(top_builddir)/src/lib/ecore_config \ +-DPACKAGE_BIN_DIR=\"$(bindir)\" \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \ +@EINA_CFLAGS@ @EVAS_CFLAGS@ + +bin_PROGRAMS = $(ECORE_CONFIG_PROG) $(ECORE_TEST_PROG) + +ecore_config_SOURCES = \ +ecore_config.c + +ecore_config_LDADD = \ +$(ECORE_CONFIG_LIB) \ +$(top_builddir)/src/lib/ecore_ipc/libecore_ipc.la \ +$(top_builddir)/src/lib/ecore_con/libecore_con.la \ +$(top_builddir)/src/lib/ecore/libecore.la \ +@EINA_LIBS@ @EVAS_LIBS@ + +ecore_config_DEPENDENCIES = \ +$(top_builddir)/src/lib/ecore_ipc/libecore_ipc.la \ +$(top_builddir)/src/lib/ecore_con/libecore_con.la \ +$(top_builddir)/src/lib/ecore/libecore.la \ +$(ECORE_CONFIG_LIB) + +ecore_test_SOURCES = \ +ecore_test.c + +ecore_test_LDADD = \ +$(top_builddir)/src/lib/ecore/libecore.la \ +@EINA_LIBS@ @EVAS_LIBS@ + +ecore_test_DEPENDENCIES = \ +$(top_builddir)/src/lib/ecore/libecore.la diff --git a/src/bin/ecore_config.c b/src/bin/ecore_config.c new file mode 100644 index 0000000..b4973d9 --- /dev/null +++ b/src/bin/ecore_config.c @@ -0,0 +1,324 @@ +#include "config.h" +#include "Ecore.h" + +#include +#include +#include + +#ifdef BUILD_ECORE_CONFIG +#include +#include +#include +#include "Ecore_Config.h" +#include "ecore_config_private.h" + +// strcmp for paths - for sorting folders before files +static int +pathcmp(const char *s1, const char *s2) +{ + char *s1d, *s2d; + + // strip common part of paths + while(*s1 && *s2 && *s1 == *s2) + { + s1++; + s2++; + } + + // handle /foo/bar/baz <> /foo/bar_baz properly + if (*s1 == '/' && *s2 != '/') return -1; + if (*s1 != '/' && *s2 == '/') return 1; + + // skip leading / + if (*s1 == '/') s1++; + if (*s2 == '/') s2++; + + // order folders before files + s1d = strchr(s1, '/'); + s2d = strchr(s2, '/'); + if (s1d && !s2d) return -1; + if (!s1d && s2d) return 1; + + return strcmp(s1, s2); +} + +static int +del(const char *key) +{ + Ecore_Config_Prop *e; + e = ecore_config_get(key); + if(!e) return -1; + + ecore_config_dst(e); + return 0; +} + +static int +get(const char *key) +{ + Ecore_Config_Prop *e; + char *temp = NULL; + + if (!(e = ecore_config_get(key))) + { + EINA_LOG_ERR("No such property"); + return -1; + } + + printf("%-10s", ecore_config_type_get(e)); + + switch (e->type) + { + case ECORE_CONFIG_NIL: + printf("\n"); + break; + case ECORE_CONFIG_INT: + printf("%ld\n", ecore_config_int_get(key)); + break; + case ECORE_CONFIG_BLN: + printf("%d\n", ecore_config_boolean_get(key)); + break; + case ECORE_CONFIG_FLT: + printf("%lf\n", ecore_config_float_get(key)); + break; + case ECORE_CONFIG_STR: + temp = ecore_config_string_get(key); + break; + case ECORE_CONFIG_RGB: + temp = ecore_config_argbstr_get(key); + break; + case ECORE_CONFIG_THM: + temp = ecore_config_theme_get(key); + break; + default: + EINA_LOG_ERR("Property has unrecognized type"); + return -1; + } + if(temp) + { + printf("\"%s\"\n", temp); + free(temp); + } + return 0; +} + +static int +list(const char *file) +{ + Ecore_Config_Prop *e; + Eina_List *keys = NULL; + char *key; + + e = __ecore_config_bundle_local->data; + + do + { + // don't show system settings + if( !(e->flags & ECORE_CONFIG_FLAG_SYSTEM) ) + keys = eina_list_append(keys, e->key); + } + while((e = e->next)); + keys = eina_list_sort(keys, -1, EINA_COMPARE_CB(pathcmp)); + + EINA_LIST_FREE(keys, key) + { + printf("%-28s\t", key); + get(key); + } + + return 0; +} + +static void +usage_and_exit(const char *prog, int ret, const char *msg) +{ + if (msg) fprintf(stderr, "%s\n\n", msg); + fprintf(stderr, "Usage: %s \n", prog); + fprintf(stderr, "Modify ecore_config files\n\n"); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -c, --file=FILE config file\n"); + fprintf(stderr, " -k, --key=KEY must be given for all commands except -a\n\n"); + fprintf(stderr, "Commands:\n"); + fprintf(stderr, " -a, --list get all keys\n"); + fprintf(stderr, " -g, --get get key\n"); + fprintf(stderr, " -d, --del delete key\n"); + fprintf(stderr, " -b, --bool=VALUE set boolean\n"); + fprintf(stderr, " -f, --float=VALUE set float\n"); + fprintf(stderr, " -i, --int=VALUE set integer\n"); + fprintf(stderr, " -r, --rgb=VALUE set RGBA\n"); + fprintf(stderr, " -s, --string=VALUE set string\n"); + fprintf(stderr, " -t, --theme=VALUE set theme\n\n"); + exit(ret); +} + +int +main(int argc, char * const argv[]) +{ + char *prog, *file, *key; + void *value = (void *)NULL; + char cmd = 's'; + int type = -1; + int ret = 0; + long i; + float f; + + file = key = prog = NULL; + eina_init(); + prog = strdup(argv[0]); + + if(argc < 4) + usage_and_exit(prog, 2, NULL); + + while(1) + { + static struct option long_options[] = { + {"file", 1, 0, 'c'}, + {"list", 0, 0, 'a'}, + {"get", 0, 0, 'g'}, + {"del", 0, 0, 'd'}, + {"bool", 1, 0, 'b'}, + {"float", 1, 0, 'f'}, + {"int", 1, 0, 'i'}, + {"rgb", 1, 0, 'r'}, + {"string", 1, 0, 's'}, + {"theme", 1, 0, 't'}, + {"key", 1, 0, 'k'}, + {0, 0, 0, 0} + }; + + ret = getopt_long(argc, argv, "c:agdb:f:i:r:s:t:k:", long_options, NULL); + if(ret == -1) + break; + + switch(ret) + { + case 'k': + key = strdup(optarg); + break; + case 'n': + if(value) + usage_and_exit(prog, 2, "too many commands"); + type = ECORE_CONFIG_NIL; + value = NULL; + break; + case 'b': + if(value) + usage_and_exit(prog, 2, "too many commands"); + type = ECORE_CONFIG_BLN; + i = atoi(optarg); + value = &i; + break; + case 'i': + if(value) + usage_and_exit(prog, 2, "too many commands"); + type = ECORE_CONFIG_INT; + i = atoi(optarg); + value = &i; + break; + case 'f': + if(value) + usage_and_exit(prog, 2, "too many commands"); + type = ECORE_CONFIG_FLT; + f = atof(optarg); + value = &f; + break; + case 'r': + if(value) + usage_and_exit(prog, 2, "too many commands"); + type = ECORE_CONFIG_RGB; + i = (long) strtoul( (*optarg == '#') ? (optarg + 1) : optarg, NULL, 16 ); + value = &i; + break; + case 's': + if(value) + usage_and_exit(prog, 2, "too many commands"); + type = ECORE_CONFIG_STR; + value = strdup(optarg); + break; + case 't': + if(value) + usage_and_exit(prog, 2, "too many commands"); + type = ECORE_CONFIG_THM; + value = strdup(optarg); + break; + case 'c': + if(file) + free(file); + file = strdup(optarg); + break; + case '?': + case ':': + return 1; + default: + cmd = ret; + break; + } + } + + if(cmd == 's' && type == -1) + usage_and_exit(prog, 2, "You need to specify a command!"); + + if(cmd != 'a' && !key) + usage_and_exit(prog, 2, "You need to specify key!"); + + if(ecore_config_init("econfig") != ECORE_CONFIG_ERR_SUCC) + { + EINA_LOG_ERR("Couldn't init ecore_config!"); + return 1; + } + + // Load configuration from file + ecore_config_file_load(file); + + ret = 0; + + // Execute command + switch (cmd) + { + case 's': + if (ecore_config_typed_set(key, value, type) != ECORE_CONFIG_ERR_SUCC) + { + fprintf(stderr, "Set failed for %s", key); + ret = 1; + } else { + ecore_config_file_save(file); + } + get(key); // display value after setting it + break; + case 'd': + if(del(key)) + { + fprintf(stderr, "Delete failed for %s", key); + ret = 1; + } else { + ecore_config_file_save(file); + } + break; + case 'g': + if (get(key)) ret = 1; + break; + case 'a': + if (list(file)) ret = 1; + break; + default: + EINA_LOG_ERR("Unhandled command '%c'", cmd); + } + + ecore_config_shutdown(); + + if(type == ECORE_CONFIG_STR || type == ECORE_CONFIG_THM) + free(value); + + if(file) + free(file); + eina_shutdown(); + return ret; +} +#else +int +main(int argc, const char **argv) +{ + printf("Ecore_config module not compiled. This program is empty.\n"); + return -1; +} +#endif diff --git a/src/bin/ecore_test.c b/src/bin/ecore_test.c new file mode 100644 index 0000000..851b2dd --- /dev/null +++ b/src/bin/ecore_test.c @@ -0,0 +1,109 @@ +#include "config.h" + +#include +#include +#include + +const char *called = NULL; + +static const char *idler_str = "idler"; +static const char *idle_enterer_str = "idler_enterer"; +static const char *idle_exiter_str = "idler_exiter"; +static const char *timer1_str = "timer 1"; +static const char *timer2_str = "timer 2"; +static const char *pipe_read_str = "pipe read"; + +int count; +Ecore_Pipe *the_pipe; + +Eina_Bool timer_one(void *data __UNUSED__) +{ + fprintf(stderr, "timer 1\n"); + assert(called == pipe_read_str); + called = timer1_str; + ecore_pipe_write(the_pipe, "b", 1); + + count++; + if (count == 10) + { + ecore_main_loop_quit(); + return EINA_FALSE; + } + + return EINA_TRUE; +} + +Eina_Bool timer_two(void *data __UNUSED__) +{ + fprintf(stderr, "timer 2\n"); + assert(called == timer1_str); + called = timer2_str; + + return EINA_TRUE; +} + +Eina_Bool idle_enterer_one(void *data __UNUSED__) +{ + fprintf(stderr, "idle enterer!\n"); + switch (count) + { + default: + assert(called == timer2_str); + break; + case 1: + assert(called == timer1_str); + break; + case 0: + assert(called == NULL); + } + called = idle_enterer_str; + return EINA_TRUE; +} + +Eina_Bool idler_one(void *data __UNUSED__) +{ + fprintf(stderr, "idler!\n"); + assert(called == idle_enterer_str); + called = idler_str; + if (count == 0) + ecore_timer_add(0.0, timer_two, NULL); + return EINA_TRUE; +} + +Eina_Bool idle_exiter_one(void *data __UNUSED__) +{ + fprintf(stderr, "idle exiter!\n"); + assert(called == idler_str); + called = idle_exiter_str; + return EINA_TRUE; +} + +void pipe_read(void *data __UNUSED__, void *buffer __UNUSED__, unsigned int nbyte __UNUSED__) +{ + fprintf(stderr, "pipe read\n"); + assert(called == idle_exiter_str); + called = pipe_read_str; +} + +int main(int argc __UNUSED__, char **argv __UNUSED__) +{ + assert(1 == ecore_init()); + + the_pipe = ecore_pipe_add(&pipe_read, NULL); + assert(the_pipe != NULL); + assert(EINA_TRUE == ecore_pipe_write(the_pipe, "a", 1)); + + assert(NULL != ecore_timer_add(0.0, timer_one, NULL)); + + assert(NULL != ecore_idle_enterer_add(&idle_enterer_one, NULL)); + assert(NULL != ecore_idler_add(&idler_one, NULL)); + assert(NULL != ecore_idle_exiter_add(&idle_exiter_one, NULL)); + + ecore_main_loop_begin(); + + /* glib main loop exits on an idle enterer */ + assert(called == idle_enterer_str); + + assert(0 == ecore_shutdown()); + return 0; +} diff --git a/src/examples/Makefile.am b/src/examples/Makefile.am new file mode 100644 index 0000000..00ea91d --- /dev/null +++ b/src/examples/Makefile.am @@ -0,0 +1,117 @@ +MAINTAINERCLEANFILES = Makefile.in + +examplesdir = $(datadir)/$(PACKAGE)/examples + +filesdir = $(datadir)/$(PACKAGE)/examples +files_DATA = + +AM_CPPFLAGS = \ +-I. \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore_evas \ +-I$(top_srcdir)/src/lib/ecore_input \ +-I$(top_srcdir)/src/lib/ecore_con \ +-DPACKAGE_EXAMPLES_DIR=\"$(datadir)/$(PACKAGE)/examples\" \ +@GLIB_CFLAGS@ @EVIL_CFLAGS@ @EVAS_CFLAGS@ @EINA_CFLAGS@ @WIN32_CPPFLAGS@ @EFL_ECORE_BUILD@ + +ECOREBASELDADD = \ + $(top_builddir)/src/lib/ecore/libecore.la \ + $(top_builddir)/src/lib/ecore_evas/libecore_evas.la \ + @dlopen_libs@ @EINA_LIBS@ @EVIL_LIBS@ @EVAS_LIBS@ @GLIB_LIBS@ @WIN32_LIBS@ @LTLIBINTL@ @EFL_PTHREAD_LIBS@ @rt_libs@ -lm + + +LDADD = \ + $(ECOREBASELDADD) + +SRCS = \ + ecore_animator_example.c \ + ecore_fd_handler_example.c \ + ecore_poller_example.c \ + ecore_event_example_01.c \ + ecore_event_example_02.c \ + ecore_idler_example.c \ + ecore_timer_example.c \ + ecore_time_functions_example.c \ + ecore_job_example.c \ + ecore_con_lookup_example.c \ + ecore_con_url_headers_example.c \ + ecore_con_url_download_example.c \ + ecore_con_url_cookies_example.c \ + ecore_con_server_simple_example.c \ + ecore_con_server_http_example.c \ + ecore_con_client_simple_example.c \ + ecore_client_bench.c \ + ecore_server_bench.c \ + ecore_con_client_example.c \ + ecore_con_server_example.c \ + ecore_fd_handler_gnutls_example.c \ + ecore_file_download_example.c \ + ecore_pipe_simple_example.c \ + ecore_pipe_gstreamer_example.c \ + ecore_thread_example.c \ + ecore_evas_callbacks.c \ + ecore_evas_window_sizes_example.c \ + ecore_evas_object_example.c \ + ecore_evas_basics_example.c \ + ecore_evas_buffer_example_01.c \ + ecore_evas_buffer_example_02.c \ + ecore_evas_ews_example.c \ + ecore_exe_example.c \ + ecore_exe_example_child.c + +EXTRA_DIST = $(SRCS) \ + $(srcdir)/red.png + +examples_PROGRAMS = + +if EFL_INSTALL_EXAMPLES +files_DATA += $(SRCS) \ + $(srcdir)/red.png +endif + +if EFL_BUILD_EXAMPLES +examples_PROGRAMS += \ + ecore_animator_example \ + ecore_fd_handler_example \ + ecore_poller_example \ + ecore_event_example_01 \ + ecore_event_example_02 \ + ecore_idler_example \ + ecore_job_example \ + ecore_timer_example \ + ecore_time_functions_example \ + ecore_pipe_simple_example \ + ecore_con_lookup_example \ + ecore_con_url_headers_example \ + ecore_con_url_download_example \ + ecore_con_url_cookies_example \ + ecore_con_server_simple_example \ + ecore_con_server_http_example \ + ecore_con_client_simple_example \ + ecore_thread_example \ + ecore_evas_callbacks \ + ecore_evas_window_sizes_example \ + ecore_evas_object_example \ + ecore_evas_basics_example \ + ecore_evas_buffer_example_01 \ + ecore_evas_buffer_example_02 \ + ecore_evas_ews_example \ + ecore_client_bench \ + ecore_server_bench \ + ecore_exe_example \ + ecore_exe_example_child + +ecore_con_lookup_example_LDADD = $(ECOREBASELDADD) $(top_builddir)/src/lib/ecore_con/libecore_con.la +ecore_con_url_headers_example_LDADD = $(ECOREBASELDADD) $(top_builddir)/src/lib/ecore_con/libecore_con.la +ecore_con_url_download_example_LDADD = $(ECOREBASELDADD) $(top_builddir)/src/lib/ecore_con/libecore_con.la +ecore_con_url_cookies_example_LDADD = $(ECOREBASELDADD) $(top_builddir)/src/lib/ecore_con/libecore_con.la +ecore_con_server_simple_example_LDADD = $(ECOREBASELDADD) $(top_builddir)/src/lib/ecore_con/libecore_con.la +ecore_con_server_http_example_LDADD = $(ECOREBASELDADD) $(top_builddir)/src/lib/ecore_con/libecore_con.la +ecore_con_client_simple_example_LDADD = $(ECOREBASELDADD) $(top_builddir)/src/lib/ecore_con/libecore_con.la +ecore_evas_window_sizes_example_LDADD = $(ECOREBASELDADD) @EVAS_LIBS@ $(top_builddir)/src/lib/ecore_evas/libecore_evas.la +ecore_evas_buffer_example_01_LDADD = $(ECOREBASELDADD) @EVAS_LIBS@ $(top_builddir)/src/lib/ecore_evas/libecore_evas.la +ecore_evas_buffer_example_02_LDADD = $(ECOREBASELDADD) @EVAS_LIBS@ $(top_builddir)/src/lib/ecore_evas/libecore_evas.la +ecore_client_bench_LDADD = $(ECOREBASELDADD) $(top_builddir)/src/lib/ecore_con/libecore_con.la +ecore_server_bench_LDADD = $(ECOREBASELDADD) $(top_builddir)/src/lib/ecore_con/libecore_con.la + +endif diff --git a/src/examples/ecore_animator_example.c b/src/examples/ecore_animator_example.c new file mode 100644 index 0000000..545d48a --- /dev/null +++ b/src/examples/ecore_animator_example.c @@ -0,0 +1,117 @@ +//Compile with: +//gcc -g -Wall `pkg-config --cflags --libs ecore-evas` -o ecore_animator_example ecore_animator_example.c + +#include +#include + +static Eina_Bool _advance_frame(void *data, double pos); +static Eina_Bool _advance_frame2(void *data, double pos); +static Eina_Bool _advance_frame3(void *data); +static Eina_Bool _start_second_anim(void *data); +static Eina_Bool _freeze_third_anim(void *data); +static Eina_Bool _thaw_third_anim(void *data); + +int +main(int argc, char *argv[]) +{ + Evas_Object *rect, *bg, *rect2; + Ecore_Evas *ee; + Evas *evas; + Ecore_Animator *anim; + + ecore_evas_init(); + + ee = ecore_evas_new(NULL, 0, 0, 300, 400, NULL); + ecore_evas_show(ee); + evas = ecore_evas_get(ee); + + bg = evas_object_rectangle_add(evas); + evas_object_resize(bg, 300, 400); + evas_object_show(bg); + + rect = evas_object_rectangle_add(evas); + evas_object_color_set(rect, 0, 0, 255, 255); + evas_object_resize(rect, 50, 50); + evas_object_show(rect); + + rect2 = evas_object_rectangle_add(evas); + evas_object_color_set(rect2, 0, 55, 0, 255); + evas_object_resize(rect2, 50, 50); + evas_object_show(rect2); + + ecore_animator_frametime_set(1. / 50); + ecore_animator_timeline_add(5, _advance_frame, rect); + + anim = ecore_animator_add(_advance_frame3, rect2); + + ecore_timer_add(10, _start_second_anim, rect); + ecore_timer_add(5, _freeze_third_anim, anim); + ecore_timer_add(10, _thaw_third_anim, anim); + ecore_main_loop_begin(); + + evas_object_del(rect); + ecore_evas_free(ee); + ecore_animator_del(anim); + ecore_evas_shutdown(); + + return 0; +} + +static Eina_Bool +_advance_frame(void *data, double pos) +{ + double frame = pos; + frame = ecore_animator_pos_map(pos, ECORE_POS_MAP_SPRING, 1.2, 15); + + evas_object_resize(data, 50 * (1 + frame), 50 * (1 + frame)); + evas_object_move(data, 100 * frame, 100 * frame); + evas_object_color_set(data, 255 * frame, 0, 255 * (1 - frame), 255); + return EINA_TRUE; +} + +static Eina_Bool +_start_second_anim(void *data) +{ + ecore_animator_frametime_set(1. / 10); + ecore_animator_timeline_add(20, _advance_frame2, data); + return EINA_FALSE; +} + +static Eina_Bool +_advance_frame2(void *data, double pos) +{ + double frame = pos; + frame = ecore_animator_pos_map(pos, ECORE_POS_MAP_BOUNCE, 1.2, 50); + + evas_object_resize(data, 100 - (50 * frame), 100 - (50 * frame)); + evas_object_move(data, 100 * (1 - frame), 100 * (1 - frame)); + evas_object_color_set(data, 255 * (1 - frame), 0, 255 * frame, 255); + return EINA_TRUE; +} + +static Eina_Bool +_advance_frame3(void *data) +{ + static int x = 0; + + if (x >= 250) + x = 0; + evas_object_move(data, ++x, 350); + + return EINA_TRUE; +} + +static Eina_Bool +_freeze_third_anim(void *data) +{ + ecore_animator_freeze(data); + return EINA_FALSE; +} + +static Eina_Bool +_thaw_third_anim(void *data) +{ + ecore_animator_thaw(data); + return EINA_FALSE; +} + diff --git a/src/examples/ecore_client_bench.c b/src/examples/ecore_client_bench.c new file mode 100644 index 0000000..dc550ee --- /dev/null +++ b/src/examples/ecore_client_bench.c @@ -0,0 +1,79 @@ +#include +#include +#include + +/* Ecore_Con client example + * 2010 Mike Blumenkrantz + */ + +#define NUM_CLIENTS 30000 + +static Eina_Counter *counter; +static int add = 0; +static int del = 0; + +Eina_Bool +_add(void *data, int type, Ecore_Con_Event_Server_Add *ev) +{ + ++add; + printf("Connection #%i!\n", add); + if (add == NUM_CLIENTS) + ecore_main_loop_quit(); + + return ECORE_CALLBACK_RENEW; +} + +Eina_Bool +_del(void *data, int type, Ecore_Con_Event_Server_Add *ev) +{ + ++del; + printf("Connection lost! #%i!\n", del); + + return ECORE_CALLBACK_RENEW; +} + +static void +_spawn(void *data) +{ + int x; + + for (x = 0; x < NUM_CLIENTS; x++) + { +// printf("Creating connection %i\n", x); + if (!ecore_con_server_connect(ECORE_CON_REMOTE_NODELAY, "127.0.0.1", 8080, NULL)) + { + printf("CRITICAL ERROR!\n" + "Could not create connection #%i!\n", x); + exit(1); + } + } + printf("***Job done***\n"); +} + +int +main(void) +{ + double done; + eina_init(); + ecore_init(); + ecore_con_init(); + + eina_log_domain_level_set("ecore_con", EINA_LOG_LEVEL_ERR); + eina_log_domain_level_set("eina", EINA_LOG_LEVEL_ERR); + counter = eina_counter_new("client"); + eina_counter_start(counter); + done = ecore_time_get(); + + ecore_job_add(_spawn, NULL); + +/* set event handler for server connect */ + ecore_event_handler_add(ECORE_CON_EVENT_SERVER_ADD, (Ecore_Event_Handler_Cb)_add, NULL); + ecore_event_handler_add(ECORE_CON_EVENT_SERVER_ADD, (Ecore_Event_Handler_Cb)_del, NULL); + +/* start client */ + ecore_main_loop_begin(); + eina_counter_stop(counter, 1); + printf("\nTime elapsed for %i connections: %f seconds\n%s", NUM_CLIENTS, ecore_time_get() - done, eina_counter_dump(counter)); + return 0; +} + diff --git a/src/examples/ecore_con_client_example.c b/src/examples/ecore_con_client_example.c new file mode 100644 index 0000000..c6ab50d --- /dev/null +++ b/src/examples/ecore_con_client_example.c @@ -0,0 +1,92 @@ +#include +#include +#include + +/* Ecore_Con client example + * 2010 Mike Blumenkrantz + */ + +/* comment if not using gnutls */ +static void +tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +Eina_Bool +_add(void *data, int type, Ecore_Con_Event_Server_Add *ev) +{ + printf("Server with ip %s connected!\n", ecore_con_server_ip_get(ev->server)); + ecore_con_server_send(ev->server, "hello!", 6); + ecore_con_server_flush(ev->server); + + return ECORE_CALLBACK_RENEW; +} + +Eina_Bool +_del(void *data, int type, Ecore_Con_Event_Server_Del *ev) +{ + printf("Lost server with ip %s!\n", ecore_con_server_ip_get(ev->server)); + ecore_main_loop_quit(); + return ECORE_CALLBACK_RENEW; +} + +Eina_Bool +_data(void *data, int type, Ecore_Con_Event_Server_Data *ev) +{ + char fmt[128]; + + snprintf(fmt, sizeof(fmt), + "Received %i bytes from server:\n" + ">>>>>\n" + "%%.%is\n" + ">>>>>\n", + ev->size, ev->size); + + printf(fmt, ev->data); + return ECORE_CALLBACK_RENEW; +} + +int +main() +{ + Ecore_Con_Server *svr; + Eina_Iterator *it; + const char *ca; + + eina_init(); + ecore_init(); + ecore_con_init(); + +/* comment if not using gnutls */ + gnutls_global_set_log_level(9); + gnutls_global_set_log_function(tls_log_func); + + if (!(it = eina_file_ls("/etc/ssl/certs"))) + exit(1); + + if (!(svr = ecore_con_server_connect(ECORE_CON_REMOTE_TCP | ECORE_CON_USE_MIXED, "www.verisign.com", 443, NULL))) + exit(1); + + /* add all the CAs */ + EINA_ITERATOR_FOREACH(it, ca) + { + if (!ecore_con_ssl_server_cafile_add(svr, ca)) + printf("Could not load CA: %s!\n", ca); + eina_stringshare_del(ca); + } + + eina_iterator_free(it); + ecore_con_ssl_server_verify(svr); + +/* set event handler for server connect */ + ecore_event_handler_add(ECORE_CON_EVENT_SERVER_ADD, (Ecore_Event_Handler_Cb)_add, NULL); +/* set event handler for server disconnect */ + ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DEL, (Ecore_Event_Handler_Cb)_del, NULL); +/* set event handler for receiving server data */ + ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DATA, (Ecore_Event_Handler_Cb)_data, NULL); + +/* start client */ + ecore_main_loop_begin(); +} + diff --git a/src/examples/ecore_con_client_simple_example.c b/src/examples/ecore_con_client_simple_example.c new file mode 100644 index 0000000..fe852b7 --- /dev/null +++ b/src/examples/ecore_con_client_simple_example.c @@ -0,0 +1,126 @@ +#include +#include +#include + +#ifdef HAVE_CONFIG_H +# include "config.h" +#else +# define __UNUSED__ +#endif + +struct _Server +{ + int sdata; +}; + +Eina_Bool +_add(void *data __UNUSED__, int type __UNUSED__, Ecore_Con_Event_Server_Add *ev) +{ + char welcome[] = "hello! - sent from the client"; + struct _Server *server = malloc(sizeof(*server)); + server->sdata = 0; + + ecore_con_server_data_set(ev->server, server); + printf("Server with ip %s, name %s, port %d, connected = %d!\n", + ecore_con_server_ip_get(ev->server), + ecore_con_server_name_get(ev->server), + ecore_con_server_port_get(ev->server), + ecore_con_server_connected_get(ev->server)); + ecore_con_server_send(ev->server, welcome, sizeof(welcome)); + ecore_con_server_flush(ev->server); + + return ECORE_CALLBACK_RENEW; +} + +Eina_Bool +_del(void *data __UNUSED__, int type __UNUSED__, Ecore_Con_Event_Server_Del *ev) +{ + if (!ev->server) + { + printf("Failed to establish connection to the server.\nExiting.\n"); + ecore_main_loop_quit(); + return ECORE_CALLBACK_RENEW; + } + + struct _Server *server = ecore_con_server_data_get(ev->server); + + printf("Lost server with ip %s!\n", ecore_con_server_ip_get(ev->server)); + + if (server) + { + printf("Total data received from this server: %d\n", server->sdata); + free(server); + } + + ecore_con_server_del(ev->server); + + ecore_main_loop_quit(); + return ECORE_CALLBACK_RENEW; +} + +Eina_Bool +_data(void *data __UNUSED__, int type __UNUSED__, Ecore_Con_Event_Server_Data *ev) +{ + char fmt[128]; + struct _Server *server = ecore_con_server_data_get(ev->server); + + snprintf(fmt, sizeof(fmt), + "Received %i bytes from server:\n" + ">>>>>\n" + "%%.%is\n" + ">>>>>\n", + ev->size, ev->size); + + printf(fmt, ev->data); + + server->sdata += ev->size; + return ECORE_CALLBACK_RENEW; +} + +int +main(int argc, const char *argv[]) +{ + Ecore_Con_Server *svr; + const char *address; + int port = 8080; + + if (argc < 2) + { + printf("wrong usage. Command syntax is:\n"); + printf("\tecore_con_client_simple_example

[port]\n"); + exit(1); + } + + address = argv[1]; + + if (argc > 2) + port = atoi(argv[2]); + + eina_init(); + ecore_init(); + ecore_con_init(); + + if (!(svr = ecore_con_server_connect(ECORE_CON_REMOTE_TCP, address, port, NULL))) + { + printf("could not connect to the server: %s, port %d.\n", + address, port); + exit(2); + } + + /* set event handler for server connect */ + ecore_event_handler_add(ECORE_CON_EVENT_SERVER_ADD, (Ecore_Event_Handler_Cb)_add, NULL); + /* set event handler for server disconnect */ + ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DEL, (Ecore_Event_Handler_Cb)_del, NULL); + /* set event handler for receiving server data */ + ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DATA, (Ecore_Event_Handler_Cb)_data, NULL); + + /* start client */ + ecore_main_loop_begin(); + + ecore_con_init(); + ecore_init(); + eina_init(); + + return 0; +} + diff --git a/src/examples/ecore_con_lookup_example.c b/src/examples/ecore_con_lookup_example.c new file mode 100644 index 0000000..1a47d0b --- /dev/null +++ b/src/examples/ecore_con_lookup_example.c @@ -0,0 +1,40 @@ +#include +#include +#include + +static void +_lookup_done_cb(const char *canonname, const char *ip, struct sockaddr *addr, int addrlen, void *data) +{ + printf("canonname = %s\n", canonname); + printf("ip = %s\n", ip); + printf("addr = %p\n", addr); + printf("addrlen = %d\n", addrlen); +} + +int +main(int argc, const char *argv[]) +{ + if (argc < 2) + { + printf("need one parameter:
\n"); + return -1; + } + + ecore_init(); + ecore_con_init(); + + if (!ecore_con_lookup(argv[1], _lookup_done_cb, NULL)) + { + printf("error when trying to start lookup for %s\n", argv[1]); + goto end; + } + + ecore_main_loop_begin(); + +end: + ecore_con_shutdown(); + ecore_shutdown(); + + return 0; +} + diff --git a/src/examples/ecore_con_server_example.c b/src/examples/ecore_con_server_example.c new file mode 100644 index 0000000..7333521 --- /dev/null +++ b/src/examples/ecore_con_server_example.c @@ -0,0 +1,81 @@ +#include +#include +#include + +/* Ecore_Con server example + * 2010 Mike Blumenkrantz + */ + +/* comment if not using gnutls */ +static void +tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +Eina_Bool +_add(void *data, int type, Ecore_Con_Event_Client_Add *ev) +{ + printf("Client with ip %s connected!\n", ecore_con_client_ip_get(ev->client)); + ecore_con_client_send(ev->client, "hello!", 6); +// ecore_con_client_flush(ev->client); + ecore_con_client_timeout_set(ev->client, 5); + + return ECORE_CALLBACK_RENEW; +} + +Eina_Bool +_del(void *data, int type, Ecore_Con_Event_Client_Del *ev) +{ + printf("Lost client with ip %s!\n", ecore_con_client_ip_get(ev->client)); + ecore_main_loop_quit(); + return ECORE_CALLBACK_RENEW; +} + +Eina_Bool +_data(void *data, int type, Ecore_Con_Event_Client_Data *ev) +{ + char fmt[128]; + + snprintf(fmt, sizeof(fmt), + "Received %i bytes from client:\n" + ">>>>>\n" + "%%.%is\n" + ">>>>>\n", + ev->size, ev->size); + + printf(fmt, ev->data); + return ECORE_CALLBACK_RENEW; +} + +int +main() +{ + Ecore_Con_Server *svr; + eina_init(); + ecore_init(); + ecore_con_init(); + +/* comment if not using gnutls */ + gnutls_global_set_log_level(9); + gnutls_global_set_log_function(tls_log_func); + +/* to use a PEM certificate with TLS and SSL3, uncomment the lines below */ + if (!(svr = ecore_con_server_add(ECORE_CON_REMOTE_TCP | ECORE_CON_USE_TLS | ECORE_CON_USE_SSL3 | ECORE_CON_LOAD_CERT, "127.0.0.1", 8080, NULL))) +/* to use simple tcp with ssl/tls, use this line */ +// if (!ecore_con_server_add(ECORE_CON_REMOTE_TCP | ECORE_CON_USE_SSL3, "127.0.0.1", 8080, NULL)) + exit(1); + + ecore_con_ssl_server_cert_add(svr, "server.pem"); + ecore_con_ssl_server_privkey_add(svr, "server.pem"); +/* set event handler for client connect */ + ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_ADD, (Ecore_Event_Handler_Cb)_add, NULL); +/* set event handler for client disconnect */ + ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DEL, (Ecore_Event_Handler_Cb)_del, NULL); +/* set event handler for receiving client data */ + ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DATA, (Ecore_Event_Handler_Cb)_data, NULL); + +/* start server */ + ecore_main_loop_begin(); +} + diff --git a/src/examples/ecore_con_server_http_example.c b/src/examples/ecore_con_server_http_example.c new file mode 100644 index 0000000..a106ba1 --- /dev/null +++ b/src/examples/ecore_con_server_http_example.c @@ -0,0 +1,136 @@ +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +# include "config.h" +#else +# define __UNUSED__ +#endif + +static const char response_template[] = + "HTTP/1.0 200 OK\r\n" + "Server: Ecore_Con custom server\r\n" + "Content-Length: %zd\r\n" + "Content-Type: text/html; charset=UTF-8\r\n" + "Set-Cookie: MYCOOKIE=1; path=/; expires=%s\r\n" + "Set-Cookie: SESSIONCOOKIE=1; path=/\r\n" + "\r\n" + "%s"; + +struct _Client +{ + int sdata; +}; + +Eina_Bool +_add(void *data __UNUSED__, int type __UNUSED__, Ecore_Con_Event_Client_Add *ev) +{ + struct _Client *client = malloc(sizeof(*client)); + client->sdata = 0; + static char buf[4096]; + char welcome[] = "Welcome to Ecore_Con server!"; + time_t t; + + printf("Client with ip %s, port %d, connected = %d!\n", + ecore_con_client_ip_get(ev->client), + ecore_con_client_port_get(ev->client), + ecore_con_client_connected_get(ev->client)); + + ecore_con_client_data_set(ev->client, client); + + t = time(NULL); + t += 60 * 60 * 24; + snprintf(buf, sizeof(buf), response_template, sizeof(welcome) - 1, ctime(&t), welcome); + + ecore_con_client_send(ev->client, buf, strlen(buf)); + ecore_con_client_flush(ev->client); + + return ECORE_CALLBACK_RENEW; +} + +Eina_Bool +_del(void *data __UNUSED__, int type __UNUSED__, Ecore_Con_Event_Client_Del *ev) +{ + struct _Client *client; + + if (!ev->client) + return ECORE_CALLBACK_RENEW; + + client = ecore_con_client_data_get(ev->client); + + printf("Lost client with ip %s!\n", ecore_con_client_ip_get(ev->client)); + printf("Total data received from this client: %d\n", client->sdata); + printf("Client was connected for %0.3f seconds.\n", + ecore_con_client_uptime_get(ev->client)); + + if (client) + free(client); + + ecore_con_client_del(ev->client); + + return ECORE_CALLBACK_RENEW; +} + +Eina_Bool +_data(void *data __UNUSED__, int type __UNUSED__, Ecore_Con_Event_Client_Data *ev) +{ + char fmt[128]; + struct _Client *client = ecore_con_client_data_get(ev->client); + + snprintf(fmt, sizeof(fmt), + "\nReceived %i bytes from client %s port %d:\n" + ">>>>>\n" + "%%.%is\n" + ">>>>>\n\n", + ev->size, ecore_con_client_ip_get(ev->client), + ecore_con_client_port_get(ev->client), ev->size); + + printf(fmt, ev->data); + + client->sdata += ev->size; + + return ECORE_CALLBACK_RENEW; +} + +int +main(void) +{ + Ecore_Con_Server *svr; + Ecore_Con_Client *cl; + const Eina_List *clients, *l; + + eina_init(); + ecore_init(); + ecore_con_init(); + + if (!(svr = ecore_con_server_add(ECORE_CON_REMOTE_TCP, "127.0.0.1", 8080, NULL))) + exit(1); + + ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_ADD, (Ecore_Event_Handler_Cb)_add, NULL); + ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DEL, (Ecore_Event_Handler_Cb)_del, NULL); + ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DATA, (Ecore_Event_Handler_Cb)_data, NULL); + ecore_con_server_client_limit_set(svr, 3, 0); + + ecore_main_loop_begin(); + + clients = ecore_con_server_clients_get(svr); + printf("Clients still connected to this server when exiting: %d\n", + eina_list_count(clients)); + EINA_LIST_FOREACH(clients, l, cl) + { + printf("%s\n", ecore_con_client_ip_get(cl)); + free(ecore_con_client_data_get(cl)); + } + + printf("Server was up for %0.3f seconds\n", + ecore_con_server_uptime_get(svr)); + + ecore_con_shutdown(); + ecore_shutdown(); + eina_shutdown(); + + return 0; +} + diff --git a/src/examples/ecore_con_server_simple_example.c b/src/examples/ecore_con_server_simple_example.c new file mode 100644 index 0000000..13dd953 --- /dev/null +++ b/src/examples/ecore_con_server_simple_example.c @@ -0,0 +1,133 @@ +#include +#include +#include + +#ifdef HAVE_CONFIG_H +# include "config.h" +#else +# define __UNUSED__ +#endif + +struct _Client +{ + int sdata; +}; + +Eina_Bool +_add(void *data __UNUSED__, int type __UNUSED__, Ecore_Con_Event_Client_Add *ev) +{ + char welcome[] = "hello! - sent from the server"; + Ecore_Con_Server *srv; + Ecore_Con_Client *cl; + const Eina_List *clients, *l; + + struct _Client *client = malloc(sizeof(*client)); + client->sdata = 0; + + printf("Client with ip %s, port %d, connected = %d!\n", + ecore_con_client_ip_get(ev->client), + ecore_con_client_port_get(ev->client), + ecore_con_client_connected_get(ev->client)); + + ecore_con_client_send(ev->client, welcome, sizeof(welcome)); + ecore_con_client_flush(ev->client); + + ecore_con_client_timeout_set(ev->client, 6); + + ecore_con_client_data_set(ev->client, client); + + srv = ecore_con_client_server_get(ev->client); + printf("Clients connected to this server:\n"); + clients = ecore_con_server_clients_get(srv); + EINA_LIST_FOREACH(clients, l, cl) + printf("%s\n", ecore_con_client_ip_get(cl)); + + return ECORE_CALLBACK_RENEW; +} + +Eina_Bool +_del(void *data __UNUSED__, int type __UNUSED__, Ecore_Con_Event_Client_Del *ev) +{ + struct _Client *client; + + if (!ev->client) + return ECORE_CALLBACK_RENEW; + + client = ecore_con_client_data_get(ev->client); + + printf("Lost client with ip %s!\n", ecore_con_client_ip_get(ev->client)); + printf("Total data received from this client: %d\n", client->sdata); + printf("Client was connected for %0.3f seconds.\n", + ecore_con_client_uptime_get(ev->client)); + + if (client) + free(client); + + ecore_con_client_del(ev->client); + + return ECORE_CALLBACK_RENEW; +} + +Eina_Bool +_data(void *data __UNUSED__, int type __UNUSED__, Ecore_Con_Event_Client_Data *ev) +{ + char fmt[128]; + struct _Client *client = ecore_con_client_data_get(ev->client); + + snprintf(fmt, sizeof(fmt), + "Received %i bytes from client %s port %d:\n" + ">>>>>\n" + "%%.%is\n" + ">>>>>\n", + ev->size, ecore_con_client_ip_get(ev->client), + ecore_con_client_port_get(ev->client), ev->size); + + printf(fmt, ev->data); + + client->sdata += ev->size; + + return ECORE_CALLBACK_RENEW; +} + +int +main(void) +{ + Ecore_Con_Server *svr; + Ecore_Con_Client *cl; + const Eina_List *clients, *l; + + eina_init(); + ecore_init(); + ecore_con_init(); + + if (!(svr = ecore_con_server_add(ECORE_CON_REMOTE_TCP, "127.0.0.1", 8080, NULL))) + exit(1); + + ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_ADD, (Ecore_Event_Handler_Cb)_add, NULL); + ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DEL, (Ecore_Event_Handler_Cb)_del, NULL); + ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DATA, (Ecore_Event_Handler_Cb)_data, NULL); + + ecore_con_server_timeout_set(svr, 10); + ecore_con_server_client_limit_set(svr, 3, 0); + + ecore_main_loop_begin(); + + clients = ecore_con_server_clients_get(svr); + printf("Clients connected to this server when exiting: %d\n", + eina_list_count(clients)); + EINA_LIST_FOREACH(clients, l, cl) + { + printf("%s\n", ecore_con_client_ip_get(cl)); + free(ecore_con_client_data_get(cl)); + } + + printf("Server was up for %0.3f seconds\n", + ecore_con_server_uptime_get(svr)); + + ecore_con_shutdown(); + ecore_shutdown(); + eina_shutdown(); + + return 0; +} + diff --git a/src/examples/ecore_con_url_cookies_example.c b/src/examples/ecore_con_url_cookies_example.c new file mode 100644 index 0000000..09c7b70 --- /dev/null +++ b/src/examples/ecore_con_url_cookies_example.c @@ -0,0 +1,123 @@ +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +# include "config.h" +#else +# define __UNUSED__ +#endif + +#define COOKIEJAR "cookies.jar" + +static Eina_Bool +_url_data_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info) +{ + Ecore_Con_Event_Url_Data *url_data = event_info; + int i; + + printf("\nData received from server:\n>>>>>\n"); + for (i = 0; i < url_data->size; i++) + printf("%c", url_data->data[i]); + printf("\n>>>>>>\n\n"); + + return EINA_TRUE; +} + +static Eina_Bool +_url_complete_cb(void *data __UNUSED__, int type __UNUSED__, void *event_info) +{ + Ecore_Con_Event_Url_Complete *url_complete = event_info; + const Eina_List *headers, *l; + char *str; + + printf("\n"); + printf("download completed with status code: %d\n", url_complete->status); + + headers = ecore_con_url_response_headers_get(url_complete->url_con); + + printf("response headers:\n"); + EINA_LIST_FOREACH(headers, l, str) + printf("header: %s", str); + + ecore_con_url_cookies_jar_write(url_complete->url_con); + + ecore_main_loop_quit(); + + return EINA_TRUE; +} + +int +main(int argc, const char *argv[]) +{ + Ecore_Con_Url *ec_url = NULL; + char cmd = '\0'; + Eina_Bool r; + + if (argc < 2) + { + printf("need at least one parameter: [command]\n"); + return -1; + } + + if (argc > 2) + cmd = argv[2][0]; + + ecore_init(); + ecore_con_init(); + ecore_con_url_init(); + + ec_url = ecore_con_url_new(argv[1]); + if (!ec_url) + { + printf("error when creating ecore con url object.\n"); + goto end; + } + + ecore_event_handler_add(ECORE_CON_EVENT_URL_DATA, _url_data_cb, NULL); + ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, _url_complete_cb, NULL); + + ecore_con_url_additional_header_add(ec_url, "User-Agent", "Ecore_Con client"); + + ecore_con_url_cookies_init(ec_url); + if (cmd != 'c' && cmd != 's') + ecore_con_url_cookies_file_add(ec_url, COOKIEJAR); + ecore_con_url_cookies_jar_file_set(ec_url, COOKIEJAR); + + switch (cmd) + { + case 'c': // clear + printf("Cleaning previously set cookies.\n"); + ecore_con_url_cookies_clear(ec_url); + break; + + case 's': // clear session + printf("Cleaning previously set session cookies.\n"); + ecore_con_url_cookies_session_clear(ec_url); + break; + + case 'i': // ignore session + printf("Ignoring old session cookies.\n"); + ecore_con_url_cookies_ignore_old_session_set(ec_url, EINA_TRUE); + } + + r = ecore_con_url_get(ec_url); + if (!r) + { + printf("could not realize request.\n"); + goto free_ec_url; + } + + ecore_main_loop_begin(); + +free_ec_url: + ecore_con_url_free(ec_url); +end: + ecore_con_url_shutdown(); + ecore_con_shutdown(); + ecore_shutdown(); + + return 0; +} + diff --git a/src/examples/ecore_con_url_download_example.c b/src/examples/ecore_con_url_download_example.c new file mode 100644 index 0000000..2f95db4 --- /dev/null +++ b/src/examples/ecore_con_url_download_example.c @@ -0,0 +1,113 @@ +#include +#include +#include +#include +#include +#include + +struct _request +{ + long size; +}; + +static Eina_Bool +_url_progress_cb(void *data, int type, void *event_info) +{ + Ecore_Con_Event_Url_Progress *url_progress = event_info; + float percent; + + if (url_progress->down.total > 0) + { + struct _request *req = ecore_con_url_data_get(url_progress->url_con); + req->size = url_progress->down.now; + + percent = (url_progress->down.now / url_progress->down.total) * 100; + printf("Total of download complete: %0.1f (%0.0f)%%\n", + percent, url_progress->down.now); + } + + return EINA_TRUE; +} + +static Eina_Bool +_url_complete_cb(void *data, int type, void *event_info) +{ + Ecore_Con_Event_Url_Complete *url_complete = event_info; + + struct _request *req = ecore_con_url_data_get(url_complete->url_con); + int nbytes = ecore_con_url_received_bytes_get(url_complete->url_con); + + printf("\n"); + printf("download completed with status code: %d\n", url_complete->status); + printf("Total size of downloaded file: %ld bytes\n", req->size); + printf("Total size of downloaded file: %ld bytes " + "(from received_bytes_get)\n", nbytes); + ecore_main_loop_quit(); + + return EINA_TRUE; +} + +int +main(int argc, const char *argv[]) +{ + Ecore_Con_Url *ec_url = NULL; + struct _request *req; + int fd; + const char *filename = "downloadedfile.dat"; + + if (argc < 2) + { + printf("need one parameter: \n"); + return -1; + } + + fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644); + + if (fd == -1) + { + printf("error: could not open file for writing: \"%s\"\n", + filename); + return -1; + } + + ecore_init(); + ecore_con_init(); + ecore_con_url_init(); + + ec_url = ecore_con_url_new(argv[1]); + if (!ec_url) + { + printf("error when creating ecore con url object.\n"); + goto end; + } + + req = malloc(sizeof(*req)); + req->size = 0; + ecore_con_url_data_set(ec_url, req); + + ecore_con_url_fd_set(ec_url, fd); + + ecore_event_handler_add(ECORE_CON_EVENT_URL_PROGRESS, _url_progress_cb, NULL); + ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, _url_complete_cb, NULL); + + if (!ecore_con_url_get(ec_url)) + { + printf("could not realize request.\n"); + goto free_ec_url; + } + + ecore_main_loop_begin(); + +free_ec_url: + free(req); + ecore_con_url_free(ec_url); +end: + + close(fd); + ecore_con_url_shutdown(); + ecore_con_shutdown(); + ecore_shutdown(); + + return 0; +} + diff --git a/src/examples/ecore_con_url_headers_example.c b/src/examples/ecore_con_url_headers_example.c new file mode 100644 index 0000000..fb05df3 --- /dev/null +++ b/src/examples/ecore_con_url_headers_example.c @@ -0,0 +1,106 @@ +#include +#include +#include +#include + +static Eina_Bool +_url_data_cb(void *data, int type, void *event_info) +{ + Ecore_Con_Event_Url_Data *url_data = event_info; + int i; + + for (i = 0; i < url_data->size; i++) + printf("%c", url_data->data[i]); + + return EINA_TRUE; +} + +static Eina_Bool +_url_complete_cb(void *data, int type, void *event_info) +{ + Ecore_Con_Event_Url_Complete *url_complete = event_info; + const Eina_List *headers, *l; + char *str; + + printf("\n"); + printf("download completed with status code: %d\n", url_complete->status); + + headers = ecore_con_url_response_headers_get(url_complete->url_con); + + EINA_LIST_FOREACH(headers, l, str) + printf("header: %s\n", str); + + ecore_main_loop_quit(); + + return EINA_TRUE; +} + +int +main(int argc, const char *argv[]) +{ + Ecore_Con_Url *ec_url = NULL; + const char *type; + Eina_Bool r; + + if (argc < 3) + { + printf("need at least two parameters: < POST|GET > \n"); + return -1; + } + + type = argv[1]; + + if (strcmp(type, "POST") && (strcmp(type, "GET"))) + { + printf("only POST or GET are supported by this example.\n"); + return -1; + } + + ecore_init(); + ecore_con_init(); + ecore_con_url_init(); + + // check if requests are being pipelined, and set them if not: + if (!ecore_con_url_pipeline_get()) + ecore_con_url_pipeline_set(EINA_TRUE); + + ec_url = ecore_con_url_custom_new(argv[2], type); + if (!ec_url) + { + printf("error when creating ecore con url object.\n"); + goto end; + } + + ecore_event_handler_add(ECORE_CON_EVENT_URL_DATA, _url_data_cb, NULL); + ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, _url_complete_cb, NULL); + + ecore_con_url_additional_header_add(ec_url, "User-Agent", "blablabla"); + ecore_con_url_verbose_set(ec_url, EINA_TRUE); + + ecore_con_url_httpauth_set(ec_url, "user", "password", EINA_FALSE); + + ecore_con_url_time(ec_url, ECORE_CON_URL_TIME_IFMODSINCE, 0); + + if (!strcmp(type, "GET")) + r = ecore_con_url_get(ec_url); + else + r = ecore_con_url_post(ec_url, NULL, 0, NULL); + + if (!r) + { + printf("could not realize request.\n"); + goto free_ec_url; + } + + ecore_main_loop_begin(); + +free_ec_url: + ecore_con_url_free(ec_url); +end: + ecore_con_url_shutdown(); + ecore_con_shutdown(); + ecore_shutdown(); + + return 0; +} + diff --git a/src/examples/ecore_evas_basics_example.c b/src/examples/ecore_evas_basics_example.c new file mode 100644 index 0000000..b62c64a --- /dev/null +++ b/src/examples/ecore_evas_basics_example.c @@ -0,0 +1,89 @@ +/** + * Ecore example illustrating the basics of ecore evas usage. + * + * You'll need at least one Evas engine built for it (excluding the + * buffer one). See stdout/stderr for output. + * + * @verbatim + * gcc -o ecore_evas_basics_example ecore_evas_basics_example.c `pkg-config --libs --cflags ecore-evas` + * @endverbatim + */ + +#include +#include +#include + +static Eina_Bool +_stdin_cb(void *data, Ecore_Fd_Handler *handler) +{ + Eina_List *l; + Ecore_Evas *ee; + char c; + + scanf("%c", &c); + if (c == 'h') + EINA_LIST_FOREACH(ecore_evas_ecore_evas_list_get(), l, ee) + ecore_evas_hide(ee); + else if (c == 's') + EINA_LIST_FOREACH(ecore_evas_ecore_evas_list_get(), l, ee) + ecore_evas_show(ee); + + return ECORE_CALLBACK_RENEW; +} + +static void +_on_delete(Ecore_Evas *ee) +{ + free(ecore_evas_data_get(ee, "key")); + ecore_main_loop_quit(); +} + +int +main(void) +{ + Ecore_Evas *ee; + Evas *canvas; + Evas_Object *bg; + Eina_List *engines, *l; + char *data; + + if (ecore_evas_init() <= 0) + return 1; + + engines = ecore_evas_engines_get(); + printf("Available engines:\n"); + EINA_LIST_FOREACH(engines, l, data) + printf("%s\n", data); + ecore_evas_engines_free(engines); + + ee = ecore_evas_new(NULL, 0, 0, 200, 200, NULL); + ecore_evas_title_set(ee, "Ecore Evas basics Example"); + ecore_evas_show(ee); + + data = malloc(sizeof(char) * 6); + sprintf(data, "%s", "hello"); + ecore_evas_data_set(ee, "key", data); + ecore_evas_callback_delete_request_set(ee, _on_delete); + + printf("Using %s engine!\n", ecore_evas_engine_name_get(ee)); + + canvas = ecore_evas_get(ee); + if (ecore_evas_ecore_evas_get(canvas) == ee) + printf("Everything is sane!\n"); + + bg = evas_object_rectangle_add(canvas); + evas_object_color_set(bg, 0, 0, 255, 255); + evas_object_resize(bg, 200, 200); + evas_object_show(bg); + ecore_evas_object_associate(ee, bg, ECORE_EVAS_OBJECT_ASSOCIATE_BASE); + + ecore_main_fd_handler_add(STDIN_FILENO, ECORE_FD_READ, _stdin_cb, NULL, NULL, NULL); + + ecore_main_loop_begin(); + + ecore_evas_free(ee); + ecore_evas_shutdown(); + + return 0; +} + diff --git a/src/examples/ecore_evas_buffer_example_01.c b/src/examples/ecore_evas_buffer_example_01.c new file mode 100644 index 0000000..a060a0a --- /dev/null +++ b/src/examples/ecore_evas_buffer_example_01.c @@ -0,0 +1,121 @@ +/** + * Simple Ecore_Evas example on the Evas buffer engine wrapper + * functions. + * + * You must have Evas compiled with the buffer engine. + * + * Compile with: + * + * @verbatim + * gcc -o evas-buffer-simple evas-buffer-simple.c `pkg-config --libs --cflags evas evas-software-buffer` + * @endverbatim + * + */ + +#ifdef HAVE_CONFIG_H + +#include "config.h" +#else +#define __UNUSED__ +#endif + +#include +#include + +#define WIDTH (320) +#define HEIGHT (240) + +static Ecore_Evas *ee; + +/* support function to save scene as PPM image */ +static void +_scene_save(Evas *canvas, + const char *dest) +{ + const unsigned int *pixels, *pixels_end; + int width, height; + FILE *f; + + evas_output_size_get(canvas, &width, &height); + + f = fopen(dest, "wb+"); + if (!f) + { + fprintf(stderr, "ERROR: could not open for writing '%s': %s\n", + dest, strerror(errno)); + return; + } + + pixels = ecore_evas_buffer_pixels_get(ee); + pixels_end = pixels + (width * height); + + /* PPM P6 format is dead simple to write: */ + fprintf(f, "P6\n%d %d\n255\n", width, height); + for (; pixels < pixels_end; pixels++) + { + int r, g, b; + + r = ((*pixels) & 0xff0000) >> 16; + g = ((*pixels) & 0x00ff00) >> 8; + b = (*pixels) & 0x0000ff; + + fprintf(f, "%c%c%c", r, g, b); + } + + fclose(f); + printf("Saved scene as '%s'\n", dest); +} + +int +main(void) +{ + Evas *canvas; + Evas_Object *bg, *r1, *r2, *r3; + + ecore_evas_init(); + + ee = ecore_evas_buffer_new(WIDTH, HEIGHT); + if (!ee) goto error; + + canvas = ecore_evas_get(ee); + + bg = evas_object_rectangle_add(canvas); + evas_object_color_set(bg, 255, 255, 255, 255); /* white bg */ + evas_object_move(bg, 0, 0); /* at origin */ + evas_object_resize(bg, WIDTH, HEIGHT); /* covers full canvas */ + evas_object_show(bg); + + r1 = evas_object_rectangle_add(canvas); + evas_object_color_set(r1, 255, 0, 0, 255); /* 100% opaque red */ + evas_object_move(r1, 10, 10); + evas_object_resize(r1, 100, 100); + evas_object_show(r1); + + r2 = evas_object_rectangle_add(canvas); + evas_object_color_set(r2, 0, 128, 0, 128); /* 50% opaque green */ + evas_object_move(r2, 10, 10); + evas_object_resize(r2, 50, 50); + evas_object_show(r2); + + r3 = evas_object_rectangle_add(canvas); + evas_object_color_set(r3, 0, 128, 0, 255); /* 100% opaque dark green */ + evas_object_move(r3, 60, 60); + evas_object_resize(r3, 50, 50); + evas_object_show(r3); + + ecore_evas_manual_render(ee); + _scene_save(canvas, "/tmp/evas-buffer-simple-render.ppm"); + + ecore_evas_free(ee); + ecore_evas_shutdown(); + + return 0; + +error: + fprintf(stderr, "You got to have at least one Evas engine built" + " and linked up to ecore-evas for this example to run" + " properly.\n"); + ecore_evas_shutdown(); + return -1; +} + diff --git a/src/examples/ecore_evas_buffer_example_02.c b/src/examples/ecore_evas_buffer_example_02.c new file mode 100644 index 0000000..360faa2 --- /dev/null +++ b/src/examples/ecore_evas_buffer_example_02.c @@ -0,0 +1,126 @@ +/** + * Simple Ecore_Evas example on the Evas buffer engine wrapper + * functions. + * + * You must have Evas compiled with the buffer engine. + * + * Compile with: + * + * @verbatim + * gcc -o evas-buffer-simple evas-buffer-simple.c `pkg-config --libs --cflags evas evas-software-buffer` + * @endverbatim + * + */ + +#ifdef HAVE_CONFIG_H + +#include "config.h" +#else +#define __UNUSED__ +#define PACKAGE_EXAMPLES_DIR "." +#endif + +#include +#include +#include + +#define WIDTH (320) +#define HEIGHT (240) + +static Ecore_Evas *ee; +static const char *border_img_path = PACKAGE_EXAMPLES_DIR "/red.png"; + +static void +_on_destroy(Ecore_Evas *ee __UNUSED__) +{ + ecore_main_loop_quit(); +} + +int +main(void) +{ + Evas *canvas, *sub_canvas; + Evas_Object *bg, *r1, *r2, *r3; /* "sub" canvas objects */ + Evas_Object *border, *img; /* canvas objects */ + Ecore_Evas *sub_ee; + + ecore_evas_init(); + + /* this will give you a window with an Evas canvas under the first + * engine available */ + ee = ecore_evas_new(NULL, 0, 0, WIDTH, HEIGHT, NULL); + if (!ee) goto error; + + ecore_evas_size_min_set(ee, WIDTH, HEIGHT); + ecore_evas_size_max_set(ee, WIDTH, HEIGHT); + + ecore_evas_callback_delete_request_set(ee, _on_destroy); + ecore_evas_title_set(ee, "Ecore_Evas buffer (image) example"); + ecore_evas_show(ee); + + canvas = ecore_evas_get(ee); + + bg = evas_object_rectangle_add(canvas); + evas_object_color_set(bg, 255, 255, 255, 255); /* white bg */ + evas_object_move(bg, 0, 0); /* at origin */ + evas_object_resize(bg, WIDTH, HEIGHT); /* covers full canvas */ + evas_object_show(bg); + + /* this is a border around the image containing a scene of another + * canvas */ + border = evas_object_image_filled_add(canvas); + evas_object_image_file_set(border, border_img_path, NULL); + evas_object_image_border_set(border, 3, 3, 3, 3); + evas_object_image_border_center_fill_set(border, EVAS_BORDER_FILL_NONE); + + evas_object_move(border, WIDTH / 6, HEIGHT / 6); + evas_object_resize(border, (2 * WIDTH) / 3, (2 * HEIGHT) / 3); + evas_object_show(border); + + img = ecore_evas_object_image_new(ee); + evas_object_image_filled_set(img, EINA_TRUE); + evas_object_image_size_set( + img, ((2 * WIDTH) / 3) - 6, ((2 * HEIGHT) / 3) - 6); + sub_ee = ecore_evas_object_ecore_evas_get(img); + sub_canvas = ecore_evas_object_evas_get(img); + + evas_object_move(img, (WIDTH / 6) + 3, (HEIGHT / 6) + 3); + + /* apply the same size on both! */ + evas_object_resize(img, ((2 * WIDTH) / 3) - 6, ((2 * HEIGHT) / 3) - 6); + ecore_evas_resize(sub_ee, ((2 * WIDTH) / 3) - 6, ((2 * HEIGHT) / 3) - 6); + + r1 = evas_object_rectangle_add(sub_canvas); + evas_object_color_set(r1, 255, 0, 0, 255); /* 100% opaque red */ + evas_object_move(r1, 10, 10); + evas_object_resize(r1, 100, 100); + evas_object_show(r1); + + r2 = evas_object_rectangle_add(sub_canvas); + evas_object_color_set(r2, 0, 128, 0, 128); /* 50% opaque green */ + evas_object_move(r2, 10, 10); + evas_object_resize(r2, 50, 50); + evas_object_show(r2); + + r3 = evas_object_rectangle_add(sub_canvas); + evas_object_color_set(r3, 0, 128, 0, 255); /* 100% opaque dark green */ + evas_object_move(r3, 60, 60); + evas_object_resize(r3, 50, 50); + evas_object_show(r3); + + evas_object_show(img); + ecore_main_loop_begin(); + + ecore_evas_free(ee); + ecore_evas_shutdown(); + + return 0; + +error: + fprintf(stderr, "You got to have at least one Evas engine built" + " and linked up to ecore-evas for this example to run" + " properly.\n"); + ecore_evas_shutdown(); + return -1; +} + diff --git a/src/examples/ecore_evas_callbacks.c b/src/examples/ecore_evas_callbacks.c new file mode 100644 index 0000000..3e42da1 --- /dev/null +++ b/src/examples/ecore_evas_callbacks.c @@ -0,0 +1,128 @@ +/** + * Ecore example illustrating ecore evas callbacks. + * + * You'll need at least one Evas engine built for it (excluding the + * buffer one). See stdout/stderr for output. + * + * @verbatim + * gcc -o ecore_evas_callbacks ecore_evas_callbacks.c `pkg-config --libs --cflags ecore-evas` + * @endverbatim + */ + +#include +#include + +static void +_destroy(Ecore_Evas *ee) +{ + printf("destroy\n"); + ecore_main_loop_quit(); +} + +static void +_delete(Ecore_Evas *ee) +{ + printf("delete\n"); + ecore_main_loop_quit(); +} + +static void +_focus_in(Ecore_Evas *ee) +{ + printf("focus_in\n"); +} + +static void +_focus_out(Ecore_Evas *ee) +{ + printf("focus_out\n"); +} + +static void +_hide(Ecore_Evas *ee) +{ + printf("hide\n"); +} + +static void +_mouse_in(Ecore_Evas *ee) +{ + printf("mouse_in\n"); +} + +static void +_show(Ecore_Evas *ee) +{ + printf("show\n"); +} + +static void +_mouse_out(Ecore_Evas *ee) +{ + printf("mouse_out\n"); +} + +static void +_move(Ecore_Evas *ee) +{ + printf("move\n"); +} + +static void +_post_render(Ecore_Evas *ee) +{ + printf("post_render\n"); +} + +static void +_pre_free(Ecore_Evas *ee) +{ + printf("pre_free\n"); +} + +static void +_pre_render(Ecore_Evas *ee) +{ + printf("pre_render\n"); +} + +static void +_resize(Ecore_Evas *ee) +{ + printf("resize\n"); +} + +int +main(void) +{ + Ecore_Evas *ee; + + ecore_evas_init(); + + ee = ecore_evas_new(NULL, 0, 0, 200, 100, NULL); + ecore_evas_title_set(ee, "Ecore Evas Callbacks Example"); + ecore_evas_show(ee); + + //callbacks + ecore_evas_callback_delete_request_set(ee, _delete); + ecore_evas_callback_destroy_set(ee, _destroy); + ecore_evas_callback_focus_in_set(ee, _focus_in); + ecore_evas_callback_focus_out_set(ee, _focus_out); + ecore_evas_callback_hide_set(ee, _hide); + ecore_evas_callback_mouse_in_set(ee, _mouse_in); + ecore_evas_callback_mouse_out_set(ee, _mouse_out); + ecore_evas_callback_move_set(ee, _move); + ecore_evas_callback_post_render_set(ee, _post_render); + ecore_evas_callback_pre_free_set(ee, _pre_free); + ecore_evas_callback_pre_render_set(ee, _pre_render); + ecore_evas_callback_resize_set(ee, _resize); + ecore_evas_callback_show_set(ee, _show); + + ecore_main_loop_begin(); + + ecore_evas_free(ee); + ecore_evas_shutdown(); + + return 0; +} + diff --git a/src/examples/ecore_evas_ews_example.c b/src/examples/ecore_evas_ews_example.c new file mode 100644 index 0000000..1209ffd --- /dev/null +++ b/src/examples/ecore_evas_ews_example.c @@ -0,0 +1,269 @@ +/** + * Ecore example illustrating the ews of ecore evas usage. + * + * You'll need at least one Evas engine built for it (excluding the + * buffer one). See stdout/stderr for output. + * + * @verbatim + * gcc -o ecore_evas_ews_example ecore_evas_ews_example.c `pkg-config --libs --cflags ecore-evas` + * @endverbatim + */ + +#include +#include +#include +#include +#include + +static Eina_Bool +_wm_win_add(void *data, int type, void *event_info) +{ + Ecore_Evas *ee = event_info; + printf("WM: new window=%p\n", ee); + return EINA_TRUE; +} + +static Eina_Bool +_wm_win_move(void *data, int type, void *event_info) +{ + Ecore_Evas *ee = event_info; + int x, y; + ecore_evas_geometry_get(ee, &x, &y, NULL, NULL); + printf("WM: window=%p moved to %d,%d\n", ee, x, y); + return EINA_TRUE; +} + +static Eina_Bool +_wm_win_resize(void *data, int type, void *event_info) +{ + Ecore_Evas *ee = event_info; + int w, h; + ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); + printf("WM: window=%p resized to %dx%d\n", ee, w, h); + return EINA_TRUE; +} + +static Eina_Bool +_wm_win_show(void *data, int type, void *event_info) +{ + Ecore_Evas *ee = event_info; + printf("WM: show window=%p\n", ee); + return EINA_TRUE; +} + +static void +optional_ews_window_manager_setup(void) +{ + ecore_event_handler_add(ECORE_EVAS_EWS_EVENT_ADD, _wm_win_add, NULL); + ecore_event_handler_add(ECORE_EVAS_EWS_EVENT_MOVE, _wm_win_move, NULL); + ecore_event_handler_add(ECORE_EVAS_EWS_EVENT_RESIZE, _wm_win_resize, NULL); + ecore_event_handler_add(ECORE_EVAS_EWS_EVENT_SHOW, _wm_win_show, NULL); + + /* one may use any known unique identifier, like an app function pointer */ + ecore_evas_ews_manager_set(optional_ews_window_manager_setup); +} + +static void +optional_ews_setup(void) +{ + Evas_Object *bg; + Evas *e; + + ecore_evas_ews_setup(0, 0, 800, 600); /* "screen" size */ + e = ecore_evas_ews_evas_get(); /* forces "screen" to be allocated */ + + bg = evas_object_rectangle_add(e); + evas_object_color_set(bg, 128, 32, 32, 255); + ecore_evas_ews_background_set(bg); +} + +static Eina_Bool +_stdin_cb(void *data, Ecore_Fd_Handler *handler) +{ + const Eina_List *l; + Ecore_Evas *ee; + char c = getchar(); + + if (c == EOF) + { + ecore_main_loop_quit(); + return EINA_FALSE; + } + + switch (c) { + case 'h': + printf("hide all windows\n"); + EINA_LIST_FOREACH(ecore_evas_ews_children_get(), l, ee) + ecore_evas_hide(ee); + break; + + case 's': + printf("show all windows\n"); + EINA_LIST_FOREACH(ecore_evas_ews_children_get(), l, ee) + ecore_evas_show(ee); + break; + + case 'l': + printf("move all windows left\n"); + EINA_LIST_FOREACH(ecore_evas_ews_children_get(), l, ee) + { + int x, y; + ecore_evas_geometry_get(ee, &x, &y, NULL, NULL); + ecore_evas_move(ee, x - 10, y); + } + break; + + case 'r': + printf("move all windows right\n"); + EINA_LIST_FOREACH(ecore_evas_ews_children_get(), l, ee) + { + int x, y; + ecore_evas_geometry_get(ee, &x, &y, NULL, NULL); + ecore_evas_move(ee, x + 10, y); + } + break; + + case 't': + printf("move all windows top\n"); + EINA_LIST_FOREACH(ecore_evas_ews_children_get(), l, ee) + { + int x, y; + ecore_evas_geometry_get(ee, &x, &y, NULL, NULL); + ecore_evas_move(ee, x, y - 10); + } + break; + + case 'b': + printf("move all windows bottom\n"); + EINA_LIST_FOREACH(ecore_evas_ews_children_get(), l, ee) + { + int x, y; + ecore_evas_geometry_get(ee, &x, &y, NULL, NULL); + ecore_evas_move(ee, x, y + 10); + } + break; + + case 'S': + printf("make all windows smaller\n"); + EINA_LIST_FOREACH(ecore_evas_ews_children_get(), l, ee) + { + int w, h; + ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); + ecore_evas_resize(ee, w - 10, h - 10); + } + break; + + case 'B': + printf("make all windows bigger\n"); + EINA_LIST_FOREACH(ecore_evas_ews_children_get(), l, ee) + { + int w, h; + ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); + ecore_evas_resize(ee, w + 10, h + 10); + } + break; + + case 'm': + printf("make all windows unmaximized\n"); + EINA_LIST_FOREACH(ecore_evas_ews_children_get(), l, ee) + ecore_evas_maximized_set(ee, EINA_FALSE); + break; + + case 'M': + printf("make all windows maximized\n"); + EINA_LIST_FOREACH(ecore_evas_ews_children_get(), l, ee) + ecore_evas_maximized_set(ee, EINA_TRUE); + break; + + case 'i': + printf("make all windows uniconified\n"); + EINA_LIST_FOREACH(ecore_evas_ews_children_get(), l, ee) + ecore_evas_iconified_set(ee, EINA_FALSE); + break; + + case 'I': + printf("make all windows iconified\n"); + EINA_LIST_FOREACH(ecore_evas_ews_children_get(), l, ee) + ecore_evas_iconified_set(ee, EINA_TRUE); + break; + + case 'f': + printf("make all windows unfullscreen\n"); + EINA_LIST_FOREACH(ecore_evas_ews_children_get(), l, ee) + ecore_evas_fullscreen_set(ee, EINA_FALSE); + break; + + case 'F': + printf("make all windows fullscreen\n"); + EINA_LIST_FOREACH(ecore_evas_ews_children_get(), l, ee) + ecore_evas_fullscreen_set(ee, EINA_TRUE); + break; + + case 'q': + printf("quit\n"); + ecore_main_loop_quit(); + break; + + default: + if (!isspace(c)) + printf("Unknown command: %c\n", c); + } + return ECORE_CALLBACK_RENEW; +} + +static void +_on_delete(Ecore_Evas *ee) +{ + free(ecore_evas_data_get(ee, "key")); + ecore_main_loop_quit(); +} + +int +main(void) +{ + Ecore_Evas *ee; + Evas *canvas; + Evas_Object *bg; + + if (ecore_evas_init() <= 0) + return 1; + + optional_ews_setup(); + optional_ews_window_manager_setup(); + + /* everything should look similar to ecore_evas_basic_example */ + ee = ecore_evas_ews_new(0, 0, 200, 200); + ecore_evas_title_set(ee, "Ecore Evas EWS Example"); + ecore_evas_show(ee); + + ecore_evas_data_set(ee, "key", strdup("hello")); + ecore_evas_callback_delete_request_set(ee, _on_delete); + + printf("Using %s engine!\n", ecore_evas_engine_name_get(ee)); + + canvas = ecore_evas_get(ee); + if (ecore_evas_ecore_evas_get(canvas) == ee) + printf("Everything is sane!\n"); + + bg = evas_object_rectangle_add(canvas); + evas_object_color_set(bg, 0, 0, 255, 255); + evas_object_resize(bg, 200, 200); + evas_object_show(bg); + ecore_evas_object_associate(ee, bg, ECORE_EVAS_OBJECT_ASSOCIATE_BASE); + + /* moving the window should move it in the screen */ + ecore_evas_move(ee, 50, 50); + + ecore_main_fd_handler_add(STDIN_FILENO, + ECORE_FD_READ | ECORE_FD_ERROR, + _stdin_cb, + NULL, NULL, NULL); + + ecore_main_loop_begin(); + + ecore_evas_free(ee); + ecore_evas_shutdown(); + + return 0; +} + diff --git a/src/examples/ecore_evas_object_example.c b/src/examples/ecore_evas_object_example.c new file mode 100644 index 0000000..38e4c4b --- /dev/null +++ b/src/examples/ecore_evas_object_example.c @@ -0,0 +1,53 @@ +/** + * Ecore example illustrating ecore evas object usage. + * + * You'll need at least one Evas engine built for it (excluding the + * buffer one). See stdout/stderr for output. + * + * @verbatim + * gcc -o ecore_evas_object_example ecore_evas_object_example.c `pkg-config --libs --cflags ecore-evas` + * @endverbatim + */ + +#include +#include + +int +main(void) +{ + Ecore_Evas *ee; + Evas_Object *bg, *cursor, *obj; + int layer, x, y; + + ecore_evas_init(); + + ee = ecore_evas_new(NULL, 0, 0, 200, 200, NULL); + ecore_evas_title_set(ee, "Ecore Evas Object Example"); + ecore_evas_show(ee); + + bg = evas_object_rectangle_add(ecore_evas_get(ee)); + evas_object_color_set(bg, 0, 0, 255, 255); + evas_object_resize(bg, 200, 200); + evas_object_show(bg); + ecore_evas_object_associate(ee, bg, ECORE_EVAS_OBJECT_ASSOCIATE_BASE); + + if (bg == ecore_evas_object_associate_get(ee)) + printf("Association worked!\n"); + + cursor = evas_object_rectangle_add(ecore_evas_get(ee)); + evas_object_color_set(cursor, 0, 255, 0, 255); + evas_object_resize(cursor, 5, 10); + ecore_evas_object_cursor_set(ee, cursor, 0, 1, 1); + + ecore_evas_cursor_get(ee, &obj, &layer, &x, &y); + if (obj == cursor && layer == 0 && x == 1 && y == 1) + printf("Set cursor worked!\n"); + + ecore_main_loop_begin(); + + ecore_evas_free(ee); + ecore_evas_shutdown(); + + return 0; +} + diff --git a/src/examples/ecore_evas_window_sizes_example.c b/src/examples/ecore_evas_window_sizes_example.c new file mode 100644 index 0000000..ceb601c --- /dev/null +++ b/src/examples/ecore_evas_window_sizes_example.c @@ -0,0 +1,204 @@ +/** + * Simple @c Ecore_Evas example illustrating how to deal with window + * sizes + * + * You'll need at least one engine built for it (excluding the buffer + * one). See stdout/stderr for output. + * + * @verbatim + * gcc -o evas-smart-object evas-smart-object.c `pkg-config --libs --cflags evas ecore ecore-evas` + * @endverbatim + */ + +#ifdef HAVE_CONFIG_H + +#include "config.h" +#else +#define __UNUSED__ +#endif + +#include +#include + +#define WIDTH (300) +#define HEIGHT (300) + +static Ecore_Evas *ee; +static Evas_Object *text, *bg; +static Eina_Bool min_set = EINA_FALSE; +static Eina_Bool max_set = EINA_FALSE; +static Eina_Bool base_set = EINA_FALSE; +static Eina_Bool step_set = EINA_FALSE; + +static const char commands[] = \ + "commands are:\n" + "\tm - impose a minumum size to the window\n" + "\tx - impose a maximum size to the window\n" + "\tb - impose a base size to the window\n" + "\ts - impose a step size (different than 1 px) to the window\n" + "\th - print help\n"; + +/* to inform current window's size */ +static void +_canvas_resize_cb(Ecore_Evas *ee) +{ + int w, h; + char buf[1024]; + + ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); + snprintf(buf, sizeof(buf), "%d x %d", w, h); + evas_object_text_text_set(text, buf); + evas_object_move(text, (w - 150) / 2, (h - 50) / 2); + + evas_object_resize(bg, w, h); +} + +static void +_on_destroy(Ecore_Evas *ee __UNUSED__) +{ + ecore_main_loop_quit(); +} + +static void +_on_keydown(void *data __UNUSED__, + Evas *evas __UNUSED__, + Evas_Object *o __UNUSED__, + void *einfo) +{ + Evas_Event_Key_Down *ev = einfo; + + if (strcmp(ev->keyname, "h") == 0) /* print help */ + { + fprintf(stdout, commands); + return; + } + + if (strcmp(ev->keyname, "m") == 0) /* impose a minimum size on the window */ + { + min_set = !min_set; + + if (min_set) + { + ecore_evas_size_min_set(ee, WIDTH / 2, HEIGHT / 2); + fprintf(stdout, "Imposing a minimum size of %d x %d\n", + WIDTH / 2, HEIGHT / 2); + } + else + { + ecore_evas_size_min_set(ee, 0, 0); + fprintf(stdout, "Taking off minimum size restriction from the" + " window\n"); + } + return; + } + + if (strcmp(ev->keyname, "x") == 0) /* impose a maximum size on the window */ + { + max_set = !max_set; + + if (max_set) + { + ecore_evas_size_max_set(ee, WIDTH * 2, HEIGHT * 2); + fprintf(stdout, "Imposing a maximum size of %d x %d\n", + WIDTH * 2, HEIGHT * 2); + } + else + { + ecore_evas_size_max_set(ee, 0, 0); + fprintf(stdout, "Taking off maximum size restriction from the" + " window\n"); + } + return; + } + + if (strcmp(ev->keyname, "b") == 0) /* impose a base size on the window */ + { + base_set = !base_set; + + if (base_set) + { + ecore_evas_size_base_set(ee, WIDTH * 2, HEIGHT * 2); + fprintf(stdout, "Imposing a base size of %d x %d\n", + WIDTH * 2, HEIGHT * 2); + } + else + { + ecore_evas_size_base_set(ee, 0, 0); + fprintf(stdout, "Taking off base size restriction from the" + " window\n"); + } + return; + } + + if (strcmp(ev->keyname, "s") == 0) /* impose a step size on the window */ + { + step_set = !step_set; + + if (step_set) + { + ecore_evas_size_step_set(ee, 40, 40); + fprintf(stdout, "Imposing a step size of %d x %d\n", 40, 40); + } + else + { + ecore_evas_size_step_set(ee, 0, 0); + fprintf(stdout, "Taking off step size restriction from the" + " window\n"); + } + return; + } +} + +int +main(void) +{ + Evas *evas; + + if (!ecore_evas_init()) + return EXIT_FAILURE; + + /* this will give you a window with an Evas canvas under the first + * engine available */ + ee = ecore_evas_new(NULL, 0, 0, WIDTH, HEIGHT, NULL); + if (!ee) goto error; + + ecore_evas_callback_delete_request_set(ee, _on_destroy); + ecore_evas_title_set(ee, "Ecore_Evas window sizes example"); + ecore_evas_callback_resize_set(ee, _canvas_resize_cb); + ecore_evas_show(ee); + + evas = ecore_evas_get(ee); + + bg = evas_object_rectangle_add(evas); + evas_object_color_set(bg, 255, 255, 255, 255); /* white bg */ + evas_object_move(bg, 0, 0); /* at canvas' origin */ + evas_object_resize(bg, WIDTH, HEIGHT); /* covers full canvas */ + evas_object_show(bg); + + evas_object_focus_set(bg, EINA_TRUE); + evas_object_event_callback_add( + bg, EVAS_CALLBACK_KEY_DOWN, _on_keydown, NULL); + + text = evas_object_text_add(evas); + evas_object_color_set(text, 0, 0, 0, 255); + evas_object_resize(text, 150, 50); + evas_object_text_font_set(text, "Sans", 20); + evas_object_show(text); + + _canvas_resize_cb(ee); + fprintf(stdout, commands); + ecore_main_loop_begin(); + + ecore_evas_free(ee); + ecore_evas_shutdown(); + + return 0; + +error: + fprintf(stderr, "You got to have at least one Evas engine built" + " and linked up to ecore-evas for this example to run" + " properly.\n"); + ecore_evas_shutdown(); + return -1; +} + diff --git a/src/examples/ecore_event_example_01.c b/src/examples/ecore_event_example_01.c new file mode 100644 index 0000000..64a5be8 --- /dev/null +++ b/src/examples/ecore_event_example_01.c @@ -0,0 +1,26 @@ +/* + * Compile with: + * gcc -g -Wall `pkg-config --cflags --libs ecore` -o ecore_event_example ecore_event_example.c + */ + +#include + +static Eina_Bool +_quitter(void *data, int ev_type, void *event) +{ + printf("Leaving already?\n"); + ecore_main_loop_quit(); + return ECORE_CALLBACK_DONE; +} + +int +main(int argc, char **argv) +{ + ecore_init(); + + ecore_event_handler_add(ECORE_EVENT_SIGNAL_EXIT, _quitter, NULL); + ecore_main_loop_begin(); + + return 0; +} + diff --git a/src/examples/ecore_event_example_02.c b/src/examples/ecore_event_example_02.c new file mode 100644 index 0000000..a8eccf3 --- /dev/null +++ b/src/examples/ecore_event_example_02.c @@ -0,0 +1,89 @@ +#include +#include + +struct context // helper struct to give some context to the callbacks +{ + const char *str1, *str2; + Ecore_Event_Handler *handler1; + Ecore_Event_Handler *handler2; +}; + +static _event_type = 0; // a new type of event will be defined and stored here + +static Eina_Bool +_event_handler1_cb(void *data, int type, void *event) +{ + int *number = event; + const char *str = data; + + printf("event_handler1: number=%d, data=\"%s\".\n", *number, str); + + if ((*number % 2) == 0) + return ECORE_CALLBACK_DONE; + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_event_handler2_cb(void *data, int type, void *event) // event callback +{ + struct context *ctxt = data; + int *number = event; + + printf("event_handler2: number=%d.\n", *number); + + if (*number == 5) + { + const char *old = NULL; + old = ecore_event_handler_data_set(ctxt->handler1, (void *)ctxt->str2); + printf("changed handler1 data from \"%s\" to \"%s\".\n", + old, ctxt->str2); + } + else if (*number >= 10) + { + printf("finish main loop.\n"); + ecore_main_loop_quit(); + } + + return ECORE_CALLBACK_DONE; // same as EINA_FALSE +} + +int +main(int argc, char **argv) +{ + struct context ctxt = {0}; + int i; + ctxt.str1 = "dataone"; + ctxt.str2 = "datatwo"; + + if (!ecore_init()) + { + printf("ERROR: Cannot init Ecore!\n"); + return -1; + } + + _event_type = ecore_event_type_new(); + + ctxt.handler1 = ecore_event_handler_add(_event_type, + _event_handler1_cb, + ctxt.str1); + ctxt.handler2 = ecore_event_handler_add(_event_type, + _event_handler2_cb, + &ctxt); + + for (i = 0; i <= 15; i++) + { + int *event_data = malloc(sizeof(*event_data)); + *event_data = i; + ecore_event_add(_event_type, event_data, NULL, NULL); + } + + printf("start the main loop.\n"); + + ecore_main_loop_begin(); + + ecore_shutdown(); + + return 0; +} + diff --git a/src/examples/ecore_exe_example.c b/src/examples/ecore_exe_example.c new file mode 100644 index 0000000..8d0dedc --- /dev/null +++ b/src/examples/ecore_exe_example.c @@ -0,0 +1,100 @@ +/** + Compile with gcc -o ecore_exe_example ecore_exe_example.c `pkg-config --cflags --libs ecore` + */ + +#include +#include +#include + +#define BUFFER_SIZE 1024 + +static Eina_Bool +_msg_from_child_handler(void *data, int type, void *event) +{ + Ecore_Exe_Event_Data *dataFromProcess = (Ecore_Exe_Event_Data *)event; + char msg[BUFFER_SIZE]; + + if (dataFromProcess->size >= (BUFFER_SIZE - 1)) + { + fprintf(stdout, "Data too big for bugger. error\n"); + return ECORE_CALLBACK_DONE; + } + + strncpy(msg, dataFromProcess->data, dataFromProcess->size); + msg[dataFromProcess->size] = 0; + + if (strcmp(msg, "quit") == 0) + { + fprintf(stdout, "My child said to me, QUIT!\n"); + ecore_main_loop_quit(); + } + else + fprintf(stdout, "I received a message from my child: %s\n", msg); + + return ECORE_CALLBACK_DONE; +} + +static Eina_Bool +_sendMessage(void *data) +{ + static int numberOfMessages = 0; + Ecore_Exe *childHandle = (Ecore_Exe *)data; + char msg[BUFFER_SIZE]; + + sprintf(msg, " Message: %d\n", numberOfMessages); + numberOfMessages++; + + if (ecore_exe_send(childHandle, msg, strlen(msg)) != EINA_TRUE) + fprintf(stderr, "Could not send my name to the child\n"); + else + fprintf(stdout, + "I'm the father and I sent this message to the child: %s\n", msg); + + return ECORE_CALLBACK_RENEW; +} + +int +main(int argc, char **argv) +{ + pid_t childPid; + Ecore_Exe *childHandle; + + if (!ecore_init()) + goto exit; + + childHandle = ecore_exe_pipe_run("./ecore_exe_example_child", + ECORE_EXE_PIPE_WRITE | + ECORE_EXE_PIPE_READ_LINE_BUFFERED | + ECORE_EXE_PIPE_READ, NULL); + + if (childHandle == NULL) + { + fprintf(stderr, "Could not create a child process!\n"); + goto ecore_shutdown; + } + + childPid = ecore_exe_pid_get(childHandle); + + if (childPid == -1) + fprintf(stderr, "Could not retrive the PID!\n"); + else + fprintf(stdout, "The child process has PID:%d\n", childPid); + + ecore_event_handler_add(ECORE_EXE_EVENT_DATA, _msg_from_child_handler, NULL); + ecore_timer_add(1, _sendMessage, childHandle); + + ecore_main_loop_begin(); + + ecore_exe_free(childHandle); //This will not affect the child process + + ecore_shutdown(); + + return EXIT_SUCCESS; + +ecore_shutdown: + ecore_shutdown(); + +exit: + return EXIT_FAILURE; +} + diff --git a/src/examples/ecore_exe_example_child.c b/src/examples/ecore_exe_example_child.c new file mode 100644 index 0000000..0d5b469 --- /dev/null +++ b/src/examples/ecore_exe_example_child.c @@ -0,0 +1,56 @@ +/** + Compile with gcc -o ecore_exe_example_child ecore_exe_example_child.c `pkg-config --cflags --libs ecore` + */ + +#include +#include +#include + +#define BUFFER_SIZE 1024 + +static Eina_Bool +_fd_handler_cb(void *data, Ecore_Fd_Handler + *fd_handler) +{ + static int numberOfMessages = 0; + char message[BUFFER_SIZE]; + + fgets(message, BUFFER_SIZE, stdin); + + numberOfMessages++; + + if (numberOfMessages < 3) + { + fprintf(stdout, "My father sent this message to me:%s\n", message); + fflush(stdout); + return ECORE_CALLBACK_RENEW; + } + else + { + fprintf(stdout, "quit\n"); + fflush(stdout); + ecore_main_loop_quit(); + return ECORE_CALLBACK_DONE; + } +} + +int +main(int argc, char **argv) +{ + if (!ecore_init()) + goto error; + + ecore_main_fd_handler_add(STDIN_FILENO, + ECORE_FD_READ, + _fd_handler_cb, + NULL, NULL, NULL); + ecore_main_loop_begin(); + + ecore_shutdown(); + + return EXIT_SUCCESS; + +error: + return EXIT_FAILURE; +} + diff --git a/src/examples/ecore_fd_handler_example.c b/src/examples/ecore_fd_handler_example.c new file mode 100644 index 0000000..381d101 --- /dev/null +++ b/src/examples/ecore_fd_handler_example.c @@ -0,0 +1,89 @@ +#include +#include + +struct context +{ + Ecore_Fd_Handler *handler; + Ecore_Timer *timer; +}; + +static void +_fd_prepare_cb(void *data, Ecore_Fd_Handler *handler) +{ + printf("prepare_cb called.\n"); +} + +static Eina_Bool +_fd_handler_cb(void *data, Ecore_Fd_Handler *handler) +{ + struct context *ctxt = data; + char buf[1024]; + size_t nbytes; + int fd; + + if (ecore_main_fd_handler_active_get(handler, ECORE_FD_ERROR)) + { + printf("An error has occurred. Stop watching this fd and quit.\n"); + ecore_main_loop_quit(); + ctxt->handler = NULL; + return ECORE_CALLBACK_CANCEL; + } + + fd = ecore_main_fd_handler_fd_get(handler); + nbytes = read(fd, buf, sizeof(buf)); + if (nbytes == 0) + { + printf("Nothing to read, exiting...\n"); + ecore_main_loop_quit(); + ctxt->handler = NULL; + return ECORE_CALLBACK_CANCEL; + } + buf[nbytes - 1] = '\0'; + + printf("Read %zd bytes from input: \"%s\"\n", nbytes - 1, buf); + + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +_timer_cb(void *data) +{ + printf("Timer expired after 5 seconds...\n"); + + return ECORE_CALLBACK_RENEW; +} + +int +main(int argc, char **argv) +{ + struct context ctxt = {0}; + + if (!ecore_init()) + { + printf("ERROR: Cannot init Ecore!\n"); + return -1; + } + + ctxt.handler = ecore_main_fd_handler_add(STDIN_FILENO, + ECORE_FD_READ | ECORE_FD_ERROR, + _fd_handler_cb, + &ctxt, NULL, NULL); + ecore_main_fd_handler_prepare_callback_set(ctxt.handler, _fd_prepare_cb, &ctxt); + ctxt.timer = ecore_timer_add(5, _timer_cb, &ctxt); + + printf("Starting the main loop. Type anything and hit to " + "activate the fd_handler callback, or CTRL+d to shutdown.\n"); + + ecore_main_loop_begin(); + + if (ctxt.handler) + ecore_main_fd_handler_del(ctxt.handler); + + if (ctxt.timer) + ecore_timer_del(ctxt.timer); + + ecore_shutdown(); + + return 0; +} + diff --git a/src/examples/ecore_fd_handler_gnutls_example.c b/src/examples/ecore_fd_handler_gnutls_example.c new file mode 100644 index 0000000..5635b13 --- /dev/null +++ b/src/examples/ecore_fd_handler_gnutls_example.c @@ -0,0 +1,203 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Ecore_Fd_Handler example + * 2010 Mike Blumenkrantz + * compile with gcc $(pkgconfig --cflags --libs gnutls ecore) + */ + +#define print(...) fprintf(stderr, "line %i: ", __LINE__); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n") + +static int done = 0; + +static void +tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +static const char * +SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_description_t status) +{ + switch (status) + { + case GNUTLS_HANDSHAKE_HELLO_REQUEST: + return "Hello request"; + + case GNUTLS_HANDSHAKE_CLIENT_HELLO: + return "Client hello"; + + case GNUTLS_HANDSHAKE_SERVER_HELLO: + return "Server hello"; + + case GNUTLS_HANDSHAKE_CERTIFICATE_PKT: + return "Certificate packet"; + + case GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE: + return "Server key exchange"; + + case GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST: + return "Certificate request"; + + case GNUTLS_HANDSHAKE_SERVER_HELLO_DONE: + return "Server hello done"; + + case GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY: + return "Certificate verify"; + + case GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE: + return "Client key exchange"; + + case GNUTLS_HANDSHAKE_FINISHED: + return "Finished"; + + case GNUTLS_HANDSHAKE_SUPPLEMENTAL: + return "Supplemental"; + } + return NULL; +} + +/* Connects to the peer and returns a socket + * descriptor. + */ +static int +tcp_connect(void) +{ + const char *PORT = "443"; + const char *SERVER = "69.58.181.89"; //verisign.com + int err, sd; + int flag = 1, curstate = 0; + struct sockaddr_in sa; + + /* sets some fd options such as nonblock */ + sd = socket(AF_INET, SOCK_STREAM, 0); + fcntl(sd, F_SETFL, O_NONBLOCK); + fcntl(sd, F_SETFD, FD_CLOEXEC); + setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (const void *)&curstate, sizeof(curstate)); + + setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int)); + + memset(&sa, '\0', sizeof (sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons(atoi(PORT)); + inet_pton(AF_INET, SERVER, &sa.sin_addr); + + /* connects to server + */ + err = connect(sd, (struct sockaddr *)&sa, sizeof (sa)); + if ((err < 0) && (errno != EINPROGRESS)) + { + print("Connect error\n"); + exit(1); + } + + return sd; +} + +/* closes the given socket descriptor. + */ +static void +tcp_close(int sd) +{ + shutdown(sd, SHUT_RDWR); /* no more receptions */ + close(sd); +} + +static Eina_Bool +_process_data(gnutls_session_t client, Ecore_Fd_Handler *fd_handler) +{ + static int ret, lastret; + static unsigned int count = 0; + + if (!done) + { + lastret = ret; + ret = gnutls_handshake(client); + count++; + if (gnutls_record_get_direction(client)) + ecore_main_fd_handler_active_set(fd_handler, ECORE_FD_WRITE); + else + ecore_main_fd_handler_active_set(fd_handler, ECORE_FD_READ); + /* avoid printing messages infinity times */ + if (lastret != ret) + { + print("gnutls returned with: %s - %s", gnutls_strerror_name(ret), gnutls_strerror(ret)); + if ((ret == GNUTLS_E_WARNING_ALERT_RECEIVED) || (ret == GNUTLS_E_FATAL_ALERT_RECEIVED)) + print("Also received alert: %s", gnutls_alert_get_name(gnutls_alert_get(client))); + print("last out: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_out(client))); + print("last in: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_in(client))); + } + + if (gnutls_error_is_fatal(ret)) + { + print("yarrr this be an error!"); + exit(1); + } + } + if (ret == GNUTLS_E_SUCCESS) + { + done = 1; + print("Handshake successful in %u handshake calls!", count); + ecore_main_loop_quit(); + } + + return ECORE_CALLBACK_RENEW; +} + +int +main(void) +{ + /* credentials */ + gnutls_anon_client_credentials_t c_anoncred; + gnutls_certificate_credentials_t c_certcred; + + gnutls_session_t client; + int sd; + + /* General init. */ + gnutls_global_init(); + ecore_init(); + gnutls_global_set_log_function(tls_log_func); + gnutls_global_set_log_level(6); + + /* Init client */ + gnutls_anon_allocate_client_credentials(&c_anoncred); + gnutls_certificate_allocate_credentials(&c_certcred); + gnutls_init(&client, GNUTLS_CLIENT); + /* set very specific priorities */ + gnutls_priority_set_direct(client, "NONE:%VERIFY_ALLOW_X509_V1_CA_CRT:+RSA:+DHE-RSA:+DHE-DSS:+ANON-DH:+COMP-DEFLATE:+COMP-NULL:+CTYPE-X509:+SHA1:+SHA256:+SHA384:+SHA512:+AES-256-CBC:+AES-128-CBC:+3DES-CBC:+VERS-TLS1.2:+VERS-TLS1.1:+VERS-TLS1.0:+VERS-SSL3.0", NULL); + gnutls_credentials_set(client, GNUTLS_CRD_ANON, c_anoncred); + gnutls_credentials_set(client, GNUTLS_CRD_CERTIFICATE, c_certcred); + gnutls_server_name_set(client, GNUTLS_NAME_DNS, "www.verisign.com", strlen("www.verisign.com")); + + /* connect to the peer + */ + sd = tcp_connect(); + + /* associate gnutls with socket */ + gnutls_transport_set_ptr(client, (gnutls_transport_ptr_t)sd); + /* add a callback for data being available for send/receive on socket */ + if (!ecore_main_fd_handler_add(sd, ECORE_FD_READ | ECORE_FD_WRITE, (Ecore_Fd_Cb)_process_data, client, NULL, NULL)) + { + print("could not create fd handler!"); + exit(1); + } + /* begin main loop */ + ecore_main_loop_begin(); + + gnutls_bye(client, GNUTLS_SHUT_RDWR); + + gnutls_deinit(client); + + tcp_close(sd); + + return 0; +} + diff --git a/src/examples/ecore_file_download_example.c b/src/examples/ecore_file_download_example.c new file mode 100644 index 0000000..42cff6c --- /dev/null +++ b/src/examples/ecore_file_download_example.c @@ -0,0 +1,86 @@ +#include +#include +#include +#include + +/* + * ecore_file_download() example + * + * compile with: + * gcc ecore_file_download_example.c `pkg-config --libs --cflags ecore-file` \ + * -o ecore_file_download_example + * + */ + +#define URL "http://www.kernel.org/pub/linux/kernel/v1.0/linux-1.0.tar.gz" +#define DST "linux-1.0.tar.gz" +#define DST_MIME "[x-gzip]linux-1.0.tar.gz" + +void +completion_cb(void *data, const char *file, int status) +{ + printf("Done (status: %d)\n", status); + ecore_main_loop_quit(); +} + +int +progress_cb(void *data, const char *file, + long int dltotal, long int dlnow, + long int ultotal, long int ulnow) +{ + printf("Progress: %ld/%ld\n", dlnow, dltotal); + return ECORE_FILE_PROGRESS_CONTINUE; // continue the download +} + +int +main(void) +{ + double start; + Eina_Hash *headers; + + eina_init(); + ecore_init(); + ecore_file_init(); + + if (ecore_file_exists(DST)) + ecore_file_unlink(DST); + + start = ecore_time_get(); + + if (ecore_file_download(URL, DST, completion_cb, progress_cb, NULL, NULL)) + { + printf("Download started successfully:\n URL: %s\n DEST: %s\n", URL, DST); + ecore_main_loop_begin(); + printf("\nTime elapsed: %f seconds\n", ecore_time_get() - start); + printf("Downloaded %lld bytes\n", ecore_file_size(DST)); + } + else + { + printf("Error, can't start download\n"); + goto done; + } + + headers = eina_hash_string_small_new(NULL); + eina_hash_add(headers, "Content-type", "application/x-gzip"); + + if (ecore_file_download_full(URL, DST_MIME, completion_cb, progress_cb, NULL, NULL, headers)) + { + printf("Download started successfully:\n URL: %s\n DEST: %s\n", URL, DST_MIME); + ecore_main_loop_begin(); + printf("\nTime elapsed: %f seconds\n", ecore_time_get() - start); + printf("Downloaded %lld bytes\n", ecore_file_size(DST)); + } + else + { + printf("Error, can't start download\n"); + goto done; + } + +done: + if (headers) eina_hash_free(headers); + ecore_file_shutdown(); + ecore_shutdown(); + eina_shutdown(); + return 0; +} + diff --git a/src/examples/ecore_idler_example.c b/src/examples/ecore_idler_example.c new file mode 100644 index 0000000..11b3397 --- /dev/null +++ b/src/examples/ecore_idler_example.c @@ -0,0 +1,115 @@ +#include +#include + +struct context // helper struct to give some context to the callbacks +{ + int count; + Ecore_Idle_Enterer *enterer; + Ecore_Idler *idler; + Ecore_Idle_Exiter *exiter; + Ecore_Event_Handler *handler; + Ecore_Timer *timer; +}; + +static _event_type = 0; // a new type of event will be defined and stored here + +static Eina_Bool +_enterer_cb(void *data) // the idle enterer callback +{ + printf("IDLE ENTERER: Ecore entering in idle state.\n"); + + return ECORE_CALLBACK_RENEW; // same as EINA_TRUE +} + +static Eina_Bool +_exiter_cb(void *data) // the idle exiter callback +{ + printf("IDLE EXITER: Ecore exiting idle state.\n"); + + return ECORE_CALLBACK_RENEW; // same as EINA_TRUE +} + +static Eina_Bool +_idler_cb(void *data) // the idler callback - ran while the mainloop is idle +{ + struct context *ctxt = data; + printf("IDLER: executing idler callback while in idle state.\n"); + + ctxt->count++; + + /* each 10 times that the callback gets called, generate an event that + * will wake up the main loop, triggering idle enterers, exiters, etc. */ + if ((ctxt->count % 10) == 0) + ecore_event_add(_event_type, NULL, NULL, NULL); + + return ECORE_CALLBACK_RENEW; // same as EINA_TRUE +} + +static Eina_Bool +_event_handler_cb(void *data, int type, void *event) // event callback +{ + struct context *ctxt = data; + + printf("EVENT: processing callback for the event received.\n"); + + if (ctxt->count > 100) + { + ecore_idle_enterer_del(ctxt->enterer); + ecore_idle_exiter_del(ctxt->exiter); + ecore_idler_del(ctxt->idler); + + ctxt->enterer = NULL; + ctxt->exiter = NULL; + ctxt->idler = NULL; + + if (ctxt->timer) + { + ecore_timer_del(ctxt->timer); + ctxt->timer = NULL; + } + + ecore_main_loop_quit(); + } + + return ECORE_CALLBACK_DONE; // same as EINA_FALSE +} + +static Eina_Bool +_timer_cb(void *data) +{ + struct context *ctxt = data; + printf("TIMER: timer callback called.\n"); + + if (ctxt->timer) + ctxt->timer = NULL; + + return ECORE_CALLBACK_CANCEL; // same as EINA_FALSE +} + +int +main(int argc, char **argv) +{ + struct context ctxt = {0}; + + if (!ecore_init()) + { + printf("ERROR: Cannot init Ecore!\n"); + return -1; + } + + _event_type = ecore_event_type_new(); + + ctxt.enterer = ecore_idle_enterer_add(_enterer_cb, &ctxt); + ctxt.exiter = ecore_idle_exiter_add(_exiter_cb, &ctxt); + ctxt.idler = ecore_idler_add(_idler_cb, &ctxt); + ctxt.handler = ecore_event_handler_add(_event_type, + _event_handler_cb, + &ctxt); + ctxt.timer = ecore_timer_add(0.0005, _timer_cb, &ctxt); + + ecore_main_loop_begin(); + ecore_shutdown(); + + return 0; +} + diff --git a/src/examples/ecore_imf_example.c b/src/examples/ecore_imf_example.c new file mode 100644 index 0000000..c2d02a0 --- /dev/null +++ b/src/examples/ecore_imf_example.c @@ -0,0 +1,571 @@ +/** + * Ecore example illustrating how to use ecore imf. + * + * @verbatim + * gcc -o ecore_imf_example ecore_imf_example.c `pkg-config --cflags --libs ecore evas ecore-evas ecore-imf ecore-imf-evas` + * @endverbatim + */ + +#include +#include +#include +#include +#include +#include + +typedef struct _Entry Entry; + +struct _Entry +{ + Evas_Object *rect; + Evas_Object *txt_obj; + Evas_Textblock_Style *txt_style; + Evas_Textblock_Cursor *cursor; + Evas_Textblock_Cursor *preedit_start; + Evas_Textblock_Cursor *preedit_end; + Ecore_IMF_Context *imf_context; + Eina_Bool have_preedit : 1; +}; + +static void +_mouse_up_cb(void *data, Evas *e, Evas_Object *o, void *event_info) +{ + Entry *en = data; + if (!en) return; + + evas_object_focus_set(en->rect, EINA_TRUE); +} + +static void +_entry_focus_in_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + Entry *en = data; + if (!en) return; + + if (en->imf_context) + ecore_imf_context_focus_in(en->imf_context); +} + +static void +_entry_focus_out_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + Entry *en = data; + if (!en) return; + + if (en->imf_context) + { + ecore_imf_context_reset(en->imf_context); + ecore_imf_context_focus_out(en->imf_context); + } +} + +static void +_canvas_focus_in_cb(void *data, Evas *e, void *event_info) +{ + Evas_Object *obj = evas_focus_get(e); + if (obj) + _entry_focus_in_cb(obj, NULL, NULL, NULL); +} + +static void +_canvas_focus_out_cb(void *data, Evas *e, void *event_info) +{ + Evas_Object *obj = evas_focus_get(e); + if (obj) + _entry_focus_out_cb(obj, NULL, NULL, NULL); +} + +static void +_imf_cursor_info_set(Entry *en) +{ + Evas_Coord x, y, w, h; + Evas_Coord cx, cy, cw, ch; // cursor geometry + int cursor_pos; // cursor position in chars (Not bytes) + + if (!en) return; + + // get cursor geometry + evas_object_geometry_get(en->txt_obj, &x, &y, &w, &h); + evas_textblock_cursor_geometry_get(en->cursor, &cx, &cy, &cw, &ch, NULL, EVAS_TEXTBLOCK_CURSOR_BEFORE); + + // get cursor position + cursor_pos = evas_textblock_cursor_pos_get(en->cursor); + + ecore_imf_context_cursor_position_set(en->imf_context, cursor_pos); + ecore_imf_context_cursor_location_set(en->imf_context, x + cx, y + cy, cw, ch); +} + +static void +_preedit_del(Entry *en) +{ + if (!en || !en->have_preedit) return; + if (!en->preedit_start || !en->preedit_end) return; + if (!evas_textblock_cursor_compare(en->preedit_start, en->preedit_end)) return; + + /* delete the preedit characters */ + evas_textblock_cursor_range_delete(en->preedit_start, en->preedit_end); +} + +static void +_preedit_clear(Entry *en) +{ + if (en->preedit_start) + { + evas_textblock_cursor_free(en->preedit_start); + en->preedit_start = NULL; + } + + if (en->preedit_end) + { + evas_textblock_cursor_free(en->preedit_end); + en->preedit_end = NULL; + } + + en->have_preedit = EINA_FALSE; +} + +static Eina_Bool +_ecore_imf_retrieve_surrounding_cb(void *data, Ecore_IMF_Context *ctx, char **text, int *cursor_pos) +{ + /* This callback will be called when the Input Method Context module requests the surrounding context. */ + Entry *en = data; + const char *str; + + if (!en) return; + + str = evas_object_textblock_text_markup_get(en->txt_obj); + *text = str ? strdup(str) : strdup(""); + + /* get the current position of cursor */ + if (cursor_pos) + *cursor_pos = evas_textblock_cursor_pos_get(en->cursor); + + return EINA_TRUE; +} + +static void +_ecore_imf_event_delete_surrounding_cb(void *data, Ecore_IMF_Context *ctx, void *event_info) +{ + /* called when the input method needs to delete all or part of the context surrounding the cursor */ + Entry *en = data; + Ecore_IMF_Event_Delete_Surrounding *ev = event_info; + Evas_Textblock_Cursor *del_start, *del_end; + int cursor_pos; + + if (!en) return; + + cursor_pos = evas_textblock_cursor_pos_get(en->cursor); + + del_start = evas_object_textblock_cursor_new(en->txt_obj); + evas_textblock_cursor_pos_set(del_start, cursor_pos + ev->offset); + + del_end = evas_object_textblock_cursor_new(en->txt_obj); + evas_textblock_cursor_pos_set(del_end, cursor_pos + ev->offset + ev->n_chars); + + /* implement function to delete character(s) from 'cursor_pos+ev->offset' cursor position to 'cursor_pos + ev->offset + ev->n_chars' */ + evas_textblock_cursor_range_delete(del_start, del_end); + + evas_textblock_cursor_free(del_start); + evas_textblock_cursor_free(del_end); +} + +static void +_ecore_imf_event_commit_cb(void *data, Ecore_IMF_Context *ctx, void *event_info) +{ + Entry *en = data; + char *commit_str = (char *)event_info; + if (!en) return; + + /* delete preedit string */ + _preedit_del(en); + _preedit_clear(en); + + printf("commit string : %s\n", commit_str); + + evas_object_textblock_text_markup_prepend(en->cursor, commit_str); + + /* notify cursor information */ + _imf_cursor_info_set(en); + + return; +} + +static void +_ecore_imf_event_preedit_changed_cb(void *data, Ecore_IMF_Context *ctx, void *event_info) +{ + /* example how to get preedit string */ + Entry *en = data; + char *preedit_string; + int cursor_pos; + Eina_List *attrs = NULL; + Eina_List *l; + Ecore_IMF_Preedit_Attr *attr; + Ecore_IMF_Context *imf_context = ctx; + int preedit_start_pos, preedit_end_pos; + int i; + Eina_Bool preedit_end_state = EINA_FALSE; + + if (!en) return; + + /* get preedit string, attributes */ + ecore_imf_context_preedit_string_with_attributes_get(imf_context, &preedit_string, &attrs, &cursor_pos); + printf("preedit string : %s\n", preedit_string); + + if (!strcmp(preedit_string, "")) + preedit_end_state = EINA_TRUE; + + /* delete preedit */ + _preedit_del(en); + + preedit_start_pos = evas_textblock_cursor_pos_get(en->cursor); + + /* insert preedit character(s) */ + if (strlen(preedit_string) > 0) + { + if (attrs) + { + EINA_LIST_FOREACH(attrs, l, attr) + { + if (attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB1) // style type + { + /* apply appropriate style such as underline */ + } + else if (attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB2 || attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB3) + { + /* apply appropriate style such as underline */ + } + } + + /* insert code to display preedit string in your editor */ + evas_object_textblock_text_markup_prepend(en->cursor, preedit_string); + } + } + + if (!preedit_end_state) + { + /* set preedit start cursor */ + if (!en->preedit_start) + en->preedit_start = evas_object_textblock_cursor_new(en->txt_obj); + evas_textblock_cursor_copy(en->cursor, en->preedit_start); + + /* set preedit end cursor */ + if (!en->preedit_end) + en->preedit_end = evas_object_textblock_cursor_new(en->txt_obj); + evas_textblock_cursor_copy(en->cursor, en->preedit_end); + + preedit_end_pos = evas_textblock_cursor_pos_get(en->cursor); + + for (i = 0; i < (preedit_end_pos - preedit_start_pos); i++) + { + evas_textblock_cursor_char_prev(en->preedit_start); + } + + en->have_preedit = EINA_TRUE; + + /* set cursor position */ + evas_textblock_cursor_pos_set(en->cursor, preedit_start_pos + cursor_pos); + } + + /* notify cursor information */ + _imf_cursor_info_set(en); + + EINA_LIST_FREE(attrs, attr) + free(attr); + + free(preedit_string); +} + +static void +_key_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + Entry *en = data; + Evas_Event_Key_Down *ev = event_info; + Eina_Bool control, alt, shift; + Eina_Bool multiline; + Eina_Bool cursor_changed; + if (!en) return; + if (!ev->key) return; + + if (en->imf_context) + { + Ecore_IMF_Event_Key_Down ecore_ev; + ecore_imf_evas_event_key_down_wrap(ev, &ecore_ev); + if (ecore_imf_context_filter_event(en->imf_context, + ECORE_IMF_EVENT_KEY_DOWN, + (Ecore_IMF_Event *)&ecore_ev)) + return; + } + + control = evas_key_modifier_is_set(ev->modifiers, "Control"); + alt = evas_key_modifier_is_set(ev->modifiers, "Alt"); + shift = evas_key_modifier_is_set(ev->modifiers, "Shift"); + + if ((!strcmp(ev->keyname, "Escape")) || + (!strcmp(ev->keyname, "Return")) || (!strcmp(ev->keyname, "KP_Enter"))) + ecore_imf_context_reset(en->imf_context); + + if (!strcmp(ev->key, "BackSpace")) + { + if (evas_textblock_cursor_char_prev(en->cursor)) + evas_textblock_cursor_char_delete(en->cursor); + + return; + } + else if (!strcmp(ev->key, "Delete") || + (!strcmp(ev->key, "KP_Delete") && !ev->string)) + { + // FILLME + } + else if ((control) && (!strcmp(ev->key, "v"))) + { + // ctrl + v + // FILLME + } + else if ((control) && (!strcmp(ev->key, "a"))) + { + // ctrl + a + // FILLME + } + else if ((control) && (!strcmp(ev->key, "A"))) + { + // ctrl + A + // FILLME + } + else if ((control) && ((!strcmp(ev->key, "c") || (!strcmp(ev->key, "Insert"))))) + { + // ctrl + c + // FILLME + } + else if ((control) && ((!strcmp(ev->key, "x") || (!strcmp(ev->key, "m"))))) + { + // ctrl + x + // FILLME + } + else if ((control) && (!strcmp(ev->key, "z"))) + { + // ctrl + z (undo) + // FILLME + } + else if ((control) && (!strcmp(ev->key, "y"))) + { + // ctrl + y (redo) + // FILLME + } + else if ((!strcmp(ev->key, "Return")) || (!strcmp(ev->key, "KP_Enter"))) + { + // FILLME + } + else + { + if (ev->string) + { + printf("key down string : %s\n", ev->string); + evas_object_textblock_text_markup_prepend(en->cursor, ev->string); + } + } + + /* notify cursor information */ + _imf_cursor_info_set(en); +} + +static void +_key_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + Entry *en = data; + Evas_Event_Key_Up *ev = event_info; + + if (!en) return; + + if (en->imf_context) + { + Ecore_IMF_Event_Key_Up ecore_ev; + + ecore_imf_evas_event_key_up_wrap(ev, &ecore_ev); + if (ecore_imf_context_filter_event(en->imf_context, + ECORE_IMF_EVENT_KEY_UP, + (Ecore_IMF_Event *)&ecore_ev)) + return; + } +} + +static void +create_input_field(Evas *evas, Entry *en, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h) +{ + if (!en) return; + + /* create background for text input field */ + en->rect = evas_object_rectangle_add(evas); + evas_object_color_set(en->rect, 150, 150, 150, 255); /* gray */ + evas_object_move(en->rect, x, y); + evas_object_resize(en->rect, w, h); + evas_object_show(en->rect); + + /* create text object for displaying text */ + en->txt_obj = evas_object_textblock_add(evas); + evas_object_color_set(en->txt_obj, 0, 0, 0, 255); + evas_object_pass_events_set(en->txt_obj, EINA_TRUE); + evas_object_move(en->txt_obj, x, y); + evas_object_resize(en->txt_obj, w, h); + evas_object_show(en->txt_obj); + + /* set style on textblock */ + static const char *style_buf = + "DEFAULT='font=Sans font_size=30 color=#000 text_class=entry'" + "newline='br'" + "b='+ font=Sans:style=bold'"; + en->txt_style = evas_textblock_style_new(); + evas_textblock_style_set(en->txt_style, style_buf); + evas_object_textblock_style_set(en->txt_obj, en->txt_style); + + /* create cursor */ + en->cursor = evas_object_textblock_cursor_new(en->txt_obj); + + /* create input context */ + const char *default_id = ecore_imf_context_default_id_get(); + if (!default_id) + return; + + en->imf_context = ecore_imf_context_add(default_id); + ecore_imf_context_client_window_set(en->imf_context, (void *)ecore_evas_window_get(ecore_evas_ecore_evas_get(evas))); + ecore_imf_context_client_canvas_set(en->imf_context, evas); + + evas_object_event_callback_add(en->rect, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, en); + evas_object_event_callback_add(en->rect, EVAS_CALLBACK_KEY_UP, _key_up_cb, en); + evas_object_event_callback_add(en->rect, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, en); + evas_object_event_callback_add(en->rect, EVAS_CALLBACK_FOCUS_IN, _entry_focus_in_cb, en); + evas_object_event_callback_add(en->rect, EVAS_CALLBACK_FOCUS_OUT, _entry_focus_out_cb, en); + + en->have_preedit = EINA_FALSE; + en->preedit_start = NULL; + en->preedit_end = NULL; + + /* register retrieve surrounding callback */ + ecore_imf_context_retrieve_surrounding_callback_set(en->imf_context, _ecore_imf_retrieve_surrounding_cb, en); + + /* register commit event callback */ + ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_COMMIT, _ecore_imf_event_commit_cb, en); + + /* register preedit changed event handler */ + ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, _ecore_imf_event_preedit_changed_cb, en); + + /* register surrounding delete event callback */ + ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, _ecore_imf_event_delete_surrounding_cb, en); +} + +static void +delete_input_field(Entry *en) +{ + if (!en) return; + + if (en->rect) + { + evas_object_del(en->rect); + en->rect = NULL; + } + + if (en->cursor) + { + evas_textblock_cursor_free(en->cursor); + en->cursor = NULL; + } + + if (en->preedit_start) + { + evas_textblock_cursor_free(en->preedit_start); + en->preedit_start = NULL; + } + + if (en->preedit_end) + { + evas_textblock_cursor_free(en->preedit_end); + en->preedit_end = NULL; + } + + if (en->txt_obj) + { + evas_object_del(en->txt_obj); + en->txt_obj = NULL; + } + + if (en->txt_style) + { + evas_textblock_style_free(en->txt_style); + en->txt_style = NULL; + } + + if (en->imf_context) + { + ecore_imf_context_del(en->imf_context); + en->imf_context = NULL; + } +} + +int +main(int argc, char *argv[]) +{ + Ecore_Evas *ee; + Evas *evas; + Entry en1, en2; + + if (!ecore_evas_init()) + { + fprintf(stderr, "failed to call ecore_evas_init()\n"); + return EXIT_FAILURE; + } + + ecore_imf_init(); + + // create a new window, with size=480x800 and default engine + ee = ecore_evas_new(NULL, 0, 0, 480, 800, NULL); + + if (!ee) + { + fprintf(stderr, "failed to call ecore_evas_new\n"); + return EXIT_FAILURE; + } + + ecore_evas_show(ee); + + // get the canvas off just-created window + evas = ecore_evas_get(ee); + if (!evas) + { + fprintf(stderr, "failed to ccall ecore_evas_get\n"); + return EXIT_FAILURE; + } + + // create input field rectangle + Evas_Object *bg = evas_object_rectangle_add(evas); + evas_object_move(bg, 0, 0); + evas_object_resize(bg, 480, 800); + evas_object_color_set(bg, 255, 255, 255, 255); + evas_object_show(bg); + + evas_event_callback_add(evas, EVAS_CALLBACK_CANVAS_FOCUS_IN, _canvas_focus_in_cb, NULL); + evas_event_callback_add(evas, EVAS_CALLBACK_CANVAS_FOCUS_OUT, _canvas_focus_out_cb, NULL); + + // create input field 1 + create_input_field(evas, &en1, 40, 60, 400, 80); + + // create input field 2 + create_input_field(evas, &en2, 40, 180, 400, 80); + + // give focus to input field 1 + evas_object_focus_set(en1.rect, EINA_TRUE); + + ecore_main_loop_begin(); // begin mainloop + + delete_input_field(&en1); // delete input field 1 + delete_input_field(&en2); // delete input field 2 + + evas_event_callback_del_full(evas, EVAS_CALLBACK_CANVAS_FOCUS_IN, _canvas_focus_in_cb, NULL); + evas_event_callback_del_full(evas, EVAS_CALLBACK_CANVAS_FOCUS_OUT, _canvas_focus_out_cb, NULL); + + ecore_evas_free(ee); + + ecore_imf_shutdown(); + ecore_evas_shutdown(); + + return 0; +} + diff --git a/src/examples/ecore_job_example.c b/src/examples/ecore_job_example.c new file mode 100644 index 0000000..561a851 --- /dev/null +++ b/src/examples/ecore_job_example.c @@ -0,0 +1,50 @@ +#include +#include + +static void +_job_print_cb(void *data) +{ + char *str = data; + + printf("%s\n", str); +} + +static void +_job_quit_cb(void *data) +{ + ecore_main_loop_quit(); +} + +int +main(int argc, char **argv) +{ + Ecore_Job *job1, *job2, *job3, *job_quit; + char *str1 = "Job 1 started."; + char *str2 = "Job 2 started."; + char *str3 = "Job 3 started."; + + if (!ecore_init()) + { + printf("ERROR: Cannot init Ecore!\n"); + return -1; + } + + job1 = ecore_job_add(_job_print_cb, str1); + job2 = ecore_job_add(_job_print_cb, str2); + job3 = ecore_job_add(_job_print_cb, str3); + + job_quit = ecore_job_add(_job_quit_cb, NULL); + printf("Created jobs 1, 2, 3 and quit.\n"); + + if (job2) + { + char *str; + str = ecore_job_del(job2); + job2 = NULL; + printf("Deleted job 2. Its data was: \"%s\"\n", str); + } + + ecore_main_loop_begin(); + ecore_shutdown(); +} + diff --git a/src/examples/ecore_pipe_gstreamer_example.c b/src/examples/ecore_pipe_gstreamer_example.c new file mode 100644 index 0000000..072aade --- /dev/null +++ b/src/examples/ecore_pipe_gstreamer_example.c @@ -0,0 +1,190 @@ +#include +#include + +static int nbr = 0; + +static GstElement *_buid_pipeline(gchar *filename, Ecore_Pipe *pipe); + +static void new_decoded_pad_cb(GstElement *demuxer, + GstPad *new_pad, + gpointer user_data); + +static void +handler(void *data, void *buf, unsigned int len) +{ + GstBuffer *buffer = *((GstBuffer **)buf); + + printf("handler : %p\n", buffer); + printf("frame : %d %p %lld %p\n", nbr++, data, (long long)GST_BUFFER_DURATION(buffer), buffer); + gst_buffer_unref(buffer); +} + +static void +handoff(GstElement *object, + GstBuffer *arg0, + GstPad *arg1, + gpointer user_data) +{ + Ecore_Pipe *pipe; + + pipe = (Ecore_Pipe *)user_data; + printf("handoff : %p\n", arg0); + gst_buffer_ref(arg0); + ecore_pipe_write(pipe, &arg0, sizeof(arg0)); +} + +int +main(int argc, char *argv[]) +{ + GstElement *pipeline; + char *filename; + Ecore_Pipe *pipe; + + gst_init(&argc, &argv); + + if (!ecore_init()) + { + gst_deinit(); + return 0; + } + + pipe = ecore_pipe_add(handler); + if (!pipe) + { + ecore_shutdown(); + gst_deinit(); + return 0; + } + + if (argc < 2) + { + g_print("usage: %s file.avi\n", argv[0]); + ecore_pipe_del(pipe); + ecore_shutdown(); + gst_deinit(); + return 0; + } + filename = argv[1]; + + pipeline = _buid_pipeline(filename, pipe); + if (!pipeline) + { + g_print("Error during the pipeline building\n"); + ecore_pipe_del(pipe); + ecore_shutdown(); + gst_deinit(); + return -1; + } + + gst_element_set_state(pipeline, GST_STATE_PLAYING); + + ecore_main_loop_begin(); + + ecore_pipe_del(pipe); + ecore_shutdown(); + gst_deinit(); + + return 0; +} + +static void +new_decoded_pad_cb(GstElement *demuxer, + GstPad *new_pad, + gpointer user_data) +{ + GstElement *decoder; + GstPad *pad; + GstCaps *caps; + gchar *str; + + caps = gst_pad_get_caps(new_pad); + str = gst_caps_to_string(caps); + + if (g_str_has_prefix(str, "video/")) + { + decoder = GST_ELEMENT(user_data); + + pad = gst_element_get_pad(decoder, "sink"); + if (GST_PAD_LINK_FAILED(gst_pad_link(new_pad, pad))) + { + g_warning("Failed to link %s:%s to %s:%s", GST_DEBUG_PAD_NAME(new_pad), + GST_DEBUG_PAD_NAME(pad)); + } + } + g_free(str); + gst_caps_unref(caps); +} + +static GstElement +_buid_pipeline(gchar *filename, Ecore_Pipe *pipe) +{ + GstElement *pipeline; + GstElement *filesrc; + GstElement *demuxer; + GstElement *decoder; + GstElement *sink; + GstStateChangeReturn res; + + pipeline = gst_pipeline_new("pipeline"); + if (!pipeline) + return NULL; + + filesrc = gst_element_factory_make("filesrc", "filesrc"); + if (!filesrc) + { + printf("no filesrc"); + goto failure; + } + g_object_set(G_OBJECT(filesrc), "location", filename, NULL); + + demuxer = gst_element_factory_make("oggdemux", "demuxer"); + if (!demuxer) + { + printf("no demux"); + goto failure; + } + + decoder = gst_element_factory_make("theoradec", "decoder"); + if (!decoder) + { + printf("no dec"); + goto failure; + } + + g_signal_connect(demuxer, "pad-added", + G_CALLBACK(new_decoded_pad_cb), decoder); + + sink = gst_element_factory_make("fakesink", "sink"); + if (!sink) + { + printf("no sink"); + goto failure; + } + g_object_set(G_OBJECT(sink), "sync", EINA_TRUE, NULL); + g_object_set(G_OBJECT(sink), "signal-handoffs", EINA_TRUE, NULL); + g_signal_connect(sink, "handoff", + G_CALLBACK(handoff), pipe); + + gst_bin_add_many(GST_BIN(pipeline), + filesrc, demuxer, decoder, sink, NULL); + + if (!gst_element_link(filesrc, demuxer)) + goto failure; + if (!gst_element_link(decoder, sink)) + goto failure; + + res = gst_element_set_state(pipeline, GST_STATE_PAUSED); + if (res == GST_STATE_CHANGE_FAILURE) + goto failure; + + res = gst_element_get_state(pipeline, NULL, NULL, GST_CLOCK_TIME_NONE); + if (res != GST_STATE_CHANGE_SUCCESS) + goto failure; + + return pipeline; + +failure: + gst_object_unref(GST_OBJECT(pipeline)); + return NULL; +} + diff --git a/src/examples/ecore_pipe_simple_example.c b/src/examples/ecore_pipe_simple_example.c new file mode 100644 index 0000000..67bd4e7 --- /dev/null +++ b/src/examples/ecore_pipe_simple_example.c @@ -0,0 +1,67 @@ +//Compile with: +//gcc -g -Wall `pkg-config --cflags --libs ecore` -o ecore_pipe_simple_example ecore_pipe_simple_example.c + +#include +#include + +static void +do_lengthy_task(Ecore_Pipe *pipe) +{ + int i, j; + char *buffer; + for (i = 0; i < 20; i++) + { + sleep(1); + buffer = malloc(sizeof(char) * i); + for (j = 0; j < i; j++) + buffer[j] = 'a' + j; + ecore_pipe_write(pipe, buffer, i); + free(buffer); + } + ecore_pipe_write(pipe, "close", 5); +} + +static void +handler(void *data, void *buf, unsigned int len) +{ + char *str = malloc(sizeof(char) * len + 1); + memcpy(str, buf, len); + str[len] = '\0'; + printf("received %d bytes\n", len); + printf("content: %s\n", (const char *)str); + free(str); + if (len && !strncmp(buf, "close", len < 5 ? len : 5)) + { + printf("close requested\n"); + ecore_main_loop_quit(); + } +} + +int +main(int argc, char *argv[]) +{ + Ecore_Pipe *pipe; + pid_t child_pid; + + ecore_init(); + + pipe = ecore_pipe_add(handler, NULL); + + child_pid = fork(); + if (!child_pid) + { + ecore_pipe_read_close(pipe); + do_lengthy_task(pipe); + } + else + { + ecore_pipe_write_close(pipe); + ecore_main_loop_begin(); + } + + ecore_pipe_del(pipe); + ecore_shutdown(); + + return 0; +} + diff --git a/src/examples/ecore_poller_example.c b/src/examples/ecore_poller_example.c new file mode 100644 index 0000000..0e246de --- /dev/null +++ b/src/examples/ecore_poller_example.c @@ -0,0 +1,49 @@ +#include +#include + +static double _initial_time = 0; + +static Eina_Bool +_poller_print_cb(void *data) +{ + char *str = data; + printf("Ecore Poller '%s' callback called after %0.3f seconds.\n", + str, ecore_time_get() - _initial_time); + + return ECORE_CALLBACK_RENEW; +} + +int +main(int argc, char **argv) +{ + double interval = 0.3; // tick each 0.3 seconds + Ecore_Poller *poller1, *poller2; + char *str1 = "poller1"; + char *str2 = "poller2"; + + if (!ecore_init()) + { + printf("ERROR: Cannot init Ecore!\n"); + return -1; + } + + _initial_time = ecore_time_get(); + + ecore_poller_poll_interval_set(ECORE_POLLER_CORE, interval); + + poller1 = ecore_poller_add(ECORE_POLLER_CORE, 4, _poller_print_cb, str1); + poller2 = ecore_poller_add(ECORE_POLLER_CORE, 8, _poller_print_cb, str2); + + ecore_main_loop_begin(); + + printf("changing poller2 interval to 16\n"); + + ecore_poller_poller_interval_set(poller2, 16); + ecore_main_loop_begin(); + + ecore_poller_del(poller1); + ecore_poller_del(poller2); + + ecore_shutdown(); +} + diff --git a/src/examples/ecore_server_bench.c b/src/examples/ecore_server_bench.c new file mode 100644 index 0000000..1f9b63a --- /dev/null +++ b/src/examples/ecore_server_bench.c @@ -0,0 +1,63 @@ +#include +#include +#include + +/* Ecore_Con server example + * 2010 Mike Blumenkrantz + */ + +static Ecore_Con_Server *svr; +static int add; +static int del; + +Eina_Bool +_add(void *data, int type, Ecore_Con_Event_Client_Add *ev) +{ + ++add; +// printf ("%s ", ecore_con_client_ip_get(ev->client)); + printf("Client #%i!\n", add); + return ECORE_CALLBACK_RENEW; +} + +Eina_Bool +_del(void *data, int type, Ecore_Con_Event_Client_Del *ev) +{ + ++del; + printf("Disconnected #%i!\n", del); + if (add == del) + ecore_main_loop_quit(); + return ECORE_CALLBACK_RENEW; +} + +int +main(int argc, const char *argv[]) +{ + ecore_init(); + ecore_con_init(); + ecore_app_args_set(argc, argv); + eina_log_domain_level_set("ecore_con", EINA_LOG_LEVEL_ERR); + eina_log_domain_level_set("eina", EINA_LOG_LEVEL_ERR); + +/* to use a PEM certificate with TLS and SSL3, uncomment the lines below */ +// if (!(svr = ecore_con_server_add(ECORE_CON_REMOTE_NODELAY | ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT, "127.0.0.1", 8080, NULL))) + +/* to use simple tcp with ssl/tls, use this line */ + svr = ecore_con_server_add(ECORE_CON_REMOTE_NODELAY, "127.0.0.1", 8080, NULL); + if (!svr) + exit(1); + + ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_ADD, (Ecore_Event_Handler_Cb)_add, NULL); + ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DEL, (Ecore_Event_Handler_Cb)_del, NULL); + +/* start server */ + ecore_main_loop_begin(); + if (add && del) + { + printf("Restarting server after %i connections\n", add); + add = del = 0; + ecore_con_server_del(svr); + ecore_app_restart(); + } + return 0; +} + diff --git a/src/examples/ecore_thread_example.c b/src/examples/ecore_thread_example.c new file mode 100644 index 0000000..f02d007 --- /dev/null +++ b/src/examples/ecore_thread_example.c @@ -0,0 +1,395 @@ +/* + * gcc -o ecore_thread_example ecore_thread_example.c `pkg-config --cflags --libs ecore` + */ +#include +#include +#include +#include +#include + +typedef struct +{ + Ecore_Thread *thread_3; + int msgs_received; + int max_msgs; + Eina_Lock mutex; + Eina_Condition condition; +} App_Data; + +typedef struct +{ + Eina_List *list; +} Thread_Data; + +typedef struct +{ + char *name; + char *base; + Eina_Lock mutex; +} Feedback_Thread_Data; + +typedef struct +{ + int all_done; + Eina_List *list; +} App_Msg; + +static void +_local_data_free(void *data) +{ + Thread_Data *td = data; + char *str; + + EINA_LIST_FREE(td->list, str) + { + printf("Freeing string: %s\n", str); + free(str); + } + free(td); +} + +static void +_short_job(void *data, Ecore_Thread *th) +{ + Thread_Data *td; + int i; + + td = ecore_thread_local_data_find(th, "data"); + if (!td) + { + td = calloc(1, sizeof(Thread_Data)); + if (!td) + { + ecore_thread_cancel(th); + return; + } + ecore_thread_local_data_add(th, "data", td, _local_data_free, + EINA_FALSE); + } + + for (i = 0; i < 10; i++) + { + char buf[200]; + + if (ecore_thread_check(th)) + { + ecore_thread_local_data_del(th, "data"); + break; + } + + snprintf(buf, sizeof(buf), "Thread %p: String number %d", th, i); + td->list = eina_list_append(td->list, strdup(buf)); + sleep(1); + } +} + +static void +_feedback_job(void *data, Ecore_Thread *th) +{ + time_t t; + int i, count; + Feedback_Thread_Data *ftd = NULL; + DIR *dir; + App_Msg *msg; + + count = (int)ecore_thread_global_data_find("count"); + for (i = 0; i < count; i++) + { + char buf[32]; + snprintf(buf, sizeof(buf), "data%d", i); + ftd = ecore_thread_global_data_find(buf); + if (!ftd) + continue; + if (eina_lock_take_try(&ftd->mutex)) + break; + else + ftd = NULL; + } + if (!ftd) + return; + + dir = opendir(ftd->base); + if (!dir) + goto the_end; + + msg = calloc(1, sizeof(App_Msg)); + + t = time(NULL); + while (time(NULL) < t + 2) + { + struct dirent entry, *result; + + if (readdir_r(dir, &entry, &result)) + break; + if (!result) + break; + + if (strlen(result->d_name) >= 10) + msg->list = eina_list_append(msg->list, + strdup(result->d_name)); + } + + closedir(dir); + ecore_thread_feedback(th, msg); + +the_end: + ecore_thread_global_data_del(ftd->name); + free(ftd->name); + free(ftd->base); + eina_lock_release(&ftd->mutex); + eina_lock_free(&ftd->mutex); + free(ftd); + ecore_thread_reschedule(th); +} + +static void +_out_of_pool_job(void *data, Ecore_Thread *th) +{ + App_Data *ad = data; + App_Msg *msg; + + while (1) + { + int msgs; + eina_condition_wait(&ad->condition); + msgs = ad->msgs_received; + eina_lock_release(&ad->mutex); + if (msgs == ad->max_msgs) + { + msg = calloc(1, sizeof(App_Msg)); + msg->all_done = 1; + ecore_thread_feedback(th, msg); + return; + } + } +} + +static void +_print_status(void) +{ + int active, pending_total, pending_feedback, pending_short, available; + + active = ecore_thread_active_get(); + pending_total = ecore_thread_pending_total_get(); + pending_feedback = ecore_thread_pending_feedback_get(); + pending_short = ecore_thread_pending_get(); + available = ecore_thread_available_get(); + + printf("Status:\n\t* Active threads: %d\n" + "\t* Available threads: %d\n" + "\t* Pending short jobs: %d\n" + "\t* Pending feedback jobs: %d\n" + "\t* Pending total: %d\n", active, available, pending_short, + pending_feedback, pending_total); +} + +static void +_feedback_job_msg_cb(void *data, Ecore_Thread *th, void *msg_data) +{ + App_Data *ad = data; + App_Msg *msg = msg_data; + char *str; + + if (msg->all_done) + { + ecore_main_loop_quit(); + free(msg); + return; + } + + _print_status(); + + if (!msg->list) + printf("Received an empty list from thread %p\n", th); + else + { + int i = 0; + printf("Received %d elements from threads %p (printing first 5):\n", + eina_list_count(msg->list), th); + EINA_LIST_FREE(msg->list, str) + { + if (i <= 5) + printf("\t%s\n", str); + free(str); + i++; + } + } + + eina_lock_take(&ad->mutex); + ad->msgs_received++; + eina_condition_signal(&ad->condition); + eina_lock_release(&ad->mutex); + + free(msg); +} + +static void +_thread_end_cb(void *data, Ecore_Thread *th) +{ + App_Data *ad = data; + + printf("Normal termination for thread %p.\n", th); + if (th == ad->thread_3) + ad->thread_3 = NULL; +} + +static void +_thread_cancel_cb(void *data, Ecore_Thread *th) +{ + App_Data *ad = data; + + printf("Thread %p got cancelled.\n", th); + if (th == ad->thread_3) + ad->thread_3 = NULL; +} + +static Eina_Bool +_cancel_timer_cb(void *data) +{ + App_Data *ad = data; + + if (ad->thread_3 && !ecore_thread_check(ad->thread_3)) + ecore_thread_cancel(ad->thread_3); + + return EINA_FALSE; +} + +static Eina_Bool +_status_timer_cb(void *data) +{ + _print_status(); + + return EINA_TRUE; +} + +static const Ecore_Getopt optdesc = { + "ecore_thread_example", + NULL, + "0.0", + "(C) 2011 Enlightenment", + "Public domain?", + "Example program for Ecore_Thread", + 0, + { + ECORE_GETOPT_STORE_INT('t', "threads", "Max number of threads to run"), + ECORE_GETOPT_STORE_INT('m', "msgs", "Max number of messages to receive"), + ECORE_GETOPT_APPEND_METAVAR('p', "path", "Add path for feedback job", + "STRING", ECORE_GETOPT_TYPE_STR), + ECORE_GETOPT_HELP('h', "help"), + ECORE_GETOPT_SENTINEL + } +}; + +int +main(int argc, char *argv[]) +{ + int i, max_threads = 0, max_msgs = 0; + Eina_Bool opt_quit = EINA_FALSE; + Eina_List *path_list = NULL; + App_Data appdata; + Ecore_Getopt_Value values[] = { + ECORE_GETOPT_VALUE_INT(max_threads), + ECORE_GETOPT_VALUE_INT(max_msgs), + ECORE_GETOPT_VALUE_LIST(path_list), + ECORE_GETOPT_VALUE_BOOL(opt_quit), + ECORE_GETOPT_VALUE_NONE + }; + + ecore_init(); + + i = ecore_thread_max_get(); + printf("Initial max threads: %d\n", i); + + memset(&appdata, 0, sizeof(App_Data)); + appdata.max_msgs = 1; + + if (ecore_getopt_parse(&optdesc, values, argc, argv) < 0) + { + printf("Argument parsing failed\n"); + return 1; + } + + if (opt_quit) + return 0; + + if (max_threads) + { + ecore_thread_max_set(max_threads); + printf("Max threads: %d\n", ecore_thread_max_get()); + } + if (max_msgs) + appdata.max_msgs = max_msgs; + + if (!path_list) + { + Feedback_Thread_Data *ftd; + ecore_thread_global_data_add("count", (void *)3, NULL, EINA_FALSE); + ftd = calloc(1, sizeof(Feedback_Thread_Data)); + ftd->name = strdup("data0"); + ftd->base = strdup("/usr/bin"); + eina_lock_new(&ftd->mutex); + ecore_thread_global_data_add(ftd->name, ftd, NULL, EINA_TRUE); + ftd = calloc(1, sizeof(Feedback_Thread_Data)); + ftd->name = strdup("data1"); + ftd->base = strdup("/usr/lib"); + eina_lock_new(&ftd->mutex); + ecore_thread_global_data_add(ftd->name, ftd, NULL, EINA_TRUE); + ftd = calloc(1, sizeof(Feedback_Thread_Data)); + ftd->name = strdup("data2"); + ftd->base = strdup("/usr/share"); + eina_lock_new(&ftd->mutex); + ecore_thread_global_data_add(ftd->name, ftd, NULL, EINA_TRUE); + } + else + { + Feedback_Thread_Data *ftd; + char *str; + ecore_thread_global_data_add("count", + (void *)eina_list_count(path_list), NULL, + EINA_FALSE); + i = 0; + EINA_LIST_FREE(path_list, str) + { + char buf[32]; + snprintf(buf, sizeof(buf), "data%d", i); + ftd = calloc(1, sizeof(Feedback_Thread_Data)); + ftd->name = strdup(buf); + ftd->base = strdup(str); + eina_lock_new(&ftd->mutex); + ecore_thread_global_data_add(ftd->name, ftd, NULL, EINA_TRUE); + free(str); + i++; + } + } + + eina_lock_new(&appdata.mutex); + eina_condition_new(&appdata.condition, &appdata.mutex); + + ecore_thread_feedback_run(_out_of_pool_job, _feedback_job_msg_cb, NULL, + NULL, &appdata, EINA_TRUE); + + ecore_thread_run(_short_job, _thread_end_cb, _thread_cancel_cb, &appdata); + ecore_thread_feedback_run(_feedback_job, _feedback_job_msg_cb, + _thread_end_cb, _thread_cancel_cb, &appdata, + EINA_FALSE); + appdata.thread_3 = ecore_thread_run(_short_job, _thread_end_cb, + _thread_cancel_cb, &appdata); + ecore_thread_feedback_run(_feedback_job, _feedback_job_msg_cb, + _thread_end_cb, _thread_cancel_cb, &appdata, + EINA_FALSE); + + ecore_timer_add(1.0, _cancel_timer_cb, &appdata); + ecore_timer_add(2.0, _status_timer_cb, NULL); + + _print_status(); + + ecore_main_loop_begin(); + + eina_condition_free(&appdata.condition); + eina_lock_free(&appdata.mutex); + + ecore_shutdown(); + + return 0; +} + diff --git a/src/examples/ecore_time_functions_example.c b/src/examples/ecore_time_functions_example.c new file mode 100644 index 0000000..d742c8b --- /dev/null +++ b/src/examples/ecore_time_functions_example.c @@ -0,0 +1,34 @@ +#include +#include + +static Eina_Bool +_timer_cb(void *data) +{ + printf("ecore time: %0.3f\n", ecore_time_get()); + printf("loop time: %0.3f\n", ecore_loop_time_get()); + printf("unix time: %0.3f\n", ecore_time_unix_get()); + printf("\nSleep for 1 second...\n\n"); + sleep(1); + printf("ecore time: %0.3f\n", ecore_time_get()); + printf("loop time: %0.3f\n", ecore_loop_time_get()); + printf("unix time: %0.3f\n", ecore_time_unix_get()); + + ecore_main_loop_quit(); + + return EINA_FALSE; +} + +int +main(int argc, char **argv) +{ + if (!ecore_init()) + { + printf("ERROR: Cannot init Ecore!\n"); + return -1; + } + + ecore_timer_add(0.1, _timer_cb, NULL); + ecore_main_loop_begin(); + ecore_shutdown(); +} + diff --git a/src/examples/ecore_timer_example.c b/src/examples/ecore_timer_example.c new file mode 100644 index 0000000..bafeacb --- /dev/null +++ b/src/examples/ecore_timer_example.c @@ -0,0 +1,187 @@ +#include +#include + +#define TIMEOUT_1 1.0 // interval for timer1 +#define TIMEOUT_2 3.0 // timer2 - delay timer1 +#define TIMEOUT_3 8.2 // timer3 - pause timer1 +#define TIMEOUT_4 11.0 // timer4 - resume timer1 +#define TIMEOUT_5 14.0 // timer5 - change interval of timer1 +#define TIMEOUT_6 18.0 // top timer1 and start timer7 and timer8 with changed precision +#define TIMEOUT_7 1.1 // interval for timer7 +#define TIMEOUT_8 1.2 // interval for timer8 +#define DELAY_1 3.0 // delay time for timer1 - used by timer2 +#define INTERVAL1 2.0 // new interval for timer1 - used by timer5 + +static double _initial_time = 0; + +struct context // helper struct to give some context to the callbacks +{ + Ecore_Timer *timer1; + Ecore_Timer *timer2; + Ecore_Timer *timer3; + Ecore_Timer *timer4; + Ecore_Timer *timer5; + Ecore_Timer *timer6; + Ecore_Timer *timer7; + Ecore_Timer *timer8; +}; + +static double +_get_current_time(void) +{ + return ecore_time_get() - _initial_time; +} + +static Eina_Bool +_timer1_cb(void *data) +{ + printf("Timer1 expired after %0.3f seconds.\n", _get_current_time()); + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +_timer2_cb(void *data) +{ + struct context *ctxt = data; + printf("Timer2 expired after %0.3f seconds. " + "Adding delay of %0.3f seconds to timer1.\n", + _get_current_time(), DELAY_1); + + ecore_timer_delay(ctxt->timer1, DELAY_1); + + ctxt->timer2 = NULL; + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool +_timer3_cb(void *data) +{ + struct context *ctxt = data; + printf("Timer3 expired after %0.3f seconds. " + "Freezing timer1.\n", _get_current_time()); + + ecore_timer_freeze(ctxt->timer1); + + ctxt->timer3 = NULL; + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool +_timer4_cb(void *data) +{ + struct context *ctxt = data; + printf("Timer4 expired after %0.3f seconds. " + "Resuming timer1, which has %0.3f seconds left to expire.\n", + _get_current_time(), ecore_timer_pending_get(ctxt->timer1)); + + ecore_timer_thaw(ctxt->timer1); + + ctxt->timer4 = NULL; + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool +_timer5_cb(void *data) +{ + struct context *ctxt = data; + double interval = ecore_timer_interval_get(ctxt->timer1); + + printf("Timer5 expired after %0.3f seconds. " + "Changing interval of timer1 from %0.3f to %0.3f seconds.\n", + _get_current_time(), interval, INTERVAL1); + + ecore_timer_interval_set(ctxt->timer1, INTERVAL1); + + ctxt->timer5 = NULL; + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool +_timer7_cb(void *data) +{ + struct context *ctxt = data; + printf("Timer7 expired after %0.3f seconds.\n", _get_current_time()); + + ctxt->timer7 = NULL; + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool +_timer8_cb(void *data) +{ + struct context *ctxt = data; + printf("Timer8 expired after %0.3f seconds.\n", _get_current_time()); + + ctxt->timer8 = NULL; + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool +_timer6_cb(void *data) +{ + struct context *ctxt = data; + printf("Timer6 expired after %0.3f seconds.\n", _get_current_time()); + + printf("Stopping timer1.\n"); + + ecore_timer_del(ctxt->timer1); + ctxt->timer1 = NULL; + + printf("Starting timer7 (%0.3fs) and timer8 (%0.3fs).\n", + TIMEOUT_7, TIMEOUT_8); + + ctxt->timer7 = ecore_timer_add(TIMEOUT_7, _timer7_cb, ctxt); + ctxt->timer8 = ecore_timer_add(TIMEOUT_8, _timer8_cb, ctxt); + + ecore_timer_precision_set(0.2); + + ctxt->timer6 = NULL; + return ECORE_CALLBACK_CANCEL; +} + +int +main(int argc, char **argv) +{ + struct context ctxt = {0}; + + if (!ecore_init()) + { + printf("ERROR: Cannot init Ecore!\n"); + return -1; + } + + _initial_time = ecore_time_get(); + + ctxt.timer1 = ecore_timer_add(TIMEOUT_1, _timer1_cb, &ctxt); + ctxt.timer2 = ecore_timer_add(TIMEOUT_2, _timer2_cb, &ctxt); + ctxt.timer3 = ecore_timer_add(TIMEOUT_3, _timer3_cb, &ctxt); + ctxt.timer4 = ecore_timer_add(TIMEOUT_4, _timer4_cb, &ctxt); + ctxt.timer5 = ecore_timer_add(TIMEOUT_5, _timer5_cb, &ctxt); + ctxt.timer6 = ecore_timer_add(TIMEOUT_6, _timer6_cb, &ctxt); + + printf("start the main loop.\n"); + + ecore_main_loop_begin(); + + if (ctxt.timer1) + ecore_timer_del(ctxt.timer1); + if (ctxt.timer2) + ecore_timer_del(ctxt.timer2); + if (ctxt.timer3) + ecore_timer_del(ctxt.timer3); + if (ctxt.timer4) + ecore_timer_del(ctxt.timer4); + if (ctxt.timer5) + ecore_timer_del(ctxt.timer5); + if (ctxt.timer6) + ecore_timer_del(ctxt.timer6); + if (ctxt.timer7) + ecore_timer_del(ctxt.timer7); + if (ctxt.timer8) + ecore_timer_del(ctxt.timer8); + + ecore_shutdown(); + + return 0; +} + diff --git a/src/examples/red.png b/src/examples/red.png new file mode 100644 index 0000000000000000000000000000000000000000..dd03528d706824eb72bddf34b9057e40484ea7a0 GIT binary patch literal 225 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3jKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-AbW|YuPgg)Hdz4wc6x=<11Hv2m#DR)zJY5_^JdVG;V#vi{z`=4b_|t#=_$uvI zf!TMXWHuP+L~<{k#>B=}cP;bW(Sr4srUnKEAHK)u`tkDc#O&T}%wqd2&cgv{4uhww KpUXO@geCwC>Ojr_ literal 0 HcmV?d00001 diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am new file mode 100644 index 0000000..d43ad75 --- /dev/null +++ b/src/lib/Makefile.am @@ -0,0 +1,75 @@ +## Process this file with automake to produce Makefile.in +MAINTAINERCLEANFILES = Makefile.in +SUBDIRS = ecore + +if BUILD_ECORE_INPUT +SUBDIRS += ecore_input +endif + +if BUILD_ECORE_INPUT_EVAS +SUBDIRS += ecore_input_evas +endif + +if BUILD_ECORE_FB +SUBDIRS += ecore_fb +endif + +if BUILD_ECORE_DIRECTFB +SUBDIRS += ecore_directfb +endif + +if BUILD_ECORE_CON +SUBDIRS += ecore_con +endif + +if BUILD_ECORE_X +SUBDIRS += ecore_x +endif + +if BUILD_ECORE_WIN32 +SUBDIRS += ecore_win32 +endif + +if BUILD_ECORE_WINCE +SUBDIRS += ecore_wince +endif + +if BUILD_ECORE_SDL +SUBDIRS += ecore_sdl +endif + +if BUILD_ECORE_PSL1GHT +SUBDIRS += ecore_psl1ght +endif + +if BUILD_ECORE_COCOA +SUBDIRS += ecore_cocoa +endif + +if BUILD_ECORE_WAYLAND +SUBDIRS += ecore_wayland +endif + +if BUILD_ECORE_IPC +SUBDIRS += ecore_ipc +endif + +if BUILD_ECORE_EVAS +SUBDIRS += ecore_evas +endif + +if BUILD_ECORE_CONFIG +SUBDIRS += ecore_config +endif + +if BUILD_ECORE_FILE +SUBDIRS += ecore_file +endif + +if BUILD_ECORE_IMF +SUBDIRS += ecore_imf +endif + +if BUILD_ECORE_IMF_EVAS +SUBDIRS += ecore_imf_evas +endif diff --git a/src/lib/ecore/Ecore.h b/src/lib/ecore/Ecore.h new file mode 100644 index 0000000..9d8041f --- /dev/null +++ b/src/lib/ecore/Ecore.h @@ -0,0 +1,2619 @@ +/** + @brief Ecore Library Public API Calls + + These routines are used for Ecore Library interaction + */ + +/** + + @mainpage Ecore + + @version 1.7 + @date 2000-2012 + + Please see the @ref authors page for contact details. + + @section intro Introduction + + Ecore is a library of convenience functions. A brief explanation of how to use + it can be found in @ref Ecore_Main_Loop_Page. + + The Ecore library provides the following modules: + @li @ref Ecore_Main_Loop_Group + @li @ref Ecore_File_Group + @li @ref Ecore_Con_Group + @li @ref Ecore_Evas_Group + @li @ref Ecore_FB_Group + @li @ref Ecore_IMF_Lib_Group + @li @ref Ecore_IMF_Context_Group + @li @ref Ecore_IMF_Context_Module_Group + @li @ref Ecore_IMF_Evas_Group + @li @link Ecore_Ipc.h Ecore_IPC - Inter Process Communication functions. @endlink + @li @link Ecore_X.h Ecore_X - X Windows System wrapper. @endlink + @li @ref Ecore_Win32_Group + @li @ref Ecore_WinCE_Group + + For more info on Ecore usage, there are these @ref Examples. + + @section compiling How to compile using Ecore? + pkgconfig (.pc) files are installed for every ecore module. + Thus, to compile using any of them, you can use something like the following: + +@verbatim +gcc *.c $(pkg-config ecore ecore-$x ecore-$y [...] --cflags --libs) +@endverbatim + + @section install How is it installed? + + Suggested configure options for ecore for a Linux desktop X display + with OpenGL and Software support, communication (networking) and + IPC (inter process communication): + +@verbatim +./configure \ + --enable-ecore-con \ + --enable-ecore-ipc \ + --enable-ecore-file \ + --enable-ecore-input \ + --enable-ecore-input-evas \ + --enable-ecore-x \ + --enable-ecore-evas \ + --enable-ecore-evas-software-buffer \ + --enable-ecore-evas-software-x11 \ + --enable-ecore-evas-opengl-x11 +make +sudo make install +@endverbatim + + */ + +/** + @page authors Authors + @author Carsten Haitzler + @author Tom Gilbert + @author Burra + @author Chris Ross + @author Term + @author Tilman Sauerbeck + @author Ibukun Olumuyiwa + @author Yuri + @author Nicholas Curran + @author Howell Tam + @author Nathan Ingersoll + @author Andrew Elcock + @author Kim Woelders + @author Sebastian Dransfeld + @author Simon Poole + @author Jorge Luis Zapata Muga + @author dan sinclair + @author Michael 'Mickey' Lauer + @author David 'onefang' Seikel + @author Hisham 'CodeWarrior' Mardam Bey + @author Brian 'rephorm' Mattern + @author Tim Horton + @author Arnaud de Turckheim 'quarium' + @author Matt Barclay + @author Peter Wehrfritz + @author Albin "Lutin" Tonnerre + @author Vincent Torri + @author Lars Munch + @author Andre Dieb + @author Mathieu Taillefumier + @author Rui Miguel Silva Seabra + @author Samsung Electronics + @author Samsung SAIT + @author Nicolas Aguirre + @author Brett Nash + @author Mike Blumenkrantz + @author Leif Middelschulte + @author Mike McCormack + @author Sangho Park + @author Jihoon Kim + @author PnB + @author Daniel Juyung Seo + @author Christopher 'devilhorns' Michael + @author ChunEon Park + @author xlopez@igalia.com + @author Rafael Antognolli + @author Kim Yunhan + @author Youness Alaoui + @author Bluezery + @author Doyoun Kang + @author Haifeng Deng + @author Jérémy Zurcher + @author Vikram Narayanan + + Please contact to get in + contact with the developers and maintainers. + */ + +/** + * @page Ecore_Main_Loop_Page The Ecore Main Loop + * + * @section intro What is Ecore? + * + * Ecore is a clean and tiny event loop library with many modules to do lots of + * convenient things for a programmer, to save time and effort. It's small and + * lean, designed to work from embedded systems all the way up to large and + * powerful multi-cpu workstations. The main loop has a number of primitives to + * be used with its main loop. It serializes all the primitives and allows for + * great responsiveness without the need for threads(or any other concurrency). + * + * @subsection timers Timers + * + * Timers serve two main purposes: doing something at a specified time and + * repeatedly doing something with a set interval. + * @see Ecore_Timer_Group + * + * @subsection poolers Poolers + * + * Poolers allow for pooling to be centralized into a single place therefore + * alleviating the need for different parts of the program to wake up at + * different times to do pooling, thereby making the code simpler and more + * efficient. + * @see Ecore_Poller_Group + * + * @subsection idler Idlers + * + * There are three types of idlers, enterers, idlers(proper) and exiters, they + * are called, respectively, when the program is about to enter an idle state, + * when the program is idle and when the program is leaving an idle state. Idler + * enterers are usually a good place to update the program state. Proper idlers + * are the appropriate place to do heavy computational tasks thereby using what + * would otherwise be wasted CPU cycles. Exiters are the perfect place to do + * anything your program should do just before processing events(also timers, + * poolers, file descriptor handlers and animators) + * @see Ecore_Idle_Group + * + * @subsection fd_handler File descriptor handlers + * + * File descriptor handlers allow you to monitor when there is data available to + * read on file descriptors, when writing will not block or if there was an + * error. Any valid file descriptor can be used with this API, regardless of if + * was gotten with an OS specific API or from ecore. + * @see Ecore_FD_Handler_Group + * + * @subsection animators Animators + * + * Ecore provides a facility called animators, so named since the intended use + * was in animations, that facilitates knowing what percentage of a given + * interval has elapsed. This is perfect for performing animations, but is not + * limited to that use, it can, for example, also be used to create a progress + * bar. + * @see Ecore_Animator_Group + * + * @subsection ev_handlers Event handlers + * + * Event handlers are, arguably, the most important feature of the ecore main + * loop, they are what allows the programmer to easily handle user interaction. + * Events however are not only things the user does, events can represent + * anything for which a type is created. + * @see Ecore_Event_Group + * + * All of these primitives are discussed in more detail in their respective + * pages linked above. + * + * Here is a diagram of the main loop flow of a simple program: + * + * @image html prog_flow.png + * @image latex prog_flow.eps width=\textwidth + * + * + * + * @section work How does Ecore work? + * + * Ecore is very easy to learn and use. All the function calls are designed to + * be easy to remember, explicit in describing what they do, and heavily + * name-spaced. Ecore programs can start and be very simple. + * + * For example: + * + * @code + * #include + * + * int + * main(int argc, const char **argv) + * { + * ecore_init(); + * ecore_app_args_set(argc, argv); + * ecore_main_loop_begin(); + * ecore_shutdown(); + * return 0; + * } + * @endcode + * + * This program is very simple and doesn't check for errors, but it does start up + * and begin a main loop waiting for events or timers to tick off. This program + * doesn't set up any, but now we can expand on this simple program a little + * more by adding some event handlers and timers. + * + * @code + * #include + * + * Ecore_Timer *timer1 = NULL; + * Ecore_Event_Handler *handler1 = NULL; + * double start_time = 0.0; + * + * int + * timer_func(void *data) + * { + * printf("Tick timer. Sec: %3.2f\n", ecore_time_get() - start_time); + * return 1; + * } + * + * int + * exit_func(void *data, int ev_type, void *ev) + * { + * Ecore_Event_Signal_Exit *e; + * + * e = (Ecore_Event_Signal_Exit *)ev; + * if (e->interrupt) printf("Exit: interrupt\n"); + * else if (e->quit) printf("Exit: quit\n"); + * else if (e->terminate) printf("Exit: terminate\n"); + * ecore_main_loop_quit(); + * return 1; + * } + * + * int + * main(int argc, const char **argv) + * { + * ecore_init(); + * ecore_app_args_set(argc, argv); + * start_time = ecore_time_get(); + * handler1 = ecore_event_handler_add(ECORE_EVENT_SIGNAL_EXIT, exit_func, NULL); + * timer1 = ecore_timer_add(0.5, timer_func, NULL); + * ecore_main_loop_begin(); + * ecore_shutdown(); + * return 0; + * } + * @endcode + * + * In the previous example, we initialize our application and get the time at + * which our program has started so we can calculate an offset. We set + * up a timer to tick off in 0.5 seconds, and since it returns 1, will + * keep ticking off every 0.5 seconds until it returns 0, or is deleted + * by hand. An event handler is set up to call a function - + * exit_func(), + * whenever an event of type ECORE_EVENT_SIGNAL_EXIT is received (CTRL-C + * on the command line will cause such an event to happen). If this event + * occurs it tells you what kind of exit signal was received, and asks + * the main loop to quit when it is finished by calling + * ecore_main_loop_quit(). + * + * The handles returned by ecore_timer_add() and + * ecore_event_handler_add() are + * only stored here as an example. If you don't need to address the timer or + * event handler again you don't need to store the result, so just call the + * function, and don't assign the result to any variable. + * + * This program looks slightly more complex than needed to do these simple + * things, but in principle, programs don't get any more complex. You add more + * event handlers, for more events, will have more timers and such, BUT it all + * follows the same principles as shown in this example. + * + */ + +/* + @page Ecore_Config_Page The Enlightened Property Library + + The Enlightened Property Library (Ecore_Config) is an abstraction + from the complexities of writing your own configuration. It provides + many features using the Enlightenment 17 development libraries. + + To use the library, you: + @li Set the default values of your properties. + @li Load the configuration from a file. You must set the default values + first, so that the library knows the correct type of each argument. + + The following examples show how to use the Enlightened Property Library: + @li @link config_basic_example.c config_basic_example.c @endlink + @li @link config_listener_example.c config_listener_example.c @endlink + + */ + +/** + @page X_Window_System_Page X Window System + + The Ecore library includes a wrapper for handling the X window system. + This page briefly explains what the X window system is and various terms + that are used. + */ + +#ifndef _ECORE_H +#define _ECORE_H + +#ifdef _MSC_VER +# include +#endif + +#include + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_ECORE_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_ECORE_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +#ifdef _WIN32 +# include +#elif defined (__FreeBSD__) || defined (__OpenBSD__) +# include +# include +#elif defined (__ANDROID__) +# include +#else +# include +# if !defined (EXOTIC_NO_SIGNAL) +# include +# endif +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup Ecore_Init_Group Ecore initialization, shutdown functions and reset on fork. + * + * @{ + */ + +EAPI int ecore_init(void); +EAPI int ecore_shutdown(void); +/** + * @} + */ + +/** + * @defgroup Ecore_Main_Loop_Group Ecore main loop + * + * This group discusses functions that are acting on Ecore's main loop itself or + * on events and infrastructure directly linked to it. Most programs only need + * to start and end the main loop, the rest of the function discussed here are + * meant to be used in special situations, and with great care. + * + * For details on the usage of ecore's main loop and how it interacts with other + * ecore facilities see: @ref Ecore_Main_Loop_Page. + * + * @{ + */ + +#define ECORE_VERSION_MAJOR 1 +#define ECORE_VERSION_MINOR 7 + +typedef struct _Ecore_Version +{ + int major; + int minor; + int micro; + int revision; +} Ecore_Version; + +EAPI extern Ecore_Version *ecore_version; + +#define ECORE_CALLBACK_CANCEL EINA_FALSE /**< Return value to remove a callback */ +#define ECORE_CALLBACK_RENEW EINA_TRUE /**< Return value to keep a callback */ + +#define ECORE_CALLBACK_PASS_ON EINA_TRUE /**< Return value to pass event to next handler */ +#define ECORE_CALLBACK_DONE EINA_FALSE /**< Return value to stop event handling */ + +/** + * @typedef Ecore_Task_Cb Ecore_Task_Cb + * A callback run for a task (timer, idler, poller, animator, etc) + */ +typedef Eina_Bool (*Ecore_Task_Cb)(void *data); + +/** + * @typedef Ecore_Select_Function + * A function which can be used to replace select() in the main loop + */ +typedef int (*Ecore_Select_Function)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); + +EAPI void ecore_main_loop_iterate(void); + +EAPI void ecore_main_loop_select_func_set(Ecore_Select_Function func); +EAPI Ecore_Select_Function ecore_main_loop_select_func_get(void); + +EAPI Eina_Bool ecore_main_loop_glib_integrate(void); +EAPI void ecore_main_loop_glib_always_integrate_disable(void); + +EAPI void ecore_main_loop_begin(void); +EAPI void ecore_main_loop_quit(void); + +/** + * @typedef Ecore_Cb Ecore_Cb + * A generic callback called as a hook when a certain point in + * execution is reached. + */ +typedef void (*Ecore_Cb)(void *data); + +/** + * @typedef Ecore_Data_Cb Ecore_Data_Cb + * A callback which is used to return data to the main function + */ +typedef void *(*Ecore_Data_Cb)(void *data); + +/** + * Add a function to be called by ecore_fork_reset() + * + * This queues @p func to be called (and passed @p data as its argument) when + * ecore_fork_reset() is called. This allows other libraries and subsystems + * to also reset their internal state after a fork. + * + * @since 1.7 + */ +EAPI Eina_Bool ecore_fork_reset_callback_add(Ecore_Cb func, const void *data); + +/** + * This removes the callback specified + * + * This deletes the callback added by ecore_fork_reset_callback_add() using + * the function and data pointer to specify which to remove. + * + * @since 1.7 + */ +EAPI Eina_Bool ecore_fork_reset_callback_del(Ecore_Cb func, const void *data); + +/** + * Reset the ecore internal state after a fork + * + * Ecore maintains internal data that can be affected by the fork() system call + * which creates a duplicate of the current process. This also duplicates + * file descriptors which is problematic in that these file descriptors still + * point to their original sources. This function makes ecore reset internal + * state (e.g. pipes used for signalling between threads) so they function + * correctly afterwards. + * + * It is highly suggested that you call this function after any fork() + * system call inside the child process if you intend to use ecore features + * after this point and not call any exec() family functions. Not doing so + * will cause possible misbehaviour. + * + * @since 1.7 + */ +EAPI void ecore_fork_reset(void); + +/** + * @brief Call callback asynchronously in the main loop. + * @since 1.1.0 + * + * @param callback The callback to call in the main loop + * @param data The data to give to that call back + * + * For all calls that need to happen in the main loop (most EFL functions do), + * this helper function provides the infrastructure needed to do it safely + * by avoiding dead lock, race condition and properly wake up the main loop. + * + * Remember after that function call, you should never touch again the @p data + * in the thread, it is owned by the main loop and your callback should take + * care of freeing it if necessary. + */ +EAPI void ecore_main_loop_thread_safe_call_async(Ecore_Cb callback, void *data); + +/** + * @brief Call callback synchronously in the main loop. + * @since 1.1.0 + * + * @param callback The callback to call in the main loop + * @param data The data to give to that call back + * @return the value returned by the callback in the main loop + * + * For all calls that need to happen in the main loop (most EFL functions do), + * this helper function provides the infrastructure needed to do it safely + * by avoiding dead lock, race condition and properly wake up the main loop. + * + * Remember this function will block until the callback is executed in the + * main loop. It can take time and you have no guaranty about the timeline. + */ +EAPI void *ecore_main_loop_thread_safe_call_sync(Ecore_Data_Cb callback, void *data); + +/** + * @brief This function suspend the main loop in a know state + * @since 1.1.0 + * + * @result the number of time ecore_thread_main_loop_begin() has been called + * in this thread, if the main loop was suspended correctly. If not, it return @c -1. + * + * This function suspend the main loop in a know state, this let you + * use any EFL call you want after it return. Be carefully, the main loop + * is blocked until you call ecore_thread_main_loop_end(). This is + * the only sane way to achieve pseudo thread safety. + * + * Notice that until the main loop is blocked, the thread is blocked + * and their is noway around that. + * + * We still advise you, when possible, to use ecore_main_loop_thread_safe_call_async() + * as it will not block the thread nor the main loop. + */ +EAPI int ecore_thread_main_loop_begin(void); + +/** + * @brief Unlock the main loop. + * @since 1.1.0 + * + * @result the number of time ecore_thread_main_loop_end() need to be called before + * the main loop is unlocked again. @c -1 will be returned if you are trying to unlock + * when there wasn't enough call to ecore_thread_main_loop_begin(). + * + * After a call to ecore_thread_main_loop_begin(), you need to absolutely + * call ecore_thread_main_loop_end(), or you application will stay frozen. + */ +EAPI int ecore_thread_main_loop_end(void); + +/** + * @} + */ + +/** + * @defgroup Ecore_Event_Group Ecore Event functions + * + * Ecore events provide two main features that are of use to those using ecore: + * creating events and being notified of events. Those two will usually be used + * in different contexts, creating events is mainly done by libraries wrapping + * some system functionality while being notified of events is mainly a + * necessity of applications. + * + * For a program to be notified of events it's interested in it needs to have a + * function to process the event and to register that function as the callback + * to the event, that's all: + * @code + * ecore_event_handler_add(EVENT_TYPE, _my_event_handler, some_data); + * ... + * static Eina_Bool + * _my_event_handler(void *data, int type, void *event) + * { + * //data is some_data + * //event is provided by whoever created the event + * //Do really cool stuff with event + * } + * @endcode + * + * One very important thing to note here is the @c EVENT_TYPE, to register a + * handler for an event you must know its type before hand. Ecore provides + * the following events which are emitted in response to POSIX + * signals(https://en.wikipedia.org/wiki/Signal_%28computing%29): + * @li @b ECORE_EVENT_SIGNAL_USER + * @li @b ECORE_EVENT_SIGNAL_HUP + * @li @b ECORE_EVENT_SIGNAL_POWER + * @li @b ECORE_EVENT_SIGNAL_EXIT + * + * @warning Don't override these using the @c signal or @c sigaction calls. + * These, however, aren't the only signals one can handle. Many + * libraries(including ecore modules) have their own signals that can be + * listened for and handled, to do that one only needs to know the type of the + * event. This information can be found on the documentation of the library + * emitting the signal, so, for example, for events related to windowing one + * would look in @ref Ecore_Evas_Group. + * + * Examples of libraries that integrate into ecore's main loop by providing + * events are @ref Ecore_Con_Group, @ref Ecore_Evas_Group and @ref + * Ecore_Exe_Group, amongst others. This usage can be divided into two parts, + * setup and adding events. The setup is very simple, all that needs doing is + * getting a type id for the event: + * @code + * int MY_EV_TYPE = ecore_event_type_new(); + * @endcode + * @note This variable should be declared in the header since it'll be needed by + * anyone wishing to register a handler to your event. + * + * The complexity of adding of an event to the queue depends on whether that + * event sends uses @c event, if it doesn't it a one-liner: + * @code + * ecore_event_add(MY_EV_TYPE, NULL, NULL, NULL); + * @endcode + * The usage when an @c event is needed is not that much more complex and can be + * seen in @ref ecore_event_add. + * + * Examples that deals with events: + * @li @ref ecore_event_example_01_c + * @li @ref ecore_event_example_02_c + * + * @ingroup Ecore_Main_Loop_Group + * + * @{ + */ + +#define ECORE_EVENT_NONE 0 +#define ECORE_EVENT_SIGNAL_USER 1 /**< User signal event */ +#define ECORE_EVENT_SIGNAL_HUP 2 /**< Hup signal event */ +#define ECORE_EVENT_SIGNAL_EXIT 3 /**< Exit signal event */ +#define ECORE_EVENT_SIGNAL_POWER 4 /**< Power signal event */ +#define ECORE_EVENT_SIGNAL_REALTIME 5 /**< Realtime signal event */ +#define ECORE_EVENT_COUNT 6 + +typedef struct _Ecore_Win32_Handler Ecore_Win32_Handler; /**< A handle for HANDLE handlers on Windows */ +typedef struct _Ecore_Event_Handler Ecore_Event_Handler; /**< A handle for an event handler */ +typedef struct _Ecore_Event_Filter Ecore_Event_Filter; /**< A handle for an event filter */ +typedef struct _Ecore_Event Ecore_Event; /**< A handle for an event */ +typedef struct _Ecore_Event_Signal_User Ecore_Event_Signal_User; /**< User signal event */ +typedef struct _Ecore_Event_Signal_Hup Ecore_Event_Signal_Hup; /**< Hup signal event */ +typedef struct _Ecore_Event_Signal_Exit Ecore_Event_Signal_Exit; /**< Exit signal event */ +typedef struct _Ecore_Event_Signal_Power Ecore_Event_Signal_Power; /**< Power signal event */ +typedef struct _Ecore_Event_Signal_Realtime Ecore_Event_Signal_Realtime; /**< Realtime signal event */ + +/** + * @typedef Ecore_Filter_Cb + * A callback used for filtering events from the main loop. + */ +typedef Eina_Bool (*Ecore_Filter_Cb)(void *data, void *loop_data, int type, void *event); + +/** + * @typedef Ecore_End_Cb Ecore_End_Cb + * This is the callback which is called at the end of a function, + * usually for cleanup purposes. + */ +typedef void (*Ecore_End_Cb)(void *user_data, void *func_data); + +/** + * @typedef Ecore_Event_Handler_Cb Ecore_Event_Handler_Cb + * A callback used by the main loop to handle events of a specified + * type. + */ +typedef Eina_Bool (*Ecore_Event_Handler_Cb)(void *data, int type, void *event); + +struct _Ecore_Event_Signal_User /** User signal event */ +{ + int number; /**< The signal number. Either 1 or 2 */ + void *ext_data; /**< Extension data - not used */ + +#if !defined (_WIN32) && !defined (__lv2ppu__) && !defined (EXOTIC_NO_SIGNAL) + siginfo_t data; /**< Signal info */ +#endif +}; + +struct _Ecore_Event_Signal_Hup /** Hup signal event */ +{ + void *ext_data; /**< Extension data - not used */ + +#if !defined (_WIN32) && !defined (__lv2ppu__) && !defined (EXOTIC_NO_SIGNAL) + siginfo_t data; /**< Signal info */ +#endif +}; + +struct _Ecore_Event_Signal_Exit /** Exit request event */ +{ + Eina_Bool interrupt : 1; /**< Set if the exit request was an interrupt signal*/ + Eina_Bool quit : 1; /**< set if the exit request was a quit signal */ + Eina_Bool terminate : 1; /**< Set if the exit request was a terminate signal */ + void *ext_data; /**< Extension data - not used */ + +#if !defined (_WIN32) && !defined (__lv2ppu__) && !defined (EXOTIC_NO_SIGNAL) + siginfo_t data; /**< Signal info */ +#endif +}; + +struct _Ecore_Event_Signal_Power /** Power event */ +{ + void *ext_data; /**< Extension data - not used */ + +#if !defined (_WIN32) && !defined (__lv2ppu__) && !defined (EXOTIC_NO_SIGNAL) + siginfo_t data; /**< Signal info */ +#endif +}; + +struct _Ecore_Event_Signal_Realtime /** Realtime event */ +{ + int num; /**< The realtime signal's number */ + +#if !defined (_WIN32) && !defined (__lv2ppu__) && !defined (EXOTIC_NO_SIGNAL) + siginfo_t data; /**< Signal info */ +#endif +}; + +/** + * @brief Add an event handler. + * @param type The type of the event this handler will get called for + * @param func The function to call when the event is found in the queue + * @param data A data pointer to pass to the called function @p func + * @return A new Event handler, or @c NULL on failure. + * + * Add an event handler to the list of handlers. This will, on success, return + * a handle to the event handler object that was created, that can be used + * later to remove the handler using ecore_event_handler_del(). The @p type + * parameter is the integer of the event type that will trigger this callback + * to be called. The callback @p func is called when this event is processed + * and will be passed the event type, a pointer to the private event + * structure that is specific to that event type, and a data pointer that is + * provided in this call as the @p data parameter. + * + * When the callback @p func is called, it must return 1 or 0. If it returns + * 1 (or ECORE_CALLBACK_PASS_ON), It will keep being called as per normal, for + * each handler set up for that event type. If it returns 0 (or + * ECORE_CALLBACK_DONE), it will cease processing handlers for that particular + * event, so all handler set to handle that event type that have not already + * been called, will not be. + */ +EAPI Ecore_Event_Handler *ecore_event_handler_add(int type, Ecore_Event_Handler_Cb func, const void *data); +/** + * @brief Delete an event handler. + * @param event_handler Event handler handle to delete + * @return Data passed to handler + * + * Delete a specified event handler from the handler list. On success this will + * delete the event handler and return the pointer passed as @p data when the + * handler was added by ecore_event_handler_add(). On failure @c NULL will be + * returned. Once a handler is deleted it will no longer be called. + */ +EAPI void *ecore_event_handler_del(Ecore_Event_Handler *event_handler); +/** + * @brief Add an event to the event queue. + * @param type The event type to add to the end of the event queue + * @param ev The data structure passed as @c event to event handlers + * @param func_free The function to be called to free @a ev + * @param data The data pointer to be passed to the free function + * @return A Handle for that event on success, otherwise NULL + * + * If it succeeds, an event of type @a type will be added to the queue for + * processing by event handlers added by ecore_event_handler_add(). The @a ev + * parameter will be passed as the @c event parameter of the handler. When the + * event is no longer needed, @a func_free will be called and passed @a ev for + * cleaning up. If @p func_free is NULL, free() will be called with the private + * structure pointer. + */ +EAPI Ecore_Event *ecore_event_add(int type, void *ev, Ecore_End_Cb func_free, void *data); +/** + * @brief Delete an event from the queue. + * @param event The event handle to delete + * @return The data pointer originally set for the event free function + * + * This deletes the event @p event from the event queue, and returns the + * @p data parameter originally set when adding it with ecore_event_add(). This + * does not immediately call the free function, and it may be called later on + * cleanup, and so if the free function depends on the data pointer to work, + * you should defer cleaning of this till the free function is called later. + */ +EAPI void *ecore_event_del(Ecore_Event *event); +/** + * @brief Get the data associated with an #Ecore_Event_Handler + * @param eh The event handler + * @return The data + * + * This function returns the data previously associated with @p eh by + * ecore_event_handler_add(). + */ +EAPI void *ecore_event_handler_data_get(Ecore_Event_Handler *eh); +/** + * @brief Set the data associated with an #Ecore_Event_Handler + * @param eh The event handler + * @param data The data to associate + * @return The previous data + * + * This function sets @p data to @p eh and returns the old data pointer + * which was previously associated with @p eh by ecore_event_handler_add(). + */ +EAPI void *ecore_event_handler_data_set(Ecore_Event_Handler *eh, const void *data); +/** + * @brief Allocate a new event type id sensibly and return the new id. + * @return A new event type id. + * + * This function allocates a new event type id and returns it. Once an event + * type has been allocated it can never be de-allocated during the life of + * the program. There is no guarantee of the contents of this event ID, or how + * it is calculated, except that the ID will be unique to the current instance + * of the process. + */ +EAPI int ecore_event_type_new(void); +/** + * @brief Add a filter the current event queue. + * + * @param func_start Function to call just before filtering and return data + * @param func_filter Function to call on each event + * @param func_end Function to call after the queue has been filtered + * @param data Data to pass to the filter functions + * @return A filter handle on success, @c NULL otherwise. + * + * Adds a callback to filter events from the event queue. Filters are called on + * the queue just before Event handler processing to try and remove redundant + * events. Just as processing is about to start @a func_start is called and + * passed the @a data pointer, the return value of this functions is passed to + * @a func_filter as loop_data. @a func_filter is also passed @a data and the + * event type and event structure. If this @a func_filter returns + * @c EINA_FALSE, the event is removed from the queue, if it returns + * @c EINA_TRUE, the event is kept. When processing is finished @p func_end is + * called and is passed the loop_data(returned by @c func_start) and @p data + * pointer to clean up. + */ +EAPI Ecore_Event_Filter *ecore_event_filter_add(Ecore_Data_Cb func_start, Ecore_Filter_Cb func_filter, Ecore_End_Cb func_end, const void *data); +/** + * @brief Delete an event filter. + * @param ef The event filter handle + * @return The data set for the filter on success, @c NULL otherwise. + * + * Delete a filter that has been added by its @p ef handle. + */ +EAPI void *ecore_event_filter_del(Ecore_Event_Filter *ef); +/** + * @brief Return the current event type being handled. + * @return The current event type being handled if inside a handler callback, + * ECORE_EVENT_NONE otherwise + * + * If the program is currently inside an Ecore event handler callback this + * will return the type of the current event being processed. + * + * This is useful when certain Ecore modules such as Ecore_Evas "swallow" + * events and not all the original information is passed on. In special cases + * this extra information may be useful or needed and using this call can let + * the program know if the event type being handled is one it wants to get more + * information about. + */ +EAPI int ecore_event_current_type_get(void); +/** + * @brief Return the current event type pointer handled. + * @return The current event pointer being handled if inside a handler callback, + * @c NULL otherwise. + * + * If the program is currently inside an Ecore event handler callback this + * will return the pointer of the current event being processed. + * + * This is useful when certain Ecore modules such as Ecore_Evas "swallow" + * events and not all the original information is passed on. In special cases + * this extra information may be useful or needed and using this call can let + * the program access the event data if the type of the event is handled by + * the program. + */ +EAPI void *ecore_event_current_event_get(void); + +/** + * @} + */ + +/** + * @defgroup Ecore_Exe_Group Process Spawning Functions + * + * This module is responsible for managing portable processes using Ecore. + * With this module you're able to spawn processes and you also can pause, + * quit your spawned processes. + * An interaction between your process and those spawned is possible + * using pipes or signals. + * + * Example + * @li @ref Ecore_exe_simple_example_c + * + * @ingroup Ecore_Main_Loop_Group + * + * @{ + */ + +/** Inherit priority from parent process */ +#define ECORE_EXE_PRIORITY_INHERIT 9999 + +EAPI extern int ECORE_EXE_EVENT_ADD; /**< A child process has been added */ +EAPI extern int ECORE_EXE_EVENT_DEL; /**< A child process has been deleted (it exited, naming consistent with the rest of ecore). */ +EAPI extern int ECORE_EXE_EVENT_DATA; /**< Data from a child process. */ +EAPI extern int ECORE_EXE_EVENT_ERROR; /**< Errors from a child process. */ + +/** + * @enum _Ecore_Exe_Flags + * Flags for executing a child with its stdin and/or stdout piped back. + */ +enum _Ecore_Exe_Flags /* flags for executing a child with its stdin and/or stdout piped back */ +{ + ECORE_EXE_NONE = 0, /**< No exe flags at all */ + ECORE_EXE_PIPE_READ = 1, /**< Exe Pipe Read mask */ + ECORE_EXE_PIPE_WRITE = 2, /**< Exe Pipe Write mask */ + ECORE_EXE_PIPE_ERROR = 4, /**< Exe Pipe error mask */ + ECORE_EXE_PIPE_READ_LINE_BUFFERED = 8, /**< Reads are buffered until a newline and split 1 line per Ecore_Exe_Event_Data_Line */ + ECORE_EXE_PIPE_ERROR_LINE_BUFFERED = 16, /**< Errors are buffered until a newline and split 1 line per Ecore_Exe_Event_Data_Line */ + ECORE_EXE_PIPE_AUTO = 32, /**< stdout and stderr are buffered automatically */ + ECORE_EXE_RESPAWN = 64, /**< FIXME: Exe is restarted if it dies */ + ECORE_EXE_USE_SH = 128, /**< Use /bin/sh to run the command. */ + ECORE_EXE_NOT_LEADER = 256, /**< Do not use setsid() to have the executed process be its own session leader */ + ECORE_EXE_TERM_WITH_PARENT = 512 /**< Makes child receive SIGTERM when parent dies. */ +}; +typedef enum _Ecore_Exe_Flags Ecore_Exe_Flags; + +/** + * @enum _Ecore_Exe_Win32_Priority + * Defines the priority of the proccess. + */ +enum _Ecore_Exe_Win32_Priority +{ + ECORE_EXE_WIN32_PRIORITY_IDLE, /**< Idle priority, for monitoring the system */ + ECORE_EXE_WIN32_PRIORITY_BELOW_NORMAL, /**< Below default priority */ + ECORE_EXE_WIN32_PRIORITY_NORMAL, /**< Default priority */ + ECORE_EXE_WIN32_PRIORITY_ABOVE_NORMAL, /**< Above default priority */ + ECORE_EXE_WIN32_PRIORITY_HIGH, /**< High priority, use with care as other threads in the system will not get processor time */ + ECORE_EXE_WIN32_PRIORITY_REALTIME /**< Realtime priority, should be almost never used as it can interrupt system threads that manage mouse input, keyboard input, and background disk flushing */ +}; +typedef enum _Ecore_Exe_Win32_Priority Ecore_Exe_Win32_Priority; + +typedef struct _Ecore_Exe Ecore_Exe; /**< A handle for spawned processes */ + +/** + * @typedef Ecore_Exe_Cb Ecore_Exe_Cb + * A callback to run with the associated @ref Ecore_Exe, usually + * for cleanup purposes. + */ +typedef void (*Ecore_Exe_Cb)(void *data, const Ecore_Exe *exe); + +typedef struct _Ecore_Exe_Event_Add Ecore_Exe_Event_Add; /**< Spawned Exe add event */ +typedef struct _Ecore_Exe_Event_Del Ecore_Exe_Event_Del; /**< Spawned Exe exit event */ +typedef struct _Ecore_Exe_Event_Data_Line Ecore_Exe_Event_Data_Line; /**< Lines from a child process */ +typedef struct _Ecore_Exe_Event_Data Ecore_Exe_Event_Data; /**< Data from a child process */ + +struct _Ecore_Exe_Event_Add /** Process add event */ +{ + Ecore_Exe *exe; /**< The handle to the added process */ + void *ext_data; /**< Extension data - not used */ +}; + +struct _Ecore_Exe_Event_Del /** Process exit event */ +{ + pid_t pid; /**< The process ID of the process that exited */ + int exit_code; /**< The exit code of the process */ + Ecore_Exe *exe; /**< The handle to the exited process, or @c NULL if not found */ + int exit_signal; /** < The signal that caused the process to exit */ + Eina_Bool exited : 1; /** < set to 1 if the process exited of its own accord */ + Eina_Bool signalled : 1; /** < set to 1 id the process exited due to uncaught signal */ + void *ext_data; /**< Extension data - not used */ +#if !defined (_WIN32) && !defined (__lv2ppu__) && !defined (EXOTIC_NO_SIGNAL) + siginfo_t data; /**< Signal info */ +#endif +}; + +struct _Ecore_Exe_Event_Data_Line /**< Lines from a child process */ +{ + char *line; /**< The bytes of a line of buffered data */ + int size; /**< The size of the line buffer in bytes */ +}; + +struct _Ecore_Exe_Event_Data /** Data from a child process event */ +{ + Ecore_Exe *exe; /**< The handle to the process */ + void *data; /**< the raw binary data from the child process that was received */ + int size; /**< the size of this data in bytes */ + Ecore_Exe_Event_Data_Line *lines; /**< an array of line data if line buffered, the last one has it's line member set to @c NULL */ +}; + +EAPI void ecore_exe_run_priority_set(int pri); +EAPI int ecore_exe_run_priority_get(void); +EAPI Ecore_Exe *ecore_exe_run(const char *exe_cmd, const void *data); +EAPI Ecore_Exe *ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data); +EAPI void ecore_exe_callback_pre_free_set(Ecore_Exe *exe, Ecore_Exe_Cb func); +EAPI Eina_Bool ecore_exe_send(Ecore_Exe *exe, const void *data, int size); +EAPI void ecore_exe_close_stdin(Ecore_Exe *exe); +EAPI void ecore_exe_auto_limits_set(Ecore_Exe *exe, int start_bytes, int end_bytes, int start_lines, int end_lines); +EAPI Ecore_Exe_Event_Data *ecore_exe_event_data_get(Ecore_Exe *exe, Ecore_Exe_Flags flags); +EAPI void ecore_exe_event_data_free(Ecore_Exe_Event_Data *data); +EAPI void *ecore_exe_free(Ecore_Exe *exe); +EAPI pid_t ecore_exe_pid_get(const Ecore_Exe *exe); +EAPI void ecore_exe_tag_set(Ecore_Exe *exe, const char *tag); +EAPI const char *ecore_exe_tag_get(const Ecore_Exe *exe); +EAPI const char *ecore_exe_cmd_get(const Ecore_Exe *exe); +EAPI void *ecore_exe_data_get(const Ecore_Exe *exe); +EAPI void *ecore_exe_data_set(Ecore_Exe *exe, void *data); +EAPI Ecore_Exe_Flags ecore_exe_flags_get(const Ecore_Exe *exe); +EAPI void ecore_exe_pause(Ecore_Exe *exe); +EAPI void ecore_exe_continue(Ecore_Exe *exe); +EAPI void ecore_exe_interrupt(Ecore_Exe *exe); +EAPI void ecore_exe_quit(Ecore_Exe *exe); +EAPI void ecore_exe_terminate(Ecore_Exe *exe); +EAPI void ecore_exe_kill(Ecore_Exe *exe); +EAPI void ecore_exe_signal(Ecore_Exe *exe, int num); +EAPI void ecore_exe_hup(Ecore_Exe *exe); + +/** + * @} + */ + +/** + * @defgroup Ecore_FD_Handler_Group File Descriptor Handling Functions + * + * @brief Functions that deal with file descriptor handlers. + * + * File descriptor handlers facilitate reading, writing and checking for errors + * without blocking the program or doing expensive pooling. This can be used to + * monitor a socket, pipe, or other stream for which an FD can be had. + * + * @warning File descriptor handlers can't be used to monitor for file creation, + * modification or deletion, see @ref Ecore_File_Group for this. + * + * One common FD to be monitored is the standard input(stdin), monitoring it for + * reading requires a single call: + * @code + * static Eina_Bool + * _my_cb_func(void *data, Ecore_Fd_Handler *handler) + * { + * char c; + * scanf("%c", &c); //Guaranteed not to block + * ... do stuff with c ... + * } + * ecore_main_fd_handler_add(STDIN_FILENO, ECORE_FD_READ, _my_cb_func, NULL, NULL, NULL); + * @endcode + * + * When using a socket, pipe or other stream it's important to remember that + * errors may occur and as such to monitor not only for reading/writing but also + * for errors using the @ref ECORE_FD_ERROR flag. + * + * Example of use of a file descriptor handler: + * @li @ref ecore_fd_handler_example_c + * + * @ingroup Ecore_Main_Loop_Group + * + * @{ + */ + +typedef struct _Ecore_Fd_Handler Ecore_Fd_Handler; /**< A handle for Fd handlers */ + +/** + * @enum _Ecore_Fd_Handler_Flags + * What to monitor the file descriptor for: reading, writing or error. + */ +enum _Ecore_Fd_Handler_Flags +{ + ECORE_FD_READ = 1, /**< Fd Read mask */ + ECORE_FD_WRITE = 2, /**< Fd Write mask */ + ECORE_FD_ERROR = 4 /**< Fd Error mask */ +}; +typedef enum _Ecore_Fd_Handler_Flags Ecore_Fd_Handler_Flags; + +/** + * @typedef Ecore_Fd_Cb Ecore_Fd_Cb + * A callback used by an @ref Ecore_Fd_Handler. + */ +typedef Eina_Bool (*Ecore_Fd_Cb)(void *data, Ecore_Fd_Handler *fd_handler); + +/** + * @typedef Ecore_Fd_Prep_Cb Ecore_Fd_Prep_Cb + * A callback used by an @ref Ecore_Fd_Handler. + */ +typedef void (*Ecore_Fd_Prep_Cb)(void *data, Ecore_Fd_Handler *fd_handler); + +/** + * @typedef Ecore_Win32_Handle_Cb Ecore_Win32_Handle_Cb + * A callback used by an @ref Ecore_Win32_Handler. + */ +typedef Eina_Bool (*Ecore_Win32_Handle_Cb)(void *data, Ecore_Win32_Handler *wh); + +/** + * @brief Adds a callback for activity on the given file descriptor. + * + * @param fd The file descriptor to watch. + * @param flags To monitor it for reading use @c ECORE_FD_READ, for writing @c + * ECORE_FD_WRITE, and for error @c ECORE_FD_ERROR. Values by |(ored). + * @param func The callback function. + * @param data The data to pass to the callback. + * @param buf_func The function to call to check if any data has been buffered + * and already read from the fd. May be @c NULL. + * @param buf_data The data to pass to the @p buf_func function. + * @return A fd handler handle on success, @c NULL otherwise. + * + * @a func will be called during the execution of @ref Ecore_Main_Loop_Page + * when the file descriptor is available for reading, writing, or there has been + * an error(depending on the given @a flags). + * + * When @a func returns ECORE_CALLBACK_CANCEL, it indicates that the + * handler should be marked for deletion (identical to calling @ref + * ecore_main_fd_handler_del). + * + * @warning @a buf_func is meant for @b internal use only and should be @b + * avoided. + * + * The return value of @a buf_func has a different meaning, when it returns + * ECORE_CALLBACK_CANCEL, it indicates that @a func @b shouldn't be called, and + * when it returns ECORE_CALLBACK_RENEW it indicates @a func should be called. + * The return value of @a buf_func will not cause the FD handler to be deleted. + * + * @a buf_func is called during event loop handling to check if data that has + * been read from the file descriptor is in a buffer and is available to read. + * Some systems, notably xlib, handle their own buffering, and would otherwise + * not work with select(). These systems should use a @a buf_func. This is a + * most annoying hack, only ecore_x uses it, so refer to that for an example. + * + * @warning This function should @b not be used for monitoring "normal" files, like text files. + * + */ +EAPI Ecore_Fd_Handler *ecore_main_fd_handler_add(int fd, Ecore_Fd_Handler_Flags flags, Ecore_Fd_Cb func, const void *data, Ecore_Fd_Cb buf_func, const void *buf_data); + +/** + * @brief Adds a callback for activity on the given file descriptor. + * + * @param fd The file descriptor to watch. + * @param flags To monitor it for reading use @c ECORE_FD_READ, for writing @c + * ECORE_FD_WRITE, and for error @c ECORE_FD_ERROR. Values by |(ored). + * @param func The callback function. + * @param data The data to pass to the callback. + * @param buf_func The function to call to check if any data has been buffered + * and already read from the fd. May be @c NULL. + * @param buf_data The data to pass to the @p buf_func function. + * @return A fd handler handle on success, @c NULL otherwise. + * + * This function is identical to ecore_main_fd_handler_add, except that it supports regular files. + * @warning This function should ONLY be called with ECORE_FD_ERROR, otherwise it will call the fd + * handler constantly. + * @warning Do not use this function unless you know what you are doing. + * + * @since 1.7 + */ +EAPI Ecore_Fd_Handler *ecore_main_fd_handler_file_add(int fd, Ecore_Fd_Handler_Flags flags, Ecore_Fd_Cb func, const void *data, Ecore_Fd_Cb buf_func, const void *buf_data); + +/** + * @brief Set the prepare callback with data for a given #Ecore_Fd_Handler + * + * @param fd_handler The fd handler + * @param func The prep function + * @param data The data to pass to the prep function + * + * This function will be called prior to any fd handler's callback function + * (even the other fd handlers), before entering the main loop select function. + * + * @note Once a prepare callback is set for a fd handler, it cannot be changed. + * You need to delete the fd handler and create a new one, to set another + * callback. + * @note You probably don't need this function. It is only necessary for very + * uncommon cases that need special behavior. + */ +EAPI void ecore_main_fd_handler_prepare_callback_set(Ecore_Fd_Handler *fd_handler, Ecore_Fd_Prep_Cb func, const void *data); +/** + * @brief Marks an FD handler for deletion. + * @param fd_handler The FD handler. + * @return The data pointer set using @ref ecore_main_fd_handler_add, for + * @a fd_handler on success, @c NULL otherwise. + * This function marks an fd handler to be deleted during an iteration of the + * main loop. It does NOT close the associated fd! + * + * @warning If the underlying fd is already closed ecore may complain if the + * main loop is using epoll internally, and also in some rare cases this may + * cause crashes and instability. Remember to delete your fd handlers before the + * fds they listen to are closed. + */ +EAPI void *ecore_main_fd_handler_del(Ecore_Fd_Handler *fd_handler); +/** + * @brief Retrieves the file descriptor that the given handler is handling. + * @param fd_handler The given FD handler. + * @return The file descriptor the handler is watching. + */ +EAPI int ecore_main_fd_handler_fd_get(Ecore_Fd_Handler *fd_handler); +/** + * @brief Gets which flags are active on an FD handler. + * @param fd_handler The given FD handler. + * @param flags The flags, @c ECORE_FD_READ, @c ECORE_FD_WRITE or + * @c ECORE_FD_ERROR to query. + * @return @c EINA_TRUE if any of the given flags are active, @c EINA_FALSE + * otherwise. + */ +EAPI Eina_Bool ecore_main_fd_handler_active_get(Ecore_Fd_Handler *fd_handler, Ecore_Fd_Handler_Flags flags); +/** + * @brief Set what active streams the given FD handler should be monitoring. + * @param fd_handler The given FD handler. + * @param flags The flags to be watching. + */ +EAPI void ecore_main_fd_handler_active_set(Ecore_Fd_Handler *fd_handler, Ecore_Fd_Handler_Flags flags); + +EAPI Ecore_Win32_Handler *ecore_main_win32_handler_add(void *h, Ecore_Win32_Handle_Cb func, const void *data); +EAPI void *ecore_main_win32_handler_del(Ecore_Win32_Handler *win32_handler); + +/** + * @} + */ + +/** + * @defgroup Ecore_Poller_Group Ecore Poll functions + * + * Ecore poller provides infrastructure for the creation of pollers. Pollers + * are, in essence, callbacks that share a single timer per type. Because not + * all pollers need to be called at the same frequency the user may specify the + * frequency in ticks(each expiration of the shared timer is called a tick, in + * ecore poller parlance) for each added poller. Ecore pollers should only be + * used when the poller doesn't have specific requirements on the exact times + * to poll. + * + * This architecture means that the main loop is only woken up once to handle + * all pollers of that type, this will save power as the CPU has more of a + * chance to go into a low power state the longer it is asleep for, so this + * should be used in situations where power usage is a concern. + * + * For now only 1 core poller type is supported: ECORE_POLLER_CORE, the default + * interval for ECORE_POLLER_CORE is 0.125(or 1/8th) second. + * + * The creation of a poller is extremely simple and only requires one line: + * @code + * ecore_poller_add(ECORE_POLLER_CORE, 1, my_poller_function, NULL); + * @endcode + * This sample creates a poller to call @c my_poller_function at every tick with + * @c NULL as data. + * + * Example: + * @li @ref ecore_poller_example_c + * + * @ingroup Ecore_Main_Loop_Group + * + * @{ + */ + +/** + * @enum _Ecore_Poller_Type + * Defines the frequency of ticks for the poller. + */ +enum _Ecore_Poller_Type /* Poller types */ +{ + ECORE_POLLER_CORE = 0 /**< The core poller interval */ +}; +typedef enum _Ecore_Poller_Type Ecore_Poller_Type; + +typedef struct _Ecore_Poller Ecore_Poller; /**< A handle for pollers */ + +/** + * @brief Sets the time(in seconds) between ticks for the given poller type. + * @param type The poller type to adjust. + * @param poll_time The time(in seconds) between ticks of the timer. + * + * This will adjust the time between ticks of the given timer type defined by + * @p type to the time period defined by @p poll_time. + */ +EAPI void ecore_poller_poll_interval_set(Ecore_Poller_Type type, double poll_time); +/** + * @brief Gets the time(in seconds) between ticks for the given poller type. + * @param type The poller type to query. + * @return The time in seconds between ticks of the poller timer. + * + * This will get the time between ticks of the specified poller timer. + */ +EAPI double ecore_poller_poll_interval_get(Ecore_Poller_Type type); +/** + * @brief Changes the polling interval rate of @p poller. + * @param poller The Ecore_Poller to change the interval of. + * @param interval The tick interval to set; must be a power of 2 and <= 32768. + * @return Returns true on success, false on failure. + * + * This allows the changing of a poller's polling interval. It is useful when + * you want to alter a poll rate without deleting and re-creating a poller. + */ +EAPI Eina_Bool ecore_poller_poller_interval_set(Ecore_Poller *poller, int interval); +/** + * @brief Gets the polling interval rate of @p poller. + * @param poller The Ecore_Poller to change the interval of. + * @return Returns the interval, in ticks, that @p poller polls at. + * + * This returns a poller's polling interval, or 0 on error. + */ +EAPI int ecore_poller_poller_interval_get(Ecore_Poller *poller); +/** + * @brief Creates a poller to call the given function at a particular tick interval. + * @param type The ticker type to attach the poller to. Must be ECORE_POLLER_CORE. + * @param interval The poll interval. + * @param func The poller function. + * @param data Data to pass to @a func when it is called. + * @return A poller object on success, @c NULL otherwise. + * + * This function adds @a func as a poller callback that will be called every @a + * interval ticks together with other pollers of type @a type. @a func will be + * passed the @p data pointer as a parameter. + * + * The @p interval must be between 1 and 32768 inclusive, and must be a power of + * 2 (i.e. 1, 2, 4, 8, 16, ... 16384, 32768). The exact tick in which @a func + * will be called is undefined, as only the interval between calls can be + * defined. Ecore will endeavor to keep pollers synchronized and to call as + * many in 1 wakeup event as possible. If @a interval is not a power of two, the + * closest power of 2 greater than @a interval will be used. + * + * When the poller @p func is called, it must return a value of either + * ECORE_CALLBACK_RENEW(or 1) or ECORE_CALLBACK_CANCEL(or 0). If it + * returns 1, it will be called again at the next tick, or if it returns + * 0 it will be deleted automatically making any references/handles for it + * invalid. + */ +EAPI Ecore_Poller *ecore_poller_add(Ecore_Poller_Type type, int interval, Ecore_Task_Cb func, const void *data); +/** + * @brief Delete the specified poller from the timer list. + * @param poller The poller to delete. + * @return The data pointer set for the timer when @ref ecore_poller_add was + * called on success, @c NULL otherwise. + * + * @note @a poller must be a valid handle. If the poller function has already + * returned 0, the handle is no longer valid (and does not need to be deleted). + */ +EAPI void *ecore_poller_del(Ecore_Poller *poller); + +/** + * @} + */ + +/** + * @defgroup Ecore_Animator_Group Ecore Animator functions + * + * @brief Ecore animators are a helper to simplify creating + * animations. + * + * Creating an animation is as simple as saying for how long it + * should be run and having a callback that does the animation, + * something like this: + * @code + * static Eina_Bool + * _do_animation(void *data, double pos) + * { + * evas_object_move(data, 100 * pos, 100 * pos); + * ... do some more animating ... + * } + * ... + *ecore_animator_timeline_add(2, _do_animation, my_evas_object); + * @endcode + * In the sample above we create an animation to move + * @c my_evas_object from position (0,0) to (100,100) in 2 seconds. + * + * If your animation will run for an unspecified amount of time you + * can use ecore_animator_add(), which is like using + *ecore_timer_add() with the interval being the + * @ref ecore_animator_frametime_set "framerate". Note that this has + * tangible benefits to creating a timer for each animation in terms + * of performance. + * + * For a more detailed example that show several animation see + * @ref tutorial_ecore_animator. + * + * @ingroup Ecore_Main_Loop_Group + * + * @{ + */ + +typedef struct _Ecore_Animator Ecore_Animator; /**< A handle for animators */ + +/** + * @enum _Ecore_Pos_Map + * Defines the position mappings for the animation. + */ +enum _Ecore_Pos_Map /* Position mappings */ +{ + ECORE_POS_MAP_LINEAR, /**< Linear 0.0 -> 1.0 */ + ECORE_POS_MAP_ACCELERATE, /**< Start slow then speed up */ + ECORE_POS_MAP_DECELERATE, /**< Start fast then slow down */ + ECORE_POS_MAP_SINUSOIDAL, /**< Start slow, speed up then slow down at end */ + ECORE_POS_MAP_ACCELERATE_FACTOR, /**< Start slow then speed up, v1 being a power factor, 0.0 being linear, 1.0 being normal accelerate, 2.0 being much more pronounced accelerate (squared), 3.0 being cubed, etc. */ + ECORE_POS_MAP_DECELERATE_FACTOR, /**< Start fast then slow down, v1 being a power factor, 0.0 being linear, 1.0 being normal decelerate, 2.0 being much more pronounced decelerate (squared), 3.0 being cubed, etc. */ + ECORE_POS_MAP_SINUSOIDAL_FACTOR, /**< Start slow, speed up then slow down at end, v1 being a power factor, 0.0 being linear, 1.0 being normal sinusoidal, 2.0 being much more pronounced sinusoidal (squared), 3.0 being cubed, etc. */ + ECORE_POS_MAP_DIVISOR_INTERP, /**< Start at gradient * v1, interpolated via power of v2 curve */ + ECORE_POS_MAP_BOUNCE, /**< Start at 0.0 then "drop" like a ball bouncing to the ground at 1.0, and bounce v2 times, with decay factor of v1 */ + ECORE_POS_MAP_SPRING /**< Start at 0.0 then "wobble" like a spring rest position 1.0, and wobble v2 times, with decay factor of v1 */ +}; +typedef enum _Ecore_Pos_Map Ecore_Pos_Map; + +/** + * @enum _Ecore_Animator_Source + * Defines the timing sources for animators. + */ +enum _Ecore_Animator_Source /* Timing sources for animators */ +{ + ECORE_ANIMATOR_SOURCE_TIMER, /**< The default system clock/timer based animator that ticks every "frametime" seconds */ + ECORE_ANIMATOR_SOURCE_CUSTOM /**< A custom animator trigger that you need to call ecore_animator_trigger() to make it tick */ +}; +typedef enum _Ecore_Animator_Source Ecore_Animator_Source; + +/** + * @typedef Ecore_Timeline_Cb Ecore_Timeline_Cb + * A callback run for a task (animators with runtimes) + */ +typedef Eina_Bool (*Ecore_Timeline_Cb)(void *data, double pos); + +/** + * @brief Add an animator to call @p func at every animation tick during main + * loop execution. + * + * @param func The function to call when it ticks off + * @param data The data to pass to the function + * @return A handle to the new animator + * + * This function adds a animator and returns its handle on success and @c NULL + * on failure. The function @p func will be called every N seconds where N is + * the @p frametime interval set by ecore_animator_frametime_set(). The + * function will be passed the @p data pointer as its parameter. + * + * When the animator @p func is called, it must return a value of either 1 or + * 0. If it returns 1 (or ECORE_CALLBACK_RENEW), it will be called again at + * the next tick, or if it returns 0 (or ECORE_CALLBACK_CANCEL) it will be + * deleted automatically making any references/handles for it invalid. + * + * @note The default @p frametime value is 1/30th of a second. + * + * @see ecore_animator_timeline_add() + * @see ecore_animator_frametime_set() + */ +EAPI Ecore_Animator *ecore_animator_add(Ecore_Task_Cb func, const void *data); +/** + * @brief Add a animator that runs for a limited time + * + * @param runtime The time to run in seconds + * @param func The function to call when it ticks off + * @param data The data to pass to the function + * @return A handle to the new animator + * + * This function is just like ecore_animator_add() except the animator only + * runs for a limited time specified in seconds by @p runtime. Once the + * runtime the animator has elapsed (animator finished) it will automatically + * be deleted. The callback function @p func can return ECORE_CALLBACK_RENEW + * to keep the animator running or ECORE_CALLBACK_CANCEL ro stop it and have + * it be deleted automatically at any time. + * + * The @p func will ALSO be passed a position parameter that will be in value + * from 0.0 to 1.0 to indicate where along the timeline (0.0 start, 1.0 end) + * the animator run is at. If the callback wishes not to have a linear + * transition it can "map" this value to one of several curves and mappings + * via ecore_animator_pos_map(). + * + * @note The default @p frametime value is 1/30th of a second. + * + * @see ecore_animator_add() + * @see ecore_animator_pos_map() + * @since 1.1.0 + */ +EAPI Ecore_Animator *ecore_animator_timeline_add(double runtime, Ecore_Timeline_Cb func, const void *data); +/** + * @brief Delete the specified animator from the animator list. + * + * @param animator The animator to delete + * @return The data pointer set for the animator on add + * + * Delete the specified @p animator from the set of animators that are + * executed during main loop execution. This function returns the data + * parameter that was being passed to the callback on success, or @c NULL on + * failure. After this call returns the specified animator object @p animator + * is invalid and should not be used again. It will not get called again after + * deletion. + */ +EAPI void *ecore_animator_del(Ecore_Animator *animator); +/** + * @brief Suspend the specified animator. + * + * @param animator The animator to delete + * + * The specified @p animator will be temporarily removed from the set of + * animators that are executed during main loop. + * + * @warning Freezing an animator doesn't freeze accounting of how long that + * animator has been running. Therefore if the animator was created with + *ecore_animator_timeline_add() the @p pos argument given to the callback + * will increase as if the animator hadn't been frozen and the animator may + * have it's execution halted if @p runtime elapsed. + */ +EAPI void ecore_animator_freeze(Ecore_Animator *animator); +/** + * @brief Restore execution of the specified animator. + * + * @param animator The animator to delete + * + * The specified @p animator will be put back in the set of animators that are + * executed during main loop. + */ +EAPI void ecore_animator_thaw(Ecore_Animator *animator); +/** + * @brief Set the animator call interval in seconds. + * + * @param frametime The time in seconds in between animator ticks. + * + * This function sets the time interval (in seconds) between animator ticks. + * At every tick the callback of every existing animator will be called. + * + * @warning Too small a value may cause performance issues and too high a + * value may cause your animation to seem "jerky". + * + * @note The default @p frametime value is 1/30th of a second. + */ +EAPI void ecore_animator_frametime_set(double frametime); +/** + * @brief Get the animator call interval in seconds. + * + * @return The time in second in between animator ticks. + * + * This function retrieves the time in seconds between animator ticks. + * + * @see ecore_animator_frametime_set() + */ +EAPI double ecore_animator_frametime_get(void); +/** + * @brief Maps an input position from 0.0 to 1.0 along a timeline to a + * position in a different curve. + * + * @param pos The input position to map + * @param map The mapping to use + * @param v1 A parameter use by the mapping (pass 0.0 if not used) + * @param v2 A parameter use by the mapping (pass 0.0 if not used) + * @return The mapped value + * + * Takes an input position (0.0 to 1.0) and maps to a new position (normally + * between 0.0 and 1.0, but it may go above/below 0.0 or 1.0 to show that it + * has "overshot" the mark) using some interpolation (mapping) algorithm. + * + * This function useful to create non-linear animations. It offers a variety + * of possible animation curves to be used: + * @li ECORE_POS_MAP_LINEAR - Linear, returns @p pos + * @li ECORE_POS_MAP_ACCELERATE - Start slow then speed up + * @li ECORE_POS_MAP_DECELERATE - Start fast then slow down + * @li ECORE_POS_MAP_SINUSOIDAL - Start slow, speed up then slow down at end + * @li ECORE_POS_MAP_ACCELERATE_FACTOR - Start slow then speed up, v1 being a + * power factor, 0.0 being linear, 1.0 being ECORE_POS_MAP_ACCELERATE, 2.0 + * being much more pronounced accelerate (squared), 3.0 being cubed, etc. + * @li ECORE_POS_MAP_DECELERATE_FACTOR - Start fast then slow down, v1 being a + * power factor, 0.0 being linear, 1.0 being ECORE_POS_MAP_DECELERATE, 2.0 + * being much more pronounced decelerate (squared), 3.0 being cubed, etc. + * @li ECORE_POS_MAP_SINUSOIDAL_FACTOR - Start slow, speed up then slow down + * at end, v1 being a power factor, 0.0 being linear, 1.0 being + * ECORE_POS_MAP_SINUSOIDAL, 2.0 being much more pronounced sinusoidal + * (squared), 3.0 being cubed, etc. + * @li ECORE_POS_MAP_DIVISOR_INTERP - Start at gradient * v1, interpolated via + * power of v2 curve + * @li ECORE_POS_MAP_BOUNCE - Start at 0.0 then "drop" like a ball bouncing to + * the ground at 1.0, and bounce v2 times, with decay factor of v1 + * @li ECORE_POS_MAP_SPRING - Start at 0.0 then "wobble" like a spring rest + * position 1.0, and wobble v2 times, with decay factor of v1 + * @note When not listed v1 and v2 have no effect. + * + * @image html ecore-pos-map.png + * @image latex ecore-pos-map.eps width=\textwidth + * + * One way to use this would be: + * @code + * double pos; // input position in a timeline from 0.0 to 1.0 + * double out; // output position after mapping + * int x1, y1, x2, y2; // x1 & y1 are start position, x2 & y2 are end position + * int x, y; // x & y are the calculated position + * + * out = ecore_animator_pos_map(pos, ECORE_POS_MAP_BOUNCE, 1.8, 7); + * x = (x1 * out) + (x2 * (1.0 - out)); + * y = (y1 * out) + (y2 * (1.0 - out)); + * move_my_object_to(myobject, x, y); + * @endcode + * This will make an animation that bounces 7 each times diminishing by a + * factor of 1.8. + * + * @see _Ecore_Pos_Map + * + * @since 1.1.0 + */ +EAPI double ecore_animator_pos_map(double pos, Ecore_Pos_Map map, double v1, double v2); +/** + * @brief Set the source of animator ticks for the mainloop + * + * @param source The source of animator ticks to use + * + * This sets the source of animator ticks. When an animator is active the + * mainloop will "tick" over frame by frame calling all animators that are + * registered until none are. The mainloop will tick at a given rate based + * on the animator source. The default source is the system clock timer + * source - ECORE_ANIMATOR_SOURCE_TIMER. This source uses the system clock + * to tick over every N seconds (specified by ecore_animator_frametime_set(), + * with the default being 1/30th of a second unless set otherwise). You can + * set a custom tick source by setting the source to + * ECORE_ANIMATOR_SOURCE_CUSTOM and then drive it yourself based on some input + * tick source (like another application via ipc, some vertical blanking + * interrupt interrupt etc.) using + *ecore_animator_custom_source_tick_begin_callback_set() and + *ecore_animator_custom_source_tick_end_callback_set() to set the functions + * that will be called to start and stop the ticking source, which when it + * gets a "tick" should call ecore_animator_custom_tick() to make the "tick" over 1 + * frame. + */ +EAPI void ecore_animator_source_set(Ecore_Animator_Source source); +/** + * @brief Get the animator source currently set. + * + * @return The current animator source + * + * This gets the current animator source. + * + * @see ecore_animator_source_set() + */ +EAPI Ecore_Animator_Source ecore_animator_source_get(void); +/** + * @brief Set the function that begins a custom animator tick source + * + * @param func The function to call when ticking is to begin + * @param data The data passed to the tick begin function as its parameter + * + * The Ecore Animator infrastructure handles tracking if animators are needed + * or not and which ones need to be called and when, but when the tick source + * is custom, you have to provide a tick source by calling + *ecore_animator_custom_tick() to indicate a frame tick happened. In order + * to allow the source of ticks to be dynamically enabled or disabled as + * needed, the @p func when set is called to enable the tick source to + * produce tick events that call ecore_animator_custom_tick(). If @p func + * is @c NULL then no function is called to begin custom ticking. + * + * @see ecore_animator_source_set() + * @see ecore_animator_custom_source_tick_end_callback_set() + * @see ecore_animator_custom_tick() + */ +EAPI void ecore_animator_custom_source_tick_begin_callback_set(Ecore_Cb func, const void *data); +/** + * @brief Set the function that ends a custom animator tick source + * + * @param func The function to call when ticking is to end + * @param data The data passed to the tick end function as its parameter + * + * This function is a matching pair to the function set by + * ecore_animator_custom_source_tick_begin_callback_set() and is called + * when ticking is to stop. If @p func is @c NULL then no function will be + * called to stop ticking. For more information please see + * ecore_animator_custom_source_tick_begin_callback_set(). + * + * @see ecore_animator_source_set() + * @see ecore_animator_custom_source_tick_begin_callback_set() + * @see ecore_animator_custom_tick() + */ +EAPI void ecore_animator_custom_source_tick_end_callback_set(Ecore_Cb func, const void *data); +/** + * @brief Trigger a custom animator tick + * + * When animator source is set to ECORE_ANIMATOR_SOURCE_CUSTOM, then calling + * this function triggers a run of all animators currently registered with + * Ecore as this indicates a "frame tick" happened. This will do nothing if + * the animator source(set by ecore_animator_source_set()) is not set to + * ECORE_ANIMATOR_SOURCE_CUSTOM. + * + * @see ecore_animator_source_set() + * @see ecore_animator_custom_source_tick_begin_callback_set + * @see ecore_animator_custom_source_tick_end_callback_set()() + */ +EAPI void ecore_animator_custom_tick(void); + +/** + * @} + */ + +/** + * @defgroup Ecore_Time_Group Ecore time functions + * + * These are function to retrieve time in a given format. + * + * Examples: + * @li @ref ecore_time_functions_example_c + * @{ + */ +EAPI double ecore_time_get(void); +EAPI double ecore_time_unix_get(void); +EAPI double ecore_loop_time_get(void); + +/** + * @} + */ + +/** + * @defgroup Ecore_Timer_Group Ecore Timer functions + * + * Ecore provides very flexible timer functionality. The basic usage of timers, + * to call a certain function at a certain interval can be achieved with a + * single line: + * @code + * Eina_Bool my_func(void *data) { + * do_funky_stuff_with_data(data); + * return EINA_TRUE; + * } + * ecore_timer_add(interval_in_seconds, my_func, data_given_to_function); + * @endcode + * @note If the function was to be executed only once simply return + * @c EINA_FALSE instead. + * + * An example that shows the usage of a lot of these: + * @li @ref ecore_timer_example_c + * + * @ingroup Ecore_Main_Loop_Group + * + * @{ + */ + +typedef struct _Ecore_Timer Ecore_Timer; /**< A handle for timers */ + +EAPI Ecore_Timer *ecore_timer_add(double in, Ecore_Task_Cb func, const void *data); +EAPI Ecore_Timer *ecore_timer_loop_add(double in, Ecore_Task_Cb func, const void *data); +EAPI void *ecore_timer_del(Ecore_Timer *timer); +EAPI void ecore_timer_interval_set(Ecore_Timer *timer, double in); +EAPI double ecore_timer_interval_get(Ecore_Timer *timer); +EAPI void ecore_timer_freeze(Ecore_Timer *timer); +EAPI void ecore_timer_thaw(Ecore_Timer *timer); +EAPI void ecore_timer_delay(Ecore_Timer *timer, double add); +EAPI void ecore_timer_reset(Ecore_Timer *timer); +EAPI double ecore_timer_pending_get(Ecore_Timer *timer); +EAPI double ecore_timer_precision_get(void); +EAPI void ecore_timer_precision_set(double precision); +EAPI char *ecore_timer_dump(void); + +/** + * @} + */ + +/** + * @defgroup Ecore_Idle_Group Ecore Idle functions + * + * The idler functionality in Ecore allows for callbacks to be called when the + * program isn't handling @ref Ecore_Event_Group "events", @ref Ecore_Timer_Group + * "timers" or @ref Ecore_FD_Handler_Group "fd handlers". + * + * There are three types of idlers: Enterers, Idlers(proper) and Exiters. They + * are called, respectively, when the program is about to enter an idle state, + * when the program is in an idle state and when the program has just left an + * idle state and will begin processing @ref Ecore_Event_Group "events", @ref + * Ecore_Timer_Group "timers" or @ref Ecore_FD_Handler_Group "fd handlers". + * + * Enterer callbacks are good for updating your program's state, if + * it has a state engine. Once all of the enterer handlers are + * called, the program will enter a "sleeping" state. + * + * Idler callbacks are called when the main loop has called all + * enterer handlers. They are useful for interfaces that require + * polling and timers would be too slow to use. + * + * Exiter callbacks are called when the main loop wakes up from an idle state. + * + * If no idler callbacks are specified, then the process literally + * goes to sleep. Otherwise, the idler callbacks are called + * continuously while the loop is "idle", using as much CPU as is + * available to the process. + * + * @note Idle state doesn't mean that the @b program is idle, but + * that the main loop is idle. It doesn't have any timers, + * events, fd handlers or anything else to process (which in most + * event driven programs also means that the @b program is + * idle too, but it's not a rule). The program itself may be doing + * a lot of processing in the idler, or in another thread, for + * example. + * + * Example with functions that deal with idle state: + * + * @li @ref ecore_idler_example_c + * + * @ingroup Ecore_Main_Loop_Group + * + * @{ + */ + +typedef struct _Ecore_Idler Ecore_Idler; /**< A handle for idlers */ +typedef struct _Ecore_Idle_Enterer Ecore_Idle_Enterer; /**< A handle for idle enterers */ +typedef struct _Ecore_Idle_Exiter Ecore_Idle_Exiter; /**< A handle for idle exiters */ + +/** + * Add an idler handler. + * @param func The function to call when idling. + * @param data The data to be passed to this @p func call. + * @return A idler handle if successfully added, @c NULL otherwise. + * + * Add an idler handle to the event loop, returning a handle on + * success and @c NULL otherwise. The function @p func will be called + * repeatedly while no other events are ready to be processed, as + * long as it returns @c 1 (or ECORE_CALLBACK_RENEW). A return of @c 0 + * (or ECORE_CALLBACK_CANCEL) deletes the idler. + * + * Idlers are useful for progressively prossessing data without blocking. + */ +EAPI Ecore_Idler *ecore_idler_add(Ecore_Task_Cb func, const void *data); + +/** + * Delete an idler callback from the list to be executed. + * @param idler The handle of the idler callback to delete + * @return The data pointer passed to the idler callback on success, @c NULL + * otherwise. + */ +EAPI void *ecore_idler_del(Ecore_Idler *idler); + +EAPI Ecore_Idle_Enterer *ecore_idle_enterer_add(Ecore_Task_Cb func, const void *data); +EAPI Ecore_Idle_Enterer *ecore_idle_enterer_before_add(Ecore_Task_Cb func, const void *data); +EAPI void *ecore_idle_enterer_del(Ecore_Idle_Enterer *idle_enterer); + +EAPI Ecore_Idle_Exiter *ecore_idle_exiter_add(Ecore_Task_Cb func, const void *data); +EAPI void *ecore_idle_exiter_del(Ecore_Idle_Exiter *idle_exiter); + +/** + * @} + */ + +/** + * @defgroup Ecore_Thread_Group Ecore Thread functions + * + * Facilities to run heavy tasks in different threads to avoid blocking + * the main loop. + * + * The EFL is, for the most part, not thread safe. This means that if you + * have some task running in another thread and you have, for example, an + * Evas object to show the status progress of this task, you cannot update + * the object from within the thread. This can only be done from the main + * thread, the one running the main loop. This problem can be solved + * by running a thread that sends messages to the main one using an + * @ref Ecore_Pipe_Group "Ecore_Pipe", but when you need to handle other + * things like cancelling the thread, your code grows in complexity and gets + * much harder to maintain. + * + * Ecore Thread is here to solve that problem. It is @b not a simple wrapper + * around standard POSIX threads (or the equivalent in other systems) and + * it's not meant to be used to run parallel tasks throughout the entire + * duration of the program, especially when these tasks are performance + * critical, as Ecore manages these tasks using a pool of threads based on + * system configuration. + * + * What Ecore Thread does, is make it a lot easier to dispatch a worker + * function to perform some heavy task and then get the result once it + * completes, without blocking the application's UI. In addition, cancelling + * and rescheduling comes practically for free and the developer needs not + * worry about how many threads are launched, since Ecore will schedule + * them according to the number of processors the system has and maximum + * amount of concurrent threads set for the application. + * + * At the system level, Ecore will start a new thread on an as-needed basis + * until the maximum set is reached. When no more threads can be launched, + * new worker functions will be queued in a waiting list until a thread + * becomes available. This way, system threads will be shared throughout + * different worker functions, but running only one at a time. At the same + * time, a worker function that is rescheduled may be run on a different + * thread the next time. + * + * The ::Ecore_Thread handler has two meanings, depending on what context + * it is on. The one returned when starting a worker with any of the + * functions ecore_thread_run() or ecore_thread_feedback_run() is an + * identifier of that specific instance of the function and can be used from + * the main loop with the ecore_thread_cancel() and ecore_thread_check() + * functions. This handler must not be shared with the worker function + * function running in the thread. This same handler will be the one received + * on the @c end, @c cancel and @c feedback callbacks. + * + * The worker function, that's the one running in the thread, also receives + * an ::Ecore_Thread handler that can be used with ecore_thread_cancel() and + *ecore_thread_check(), sharing the flag with the main loop. But this + * handler is also associated with the thread where the function is running. + * This has strong implications when working with thread local data. + * + * There are two kinds of worker threads Ecore handles: simple, or short, + * workers and feedback workers. + * + * The first kind is for simple functions that perform a + * usually small but time consuming task. Ecore will run this function in + * a thread as soon as one becomes available and notify the calling user of + * its completion once the task is done. + * + * The following image shows the flow of a program running four tasks on + * a pool of two threads. + * + * @image html ecore_thread.png + * @image rtf ecore_thread.png + * @image latex ecore_thread.eps width=\textwidth + * + * For larger tasks that may require continuous communication with the main + * program, the feedback workers provide the same functionality plus a way + * for the function running in the thread to send messages to the main + * thread. + * + * The next diagram omits some details shown in the previous one regarding + * how threads are spawned and tasks are queued, but illustrates how feedback + * jobs communicate with the main loop and the special case of threads + * running out of pool. + * + * @image html ecore_thread_feedback.png + * @image rtf ecore_thread_feedback.png + * @image latex ecore_thread_feedback.eps width=\textwidth + * + * See an overview example in @ref ecore_thread_example_c. + * + * @ingroup Ecore_Main_Loop_Group + * + * @{ + */ + +typedef struct _Ecore_Thread Ecore_Thread; /**< A handle for threaded jobs */ + +/** + * @typedef Ecore_Thread_Cb Ecore_Thread_Cb + * A callback used by Ecore_Thread helper. + */ +typedef void (*Ecore_Thread_Cb)(void *data, Ecore_Thread *thread); +/** + * @typedef Ecore_Thread_Notify_Cb Ecore_Thread_Notify_Cb + * A callback used by the main loop to receive data sent by an + * @ref Ecore_Thread_Group. + */ +typedef void (*Ecore_Thread_Notify_Cb)(void *data, Ecore_Thread *thread, void *msg_data); + +/** + * Schedule a task to run in a parallel thread to avoid locking the main loop + * + * @param func_blocking The function that should run in another thread. + * @param func_end Function to call from main loop when @p func_blocking + * completes its task successfully (may be NULL) + * @param func_cancel Function to call from main loop if the thread running + * @p func_blocking is cancelled or fails to start (may be NULL) + * @param data User context data to pass to all callbacks. + * @return A new thread handler, or @c NULL on failure. + * + * This function will try to create a new thread to run @p func_blocking in, + * or if the maximum number of concurrent threads has been reached, will + * add it to the pending list, where it will wait until a thread becomes + * available. The return value will be an ::Ecore_Thread handle that can + * be used to cancel the thread before its completion. + * + * @note This function should always return immediately, but in the rare + * case that Ecore is built with no thread support, @p func_blocking will + * be called here, actually blocking the main loop. + * + * Once a thread becomes available, @p func_blocking will be run in it until + * it finishes, then @p func_end is called from the thread containing the + * main loop to inform the user of its completion. While in @p func_blocking, + * no functions from the EFL can be used, except for those from Eina that are + * marked to be thread-safe. Even for the latter, caution needs to be taken + * if the data is shared across several threads. + * + * @p func_end will be called from the main thread when @p func_blocking ends, + * so here it's safe to use anything from the EFL freely. + * + * The thread can also be cancelled before its completion calling + *ecore_thread_cancel(), either from the main thread or @p func_blocking. + * In this case, @p func_cancel will be called, also from the main thread + * to inform of this happening. If the thread could not be created, this + * function will be called and it's @c thread parameter will be NULL. It's + * also safe to call any EFL function here, as it will be running in the + * main thread. + * + * Inside @p func_blocking, it's possible to call ecore_thread_reschedule() + * to tell Ecore that this function should be called again. + * + * Be aware that no assumptions can be made about the order in which the + * @p func_end callbacks for each task will be called. Once the function is + * running in a different thread, it's the OS that will handle its running + * schedule, and different functions may take longer to finish than others. + * Also remember that just starting several tasks together doesn't mean they + * will be running at the same time. Ecore will schedule them based on the + * number of threads available for the particular system it's running in, + * so some of the jobs started may be waiting until another one finishes + * before it can execute its own @p func_blocking. + * + * @see ecore_thread_feedback_run() + * @see ecore_thread_cancel() + * @see ecore_thread_reschedule() + * @see ecore_thread_max_set() + */ +EAPI Ecore_Thread *ecore_thread_run(Ecore_Thread_Cb func_blocking, Ecore_Thread_Cb func_end, Ecore_Thread_Cb func_cancel, const void *data); +/** + * Launch a thread to run a task that can talk back to the main thread + * + * @param func_heavy The function that should run in another thread. + * @param func_notify Function that receives the data sent from the thread + * @param func_end Function to call from main loop when @p func_heavy + * completes its task successfully + * @param func_cancel Function to call from main loop if the thread running + * @p func_heavy is cancelled or fails to start + * @param data User context data to pass to all callback. + * @param try_no_queue If you want to run outside of the thread pool. + * @return A new thread handler, or @c NULL on failure. + * + * See ecore_thread_run() for a general description of this function. + * + * The difference with the above is that ecore_thread_run() is meant for + * tasks that don't need to communicate anything until they finish, while + * this function is provided with a new callback, @p func_notify, that will + * be called from the main thread for every message sent from @p func_heavy + * with ecore_thread_feedback(). + * + * Like with ecore_thread_run(), a new thread will be launched to run + * @p func_heavy unless the maximum number of simultaneous threads has been + * reached, in which case the function will be scheduled to run whenever a + * running task ends and a thread becomes free. But if @p try_no_queue is + * set, Ecore will first try to launch a thread outside of the pool to run + * the task. If it fails, it will revert to the normal behaviour of using a + * thread from the pool as if @p try_no_queue had not been set. + * + * Keep in mind that Ecore handles the thread pool based on the number of + * CPUs available, but running a thread outside of the pool doesn't count for + * this, so having too many of them may have drastic effects over the + * program's performance. + * + * @see ecore_thread_feedback() + * @see ecore_thread_run() + * @see ecore_thread_cancel() + * @see ecore_thread_reschedule() + * @see ecore_thread_max_set() + */ +EAPI Ecore_Thread *ecore_thread_feedback_run(Ecore_Thread_Cb func_heavy, Ecore_Thread_Notify_Cb func_notify, + Ecore_Thread_Cb func_end, Ecore_Thread_Cb func_cancel, + const void *data, Eina_Bool try_no_queue); +/** + * Cancel a running thread. + * + * @param thread The thread to cancel. + * @return Will return @c EINA_TRUE if the thread has been cancelled, + * @c EINA_FALSE if it is pending. + * + * This function can be called both in the main loop or in the running thread. + * + * This function cancels a running thread. If @p thread can be immediately + * cancelled (it's still pending execution after creation or rescheduling), + * then the @c cancel callback will be called, @p thread will be freed and + * the function will return @c EINA_TRUE. + * + * If the thread is already running, then this function returns @c EINA_FALSE + * after marking the @p thread as pending cancellation. For the thread to + * actually be terminated, it needs to return from the user function back + * into Ecore control. This can happen in several ways: + * @li The function ends and returns normally. If it hadn't been cancelled, + * @c func_end would be called here, but instead @c func_cancel will happen. + * @li The function returns after requesting to be rescheduled with + * ecore_thread_reschedule(). + * @li The function is prepared to leave early by checking if + * ecore_thread_check() returns @c EINA_TRUE. + * + * The user function can cancel itself by calling ecore_thread_cancel(), but + * it should always use the ::Ecore_Thread handle passed to it and never + * share it with the main loop thread by means of shared user data or any + * other way. + * + * @p thread will be freed and should not be used again if this function + * returns @c EINA_TRUE or after the @c func_cancel callback returns. + * + * @see ecore_thread_check() + */ +EAPI Eina_Bool ecore_thread_cancel(Ecore_Thread *thread); +/** + * Checks if a thread is pending cancellation + * + * @param thread The thread to test. + * @return @c EINA_TRUE if the thread is pending cancellation, + * @c EINA_FALSE if it is not. + * + * This function can be called both in the main loop or in the running thread. + * + * When ecore_thread_cancel() is called on an already running task, the + * thread is marked as pending cancellation. This function returns @c EINA_TRUE + * if this mark is set for the given @p thread and can be used from the + * main loop thread to check if a still active thread has been cancelled, + * or from the user function running in the thread to check if it should + * stop doing what it's doing and return early, effectively cancelling the + * task. + * + * @see ecore_thread_cancel() + */ +EAPI Eina_Bool ecore_thread_check(Ecore_Thread *thread); +/** + * Sends data from the worker thread to the main loop + * + * @param thread The current ::Ecore_Thread context to send data from + * @param msg_data Data to be transmitted to the main loop + * @return @c EINA_TRUE if @p msg_data was successfully sent to main loop, + * @c EINA_FALSE if anything goes wrong. + * + * You should use this function only in the @c func_heavy call. + * + * Only the address to @p msg_data will be sent and once this function + * returns @c EINA_TRUE, the job running in the thread should never touch the + * contents of it again. The data sent should be malloc()'ed or something + * similar, as long as it's not memory local to the thread that risks being + * overwritten or deleted once it goes out of scope or the thread finishes. + * + * Care must be taken that @p msg_data is properly freed in the @c func_notify + * callback set when creating the thread. + * + * @see ecore_thread_feedback_run() + */ +EAPI Eina_Bool ecore_thread_feedback(Ecore_Thread *thread, const void *msg_data); +/** + * Asks for the function in the thread to be called again at a later time + * + * @param thread The current ::Ecore_Thread context to rescheduled + * @return @c EINA_TRUE if the task was successfully rescheduled, + * @c EINA_FALSE if anything goes wrong. + * + * This function should be called only from the same function represented + * by @p thread. + * + * Calling this function will mark the thread for a reschedule, so as soon + * as it returns, it will be added to the end of the list of pending tasks. + * If no other tasks are waiting or there are sufficient threads available, + * the rescheduled task will be launched again immediately. + * + * This should never return @c EINA_FALSE, unless it was called from the wrong + * thread or with the wrong arguments. + * + * The @c func_end callback set when the thread is created will not be + * called until the function in the thread returns without being rescheduled. + * Similarly, if the @p thread is cancelled, the reschedule will not take + * effect. + */ +EAPI Eina_Bool ecore_thread_reschedule(Ecore_Thread *thread); +/** + * Gets the number of active threads running jobs + * + * @return Number of active threads running jobs + * + * This returns the number of threads currently running jobs of any type + * through the Ecore_Thread API. + * + * @note Jobs started through the ecore_thread_feedback_run() function with + * the @c try_no_queue parameter set to @c EINA_TRUE will not be accounted for + * in the return of this function unless the thread creation fails and it + * falls back to using one from the pool. + */ +EAPI int ecore_thread_active_get(void); +/** + * Gets the number of short jobs waiting for a thread to run + * + * @return Number of pending threads running "short" jobs + * + * This returns the number of tasks started with ecore_thread_run() that are + * pending, waiting for a thread to become available to run them. + */ +EAPI int ecore_thread_pending_get(void); +/** + * Gets the number of feedback jobs waiting for a thread to run + * + * @return Number of pending threads running "feedback" jobs + * + * This returns the number of tasks started with ecore_thread_feedback_run() + * that are pending, waiting for a thread to become available to run them. + */ +EAPI int ecore_thread_pending_feedback_get(void); +/** + * Gets the total number of pending jobs + * + * @return Number of pending threads running jobs + * + * Same as the sum of ecore_thread_pending_get() and + *ecore_thread_pending_feedback_get(). + */ +EAPI int ecore_thread_pending_total_get(void); +/** + * Gets the maximum number of threads that can run simultaneously + * + * @return Max possible number of Ecore_Thread's running concurrently + * + * This returns the maximum number of Ecore_Thread's that may be running at + * the same time. If this number is reached, new jobs started by either + *ecore_thread_run() or ecore_thread_feedback_run() will be added to the + * respective pending queue until one of the running threads finishes its + * task and becomes available to run a new one. + * + * By default, this will be the number of available CPUs for the + * running program (as returned by eina_cpu_count()), or 1 if this value + * could not be fetched. + * + * @see ecore_thread_max_set() + * @see ecore_thread_max_reset() + */ +EAPI int ecore_thread_max_get(void); +/** + * Sets the maximum number of threads allowed to run simultaneously + * + * @param num The new maximum + * + * This sets a new value for the maximum number of concurrently running + * Ecore_Thread's. It @b must an integer between 1 and (16 * @c x), where @c x + * is the number for CPUs available. + * + * @see ecore_thread_max_get() + * @see ecore_thread_max_reset() + */ +EAPI void ecore_thread_max_set(int num); +/** + * Resets the maximum number of concurrently running threads to the default + * + * This resets the value returned by ecore_thread_max_get() back to its + * default. + * + * @see ecore_thread_max_get() + * @see ecore_thread_max_set() + */ +EAPI void ecore_thread_max_reset(void); +/** + * Gets the number of threads available for running tasks + * + * @return The number of available threads + * + * Same as doing ecore_thread_max_get() - ecore_thread_active_get(). + * + * This function may return a negative number only in the case the user + * changed the maximum number of running threads while other tasks are + * running. + */ +EAPI int ecore_thread_available_get(void); +/** + * Adds some data to a hash local to the thread + * + * @param thread The thread context the data belongs to + * @param key The name under which the data will be stored + * @param value The data to add + * @param cb Function to free the data when removed from the hash + * @param direct If true, this will not copy the key string (like + * eina_hash_direct_add()) + * @return @c EINA_TRUE on success, @c EINA_FALSE on failure. + * + * Ecore Thread has a mechanism to share data across several worker functions + * that run on the same system thread. That is, the data is stored per + * thread and for a worker function to have access to it, it must be run + * by the same thread that stored the data. + * + * When there are no more workers pending, the thread will be destroyed + * along with the internal hash and any data left in it will be freed with + * the @p cb function given. + * + * This set of functions is useful to share things around several instances + * of a function when that thing is costly to create and can be reused, but + * may only be used by one function at a time. + * + * For example, if you have a program doing requisitions to a database, + * these requisitions can be done in threads so that waiting for the + * database to respond doesn't block the UI. Each of these threads will + * run a function, and each function will be dependent on a connection to + * the database, which may not be able to handle more than one request at + * a time so for each running function you will need one connection handle. + * The options then are: + * @li Each function opens a connection when it's called, does the work and + * closes the connection when it finishes. This may be costly, wasting a lot + * of time on resolving hostnames, negotiating permissions and allocating + * memory. + * @li Open the connections in the main loop and pass it to the threads + * using the data pointer. Even worse, it's just as costly as before and now + * it may even be kept with connections open doing nothing until a thread + * becomes available to run the function. + * @li Have a way to share connection handles, so that each instance of the + * function can check if an available connection exists, and if it doesn't, + * create one and add it to the pool. When no more connections are needed, + * they are all closed. + * + * The last option is the most efficient, but it requires a lot of work to + * implement properly. Using thread local data helps to achieve the same + * result while avoiding doing all the tracking work on your code. The way + * to use it would be, at the worker function, to ask for the connection + * with ecore_thread_local_data_find() and if it doesn't exist, then open + * a new one and save it with ecore_thread_local_data_add(). Do the work and + * forget about the connection handle, when everything is done the function + * just ends. The next worker to run on that thread will check if a + * connection exists and find that it does, so the process of opening a + * new one has been spared. When no more workers exist, the thread is + * destroyed and the callback used when saving the connection will be called + * to close it. + * + * This function adds the data @p value to the thread data under the given + * @p key. + * No other value in the hash may have the same @p key. If you need to + * change the value under a @p key, or you don't know if one exists already, + * you can use ecore_thread_local_data_set(). + * + * Neither @p key nor @p value may be @c NULL and @p key will be copied in the + * hash, unless @p direct is set, in which case the string used should not + * be freed until the data is removed from the hash. + * + * The @p cb function will be called when the data in the hash needs to be + * freed, be it because it got deleted with ecore_thread_local_data_del() or + * because @p thread was terminated and the hash destroyed. This parameter + * may be NULL, in which case @p value needs to be manually freed after + * removing it from the hash with either ecore_thread_local_data_del() or + * ecore_thread_local_data_set(), but it's very unlikely that this is what + * you want. + * + * This function, and all of the others in the @c ecore_thread_local_data + * family of functions, can only be called within the worker function running + * in the thread. Do not call them from the main loop or from a thread + * other than the one represented by @p thread. + * + * @see ecore_thread_local_data_set() + * @see ecore_thread_local_data_find() + * @see ecore_thread_local_data_del() + */ +EAPI Eina_Bool ecore_thread_local_data_add(Ecore_Thread *thread, const char *key, void *value, + Eina_Free_Cb cb, Eina_Bool direct); +/** + * Sets some data in the hash local to the given thread + * + * @param thread The thread context the data belongs to + * @param key The name under which the data will be stored + * @param value The data to add + * @param cb Function to free the data when removed from the hash + * + * If no data exists in the hash under the @p key, this function adds + * @p value in the hash under the given @p key and returns NULL. + * The key itself is copied. + * + * If the hash already contains something under @p key, the data will be + * replaced by @p value and the old value will be returned. + * + * @c NULL will also be returned if either @p key or @p value are @c NULL, or + * if an error occurred. + * + * This function, and all of the others in the @c ecore_thread_local_data + * family of functions, can only be called within the worker function running + * in the thread. Do not call them from the main loop or from a thread + * other than the one represented by @p thread. + * + * @see ecore_thread_local_data_add() + * @see ecore_thread_local_data_del() + * @see ecore_thread_local_data_find() + */ +EAPI void *ecore_thread_local_data_set(Ecore_Thread *thread, const char *key, void *value, Eina_Free_Cb cb); +/** + * Gets data stored in the hash local to the given thread + * + * @param thread The thread context the data belongs to + * @param key The name under which the data is stored + * @return The value under the given key, or @c NULL on error. + * + * Finds and return the data stored in the shared hash under the key @p key. + * + * This function, and all of the others in the @c ecore_thread_local_data + * family of functions, can only be called within the worker function running + * in the thread. Do not call them from the main loop or from a thread + * other than the one represented by @p thread. + * + * @see ecore_thread_local_data_add() + * @see ecore_thread_local_data_wait() + */ +EAPI void *ecore_thread_local_data_find(Ecore_Thread *thread, const char *key); +/** + * Deletes from the thread's hash the data corresponding to the given key + * + * @param thread The thread context the data belongs to + * @param key The name under which the data is stored + * @return @c EINA_TRUE on success, @c EINA_FALSE on failure. + * + * If there's any data stored associated with @p key in the global hash, + * this function will remove it from it and return @c EINA_TRUE. If no data + * exists or an error occurs, it returns @c EINA_FALSE. + * + * If the data was added to the hash with a free function, then it will + * also be freed after removing it from the hash, otherwise it requires + * to be manually freed by the user, which means that if no other reference + * to it exists before calling this function, it will result in a memory + * leak. + * + * This function, and all of the others in the @c ecore_thread_local_data + * family of functions, can only be called within the worker function running + * in the thread. Do not call them from the main loop or from a thread + * other than the one represented by @p thread. + * + * @see ecore_thread_local_data_add() + */ +EAPI Eina_Bool ecore_thread_local_data_del(Ecore_Thread *thread, const char *key); + +/** + * Adds some data to a hash shared by all threads + * + * @param key The name under which the data will be stored + * @param value The data to add + * @param cb Function to free the data when removed from the hash + * @param direct If true, this will not copy the key string (like + * eina_hash_direct_add()) + * @return @c EINA_TRUE on success, @c EINA_FALSE on failure. + * + * Ecore Thread keeps a hash that can be used to share data across several + * threads, including the main loop one, without having to manually handle + * mutexes to do so safely. + * + * This function adds the data @p value to this hash under the given @p key. + * No other value in the hash may have the same @p key. If you need to + * change the value under a @p key, or you don't know if one exists already, + * you can use ecore_thread_global_data_set(). + * + * Neither @p key nor @p value may be @c NULL and @p key will be copied in the + * hash, unless @p direct is set, in which case the string used should not + * be freed until the data is removed from the hash. + * + * The @p cb function will be called when the data in the hash needs to be + * freed, be it because it got deleted with ecore_thread_global_data_del() or + * because Ecore Thread was shut down and the hash destroyed. This parameter + * may be NULL, in which case @p value needs to be manually freed after + * removing it from the hash with either ecore_thread_global_data_del() or + *ecore_thread_global_data_set(). + * + * Manually freeing any data that was added to the hash with a @p cb function + * is likely to produce a segmentation fault, or any other strange + * happenings, later on in the program. + * + * @see ecore_thread_global_data_del() + * @see ecore_thread_global_data_set() + * @see ecore_thread_global_data_find() + */ +EAPI Eina_Bool ecore_thread_global_data_add(const char *key, void *value, Eina_Free_Cb cb, Eina_Bool direct); +/** + * Sets some data in the hash shared by all threads + * + * @param key The name under which the data will be stored + * @param value The data to add + * @param cb Function to free the data when removed from the hash + * + * If no data exists in the hash under the @p key, this function adds + * @p value in the hash under the given @p key and returns NULL. + * The key itself is copied. + * + * If the hash already contains something under @p key, the data will be + * replaced by @p value and the old value will be returned. + * + * @c NULL will also be returned if either @p key or @p value are @c NULL, or + * if an error occurred. + * + * @see ecore_thread_global_data_add() + * @see ecore_thread_global_data_del() + * @see ecore_thread_global_data_find() + */ +EAPI void *ecore_thread_global_data_set(const char *key, void *value, Eina_Free_Cb cb); +/** + * Gets data stored in the hash shared by all threads + * + * @param key The name under which the data is stored + * @return The value under the given key, or @c NULL on error. + * + * Finds and return the data stored in the shared hash under the key @p key. + * + * Keep in mind that the data returned may be used by more than one thread + * at the same time and no reference counting is done on it by Ecore. + * Freeing the data or modifying its contents may require additional + * precautions to be considered, depending on the application's design. + * + * @see ecore_thread_global_data_add() + * @see ecore_thread_global_data_wait() + */ +EAPI void *ecore_thread_global_data_find(const char *key); +/** + * Deletes from the shared hash the data corresponding to the given key + * + * @param key The name under which the data is stored + * @return @c EINA_TRUE on success, @c EINA_FALSE on failure. + * + * If there's any data stored associated with @p key in the global hash, + * this function will remove it from it and return @c EINA_TRUE. If no data + * exists or an error occurs, it returns @c EINA_FALSE. + * + * If the data was added to the hash with a free function, then it will + * also be freed after removing it from the hash, otherwise it requires + * to be manually freed by the user, which means that if no other reference + * to it exists before calling this function, it will result in a memory + * leak. + * + * Note, also, that freeing data that other threads may be using will result + * in a crash, so appropriate care must be taken by the application when + * that possibility exists. + * + * @see ecore_thread_global_data_add() + */ +EAPI Eina_Bool ecore_thread_global_data_del(const char *key); +/** + * Gets data stored in the shared hash, or wait for it if it doesn't exist + * + * @param key The name under which the data is stored + * @param seconds The amount of time in seconds to wait for the data. + * @return The value under the given key, or @c NULL on error. + * + * Finds and return the data stored in the shared hash under the key @p key. + * + * If there's nothing in the hash under the given @p key, the function + * will block and wait up to @p seconds seconds for some other thread to + * add it with either ecore_thread_global_data_add() or + * ecore_thread_global_data_set(). If after waiting there's still no data + * to get, @c NULL will be returned. + * + * If @p seconds is 0, then no waiting will happen and this function works + * like ecore_thread_global_data_find(). If @p seconds is less than 0, then + * the function will wait indefinitely. + * + * Keep in mind that the data returned may be used by more than one thread + * at the same time and no reference counting is done on it by Ecore. + * Freeing the data or modifying its contents may require additional + * precautions to be considered, depending on the application's design. + * + * @see ecore_thread_global_data_add() + * @see ecore_thread_global_data_find() + */ +EAPI void *ecore_thread_global_data_wait(const char *key, double seconds); + +/** + * @} + */ + +/** + * @defgroup Ecore_Pipe_Group Pipe wrapper + * + * These functions wrap the pipe / write / read functions to easily + * integrate its use into ecore's main loop. + * + * The ecore_pipe_add() function creates file descriptors (sockets + * on Windows) and attach a handle to the ecore main loop. That + * handle is called when data is read in the pipe. To write data in + * the pipe, just call ecore_pipe_write(). When you are done, just + * call ecore_pipe_del(). + * + * For examples see here: + * @li @ref tutorial_ecore_pipe_gstreamer_example + * @li @ref tutorial_ecore_pipe_simple_example + * + * @ingroup Ecore_Main_Loop_Group + * + * @{ + */ + +typedef struct _Ecore_Pipe Ecore_Pipe; /**< A handle for pipes */ + +/** + * @typedef Ecore_Pipe_Cb Ecore_Pipe_Cb + * The callback that data written to the pipe is sent to. + */ +typedef void (*Ecore_Pipe_Cb)(void *data, void *buffer, unsigned int nbyte); + +EAPI Ecore_Pipe *ecore_pipe_add(Ecore_Pipe_Cb handler, const void *data); +EAPI void *ecore_pipe_del(Ecore_Pipe *p); +EAPI Eina_Bool ecore_pipe_write(Ecore_Pipe *p, const void *buffer, unsigned int nbytes); +EAPI void ecore_pipe_write_close(Ecore_Pipe *p); +EAPI void ecore_pipe_read_close(Ecore_Pipe *p); +EAPI void ecore_pipe_thaw(Ecore_Pipe *p); +EAPI void ecore_pipe_freeze(Ecore_Pipe *p); +EAPI int ecore_pipe_wait(Ecore_Pipe *p, int message_count, double wait); + +/** + * @} + */ + +/** + * @defgroup Ecore_Job_Group Ecore Job functions + * + * You can queue jobs that are to be done by the main loop when the + * current event is dealt with. + * + * Jobs are processed by the main loop similarly to events. They + * also will be executed in the order in which they were added. + * + * A good use for them is when you don't want to execute an action + * immediately, but want to give the control back to the main loop + * so that it will call your job callback when jobs start being + * processed (and if there are other jobs added before yours, they + * will be processed first). This also gives the chance to other + * actions in your program to cancel the job before it is started. + * + * Examples of using @ref Ecore_Job : + * @li @ref ecore_job_example_c + * + * @ingroup Ecore_Main_Loop_Group + * + * @{ + */ + +typedef struct _Ecore_Job Ecore_Job; /**< A job handle */ + +EAPI Ecore_Job *ecore_job_add(Ecore_Cb func, const void *data); +EAPI void *ecore_job_del(Ecore_Job *job); + +/** + * @} + */ + +/** + * @defgroup Ecore_Application_Group Ecore Application functions + * + * @{ + */ + +EAPI void ecore_app_args_set(int argc, const char **argv); +EAPI void ecore_app_args_get(int *argc, char ***argv); +EAPI void ecore_app_restart(void); + +/** + * @} + */ + +/** + * @defgroup Ecore_Throttle_Group Ecore Throttle functions + * + * @ingroup Ecore_Main_Loop_Group + * + * @{ + */ + +EAPI void ecore_throttle_adjust(double amount); +EAPI double ecore_throttle_get(void); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/lib/ecore/Ecore_Getopt.h b/src/lib/ecore/Ecore_Getopt.h new file mode 100644 index 0000000..0a11787 --- /dev/null +++ b/src/lib/ecore/Ecore_Getopt.h @@ -0,0 +1,419 @@ +#ifndef _ECORE_GETOPT_H +#define _ECORE_GETOPT_H + +#include +#include + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_ECORE_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_ECORE_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +/** + * @file Ecore_Getopt.h + * @brief Contains powerful getopt replacement. + * + * This replacement handles both short (-X) or long options (--ABC) + * options, with various actions supported, like storing one value and + * already converting to required type, counting number of + * occurrences, setting true or false values, show help, license, + * copyright and even support user-defined callbacks. + * + * It is provided a set of C Pre Processor macros so definition is + * straightforward. + * + * Values will be stored elsewhere indicated by an array of pointers + * to values, it is given in separate to parser description so you can + * use multiple values with the same parser. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + ECORE_GETOPT_ACTION_STORE, + ECORE_GETOPT_ACTION_STORE_CONST, + ECORE_GETOPT_ACTION_STORE_TRUE, + ECORE_GETOPT_ACTION_STORE_FALSE, + ECORE_GETOPT_ACTION_CHOICE, + ECORE_GETOPT_ACTION_APPEND, + ECORE_GETOPT_ACTION_COUNT, + ECORE_GETOPT_ACTION_CALLBACK, + ECORE_GETOPT_ACTION_HELP, + ECORE_GETOPT_ACTION_VERSION, + ECORE_GETOPT_ACTION_COPYRIGHT, + ECORE_GETOPT_ACTION_LICENSE +} Ecore_Getopt_Action; + +typedef enum { + ECORE_GETOPT_TYPE_STR, + ECORE_GETOPT_TYPE_BOOL, + ECORE_GETOPT_TYPE_SHORT, + ECORE_GETOPT_TYPE_INT, + ECORE_GETOPT_TYPE_LONG, + ECORE_GETOPT_TYPE_USHORT, + ECORE_GETOPT_TYPE_UINT, + ECORE_GETOPT_TYPE_ULONG, + ECORE_GETOPT_TYPE_DOUBLE +} Ecore_Getopt_Type; + +typedef enum { + ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO = 0, + ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES = 1, + ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL = 3 +} Ecore_Getopt_Desc_Arg_Requirement; + +typedef union _Ecore_Getopt_Value Ecore_Getopt_Value; + +typedef struct _Ecore_Getopt_Desc_Store Ecore_Getopt_Desc_Store; +typedef struct _Ecore_Getopt_Desc_Callback Ecore_Getopt_Desc_Callback; +typedef struct _Ecore_Getopt_Desc Ecore_Getopt_Desc; +typedef struct _Ecore_Getopt Ecore_Getopt; + +union _Ecore_Getopt_Value +{ + char **strp; + unsigned char *boolp; + short *shortp; + int *intp; + long *longp; + unsigned short *ushortp; + unsigned int *uintp; + unsigned long *ulongp; + double *doublep; + Eina_List **listp; + void **ptrp; +}; + +struct _Ecore_Getopt_Desc_Store +{ + Ecore_Getopt_Type type; /**< type of data being handled */ + Ecore_Getopt_Desc_Arg_Requirement arg_req; + union + { + const char *strv; + Eina_Bool boolv; + short shortv; + int intv; + long longv; + unsigned short ushortv; + unsigned int uintv; + unsigned long ulongv; + double doublev; + } def; +}; + +struct _Ecore_Getopt_Desc_Callback +{ + Eina_Bool (*func)(const Ecore_Getopt *parser, + const Ecore_Getopt_Desc *desc, + const char *str, + void *data, + Ecore_Getopt_Value *storage); + const void *data; + Ecore_Getopt_Desc_Arg_Requirement arg_req; + const char *def; +}; + +struct _Ecore_Getopt_Desc +{ + char shortname; /**< used with a single dash */ + const char *longname; /**< used with double dashes */ + const char *help; /**< used by --help/ecore_getopt_help() */ + const char *metavar; /**< used by ecore_getopt_help() with nargs > 0 */ + + Ecore_Getopt_Action action; /**< define how to handle it */ + union + { + const Ecore_Getopt_Desc_Store store; + const void *store_const; + const char *const *choices; /* NULL terminated. */ + const Ecore_Getopt_Type append_type; + const Ecore_Getopt_Desc_Callback callback; + const void *dummy; + } action_param; +}; + +struct _Ecore_Getopt +{ + const char *prog; /**< to be used when ecore_app_args_get() fails */ + const char *usage; /**< usage example, %prog is replaced */ + const char *version; /**< if exists, --version will work */ + const char *copyright; /**< if exists, --copyright will work */ + const char *license; /**< if exists, --license will work */ + const char *description; /**< long description, possible multiline */ + Eina_Bool strict : 1; /**< fail on errors */ + const Ecore_Getopt_Desc descs[]; /* NULL terminated. */ +}; + +#define ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, type, arg_requirement, default_value) \ + {shortname, longname, help, metavar, ECORE_GETOPT_ACTION_STORE, \ + {.store = {type, arg_requirement, default_value}}} + +#define ECORE_GETOPT_STORE(shortname, longname, help, type) \ + ECORE_GETOPT_STORE_FULL(shortname, longname, help, NULL, type, \ + ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES, {}) + +#define ECORE_GETOPT_STORE_STR(shortname, longname, help) \ + ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_STR) +#define ECORE_GETOPT_STORE_BOOL(shortname, longname, help) \ + ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_BOOL) +#define ECORE_GETOPT_STORE_SHORT(shortname, longname, help) \ + ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_SHORT) +#define ECORE_GETOPT_STORE_INT(shortname, longname, help) \ + ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_INT) +#define ECORE_GETOPT_STORE_LONG(shortname, longname, help) \ + ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_LONG) +#define ECORE_GETOPT_STORE_USHORT(shortname, longname, help) \ + ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_USHORT) +#define ECORE_GETOPT_STORE_UINT(shortname, longname, help) \ + ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_UINT) +#define ECORE_GETOPT_STORE_ULONG(shortname, longname, help) \ + ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_ULONG) +#define ECORE_GETOPT_STORE_DOUBLE(shortname, longname, help) \ + ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_DOUBLE) + +#define ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, type) \ + ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, type, \ + ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES, {}) + +#define ECORE_GETOPT_STORE_METAVAR_STR(shortname, longname, help, metavar) \ + ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, ECORE_GETOPT_TYPE_STR) +#define ECORE_GETOPT_STORE_METAVAR_BOOL(shortname, longname, help, metavar) \ + ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, ECORE_GETOPT_TYPE_BOOL) +#define ECORE_GETOPT_STORE_METAVAR_SHORT(shortname, longname, help, metavar) \ + ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, ECORE_GETOPT_TYPE_SHORT) +#define ECORE_GETOPT_STORE_METAVAR_INT(shortname, longname, help, metavar) \ + ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, ECORE_GETOPT_TYPE_INT) +#define ECORE_GETOPT_STORE_METAVAR_LONG(shortname, longname, help, metavar) \ + ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, ECORE_GETOPT_TYPE_LONG) +#define ECORE_GETOPT_STORE_METAVAR_USHORT(shortname, longname, help, metavar) \ + ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, ECORE_GETOPT_TYPE_USHORT) +#define ECORE_GETOPT_STORE_METAVAR_UINT(shortname, longname, help, metavar) \ + ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, ECORE_GETOPT_TYPE_UINT) +#define ECORE_GETOPT_STORE_METAVAR_ULONG(shortname, longname, help, metavar) \ + ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, ECORE_GETOPT_TYPE_ULONG) +#define ECORE_GETOPT_STORE_METAVAR_DOUBLE(shortname, longname, help, metavar) \ + ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, ECORE_GETOPT_TYPE_DOUBLE) + +#define ECORE_GETOPT_STORE_DEF(shortname, longname, help, type, default_value) \ + ECORE_GETOPT_STORE_FULL(shortname, longname, help, NULL, type, \ + ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL, \ + default_value) + +#define ECORE_GETOPT_STORE_DEF_STR(shortname, longname, help, default_value) \ + ECORE_GETOPT_STORE_DEF(shortname, longname, help, \ + ECORE_GETOPT_TYPE_STR, \ + {.strv = default_value}) +#define ECORE_GETOPT_STORE_DEF_BOOL(shortname, longname, help, default_value) \ + ECORE_GETOPT_STORE_DEF(shortname, longname, help, \ + ECORE_GETOPT_TYPE_BOOL, \ + {.boolv = default_value}) +#define ECORE_GETOPT_STORE_DEF_SHORT(shortname, longname, help, default_value) \ + ECORE_GETOPT_STORE_DEF(shortname, longname, help, \ + ECORE_GETOPT_TYPE_SHORT, \ + {.shortv = default_value}) +#define ECORE_GETOPT_STORE_DEF_INT(shortname, longname, help, default_value) \ + ECORE_GETOPT_STORE_DEF(shortname, longname, help, \ + ECORE_GETOPT_TYPE_INT, \ + {.intv = default_value}) +#define ECORE_GETOPT_STORE_DEF_LONG(shortname, longname, help, default_value) \ + ECORE_GETOPT_STORE_DEF(shortname, longname, help, \ + ECORE_GETOPT_TYPE_LONG, \ + {.longv = default_value}) +#define ECORE_GETOPT_STORE_DEF_USHORT(shortname, longname, help, default_value) \ + ECORE_GETOPT_STORE_DEF(shortname, longname, help, \ + ECORE_GETOPT_TYPE_USHORT, \ + {.ushortv = default_value}) +#define ECORE_GETOPT_STORE_DEF_UINT(shortname, longname, help, default_value) \ + ECORE_GETOPT_STORE_DEF(shortname, longname, help, \ + ECORE_GETOPT_TYPE_UINT, \ + {.uintv = default_value}) +#define ECORE_GETOPT_STORE_DEF_ULONG(shortname, longname, help, default_value) \ + ECORE_GETOPT_STORE_DEF(shortname, longname, help, \ + ECORE_GETOPT_TYPE_ULONG, \ + {.ulongv = default_value}) +#define ECORE_GETOPT_STORE_DEF_DOUBLE(shortname, longname, help, default_value) \ + ECORE_GETOPT_STORE_DEF(shortname, longname, help, \ + ECORE_GETOPT_TYPE_DOUBLE, \ + {.doublev = default_value}) + +#define ECORE_GETOPT_STORE_FULL_STR(shortname, longname, help, metavar, arg_requirement, default_value) \ + ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, \ + ECORE_GETOPT_TYPE_STR, \ + arg_requirement, \ + {.strv = default_value}) +#define ECORE_GETOPT_STORE_FULL_BOOL(shortname, longname, help, metavar, arg_requirement, default_value) \ + ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, \ + ECORE_GETOPT_TYPE_BOOL, \ + arg_requirement, \ + {.boolv = default_value}) +#define ECORE_GETOPT_STORE_FULL_SHORT(shortname, longname, help, metavar, arg_requirement, default_value) \ + ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, \ + ECORE_GETOPT_TYPE_SHORT, \ + arg_requirement, \ + {.shortv = default_value}) +#define ECORE_GETOPT_STORE_FULL_INT(shortname, longname, help, metavar, arg_requirement, default_value) \ + ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, \ + ECORE_GETOPT_TYPE_INT, \ + arg_requirement, \ + {.intv = default_value}) +#define ECORE_GETOPT_STORE_FULL_LONG(shortname, longname, help, metavar, arg_requirement, default_value) \ + ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, \ + ECORE_GETOPT_TYPE_LONG, \ + arg_requirement, \ + {.longv = default_value}) +#define ECORE_GETOPT_STORE_FULL_USHORT(shortname, longname, help, metavar, arg_requirement, default_value) \ + ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, \ + ECORE_GETOPT_TYPE_USHORT, \ + arg_requirement, \ + {.ushortv = default_value}) +#define ECORE_GETOPT_STORE_FULL_UINT(shortname, longname, help, metavar, arg_requirement, default_value) \ + ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, \ + ECORE_GETOPT_TYPE_UINT, \ + arg_requirement, \ + {.uintv = default_value}) +#define ECORE_GETOPT_STORE_FULL_ULONG(shortname, longname, help, metavar, arg_requirement, default_value) \ + ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, \ + ECORE_GETOPT_TYPE_ULONG, \ + arg_requirement, \ + {.ulongv = default_value}) +#define ECORE_GETOPT_STORE_FULL_DOUBLE(shortname, longname, help, metavar, arg_requirement, default_value) \ + ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, \ + ECORE_GETOPT_TYPE_DOUBLE, \ + arg_requirement, \ + {.doublev = default_value}) + +#define ECORE_GETOPT_STORE_CONST(shortname, longname, help, value) \ + {shortname, longname, help, NULL, ECORE_GETOPT_ACTION_STORE_CONST, \ + {.store_const = value}} +#define ECORE_GETOPT_STORE_TRUE(shortname, longname, help) \ + {shortname, longname, help, NULL, ECORE_GETOPT_ACTION_STORE_TRUE, \ + {.dummy = NULL}} +#define ECORE_GETOPT_STORE_FALSE(shortname, longname, help) \ + {shortname, longname, help, NULL, ECORE_GETOPT_ACTION_STORE_FALSE, \ + {.dummy = NULL}} + +#define ECORE_GETOPT_CHOICE(shortname, longname, help, choices_array) \ + {shortname, longname, help, NULL, ECORE_GETOPT_ACTION_CHOICE, \ + {.choices = choices_array}} +#define ECORE_GETOPT_CHOICE_METAVAR(shortname, longname, help, metavar, choices_array) \ + {shortname, longname, help, metavar, ECORE_GETOPT_ACTION_CHOICE, \ + {.choices = choices_array}} + +#define ECORE_GETOPT_APPEND(shortname, longname, help, sub_type) \ + {shortname, longname, help, NULL, ECORE_GETOPT_ACTION_APPEND, \ + {.append_type = sub_type}} +#define ECORE_GETOPT_APPEND_METAVAR(shortname, longname, help, metavar, type) \ + {shortname, longname, help, metavar, ECORE_GETOPT_ACTION_APPEND, \ + {.append_type = type}} + +#define ECORE_GETOPT_COUNT(shortname, longname, help) \ + {shortname, longname, help, NULL, ECORE_GETOPT_ACTION_COUNT, \ + {.dummy = NULL}} + +#define ECORE_GETOPT_CALLBACK_FULL(shortname, longname, help, metavar, callback_func, callback_data, argument_requirement, default_value) \ + {shortname, longname, help, metavar, ECORE_GETOPT_ACTION_CALLBACK, \ + {.callback = {callback_func, callback_data, \ + argument_requirement, default_value}}} +#define ECORE_GETOPT_CALLBACK_NOARGS(shortname, longname, help, callback_func, callback_data) \ + ECORE_GETOPT_CALLBACK_FULL(shortname, longname, help, NULL, \ + callback_func, callback_data, \ + ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO, \ + NULL) +#define ECORE_GETOPT_CALLBACK_ARGS(shortname, longname, help, metavar, callback_func, callback_data) \ + ECORE_GETOPT_CALLBACK_FULL(shortname, longname, help, metavar, \ + callback_func, callback_data, \ + ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES, \ + NULL) + +#define ECORE_GETOPT_HELP(shortname, longname) \ + {shortname, longname, "show this message.", NULL, \ + ECORE_GETOPT_ACTION_HELP, \ + {.dummy = NULL}} + +#define ECORE_GETOPT_VERSION(shortname, longname) \ + {shortname, longname, "show program version.", NULL, \ + ECORE_GETOPT_ACTION_VERSION, \ + {.dummy = NULL}} + +#define ECORE_GETOPT_COPYRIGHT(shortname, longname) \ + {shortname, longname, "show copyright.", NULL, \ + ECORE_GETOPT_ACTION_COPYRIGHT, \ + {.dummy = NULL}} + +#define ECORE_GETOPT_LICENSE(shortname, longname) \ + {shortname, longname, "show license.", NULL, \ + ECORE_GETOPT_ACTION_LICENSE, \ + {.dummy = NULL}} + +#define ECORE_GETOPT_SENTINEL {0, NULL, NULL, NULL, 0, {.dummy = NULL}} + +#define ECORE_GETOPT_VALUE_STR(val) {.strp = &(val)} +#define ECORE_GETOPT_VALUE_BOOL(val) {.boolp = &(val)} +#define ECORE_GETOPT_VALUE_SHORT(val) {.shortp = &(val)} +#define ECORE_GETOPT_VALUE_INT(val) {.intp = &(val)} +#define ECORE_GETOPT_VALUE_LONG(val) {.longp = &(val)} +#define ECORE_GETOPT_VALUE_USHORT(val) {.ushortp = &(val)} +#define ECORE_GETOPT_VALUE_UINT(val) {.uintp = &(val)} +#define ECORE_GETOPT_VALUE_ULONG(val) {.ulongp = &(val)} +#define ECORE_GETOPT_VALUE_DOUBLE(val) {.doublep = &(val)} +#define ECORE_GETOPT_VALUE_PTR(val) {.ptrp = &(val)} +#define ECORE_GETOPT_VALUE_PTR_CAST(val) {.ptrp = (void **)&(val)} +#define ECORE_GETOPT_VALUE_LIST(val) {.listp = &(val)} +#define ECORE_GETOPT_VALUE_NONE {.ptrp = NULL} + +EAPI void +ecore_getopt_help(FILE *fp, + const Ecore_Getopt *info); + +EAPI Eina_Bool + ecore_getopt_parser_has_duplicates(const Ecore_Getopt *parser); +EAPI int + ecore_getopt_parse(const Ecore_Getopt *parser, + Ecore_Getopt_Value *values, + int argc, + char **argv); + +EAPI Eina_List *ecore_getopt_list_free(Eina_List *list); + +/* helper functions to be used with ECORE_GETOPT_CALLBACK_*() */ +EAPI Eina_Bool +ecore_getopt_callback_geometry_parse(const Ecore_Getopt *parser, + const Ecore_Getopt_Desc *desc, + const char *str, + void *data, + Ecore_Getopt_Value *storage); +EAPI Eina_Bool +ecore_getopt_callback_size_parse(const Ecore_Getopt *parser, + const Ecore_Getopt_Desc *desc, + const char *str, + void *data, + Ecore_Getopt_Value *storage); + +#ifdef __cplusplus +} +#endif +#endif /* _ECORE_GETOPT_H */ diff --git a/src/lib/ecore/Makefile.am b/src/lib/ecore/Makefile.am new file mode 100644 index 0000000..6f14387 --- /dev/null +++ b/src/lib/ecore/Makefile.am @@ -0,0 +1,69 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = @GLIB_CFLAGS@ @EVIL_CFLAGS@ @EINA_CFLAGS@ @WIN32_CPPFLAGS@ @EFL_ECORE_BUILD@ +AM_CFLAGS = @WIN32_CFLAGS@ @EFL_PTHREAD_CFLAGS@ + +lib_LTLIBRARIES = libecore.la +includes_HEADERS = \ +Ecore.h \ +Ecore_Getopt.h +includesdir = $(includedir)/ecore-@VMAJ@ + +libecore_la_SOURCES = \ +ecore.c \ +ecore_alloc.c \ +ecore_anim.c \ +ecore_app.c \ +ecore_events.c \ +ecore_getopt.c \ +ecore_idle_enterer.c \ +ecore_idle_exiter.c \ +ecore_idler.c \ +ecore_job.c \ +ecore_main.c \ +ecore_pipe.c \ +ecore_poll.c \ +ecore_time.c \ +ecore_timer.c \ +ecore_thread.c \ +ecore_glib.c \ +ecore_throttle.c + +if ECORE_HAVE_WIN32 + +libecore_la_SOURCES += ecore_exe_win32.c + +else + +if ECORE_HAVE_WINCE + +libecore_la_SOURCES += ecore_exe_wince.c + +else + +if ECORE_HAVE_PS3 + +libecore_la_SOURCES += ecore_exe_ps3.c + +else + +if ECORE_HAVE_EXOTIC + +libecore_la_SOURCES += + +else + +libecore_la_SOURCES += ecore_signal.c ecore_exe.c + +endif + +endif + +endif + +endif + +libecore_la_LIBADD = @dlopen_libs@ @EINA_LIBS@ @EVIL_LIBS@ @GLIB_LIBS@ @WIN32_LIBS@ @LTLIBINTL@ @EFL_PTHREAD_LIBS@ @rt_libs@ -lm +libecore_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ @EFL_PTHREAD_LIBS@ + +EXTRA_DIST = ecore_private.h diff --git a/src/lib/ecore/ecore.c b/src/lib/ecore/ecore.c new file mode 100644 index 0000000..0df319b --- /dev/null +++ b/src/lib/ecore/ecore.c @@ -0,0 +1,854 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include + +#ifndef _MSC_VER +# include +#endif + +#ifdef HAVE_LOCALE_H +# include +#endif + +#ifdef HAVE_LANGINFO_H +# include +#endif + +#ifdef HAVE_SYS_MMAN_H +# include +#endif + +#ifdef HAVE_EVIL +# include +#endif +#include + +#include "Ecore.h" +#include "ecore_private.h" + +#if HAVE_MALLINFO +#include + +static Ecore_Version _version = { VERS_MAJ, VERS_MIN, VERS_MIC, VERS_REV }; +EAPI Ecore_Version *ecore_version = &_version; + +#define KEEP_MAX(Global, Local) \ + if (Global < (Local)) \ + Global = Local; + +static Eina_Bool _ecore_memory_statistic(void *data); +static int _ecore_memory_max_total = 0; +static int _ecore_memory_max_free = 0; +static pid_t _ecore_memory_pid = 0; +#endif + +static const char *_ecore_magic_string_get(Ecore_Magic m); +static int _ecore_init_count = 0; +int _ecore_log_dom = -1; +int _ecore_fps_debug = 0; + +typedef struct _Ecore_Safe_Call Ecore_Safe_Call; +struct _Ecore_Safe_Call +{ + union { + Ecore_Cb async; + Ecore_Data_Cb sync; + } cb; + void *data; + + Eina_Lock m; + Eina_Condition c; + + int current_id; + + Eina_Bool sync : 1; + Eina_Bool suspend : 1; +}; + +static void _ecore_main_loop_thread_safe_call(Ecore_Safe_Call *order); +static void _thread_safe_cleanup(void *data); +static void _thread_callback(void *data, + void *buffer, + unsigned int nbyte); +static Eina_List *_thread_cb = NULL; +static Ecore_Pipe *_thread_call = NULL; +static Eina_Lock _thread_safety; +static const int wakeup = 42; + +static int _thread_loop = 0; +static Eina_Lock _thread_mutex; +static Eina_Condition _thread_cond; +static Eina_Lock _thread_feedback_mutex; +static Eina_Condition _thread_feedback_cond; + +static Eina_Lock _thread_id_lock; +static int _thread_id = -1; +static int _thread_id_max = 0; +static int _thread_id_update = 0; + +Eina_Lock _ecore_main_loop_lock; +int _ecore_main_lock_count; + +/** OpenBSD does not define CODESET + * FIXME ?? + */ + +#ifndef CODESET +# define CODESET "INVALID" +#endif + +/** + * @addtogroup Ecore_Init_Group + * + * @{ + */ + +/** + * Set up connections, signal handlers, sockets etc. + * @return 1 or greater on success, 0 otherwise + * + * This function sets up all singal handlers and the basic event loop. If it + * succeeds, 1 will be returned, otherwise 0 will be returned. + * + * @code + * #include + * + * int main(int argc, char **argv) + * { + * if (!ecore_init()) + * { + * printf("ERROR: Cannot init Ecore!\n"); + * return -1; + * } + * ecore_main_loop_begin(); + * ecore_shutdown(); + * } + * @endcode + */ +EAPI int +ecore_init(void) +{ + if (++_ecore_init_count != 1) + return _ecore_init_count; + +#ifdef HAVE_LOCALE_H + setlocale(LC_CTYPE, ""); +#endif + /* + if (strcmp(nl_langinfo(CODESET), "UTF-8")) + { + WRN("Not a utf8 locale!"); + } + */ +#ifdef HAVE_EVIL + if (!evil_init()) + return --_ecore_init_count; +#endif + if (!eina_init()) + goto shutdown_evil; + _ecore_log_dom = eina_log_domain_register("ecore", ECORE_DEFAULT_LOG_COLOR); + if (_ecore_log_dom < 0) + { + EINA_LOG_ERR("Ecore was unable to create a log domain."); + goto shutdown_log_dom; + } + if (getenv("ECORE_FPS_DEBUG")) _ecore_fps_debug = 1; + if (_ecore_fps_debug) _ecore_fps_debug_init(); + if (!ecore_mempool_init()) goto shutdown_mempool; + _ecore_main_loop_init(); + _ecore_signal_init(); +#ifndef HAVE_EXOTIC + _ecore_exe_init(); +#endif + _ecore_thread_init(); + _ecore_glib_init(); + _ecore_job_init(); + _ecore_time_init(); + + eina_lock_new(&_thread_mutex); + eina_condition_new(&_thread_cond, &_thread_mutex); + eina_lock_new(&_thread_feedback_mutex); + eina_condition_new(&_thread_feedback_cond, &_thread_feedback_mutex); + _thread_call = ecore_pipe_add(_thread_callback, NULL); + eina_lock_new(&_thread_safety); + + eina_lock_new(&_thread_id_lock); + + eina_lock_new(&_ecore_main_loop_lock); + +#if HAVE_MALLINFO + if (getenv("ECORE_MEM_STAT")) + { + _ecore_memory_pid = getpid(); + ecore_animator_add(_ecore_memory_statistic, NULL); + } +#endif + +#if defined(GLIB_INTEGRATION_ALWAYS) + if (_ecore_glib_always_integrate) ecore_main_loop_glib_integrate(); +#endif + + return _ecore_init_count; + +shutdown_mempool: + ecore_mempool_shutdown(); +shutdown_log_dom: + eina_shutdown(); +shutdown_evil: +#ifdef HAVE_EVIL + evil_shutdown(); +#endif + return --_ecore_init_count; +} + +/** + * Shut down connections, signal handlers sockets etc. + * + * @return 0 if ecore shuts down, greater than 0 otherwise. + * This function shuts down all things set up in ecore_init() and cleans up all + * event queues, handlers, filters, timers, idlers, idle enterers/exiters + * etc. set up after ecore_init() was called. + * + * Do not call this function from any callback that may be called from the main + * loop, as the main loop will then fall over and not function properly. + */ +EAPI int +ecore_shutdown(void) +{ + Ecore_Pipe *p; + /* + * take a lock here because _ecore_event_shutdown() does callbacks + */ + _ecore_lock(); + if (_ecore_init_count <= 0) + { + ERR("Init count not greater than 0 in shutdown."); + _ecore_unlock(); + return 0; + } + if (--_ecore_init_count != 0) + goto unlock; + + if (_ecore_fps_debug) _ecore_fps_debug_shutdown(); + _ecore_poller_shutdown(); + _ecore_animator_shutdown(); + _ecore_glib_shutdown(); + _ecore_job_shutdown(); + _ecore_thread_shutdown(); + + /* this looks horrible - a hack for now, but something to note. as + * we delete the _thread_call pipe a thread COULD be doing + * ecore_pipe_write() or what not to it at the same time - we + * must ensure all possible users of this _thread_call are finished + * and exited before we delete it here */ + /* + * ok - this causes other valgrind complaints regarding glib aquiring + * locks internally. so fix bug a or bug b. let's leave the original + * bug in then and leave this as a note for now + */ + /* + * It should be fine now as we do wait for thread to shutdown before + * we try to destroy the pipe. + */ + p = _thread_call; + _thread_call = NULL; + ecore_pipe_wait(p, 1, 0.1); + ecore_pipe_del(p); + eina_lock_free(&_thread_safety); + eina_condition_free(&_thread_cond); + eina_lock_free(&_thread_mutex); + eina_condition_free(&_thread_feedback_cond); + eina_lock_free(&_thread_feedback_mutex); + eina_lock_free(&_thread_id_lock); + + +#ifndef HAVE_EXOTIC + _ecore_exe_shutdown(); +#endif + _ecore_idle_enterer_shutdown(); + _ecore_idle_exiter_shutdown(); + _ecore_idler_shutdown(); + _ecore_timer_shutdown(); + _ecore_event_shutdown(); + _ecore_main_shutdown(); + _ecore_signal_shutdown(); + _ecore_main_loop_shutdown(); + +#if HAVE_MALLINFO + if (getenv("ECORE_MEM_STAT")) + { + _ecore_memory_statistic(NULL); + + ERR("[%i] Memory MAX total: %i, free: %i", + _ecore_memory_pid, + _ecore_memory_max_total, + _ecore_memory_max_free); + } +#endif + ecore_mempool_shutdown(); + eina_log_domain_unregister(_ecore_log_dom); + _ecore_log_dom = -1; + eina_shutdown(); +#ifdef HAVE_EVIL + evil_shutdown(); +#endif +unlock: + _ecore_unlock(); + + return _ecore_init_count; +} + +struct _Ecore_Fork_Cb +{ + Ecore_Cb func; + void *data; + Eina_Bool delete_me : 1; +}; + +typedef struct _Ecore_Fork_Cb Ecore_Fork_Cb; + +static int fork_cbs_walking = 0; +static Eina_List *fork_cbs = NULL; + +EAPI Eina_Bool +ecore_fork_reset_callback_add(Ecore_Cb func, const void *data) +{ + Ecore_Fork_Cb *fcb; + + fcb = calloc(1, sizeof(Ecore_Fork_Cb)); + if (!fcb) return EINA_FALSE; + fcb->func = func; + fcb->data = (void *)data; + fork_cbs = eina_list_append(fork_cbs, fcb); + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_fork_reset_callback_del(Ecore_Cb func, const void *data) +{ + Eina_List *l; + Ecore_Fork_Cb *fcb; + + EINA_LIST_FOREACH(fork_cbs, l, fcb) + { + if ((fcb->func == func) && (fcb->data == data)) + { + if (!fork_cbs_walking) + { + fork_cbs = eina_list_remove_list(fork_cbs, l); + free(fcb); + } + else + fcb->delete_me = EINA_TRUE; + return EINA_TRUE; + } + } + return EINA_FALSE; +} + +EAPI void +ecore_fork_reset(void) +{ + Eina_List *l, *ln; + Ecore_Fork_Cb *fcb; + + eina_lock_take(&_thread_safety); + + ecore_pipe_del(_thread_call); + _thread_call = ecore_pipe_add(_thread_callback, NULL); + /* If there was something in the pipe, trigger a wakeup again */ + if (_thread_cb) ecore_pipe_write(_thread_call, &wakeup, sizeof (int)); + + eina_lock_release(&_thread_safety); + + // should this be done withing the eina lock stuff? + + fork_cbs_walking++; + EINA_LIST_FOREACH(fork_cbs, l, fcb) + { + fcb->func(fcb->data); + } + fork_cbs_walking--; + + EINA_LIST_FOREACH_SAFE(fork_cbs, l, ln, fcb) + { + if (fcb->delete_me) + { + fork_cbs = eina_list_remove_list(fork_cbs, l); + free(fcb); + } + } +} + +/** + * @} + */ + +EAPI void +ecore_main_loop_thread_safe_call_async(Ecore_Cb callback, + void *data) +{ + Ecore_Safe_Call *order; + + if (!callback) return; + + if (eina_main_loop_is()) + { + callback(data); + return; + } + + order = malloc(sizeof (Ecore_Safe_Call)); + if (!order) return; + + order->cb.async = callback; + order->data = data; + order->sync = EINA_FALSE; + order->suspend = EINA_FALSE; + + _ecore_main_loop_thread_safe_call(order); +} + +EAPI void * +ecore_main_loop_thread_safe_call_sync(Ecore_Data_Cb callback, + void *data) +{ + Ecore_Safe_Call *order; + void *ret; + + if (!callback) return NULL; + + if (eina_main_loop_is()) + { + return callback(data); + } + + order = malloc(sizeof (Ecore_Safe_Call)); + if (!order) return NULL; + + order->cb.sync = callback; + order->data = data; + eina_lock_new(&order->m); + eina_condition_new(&order->c, &order->m); + order->sync = EINA_TRUE; + order->suspend = EINA_FALSE; + + _ecore_main_loop_thread_safe_call(order); + + eina_lock_take(&order->m); + eina_condition_wait(&order->c); + eina_lock_release(&order->m); + + ret = order->data; + + order->sync = EINA_FALSE; + order->cb.async = _thread_safe_cleanup; + order->data = order; + + _ecore_main_loop_thread_safe_call(order); + + return ret; +} + +EAPI int +ecore_thread_main_loop_begin(void) +{ + Ecore_Safe_Call *order; + + if (eina_main_loop_is()) + { + return ++_thread_loop; + } + + order = malloc(sizeof (Ecore_Safe_Call)); + if (!order) return -1; + + eina_lock_take(&_thread_id_lock); + order->current_id = ++_thread_id_max; + if (order->current_id < 0) + { + _thread_id_max = 0; + order->current_id = ++_thread_id_max; + } + eina_lock_release(&_thread_id_lock); + + eina_lock_new(&order->m); + eina_condition_new(&order->c, &order->m); + order->suspend = EINA_TRUE; + + _ecore_main_loop_thread_safe_call(order); + + eina_lock_take(&order->m); + while (order->current_id != _thread_id) + eina_condition_wait(&order->c); + eina_lock_release(&order->m); + + eina_main_loop_define(); + + _thread_loop = 1; + + return EINA_TRUE; +} + +EAPI int +ecore_thread_main_loop_end(void) +{ + int current_id; + + if (_thread_loop == 0) + { + ERR("the main loop is not locked ! No matching call to ecore_thread_main_loop_begin()."); + return -1; + } + + /* until we unlock the main loop, this thread has the main loop id */ + if (!eina_main_loop_is()) + { + ERR("Not in a locked thread !"); + return -1; + } + + _thread_loop--; + if (_thread_loop > 0) + return _thread_loop; + + current_id = _thread_id; + + eina_lock_take(&_thread_mutex); + _thread_id_update = _thread_id; + eina_condition_broadcast(&_thread_cond); + eina_lock_release(&_thread_mutex); + + eina_lock_take(&_thread_feedback_mutex); + while (current_id == _thread_id && _thread_id != -1) + eina_condition_wait(&_thread_feedback_cond); + eina_lock_release(&_thread_feedback_mutex); + + return 0; +} + +EAPI void +ecore_print_warning(const char *function __UNUSED__, + const char *sparam __UNUSED__) +{ + WRN("***** Developer Warning ***** :\n" + "\tThis program is calling:\n\n" + "\t%s();\n\n" + "\tWith the parameter:\n\n" + "\t%s\n\n" + "\tbeing NULL. Please fix your program.", function, sparam); + if (getenv("ECORE_ERROR_ABORT")) abort(); +} + +EAPI void +_ecore_magic_fail(const void *d, + Ecore_Magic m, + Ecore_Magic req_m, + const char *fname __UNUSED__) +{ + ERR("\n" + "*** ECORE ERROR: Ecore Magic Check Failed!!!\n" + "*** IN FUNCTION: %s()", fname); + if (!d) + ERR(" Input handle pointer is NULL!"); + else if (m == ECORE_MAGIC_NONE) + ERR(" Input handle has already been freed!"); + else if (m != req_m) + ERR(" Input handle is wrong type\n" + " Expected: %08x - %s\n" + " Supplied: %08x - %s", + (unsigned int)req_m, _ecore_magic_string_get(req_m), + (unsigned int)m, _ecore_magic_string_get(m)); + ERR("*** NAUGHTY PROGRAMMER!!!\n" + "*** SPANK SPANK SPANK!!!\n" + "*** Now go fix your code. Tut tut tut!"); + if (getenv("ECORE_ERROR_ABORT")) abort(); +} + +static const char * +_ecore_magic_string_get(Ecore_Magic m) +{ + switch (m) + { + case ECORE_MAGIC_NONE: + return "None (Freed Object)"; + break; + + case ECORE_MAGIC_EXE: + return "Ecore_Exe (Executable)"; + break; + + case ECORE_MAGIC_TIMER: + return "Ecore_Timer (Timer)"; + break; + + case ECORE_MAGIC_IDLER: + return "Ecore_Idler (Idler)"; + break; + + case ECORE_MAGIC_IDLE_ENTERER: + return "Ecore_Idle_Enterer (Idler Enterer)"; + break; + + case ECORE_MAGIC_IDLE_EXITER: + return "Ecore_Idle_Exiter (Idler Exiter)"; + break; + + case ECORE_MAGIC_FD_HANDLER: + return "Ecore_Fd_Handler (Fd Handler)"; + break; + + case ECORE_MAGIC_WIN32_HANDLER: + return "Ecore_Win32_Handler (Win32 Handler)"; + break; + + case ECORE_MAGIC_EVENT_HANDLER: + return "Ecore_Event_Handler (Event Handler)"; + break; + + case ECORE_MAGIC_EVENT: + return "Ecore_Event (Event)"; + break; + + default: + return ""; + } +} + +/* fps debug calls - for debugging how much time your app actually spends */ +/* "running" (and the inverse being time spent running)... this does not */ +/* account for other apps and multitasking... */ + +static int _ecore_fps_debug_init_count = 0; +static int _ecore_fps_debug_fd = -1; +unsigned int *_ecore_fps_runtime_mmap = NULL; + +void +_ecore_fps_debug_init(void) +{ + char buf[PATH_MAX]; + const char *tmp; + int pid; + + _ecore_fps_debug_init_count++; + if (_ecore_fps_debug_init_count > 1) return; + +#ifndef HAVE_EVIL + tmp = "/tmp"; +#else + tmp = evil_tmpdir_get (); +#endif /* HAVE_EVIL */ + pid = (int)getpid(); + snprintf(buf, sizeof(buf), "%s/.ecore_fps_debug-%i", tmp, pid); + _ecore_fps_debug_fd = open(buf, O_CREAT | O_TRUNC | O_RDWR, 0644); + if (_ecore_fps_debug_fd < 0) + { + unlink(buf); + _ecore_fps_debug_fd = open(buf, O_CREAT | O_TRUNC | O_RDWR, 0644); + } + if (_ecore_fps_debug_fd >= 0) + { + unsigned int zero = 0; + char *buf2 = (char *)&zero; + ssize_t todo = sizeof(unsigned int); + + while (todo > 0) + { + ssize_t r = write(_ecore_fps_debug_fd, buf2, todo); + if (r > 0) + { + todo -= r; + buf2 += r; + } + else if ((r < 0) && (errno == EINTR)) + continue; + else + { + ERR("could not write to file '%s' fd %d: %s", + tmp, _ecore_fps_debug_fd, strerror(errno)); + close(_ecore_fps_debug_fd); + _ecore_fps_debug_fd = -1; + return; + } + } + _ecore_fps_runtime_mmap = mmap(NULL, sizeof(unsigned int), + PROT_READ | PROT_WRITE, + MAP_SHARED, + _ecore_fps_debug_fd, 0); + if (_ecore_fps_runtime_mmap == MAP_FAILED) + _ecore_fps_runtime_mmap = NULL; + } +} + +void +_ecore_fps_debug_shutdown(void) +{ + _ecore_fps_debug_init_count--; + if (_ecore_fps_debug_init_count > 0) return; + if (_ecore_fps_debug_fd >= 0) + { + char buf[4096]; + const char *tmp; + int pid; + +#ifndef HAVE_EVIL + tmp = "/tmp"; +#else + tmp = (char *)evil_tmpdir_get (); +#endif /* HAVE_EVIL */ + pid = (int)getpid(); + snprintf(buf, sizeof(buf), "%s/.ecore_fps_debug-%i", tmp, pid); + unlink(buf); + if (_ecore_fps_runtime_mmap) + { + munmap(_ecore_fps_runtime_mmap, sizeof(int)); + _ecore_fps_runtime_mmap = NULL; + } + close(_ecore_fps_debug_fd); + _ecore_fps_debug_fd = -1; + } +} + +void +_ecore_fps_debug_runtime_add(double t) +{ + if ((_ecore_fps_debug_fd >= 0) && + (_ecore_fps_runtime_mmap)) + { + unsigned int tm; + + tm = (unsigned int)(t * 1000000.0); + /* i know its not 100% theoretically guaranteed, but i'd say a write */ + /* of an int could be considered atomic for all practical purposes */ + /* oh and since this is cumulative, 1 second = 1,000,000 ticks, so */ + /* this can run for about 4294 seconds becore looping. if you are */ + /* doing performance testing in one run for over an hour... well */ + /* time to restart or handle a loop condition :) */ + *(_ecore_fps_runtime_mmap) += tm; + } +} + +#if HAVE_MALLINFO +static Eina_Bool +_ecore_memory_statistic(__UNUSED__ void *data) +{ + struct mallinfo mi; + static int uordblks = 0; + static int fordblks = 0; + Eina_Bool changed = EINA_FALSE; + + mi = mallinfo(); + +#define HAS_CHANGED(Global, Local) \ + if (Global != Local) \ + { \ + Global = Local; \ + changed = EINA_TRUE; \ + } + + HAS_CHANGED(uordblks, mi.uordblks); + HAS_CHANGED(fordblks, mi.fordblks); + + if (changed) + ERR("[%i] Memory total: %i, free: %i", + _ecore_memory_pid, + mi.uordblks, + mi.fordblks); + + KEEP_MAX(_ecore_memory_max_total, mi.uordblks); + KEEP_MAX(_ecore_memory_max_free, mi.fordblks); + + return ECORE_CALLBACK_RENEW; +} + +#endif + +static void +_ecore_main_loop_thread_safe_call(Ecore_Safe_Call *order) +{ + Eina_Bool count; + + eina_lock_take(&_thread_safety); + + count = _thread_cb ? 0 : 1; + _thread_cb = eina_list_append(_thread_cb, order); + if (count) ecore_pipe_write(_thread_call, &wakeup, sizeof (int)); + + eina_lock_release(&_thread_safety); +} + +static void +_thread_safe_cleanup(void *data) +{ + Ecore_Safe_Call *call = data; + + eina_condition_free(&call->c); + eina_lock_free(&call->m); +} + +void +_ecore_main_call_flush(void) +{ + Ecore_Safe_Call *call; + Eina_List *callback; + + eina_lock_take(&_thread_safety); + callback = _thread_cb; + _thread_cb = NULL; + eina_lock_release(&_thread_safety); + + EINA_LIST_FREE(callback, call) + { + if (call->suspend) + { + eina_lock_take(&_thread_mutex); + + eina_lock_take(&call->m); + _thread_id = call->current_id; + eina_condition_broadcast(&call->c); + eina_lock_release(&call->m); + + while (_thread_id_update != _thread_id) + eina_condition_wait(&_thread_cond); + eina_lock_release(&_thread_mutex); + + eina_main_loop_define(); + + eina_lock_take(&_thread_feedback_mutex); + + _thread_id = -1; + + eina_condition_broadcast(&_thread_feedback_cond); + eina_lock_release(&_thread_feedback_mutex); + + _thread_safe_cleanup(call); + free(call); + } + else if (call->sync) + { + call->data = call->cb.sync(call->data); + eina_condition_broadcast(&call->c); + } + else + { + call->cb.async(call->data); + free(call); + } + } +} + +static void +_thread_callback(void *data __UNUSED__, + void *buffer __UNUSED__, + unsigned int nbyte __UNUSED__) +{ + _ecore_main_call_flush(); +} + diff --git a/src/lib/ecore/ecore_alloc.c b/src/lib/ecore/ecore_alloc.c new file mode 100644 index 0000000..58aa131 --- /dev/null +++ b/src/lib/ecore/ecore_alloc.c @@ -0,0 +1,132 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include + +#include "Ecore.h" +#include "ecore_private.h" + +typedef struct _Ecore_Mempool Ecore_Mempool; +struct _Ecore_Mempool +{ + const char *name; + Eina_Mempool *mp; + size_t size; +}; + +#define GENERIC_ALLOC_FREE(TYPE, Type) \ + extern size_t _ecore_sizeof_##TYPE; \ + Ecore_Mempool Type##_mp = { #TYPE, NULL, 0 }; \ + TYPE * \ + Type##_calloc(unsigned int num) \ + { \ + return eina_mempool_calloc(Type##_mp.mp, \ + num * _ecore_sizeof_##TYPE); \ + } \ + void \ + Type##_mp_free(TYPE *e) \ + { \ + eina_mempool_free(Type##_mp.mp, e); \ + } + +GENERIC_ALLOC_FREE(Ecore_Animator, ecore_animator); +GENERIC_ALLOC_FREE(Ecore_Event_Handler, ecore_event_handler); +GENERIC_ALLOC_FREE(Ecore_Event_Filter, ecore_event_filter); +GENERIC_ALLOC_FREE(Ecore_Event, ecore_event); +GENERIC_ALLOC_FREE(Ecore_Idle_Exiter, ecore_idle_exiter); +GENERIC_ALLOC_FREE(Ecore_Idle_Enterer, ecore_idle_enterer); +GENERIC_ALLOC_FREE(Ecore_Idler, ecore_idler); +GENERIC_ALLOC_FREE(Ecore_Job, ecore_job); +GENERIC_ALLOC_FREE(Ecore_Timer, ecore_timer); +GENERIC_ALLOC_FREE(Ecore_Poller, ecore_poller); +GENERIC_ALLOC_FREE(Ecore_Pipe, ecore_pipe); +GENERIC_ALLOC_FREE(Ecore_Fd_Handler, ecore_fd_handler); +#ifdef _WIN32 +GENERIC_ALLOC_FREE(Ecore_Win32_Handler, ecore_win32_handler); +#endif + +static Ecore_Mempool *mempool_array[] = { + &ecore_animator_mp, + &ecore_event_handler_mp, + &ecore_event_filter_mp, + &ecore_event_mp, + &ecore_idle_exiter_mp, + &ecore_idle_enterer_mp, + &ecore_idler_mp, + &ecore_job_mp, + &ecore_timer_mp, + &ecore_poller_mp, + &ecore_pipe_mp, + &ecore_fd_handler_mp, +#ifdef _WIN32 + &ecore_win32_handler_mp +#endif +}; + +Eina_Bool +ecore_mempool_init(void) +{ + const char *choice; + unsigned int i; + +#define MP_SIZE_INIT(TYPE, Type) \ + Type##_mp.size = _ecore_sizeof_##TYPE + + MP_SIZE_INIT(Ecore_Animator, ecore_animator); + MP_SIZE_INIT(Ecore_Event_Handler, ecore_event_handler); + MP_SIZE_INIT(Ecore_Event_Filter, ecore_event_filter); + MP_SIZE_INIT(Ecore_Event, ecore_event); + MP_SIZE_INIT(Ecore_Idle_Exiter, ecore_idle_exiter); + MP_SIZE_INIT(Ecore_Idle_Enterer, ecore_idle_enterer); + MP_SIZE_INIT(Ecore_Idler, ecore_idler); + MP_SIZE_INIT(Ecore_Job, ecore_job); + MP_SIZE_INIT(Ecore_Timer, ecore_timer); + MP_SIZE_INIT(Ecore_Poller, ecore_poller); + MP_SIZE_INIT(Ecore_Pipe, ecore_pipe); + MP_SIZE_INIT(Ecore_Fd_Handler, ecore_fd_handler); +#ifdef _WIN32 + MP_SIZE_INIT(Ecore_Win32_Handler, ecore_win32_handler); +#endif +#undef MP_SIZE_INIT + + choice = getenv("EINA_MEMPOOL"); + if ((!choice) || (!choice[0])) + choice = "chained_mempool"; + + for (i = 0; i < sizeof (mempool_array) / sizeof (mempool_array[0]); ++i) + { + retry: + mempool_array[i]->mp = eina_mempool_add(choice, mempool_array[i]->name, NULL, mempool_array[i]->size, 16); + if (!mempool_array[i]->mp) + { + if (!(!strcmp(choice, "pass_through"))) + { + ERR("Falling back to pass through ! Previously tried '%s' mempool.", choice); + choice = "pass_through"; + goto retry; + } + else + { + ERR("Impossible to allocate mempool '%s' !", choice); + return EINA_FALSE; + } + } + } + return EINA_TRUE; +} + +void +ecore_mempool_shutdown(void) +{ + unsigned int i; + + for (i = 0; i < sizeof (mempool_array) / sizeof (mempool_array[0]); ++i) + { + eina_mempool_del(mempool_array[i]->mp); + mempool_array[i]->mp = NULL; + } +} + diff --git a/src/lib/ecore/ecore_anim.c b/src/lib/ecore/ecore_anim.c new file mode 100644 index 0000000..67bf8b1 --- /dev/null +++ b/src/lib/ecore/ecore_anim.c @@ -0,0 +1,516 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "Ecore.h" +#include "ecore_private.h" + +struct _Ecore_Animator +{ + EINA_INLIST; + ECORE_MAGIC; + + Ecore_Task_Cb func; + void *data; + + double start, run; + Ecore_Timeline_Cb run_func; + void *run_data; + + Eina_Bool delete_me : 1; + Eina_Bool suspended : 1; + Eina_Bool just_added : 1; +}; + +GENERIC_ALLOC_SIZE_DECLARE(Ecore_Animator); + +static Eina_Bool _ecore_animator_run(void *data); +static Eina_Bool _ecore_animator(void *data); + +static int animators_delete_me = 0; +static Ecore_Animator *animators = NULL; +static double animators_frametime = 1.0 / 30.0; + +static Ecore_Animator_Source src = ECORE_ANIMATOR_SOURCE_TIMER; +static Ecore_Timer *timer = NULL; +static int ticking = 0; +static Ecore_Cb begin_tick_cb = NULL; +static const void *begin_tick_data = NULL; +static Ecore_Cb end_tick_cb = NULL; +static const void *end_tick_data = NULL; + +static void +_begin_tick(void) +{ + if (ticking) return; + ticking = 1; + switch (src) + { + case ECORE_ANIMATOR_SOURCE_TIMER: + if (!timer) + { + double t_loop = ecore_loop_time_get(); + double sync_0 = 0.0; + double d = -fmod(t_loop - sync_0, animators_frametime); + + timer = _ecore_timer_loop_add(animators_frametime, + _ecore_animator, NULL); + _ecore_timer_delay(timer, d); + } + break; + + case ECORE_ANIMATOR_SOURCE_CUSTOM: + if (begin_tick_cb) begin_tick_cb((void *)begin_tick_data); + break; + + default: + break; + } +} + +static void +_end_tick(void) +{ + if (!ticking) return; + ticking = 0; + switch (src) + { + case ECORE_ANIMATOR_SOURCE_TIMER: + if (timer) + { + _ecore_timer_del(timer); + timer = NULL; + } + break; + + case ECORE_ANIMATOR_SOURCE_CUSTOM: + if (end_tick_cb) end_tick_cb((void *)end_tick_data); + break; + + default: + break; + } +} + +static Eina_Bool +_do_tick(void) +{ + Ecore_Animator *animator; + + EINA_INLIST_FOREACH(animators, animator) + { + animator->just_added = EINA_FALSE; + } + EINA_INLIST_FOREACH(animators, animator) + { + if ((!animator->delete_me) && + (!animator->suspended) && + (!animator->just_added)) + { + if (!_ecore_call_task_cb(animator->func, animator->data)) + { + animator->delete_me = EINA_TRUE; + animators_delete_me++; + } + } + else animator->just_added = EINA_FALSE; + } + if (animators_delete_me) + { + Ecore_Animator *l; + for (l = animators; l; ) + { + animator = l; + l = (Ecore_Animator *)EINA_INLIST_GET(l)->next; + if (animator->delete_me) + { + animators = (Ecore_Animator *) + eina_inlist_remove(EINA_INLIST_GET(animators), + EINA_INLIST_GET(animator)); + ECORE_MAGIC_SET(animator, ECORE_MAGIC_NONE); + ecore_animator_mp_free(animator); + animators_delete_me--; + if (animators_delete_me == 0) break; + } + } + } + if (!animators) + { + _end_tick(); + return ECORE_CALLBACK_CANCEL; + } + return ECORE_CALLBACK_RENEW; +} + +static Ecore_Animator * +_ecore_animator_add(Ecore_Task_Cb func, + const void *data) +{ + Ecore_Animator *animator = NULL; + + if (!func) return animator; + animator = ecore_animator_calloc(1); + if (!animator) return animator; + ECORE_MAGIC_SET(animator, ECORE_MAGIC_ANIMATOR); + animator->func = func; + animator->data = (void *)data; + animator->just_added = EINA_TRUE; + animators = (Ecore_Animator *)eina_inlist_append(EINA_INLIST_GET(animators), EINA_INLIST_GET(animator)); + _begin_tick(); + return animator; +} + +EAPI Ecore_Animator * +ecore_animator_add(Ecore_Task_Cb func, + const void *data) +{ + Ecore_Animator *animator; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); + animator = _ecore_animator_add(func, data); + _ecore_unlock(); + + return animator; +} + +EAPI Ecore_Animator * +ecore_animator_timeline_add(double runtime, + Ecore_Timeline_Cb func, + const void *data) +{ + Ecore_Animator *animator; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); + if (runtime <= 0.0) runtime = 0.0; + animator = _ecore_animator_add(_ecore_animator_run, NULL); + animator->data = animator; + animator->run_func = func; + animator->run_data = (void *)data; + animator->start = ecore_loop_time_get(); + animator->run = runtime; + _ecore_unlock(); + return animator; +} + +static double +_pos_map_sin(double in) +{ + return eina_f32p32_double_to(eina_f32p32_sin(eina_f32p32_double_from(in))); +} + +#if 0 +static double +_pos_map_cos(double in) +{ + return eina_f32p32_double_to(eina_f32p32_cos(eina_f32p32_double_from(in))); +} +#endif + +static double +_pos_map_accel_factor(double pos, + double v1) +{ + int i, fact = (int)v1; + double p, o1 = pos, o2, v; + p = 1.0 - _pos_map_sin((M_PI / 2.0) + ((pos * M_PI) / 2.0)); + o2 = p; + for (i = 0; i < fact; i++) + { + o1 = o2; + o2 = o2 * p; + } + v = v1 - (double)fact; + pos = (v * o2) + ((1.0 - v) * o1); + return pos; +} + +static double +_pos_map_pow(double pos, + double divis, + int p) +{ + double v = 1.0; + int i; + for (i = 0; i < p; i++) v *= pos; + return ((pos * divis) * (1.0 - v)) + (pos * v); +} + +static double +_pos_map_spring(double pos, + int bounces, + double decfac) +{ + int segnum, segpos, b1, b2; + double len, decay, decpos, p2; + if (bounces < 0) bounces = 0; + p2 = _pos_map_pow(pos, 0.5, 3); + len = (M_PI / 2.0) + ((double)bounces * M_PI); + segnum = (bounces * 2) + 1; + segpos = 2 * (((int)(p2 * segnum) + 1) / 2); + b1 = segpos; + b2 = segnum + 1; + if (b1 < 0) b1 = 0; + decpos = (double)b1 / (double)b2; + decay = _pos_map_accel_factor(1.0 - decpos, decfac); + return _pos_map_sin((M_PI / 2.0) + (p2 * len)) * decay; +} + +#define DBL_TO(Fp) eina_f32p32_double_to(Fp) +#define DBL_FROM(D) eina_f32p32_double_from(D) +#define INT_FROM(I) eina_f32p32_int_from(I) +#define SIN(Fp) eina_f32p32_sin(Fp) +#define COS(Fp) eina_f32p32_cos(Fp) +#define ADD(A, B) eina_f32p32_add(A, B) +#define SUB(A, B) eina_f32p32_sub(A, B) +#define MUL(A, B) eina_f32p32_mul(A, B) + +EAPI double +ecore_animator_pos_map(double pos, + Ecore_Pos_Map map, + double v1, + double v2) +{ + /* purely functional - locking not required */ + if (pos > 1.0) pos = 1.0; + else if (pos < 0.0) + pos = 0.0; + switch (map) + { + case ECORE_POS_MAP_LINEAR: + return pos; + + case ECORE_POS_MAP_ACCELERATE: + /* pos = 1 - sin(Pi / 2 + pos * Pi / 2); */ + pos = DBL_TO(SUB(INT_FROM(1), SIN(ADD((EINA_F32P32_PI >> 1), MUL(DBL_FROM(pos), (EINA_F32P32_PI >> 1)))))); + return pos; + + case ECORE_POS_MAP_DECELERATE: + /* pos = sin(pos * Pi / 2); */ + pos = DBL_TO(SIN(MUL(DBL_FROM(pos), (EINA_F32P32_PI >> 1)))); + return pos; + + case ECORE_POS_MAP_SINUSOIDAL: + /* pos = (1 - cos(pos * Pi)) / 2 */ + pos = DBL_TO((SUB(INT_FROM(1), COS(MUL(DBL_FROM(pos), EINA_F32P32_PI)))) >> 1); + return pos; + + case ECORE_POS_MAP_ACCELERATE_FACTOR: + pos = _pos_map_accel_factor(pos, v1); + return pos; + + case ECORE_POS_MAP_DECELERATE_FACTOR: + pos = 1.0 - _pos_map_accel_factor(1.0 - pos, v1); + return pos; + + case ECORE_POS_MAP_SINUSOIDAL_FACTOR: + if (pos < 0.5) pos = _pos_map_accel_factor(pos * 2.0, v1) / 2.0; + else pos = 1.0 - (_pos_map_accel_factor((1.0 - pos) * 2.0, v1) / 2.0); + return pos; + + case ECORE_POS_MAP_DIVISOR_INTERP: + pos = _pos_map_pow(pos, v1, (int)v2); + return pos; + + case ECORE_POS_MAP_BOUNCE: + pos = _pos_map_spring(pos, (int)v2, v1); + if (pos < 0.0) pos = -pos; + pos = 1.0 - pos; + return pos; + + case ECORE_POS_MAP_SPRING: + pos = 1.0 - _pos_map_spring(pos, (int)v2, v1); + return pos; + + default: + return pos; + } + return pos; +} + +EAPI void * +ecore_animator_del(Ecore_Animator *animator) +{ + void *data = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); + if (!ECORE_MAGIC_CHECK(animator, ECORE_MAGIC_ANIMATOR)) + { + ECORE_MAGIC_FAIL(animator, ECORE_MAGIC_ANIMATOR, + "ecore_animator_del"); + goto unlock; + } + if (animator->delete_me) + { + data = animator->data; + goto unlock; + } + animator->delete_me = EINA_TRUE; + animators_delete_me++; + if (animator->run_func) + data = animator->run_data; + else + data = animator->data; +unlock: + _ecore_unlock(); + return data; +} + +EAPI void +ecore_animator_frametime_set(double frametime) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + _ecore_lock(); + if (frametime < 0.0) frametime = 0.0; + if (animators_frametime == frametime) goto unlock; + animators_frametime = frametime; + _end_tick(); + if (animators) _begin_tick(); +unlock: + _ecore_unlock(); +} + +EAPI double +ecore_animator_frametime_get(void) +{ + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0.0); + return animators_frametime; +} + +EAPI void +ecore_animator_freeze(Ecore_Animator *animator) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + _ecore_lock(); + if (!ECORE_MAGIC_CHECK(animator, ECORE_MAGIC_ANIMATOR)) + { + ECORE_MAGIC_FAIL(animator, ECORE_MAGIC_ANIMATOR, + "ecore_animator_del"); + goto unlock; + } + if (animator->delete_me) goto unlock; + animator->suspended = EINA_TRUE; +unlock: + _ecore_unlock(); +} + +EAPI void +ecore_animator_thaw(Ecore_Animator *animator) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + _ecore_lock(); + if (!ECORE_MAGIC_CHECK(animator, ECORE_MAGIC_ANIMATOR)) + { + ECORE_MAGIC_FAIL(animator, ECORE_MAGIC_ANIMATOR, + "ecore_animator_del"); + goto unlock; + } + if (animator->delete_me) goto unlock; + animator->suspended = EINA_FALSE; +unlock: + _ecore_unlock(); +} + +EAPI void +ecore_animator_source_set(Ecore_Animator_Source source) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + _ecore_lock(); + src = source; + _end_tick(); + if (animators) _begin_tick(); + _ecore_unlock(); +} + +EAPI Ecore_Animator_Source +ecore_animator_source_get(void) +{ + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0); + return src; +} + +EAPI void +ecore_animator_custom_source_tick_begin_callback_set(Ecore_Cb func, + const void *data) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + _ecore_lock(); + begin_tick_cb = func; + begin_tick_data = data; + _end_tick(); + if (animators) _begin_tick(); + _ecore_unlock(); +} + +EAPI void +ecore_animator_custom_source_tick_end_callback_set(Ecore_Cb func, + const void *data) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + _ecore_lock(); + end_tick_cb = func; + end_tick_data = data; + _end_tick(); + if (animators) _begin_tick(); + _ecore_unlock(); +} + +EAPI void +ecore_animator_custom_tick(void) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + _ecore_lock(); + if (src == ECORE_ANIMATOR_SOURCE_CUSTOM) _do_tick(); + _ecore_unlock(); +} + +void +_ecore_animator_shutdown(void) +{ + _end_tick(); + while (animators) + { + Ecore_Animator *animator; + + animator = animators; + animators = (Ecore_Animator *)eina_inlist_remove(EINA_INLIST_GET(animators), EINA_INLIST_GET(animators)); + ECORE_MAGIC_SET(animator, ECORE_MAGIC_NONE); + ecore_animator_mp_free(animator); + } +} + +static Eina_Bool +_ecore_animator_run(void *data) +{ + Ecore_Animator *animator = data; + double pos = 0.0, t; + Eina_Bool run_ret; + + t = ecore_loop_time_get(); + if (animator->run > 0.0) + { + pos = (t - animator->start) / animator->run; + if (pos > 1.0) pos = 1.0; + else if (pos < 0.0) + pos = 0.0; + } + run_ret = animator->run_func(animator->run_data, pos); + if (t >= (animator->start + animator->run)) run_ret = EINA_FALSE; + return run_ret; +} + +static Eina_Bool +_ecore_animator(void *data __UNUSED__) +{ + Eina_Bool r; + _ecore_lock(); + r = _do_tick(); + _ecore_unlock(); + return r; +} + diff --git a/src/lib/ecore/ecore_app.c b/src/lib/ecore/ecore_app.c new file mode 100644 index 0000000..6e73da0 --- /dev/null +++ b/src/lib/ecore/ecore_app.c @@ -0,0 +1,96 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#ifndef _MSC_VER +# include +#else +# include +#endif + +#ifdef HAVE_EVIL +# include +#endif + +#include "Ecore.h" +#include "ecore_private.h" + +static int app_argc = 0; +static char **app_argv = NULL; + +/** + * @addtogroup Ecore_Application_Group + * + * @{ + */ + +/** + * Set up the programs command-line arguments. + * @param argc The same as passed as argc to the programs main() function + * @param argv The same as passed as argv to the programs main() function + * + * A call to this function will store the programs command-line arguments + * for later use by ecore_app_restart() or ecore_app_args_get(). + */ +EAPI void +ecore_app_args_set(int argc, + const char **argv) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + + if ((argc < 1) || + (!argv)) return; + app_argc = argc; + app_argv = (char **)argv; +} + +/** + * Return the programs stored command-line arguments. + * @param argc A pointer to the return value to hold argc + * @param argv A pointer to the return value to hold argv + * + * When called, this funciton returns the arguments for the program stored by + * ecore_app_args_set(). The integer pointed to by @p argc will be filled, if + * the pointer is not NULL, and the string array pointer @p argv will be filled + * also if the pointer is not NULL. The values they are filled with will be the + * same set by ecore_app_args_set(). + */ +EAPI void +ecore_app_args_get(int *argc, + char ***argv) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + + if (argc) *argc = app_argc; + if (argv) *argv = app_argv; +} + +/** + * Restart the program executable with the command-line arguments stored. + * + * This function will restart & re-execute this program in place of itself + * using the command-line arguments stored by ecore_app_args_set(). This is + * an easy way for a program to restart itself for cleanup purposes, + * configuration reasons or in the event of a crash. + */ +EAPI void +ecore_app_restart(void) +{ + EINA_MAIN_LOOP_CHECK_RETURN; +#ifdef HAVE_EXECVP + char *args[4096]; + int i; + + if ((app_argc < 1) || (!app_argv)) return; + if (app_argc >= 4096) return; + for (i = 0; i < app_argc; i++) args[i] = app_argv[i]; + args[i] = NULL; + execvp(app_argv[0], args); +#endif +} + +/** + * @} + */ diff --git a/src/lib/ecore/ecore_events.c b/src/lib/ecore/ecore_events.c new file mode 100644 index 0000000..bbfa7a9 --- /dev/null +++ b/src/lib/ecore/ecore_events.c @@ -0,0 +1,648 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "Ecore.h" +#include "ecore_private.h" + +static int inpurge = 0; + +struct _Ecore_Event_Handler +{ + EINA_INLIST; + ECORE_MAGIC; + int type; + Ecore_Event_Handler_Cb func; + void *data; + int references; + Eina_Bool delete_me : 1; +}; +GENERIC_ALLOC_SIZE_DECLARE(Ecore_Event_Handler); + +struct _Ecore_Event_Filter +{ + EINA_INLIST; + ECORE_MAGIC; + Ecore_Data_Cb func_start; + Ecore_Filter_Cb func_filter; + Ecore_End_Cb func_end; + void *loop_data; + void *data; + int references; + Eina_Bool delete_me : 1; +}; +GENERIC_ALLOC_SIZE_DECLARE(Ecore_Event_Filter); + +struct _Ecore_Event +{ + EINA_INLIST; + ECORE_MAGIC; + int type; + void *event; + Ecore_End_Cb func_free; + void *data; + int references; + Eina_Bool delete_me : 1; +}; +GENERIC_ALLOC_SIZE_DECLARE(Ecore_Event); + +static int events_num = 0; +static Ecore_Event *events = NULL; +static Ecore_Event *event_current = NULL; +static Ecore_Event *purge_events = NULL; + +static Ecore_Event_Handler **event_handlers = NULL; +static Ecore_Event_Handler *event_handler_current = NULL; +static int event_handlers_num = 0; +static int event_handlers_alloc_num = 0; +static Eina_List *event_handlers_delete_list = NULL; + +static Ecore_Event_Handler *event_handlers_add_list = NULL; + +static Ecore_Event_Filter *event_filters = NULL; +static Ecore_Event_Filter *event_filter_current = NULL; +static Ecore_Event *event_filter_event_current = NULL; +static int event_filters_delete_me = 0; +static int event_id_max = ECORE_EVENT_COUNT; +static int ecore_raw_event_type = ECORE_EVENT_NONE; +static void *ecore_raw_event_event = NULL; + +static void _ecore_event_purge_deleted(void); +static void *_ecore_event_del(Ecore_Event *event); + +EAPI Ecore_Event_Handler * +ecore_event_handler_add(int type, + Ecore_Event_Handler_Cb func, + const void *data) +{ + Ecore_Event_Handler *eh = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); + + if (!func) goto unlock; + if ((type <= ECORE_EVENT_NONE) || (type >= event_id_max)) goto unlock; + eh = ecore_event_handler_calloc(1); + if (!eh) goto unlock; + ECORE_MAGIC_SET(eh, ECORE_MAGIC_EVENT_HANDLER); + eh->type = type; + eh->func = func; + eh->data = (void *)data; + if (type >= (event_handlers_num - 1)) + { + int p_alloc_num; + + p_alloc_num = event_handlers_alloc_num; + event_handlers_num = type + 1; + if (event_handlers_num > event_handlers_alloc_num) + { + Ecore_Event_Handler **new_handlers; + int i; + + event_handlers_alloc_num = ((event_handlers_num + 16) / 16) * 16; + new_handlers = realloc(event_handlers, event_handlers_alloc_num * sizeof(Ecore_Event_Handler *)); + if (!new_handlers) + { + ecore_event_handler_mp_free(eh); + goto unlock; + } + event_handlers = new_handlers; + for (i = p_alloc_num; i < event_handlers_alloc_num; i++) + event_handlers[i] = NULL; + } + } + if (ecore_raw_event_type == type) + event_handlers_add_list = (Ecore_Event_Handler *)eina_inlist_append(EINA_INLIST_GET(event_handlers_add_list), EINA_INLIST_GET(eh)); + else if (type < event_handlers_alloc_num) + event_handlers[type] = (Ecore_Event_Handler *)eina_inlist_append(EINA_INLIST_GET(event_handlers[type]), EINA_INLIST_GET(eh)); + +unlock: + _ecore_unlock(); + return eh; +} + +EAPI void * +ecore_event_handler_del(Ecore_Event_Handler *event_handler) +{ + void *data = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); + if (!ECORE_MAGIC_CHECK(event_handler, ECORE_MAGIC_EVENT_HANDLER)) + { + ECORE_MAGIC_FAIL(event_handler, ECORE_MAGIC_EVENT_HANDLER, + "ecore_event_handler_del"); + goto unlock; + } + data = _ecore_event_handler_del(event_handler); +unlock: + _ecore_unlock(); + + return data; +} + +EAPI void * +ecore_event_handler_data_get(Ecore_Event_Handler *eh) +{ + void *data = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); + if (!ECORE_MAGIC_CHECK(eh, ECORE_MAGIC_EVENT_HANDLER)) + { + ECORE_MAGIC_FAIL(eh, ECORE_MAGIC_EVENT_HANDLER, "ecore_event_handler_data_get"); + goto unlock; + } + data = eh->data; +unlock: + _ecore_unlock(); + return data; +} + +EAPI void * +ecore_event_handler_data_set(Ecore_Event_Handler *eh, + const void *data) +{ + void *old = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); + if (!ECORE_MAGIC_CHECK(eh, ECORE_MAGIC_EVENT_HANDLER)) + { + ECORE_MAGIC_FAIL(eh, ECORE_MAGIC_EVENT_HANDLER, "ecore_event_handler_data_set"); + goto unlock; + } + old = eh->data; + eh->data = (void *)data; +unlock: + _ecore_unlock(); + + return old; +} + +static void +_ecore_event_generic_free(void *data __UNUSED__, + void *event) +{ /* DO NOT MEMPOOL FREE THIS */ + free(event); +} + +EAPI Ecore_Event * +ecore_event_add(int type, + void *ev, + Ecore_End_Cb func_free, + void *data) +{ + Ecore_Event *event = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); + +/* if (!ev) goto unlock; */ + if (type <= ECORE_EVENT_NONE) goto unlock; + if (type >= event_id_max) goto unlock; + if ((ev) && (!func_free)) func_free = _ecore_event_generic_free; + event = _ecore_event_add(type, ev, func_free, data); +unlock: + _ecore_unlock(); + return event; +} + +EAPI void * +ecore_event_del(Ecore_Event *event) +{ + void *data = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); + if (!ECORE_MAGIC_CHECK(event, ECORE_MAGIC_EVENT)) + { + ECORE_MAGIC_FAIL(event, ECORE_MAGIC_EVENT, "ecore_event_del"); + goto unlock; + } + EINA_SAFETY_ON_TRUE_GOTO(event->delete_me, unlock); + event->delete_me = 1; + data = event->data; +unlock: + _ecore_unlock(); + return data; +} + +EAPI int +ecore_event_type_new(void) +{ + int id; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0); + _ecore_lock(); + id = event_id_max++; + _ecore_unlock(); + + return id; +} + +EAPI Ecore_Event_Filter * +ecore_event_filter_add(Ecore_Data_Cb func_start, + Ecore_Filter_Cb func_filter, + Ecore_End_Cb func_end, + const void *data) +{ + Ecore_Event_Filter *ef = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); + if (!func_filter) goto unlock; + ef = ecore_event_filter_calloc(1); + if (!ef) goto unlock; + ECORE_MAGIC_SET(ef, ECORE_MAGIC_EVENT_FILTER); + ef->func_start = func_start; + ef->func_filter = func_filter; + ef->func_end = func_end; + ef->data = (void *)data; + event_filters = (Ecore_Event_Filter *)eina_inlist_append(EINA_INLIST_GET(event_filters), EINA_INLIST_GET(ef)); +unlock: + _ecore_unlock(); + return ef; +} + +EAPI void * +ecore_event_filter_del(Ecore_Event_Filter *ef) +{ + void *data = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); + if (!ECORE_MAGIC_CHECK(ef, ECORE_MAGIC_EVENT_FILTER)) + { + ECORE_MAGIC_FAIL(ef, ECORE_MAGIC_EVENT_FILTER, "ecore_event_filter_del"); + goto unlock; + } + EINA_SAFETY_ON_TRUE_GOTO(ef->delete_me, unlock); + ef->delete_me = 1; + event_filters_delete_me = 1; + data = ef->data; +unlock: + _ecore_unlock(); + + return data; +} + +EAPI int +ecore_event_current_type_get(void) +{ + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0); + return ecore_raw_event_type; +} + +EAPI void * +ecore_event_current_event_get(void) +{ + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + return ecore_raw_event_event; +} + +EAPI void * +_ecore_event_handler_del(Ecore_Event_Handler *event_handler) +{ + EINA_SAFETY_ON_TRUE_RETURN_VAL(event_handler->delete_me, NULL); + event_handler->delete_me = 1; + event_handlers_delete_list = eina_list_append(event_handlers_delete_list, event_handler); + return event_handler->data; +} + +void +_ecore_event_shutdown(void) +{ + int i; + Ecore_Event_Handler *eh; + Ecore_Event_Filter *ef; + + while (events) _ecore_event_del(events); + event_current = NULL; + for (i = 0; i < event_handlers_num; i++) + { + while ((eh = event_handlers[i])) + { + event_handlers[i] = (Ecore_Event_Handler *)eina_inlist_remove(EINA_INLIST_GET(event_handlers[i]), EINA_INLIST_GET(event_handlers[i])); + ECORE_MAGIC_SET(eh, ECORE_MAGIC_NONE); + if (!eh->delete_me) ecore_event_handler_mp_free(eh); + } + } + EINA_LIST_FREE(event_handlers_delete_list, eh) + ecore_event_handler_mp_free(eh); + if (event_handlers) free(event_handlers); + event_handlers = NULL; + event_handlers_num = 0; + event_handlers_alloc_num = 0; + while ((ef = event_filters)) + { + event_filters = (Ecore_Event_Filter *)eina_inlist_remove(EINA_INLIST_GET(event_filters), EINA_INLIST_GET(event_filters)); + ECORE_MAGIC_SET(ef, ECORE_MAGIC_NONE); + ecore_event_filter_mp_free(ef); + } + event_filters_delete_me = 0; + event_filter_current = NULL; + event_filter_event_current = NULL; +} + +int +_ecore_event_exist(void) +{ + Ecore_Event *e; + EINA_INLIST_FOREACH(events, e) + if (!e->delete_me) return 1; + return 0; +} + +Ecore_Event * +_ecore_event_add(int type, + void *ev, + Ecore_End_Cb func_free, + void *data) +{ + Ecore_Event *e; + + e = ecore_event_calloc(1); + if (!e) return NULL; + ECORE_MAGIC_SET(e, ECORE_MAGIC_EVENT); + e->type = type; + e->event = ev; + e->func_free = func_free; + e->data = data; + if (inpurge > 0) + { + purge_events = (Ecore_Event *)eina_inlist_append(EINA_INLIST_GET(purge_events), EINA_INLIST_GET(e)); + events_num++; + } + else + { + events = (Ecore_Event *)eina_inlist_append(EINA_INLIST_GET(events), EINA_INLIST_GET(e)); + events_num++; + } + return e; +} + +void * +_ecore_event_del(Ecore_Event *event) +{ + void *data; + + data = event->data; + if (event->func_free) _ecore_call_end_cb(event->func_free, event->data, event->event); + events = (Ecore_Event *)eina_inlist_remove(EINA_INLIST_GET(events), EINA_INLIST_GET(event)); + ECORE_MAGIC_SET(event, ECORE_MAGIC_NONE); + ecore_event_mp_free(event); + events_num--; + return data; +} + +static void +_ecore_event_purge_deleted(void) +{ + Ecore_Event *itr = events; + + inpurge++; + while (itr) + { + Ecore_Event *next = (Ecore_Event *)EINA_INLIST_GET(itr)->next; + if ((!itr->references) && (itr->delete_me)) + _ecore_event_del(itr); + itr = next; + } + inpurge--; + while (purge_events) + { + Ecore_Event *e = purge_events; + purge_events = (Ecore_Event *)eina_inlist_remove(EINA_INLIST_GET(purge_events), EINA_INLIST_GET(purge_events)); + events = (Ecore_Event *)eina_inlist_append(EINA_INLIST_GET(events), EINA_INLIST_GET(e)); + } +} + +static inline void +_ecore_event_filters_apply() +{ + if (!event_filter_current) + { + /* regular main loop, start from head */ + event_filter_current = event_filters; + } + else + { + /* recursive main loop, continue from where we were */ + event_filter_current = (Ecore_Event_Filter *)EINA_INLIST_GET(event_filter_current)->next; + } + + while (event_filter_current) + { + Ecore_Event_Filter *ef = event_filter_current; + + if (!ef->delete_me) + { + ef->references++; + + if (ef->func_start) + ef->loop_data = _ecore_call_data_cb(ef->func_start, ef->data); + + if (!event_filter_event_current) + { + /* regular main loop, start from head */ + event_filter_event_current = events; + } + else + { + /* recursive main loop, continue from where we were */ + event_filter_event_current = (Ecore_Event *)EINA_INLIST_GET(event_filter_event_current)->next; + } + + while (event_filter_event_current) + { + Ecore_Event *e = event_filter_event_current; + + if (!_ecore_call_filter_cb(ef->func_filter, ef->data, + ef->loop_data, e->type, e->event)) + { + ecore_event_del(e); + } + + if (event_filter_event_current) /* may have changed in recursive main loops */ + event_filter_event_current = (Ecore_Event *)EINA_INLIST_GET(event_filter_event_current)->next; + } + if (ef->func_end) + _ecore_call_end_cb(ef->func_end, ef->data, ef->loop_data); + + ef->references--; + } + + if (event_filter_current) /* may have changed in recursive main loops */ + event_filter_current = (Ecore_Event_Filter *)EINA_INLIST_GET(event_filter_current)->next; + } + if (event_filters_delete_me) + { + int deleted_in_use = 0; + Ecore_Event_Filter *l; + for (l = event_filters; l; ) + { + Ecore_Event_Filter *ef = l; + l = (Ecore_Event_Filter *)EINA_INLIST_GET(l)->next; + if (ef->delete_me) + { + if (ef->references) + { + deleted_in_use++; + continue; + } + + event_filters = (Ecore_Event_Filter *)eina_inlist_remove(EINA_INLIST_GET(event_filters), EINA_INLIST_GET(ef)); + ECORE_MAGIC_SET(ef, ECORE_MAGIC_NONE); + ecore_event_filter_mp_free(ef); + } + } + if (!deleted_in_use) + event_filters_delete_me = 0; + } +} + +void +_ecore_event_call(void) +{ + Eina_List *l, *l_next; + Ecore_Event_Handler *eh; + + _ecore_event_filters_apply(); + + if (!event_current) + { + /* regular main loop, start from head */ + event_current = events; + event_handler_current = NULL; + } + + while (event_current) + { + Ecore_Event *e = event_current; + int handle_count = 0; + + if (e->delete_me) + { + event_current = (Ecore_Event *)EINA_INLIST_GET(event_current)->next; + continue; + } + + ecore_raw_event_type = e->type; + ecore_raw_event_event = e->event; + e->references++; + if ((e->type >= 0) && (e->type < event_handlers_num)) + { + if (!event_handler_current) + { + /* regular main loop, start from head */ + event_handler_current = event_handlers[e->type]; + } + else + { + /* recursive main loop, continue from where we were */ + event_handler_current = (Ecore_Event_Handler *)EINA_INLIST_GET(event_handler_current)->next; + } + + while ((event_handler_current) && (!e->delete_me)) + { + eh = event_handler_current; + if (!eh->delete_me) + { + Eina_Bool ret; + + handle_count++; + + eh->references++; + ret = _ecore_call_handler_cb(eh->func, eh->data, e->type, e->event); + eh->references--; + + if (!ret) + { + event_handler_current = NULL; + break; /* 0 == "call no further handlers" */ + } + } + + if (event_handler_current) /* may have changed in recursive main loops */ + event_handler_current = (Ecore_Event_Handler *)EINA_INLIST_GET(event_handler_current)->next; + } + } + while (event_handlers_add_list) + { + eh = event_handlers_add_list; + event_handlers_add_list = (Ecore_Event_Handler *)eina_inlist_remove(EINA_INLIST_GET(event_handlers_add_list), EINA_INLIST_GET(eh)); + event_handlers[eh->type] = (Ecore_Event_Handler *)eina_inlist_append(EINA_INLIST_GET(event_handlers[eh->type]), EINA_INLIST_GET(eh)); + } + /* if no handlers were set for EXIT signal - then default is */ + /* to quit the main loop */ + if ((e->type == ECORE_EVENT_SIGNAL_EXIT) && (handle_count == 0)) + ecore_main_loop_quit(); + e->references--; + e->delete_me = 1; + + if (event_current) /* may have changed in recursive main loops */ + event_current = (Ecore_Event *)EINA_INLIST_GET(event_current)->next; + } + + ecore_raw_event_type = ECORE_EVENT_NONE; + ecore_raw_event_event = NULL; + + _ecore_event_purge_deleted(); + + EINA_LIST_FOREACH_SAFE(event_handlers_delete_list, l, l_next, eh) + { + if (eh->references) continue; + + event_handlers_delete_list = eina_list_remove_list(event_handlers_delete_list, l); + + event_handlers[eh->type] = (Ecore_Event_Handler *)eina_inlist_remove(EINA_INLIST_GET(event_handlers[eh->type]), EINA_INLIST_GET(eh)); + ECORE_MAGIC_SET(eh, ECORE_MAGIC_NONE); + ecore_event_handler_mp_free(eh); + } +} + +void * +_ecore_event_signal_user_new(void) +{ + Ecore_Event_Signal_User *e; + + e = calloc(1, sizeof(Ecore_Event_Signal_User)); + return e; +} + +void * +_ecore_event_signal_hup_new(void) +{ + Ecore_Event_Signal_Hup *e; + + e = calloc(1, sizeof(Ecore_Event_Signal_Hup)); + return e; +} + +void * +_ecore_event_signal_exit_new(void) +{ + Ecore_Event_Signal_Exit *e; + + e = calloc(1, sizeof(Ecore_Event_Signal_Exit)); + return e; +} + +void * +_ecore_event_signal_power_new(void) +{ + Ecore_Event_Signal_Power *e; + + e = calloc(1, sizeof(Ecore_Event_Signal_Power)); + return e; +} + +void * +_ecore_event_signal_realtime_new(void) +{ + return calloc(1, sizeof(Ecore_Event_Signal_Realtime)); +} + diff --git a/src/lib/ecore/ecore_exe.c b/src/lib/ecore/ecore_exe.c new file mode 100644 index 0000000..7cc4b0f --- /dev/null +++ b/src/lib/ecore/ecore_exe.c @@ -0,0 +1,1913 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_PRCTL_H +# include +#endif + +#ifdef HAVE_SYS_WAIT_H +# include +#endif + +#include "Ecore.h" +#include "ecore_private.h" + +/* FIXME: Getting respawn to work + * + * There is no way that we can do anything about the internal state info of + * an external exe. The same can be said about the state of user code. User + * code in this context means the code that is using ecore_exe to manage exe's + * for it. + * + * Document that the exe must be respawnable, in other words, there is no + * state that it cannot regenerate by just killing it and starting it again. + * This includes state that the user code knows about, as the respawn is + * transparent to that code. On the other hand, maybe a respawn event might + * be useful, or maybe resend the currently non existent add event. For + * consistancy with ecore_con, an add event is good anyway. + * + * The Ecore_exe structure is reused for respawning, so that the (opaque) + * pointer held by the user remains valid. This means that the Ecore_Exe + * init and del functions may need to be split into two parts each to avoid + * duplicating code - common code part, and the rest. This implies that + * the unchanging members mentioned next should NEVER change. + * + * These structure members don't need to change - + * __list_data - we stay on the list + * ECORE_MAGIC - this is a constant + * data - passed in originally + * cmd - passed in originally + * flags - passed in originally + * + * These structure members need to change - + * tag - state that must be regenerated, zap it + * pid - it will be different + * child_fd_write - it will be different + * child_fd_read - it will be different + * child_fd_error - it will be different + * write_fd_handler - we cannot change the fd used by a handler, this changes coz the fd changes. + * read_fd_handler - we cannot change the fd used by a handler, this changes coz the fd changes. + * error_fd_handler - we cannot change the fd used by a handler, this changes coz the fd changes. + * + * Hmm, the read, write, and error buffers could be tricky. + * They are not atomic, and could be in a semi complete state. + * They fall into the "state must be regenerated" mentioned above. + * A respawn/add event should take care of it. + * + * These structure members need to change - + * write_data_buf - state that must be regenerated, zap it + * write_data_size - state that must be regenerated, zap it + * write_data_offset - state that must be regenerated, zap it + * read_data_buf - state that must be regenerated, zap it + * read_data_size - state that must be regenerated, zap it + * error_data_buf - state that must be regenerated, zap it + * error_data_size - state that must be regenerated, zap it + * close_write - state that must be regenerated, zap it + * + * There is the problem that an exe that fell over and needs respawning + * might keep falling over, keep needing to be respawned, and tie up system + * resources with the constant respawning. An exponentially increasing + * timeout (with maximum timeout) between respawns should take care of that. + * Although this is not a "contention for a resource" problem, the exe falling + * over may be, so a random element added to the timeout may help, and won't + * hurt. The user code may need to be informed that a timeout is in progress. + */ + +struct _Ecore_Exe +{ + EINA_INLIST; + ECORE_MAGIC; + pid_t pid; + void *data; + char *tag, *cmd; + Ecore_Exe_Flags flags; + Ecore_Fd_Handler *write_fd_handler; /* the fd_handler to handle write to child - if this was used, or NULL if not */ + Ecore_Fd_Handler *read_fd_handler; /* the fd_handler to handle read from child - if this was used, or NULL if not */ + Ecore_Fd_Handler *error_fd_handler; /* the fd_handler to handle errors from child - if this was used, or NULL if not */ + void *write_data_buf; /* a data buffer for data to write to the child - + * realloced as needed for more data and flushed when the fd handler says writes are possible + */ + int write_data_size; /* the size in bytes of the data buffer */ + int write_data_offset; /* the offset in bytes in the data buffer */ + void *read_data_buf; /* data read from the child awating delivery to an event */ + int read_data_size; /* data read from child in bytes */ + void *error_data_buf; /* errors read from the child awating delivery to an event */ + int error_data_size; /* errors read from child in bytes */ + int child_fd_write; /* fd to write TO to send data to the child */ + int child_fd_read; /* fd to read FROM when child has sent us (the parent) data */ + int child_fd_error; /* fd to read FROM when child has sent us (the parent) errors */ + int child_fd_write_x; /* fd to write TO to send data to the child */ + int child_fd_read_x; /* fd to read FROM when child has sent us (the parent) data */ + int child_fd_error_x; /* fd to read FROM when child has sent us (the parent) errors */ + Eina_Bool close_stdin : 1; + + int start_bytes, end_bytes, start_lines, end_lines; /* Number of bytes/lines to auto pipe at start/end of stdout/stderr. */ + + Ecore_Timer *doomsday_clock; /* The Timer of Death. Muahahahaha. */ + void *doomsday_clock_dead; /* data for the doomsday clock */ + + Ecore_Exe_Cb pre_free_cb; +}; + +/* TODO: Something to let people build a command line and does auto escaping - + * + * ecore_exe_snprintf() + * + * OR + * + * cmd = ecore_exe_comand_parameter_append(cmd, "firefox"); + * cmd = ecore_exe_comand_parameter_append(cmd, "http://www.foo.com/bar.html?baz=yes"); + * each parameter appended is one argument, and it gets escaped, quoted, and + * appended with a preceding space. The first is the command off course. + */ + +struct _ecore_exe_dead_exe +{ + pid_t pid; + char *cmd; +}; + +static inline void _ecore_exe_exec_it(const char *exe_cmd, + Ecore_Exe_Flags flags); +static Eina_Bool _ecore_exe_data_generic_handler(void *data, + Ecore_Fd_Handler *fd_handler, + Ecore_Exe_Flags flags); +static Eina_Bool _ecore_exe_data_error_handler(void *data, + Ecore_Fd_Handler *fd_handler); +static Eina_Bool _ecore_exe_data_read_handler(void *data, + Ecore_Fd_Handler *fd_handler); +static Eina_Bool _ecore_exe_data_write_handler(void *data, + Ecore_Fd_Handler *fd_handler); +static void _ecore_exe_flush(Ecore_Exe *exe); +static void _ecore_exe_event_exe_data_free(void *data __UNUSED__, + void *ev); +static Ecore_Exe *_ecore_exe_is_it_alive(pid_t pid); +static Eina_Bool _ecore_exe_make_sure_its_dead(void *data); +static Eina_Bool _ecore_exe_make_sure_its_really_dead(void *data); +static Ecore_Exe_Event_Add *_ecore_exe_event_add_new(void); +static void _ecore_exe_event_add_free(void *data, + void *ev); +static void _ecore_exe_dead_attach(Ecore_Exe *exe); + +EAPI int ECORE_EXE_EVENT_ADD = 0; +EAPI int ECORE_EXE_EVENT_DEL = 0; +EAPI int ECORE_EXE_EVENT_DATA = 0; +EAPI int ECORE_EXE_EVENT_ERROR = 0; + +static Ecore_Exe *exes = NULL; +static const char *shell = NULL; + +/* FIXME: This errno checking stuff should be put elsewhere for everybody to use. + * For now it lives here though, just to make testing easier. + */ +static int _ecore_exe_check_errno(int result, + const char *file, + int line); + +#define E_IF_NO_ERRNO(result, foo, ok) \ + while (((ok) = _ecore_exe_check_errno((result) = (foo), __FILE__, __LINE__)) == -1) sleep(1); \ + if (ok) + +#define E_NO_ERRNO(result, foo, ok) \ + while (((ok) = _ecore_exe_check_errno((result) = (foo), __FILE__, __LINE__)) == -1) sleep(1) + +#define E_IF_NO_ERRNO_NOLOOP(result, foo, ok) \ + if (((ok) = _ecore_exe_check_errno((result) = (foo), __FILE__, __LINE__))) + +static int +_ecore_exe_check_errno(int result, + const char *file __UNUSED__, + int line __UNUSED__) +{ + int saved_errno = errno; + + if (result == -1) + { + perror("*** errno reports "); +/* What is currently supported - + * + * pipe + * EFAULT Argument is not valid. + * EMFILE Too many file descriptors used by process. + * ENFILE Too many open files by system. + * read + * EAGAIN No data now, try again. + * EBADF This is not an fd that can be read. + * EFAULT This is not a valid buffer. + * EINTR Interupted by signal, try again. + * EINVAL This is not an fd that can be read. + * EIO I/O error. + * EISDIR This is a directory, and cannot be read. + * others Depending on what sort of thing we are reading from. + * close + * EBADF This is not an fd that can be closed. + * EINTR Interupted by signal, try again. + * EIO I/O error. + * dup2 + * EBADF This is not an fd that can be dup2'ed. + * EBUSY Race condition between open() and dup() + * EINTR Interupted by signal, try again. + * EMFILE Too many file descriptors used by process. + * fcntl + * EACCES, EAGAIN Locked or mapped by something else, try again later. + * EBADF This is not an fd that can be fcntl'ed. + * EDEADLK This will cause a deadlock. + * EFAULT This is not a valid lock. + * EINTR Interupted by signal, try again. + * EINVAL This is not a valid arg. + * EMFILE Too many file descriptors used by process. + * ENOLCK Problem getting a lock. + * EPERM Not allowed to do that. + * fsync + * EBADF This is not an fd that is open for writing. + * EINVAL, EROFS This is not an fd that can be fsynced. + * EIO I/O error. + * + * How to use it - + * int ok = 0; + * int result; + * + * E_IF_NO_ERRNO(result, foo(bar), ok) + * { + * E_IF_NO_ERRNO_NOLOOP(result, foo(bar), ok) + * { + * } + * } + * + * if (!ok) + * { + * // Something failed, cleanup. + * } + */ + switch (saved_errno) + { + case EACCES: + case EAGAIN: + case EINTR: + { /* Not now, try later. */ + ERR("*** Must try again in %s @%u.", file, line); + result = -1; + break; + } + + case EMFILE: + case ENFILE: + case ENOLCK: + { /* Low on resources. */ + ERR("*** Low on resources in %s @%u.", file, + line); + result = 0; + break; + } + + case EIO: + { /* I/O error. */ + ERR("*** I/O error in %s @%u.", file, line); + result = 0; + break; + } + + case EFAULT: + case EBADF: + case EINVAL: + case EROFS: + case EISDIR: + case EDEADLK: + case EPERM: + case EBUSY: + { /* Programmer fucked up. */ + ERR("*** NAUGHTY PROGRAMMER!!!\n" + "*** SPANK SPANK SPANK!!!\n" + "*** Now go fix your code in %s @%u. Tut tut tut!", + file, line); + result = 0; + break; + } + + default: + { /* Unsupported errno code, please add this one. */ + ERR("*** NAUGHTY PROGRAMMER!!!\n" + "*** SPANK SPANK SPANK!!!\n" + "*** Unsupported errno code %d, please add this one.\n" + "*** Now go fix your code in %s @%u, from %s @%u. Tut tut tut!", + saved_errno, __FILE__, __LINE__, file, line); + result = 0; + break; + } + } + } + else /* Everything is fine. */ + result = 1; + + errno = saved_errno; + return result; +} + +/** + * @addtogroup Ecore_Exe_Group + * + * @{ + */ + +static int run_pri = ECORE_EXE_PRIORITY_INHERIT; + +/** + * Sets the priority at which to launch processes + * + * This sets the priority of processes run by ecore_exe_run() and + * ecore_exe_pipe_run(). + * @li On Windows, the child process is created by default with the + * @ref ECORE_EXE_WIN32_PRIORITY_NORMAL priority, unless the calling + * process is in @ref ECORE_EXE_WIN32_PRIORITY_IDLE or + * @ref ECORE_EXE_WIN32_PRIORITY_BELOW_NORMAL priority. In that case, the + * child process inherits this priority. + * @li On other platforms, if set to @ref ECORE_EXE_PRIORITY_INHERIT child + * processes inherits the priority of their parent. This is the default. + * + * @param pri value a Ecore_Exe_Win32_Priority value on Windows, -20 + * to 19 or @ref ECORE_EXE_PRIORITY_INHERIT on other OS. + */ +EAPI void +ecore_exe_run_priority_set(int pri) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + run_pri = pri; +} + +/** + * Gets the priority at which to launch processes + * + * This gets ths priority of launched processes. See + * ecore_exe_run_priority_set() for details. This just returns the value set + * by this call. + * + * @return the value set by ecore_exe_run_priority_set() + */ +EAPI int +ecore_exe_run_priority_get(void) +{ + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0); + return run_pri; +} + +/** + * Spawns a child process. + * + * This is now just a thin wrapper around ecore_exe_pipe_run() + * @note When you use this function you will have no permissions + * to write or read on the pipe that connects you with the spwaned process. + * If you need to do that use ecore_exe_pipe_run() with the + * appropriated flags. + * + * @param exe_cmd The command to run with @c /bin/sh. + * @param data Data to attach to the returned process handle. + * @return A process handle to the spawned process. + */ +EAPI Ecore_Exe * +ecore_exe_run(const char *exe_cmd, + const void *data) +{ + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + return ecore_exe_pipe_run(exe_cmd, 0, data); +} + +/** + * Spawns a child process with its stdin/out available for communication. + * + * This function forks and runs the given command using @c /bin/sh. + * + * Note that the process handle is only valid until a child process + * terminated event is received. After all handlers for the child process + * terminated event have been called, the handle will be freed by Ecore. + * + * This function does the same thing as ecore_exe_run(), but also makes the + * standard in and/or out as well as stderr from the child process available + * for reading or writing. To write use ecore_exe_send(). To read listen to + * ECORE_EXE_EVENT_DATA or ECORE_EXE_EVENT_ERROR events (set up handlers). + * Ecore may buffer read and error data until a newline character if asked + * for with the @p flags. All data will be included in the events (newlines + * will be replaced with NULLS if line buffered). ECORE_EXE_EVENT_DATA events + * will only happen if the process is run with ECORE_EXE_PIPE_READ enabled + * in the flags. The same with the error version. Writing will only be + * allowed with ECORE_EXE_PIPE_WRITE enabled in the flags. + * + * @param exe_cmd The command to run with @c /bin/sh. + * @param flags The flag parameters for how to deal with inter-process I/O + * @param data Data to attach to the returned process handle. + * @return A process handle to the spawned process. + */ +EAPI Ecore_Exe * +ecore_exe_pipe_run(const char *exe_cmd, + Ecore_Exe_Flags flags, + const void *data) +{ + Ecore_Exe *exe = NULL; + int statusPipe[2] = { -1, -1 }; + int errorPipe[2] = { -1, -1 }; + int readPipe[2] = { -1, -1 }; + int writePipe[2] = { -1, -1 }; + int n = 0; + int ok = 1; + int result; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + if (!exe_cmd) return NULL; + exe = calloc(1, sizeof(Ecore_Exe)); + if (!exe) return NULL; + + if ((flags & ECORE_EXE_PIPE_AUTO) && (!(flags & ECORE_EXE_PIPE_ERROR)) + && (!(flags & ECORE_EXE_PIPE_READ))) + /* We need something to auto pipe. */ + flags |= ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR; + + exe->child_fd_error = -1; + exe->child_fd_read = -1; + exe->child_fd_write = -1; + exe->child_fd_error_x = -1; + exe->child_fd_read_x = -1; + exe->child_fd_write_x = -1; + + /* Create some pipes. */ + if (ok) + { + E_IF_NO_ERRNO_NOLOOP(result, pipe(statusPipe), ok) + { + } + } + if (ok && (flags & ECORE_EXE_PIPE_ERROR)) + { + E_IF_NO_ERRNO_NOLOOP(result, pipe(errorPipe), ok) + { + exe->child_fd_error = errorPipe[0]; + exe->child_fd_error_x = errorPipe[1]; + } + } + if (ok && (flags & ECORE_EXE_PIPE_READ)) + { + E_IF_NO_ERRNO_NOLOOP(result, pipe(readPipe), ok) + { + exe->child_fd_read = readPipe[0]; + exe->child_fd_read_x = readPipe[1]; + } + } + if (ok && (flags & ECORE_EXE_PIPE_WRITE)) + { + E_IF_NO_ERRNO_NOLOOP(result, pipe(writePipe), ok) + { + exe->child_fd_write = writePipe[1]; + exe->child_fd_write_x = writePipe[0]; + } + } + if (ok) + { + pid_t pid = 0; + volatile int vfork_exec_errno = 0; + + /* FIXME: I should double check this. After a quick look around, this is already done, but via a more modern method. */ + /* signal(SIGPIPE, SIG_IGN); We only want EPIPE on errors */ + pid = fork(); + + if (pid == -1) + { + ERR("Failed to fork process"); + pid = 0; + } + else if (pid == 0) /* child */ + { + if (run_pri != ECORE_EXE_PRIORITY_INHERIT) + { +#ifdef PRIO_PROCESS + if ((run_pri >= -20) && (run_pri <= 19)) + setpriority(PRIO_PROCESS, 0, run_pri); +#else +#warning "Your OS/libc does not provide PRIO_PROCESS (and possibly setpriority())" +#warning "This is a POSIX-1.2001 standard and it is highly encouraged that you" +#warning "Have support for this" +#endif + } + /* dup2 STDERR, STDIN, and STDOUT. dup2() allegedly closes the + * second pipe if it's open. On the other hand, there was the + * Great FD Leak Scare of '06, so let's be paranoid. */ + if (ok && (flags & ECORE_EXE_PIPE_ERROR)) + { + E_NO_ERRNO(result, close(STDERR_FILENO), ok); + E_NO_ERRNO(result, dup2(errorPipe[1], STDERR_FILENO), ok); + } + if (ok && (flags & ECORE_EXE_PIPE_READ)) + { + E_NO_ERRNO(result, close(STDOUT_FILENO), ok); + E_NO_ERRNO(result, dup2(readPipe[1], STDOUT_FILENO), ok); + } + if (ok && (flags & ECORE_EXE_PIPE_WRITE)) + { + E_NO_ERRNO(result, close(STDIN_FILENO), ok); + E_NO_ERRNO(result, dup2(writePipe[0], STDIN_FILENO), ok); + } + + if (ok) + { + /* Setup the status pipe. */ + E_NO_ERRNO(result, close(statusPipe[0]), ok); + E_IF_NO_ERRNO(result, fcntl(statusPipe[1], F_SETFD, FD_CLOEXEC), ok) /* close on exec shows success */ + { + /* Run the actual command. */ + _ecore_exe_exec_it(exe_cmd, flags); /* no return */ + } + } + + /* Something went 'orribly wrong. */ + vfork_exec_errno = errno; + + /* Close the pipes. */ + if (flags & ECORE_EXE_PIPE_ERROR) + E_NO_ERRNO(result, close(errorPipe[1]), ok); + if (flags & ECORE_EXE_PIPE_READ) + E_NO_ERRNO(result, close(readPipe[1]), ok); + if (flags & ECORE_EXE_PIPE_WRITE) + E_NO_ERRNO(result, close(writePipe[0]), ok); + E_NO_ERRNO(result, close(statusPipe[1]), ok); + + _exit(-1); + } + else /* parent */ + { + /* Close the unused pipes. */ + E_NO_ERRNO(result, close(statusPipe[1]), ok); + + /* FIXME: after having a good look at the current e fd + * handling, investigate fcntl(dataPipe[x], F_SETSIG, ...) */ + /* FIXME: above F_SETSIG etc. - this is async SIGIO based IO + * which is also linux specific so we probably don't want to + * do this as long as select() is working fine. the only time + * we really want to think of SIGIO async IO is when it all + * actually works basically everywhere and we can turn all + * IO into DMA async activities (i.e. you do a read() then + * the read is complete not on return but when you get a + * SIGIO - the read() just starts the transfer and it is + * completed in the background by DMA (or whatever mechanism + * the kernel choses)) */ + + /* Wait for it to start executing. */ + /* FIXME: this doesn't seem very nice - we sit and block + * waiting on a child process... even though it's just + * the segment between the fork() and the exec) it just feels + * wrong */ + for (;; ) + { + char buf; + + E_NO_ERRNO(result, read(statusPipe[0], &buf, 1), ok); + if (result == 0) + { + if (vfork_exec_errno != 0) + { + n = vfork_exec_errno; + ERR("Could not start \"%s\"", exe_cmd); + pid = 0; + } + break; + } + } + + /* Close the status pipe. */ + E_NO_ERRNO(result, close(statusPipe[0]), ok); + } + + if (pid) + { + /* Setup the exe structure. */ + ECORE_MAGIC_SET(exe, ECORE_MAGIC_EXE); + exe->start_bytes = -1; + exe->end_bytes = -1; + exe->start_lines = -1; + exe->end_lines = -1; + exe->pid = pid; + exe->flags = flags; + exe->data = (void *)data; + if ((exe->cmd = strdup(exe_cmd))) + { + if (flags & ECORE_EXE_PIPE_ERROR) /* Setup the error stuff. */ + { + E_IF_NO_ERRNO(result, + fcntl(exe->child_fd_error, F_SETFL, + O_NONBLOCK), ok) { + } + E_IF_NO_ERRNO(result, + fcntl(exe->child_fd_error, F_SETFD, + FD_CLOEXEC), ok) { + } + E_IF_NO_ERRNO(result, + fcntl(exe->child_fd_error_x, F_SETFD, + FD_CLOEXEC), ok) { + } + { + exe->error_fd_handler = + ecore_main_fd_handler_add(exe->child_fd_error, + ECORE_FD_READ, + _ecore_exe_data_error_handler, + exe, NULL, NULL); + if (!exe->error_fd_handler) + ok = 0; + } + } + if (ok && (flags & ECORE_EXE_PIPE_READ)) /* Setup the read stuff. */ + { + E_IF_NO_ERRNO(result, + fcntl(exe->child_fd_read, F_SETFL, + O_NONBLOCK), ok) { + } + E_IF_NO_ERRNO(result, + fcntl(exe->child_fd_read, F_SETFD, + FD_CLOEXEC), ok) { + } + E_IF_NO_ERRNO(result, + fcntl(exe->child_fd_read_x, F_SETFD, + FD_CLOEXEC), ok) { + } + { + exe->read_fd_handler = + ecore_main_fd_handler_add(exe->child_fd_read, + ECORE_FD_READ, + _ecore_exe_data_read_handler, + exe, NULL, NULL); + if (!exe->read_fd_handler) + ok = 0; + } + } + if (ok && (flags & ECORE_EXE_PIPE_WRITE)) /* Setup the write stuff. */ + { + E_IF_NO_ERRNO(result, + fcntl(exe->child_fd_write, F_SETFL, + O_NONBLOCK), ok) { + } + E_IF_NO_ERRNO(result, + fcntl(exe->child_fd_write, F_SETFD, + FD_CLOEXEC), ok) { + } + E_IF_NO_ERRNO(result, + fcntl(exe->child_fd_write_x, F_SETFD, + FD_CLOEXEC), ok) { + } + { + exe->write_fd_handler = + ecore_main_fd_handler_add(exe->child_fd_write, + ECORE_FD_WRITE, + _ecore_exe_data_write_handler, + exe, NULL, NULL); + if (exe->write_fd_handler) + ecore_main_fd_handler_active_set(exe->write_fd_handler, 0); /* Nothing to write to start with. */ + else + ok = 0; + } + } + + exes = (Ecore_Exe *)eina_inlist_append(EINA_INLIST_GET(exes), EINA_INLIST_GET(exe)); + n = 0; + } + else + ok = 0; + } + else + ok = 0; + } + + if (!ok) /* Something went wrong, so pull down everything. */ + { + if (exe->pid) ecore_exe_terminate(exe); + IF_FN_DEL(ecore_exe_free, exe); + } + else + { + Ecore_Exe_Event_Add *e; + + e = _ecore_exe_event_add_new(); + e->exe = exe; + if (e) /* Send the event. */ + ecore_event_add(ECORE_EXE_EVENT_ADD, e, + _ecore_exe_event_add_free, NULL); + /* INF("Running as %d for %s.\n", exe->pid, exe->cmd); */ + } + + errno = n; + return exe; +} + +/** + * Defines a function to be called before really freeing the handle data. + * + * This might be useful for language bindings such as Python and Perl + * that need to deallocate wrappers associated with this handle. + * + * This handle should never be modified by this call. It should be + * considered informative only. All getters are valid when the given + * function is called back. + * + * @param exe The child process to attach the pre_free function. + * @param func The function to call before @a exe is freed. + */ +EAPI void +ecore_exe_callback_pre_free_set(Ecore_Exe *exe, + Ecore_Exe_Cb func) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, + "ecore_exe_callback_pre_free_set"); + return; + } + exe->pre_free_cb = func; +} + +/** + * Sends data to the given child process which it receives on stdin. + * + * This function writes to a child processes standard in, with unlimited + * buffering. This call will never block. It may fail if the system runs out + * of memory. + * + * @param exe The child process to send to + * @param data The data to send + * @param size The size of the data to send, in bytes + * @return @c EINA_TRUE if successful, @c EINA_FALSE on failure. + */ +EAPI Eina_Bool +ecore_exe_send(Ecore_Exe *exe, + const void *data, + int size) +{ + void *buf; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(EINA_FALSE); + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_send"); + return EINA_FALSE; + } + + if (exe->close_stdin) + { + ERR("Ecore_Exe %p stdin is closed! Cannot send %d bytes from %p", + exe, size, data); + return EINA_FALSE; + } + + if (exe->child_fd_write == -1) + { + ERR("Ecore_Exe %p created without ECORE_EXE_PIPE_WRITE! " + "Cannot send %d bytes from %p", exe, size, data); + return EINA_FALSE; + } + + buf = realloc(exe->write_data_buf, exe->write_data_size + size); + if (!buf) return EINA_FALSE; + + exe->write_data_buf = buf; + memcpy((char *)exe->write_data_buf + exe->write_data_size, data, size); + exe->write_data_size += size; + + if (exe->write_fd_handler) + ecore_main_fd_handler_active_set(exe->write_fd_handler, ECORE_FD_WRITE); + + return EINA_TRUE; +} + +/** + * The stdin of the given child process will close when the write buffer is empty. + * + * @param exe The child process + */ +EAPI void +ecore_exe_close_stdin(Ecore_Exe *exe) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_close_stdin"); + return; + } + exe->close_stdin = 1; +} + +/** + * Sets the auto pipe limits for the given process handle. On Windows + * this function does nothing. + * + * @param exe The given process handle. + * @param start_bytes limit of bytes at start of output to buffer. + * @param end_bytes limit of bytes at end of output to buffer. + * @param start_lines limit of lines at start of output to buffer. + * @param end_lines limit of lines at end of output to buffer. + */ +EAPI void +ecore_exe_auto_limits_set(Ecore_Exe *exe, + int start_bytes, + int end_bytes, + int start_lines, + int end_lines) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_auto_limits_set"); + return; + } + /* FIXME: sanitize the input. */ + exe->start_bytes = start_bytes; + exe->end_bytes = end_bytes; + exe->start_lines = start_lines; + exe->end_lines = end_lines; + + /* FIXME: get this can of worms working. + * + * capture stderr & stdout internally + * + * raster and onefang keep moving the goal posts on this one. It started out as + * "show users the error output if an exe fails" and is rapidly approaching + * "alternative method of getting the data, poll vs event driven". Some serious + * thinking needs to be applied to this. Do we really want to go that far? If + * so, we should change the names. The basic design will probably remain the + * same which ever way we go. The constant goal post moving is probably due to + * generic design methods leading to feature creep as we inspired each other to + * more generic designs. It does seem like the closer we get to poll driven, + * the more issues and corner cases there are. + * + * Instead of doing the usual register an event handler thing, we are ecore_exe, + * we can take some short cuts. Don't send the events, just leave the exe buffers + * as is until the user asks for them, then return the event. + * + * start = 0, end = 0; clogged arteries get flushed, everything is ignored. + * start = -1, end = -1; clogged arteries get transferred to internal buffers. Actually, either == -1 means buffer everything. + * start = X, end = 0; buffer first X out of clogged arteries, flush and ignore rest. + * start = 0, end = X; circular buffer X + * start = X, end = Y; buffer first X out of clogged arteries, circular buffer Y from beginning. + * + * bytes vs lines, which ever one reaches the limit first. + * Before we go beyond the start+end limit, leave the end buffer empty, and store both in the start buffer, coz they overlap. + * After we pass the the start+end limit, insert "\n...\n" at the end of the start buffer, copy the rest to the end buffer, then store in the end buffer. + * + * Other issues - + * Spank programmer for polling data if polling is not turned on. + * Spank programmer for setting up event callbacks if polling is turned on. + * Spank programmer for freeing the event data if it came from the event system, as that autofrees. + * Spank the programmer if they try to set the limits bigger than what has been gathered & ignored already, coz they just lost data. + * Spank onefang and raster for opening this can of worms. + * Should we have separate out/err limits? + * Should we remove from the internal buffer the data that was delivered already? + * If so, what to do about limits, start, and end? They could loose their meaning. + */ +} + +/** + * Gets the auto pipe data for the given process handle + * + * @param exe The given process handle. + * @param flags Is this a ECORE_EXE_PIPE_READ or ECORE_EXE_PIPE_ERROR? + * @return The event data. + */ +EAPI Ecore_Exe_Event_Data * +ecore_exe_event_data_get(Ecore_Exe *exe, + Ecore_Exe_Flags flags) +{ + Ecore_Exe_Event_Data *e = NULL; + int is_buffered = 0; + unsigned char *inbuf; + int inbuf_num; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_event_data_get"); + return NULL; + } + + /* Sort out what sort of event we are. */ + if (flags & ECORE_EXE_PIPE_READ) + { + flags = ECORE_EXE_PIPE_READ; + if (exe->flags & ECORE_EXE_PIPE_READ_LINE_BUFFERED) + is_buffered = 1; + } + else + { + flags = ECORE_EXE_PIPE_ERROR; + if (exe->flags & ECORE_EXE_PIPE_ERROR_LINE_BUFFERED) + is_buffered = 1; + } + + /* Get the data. */ + if (flags & ECORE_EXE_PIPE_READ) + { + inbuf = exe->read_data_buf; + inbuf_num = exe->read_data_size; + exe->read_data_buf = NULL; + exe->read_data_size = 0; + } + else + { + inbuf = exe->error_data_buf; + inbuf_num = exe->error_data_size; + exe->error_data_buf = NULL; + exe->error_data_size = 0; + } + + e = calloc(1, sizeof(Ecore_Exe_Event_Data)); + if (e) + { + e->exe = exe; + e->data = inbuf; + e->size = inbuf_num; + + if (is_buffered) /* Deal with line buffering. */ + { + int max = 0; + int count = 0; + int i; + int last = 0; + char *c; + + c = (char *)inbuf; + for (i = 0; i < inbuf_num; i++) /* Find the lines. */ + { + if (inbuf[i] == '\n') + { + if (count >= max) + { + /* In testing, the lines seem to arrive in batches of 500 to 1000 lines at most, roughly speaking. */ + max += 10; /* FIXME: Maybe keep track of the largest number of lines ever sent, and add half that many instead of 10. */ + e->lines = realloc(e->lines, sizeof(Ecore_Exe_Event_Data_Line) * (max + 1)); /* Allow room for the NULL termination. */ + } + /* raster said to leave the line endings as line endings, however - + * This is line buffered mode, we are not dealing with binary here, but lines. + * If we are not dealing with binary, we must be dealing with ASCII, unicode, or some other text format. + * Thus the user is most likely gonna deal with this text as strings. + * Thus the user is most likely gonna pass this data to str functions. + * rasters way - the endings are always gonna be '\n'; onefangs way - they will always be '\0' + * We are handing them the string length as a convenience. + * Thus if they really want it in raw format, they can e->lines[i].line[e->lines[i].size - 1] = '\n'; easily enough. + * In the default case, we can do this conversion quicker than the user can, as we already have the index and pointer. + * Let's make it easy on them to use these as standard C strings. + * + * onefang is proud to announce that he has just set a new personal record for the + * most over documentation of a simple assignment statement. B-) + */ + inbuf[i] = '\0'; + e->lines[count].line = c; + e->lines[count].size = i - last; + last = i + 1; + c = (char *)&inbuf[last]; + count++; + } + } + if (i > last) /* Partial line left over, save it for next time. */ + { + if (count != 0) e->size = last; + if (flags & ECORE_EXE_PIPE_READ) + { + exe->read_data_size = i - last; + exe->read_data_buf = malloc(exe->read_data_size); + memcpy(exe->read_data_buf, c, exe->read_data_size); + } + else + { + exe->error_data_size = i - last; + exe->error_data_buf = malloc(exe->error_data_size); + memcpy(exe->error_data_buf, c, exe->error_data_size); + } + } + if (count == 0) /* No lines to send, cancel the event. */ + { + _ecore_exe_event_exe_data_free(NULL, e); + e = NULL; + } + else /* NULL terminate the array, so that people know where the end is. */ + { + e->lines[count].line = NULL; + e->lines[count].size = 0; + } + } + } + + return e; +} + +/** + * Sets the string tag for the given process handle + * + * @param exe The given process handle. + * @param tag The string tag to set on the process handle. + */ +EAPI void +ecore_exe_tag_set(Ecore_Exe *exe, + const char *tag) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_tag_set"); + return; + } + IF_FREE(exe->tag); + if (tag) + exe->tag = strdup(tag); + else + exe->tag = NULL; +} + +/** + * Retrieves the tag attached to the given process handle. There is no need to + * free it as it just returns the internal pointer value. This value is only + * valid as long as the @p exe is valid or until the tag is set to something + * else on this @p exe. + * + * @param exe The given process handle. + * @return The string attached to @p exe. It is a handle to existing + * internal string and should not be modified, use + * ecore_exe_tag_set() to change it. It might be @c NULL. + */ +EAPI const char * +ecore_exe_tag_get(const Ecore_Exe *exe) +{ + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_tag_get"); + return NULL; + } + return exe->tag; +} + +/** + * Frees the given process handle. + * + * Note that the process that the handle represents is unaffected by this + * function. + * + * @param exe The given process handle. + * @return The data attached to the handle when @ref ecore_exe_run was + * called. + */ +EAPI void * +ecore_exe_free(Ecore_Exe *exe) +{ + void *data; + int ok = 0; + int result; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_free"); + return NULL; + } + + data = exe->data; + + if (exe->pre_free_cb) + exe->pre_free_cb(data, exe); + + if (exe->doomsday_clock) + { + struct _ecore_exe_dead_exe *dead; + + ecore_timer_del(exe->doomsday_clock); + exe->doomsday_clock = NULL; + dead = exe->doomsday_clock_dead; + if (dead) + { + IF_FREE(dead->cmd); + free(dead); + exe->doomsday_clock_dead = NULL; + } + } + IF_FN_DEL(ecore_main_fd_handler_del, exe->write_fd_handler); + IF_FN_DEL(ecore_main_fd_handler_del, exe->read_fd_handler); + IF_FN_DEL(ecore_main_fd_handler_del, exe->error_fd_handler); + if (exe->child_fd_write_x != -1) + E_NO_ERRNO(result, close(exe->child_fd_write_x), ok); + if (exe->child_fd_read_x != -1) + E_NO_ERRNO(result, close(exe->child_fd_read_x), ok); + if (exe->child_fd_error_x != -1) + E_NO_ERRNO(result, close(exe->child_fd_error_x), ok); + if (exe->child_fd_write != -1) + E_NO_ERRNO(result, close(exe->child_fd_write), ok); + if (exe->child_fd_read != -1) + E_NO_ERRNO(result, close(exe->child_fd_read), ok); + if (exe->child_fd_error != -1) + E_NO_ERRNO(result, close(exe->child_fd_error), ok); + IF_FREE(exe->write_data_buf); + IF_FREE(exe->read_data_buf); + IF_FREE(exe->error_data_buf); + IF_FREE(exe->cmd); + + exes = (Ecore_Exe *)eina_inlist_remove(EINA_INLIST_GET(exes), EINA_INLIST_GET(exe)); + ECORE_MAGIC_SET(exe, ECORE_MAGIC_NONE); + IF_FREE(exe->tag); + free(exe); + return data; +} + +/** + * Frees the given event data. + * + * @param e The given event data. + */ +EAPI void +ecore_exe_event_data_free(Ecore_Exe_Event_Data *e) +{ + if (!e) return; + IF_FREE(e->lines); + IF_FREE(e->data); + free(e); +} + +/** + * Retrieves the process ID of the given spawned process. + * @param exe Handle to the given spawned process. + * @return The process ID on success. @c -1 otherwise. + */ +EAPI pid_t +ecore_exe_pid_get(const Ecore_Exe *exe) +{ + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0); + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_pid_get"); + return -1; + } + return exe->pid; +} + +/** + * Retrieves the command of the given spawned process. + * @param exe Handle to the given spawned process. + * @return The command on success, @c NULL otherwise. This string is the + * pointer to the internal value and must not be modified in + * any way. + */ +EAPI const char * +ecore_exe_cmd_get(const Ecore_Exe *exe) +{ + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_cmd_get"); + return NULL; + } + return exe->cmd; +} + +/** + * Retrieves the data attached to the given process handle. + * @param exe The given process handle. + * @return The data pointer attached to @p exe Given to + * ecore_exe_run() or ecore_exe_pipe_run() + */ +EAPI void * +ecore_exe_data_get(const Ecore_Exe *exe) +{ + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_data_get"); + return NULL; + } + return exe->data; +} + +/** + * Sets the data attached to the given process handle. + * @param exe The given process handle. + * @param data The pointer to attach + * @return The data pointer previously attached to @p exe with + * ecore_exe_run(), ecore_exe_pipe_run(), or ecore_exe_data_set() + * @since 1.1 + */ +EAPI void * +ecore_exe_data_set(Ecore_Exe *exe, + void *data) +{ + void *ret; + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, __func__); + return NULL; + } + ret = exe->data; + exe->data = data; + return ret; +} + +/** + * Retrieves the flags attached to the given process handle. + * @param exe The given process handle. + * @return The flags attached to @p exe. + */ +EAPI Ecore_Exe_Flags +ecore_exe_flags_get(const Ecore_Exe *exe) +{ + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0); + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_data_get"); + return 0; + } + return exe->flags; +} + +/** + * Pauses the given process by sending it a @c SIGSTOP signal. + * @param exe Process handle to the given process. + */ +EAPI void +ecore_exe_pause(Ecore_Exe *exe) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_pause"); + return; + } + kill(exe->pid, SIGSTOP); +} + +/** + * Continues the given paused process by sending it a @c SIGCONT signal. + * @param exe Process handle to the given process. + */ +EAPI void +ecore_exe_continue(Ecore_Exe *exe) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_continue"); + return; + } + kill(exe->pid, SIGCONT); +} + +/** + * Sends the given spawned process a interrupt (@c SIGINT) signal. + * @param exe Process handle to the given process. + */ +EAPI void +ecore_exe_interrupt(Ecore_Exe *exe) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_interrupt"); + return; + } + _ecore_exe_dead_attach(exe); + kill(exe->pid, SIGINT); +} + +/** + * Sends the given spawned process a quit (@c SIGQUIT) signal. + * @param exe Process handle to the given process. + */ +EAPI void +ecore_exe_quit(Ecore_Exe *exe) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_quit"); + return; + } + _ecore_exe_dead_attach(exe); + kill(exe->pid, SIGQUIT); +} + +/** + * Sends the given spawned process a terminate (@c SIGTERM) signal. + * @param exe Process handle to the given process. + */ +EAPI void +ecore_exe_terminate(Ecore_Exe *exe) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_terminate"); + return; + } + _ecore_exe_dead_attach(exe); + INF("Sending TERM signal to %s (%d).", exe->cmd, exe->pid); + kill(exe->pid, SIGTERM); +} + +/** + * Kills the given spawned process by sending it a @c SIGKILL signal. + * @param exe Process handle to the given process. + */ +EAPI void +ecore_exe_kill(Ecore_Exe *exe) +{ + struct _ecore_exe_dead_exe *dead; + + EINA_MAIN_LOOP_CHECK_RETURN; + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_kill"); + return; + } + + dead = calloc(1, sizeof(struct _ecore_exe_dead_exe)); + if (dead) + { + dead->pid = exe->pid; + dead->cmd = strdup(exe->cmd); + IF_FN_DEL(ecore_timer_del, exe->doomsday_clock); + exe->doomsday_clock = + ecore_timer_add(10.0, _ecore_exe_make_sure_its_really_dead, dead); + } + + INF("Sending KILL signal to %s (%d).", exe->cmd, exe->pid); + kill(exe->pid, SIGKILL); +} + +/** + * Sends a @c SIGUSR signal to the given spawned process. + * @param exe Process handle to the given process. + * @param num The number user signal to send. Must be either 1 or 2, or + * the signal will be ignored. + */ +EAPI void +ecore_exe_signal(Ecore_Exe *exe, + int num) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_signal"); + return; + } + if (num == 1) + kill(exe->pid, SIGUSR1); + else if (num == 2) + kill(exe->pid, SIGUSR2); +} + +/** + * Sends a @c SIGHUP signal to the given spawned process. + * @param exe Process handle to the given process. + */ +EAPI void +ecore_exe_hup(Ecore_Exe *exe) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_hup"); + return; + } + kill(exe->pid, SIGHUP); +} + +/** + * @} + */ + +static Ecore_Exe * +_ecore_exe_is_it_alive(pid_t pid) +{ + Ecore_Exe *exe = NULL; + + /* FIXME: There is no nice, safe, OS independent way to tell if a + * particular PID is still alive. I have written code to do so + * for my urunlevel busybox applet (http://urunlevel.sourceforge.net/), + * but it's for linux only, and still not guaranteed. + * + * So for now, we just check that a valid Ecore_Exe structure + * exists for it. Even that is not a guarantee, as the structure + * can be freed without killing the process. + * + * I think we can safely put exe's into two categories, those users + * that care about the life of the exe, and the run and forget type. + * The run and forget type starts up the exe, then free's the + * Ecore_Exe structure straight away. They can never call any of + * the functions that can call this, so we don't worry about them. + * + * Those user's that care about the life of exe's will keep the + * Ecore_Exe structure around, terminate them eventually, or + * register for exit events. For these ones the assumption + * that valid Ecore_Exe struct == live exe is almost valid. + * + * I will probably copy my urunlevel code into here someday. + */ + exe = _ecore_exe_find(pid); + if (exe) + { + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + exe = NULL; + } + + return exe; +} + +static Eina_Bool +_ecore_exe_make_sure_its_dead(void *data) +{ + struct _ecore_exe_dead_exe *dead; + + dead = data; + if (dead) + { + Ecore_Exe *exe = NULL; + + if ((exe = _ecore_exe_is_it_alive(dead->pid))) + { + if (dead->cmd) + INF("Sending KILL signal to allegedly dead %s (%d).", + dead->cmd, dead->pid); + else + INF("Sending KILL signal to allegedly dead PID %d.", + dead->pid); + exe->doomsday_clock = + ecore_timer_add(10.0, _ecore_exe_make_sure_its_really_dead, + dead); + kill(dead->pid, SIGKILL); + } + else + { + IF_FREE(dead->cmd); + free(dead); + } + } + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool +_ecore_exe_make_sure_its_really_dead(void *data) +{ + struct _ecore_exe_dead_exe *dead; + + dead = data; + if (dead) + { + Ecore_Exe *exe = NULL; + + if ((exe = _ecore_exe_is_it_alive(dead->pid))) + { + ERR("RUN! The zombie wants to eat your brains! And your CPU!"); + if (dead->cmd) + INF("%s (%d) is not really dead.", dead->cmd, dead->pid); + else + INF("PID %d is not really dead.", dead->pid); + exe->doomsday_clock = NULL; + } + IF_FREE(dead->cmd); + free(dead); + } + return ECORE_CALLBACK_CANCEL; +} + +void +_ecore_exe_init(void) +{ + ECORE_EXE_EVENT_ADD = ecore_event_type_new(); + ECORE_EXE_EVENT_DEL = ecore_event_type_new(); + ECORE_EXE_EVENT_DATA = ecore_event_type_new(); + ECORE_EXE_EVENT_ERROR = ecore_event_type_new(); +} + +void +_ecore_exe_shutdown(void) +{ + while (exes) + ecore_exe_free(exes); +} + +Ecore_Exe * +_ecore_exe_find(pid_t pid) +{ + Ecore_Exe *exe; + + EINA_INLIST_FOREACH(exes, exe) + { + if (exe->pid == pid) + return exe; + } + return NULL; +} + +Ecore_Timer * +_ecore_exe_doomsday_clock_get(Ecore_Exe *exe) +{ + return exe->doomsday_clock; +} + +void +_ecore_exe_doomsday_clock_set(Ecore_Exe *exe, + Ecore_Timer *dc) +{ + exe->doomsday_clock = dc; +} + +static inline void +_ecore_exe_exec_it(const char *exe_cmd, + Ecore_Exe_Flags flags) +{ + char use_sh = 1; + char *buf = NULL; + char **args = NULL; + int save_errno = 0; + + /* So what is this doing? + * + * We are trying to avoid wrapping the exe call with /bin/sh -c. + * We conservatively search for certain shell meta characters, + * If we don't find them, we can call the exe directly. + */ + if (!strpbrk(exe_cmd, "|&;<>()$`\\\"'*?#")) + { + char *token; + char pre_command = 1; + int num_tokens = 0; + + if (!(buf = strdup(exe_cmd))) + return; + + token = strtok(buf, " \t\n\v"); + while (token) + { + if (token[0] == '~') + break; + if (pre_command) + { + if (token[0] == '[') + break; + if (strchr(token, '=')) + break; + else + pre_command = 0; + } + num_tokens++; + token = strtok(NULL, " \t\n\v"); + } + IF_FREE(buf); + if ((!token) && (num_tokens)) + { + int i = 0; + + if (!(buf = strdup(exe_cmd))) + return; + + token = strtok(buf, " \t\n\v"); + use_sh = 0; + if (!(args = (char **)calloc(num_tokens + 1, sizeof(char *)))) + { + IF_FREE(buf); + return; + } + for (i = 0; i < num_tokens; i++) + { + if (token) + args[i] = token; + token = strtok(NULL, " \t\n\v"); + } + args[num_tokens] = NULL; + } + } + +#ifdef HAVE_SYS_PRCTL_H + if ((flags & ECORE_EXE_TERM_WITH_PARENT)) + { + prctl(PR_SET_PDEATHSIG, SIGTERM); + } +#endif + + if (!(flags & ECORE_EXE_NOT_LEADER)) setsid(); + if ((flags & ECORE_EXE_USE_SH)) + { + errno = 0; + execl("/bin/sh", "/bin/sh", "-c", exe_cmd, (char *)NULL); + } + else if (use_sh) /* We have to use a shell to run this. */ + { + if (!shell) /* Find users preferred shell. */ + { + shell = getenv("SHELL"); + if (!shell) + shell = "/bin/sh"; + } + errno = 0; + execl(shell, shell, "-c", exe_cmd, (char *)NULL); + } + else + { /* We can run this directly. */ + if (!args) + { + IF_FREE(buf); + IF_FREE(args); + ERR("arg[0] is NULL!"); + return; + } + errno = 0; + execvp(args[0], args); + } + + save_errno = errno; + IF_FREE(buf); + IF_FREE(args); + errno = save_errno; + return; +} + +static Eina_Bool +_ecore_exe_data_generic_handler(void *data, + Ecore_Fd_Handler *fd_handler, + Ecore_Exe_Flags flags) +{ + Ecore_Exe *exe; + int child_fd; + int event_type; + + exe = data; + + /* Sort out what sort of handler we are. */ + if (flags & ECORE_EXE_PIPE_READ) + { + flags = ECORE_EXE_PIPE_READ; + event_type = ECORE_EXE_EVENT_DATA; + child_fd = exe->child_fd_read; + } + else + { + flags = ECORE_EXE_PIPE_ERROR; + event_type = ECORE_EXE_EVENT_ERROR; + child_fd = exe->child_fd_error; + } + + if ((fd_handler) + && (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))) + { + unsigned char *inbuf; + int inbuf_num; + + /* Get any left over data from last time. */ + if (flags & ECORE_EXE_PIPE_READ) + { + inbuf = exe->read_data_buf; + inbuf_num = exe->read_data_size; + exe->read_data_buf = NULL; + exe->read_data_size = 0; + } + else + { + inbuf = exe->error_data_buf; + inbuf_num = exe->error_data_size; + exe->error_data_buf = NULL; + exe->error_data_size = 0; + } + + for (;; ) + { + int num, lost_exe; + char buf[READBUFSIZ]; + + lost_exe = 0; + errno = 0; + if ((num = read(child_fd, buf, READBUFSIZ)) < 1) + { + /* FIXME: SPEED/SIZE TRADE OFF - add a smaller READBUFSIZE + * (currently 64k) to inbuf, use that instead of buf, and + * save ourselves a memcpy(). */ + lost_exe = ((errno == EIO) || + (errno == EBADF) || + (errno == EPIPE) || + (errno == EINVAL) || (errno == ENOSPC)); + if ((errno != EAGAIN) && (errno != EINTR)) + perror("_ecore_exe_generic_handler() read problem "); + } + if (num > 0) /* data got read. */ + { + inbuf = realloc(inbuf, inbuf_num + num); + memcpy(inbuf + inbuf_num, buf, num); + inbuf_num += num; + } + else + { /* No more data to read. */ + if (inbuf) + { + Ecore_Exe_Event_Data *e; + + /* Stash the data away for later. */ + if (flags & ECORE_EXE_PIPE_READ) + { + exe->read_data_buf = inbuf; + exe->read_data_size = inbuf_num; + } + else + { + exe->error_data_buf = inbuf; + exe->error_data_size = inbuf_num; + } + + if (!(exe->flags & ECORE_EXE_PIPE_AUTO)) + { + e = ecore_exe_event_data_get(exe, flags); + if (e) /* Send the event. */ + ecore_event_add(event_type, e, + _ecore_exe_event_exe_data_free, + NULL); + } + } + if (lost_exe) + { + if (flags & ECORE_EXE_PIPE_READ) + { + if (exe->read_data_size) + INF("There are %d bytes left unsent from the dead exe %s.", + exe->read_data_size, exe->cmd); + } + else + { + if (exe->error_data_size) + INF("There are %d bytes left unsent from the dead exe %s.", + exe->error_data_size, exe->cmd); + } + /* Thought about this a bit. If the exe has actually + * died, this won't do any harm as it must have died + * recently and the pid has not had a chance to recycle. + * It is also a paranoid catchall, coz the usual ecore_signal + * mechenism should kick in. But let's give it a good + * kick in the head anyway. + */ + ecore_exe_terminate(exe); + } + break; + } + } + } + + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +_ecore_exe_data_error_handler(void *data, + Ecore_Fd_Handler *fd_handler) +{ + return _ecore_exe_data_generic_handler(data, fd_handler, + ECORE_EXE_PIPE_ERROR); +} + +static Eina_Bool +_ecore_exe_data_read_handler(void *data, + Ecore_Fd_Handler *fd_handler) +{ + return _ecore_exe_data_generic_handler(data, fd_handler, + ECORE_EXE_PIPE_READ); +} + +static Eina_Bool +_ecore_exe_data_write_handler(void *data, + Ecore_Fd_Handler *fd_handler __UNUSED__) +{ + Ecore_Exe *exe; + + exe = data; + if ((exe->write_fd_handler) && + (ecore_main_fd_handler_active_get + (exe->write_fd_handler, ECORE_FD_WRITE))) + _ecore_exe_flush(exe); + + /* If we have sent all there is to send, and we need to close the pipe, then close it. */ + if ((exe->close_stdin == 1) + && (exe->write_data_size == exe->write_data_offset)) + { + int ok = 0; + int result; + + INF("Closing stdin for %s", exe->cmd); + /* if (exe->child_fd_write != -1) E_NO_ERRNO(result, fsync(exe->child_fd_write), ok); This a) doesn't work, and b) isn't needed. */ + IF_FN_DEL(ecore_main_fd_handler_del, exe->write_fd_handler); + if (exe->child_fd_write != -1) + E_NO_ERRNO(result, close(exe->child_fd_write), ok); + exe->child_fd_write = -1; + IF_FREE(exe->write_data_buf); + } + + return ECORE_CALLBACK_RENEW; +} + +static void +_ecore_exe_flush(Ecore_Exe *exe) +{ + int count; + + /* check whether we need to write anything at all. */ + if ((exe->child_fd_write == -1) || (!exe->write_data_buf)) + return; + if (exe->write_data_size == exe->write_data_offset) + return; + + count = write(exe->child_fd_write, + (char *)exe->write_data_buf + exe->write_data_offset, + exe->write_data_size - exe->write_data_offset); + if (count < 1) + { + if (errno == EIO || errno == EBADF || errno == EPIPE || errno == EINVAL || errno == ENOSPC) /* we lost our exe! */ + { + ecore_exe_terminate(exe); + if (exe->write_fd_handler) + ecore_main_fd_handler_active_set(exe->write_fd_handler, 0); + } + } + else + { + exe->write_data_offset += count; + if (exe->write_data_offset >= exe->write_data_size) /* Nothing left to write, clean up. */ + { + exe->write_data_size = 0; + exe->write_data_offset = 0; + IF_FREE(exe->write_data_buf); + if (exe->write_fd_handler) + ecore_main_fd_handler_active_set(exe->write_fd_handler, 0); + } + } +} + +static void +_ecore_exe_event_exe_data_free(void *data __UNUSED__, + void *ev) +{ + Ecore_Exe_Event_Data *e; + + e = ev; + ecore_exe_event_data_free(e); +} + +static Ecore_Exe_Event_Add * +_ecore_exe_event_add_new(void) +{ + Ecore_Exe_Event_Add *e; + + e = calloc(1, sizeof(Ecore_Exe_Event_Add)); + return e; +} + +static void +_ecore_exe_event_add_free(void *data __UNUSED__, + void *ev) +{ + Ecore_Exe_Event_Add *e; + + e = ev; + free(e); +} + +void * +_ecore_exe_event_del_new(void) +{ + Ecore_Exe_Event_Del *e; + + e = calloc(1, sizeof(Ecore_Exe_Event_Del)); + return e; +} + +void +_ecore_exe_event_del_free(void *data __UNUSED__, + void *ev) +{ + Ecore_Exe_Event_Del *e; + + e = ev; + if (e->exe) + ecore_exe_free(e->exe); + free(e); +} + +static void +_ecore_exe_dead_attach(Ecore_Exe *exe) +{ + struct _ecore_exe_dead_exe *dead; + + if (exe->doomsday_clock_dead) return; + dead = calloc(1, sizeof(struct _ecore_exe_dead_exe)); + if (dead) + { + dead->pid = exe->pid; + dead->cmd = strdup(exe->cmd); + IF_FN_DEL(ecore_timer_del, exe->doomsday_clock); + exe->doomsday_clock = + ecore_timer_add(10.0, _ecore_exe_make_sure_its_dead, dead); + exe->doomsday_clock_dead = dead; + } +} + diff --git a/src/lib/ecore/ecore_exe_ps3.c b/src/lib/ecore/ecore_exe_ps3.c new file mode 100644 index 0000000..1ef1e81 --- /dev/null +++ b/src/lib/ecore/ecore_exe_ps3.c @@ -0,0 +1,20 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_ESCAPE +# include +#endif + +#include "Ecore.h" +#include "ecore_private.h" + +void +_ecore_exe_init(void) +{ +} + +void +_ecore_exe_shutdown(void) +{ +} diff --git a/src/lib/ecore/ecore_exe_win32.c b/src/lib/ecore/ecore_exe_win32.c new file mode 100644 index 0000000..1f5cb4e --- /dev/null +++ b/src/lib/ecore/ecore_exe_win32.c @@ -0,0 +1,1055 @@ +/* + * TODO: + * - manage I/O pipes (several ones, and stdin) + * - manage SetConsoleCtrlHandler ? + * - the child process seems to still run after the DEL event + * - add log messages + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_EVIL +# include +#endif + +#include "Ecore.h" +#include "ecore_private.h" + +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN +#include + +#define ECORE_EXE_WIN32_TIMEOUT 3000 + +typedef enum +{ + ECORE_EXE_WIN32_SIGINT, + ECORE_EXE_WIN32_SIGQUIT, + ECORE_EXE_WIN32_SIGTERM, + ECORE_EXE_WIN32_SIGKILL +} Ecore_Exe_Win32_Signal; + +struct _Ecore_Exe +{ + EINA_INLIST; + ECORE_MAGIC; + + HANDLE process2; + HANDLE process; /* CloseHandle */ + HANDLE process_thread; + DWORD process_id; + DWORD thread_id; + void *data; + char *tag; + char *cmd; + Ecore_Exe_Flags flags; + Ecore_Exe_Win32_Signal sig; + Ecore_Win32_Handler *h_close; + struct + { + HANDLE child_pipe; + HANDLE child_pipe_x; + Ecore_Pipe *p; + HANDLE thread; + void *data_buf; + int data_size; + } pipe_read; + struct + { + HANDLE child_pipe; + HANDLE child_pipe_x; + HANDLE thread; + Ecore_Win32_Handler *h; + void *data_buf; + int data_size; + } pipe_write; + struct + { + HANDLE child_pipe; + HANDLE child_pipe_x; + Ecore_Pipe *p; + HANDLE thread; + void *data_buf; + int data_size; + } pipe_error; + Eina_Bool close_stdin : 1; + Eina_Bool is_suspended : 1; + + Ecore_Exe_Cb pre_free_cb; +}; + +static Ecore_Exe *exes = NULL; + +static int _ecore_exe_win32_pipes_set(Ecore_Exe *exe); +static void _ecore_exe_win32_pipes_close(Ecore_Exe *exe); + +static BOOL CALLBACK _ecore_exe_enum_windows_procedure(HWND window, + LPARAM data); +static void _ecore_exe_event_add_free(void *data, + void *ev); +static void _ecore_exe_event_del_free(void *data, + void *ev); +static void _ecore_exe_event_exe_data_free(void *data, + void *ev); +static int _ecore_exe_win32_pipe_thread_generic_cb(void *data, + Ecore_Exe_Flags flags); +static DWORD WINAPI _ecore_exe_win32_pipe_thread_read_cb(void *data); +static DWORD WINAPI _ecore_exe_win32_pipe_thread_error_cb(void *data); +static Eina_Bool _ecore_exe_close_cb(void *data, + Ecore_Win32_Handler *wh); +static void _ecore_exe_pipe_read_cb(void *data, + void *buf, + unsigned int size); +static int _ecore_exe_pipe_write_cb(void *data, + Ecore_Win32_Handler *wh); +static void _ecore_exe_pipe_error_cb(void *data, + void *buf, + unsigned int size); + +EAPI int ECORE_EXE_EVENT_ADD = 0; +EAPI int ECORE_EXE_EVENT_DEL = 0; +EAPI int ECORE_EXE_EVENT_DATA = 0; +EAPI int ECORE_EXE_EVENT_ERROR = 0; + +void +_ecore_exe_init(void) +{ + ECORE_EXE_EVENT_ADD = ecore_event_type_new(); + ECORE_EXE_EVENT_DEL = ecore_event_type_new(); + ECORE_EXE_EVENT_DATA = ecore_event_type_new(); + ECORE_EXE_EVENT_ERROR = ecore_event_type_new(); +} + +void +_ecore_exe_shutdown(void) +{ + while (exes) + ecore_exe_free(exes); +} + +static int run_pri = NORMAL_PRIORITY_CLASS; + +EAPI void +ecore_exe_run_priority_set(int pri) +{ + switch (pri) + { + case ECORE_EXE_WIN32_PRIORITY_IDLE: + run_pri = IDLE_PRIORITY_CLASS; + break; + + case ECORE_EXE_WIN32_PRIORITY_BELOW_NORMAL: + run_pri = BELOW_NORMAL_PRIORITY_CLASS; + break; + + case ECORE_EXE_WIN32_PRIORITY_NORMAL: + run_pri = NORMAL_PRIORITY_CLASS; + break; + + case ECORE_EXE_WIN32_PRIORITY_ABOVE_NORMAL: + run_pri = ABOVE_NORMAL_PRIORITY_CLASS; + break; + + case ECORE_EXE_WIN32_PRIORITY_HIGH: + run_pri = HIGH_PRIORITY_CLASS; + break; + + case ECORE_EXE_WIN32_PRIORITY_REALTIME: + run_pri = REALTIME_PRIORITY_CLASS; + break; + + default: + break; + } +} + +EAPI int +ecore_exe_run_priority_get(void) +{ + switch (run_pri) + { + case IDLE_PRIORITY_CLASS: + return ECORE_EXE_WIN32_PRIORITY_IDLE; + + case BELOW_NORMAL_PRIORITY_CLASS: + return ECORE_EXE_WIN32_PRIORITY_BELOW_NORMAL; + + case NORMAL_PRIORITY_CLASS: + return ECORE_EXE_WIN32_PRIORITY_NORMAL; + + case ABOVE_NORMAL_PRIORITY_CLASS: + return ECORE_EXE_WIN32_PRIORITY_ABOVE_NORMAL; + + case HIGH_PRIORITY_CLASS: + return ECORE_EXE_WIN32_PRIORITY_HIGH; + + case REALTIME_PRIORITY_CLASS: + return ECORE_EXE_WIN32_PRIORITY_REALTIME; + + /* default should not be reached */ + default: + return ECORE_EXE_WIN32_PRIORITY_NORMAL; + } +} + +EAPI Ecore_Exe * +ecore_exe_run(const char *exe_cmd, + const void *data) +{ + return ecore_exe_pipe_run(exe_cmd, 0, data); +} + +EAPI Ecore_Exe * +ecore_exe_pipe_run(const char *exe_cmd, + Ecore_Exe_Flags flags, + const void *data) +{ + STARTUPINFO si; + PROCESS_INFORMATION pi; + Ecore_Exe_Event_Add *e; + Ecore_Exe *exe; + char *ret = NULL; + + exe = calloc(1, sizeof(Ecore_Exe)); + if (!exe) + return NULL; + + if ((flags & ECORE_EXE_PIPE_AUTO) && (!(flags & ECORE_EXE_PIPE_ERROR)) + && (!(flags & ECORE_EXE_PIPE_READ))) + /* We need something to auto pipe. */ + flags |= ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR; + + exe->flags = flags; + if (exe->flags & ECORE_EXE_PIPE_READ) + if (!_ecore_exe_win32_pipes_set(exe)) + goto free_exe; + + if (exe->flags & ECORE_EXE_PIPE_WRITE) + if (!_ecore_exe_win32_pipes_set(exe)) + goto close_pipes; + + if (exe->flags & ECORE_EXE_PIPE_ERROR) + if (!_ecore_exe_win32_pipes_set(exe)) + goto close_pipes; + + if ((exe->flags & ECORE_EXE_USE_SH) || + ((ret = strrstr(exe_cmd, ".bat")) && (ret[4] == '\0'))) + { + char buf[PATH_MAX]; + snprintf(buf, PATH_MAX, "cmd.exe /c %s", exe_cmd); + exe->cmd = strdup(buf); + } + else + exe->cmd = strdup(exe_cmd); + + if (!exe->cmd) + goto close_pipes; + + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + si.hStdOutput = exe->pipe_read.child_pipe_x; + si.hStdInput = exe->pipe_write.child_pipe; + si.hStdError = exe->pipe_error.child_pipe_x; + si.dwFlags |= STARTF_USESTDHANDLES; + + /* FIXME: gerer la priorite */ + + if (!CreateProcess(NULL, exe->cmd, NULL, NULL, EINA_TRUE, + run_pri | CREATE_SUSPENDED, NULL, NULL, &si, &pi)) + goto free_exe_cmd; + + /* be sure that the child process is running */ + /* FIXME: This does not work if the child is an EFL-based app */ + /* if (WaitForInputIdle(pi.hProcess, INFINITE) == WAIT_FAILED) */ + /* goto free_exe_cmd; */ + + ECORE_MAGIC_SET(exe, ECORE_MAGIC_EXE); + exe->process = pi.hProcess; + exe->process_thread = pi.hThread; + exe->process_id = pi.dwProcessId; + exe->thread_id = pi.dwThreadId; + exe->data = (void *)data; + + if (!(exe->process2 = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_SUSPEND_RESUME | PROCESS_TERMINATE | SYNCHRONIZE, + EINA_FALSE, pi.dwProcessId))) + goto close_thread; + + exe->h_close = ecore_main_win32_handler_add(exe->process2, _ecore_exe_close_cb, exe); + if (!exe->h_close) goto close_process2; + + if (ResumeThread(exe->process_thread) == ((DWORD)-1)) + goto close_process2; + + exes = (Ecore_Exe *)eina_inlist_append(EINA_INLIST_GET(exes), EINA_INLIST_GET(exe)); + + e = (Ecore_Exe_Event_Add *)calloc(1, sizeof(Ecore_Exe_Event_Add)); + if (!e) goto delete_h_close; + + e->exe = exe; + ecore_event_add(ECORE_EXE_EVENT_ADD, e, + _ecore_exe_event_add_free, NULL); + + return exe; + +delete_h_close: + ecore_main_win32_handler_del(exe->h_close); +close_process2: + CloseHandle(exe->process2); +close_thread: + CloseHandle(exe->process_thread); + CloseHandle(exe->process); +free_exe_cmd: + free(exe->cmd); +close_pipes: + _ecore_exe_win32_pipes_close(exe); +free_exe: + free(exe); + return NULL; +} + +EAPI void +ecore_exe_callback_pre_free_set(Ecore_Exe *exe, + Ecore_Exe_Cb func) +{ + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, + "ecore_exe_callback_pre_free_set"); + return; + } + exe->pre_free_cb = func; +} + +EAPI Eina_Bool +ecore_exe_send(Ecore_Exe *exe, + const void *data, + int size) +{ + void *buf; + + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_send"); + return 0; + } + + if (exe->close_stdin) + { + ERR("Ecore_Exe %p stdin is closed! Cannot send %d bytes from %p", + exe, size, data); + return 0; + } + + if (!exe->pipe_write.child_pipe) + { + ERR("Ecore_Exe %p created without ECORE_EXE_PIPE_WRITE! " + "Cannot send %d bytes from %p", exe, size, data); + return 0; + } + + buf = realloc(exe->pipe_write.data_buf, exe->pipe_write.data_size + size); + if (!buf) return 0; + + exe->pipe_write.data_buf = buf; + memcpy((char *)exe->pipe_write.data_buf + exe->pipe_write.data_size, data, size); + exe->pipe_write.data_size += size; + + /* if (exe->pipe_write.) */ + /* ecore_main_fd_handler_active_set(exe->pipe_write.h, ECORE_FD_WRITE); */ + + return 1; +} + +EAPI void +ecore_exe_close_stdin(Ecore_Exe *exe) +{ + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_close_stdin"); + return; + } + exe->close_stdin = 1; +} + +/* Not used on Windows */ +EAPI void +ecore_exe_auto_limits_set(Ecore_Exe *exe __UNUSED__, + int start_bytes __UNUSED__, + int end_bytes __UNUSED__, + int start_lines __UNUSED__, + int end_lines __UNUSED__) +{ +} + +EAPI Ecore_Exe_Event_Data * +ecore_exe_event_data_get(Ecore_Exe *exe, + Ecore_Exe_Flags flags) +{ + Ecore_Exe_Event_Data *e = NULL; + unsigned char *inbuf; + int inbuf_num; + + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_event_data_get"); + return NULL; + } + + /* Sort out what sort of event we are, */ + /* And get the data. */ + if (flags & ECORE_EXE_PIPE_READ) + { + inbuf = exe->pipe_read.data_buf; + inbuf_num = exe->pipe_read.data_size; + exe->pipe_read.data_buf = NULL; + exe->pipe_read.data_size = 0; + } + else + { + inbuf = exe->pipe_error.data_buf; + inbuf_num = exe->pipe_error.data_size; + exe->pipe_error.data_buf = NULL; + exe->pipe_error.data_size = 0; + } + + e = calloc(1, sizeof(Ecore_Exe_Event_Data)); + if (e) + { + e->exe = exe; + e->data = inbuf; + e->size = inbuf_num; + } + + return e; +} + +EAPI void +ecore_exe_event_data_free(Ecore_Exe_Event_Data *e) +{ + if (!e) return; + IF_FREE(e->lines); + IF_FREE(e->data); + free(e); +} + +EAPI void * +ecore_exe_free(Ecore_Exe *exe) +{ + void *data; + + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_free"); + return NULL; + } + + data = exe->data; + + if (exe->pre_free_cb) + exe->pre_free_cb(data, exe); + + CloseHandle(exe->process2); + CloseHandle(exe->process_thread); + CloseHandle(exe->process); + free(exe->cmd); + _ecore_exe_win32_pipes_close(exe); + exes = (Ecore_Exe *)eina_inlist_remove(EINA_INLIST_GET(exes), EINA_INLIST_GET(exe)); + ECORE_MAGIC_SET(exe, ECORE_MAGIC_NONE); + if (exe->tag) free(exe->tag); + free(exe); + + return data; +} + +EAPI pid_t +ecore_exe_pid_get(const Ecore_Exe *exe) +{ + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_pid_get"); + return -1; + } + return exe->process_id; +} + +EAPI void +ecore_exe_tag_set(Ecore_Exe *exe, + const char *tag) +{ + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_tag_set"); + return; + } + IF_FREE(exe->tag); + if (tag) + exe->tag = strdup(tag); +} + +EAPI const char * +ecore_exe_tag_get(const Ecore_Exe *exe) +{ + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_tag_get"); + return NULL; + } + return exe->tag; +} + +EAPI const char * +ecore_exe_cmd_get(const Ecore_Exe *exe) +{ + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_cmd_get"); + return NULL; + } + return exe->cmd; +} + +EAPI void * +ecore_exe_data_get(const Ecore_Exe *exe) +{ + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_data_get"); + return NULL; + } + return exe->data; +} + +EAPI Ecore_Exe_Flags +ecore_exe_flags_get(const Ecore_Exe *exe) +{ + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_data_get"); + return 0; + } + return exe->flags; +} + +EAPI void +ecore_exe_pause(Ecore_Exe *exe) +{ + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_pause"); + return; + } + + if (exe->is_suspended) + return; + + if (SuspendThread(exe->process_thread) != (DWORD)-1) + exe->is_suspended = 1; +} + +EAPI void +ecore_exe_continue(Ecore_Exe *exe) +{ + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_continue"); + return; + } + + if (!exe->is_suspended) + return; + + if (ResumeThread(exe->process_thread) != (DWORD)-1) + exe->is_suspended = 0; +} + +EAPI void +ecore_exe_interrupt(Ecore_Exe *exe) +{ + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_interrupt"); + return; + } + + CloseHandle(exe->process_thread); + CloseHandle(exe->process); + exe->sig = ECORE_EXE_WIN32_SIGINT; + while (EnumWindows(_ecore_exe_enum_windows_procedure, (LPARAM)exe)) ; +} + +EAPI void +ecore_exe_quit(Ecore_Exe *exe) +{ + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_quit"); + return; + } + + CloseHandle(exe->process_thread); + CloseHandle(exe->process); + exe->sig = ECORE_EXE_WIN32_SIGQUIT; + while (EnumWindows(_ecore_exe_enum_windows_procedure, (LPARAM)exe)) ; +} + +EAPI void +ecore_exe_terminate(Ecore_Exe *exe) +{ + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_terminate"); + return; + } + +/* CloseHandle(exe->thread); */ + CloseHandle(exe->process); + exe->sig = ECORE_EXE_WIN32_SIGTERM; + while (EnumWindows(_ecore_exe_enum_windows_procedure, (LPARAM)exe)) ; +} + +EAPI void +ecore_exe_kill(Ecore_Exe *exe) +{ + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_kill"); + return; + } + + CloseHandle(exe->process_thread); + CloseHandle(exe->process); + exe->sig = ECORE_EXE_WIN32_SIGKILL; + while (EnumWindows(_ecore_exe_enum_windows_procedure, (LPARAM)exe)) ; +} + +EAPI void +ecore_exe_signal(Ecore_Exe *exe, + int num __UNUSED__) +{ + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_signal"); + return; + } + + /* does nothing */ +} + +EAPI void +ecore_exe_hup(Ecore_Exe *exe) +{ + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_hup"); + return; + } + + /* does nothing */ +} + +/* FIXME: manage error mode */ +static int +_ecore_exe_win32_pipe_thread_generic_cb(void *data, + Ecore_Exe_Flags flags) +{ +#define BUFSIZE 2048 + char buf[BUFSIZE]; + Ecore_Exe *exe; + char *current_buf = NULL; + HANDLE child_pipe; + Ecore_Pipe *ecore_pipe; + Ecore_Exe_Event_Data *event; + DWORD size; + DWORD current_size = 0; + BOOL res; + + exe = (Ecore_Exe *)data; + + /* Sort out what sort of handler we are. */ + /* And get any left over data from last time. */ + if ((exe->flags & ECORE_EXE_PIPE_READ) && (flags == ECORE_EXE_PIPE_READ)) + { + child_pipe = exe->pipe_read.child_pipe; + ecore_pipe = exe->pipe_read.p; + flags = ECORE_EXE_PIPE_READ; + } + else if ((exe->flags & ECORE_EXE_PIPE_ERROR) && (flags == ECORE_EXE_PIPE_ERROR)) + { + child_pipe = exe->pipe_error.child_pipe; + ecore_pipe = exe->pipe_error.p; + flags = ECORE_EXE_PIPE_ERROR; + } + else + return 0; + + while (1) + { + if (!PeekNamedPipe(child_pipe, buf, sizeof(buf), &size, ¤t_size, NULL)) + continue; + if (size == 0) + continue; + current_buf = (char *)malloc(current_size); + if (!current_buf) + continue; + res = ReadFile(child_pipe, current_buf, current_size, &size, NULL); + if (!res || (size == 0)) + { + free(current_buf); + current_buf = NULL; + continue; + } + if (current_size != size) + { + free(current_buf); + current_buf = NULL; + continue; + } + current_size = size; + + if (flags == ECORE_EXE_PIPE_READ) + { + exe->pipe_read.data_buf = current_buf; + exe->pipe_read.data_size = current_size; + } + else + { + exe->pipe_error.data_buf = current_buf; + exe->pipe_error.data_size = current_size; + } + + event = ecore_exe_event_data_get(exe, flags); + if (event) + ecore_pipe_write(ecore_pipe, &event, sizeof(event)); + + current_buf = NULL; + current_size = 0; + } + + return 1; +} + +static DWORD WINAPI +_ecore_exe_win32_pipe_thread_read_cb(void *data) +{ + return _ecore_exe_win32_pipe_thread_generic_cb(data, ECORE_EXE_PIPE_READ); +} + +static DWORD WINAPI +_ecore_exe_win32_pipe_thread_error_cb(void *data) +{ + return _ecore_exe_win32_pipe_thread_generic_cb(data, ECORE_EXE_PIPE_ERROR); +} + +static int +_ecore_exe_win32_pipes_set(Ecore_Exe *exe) +{ + SECURITY_ATTRIBUTES sa; + HANDLE child_pipe; + HANDLE child_pipe_x; + + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = EINA_TRUE; + sa.lpSecurityDescriptor = NULL; + + if (!CreatePipe(&child_pipe, &child_pipe_x, &sa, 0)) + return 0; + if (exe->flags & ECORE_EXE_PIPE_WRITE) + { + if (!SetHandleInformation(child_pipe_x, HANDLE_FLAG_INHERIT, 0)) + goto close_pipe; + } + else + { + if (!SetHandleInformation(child_pipe, HANDLE_FLAG_INHERIT, 0)) + goto close_pipe; + } + + if (exe->flags & ECORE_EXE_PIPE_READ) + { + exe->pipe_read.child_pipe = child_pipe; + exe->pipe_read.child_pipe_x = child_pipe_x; + exe->pipe_read.p = ecore_pipe_add(_ecore_exe_pipe_read_cb, exe); + exe->pipe_read.thread = CreateThread(NULL, 0, + _ecore_exe_win32_pipe_thread_read_cb, + exe, 0, NULL); + } + else if (exe->flags & ECORE_EXE_PIPE_WRITE) + { + exe->pipe_write.child_pipe = child_pipe; + exe->pipe_write.child_pipe_x = child_pipe_x; +/* exe->pipe_write.thread = CreateThread(NULL, 0, */ +/* _ecore_exe_win32_pipe_thread_cb, */ +/* exe, 0, NULL); */ + } + else + { + exe->pipe_error.child_pipe = child_pipe; + exe->pipe_error.child_pipe_x = child_pipe_x; + exe->pipe_error.p = ecore_pipe_add(_ecore_exe_pipe_error_cb, exe); + exe->pipe_error.thread = CreateThread(NULL, 0, + _ecore_exe_win32_pipe_thread_error_cb, + exe, 0, NULL); + } + + return 1; + +close_pipe: + CloseHandle(child_pipe); + CloseHandle(child_pipe_x); + + return 0; +} + +static void +_ecore_exe_win32_pipes_close(Ecore_Exe *exe) +{ + if (exe->flags & ECORE_EXE_PIPE_READ) + { + if (exe->pipe_read.child_pipe) + { + CloseHandle(exe->pipe_read.child_pipe); + exe->pipe_read.child_pipe = NULL; + } + if (exe->pipe_read.child_pipe_x) + { + CloseHandle(exe->pipe_read.child_pipe_x); + exe->pipe_read.child_pipe_x = NULL; + } + } + + if (exe->flags & ECORE_EXE_PIPE_WRITE) + { + if (exe->pipe_write.child_pipe) + { + CloseHandle(exe->pipe_write.child_pipe); + exe->pipe_write.child_pipe = NULL; + } + if (exe->pipe_write.child_pipe_x) + { + CloseHandle(exe->pipe_write.child_pipe_x); + exe->pipe_write.child_pipe_x = NULL; + } + } + + if (exe->flags & ECORE_EXE_PIPE_ERROR) + { + if (exe->pipe_error.child_pipe) + { + CloseHandle(exe->pipe_error.child_pipe); + exe->pipe_error.child_pipe = NULL; + } + if (exe->pipe_error.child_pipe_x) + { + CloseHandle(exe->pipe_error.child_pipe_x); + exe->pipe_error.child_pipe_x = NULL; + } + } +} + +static DWORD WINAPI +_ecore_exe_thread_procedure(LPVOID data __UNUSED__) +{ + GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); + GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0); + return 1; +} + +static BOOL CALLBACK +_ecore_exe_enum_windows_procedure(HWND window, + LPARAM data) +{ + Ecore_Exe *exe; + DWORD thread_id; + + exe = (Ecore_Exe *)data; + thread_id = GetWindowThreadProcessId(window, NULL); + + if (thread_id == exe->thread_id) + { + /* Ctrl-C or Ctrl-Break */ + if (CreateRemoteThread(exe->process, NULL, 0, + (LPTHREAD_START_ROUTINE)_ecore_exe_thread_procedure, NULL, + 0, NULL)) + { + printf ("remote thread\n"); + return EINA_FALSE; + } + + if ((exe->sig == ECORE_EXE_WIN32_SIGINT) || + (exe->sig == ECORE_EXE_WIN32_SIGQUIT)) + { + printf ("int or quit\n"); + return EINA_FALSE; + } + + /* WM_CLOSE message */ + PostMessage(window, WM_CLOSE, 0, 0); + if (WaitForSingleObject(exe->process, ECORE_EXE_WIN32_TIMEOUT) == WAIT_OBJECT_0) + { + printf ("CLOSE\n"); + return EINA_FALSE; + } + + /* WM_QUIT message */ + PostMessage(window, WM_QUIT, 0, 0); + if (WaitForSingleObject(exe->process, ECORE_EXE_WIN32_TIMEOUT) == WAIT_OBJECT_0) + { + printf ("QUIT\n"); + return EINA_FALSE; + } + + /* Exit process */ + if (CreateRemoteThread(exe->process, NULL, 0, + (LPTHREAD_START_ROUTINE)ExitProcess, NULL, + 0, NULL)) + { + printf ("remote thread 2\n"); + return EINA_FALSE; + } + + if (exe->sig == ECORE_EXE_WIN32_SIGTERM) + { + printf ("term\n"); + return EINA_FALSE; + } + + TerminateProcess(exe->process, 0); + + return EINA_FALSE; + } + + return EINA_TRUE; +} + +static void +_ecore_exe_event_add_free(void *data __UNUSED__, + void *ev) +{ + Ecore_Exe_Event_Add *e; + + e = (Ecore_Exe_Event_Add *)ev; + free(e); +} + +static void +_ecore_exe_event_del_free(void *data __UNUSED__, + void *ev) +{ + Ecore_Exe_Event_Del *e; + + e = (Ecore_Exe_Event_Del *)ev; + if (e->exe) + ecore_exe_free(e->exe); + free(e); +} + +static void +_ecore_exe_event_exe_data_free(void *data __UNUSED__, + void *ev) +{ + Ecore_Exe_Event_Data *e; + + e = (Ecore_Exe_Event_Data *)ev; + ecore_exe_event_data_free(e); +} + +static Eina_Bool +_ecore_exe_close_cb(void *data, + Ecore_Win32_Handler *wh __UNUSED__) +{ + Ecore_Exe_Event_Del *e; + Ecore_Exe *exe; + DWORD exit_code = 0; + + e = calloc(1, sizeof(Ecore_Exe_Event_Del)); + if (!e) return 0; + + exe = (Ecore_Exe *)data; + + if (GetExitCodeProcess(exe->process2, &exit_code)) + { + e->exit_code = exit_code; + e->exited = 1; + } + else + { + char *msg; + + msg = evil_last_error_get(); + printf("%s\n", msg); + free(msg); + } + e->pid = exe->process_id; + e->exe = exe; + + ecore_event_add(ECORE_EXE_EVENT_DEL, e, + _ecore_exe_event_del_free, NULL); + + return 0; +} + +static void +_ecore_exe_pipe_read_cb(void *data, + void *buf, + unsigned int size) +{ + Ecore_Exe_Event_Data *e; + + e = *((Ecore_Exe_Event_Data **)buf); + if (e) + ecore_event_add(ECORE_EXE_EVENT_DATA, e, + _ecore_exe_event_exe_data_free, + NULL); +} + +static int +_ecore_exe_pipe_write_cb(void *data, + Ecore_Win32_Handler *wh __UNUSED__) +{ + char buf[READBUFSIZ]; + Ecore_Exe *exe; + DWORD num_exe; + BOOL res; + + exe = (Ecore_Exe *)data; + + res = WriteFile(exe->pipe_write.child_pipe_x, buf, READBUFSIZ, &num_exe, NULL); + if (!res || num_exe == 0) + { + /* FIXME: what to do here ?? */ + } + + if (exe->close_stdin == 1) + { + if (exe->pipe_write.h) + { + ecore_main_win32_handler_del(exe->pipe_write.h); + exe->pipe_write.h = NULL; + } + exe->pipe_write.h = NULL; + CloseHandle(exe->pipe_write.child_pipe); + exe->pipe_write.child_pipe = NULL; + } + + return 1; +} + +static void +_ecore_exe_pipe_error_cb(void *data, + void *buf, + unsigned int size) +{ + Ecore_Exe_Event_Data *e; + + e = *((Ecore_Exe_Event_Data **)buf); + if (e) + ecore_event_add(ECORE_EXE_EVENT_ERROR, e, + _ecore_exe_event_exe_data_free, + NULL); +} + diff --git a/src/lib/ecore/ecore_exe_wince.c b/src/lib/ecore/ecore_exe_wince.c new file mode 100644 index 0000000..c07fcbe --- /dev/null +++ b/src/lib/ecore/ecore_exe_wince.c @@ -0,0 +1,21 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_EVIL +# include +#endif + +#include "Ecore.h" +#include "ecore_private.h" + +void +_ecore_exe_init(void) +{ +} + +void +_ecore_exe_shutdown(void) +{ +} + diff --git a/src/lib/ecore/ecore_getopt.c b/src/lib/ecore/ecore_getopt.c new file mode 100644 index 0000000..64f5f9c --- /dev/null +++ b/src/lib/ecore/ecore_getopt.c @@ -0,0 +1,1927 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_ALLOCA_H +# include +#elif defined __GNUC__ +# define alloca __builtin_alloca +#elif defined _AIX +# define alloca __alloca +#elif defined _MSC_VER +# include +# define alloca _alloca +#else +# include +# ifdef __cplusplus +extern "C" +# endif +void *alloca(size_t); +#endif + +#include +#include +#include +#include +#include + +#ifdef ENABLE_NLS +# include +#else +# define gettext(x) (x) +# define dgettext(domain, x) (x) +#endif + +#define _(x) dgettext("ecore", x) + +#ifdef _WIN32_WCE +# include +#endif + +#ifdef HAVE_EXOTIC +# include +#endif + +#include "Ecore.h" +#include "Ecore_Getopt.h" + +static const char *prog = NULL; +static char **_argv = NULL; +static int _argc = 0; +static int cols = 80; +static int helpcol = 80 / 3; + +static void +_ecore_getopt_help_print_replace_program(FILE *fp, + const Ecore_Getopt *parser __UNUSED__, + const char *text) +{ + do + { + const char *d = strchr(text, '%'); + + if (!d) + { + fputs(text, fp); + break; + } + + if (fwrite(text, 1, d - text, fp) != (size_t)(d - text)) + return; + d++; + if (strncmp(d, "prog", sizeof("prog") - 1) == 0) + { + fputs(prog ? prog : "???", fp); + d += sizeof("prog") - 1; + } + else + { + if (d[0] == '%') + d++; + fputc('%', fp); + } + + text = d; + } + while (text[0] != '\0'); + + fputc('\n', fp); +} + +static void +_ecore_getopt_version(FILE *fp, + const Ecore_Getopt *parser) +{ + fputs(_("Version:"), fp); + fputc(' ', fp); + _ecore_getopt_help_print_replace_program(fp, parser, parser->version); +} + +static void +_ecore_getopt_help_usage(FILE *fp, + const Ecore_Getopt *parser) +{ + fputs(_("Usage:"), fp); + fputc(' ', fp); + + if (!parser->usage) + { + fprintf(fp, _("%s [options]\n"), prog); + return; + } + + _ecore_getopt_help_print_replace_program(fp, parser, gettext(parser->usage)); +} + +static int +_ecore_getopt_help_line(FILE *fp, + const int base, + const int total, + int used, + const char *text, + int len) +{ + int linebreak = 0; + do + { + /* process line considering spaces (new line and tabs are spaces!) */ + while ((used < total) && (len > 0)) + { + const char *space = NULL; + int i, todo; + + todo = total - used; + if (todo > len) + todo = len; + + for (i = 0; i < todo; i++) + if (isspace((unsigned char)text[i])) + { + space = text + i; + break; + } + + if (space) + { + i = fwrite(text, 1, i, fp); + i++; + text += i; + len -= i; + used += i; + + if (linebreak) + { + linebreak = 0; + continue; + } + + if (space[0] == '\n') + break; + else if (space[0] == '\t') + { + int c; + + used--; + c = ((used / 8) + 1) * 8; + if (c < total) + { + for (; used < c; used++) + fputc(' ', fp); + } + else + { + text--; + len++; + break; + } + } + else if (used < total) + fputc(space[0], fp); + } + else + { + i = fwrite(text, 1, i, fp); + text += i; + len -= i; + used += i; + } + linebreak = 0; + } + if (len <= 0) + break; + linebreak = 1; + fputc('\n', fp); + for (used = 0; used < base; used++) + fputc(' ', fp); + } + while (1); + + return used; +} + +static void +_ecore_getopt_help_description(FILE *fp, + const Ecore_Getopt *parser) +{ + const char *p, *prg, *ver; + int used, prglen, verlen; + + p = gettext(parser->description); + if (!p) + return; + + fputc('\n', fp); + + prg = prog ? prog : "???"; + ver = parser->version ? parser->version : "???"; + + prglen = strlen(prg); + verlen = strlen(ver); + + used = 0; + + do + { + const char *d = strchr(p, '%'); + + if (!d) + { + _ecore_getopt_help_line(fp, 0, cols, used, p, strlen(p)); + break; + } + + used = _ecore_getopt_help_line(fp, 0, cols, used, p, d - p); + d++; + if (strncmp(d, "prog", sizeof("prog") - 1) == 0) + { + used = _ecore_getopt_help_line(fp, 0, cols, used, prg, prglen); + d += sizeof("prog") - 1; + } + else if (strncmp(d, "version", sizeof("version") - 1) == 0) + { + used = _ecore_getopt_help_line(fp, 0, cols, used, ver, verlen); + d += sizeof("version") - 1; + } + else + { + if (d[0] == '%') + d++; + used = _ecore_getopt_help_line(fp, 0, cols, used, "%", 1); + } + + p = d; + } + while (p[0] != '\0'); + + fputs("\n\n", fp); +} + +static void +_ecore_getopt_copyright(FILE *fp, + const Ecore_Getopt *parser) +{ + const char *txt = gettext(parser->copyright); + fputs(_("Copyright:"), fp); + fputs("\n ", fp); + _ecore_getopt_help_line + (fp, 3, cols, 3, txt, strlen(txt)); + fputc('\n', fp); +} + +static void +_ecore_getopt_license(FILE *fp, + const Ecore_Getopt *parser) +{ + const char *txt = gettext(parser->license); + fputs(_("License:"), fp); + fputs("\n ", fp); + _ecore_getopt_help_line + (fp, 3, cols, 3, txt, strlen(txt)); + fputc('\n', fp); +} + +static Ecore_Getopt_Desc_Arg_Requirement +_ecore_getopt_desc_arg_requirement(const Ecore_Getopt_Desc *desc) +{ + switch (desc->action) + { + case ECORE_GETOPT_ACTION_STORE: + return desc->action_param.store.arg_req; + + case ECORE_GETOPT_ACTION_STORE_CONST: + return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO; + + case ECORE_GETOPT_ACTION_STORE_TRUE: + return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO; + + case ECORE_GETOPT_ACTION_STORE_FALSE: + return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO; + + case ECORE_GETOPT_ACTION_CHOICE: + return ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES; + + case ECORE_GETOPT_ACTION_APPEND: + return ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES; + + case ECORE_GETOPT_ACTION_COUNT: + return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO; + + case ECORE_GETOPT_ACTION_CALLBACK: + return desc->action_param.callback.arg_req; + + case ECORE_GETOPT_ACTION_HELP: + return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO; + + case ECORE_GETOPT_ACTION_VERSION: + return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO; + + default: + return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO; + } +} + +static void +_ecore_getopt_help_desc_setup_metavar(const Ecore_Getopt_Desc *desc, + char *metavar, + int *metavarlen, + int maxsize) +{ + if (desc->metavar) + { + const char *txt = gettext(desc->metavar); + *metavarlen = strlen(txt); + if (*metavarlen > maxsize - 1) + *metavarlen = maxsize - 1; + + memcpy(metavar, txt, *metavarlen); + metavar[*metavarlen] = '\0'; + } + else if (desc->longname) + { + int i; + + *metavarlen = strlen(desc->longname); + if (*metavarlen > maxsize - 1) + *metavarlen = maxsize - 1; + + for (i = 0; i < *metavarlen; i++) + metavar[i] = toupper((int) desc->longname[i]); + metavar[i] = '\0'; + } +} + +static int +_ecore_getopt_help_desc_show_arg(FILE *fp, + Ecore_Getopt_Desc_Arg_Requirement requirement, + const char *metavar, + int metavarlen) +{ + int used; + + if (requirement == ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO) + return 0; + + used = 0; + + if (requirement == ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL) + { + fputc('[', fp); + used++; + } + + if (requirement != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO) + { + fputc('=', fp); + fputs(metavar, fp); + used += metavarlen + 1; + } + + if (requirement == ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL) + { + fputc(']', fp); + used++; + } + + return used; +} + +static int +_ecore_getopt_help_desc_store(FILE *fp, + const int base, + const int total, + int used, + const Ecore_Getopt_Desc *desc) +{ + const Ecore_Getopt_Desc_Store *store = &desc->action_param.store; + char buf[64]; + const char *str; + size_t len; + + fputc('\n', fp); + for (used = 0; used < base; used++) + fputc(' ', fp); + + switch (store->type) + { + case ECORE_GETOPT_TYPE_STR: + str = "STR"; + len = sizeof("STR") - 1; + break; + + case ECORE_GETOPT_TYPE_BOOL: + str = "BOOL"; + len = sizeof("BOOL") - 1; + break; + + case ECORE_GETOPT_TYPE_SHORT: + str = "SHORT"; + len = sizeof("SHORT") - 1; + break; + + case ECORE_GETOPT_TYPE_INT: + str = "INT"; + len = sizeof("INT") - 1; + break; + + case ECORE_GETOPT_TYPE_LONG: + str = "LONG"; + len = sizeof("LONG") - 1; + break; + + case ECORE_GETOPT_TYPE_USHORT: + str = "USHORT"; + len = sizeof("USHORT") - 1; + break; + + case ECORE_GETOPT_TYPE_UINT: + str = "UINT"; + len = sizeof("UINT") - 1; + break; + + case ECORE_GETOPT_TYPE_ULONG: + str = "ULONG"; + len = sizeof("ULONG") - 1; + break; + + case ECORE_GETOPT_TYPE_DOUBLE: + str = "DOUBLE"; + len = sizeof("DOUBLE") - 1; + break; + + default: + str = "???"; + len = sizeof("???") - 1; + } + + used = _ecore_getopt_help_line + (fp, base, total, used, _("Type: "), strlen(_("Type: "))); + used = _ecore_getopt_help_line(fp, base, total, used, str, len); + + if (store->arg_req == ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES) + goto end; + + used = _ecore_getopt_help_line + (fp, base, total, used, ". ", sizeof(". ") - 1); + + switch (store->type) + { + case ECORE_GETOPT_TYPE_STR: + str = store->def.strv; + len = str ? strlen(str) : 0; + break; + + case ECORE_GETOPT_TYPE_BOOL: + str = store->def.boolv ? "true" : "false"; + len = strlen(str); + break; + + case ECORE_GETOPT_TYPE_SHORT: + str = buf; + len = snprintf(buf, sizeof(buf), "%hd", store->def.shortv); + if (len > sizeof(buf) - 1) + len = sizeof(buf) - 1; + break; + + case ECORE_GETOPT_TYPE_INT: + str = buf; + len = snprintf(buf, sizeof(buf), "%d", store->def.intv); + if (len > sizeof(buf) - 1) + len = sizeof(buf) - 1; + break; + + case ECORE_GETOPT_TYPE_LONG: + str = buf; + len = snprintf(buf, sizeof(buf), "%ld", store->def.longv); + if (len > sizeof(buf) - 1) + len = sizeof(buf) - 1; + break; + + case ECORE_GETOPT_TYPE_USHORT: + str = buf; + len = snprintf(buf, sizeof(buf), "%hu", store->def.ushortv); + if (len > sizeof(buf) - 1) + len = sizeof(buf) - 1; + break; + + case ECORE_GETOPT_TYPE_UINT: + str = buf; + len = snprintf(buf, sizeof(buf), "%u", store->def.uintv); + if (len > sizeof(buf) - 1) + len = sizeof(buf) - 1; + break; + + case ECORE_GETOPT_TYPE_ULONG: + str = buf; + len = snprintf(buf, sizeof(buf), "%lu", store->def.ulongv); + if (len > sizeof(buf) - 1) + len = sizeof(buf) - 1; + break; + + case ECORE_GETOPT_TYPE_DOUBLE: + str = buf; + len = snprintf(buf, sizeof(buf), "%f", store->def.doublev); + if (len > sizeof(buf) - 1) + len = sizeof(buf) - 1; + break; + + default: + str = "???"; + len = sizeof("???") - 1; + } + + used = _ecore_getopt_help_line + (fp, base, total, used, _("Default: "), strlen(_("Default: "))); + used = _ecore_getopt_help_line(fp, base, total, used, str, len); + +end: + return _ecore_getopt_help_line(fp, base, total, used, ".", 1); +} + +static int +_ecore_getopt_help_desc_choices(FILE *fp, + const int base, + const int total, + int used, + const Ecore_Getopt_Desc *desc) +{ + const char *const *itr; + const char sep[] = ", "; + const int seplen = sizeof(sep) - 1; + + if (used > 0) + { + fputc('\n', fp); + used = 0; + } + for (; used < base; used++) + fputc(' ', fp); + + used = _ecore_getopt_help_line + (fp, base, total, used, _("Choices: "), strlen(_("Choices: "))); + + for (itr = desc->action_param.choices; *itr; itr++) + { + used = _ecore_getopt_help_line + (fp, base, total, used, *itr, strlen(*itr)); + if (itr[1]) + used = _ecore_getopt_help_line(fp, base, total, used, sep, seplen); + } + + return _ecore_getopt_help_line(fp, base, total, used, ".", 1); +} + +static void +_ecore_getopt_help_desc(FILE *fp, + const Ecore_Getopt_Desc *desc) +{ + Ecore_Getopt_Desc_Arg_Requirement arg_req; + char metavar[32] = "ARG"; + int metavarlen = 3; + int used; + + arg_req = _ecore_getopt_desc_arg_requirement(desc); + if (arg_req != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO) + _ecore_getopt_help_desc_setup_metavar + (desc, metavar, &metavarlen, sizeof(metavar)); + + fputs(" ", fp); + used = 2; + + if (desc->shortname) + { + fputc('-', fp); + fputc(desc->shortname, fp); + used += 2; + used += _ecore_getopt_help_desc_show_arg + (fp, arg_req, metavar, metavarlen); + } + + if (desc->shortname && desc->longname) + { + fputs(", ", fp); + used += 2; + } + + if (desc->longname) + { + int namelen = strlen(desc->longname); + + fputs("--", fp); + fputs(desc->longname, fp); + used += 2 + namelen; + used += _ecore_getopt_help_desc_show_arg + (fp, arg_req, metavar, metavarlen); + } + + if (!desc->help) + goto end; + + if (used + 3 >= helpcol) + { + fputc('\n', fp); + used = 0; + } + + for (; used < helpcol; used++) + fputc(' ', fp); + + used = _ecore_getopt_help_line + (fp, helpcol, cols, used, desc->help, strlen(desc->help)); + + switch (desc->action) + { + case ECORE_GETOPT_ACTION_STORE: + _ecore_getopt_help_desc_store(fp, helpcol, cols, used, desc); + break; + + case ECORE_GETOPT_ACTION_CHOICE: + _ecore_getopt_help_desc_choices(fp, helpcol, cols, used, desc); + break; + + default: + break; + } + +end: + fputc('\n', fp); +} + +static Eina_Bool +_ecore_getopt_desc_is_sentinel(const Ecore_Getopt_Desc *desc) +{ + return (desc->shortname == '\0') && (!desc->longname); +} + +static void +_ecore_getopt_help_options(FILE *fp, + const Ecore_Getopt *parser) +{ + const Ecore_Getopt_Desc *desc; + + fputs(_("Options:\n"), fp); + + for (desc = parser->descs; !_ecore_getopt_desc_is_sentinel(desc); desc++) + _ecore_getopt_help_desc(fp, desc); + + fputc('\n', fp); +} + +/** + * Show nicely formatted help message for the given parser. + * + * @param fp The file the message will be printed on. + * @param parser The parser to be used. + */ +EAPI void +ecore_getopt_help(FILE *fp, + const Ecore_Getopt *parser) +{ + const char *var; + + EINA_MAIN_LOOP_CHECK_RETURN; + if (!parser) return; + + if (_argc < 1) + { + ecore_app_args_get(&_argc, &_argv); + if ((_argc > 0) && (_argv[0])) + prog = _argv[0]; + else + prog = parser->prog; + } + + var = getenv("COLUMNS"); + if (var) + { + cols = atoi(var); + if (cols < 20) + cols = 20; + + helpcol = cols / 3; + } + + _ecore_getopt_help_usage(fp, parser); + _ecore_getopt_help_description(fp, parser); + _ecore_getopt_help_options(fp, parser); +} + +static const Ecore_Getopt_Desc * +_ecore_getopt_parse_find_long(const Ecore_Getopt *parser, + const char *name) +{ + const Ecore_Getopt_Desc *desc = parser->descs; + const char *p = strchr(name, '='); + int len = 0; + + if (p) + len = p - name; + + for (; !_ecore_getopt_desc_is_sentinel(desc); desc++) + { + if (!desc->longname) + continue; + + if (p) + { + if ((strncmp(name, desc->longname, len) == 0) && + (desc->longname[len] == '\0')) + return desc; + } + else + { + if (strcmp(name, desc->longname) == 0) + return desc; + } + } + + return NULL; +} + +static const Ecore_Getopt_Desc * +_ecore_getopt_parse_find_short(const Ecore_Getopt *parser, + char name) +{ + const Ecore_Getopt_Desc *desc = parser->descs; + for (; !_ecore_getopt_desc_is_sentinel(desc); desc++) + if (name == desc->shortname) + return desc; + return NULL; +} + +static int +_ecore_getopt_parse_find_nonargs_base(const Ecore_Getopt *parser, + int argc, + char **argv) +{ + char **nonargs; + int src, dst, used, base; + + nonargs = alloca(sizeof(char *) * argc); + src = 1; + dst = 1; + used = 0; + base = 0; + while (src < argc) + { + const Ecore_Getopt_Desc *desc; + Ecore_Getopt_Desc_Arg_Requirement arg_req; + char *arg = argv[src]; + + if (arg[0] != '-') + goto found_nonarg; + + if (arg[1] == '-') + { + if (arg[2] == '\0') /* explicit end of options, "--" */ + { + base = 1; + break; + } + desc = _ecore_getopt_parse_find_long(parser, arg + 2); + } + else + desc = _ecore_getopt_parse_find_short(parser, arg[1]); + + if (!desc) + { + if (arg[1] == '-') + fprintf(stderr, _("ERROR: unknown option --%s.\n"), arg + 2); + else + fprintf(stderr, _("ERROR: unknown option -%c.\n"), arg[1]); + if (parser->strict) + { + memmove(argv + dst, nonargs, used * sizeof(char *)); + return -1; + } + else + goto found_nonarg; + } + + if (src != dst) + argv[dst] = argv[src]; + src++; + dst++; + + arg_req = _ecore_getopt_desc_arg_requirement(desc); + if (arg_req == ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO) + continue; + + if (strchr(arg, '=')) + continue; + + if ((src >= argc) || (argv[src][0] == '-')) + continue; + + if (src != dst) + argv[dst] = argv[src]; + src++; + dst++; + continue; + +found_nonarg: + nonargs[used] = arg; + used++; + src++; + } + + if (!base) /* '--' not found */ + base = dst; + else + { + base = dst; + if (src != dst) + argv[dst] = argv[src]; + dst++; + } + + memmove(argv + dst, nonargs, used * sizeof(char *)); + return base; +} + +static void +_ecore_getopt_desc_print_error(const Ecore_Getopt_Desc *desc, + const char *fmt, + ...) +{ + va_list ap; + + fputs(_("ERROR: "), stderr); + + if (desc->shortname) + { + fputc('-', stderr); + fputc(desc->shortname, stderr); + } + + if (desc->shortname && desc->longname) + fputs(", ", stderr); + + if (desc->longname) + { + fputs("--", stderr); + fputs(desc->longname, stderr); + } + + fputs(": ", stderr); + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +static Eina_Bool +_ecore_getopt_parse_bool(const char *str, + Eina_Bool *v) +{ + if ((strcmp(str, "0") == 0) || + (strcasecmp(str, "f") == 0) || + (strcasecmp(str, "false") == 0) || + (strcasecmp(str, "no") == 0) || + (strcasecmp(str, "off") == 0) + ) + { + *v = EINA_FALSE; + return EINA_TRUE; + } + else if ((strcmp(str, "1") == 0) || + (strcasecmp(str, "t") == 0) || + (strcasecmp(str, "true") == 0) || + (strcasecmp(str, "yes") == 0) || + (strcasecmp(str, "on") == 0) + ) + { + *v = EINA_TRUE; + return EINA_TRUE; + } + + return EINA_FALSE; +} + +static Eina_Bool +_ecore_getopt_parse_long(const char *str, + long int *v) +{ + char *endptr = NULL; + *v = strtol(str, &endptr, 0); + return endptr > str; +} + +static Eina_Bool +_ecore_getopt_parse_double(const char *str, + double *v) +{ + char *endptr = NULL; + *v = strtod(str, &endptr); + return endptr > str; +} + +static Eina_Bool +_ecore_getopt_parse_store(const Ecore_Getopt *parser __UNUSED__, + const Ecore_Getopt_Desc *desc, + Ecore_Getopt_Value *value, + const char *arg_val) +{ + const Ecore_Getopt_Desc_Store *store = &desc->action_param.store; + long int v; + double d; + Eina_Bool b; + + if (!value->ptrp) + { + _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n")); + return EINA_FALSE; + } + + switch (store->arg_req) + { + case ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO: + goto use_optional; + + case ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL: + if (!arg_val) + goto use_optional; + + case ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES: + break; + } + + switch (store->type) + { + case ECORE_GETOPT_TYPE_STR: + *value->strp = (char *)arg_val; + return EINA_TRUE; + + case ECORE_GETOPT_TYPE_BOOL: + if (_ecore_getopt_parse_bool(arg_val, &b)) + { + *value->boolp = b; + return EINA_TRUE; + } + else + { + _ecore_getopt_desc_print_error + (desc, _("unknown boolean value %s.\n"), arg_val); + return EINA_FALSE; + } + + case ECORE_GETOPT_TYPE_SHORT: + if (!_ecore_getopt_parse_long(arg_val, &v)) + goto error; + *value->shortp = v; + return EINA_TRUE; + + case ECORE_GETOPT_TYPE_INT: + if (!_ecore_getopt_parse_long(arg_val, &v)) + goto error; + *value->intp = v; + return EINA_TRUE; + + case ECORE_GETOPT_TYPE_LONG: + if (!_ecore_getopt_parse_long(arg_val, &v)) + goto error; + *value->longp = v; + return EINA_TRUE; + + case ECORE_GETOPT_TYPE_USHORT: + if (!_ecore_getopt_parse_long(arg_val, &v)) + goto error; + *value->ushortp = v; + return EINA_TRUE; + + case ECORE_GETOPT_TYPE_UINT: + if (!_ecore_getopt_parse_long(arg_val, &v)) + goto error; + *value->uintp = v; + return EINA_TRUE; + + case ECORE_GETOPT_TYPE_ULONG: + if (!_ecore_getopt_parse_long(arg_val, &v)) + goto error; + *value->ulongp = v; + return EINA_TRUE; + + case ECORE_GETOPT_TYPE_DOUBLE: + if (!_ecore_getopt_parse_double(arg_val, &d)) + goto error; + *value->doublep = d; + break; + } + + return EINA_TRUE; + +error: + _ecore_getopt_desc_print_error + (desc, _("invalid number format %s\n"), arg_val); + return EINA_FALSE; + +use_optional: + switch (store->type) + { + case ECORE_GETOPT_TYPE_STR: + *value->strp = (char *)store->def.strv; + break; + + case ECORE_GETOPT_TYPE_BOOL: + *value->boolp = store->def.boolv; + break; + + case ECORE_GETOPT_TYPE_SHORT: + *value->shortp = store->def.shortv; + break; + + case ECORE_GETOPT_TYPE_INT: + *value->intp = store->def.intv; + break; + + case ECORE_GETOPT_TYPE_LONG: + *value->longp = store->def.longv; + break; + + case ECORE_GETOPT_TYPE_USHORT: + *value->ushortp = store->def.ushortv; + break; + + case ECORE_GETOPT_TYPE_UINT: + *value->uintp = store->def.uintv; + break; + + case ECORE_GETOPT_TYPE_ULONG: + *value->ulongp = store->def.ulongv; + break; + + case ECORE_GETOPT_TYPE_DOUBLE: + *value->doublep = store->def.doublev; + break; + } + + return EINA_TRUE; +} + +static Eina_Bool +_ecore_getopt_parse_store_const(const Ecore_Getopt *parser __UNUSED__, + const Ecore_Getopt_Desc *desc, + Ecore_Getopt_Value *val, + const char *arg_val __UNUSED__) +{ + if (!val->ptrp) + { + _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n")); + return EINA_FALSE; + } + + *val->ptrp = (void *)desc->action_param.store_const; + return EINA_TRUE; +} + +static Eina_Bool +_ecore_getopt_parse_store_true(const Ecore_Getopt *parser __UNUSED__, + const Ecore_Getopt_Desc *desc, + Ecore_Getopt_Value *val, + const char *arg_val __UNUSED__) +{ + if (!val->boolp) + { + _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n")); + return EINA_FALSE; + } + *val->boolp = EINA_TRUE; + return EINA_TRUE; +} + +static Eina_Bool +_ecore_getopt_parse_store_false(const Ecore_Getopt *parser __UNUSED__, + const Ecore_Getopt_Desc *desc, + Ecore_Getopt_Value *val, + const char *arg_val __UNUSED__) +{ + if (!val->boolp) + { + _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n")); + return EINA_FALSE; + } + *val->boolp = EINA_FALSE; + return EINA_TRUE; +} + +static Eina_Bool +_ecore_getopt_parse_choice(const Ecore_Getopt *parser __UNUSED__, + const Ecore_Getopt_Desc *desc, + Ecore_Getopt_Value *val, + const char *arg_val) +{ + const char *const *pchoice; + + if (!val->strp) + { + _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n")); + return EINA_FALSE; + } + + pchoice = desc->action_param.choices; + for (; *pchoice; pchoice++) + if (strcmp(*pchoice, arg_val) == 0) + { + *val->strp = (char *)*pchoice; + return EINA_TRUE; + } + + _ecore_getopt_desc_print_error + (desc, _("invalid choice \"%s\". Valid values are: "), arg_val); + + pchoice = desc->action_param.choices; + for (; *pchoice; pchoice++) + { + fputs(*pchoice, stderr); + if (pchoice[1]) + fputs(", ", stderr); + } + + fputs(".\n", stderr); + return EINA_FALSE; +} + +static Eina_Bool +_ecore_getopt_parse_append(const Ecore_Getopt *parser __UNUSED__, + const Ecore_Getopt_Desc *desc, + Ecore_Getopt_Value *val, + const char *arg_val) +{ + void *data; + long int v; + double d; + Eina_Bool b; + + if (!arg_val) + { + _ecore_getopt_desc_print_error + (desc, _("missing parameter to append.\n")); + return EINA_FALSE; + } + + if (!val->listp) + { + _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n")); + return EINA_FALSE; + } + + switch (desc->action_param.append_type) + { + case ECORE_GETOPT_TYPE_STR: + data = strdup(arg_val); + break; + + case ECORE_GETOPT_TYPE_BOOL: + { + if (_ecore_getopt_parse_bool(arg_val, &b)) + { + data = malloc(sizeof(Eina_Bool)); + if (data) + *(Eina_Bool *)data = b; + } + else + { + _ecore_getopt_desc_print_error(desc, _("unknown boolean value %s.\n"), arg_val); + return EINA_FALSE; + } + } + break; + + case ECORE_GETOPT_TYPE_SHORT: + { + if (!_ecore_getopt_parse_long(arg_val, &v)) + goto error; + data = malloc(sizeof(short)); + if (data) + *(short *)data = (short)v; + } + break; + + case ECORE_GETOPT_TYPE_INT: + { + if (!_ecore_getopt_parse_long(arg_val, &v)) + goto error; + data = malloc(sizeof(int)); + if (data) + *(int *)data = (int)v; + } + break; + + case ECORE_GETOPT_TYPE_LONG: + { + if (!_ecore_getopt_parse_long(arg_val, &v)) + goto error; + data = malloc(sizeof(long)); + if (data) + *(long *)data = v; + } + break; + + case ECORE_GETOPT_TYPE_USHORT: + { + if (!_ecore_getopt_parse_long(arg_val, &v)) + goto error; + data = malloc(sizeof(unsigned short)); + if (data) + *(unsigned short *)data = (unsigned short)v; + } + break; + + case ECORE_GETOPT_TYPE_UINT: + { + if (!_ecore_getopt_parse_long(arg_val, &v)) + goto error; + data = malloc(sizeof(unsigned int)); + if (data) + *(unsigned int *)data = (unsigned int)v; + } + break; + + case ECORE_GETOPT_TYPE_ULONG: + { + if (!_ecore_getopt_parse_long(arg_val, &v)) + goto error; + data = malloc(sizeof(unsigned long)); + if (data) + *(unsigned long *)data = v; + } + break; + + case ECORE_GETOPT_TYPE_DOUBLE: + { + if (!_ecore_getopt_parse_double(arg_val, &d)) + goto error; + data = malloc(sizeof(double)); + if (data) + *(double *)data = d; + } + break; + + default: + { + _ecore_getopt_desc_print_error(desc, _("could not parse value.\n")); + return EINA_FALSE; + } + } + + *val->listp = eina_list_append(*val->listp, data); + return EINA_TRUE; + +error: + _ecore_getopt_desc_print_error + (desc, _("invalid number format %s\n"), arg_val); + return EINA_FALSE; +} + +static Eina_Bool +_ecore_getopt_parse_count(const Ecore_Getopt *parser __UNUSED__, + const Ecore_Getopt_Desc *desc, + Ecore_Getopt_Value *val, + const char *arg_val __UNUSED__) +{ + if (!val->intp) + { + _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n")); + return EINA_FALSE; + } + + (*val->intp)++; + return EINA_TRUE; +} + +static Eina_Bool +_ecore_getopt_parse_callback(const Ecore_Getopt *parser, + const Ecore_Getopt_Desc *desc, + Ecore_Getopt_Value *val, + const char *arg_val) +{ + const Ecore_Getopt_Desc_Callback *cb = &desc->action_param.callback; + + switch (cb->arg_req) + { + case ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO: + arg_val = cb->def; + break; + + case ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL: + if (!arg_val) + arg_val = cb->def; + break; + + case ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES: + break; + } + + if (cb->arg_req != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO) + { + if ((!arg_val) || (arg_val[0] == '\0')) + { + _ecore_getopt_desc_print_error(desc, _("missing parameter.\n")); + return EINA_FALSE; + } + + if (!val->ptrp) + { + _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n")); + return EINA_FALSE; + } + } + + if (!cb->func) + { + _ecore_getopt_desc_print_error(desc, _("missing callback function!\n")); + return EINA_FALSE; + } + + return cb->func(parser, desc, arg_val, (void *)cb->data, val); +} + +static Eina_Bool +_ecore_getopt_parse_help(const Ecore_Getopt *parser, + const Ecore_Getopt_Desc *desc __UNUSED__, + Ecore_Getopt_Value *val, + const char *arg_val __UNUSED__) +{ + if (val->boolp) + (*val->boolp) = EINA_TRUE; + ecore_getopt_help(stdout, parser); + return EINA_TRUE; +} + +static Eina_Bool +_ecore_getopt_parse_version(const Ecore_Getopt *parser, + const Ecore_Getopt_Desc *desc, + Ecore_Getopt_Value *val, + const char *arg_val __UNUSED__) +{ + if (val->boolp) + (*val->boolp) = EINA_TRUE; + if (!parser->version) + { + _ecore_getopt_desc_print_error(desc, _("no version was defined.\n")); + return EINA_FALSE; + } + _ecore_getopt_version(stdout, parser); + return EINA_TRUE; +} + +static Eina_Bool +_ecore_getopt_parse_copyright(const Ecore_Getopt *parser, + const Ecore_Getopt_Desc *desc, + Ecore_Getopt_Value *val, + const char *arg_val __UNUSED__) +{ + if (val->boolp) + (*val->boolp) = EINA_TRUE; + if (!parser->copyright) + { + _ecore_getopt_desc_print_error(desc, _("no copyright was defined.\n")); + return EINA_FALSE; + } + _ecore_getopt_copyright(stdout, parser); + return EINA_TRUE; +} + +static Eina_Bool +_ecore_getopt_parse_license(const Ecore_Getopt *parser, + const Ecore_Getopt_Desc *desc, + Ecore_Getopt_Value *val, + const char *arg_val __UNUSED__) +{ + if (val->boolp) + (*val->boolp) = EINA_TRUE; + if (!parser->license) + { + _ecore_getopt_desc_print_error(desc, _("no license was defined.\n")); + return EINA_FALSE; + } + _ecore_getopt_license(stdout, parser); + return EINA_TRUE; +} + +static Eina_Bool +_ecore_getopt_desc_handle(const Ecore_Getopt *parser, + const Ecore_Getopt_Desc *desc, + Ecore_Getopt_Value *value, + const char *arg_val) +{ + switch (desc->action) + { + case ECORE_GETOPT_ACTION_STORE: + return _ecore_getopt_parse_store(parser, desc, value, arg_val); + + case ECORE_GETOPT_ACTION_STORE_CONST: + return _ecore_getopt_parse_store_const(parser, desc, value, arg_val); + + case ECORE_GETOPT_ACTION_STORE_TRUE: + return _ecore_getopt_parse_store_true(parser, desc, value, arg_val); + + case ECORE_GETOPT_ACTION_STORE_FALSE: + return _ecore_getopt_parse_store_false(parser, desc, value, arg_val); + + case ECORE_GETOPT_ACTION_CHOICE: + return _ecore_getopt_parse_choice(parser, desc, value, arg_val); + + case ECORE_GETOPT_ACTION_APPEND: + return _ecore_getopt_parse_append(parser, desc, value, arg_val); + + case ECORE_GETOPT_ACTION_COUNT: + return _ecore_getopt_parse_count(parser, desc, value, arg_val); + + case ECORE_GETOPT_ACTION_CALLBACK: + return _ecore_getopt_parse_callback(parser, desc, value, arg_val); + + case ECORE_GETOPT_ACTION_HELP: + return _ecore_getopt_parse_help(parser, desc, value, arg_val); + + case ECORE_GETOPT_ACTION_VERSION: + return _ecore_getopt_parse_version(parser, desc, value, arg_val); + + case ECORE_GETOPT_ACTION_COPYRIGHT: + return _ecore_getopt_parse_copyright(parser, desc, value, arg_val); + + case ECORE_GETOPT_ACTION_LICENSE: + return _ecore_getopt_parse_license(parser, desc, value, arg_val); + + default: + return EINA_FALSE; + } +} + +static Eina_Bool +_ecore_getopt_parse_arg_long(const Ecore_Getopt *parser, + Ecore_Getopt_Value *values, + int argc __UNUSED__, + char **argv, + int *idx, + int *nonargs, + const char *arg) +{ + const Ecore_Getopt_Desc *desc; + Ecore_Getopt_Desc_Arg_Requirement arg_req; + const char *arg_val; + int desc_idx; + Ecore_Getopt_Value *value; + Eina_Bool ret; + + desc = _ecore_getopt_parse_find_long(parser, arg); + if (!desc) + { + fprintf(stderr, _("ERROR: unknown option --%s, ignored.\n"), arg); + if (parser->strict) + return EINA_FALSE; + + (*idx)++; + return EINA_TRUE; + } + + (*idx)++; + + arg_req = _ecore_getopt_desc_arg_requirement(desc); + if (arg_req != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO) + { + arg_val = strchr(arg, '='); + if (arg_val) + arg_val++; + else + { + if ((*idx < *nonargs) && (argv[*idx][0] != '-')) + { + arg_val = argv[*idx]; + (*idx)++; + } + else + arg_val = NULL; + } + + if (arg_val && arg_val[0] == '\0') + arg_val = NULL; + + if ((!arg_val) && (arg_req == ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES)) + { + fprintf + (stderr, _("ERROR: option --%s requires an argument!\n"), arg); + if (parser->strict) + return EINA_FALSE; + return EINA_TRUE; + } + } + else + arg_val = NULL; + + desc_idx = desc - parser->descs; + value = values + desc_idx; + ret = _ecore_getopt_desc_handle(parser, desc, value, arg_val); + if ((!ret) && parser->strict) + return EINA_FALSE; + + return EINA_TRUE; +} + +static Eina_Bool +_ecore_getopt_parse_arg_short(const Ecore_Getopt *parser, + Ecore_Getopt_Value *values, + int argc __UNUSED__, + char **argv, + int *idx, + int *nonargs, + const char *arg) +{ + int run = 1; + while (run && (arg[0] != '\0')) + { + int opt = arg[0]; + const Ecore_Getopt_Desc *desc; + Ecore_Getopt_Desc_Arg_Requirement arg_req; + const char *arg_val; + int desc_idx; + Ecore_Getopt_Value *value; + Eina_Bool ret; + + desc = _ecore_getopt_parse_find_short(parser, arg[0]); + if (!desc) + { + fprintf + (stderr, _("ERROR: unknown option -%c, ignored.\n"), arg[0]); + if (parser->strict) + return EINA_FALSE; + + arg++; + continue; + } + + arg++; + + arg_req = _ecore_getopt_desc_arg_requirement(desc); + if (arg_req != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO) + { + (*idx)++; + run = 0; + + if (arg[0] == '=') + arg_val = arg + 1; + else if (arg[0] != '\0') + arg_val = arg; + else + { + if ((*idx < *nonargs) && (argv[*idx][0] != '-')) + { + arg_val = argv[*idx]; + (*idx)++; + } + else + arg_val = NULL; + } + + if (arg_val && arg_val[0] == '\0') + arg_val = NULL; + + if ((!arg_val) && + (arg_req == ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES)) + { + fprintf + (stderr, _("ERROR: option -%c requires an argument!\n"), + opt); + if (parser->strict) + return EINA_FALSE; + return EINA_TRUE; + } + } + else + arg_val = NULL; + + desc_idx = desc - parser->descs; + value = values + desc_idx; + ret = _ecore_getopt_desc_handle(parser, desc, value, arg_val); + if ((!ret) && parser->strict) + return EINA_FALSE; + } + + if (run) + (*idx)++; + + return EINA_TRUE; +} + +static Eina_Bool +_ecore_getopt_parse_arg(const Ecore_Getopt *parser, + Ecore_Getopt_Value *values, + int argc, + char **argv, + int *idx, + int *nonargs) +{ + char *arg = argv[*idx]; + + if (arg[0] != '-') + { + char **dst, **src, **src_end; + + dst = argv + *idx; + src = dst + 1; + src_end = src + *nonargs - *idx - 1; + + for (; src < src_end; src++, dst++) + *dst = *src; + + *dst = arg; + (*nonargs)--; + return EINA_TRUE; + } + + if (arg[1] == '-') + return _ecore_getopt_parse_arg_long(parser, values, argc, argv, idx, nonargs, arg + 2); + else + return _ecore_getopt_parse_arg_short(parser, values, argc, argv, idx, nonargs, arg + 1); +} + +static const Ecore_Getopt_Desc * +_ecore_getopt_parse_find_short_other(const Ecore_Getopt *parser, + const Ecore_Getopt_Desc *orig) +{ + const Ecore_Getopt_Desc *desc = parser->descs; + const char c = orig->shortname; + + for (; !_ecore_getopt_desc_is_sentinel(desc); desc++) + { + if (desc == orig) + return NULL; + + if (c == desc->shortname) + return desc; + } + + return NULL; +} + +static const Ecore_Getopt_Desc * +_ecore_getopt_parse_find_long_other(const Ecore_Getopt *parser, + const Ecore_Getopt_Desc *orig) +{ + const Ecore_Getopt_Desc *desc = parser->descs; + const char *name = orig->longname; + + for (; !_ecore_getopt_desc_is_sentinel(desc); desc++) + { + if (desc == orig) + return NULL; + + if (desc->longname && (strcmp(name, desc->longname) == 0)) + return desc; + } + + return NULL; +} + +/** + * Check parser for duplicate entries, print them out. + * + * @return @c EINA_TRUE if there are duplicates, @c EINA_FALSE otherwise. + * @param parser The parser to be checked. + */ +EAPI Eina_Bool +ecore_getopt_parser_has_duplicates(const Ecore_Getopt *parser) +{ + const Ecore_Getopt_Desc *desc = parser->descs; + for (; !_ecore_getopt_desc_is_sentinel(desc); desc++) + { + if (desc->shortname) + { + const Ecore_Getopt_Desc *other; + other = _ecore_getopt_parse_find_short_other(parser, desc); + if (other) + { + _ecore_getopt_desc_print_error(desc, "short name -%c already exists.", desc->shortname); + + if (other->longname) + fprintf(stderr, " Other is --%s.\n", other->longname); + else + fputc('\n', stderr); + return EINA_TRUE; + } + } + + if (desc->longname) + { + const Ecore_Getopt_Desc *other; + other = _ecore_getopt_parse_find_long_other(parser, desc); + if (other) + { + _ecore_getopt_desc_print_error(desc, "long name --%s already exists.", desc->longname); + + if (other->shortname) + fprintf(stderr, " Other is -%c.\n", other->shortname); + else + fputc('\n', stderr); + return EINA_TRUE; + } + } + } + return EINA_FALSE; +} + +static const Ecore_Getopt_Desc * +_ecore_getopt_find_help(const Ecore_Getopt *parser) +{ + const Ecore_Getopt_Desc *desc = parser->descs; + for (; !_ecore_getopt_desc_is_sentinel(desc); desc++) + if (desc->action == ECORE_GETOPT_ACTION_HELP) + return desc; + return NULL; +} + +/** + * Parse command line parameters. + * + * Walks the command line parameters and parse them based on @a parser + * description, doing actions based on @c parser->descs->action, like + * showing help text, license, copyright, storing values in values and + * so on. + * + * It is expected that values is of the same size than @c parser->descs, + * options that do not need a value it will be left untouched. + * + * All values are expected to be initialized before use. Options with + * action @c ECORE_GETOPT_ACTION_STORE and non required arguments + * (others than @c ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES), are expected + * to provide a value in @c def to be used. + * + * The following actions will store @c 1 on value as a boolean + * (@c value->boolp) if it's not @c NULL to indicate these actions were + * executed: + * - @c ECORE_GETOPT_ACTION_HELP + * - @c ECORE_GETOPT_ACTION_VERSION + * - @c ECORE_GETOPT_ACTION_COPYRIGHT + * - @c ECORE_GETOPT_ACTION_LICENSE + * + * Just @c ECORE_GETOPT_ACTION_APPEND will allocate memory and thus + * need to be freed. For consistency between all of appended subtypes, + * @c eina_list->data will contain an allocated memory with the value, + * that is, for @c ECORE_GETOPT_TYPE_STR it will contain a copy of the + * argument, @c ECORE_GETOPT_TYPE_INT a pointer to an allocated + * integer and so on. + * + * If parser is in strict mode (see @c Ecore_Getopt->strict), then any + * error will abort parsing and @c -1 is returned. Otherwise it will try + * to continue as far as possible. + * + * This function may reorder @a argv elements. + * + * Translation of help strings (description), metavar, usage, license + * and copyright may be translated, standard/global gettext() call + * will be applied on them if ecore was compiled with such support. + * + * @param parser description of how to work. + * @param values where to store values, it is assumed that this is a vector + * of the same size as @c parser->descs. Values should be previously + * initialized. + * @param argc how many elements in @a argv. If not provided it will be + * retrieved with ecore_app_args_get(). + * @param argv command line parameters. + * + * @return index of first non-option parameter or -1 on error. + */ +EAPI int +ecore_getopt_parse(const Ecore_Getopt *parser, + Ecore_Getopt_Value *values, + int argc, + char **argv) +{ + int i, nonargs; + + if (!parser) + { + fputs(_("ERROR: no parser provided.\n"), stderr); + return -1; + } + if (!values) + { + fputs(_("ERROR: no values provided.\n"), stderr); + return -1; + } + + if ((argc < 1) || (!argv)) + ecore_app_args_get(&argc, &argv); + + if (argc < 1) + { + fputs(_("ERROR: no arguments provided.\n"), stderr); + return -1; + } + + if (argv[0]) + prog = argv[0]; + else + prog = parser->prog; + + nonargs = _ecore_getopt_parse_find_nonargs_base(parser, argc, argv); + if (nonargs < 0) + goto error; + + if (nonargs > argc) + nonargs = argc; + + i = 1; + while (i < nonargs) + if (!_ecore_getopt_parse_arg(parser, values, argc, argv, &i, &nonargs)) + goto error; + + return nonargs; + +error: + { + const Ecore_Getopt_Desc *help; + fputs(_("ERROR: invalid options found."), stderr); + + help = _ecore_getopt_find_help(parser); + if (!help) + fputc('\n', stderr); + else if (help->longname) + fprintf(stderr, _(" See --%s.\n"), help->longname); + else + fprintf(stderr, _(" See -%c.\n"), help->shortname); + } + + return -1; +} + +/** + * Utility to free list and nodes allocated by @a ECORE_GETOPT_ACTION_APPEND. + * + * @param list pointer to list to be freed. + * @return always @c NULL, so you can easily make your list head @c NULL. + */ +EAPI Eina_List * +ecore_getopt_list_free(Eina_List *list) +{ + void *data; + + EINA_LIST_FREE(list, data) + free(data); + return NULL; +} + +/** + * Helper ecore_getopt callback to parse geometry (x:y:w:h). + * + * @param parser This parameter isn't in use. + * @param desc This parameter isn't in use. + * @param str Geometry value + * @param data This parameter isn't in use. + * @param storage must be a pointer to @c Eina_Rectangle and will be used to + * store the four values passed in the given string. + * @return @c EINA_TRUE on success, @c EINA_FALSE on incorrect geometry value. + * + * @c callback_data value is ignored, you can safely use @c NULL. + */ +EAPI Eina_Bool +ecore_getopt_callback_geometry_parse(const Ecore_Getopt *parser __UNUSED__, + const Ecore_Getopt_Desc *desc __UNUSED__, + const char *str, + void *data __UNUSED__, + Ecore_Getopt_Value *storage) +{ + Eina_Rectangle *v = (Eina_Rectangle *)storage->ptrp; + + if (sscanf(str, "%d:%d:%d:%d", &v->x, &v->y, &v->w, &v->h) != 4) + { + fprintf(stderr, _("ERROR: incorrect geometry value '%s'\n"), str); + return EINA_FALSE; + } + + return EINA_TRUE; +} + +/** + * Helper ecore_getopt callback to parse geometry size (WxH). + * + * @param parser This parameter isn't in use. + * @param desc This parameter isn't in use. + * @param str size value + * @param data This parameter isn't in use. + * @param storage must be a pointer to @c Eina_Rectangle and will be used to + * store the two values passed in the given string and @c 0 in the x and y + * fields. + * @return @c EINA_TRUE on success, @c EINA_FALSE on incorrect size value. + * + * @c callback_data value is ignored, you can safely use @c NULL. + */ +EAPI Eina_Bool +ecore_getopt_callback_size_parse(const Ecore_Getopt *parser __UNUSED__, + const Ecore_Getopt_Desc *desc __UNUSED__, + const char *str, + void *data __UNUSED__, + Ecore_Getopt_Value *storage) +{ + Eina_Rectangle *v = (Eina_Rectangle *)storage->ptrp; + + if (sscanf(str, "%dx%d", &v->w, &v->h) != 2) + { + fprintf(stderr, _("ERROR: incorrect size value '%s'\n"), str); + return EINA_FALSE; + } + v->x = 0; + v->y = 0; + + return EINA_TRUE; +} + diff --git a/src/lib/ecore/ecore_glib.c b/src/lib/ecore/ecore_glib.c new file mode 100644 index 0000000..a4db0ab --- /dev/null +++ b/src/lib/ecore/ecore_glib.c @@ -0,0 +1,342 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "Ecore.h" +#include "ecore_private.h" + +#ifdef HAVE_GLIB +#include + +static Eina_Bool _ecore_glib_active = EINA_FALSE; +static Ecore_Select_Function _ecore_glib_select_original; +static GCond *_ecore_glib_cond = NULL; +static GPollFD *_ecore_glib_fds = NULL; +static size_t _ecore_glib_fds_size = 0; +static const size_t ECORE_GLIB_FDS_INITIAL = 128; +static const size_t ECORE_GLIB_FDS_STEP = 8; +static const size_t ECORE_GLIB_FDS_MAX_FREE = 256; + +static Eina_Bool +_ecore_glib_fds_resize(size_t size) +{ + void *tmp = realloc(_ecore_glib_fds, sizeof(GPollFD) * size); + + if (!tmp) + { + ERR("Could not realloc from %zu to %zu buckets.", + _ecore_glib_fds_size, size); + return EINA_FALSE; + } + + _ecore_glib_fds = tmp; + _ecore_glib_fds_size = size; + return EINA_TRUE; +} + +static int +_ecore_glib_context_query(GMainContext *ctx, + int priority, + int *p_timer) +{ + int reqfds; + + if (_ecore_glib_fds_size == 0) + { + if (!_ecore_glib_fds_resize(ECORE_GLIB_FDS_INITIAL)) return -1; + } + + while (1) + { + size_t size; + + reqfds = g_main_context_query + (ctx, priority, p_timer, _ecore_glib_fds, _ecore_glib_fds_size); + if (reqfds <= (int)_ecore_glib_fds_size) break; + + size = (1 + reqfds / ECORE_GLIB_FDS_STEP) * ECORE_GLIB_FDS_STEP; + if (!_ecore_glib_fds_resize(size)) return -1; + } + + if (reqfds + ECORE_GLIB_FDS_MAX_FREE < _ecore_glib_fds_size) + { + size_t size; + + size = (1 + reqfds / ECORE_GLIB_FDS_MAX_FREE) * ECORE_GLIB_FDS_MAX_FREE; + _ecore_glib_fds_resize(size); + } + + return reqfds; +} + +static int +_ecore_glib_context_poll_from(const GPollFD *pfds, + int count, + fd_set *rfds, + fd_set *wfds, + fd_set *efds) +{ + const GPollFD *itr = pfds, *itr_end = pfds + count; + int glib_fds = -1; + + for (; itr < itr_end; itr++) + { + if (glib_fds < itr->fd) + glib_fds = itr->fd; + + if (itr->events & G_IO_IN) + FD_SET(itr->fd, rfds); + if (itr->events & G_IO_OUT) + FD_SET(itr->fd, wfds); + if (itr->events & (G_IO_HUP | G_IO_ERR)) + FD_SET(itr->fd, efds); + } + + return glib_fds + 1; +} + +static int +_ecore_glib_context_poll_to(GPollFD *pfds, + int count, + const fd_set *rfds, + const fd_set *wfds, + const fd_set *efds, + int ready) +{ + GPollFD *itr = pfds, *itr_end = pfds + count; + + for (; (itr < itr_end) && (ready > 0); itr++) + { + itr->revents = 0; + if (FD_ISSET(itr->fd, rfds) && (itr->events & G_IO_IN)) + { + itr->revents |= G_IO_IN; + ready--; + } + if (FD_ISSET(itr->fd, wfds) && (itr->events & G_IO_OUT)) + { + itr->revents |= G_IO_OUT; + ready--; + } + if (FD_ISSET(itr->fd, efds) && (itr->events & (G_IO_HUP | G_IO_ERR))) + { + itr->revents |= G_IO_ERR; + ready--; + } + } + return ready; +} + +static int +_ecore_glib_select__locked(GMainContext *ctx, + int ecore_fds, + fd_set *rfds, + fd_set *wfds, + fd_set *efds, + struct timeval *ecore_timeout) +{ + int priority, maxfds, glib_fds, reqfds, reqtimeout, ret; + struct timeval *timeout, glib_timeout; + + g_main_context_prepare(ctx, &priority); + reqfds = _ecore_glib_context_query(ctx, priority, &reqtimeout); + if (reqfds < 0) goto error; + + glib_fds = _ecore_glib_context_poll_from + (_ecore_glib_fds, reqfds, rfds, wfds, efds); + + if (reqtimeout == -1) + timeout = ecore_timeout; + else + { + glib_timeout.tv_sec = reqtimeout / 1000; + glib_timeout.tv_usec = (reqtimeout % 1000) * 1000; + + if (!ecore_timeout || timercmp(ecore_timeout, &glib_timeout, >)) + timeout = &glib_timeout; + else + timeout = ecore_timeout; + } + + maxfds = (ecore_fds >= glib_fds) ? ecore_fds : glib_fds; + ret = _ecore_glib_select_original(maxfds, rfds, wfds, efds, timeout); + + ret = _ecore_glib_context_poll_to + (_ecore_glib_fds, reqfds, rfds, wfds, efds, ret); + + if (g_main_context_check(ctx, priority, _ecore_glib_fds, reqfds)) + g_main_context_dispatch(ctx); + + return ret; + +error: + return _ecore_glib_select_original + (ecore_fds, rfds, wfds, efds, ecore_timeout); +} + +static int +_ecore_glib_select(int ecore_fds, + fd_set *rfds, + fd_set *wfds, + fd_set *efds, + struct timeval *ecore_timeout) +{ + GStaticMutex lock = G_STATIC_MUTEX_INIT; + GMutex *mutex = g_static_mutex_get_mutex(&lock); + GMainContext *ctx = g_main_context_default(); + int ret; + + if (g_main_context_acquire(ctx)) + { + if (mutex) g_mutex_lock(mutex); + } + else + { + if (!_ecore_glib_cond) + _ecore_glib_cond = g_cond_new(); + + while (!g_main_context_wait(ctx, _ecore_glib_cond, mutex)) + g_thread_yield(); + } + + ret = _ecore_glib_select__locked + (ctx, ecore_fds, rfds, wfds, efds, ecore_timeout); + + if (mutex) g_mutex_unlock(mutex); + g_main_context_release(ctx); + g_static_mutex_free(&lock); + + return ret; +} + +#endif + +void +_ecore_glib_init(void) +{ +} + +void +_ecore_glib_shutdown(void) +{ +#ifdef HAVE_GLIB + if (!_ecore_glib_active) return; + _ecore_glib_active = EINA_FALSE; + + if (ecore_main_loop_select_func_get() == _ecore_glib_select) + ecore_main_loop_select_func_set(_ecore_glib_select_original); + + if (_ecore_glib_fds) + { + free(_ecore_glib_fds); + _ecore_glib_fds = NULL; + } + _ecore_glib_fds_size = 0; + + if (_ecore_glib_cond) + { + g_cond_free(_ecore_glib_cond); + _ecore_glib_cond = NULL; + } +#endif +} + +/** + * @addtogroup Ecore_Main_Loop_Group + * + * @} + */ + +/** + * Request ecore to integrate GLib's main loop. + * + * This will add a small overhead during every main loop interaction + * by checking glib's default main context (used by its main loop). If + * it have events to be checked (timers, file descriptors or idlers), + * then these will be polled alongside with Ecore's own events, then + * dispatched before Ecore's. This is done by calling + * ecore_main_loop_select_func_set(). + * + * This will cooperate with previously set + * ecore_main_loop_select_func_set() by calling the old + * function. Similarly, if you want to override + * ecore_main_loop_select_func_set() after main loop is integrated, + * call the new select function set by this call (get it by calling + * ecore_main_loop_select_func_get() right after + * ecore_main_loop_glib_integrate()). + * + * This is useful to use GMainLoop libraries, like GTK, GUPnP, + * LibSoup, GConf and more. Adobe Flash plugin and other plugins + * systems depend on this as well. + * + * Once initialized/integrated, it will be valid until Ecore is + * completely shut down. + * + * Example of use: + * @code + * + * int main(void) + * { + * ecore_init(); + * ecore_main_loop_glib_integrate(); + * + * // some code here + * + * ecore_main_loop_begin(); + * + * ecore_shutdown(); + * + * return 0; + * } + * + * @endcode + * + * @note This is only available if Ecore was compiled with GLib support. + * @note You don't need to call this function if Ecore was compiled with + * --enable-glib-integration-always. + * + * @return @c EINA_TRUE on success of @c EINA_FALSE if it failed, + * likely no GLib support in Ecore. + */ +EAPI Eina_Bool +ecore_main_loop_glib_integrate(void) +{ +#ifdef HAVE_GLIB + void *func; + + if (_ecore_glib_active) return EINA_TRUE; + func = ecore_main_loop_select_func_get(); + if (func == _ecore_glib_select) return EINA_TRUE; + _ecore_glib_select_original = func; + ecore_main_loop_select_func_set(_ecore_glib_select); + _ecore_glib_active = EINA_TRUE; + return EINA_TRUE; +#else + fputs("ERROR: no glib support in ecore.\n", stderr); + return EINA_FALSE; +#endif +} + +Eina_Bool _ecore_glib_always_integrate = 1; + +/** + * Disable always integrating glib + * + * If ecore is compiled with --enable-glib-integration-always (to always + * call ecore_main_loop_glib_integrate() when ecore_init() is called), then + * calling this before calling ecore_init() will disable the integration. + * This is for apps that explicitly do not want this to happen for whatever + * reasons they may have. + */ +EAPI void +ecore_main_loop_glib_always_integrate_disable(void) +{ + _ecore_glib_always_integrate = 0; +} + +/** + * @} + */ diff --git a/src/lib/ecore/ecore_idle_enterer.c b/src/lib/ecore/ecore_idle_enterer.c new file mode 100644 index 0000000..73e72cb --- /dev/null +++ b/src/lib/ecore/ecore_idle_enterer.c @@ -0,0 +1,211 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "Ecore.h" +#include "ecore_private.h" + +struct _Ecore_Idle_Enterer +{ + EINA_INLIST; + ECORE_MAGIC; + Ecore_Task_Cb func; + void *data; + int references; + Eina_Bool delete_me : 1; +}; +GENERIC_ALLOC_SIZE_DECLARE(Ecore_Idle_Enterer); + +static Ecore_Idle_Enterer *idle_enterers = NULL; +static Ecore_Idle_Enterer *idle_enterer_current = NULL; +static int idle_enterers_delete_me = 0; + +static void * +_ecore_idle_enterer_del(Ecore_Idle_Enterer *idle_enterer); + +/** + * @addtogroup Ecore_Idle_Group + * + * @{ + */ + +/** + * Add an idle enterer handler. + * @param func The function to call when entering an idle state. + * @param data The data to be passed to the @p func call + * @return A handle to the idle enterer callback if successful. Otherwise, + * NULL is returned. + * @note The function func will be called every time the main loop is entering + * idle state, as long as it returns 1 (or ECORE_CALLBACK_RENEW). A return of 0 + * (or ECORE_CALLBACK_CANCEL) deletes the idle enterer. + */ +EAPI Ecore_Idle_Enterer * +ecore_idle_enterer_add(Ecore_Task_Cb func, + const void *data) +{ + Ecore_Idle_Enterer *ie = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); + + if (!func) goto unlock; + ie = ecore_idle_enterer_calloc(1); + if (!ie) goto unlock; + ECORE_MAGIC_SET(ie, ECORE_MAGIC_IDLE_ENTERER); + ie->func = func; + ie->data = (void *)data; + idle_enterers = (Ecore_Idle_Enterer *)eina_inlist_append(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(ie)); +unlock: + _ecore_unlock(); + return ie; +} + +/** + * Add an idle enterer handler at the start of the list so it gets called earlier than others. + * @param func The function to call when entering an idle state. + * @param data The data to be passed to the @p func call + * @return A handle to the idle enterer callback if successful. Otherwise, + * NULL is returned. + * @note The function func will be called every time the main loop is entering + * idle state, as long as it returns 1 (or ECORE_CALLBACK_RENEW). A return of 0 + * (or ECORE_CALLBACK_CANCEL) deletes the idle enterer. + */ +EAPI Ecore_Idle_Enterer * +ecore_idle_enterer_before_add(Ecore_Task_Cb func, + const void *data) +{ + Ecore_Idle_Enterer *ie = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); + + if (!func) goto unlock; + ie = ecore_idle_enterer_calloc(1); + if (!ie) goto unlock; + ECORE_MAGIC_SET(ie, ECORE_MAGIC_IDLE_ENTERER); + ie->func = func; + ie->data = (void *)data; + idle_enterers = (Ecore_Idle_Enterer *)eina_inlist_prepend(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(ie)); +unlock: + _ecore_unlock(); + return ie; +} + +/** + * Delete an idle enterer callback. + * @param idle_enterer The idle enterer to delete + * @return The data pointer passed to the idler enterer callback on success. + * NULL otherwise. + */ +EAPI void * +ecore_idle_enterer_del(Ecore_Idle_Enterer *idle_enterer) +{ + void *data; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + if (!ECORE_MAGIC_CHECK(idle_enterer, ECORE_MAGIC_IDLE_ENTERER)) + { + ECORE_MAGIC_FAIL(idle_enterer, ECORE_MAGIC_IDLE_ENTERER, + "ecore_idle_enterer_del"); + return NULL; + } + _ecore_lock(); + data = _ecore_idle_enterer_del(idle_enterer); + _ecore_unlock(); + return data; +} + +/** + * @} + */ + +static void * +_ecore_idle_enterer_del(Ecore_Idle_Enterer *idle_enterer) +{ + EINA_SAFETY_ON_TRUE_RETURN_VAL(idle_enterer->delete_me, NULL); + idle_enterer->delete_me = 1; + idle_enterers_delete_me = 1; + return idle_enterer->data; +} + +void +_ecore_idle_enterer_shutdown(void) +{ + Ecore_Idle_Enterer *ie; + while ((ie = idle_enterers)) + { + idle_enterers = (Ecore_Idle_Enterer *)eina_inlist_remove(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(idle_enterers)); + ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE); + ecore_idle_enterer_mp_free(ie); + } + idle_enterers_delete_me = 0; + idle_enterer_current = NULL; +} + +void +_ecore_idle_enterer_call(void) +{ + if (!idle_enterer_current) + { + /* regular main loop, start from head */ + idle_enterer_current = idle_enterers; + } + else + { + /* recursive main loop, continue from where we were */ + idle_enterer_current = + (Ecore_Idle_Enterer *)EINA_INLIST_GET(idle_enterer_current)->next; + } + + while (idle_enterer_current) + { + Ecore_Idle_Enterer *ie = (Ecore_Idle_Enterer *)idle_enterer_current; + if (!ie->delete_me) + { + ie->references++; + if (!_ecore_call_task_cb(ie->func, ie->data)) + { + if (!ie->delete_me) _ecore_idle_enterer_del(ie); + } + ie->references--; + } + if (idle_enterer_current) /* may have changed in recursive main loops */ + idle_enterer_current = + (Ecore_Idle_Enterer *)EINA_INLIST_GET(idle_enterer_current)->next; + } + if (idle_enterers_delete_me) + { + Ecore_Idle_Enterer *l; + int deleted_idler_enterers_in_use = 0; + + for (l = idle_enterers; l; ) + { + Ecore_Idle_Enterer *ie = l; + l = (Ecore_Idle_Enterer *)EINA_INLIST_GET(l)->next; + if (ie->delete_me) + { + if (ie->references) + { + deleted_idler_enterers_in_use++; + continue; + } + + idle_enterers = (Ecore_Idle_Enterer *)eina_inlist_remove(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(ie)); + ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE); + ecore_idle_enterer_mp_free(ie); + } + } + if (!deleted_idler_enterers_in_use) + idle_enterers_delete_me = 0; + } +} + +int +_ecore_idle_enterer_exist(void) +{ + if (idle_enterers) return 1; + return 0; +} + diff --git a/src/lib/ecore/ecore_idle_exiter.c b/src/lib/ecore/ecore_idle_exiter.c new file mode 100644 index 0000000..0086bb6 --- /dev/null +++ b/src/lib/ecore/ecore_idle_exiter.c @@ -0,0 +1,179 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "Ecore.h" +#include "ecore_private.h" + +struct _Ecore_Idle_Exiter +{ + EINA_INLIST; + ECORE_MAGIC; + Ecore_Task_Cb func; + void *data; + int references; + Eina_Bool delete_me : 1; +}; +GENERIC_ALLOC_SIZE_DECLARE(Ecore_Idle_Exiter); + +static Ecore_Idle_Exiter *idle_exiters = NULL; +static Ecore_Idle_Exiter *idle_exiter_current = NULL; +static int idle_exiters_delete_me = 0; + +static void * +_ecore_idle_exiter_del(Ecore_Idle_Exiter *idle_exiter); + +/** + * @addtogroup Ecore_Idle_Group + * + * @{ + */ + +/** + * Add an idle exiter handler. + * @param func The function to call when exiting an idle state. + * @param data The data to be passed to the @p func call + * @return A handle to the idle exiter callback on success. NULL otherwise. + * @note The function func will be called every time the main loop is exiting + * idle state, as long as it returns 1 (or ECORE_CALLBACK_RENEW). A return of 0 + * (or ECORE_CALLBACK_CANCEL) deletes the idle exiter. + */ +EAPI Ecore_Idle_Exiter * +ecore_idle_exiter_add(Ecore_Task_Cb func, + const void *data) +{ + Ecore_Idle_Exiter *ie = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); + if (!func) goto unlock; + ie = ecore_idle_exiter_calloc(1); + if (!ie) goto unlock; + ECORE_MAGIC_SET(ie, ECORE_MAGIC_IDLE_EXITER); + ie->func = func; + ie->data = (void *)data; + idle_exiters = (Ecore_Idle_Exiter *)eina_inlist_append(EINA_INLIST_GET(idle_exiters), EINA_INLIST_GET(ie)); +unlock: + _ecore_unlock(); + return ie; +} + +/** + * Delete an idle exiter handler from the list to be run on exiting idle state. + * @param idle_exiter The idle exiter to delete + * @return The data pointer that was being being passed to the handler if + * successful. NULL otherwise. + */ +EAPI void * +ecore_idle_exiter_del(Ecore_Idle_Exiter *idle_exiter) +{ + void *data; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + if (!ECORE_MAGIC_CHECK(idle_exiter, ECORE_MAGIC_IDLE_EXITER)) + { + ECORE_MAGIC_FAIL(idle_exiter, ECORE_MAGIC_IDLE_EXITER, + "ecore_idle_exiter_del"); + return NULL; + } + _ecore_lock(); + data = _ecore_idle_exiter_del(idle_exiter); + _ecore_unlock(); + return data; +} + +/** + * @} + */ + +static void * +_ecore_idle_exiter_del(Ecore_Idle_Exiter *idle_exiter) +{ + EINA_SAFETY_ON_TRUE_RETURN_VAL(idle_exiter->delete_me, NULL); + idle_exiter->delete_me = 1; + idle_exiters_delete_me = 1; + return idle_exiter->data; +} + +void +_ecore_idle_exiter_shutdown(void) +{ + Ecore_Idle_Exiter *ie; + while ((ie = idle_exiters)) + { + idle_exiters = (Ecore_Idle_Exiter *)eina_inlist_remove(EINA_INLIST_GET(idle_exiters), EINA_INLIST_GET(idle_exiters)); + ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE); + ecore_idle_exiter_mp_free(ie); + } + idle_exiters_delete_me = 0; + idle_exiter_current = NULL; +} + +void +_ecore_idle_exiter_call(void) +{ + if (!idle_exiter_current) + { + /* regular main loop, start from head */ + idle_exiter_current = idle_exiters; + } + else + { + /* recursive main loop, continue from where we were */ + idle_exiter_current = + (Ecore_Idle_Exiter *)EINA_INLIST_GET(idle_exiter_current)->next; + } + + while (idle_exiter_current) + { + Ecore_Idle_Exiter *ie = (Ecore_Idle_Exiter *)idle_exiter_current; + if (!ie->delete_me) + { + ie->references++; + if (!_ecore_call_task_cb(ie->func, ie->data)) + { + if (!ie->delete_me) _ecore_idle_exiter_del(ie); + } + ie->references--; + } + if (idle_exiter_current) /* may have changed in recursive main loops */ + idle_exiter_current = + (Ecore_Idle_Exiter *)EINA_INLIST_GET(idle_exiter_current)->next; + } + if (idle_exiters_delete_me) + { + Ecore_Idle_Exiter *l; + int deleted_idler_exiters_in_use = 0; + + for (l = idle_exiters; l; ) + { + Ecore_Idle_Exiter *ie = l; + + l = (Ecore_Idle_Exiter *)EINA_INLIST_GET(l)->next; + if (ie->delete_me) + { + if (ie->references) + { + deleted_idler_exiters_in_use++; + continue; + } + + idle_exiters = (Ecore_Idle_Exiter *)eina_inlist_remove(EINA_INLIST_GET(idle_exiters), EINA_INLIST_GET(ie)); + ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE); + ecore_idle_exiter_mp_free(ie); + } + } + if (!deleted_idler_exiters_in_use) + idle_exiters_delete_me = 0; + } +} + +int +_ecore_idle_exiter_exist(void) +{ + if (idle_exiters) return 1; + return 0; +} + diff --git a/src/lib/ecore/ecore_idler.c b/src/lib/ecore/ecore_idler.c new file mode 100644 index 0000000..62998b6 --- /dev/null +++ b/src/lib/ecore/ecore_idler.c @@ -0,0 +1,161 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "Ecore.h" +#include "ecore_private.h" + +struct _Ecore_Idler +{ + EINA_INLIST; + ECORE_MAGIC; + Ecore_Task_Cb func; + void *data; + int references; + Eina_Bool delete_me : 1; +}; +GENERIC_ALLOC_SIZE_DECLARE(Ecore_Idler); + +static Ecore_Idler *idlers = NULL; +static Ecore_Idler *idler_current = NULL; +static int idlers_delete_me = 0; + +static void * +_ecore_idler_del(Ecore_Idler *idler); + +EAPI Ecore_Idler * +ecore_idler_add(Ecore_Task_Cb func, + const void *data) +{ + Ecore_Idler *ie = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); + if (!func) goto unlock; + ie = ecore_idler_calloc(1); + if (!ie) goto unlock; + ECORE_MAGIC_SET(ie, ECORE_MAGIC_IDLER); + ie->func = func; + ie->data = (void *)data; + idlers = (Ecore_Idler *)eina_inlist_append(EINA_INLIST_GET(idlers), EINA_INLIST_GET(ie)); +unlock: + _ecore_unlock(); + return ie; +} + +EAPI void * +ecore_idler_del(Ecore_Idler *idler) +{ + void *data = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + if (!ECORE_MAGIC_CHECK(idler, ECORE_MAGIC_IDLER)) + { + ECORE_MAGIC_FAIL(idler, ECORE_MAGIC_IDLER, + "ecore_idler_del"); + return NULL; + } + + _ecore_lock(); + data = _ecore_idler_del(idler); + _ecore_unlock(); + return data; +} + +/** + * @} + */ + +/** + * @} + */ + +static void * +_ecore_idler_del(Ecore_Idler *idler) +{ + EINA_SAFETY_ON_TRUE_RETURN_VAL(idler->delete_me, NULL); + idler->delete_me = 1; + idlers_delete_me = 1; + return idler->data; +} + +void +_ecore_idler_shutdown(void) +{ + Ecore_Idler *ie; + while ((ie = idlers)) + { + idlers = (Ecore_Idler *)eina_inlist_remove(EINA_INLIST_GET(idlers), EINA_INLIST_GET(idlers)); + ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE); + ecore_idler_mp_free(ie); + } + idlers_delete_me = 0; + idler_current = NULL; +} + +int +_ecore_idler_all_call(void) +{ + if (!idler_current) + { + /* regular main loop, start from head */ + idler_current = idlers; + } + else + { + /* recursive main loop, continue from where we were */ + idler_current = (Ecore_Idler *)EINA_INLIST_GET(idler_current)->next; + } + + while (idler_current) + { + Ecore_Idler *ie = (Ecore_Idler *)idler_current; + if (!ie->delete_me) + { + ie->references++; + if (!_ecore_call_task_cb(ie->func, ie->data)) + { + if (!ie->delete_me) _ecore_idler_del(ie); + } + ie->references--; + } + if (idler_current) /* may have changed in recursive main loops */ + idler_current = (Ecore_Idler *)EINA_INLIST_GET(idler_current)->next; + } + if (idlers_delete_me) + { + Ecore_Idler *l; + int deleted_idlers_in_use = 0; + for (l = idlers; l; ) + { + Ecore_Idler *ie = l; + l = (Ecore_Idler *)EINA_INLIST_GET(l)->next; + if (ie->delete_me) + { + if (ie->references) + { + deleted_idlers_in_use++; + continue; + } + + idlers = (Ecore_Idler *)eina_inlist_remove(EINA_INLIST_GET(idlers), EINA_INLIST_GET(ie)); + ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE); + ecore_idler_mp_free(ie); + } + } + if (!deleted_idlers_in_use) + idlers_delete_me = 0; + } + if (idlers) return 1; + return 0; +} + +int +_ecore_idler_exist(void) +{ + if (idlers) return 1; + return 0; +} + diff --git a/src/lib/ecore/ecore_job.c b/src/lib/ecore/ecore_job.c new file mode 100644 index 0000000..93852a3 --- /dev/null +++ b/src/lib/ecore/ecore_job.c @@ -0,0 +1,125 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "Ecore.h" +#include "ecore_private.h" + +static Eina_Bool _ecore_job_event_handler(void *data, + int type, + void *ev); +static void _ecore_job_event_free(void *data, + void *ev); + +static int ecore_event_job_type = 0; +static Ecore_Event_Handler *_ecore_job_handler = NULL; + +struct _Ecore_Job +{ + ECORE_MAGIC; + Ecore_Event *event; + Ecore_Cb func; + void *data; +}; +GENERIC_ALLOC_SIZE_DECLARE(Ecore_Job); + +void +_ecore_job_init(void) +{ + ecore_event_job_type = ecore_event_type_new(); + _ecore_job_handler = ecore_event_handler_add(ecore_event_job_type, _ecore_job_event_handler, NULL); +} + +void +_ecore_job_shutdown(void) +{ + _ecore_event_handler_del(_ecore_job_handler); + _ecore_job_handler = NULL; +} + +/** + * @addtogroup Ecore_Job_Group + * + * @{ + */ + +/** + * Add a job to the event queue. + * @param func The function to call when the job gets handled. + * @param data Data pointer to be passed to the job function when the job is + * handled. + * @return The handle of the job. @c NULL is returned if the job could not be + * added to the queue. + * @note Once the job has been executed, the job handle is invalid. + */ +EAPI Ecore_Job * +ecore_job_add(Ecore_Cb func, + const void *data) +{ + Ecore_Job *job; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + if (!func) return NULL; + + job = ecore_job_calloc(1); + if (!job) return NULL; + ECORE_MAGIC_SET(job, ECORE_MAGIC_JOB); + job->event = ecore_event_add(ecore_event_job_type, job, _ecore_job_event_free, NULL); + if (!job->event) + { + ecore_job_mp_free(job); + return NULL; + } + job->func = func; + job->data = (void *)data; + return job; +} + +/** + * Delete a queued job that has not yet been executed. + * @param job Handle of the job to delete. + * @return The data pointer that was to be passed to the job. + */ +EAPI void * +ecore_job_del(Ecore_Job *job) +{ + void *data; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + if (!ECORE_MAGIC_CHECK(job, ECORE_MAGIC_JOB)) + { + ECORE_MAGIC_FAIL(job, ECORE_MAGIC_JOB, + "ecore_job_del"); + return NULL; + } + data = job->data; + ECORE_MAGIC_SET(job, ECORE_MAGIC_NONE); + ecore_event_del(job->event); + return data; +} + +/** + * @} + */ + +static Eina_Bool +_ecore_job_event_handler(void *data __UNUSED__, + int type __UNUSED__, + void *ev) +{ + Ecore_Job *job; + + job = ev; + job->func(job->data); + return ECORE_CALLBACK_CANCEL; +} + +static void +_ecore_job_event_free(void *data __UNUSED__, + void *job) +{ + ecore_job_mp_free(job); +} + diff --git a/src/lib/ecore/ecore_main.c b/src/lib/ecore/ecore_main.c new file mode 100644 index 0000000..fea9fa8 --- /dev/null +++ b/src/lib/ecore/ecore_main.c @@ -0,0 +1,2093 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef _WIN32 +# define WIN32_LEAN_AND_MEAN +# include +# undef WIN32_LEAN_AND_MEAN +# ifndef USER_TIMER_MINIMUM +# define USER_TIMER_MINIMUM 0x0a +# endif +#endif + +#ifdef __SUNPRO_C +# include +# include +#endif + +#include +#include +#include +#include +#include +#include + +#ifndef _MSC_VER +# include +# include +#else +# include +#endif + +#ifdef HAVE_ISFINITE +# define ECORE_FINITE(t) isfinite(t) +#else +# ifdef _MSC_VER +# define ECORE_FINITE(t) _finite(t) +# else +# define ECORE_FINITE(t) finite(t) +# endif +#endif + +//#define FIX_HZ 1 + +#ifdef FIX_HZ +# ifndef _MSC_VER +# include +# endif +# ifndef HZ +# define HZ 100 +# endif +#endif + +#ifdef HAVE_EVIL +# include +#endif + +#include "Ecore.h" +#include "ecore_private.h" + +#ifdef HAVE_SYS_EPOLL_H +# define HAVE_EPOLL 1 +# include +#else + +# define HAVE_EPOLL 0 +# define EPOLLIN 1 +# define EPOLLPRI 2 +# define EPOLLOUT 4 +# define EPOLLERR 8 + +#define EPOLL_CTL_ADD 1 +#define EPOLL_CTL_DEL 2 +#define EPOLL_CTL_MOD 3 + +typedef union epoll_data { + void *ptr; + int fd; + uint32_t u32; + uint64_t u64; +} epoll_data_t; + +struct epoll_event +{ + uint32_t events; + epoll_data_t data; +}; + +static inline int +epoll_create(int size __UNUSED__) +{ + return -1; +} + +static inline int +epoll_wait(int epfd __UNUSED__, + struct epoll_event *events __UNUSED__, + int maxevents __UNUSED__, + int timeout __UNUSED__) +{ + return -1; +} + +static inline int +epoll_ctl(int epfd __UNUSED__, + int op __UNUSED__, + int fd __UNUSED__, + struct epoll_event *event __UNUSED__) +{ + return -1; +} + +#endif + +#ifdef HAVE_SYS_TIMERFD_H +#include +#else +/* fallback code if we don't have real timerfd - reduces number of ifdefs */ +#ifndef CLOCK_MONOTONIC +#define CLOCK_MONOTONIC 0 /* bogus value */ +#endif +#ifndef TFD_NONBLOCK +#define TFD_NONBLOCK 0 /* bogus value */ +#endif +static inline int +timerfd_create(int clockid __UNUSED__, + int flags __UNUSED__) +{ + return -1; +} + +static inline int +timerfd_settime(int fd __UNUSED__, + int flags __UNUSED__, + const struct itimerspec *new_value __UNUSED__, + struct itimerspec *old_value __UNUSED__) +{ + return -1; +} + +#endif /* HAVE_SYS_TIMERFD_H */ + +#ifdef USE_G_MAIN_LOOP +# include +#endif + +#define NS_PER_SEC (1000.0 * 1000.0 * 1000.0) + +struct _Ecore_Fd_Handler +{ + EINA_INLIST; + ECORE_MAGIC; + Ecore_Fd_Handler *next_ready; + int fd; + Ecore_Fd_Handler_Flags flags; + Ecore_Fd_Cb func; + void *data; + Ecore_Fd_Cb buf_func; + void *buf_data; + Ecore_Fd_Prep_Cb prep_func; + void *prep_data; + int references; + Eina_Bool read_active : 1; + Eina_Bool write_active : 1; + Eina_Bool error_active : 1; + Eina_Bool delete_me : 1; + Eina_Bool file : 1; +#if defined(USE_G_MAIN_LOOP) + GPollFD gfd; +#endif +}; +GENERIC_ALLOC_SIZE_DECLARE(Ecore_Fd_Handler); + +#ifdef _WIN32 +struct _Ecore_Win32_Handler +{ + EINA_INLIST; + ECORE_MAGIC; + HANDLE h; + Ecore_Win32_Handle_Cb func; + void *data; + int references; + Eina_Bool delete_me : 1; +}; +GENERIC_ALLOC_SIZE_DECLARE(Ecore_Win32_Handler); +#endif + +#ifndef USE_G_MAIN_LOOP +static int _ecore_main_select(double timeout); +#endif +static void _ecore_main_prepare_handlers(void); +static void _ecore_main_fd_handlers_cleanup(void); +#ifndef _WIN32 +# ifndef USE_G_MAIN_LOOP +static void _ecore_main_fd_handlers_bads_rem(void); +# endif +#endif +static void _ecore_main_fd_handlers_call(void); +static int _ecore_main_fd_handlers_buf_call(void); +#ifndef USE_G_MAIN_LOOP +static void _ecore_main_loop_iterate_internal(int once_only); +#endif + +#ifdef _WIN32 +static int _ecore_main_win32_select(int nfds, + fd_set *readfds, + fd_set *writefds, + fd_set *exceptfds, + struct timeval *timeout); +static void _ecore_main_win32_handlers_cleanup(void); +#endif + +static int in_main_loop = 0; +static int do_quit = 0; +static Ecore_Fd_Handler *fd_handlers = NULL; +static Ecore_Fd_Handler *fd_handler_current = NULL; +static Eina_List *fd_handlers_with_prep = NULL; +static Eina_List *file_fd_handlers = NULL; +static Eina_List *fd_handlers_with_buffer = NULL; +static Eina_List *fd_handlers_to_delete = NULL; + +/* single linked list of ready fdhs, terminated by loop to self */ +static Ecore_Fd_Handler *fd_handlers_to_call; +static Ecore_Fd_Handler *fd_handlers_to_call_current; + +#ifdef _WIN32 +static Ecore_Win32_Handler *win32_handlers = NULL; +static Ecore_Win32_Handler *win32_handler_current = NULL; +static Eina_Bool win32_handlers_delete_me = EINA_FALSE; +#endif + +#ifdef _WIN32 +Ecore_Select_Function main_loop_select = _ecore_main_win32_select; +#else +# if !defined EXOTIC_NO_SELECT +# ifdef HAVE_SYS_SELECT_H +# include +# endif +Ecore_Select_Function main_loop_select = select; +# else +Ecore_Select_Function main_loop_select = NULL; +# endif +#endif + +#ifndef USE_G_MAIN_LOOP +static double t1 = 0.0; +static double t2 = 0.0; +#endif + +static int timer_fd = -1; +static int epoll_fd = -1; +static pid_t epoll_pid; + +#ifdef USE_G_MAIN_LOOP +static GPollFD ecore_epoll_fd; +static GPollFD ecore_timer_fd; +static GSource *ecore_glib_source; +static guint ecore_glib_source_id; +static GMainLoop *ecore_main_loop; +static gboolean ecore_idling; +static gboolean _ecore_glib_idle_enterer_called; +static gboolean ecore_fds_ready; +#endif + +static inline void +_ecore_fd_valid(void) +{ + if (HAVE_EPOLL && epoll_fd >= 0) + { + if (fcntl(epoll_fd, F_GETFD) < 0) + { + ERR("arghhh you caught me! report a backtrace to edevel!"); + pause(); + } + } +} + +static inline void +_ecore_try_add_to_call_list(Ecore_Fd_Handler *fdh) +{ + /* check if this fdh is already in the list */ + if (fdh->next_ready) + return; + if (fdh->read_active || fdh->write_active || fdh->error_active) + { + /* + * make sure next_ready is non-null by pointing to ourselves + * use that to indicate this fdh is in the ready list + * insert at the head of the list to avoid trouble + */ + fdh->next_ready = fd_handlers_to_call ? fd_handlers_to_call : fdh; + fd_handlers_to_call = fdh; + } +} + +static inline int +_ecore_get_epoll_fd(void) +{ + if (epoll_pid && epoll_pid != getpid()) + { + /* forked! */ + _ecore_main_loop_shutdown(); + } + if (epoll_pid == 0 && epoll_fd < 0) + { + _ecore_main_loop_init(); + } + return epoll_fd; +} + +static inline int +_ecore_epoll_add(int efd, + int fd, + int events, + void *ptr) +{ + struct epoll_event ev; + + memset(&ev, 0, sizeof (ev)); + ev.events = events; + ev.data.ptr = ptr; + INF("adding poll on %d %08x", fd, events); + return epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ev); +} + +static inline int +_ecore_poll_events_from_fdh(Ecore_Fd_Handler *fdh) +{ + int events = 0; + if (fdh->flags & ECORE_FD_READ) events |= EPOLLIN; + if (fdh->flags & ECORE_FD_WRITE) events |= EPOLLOUT; + if (fdh->flags & ECORE_FD_ERROR) events |= EPOLLERR | EPOLLPRI; + return events; +} + +#ifdef USE_G_MAIN_LOOP +static inline int +_gfd_events_from_fdh(Ecore_Fd_Handler *fdh) +{ + int events = 0; + if (fdh->flags & ECORE_FD_READ) events |= G_IO_IN; + if (fdh->flags & ECORE_FD_WRITE) events |= G_IO_OUT; + if (fdh->flags & ECORE_FD_ERROR) events |= G_IO_ERR; + return events; +} + +#endif + +static inline int +_ecore_main_fdh_poll_add(Ecore_Fd_Handler *fdh) +{ + int r = 0; + + if ((!fdh->file) && HAVE_EPOLL && epoll_fd >= 0) + { + r = _ecore_epoll_add(_ecore_get_epoll_fd(), fdh->fd, + _ecore_poll_events_from_fdh(fdh), fdh); + } + else + { +#ifdef USE_G_MAIN_LOOP + fdh->gfd.fd = fdh->fd; + fdh->gfd.events = _gfd_events_from_fdh(fdh); + fdh->gfd.revents = 0; + INF("adding gpoll on %d %08x", fdh->fd, fdh->gfd.events); + g_source_add_poll(ecore_glib_source, &fdh->gfd); +#endif + } + return r; +} + +static inline void +_ecore_main_fdh_poll_del(Ecore_Fd_Handler *fdh) +{ + if ((!fdh->file) && HAVE_EPOLL && epoll_fd >= 0) + { + struct epoll_event ev; + int efd = _ecore_get_epoll_fd(); + + memset(&ev, 0, sizeof (ev)); + INF("removing poll on %d", fdh->fd); + /* could get an EBADF if somebody closed the FD before removing it */ + if ((epoll_ctl(efd, EPOLL_CTL_DEL, fdh->fd, &ev) < 0)) + { + if (errno == EBADF) + { + WRN("fd %d was closed, can't remove from epoll - reinit!", + fdh->fd); + _ecore_main_loop_shutdown(); + _ecore_main_loop_init(); + } + else + { + ERR("Failed to delete epoll fd %d! (errno=%d)", fdh->fd, errno); + } + } + } + else + { +#ifdef USE_G_MAIN_LOOP + fdh->gfd.fd = fdh->fd; + fdh->gfd.events = _gfd_events_from_fdh(fdh); + fdh->gfd.revents = 0; + INF("adding gpoll on %d %08x", fdh->fd, fdh->gfd.events); + g_source_add_poll(ecore_glib_source, &fdh->gfd); +#endif + } +} + +static inline int +_ecore_main_fdh_poll_modify(Ecore_Fd_Handler *fdh) +{ + int r = 0; + if ((!fdh->file) && HAVE_EPOLL && epoll_fd >= 0) + { + struct epoll_event ev; + int efd = _ecore_get_epoll_fd(); + + memset(&ev, 0, sizeof (ev)); + ev.events = _ecore_poll_events_from_fdh(fdh); + ev.data.ptr = fdh; + INF("modifing epoll on %d to %08x", fdh->fd, ev.events); + r = epoll_ctl(efd, EPOLL_CTL_MOD, fdh->fd, &ev); + } + else + { +#ifdef USE_G_MAIN_LOOP + fdh->gfd.fd = fdh->fd; + fdh->gfd.events = _gfd_events_from_fdh(fdh); + fdh->gfd.revents = 0; + INF("modifing gpoll on %d to %08x", fdh->fd, fdh->gfd.events); +#endif + } + return r; +} + +static inline int +_ecore_main_fdh_epoll_mark_active(void) +{ + struct epoll_event ev[32]; + int i, ret; + int efd = _ecore_get_epoll_fd(); + + memset(&ev, 0, sizeof (ev)); + ret = epoll_wait(efd, ev, sizeof(ev) / sizeof(struct epoll_event), 0); + if (ret < 0) + { + if (errno == EINTR) return -1; + ERR("epoll_wait failed %d", errno); + return -1; + } + + for (i = 0; i < ret; i++) + { + Ecore_Fd_Handler *fdh; + + fdh = ev[i].data.ptr; + if (!ECORE_MAGIC_CHECK(fdh, ECORE_MAGIC_FD_HANDLER)) + { + ECORE_MAGIC_FAIL(fdh, ECORE_MAGIC_FD_HANDLER, + "_ecore_main_fdh_epoll_mark_active"); + continue; + } + if (fdh->delete_me) + { + ERR("deleted fd in epoll"); + continue; + } + + if (ev[i].events & EPOLLIN) + fdh->read_active = EINA_TRUE; + if (ev[i].events & EPOLLOUT) + fdh->write_active = EINA_TRUE; + if (ev[i].events & EPOLLERR) + fdh->error_active = EINA_TRUE; + + _ecore_try_add_to_call_list(fdh); + } + + return ret; +} + +#ifdef USE_G_MAIN_LOOP + +static inline int +_ecore_main_fdh_glib_mark_active(void) +{ + Ecore_Fd_Handler *fdh; + int ret = 0; + + /* call the prepare callback for all handlers */ + EINA_INLIST_FOREACH(fd_handlers, fdh) + { + if (fdh->delete_me) + continue; + + if (fdh->gfd.revents & G_IO_IN) + fdh->read_active = EINA_TRUE; + if (fdh->gfd.revents & G_IO_OUT) + fdh->write_active = EINA_TRUE; + if (fdh->gfd.revents & G_IO_ERR) + fdh->error_active = EINA_TRUE; + + _ecore_try_add_to_call_list(fdh); + + if (fdh->gfd.revents & (G_IO_IN | G_IO_OUT | G_IO_ERR)) ret++; + } + + return ret; +} + +/* like we are about to enter main_loop_select in _ecore_main_select */ +static gboolean +_ecore_main_gsource_prepare(GSource *source __UNUSED__, + gint *next_time) +{ + gboolean ready = FALSE; + + _ecore_lock(); + in_main_loop++; + + if (!ecore_idling && !_ecore_glib_idle_enterer_called) + { + _ecore_time_loop_time = ecore_time_get(); + _ecore_timer_expired_timers_call(_ecore_time_loop_time); + _ecore_timer_cleanup(); + + _ecore_idle_enterer_call(); + _ecore_throttle(); + _ecore_glib_idle_enterer_called = FALSE; + + if (fd_handlers_with_buffer) + _ecore_main_fd_handlers_buf_call(); + } + + _ecore_signal_received_process(); + + /* don't check fds if somebody quit */ + if (g_main_loop_is_running(ecore_main_loop)) + { + /* only set idling state in dispatch */ + if (ecore_idling && !_ecore_idler_exist() && !_ecore_event_exist()) + { + if (_ecore_timers_exists()) + { + int r = -1; + double t = _ecore_timer_next_get(); + if (timer_fd >= 0 && t > 0.0) + { + struct itimerspec ts; + + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 0; + ts.it_value.tv_sec = t; + ts.it_value.tv_nsec = fmod(t * NS_PER_SEC, NS_PER_SEC); + + /* timerfd cannot sleep for 0 time */ + if (ts.it_value.tv_sec || ts.it_value.tv_nsec) + { + r = timerfd_settime(timer_fd, 0, &ts, NULL); + if (r < 0) + { + ERR("timer set returned %d (errno=%d)", r, errno); + close(timer_fd); + timer_fd = -1; + } + else + INF("sleeping for %ld s %06ldus", + ts.it_value.tv_sec, + ts.it_value.tv_nsec / 1000); + } + } + if (r == -1) + { + *next_time = ceil(t * 1000.0); + if (t == 0.0) + ready = TRUE; + } + } + else + *next_time = -1; + } + else + { + *next_time = 0; + if (_ecore_event_exist()) + ready = TRUE; + } + + if (fd_handlers_with_prep) + _ecore_main_prepare_handlers(); + } + else + ready = TRUE; + + in_main_loop--; + INF("leave, timeout = %d", *next_time); + _ecore_unlock(); + + /* ready if we're not running (about to quit) */ + return ready; +} + +static gboolean +_ecore_main_gsource_check(GSource *source __UNUSED__) +{ + gboolean ret = FALSE; + + _ecore_lock(); + in_main_loop++; + + /* check if old timers expired */ + if (ecore_idling && !_ecore_idler_exist() && !_ecore_event_exist()) + { + if (timer_fd >= 0) + { + uint64_t count = 0; + int r = read(timer_fd, &count, sizeof count); + if (r == -1 && errno == EAGAIN) + ; + else if (r == sizeof count) + ret = TRUE; + else + { + /* unexpected things happened... fail back to old way */ + ERR("timer read returned %d (errno=%d)", r, errno); + close(timer_fd); + timer_fd = -1; + } + } + } + else + ret = TRUE; + + /* check if fds are ready */ + if (HAVE_EPOLL && epoll_fd >= 0) + ecore_fds_ready = (_ecore_main_fdh_epoll_mark_active() > 0); + else + ecore_fds_ready = (_ecore_main_fdh_glib_mark_active() > 0); + _ecore_main_fd_handlers_cleanup(); + if (ecore_fds_ready) + ret = TRUE; + + /* check timers after updating loop time */ + if (!ret && _ecore_timers_exists()) + ret = (0.0 == _ecore_timer_next_get()); + + in_main_loop--; + _ecore_unlock(); + + return ret; +} + +/* like we just came out of main_loop_select in _ecore_main_select */ +static gboolean +_ecore_main_gsource_dispatch(GSource *source __UNUSED__, + GSourceFunc callback __UNUSED__, + gpointer user_data __UNUSED__) +{ + gboolean events_ready, timers_ready, idlers_ready; + double next_time; + + _ecore_lock(); + _ecore_time_loop_time = ecore_time_get(); + _ecore_timer_enable_new(); + next_time = _ecore_timer_next_get(); + + events_ready = _ecore_event_exist(); + timers_ready = _ecore_timers_exists() && (0.0 == next_time); + idlers_ready = _ecore_idler_exist(); + + in_main_loop++; + INF("enter idling=%d fds=%d events=%d timers=%d (next=%.2f) idlers=%d", + ecore_idling, ecore_fds_ready, events_ready, + timers_ready, next_time, idlers_ready); + + if (ecore_idling && events_ready) + { + _ecore_idle_exiter_call(); + ecore_idling = 0; + } + else if (!ecore_idling && !events_ready) + { + ecore_idling = 1; + } + + if (ecore_idling) + { + _ecore_idler_all_call(); + + events_ready = _ecore_event_exist(); + + if (ecore_fds_ready || events_ready || timers_ready) + { + _ecore_idle_exiter_call(); + ecore_idling = 0; + } + } + + /* process events */ + if (!ecore_idling) + { + _ecore_main_fd_handlers_call(); + if (fd_handlers_with_buffer) + _ecore_main_fd_handlers_buf_call(); + _ecore_signal_received_process(); + _ecore_event_call(); + _ecore_main_fd_handlers_cleanup(); + + _ecore_timer_expired_timers_call(_ecore_time_loop_time); + _ecore_timer_cleanup(); + + _ecore_idle_enterer_call(); + _ecore_throttle(); + _ecore_glib_idle_enterer_called = TRUE; + + if (fd_handlers_with_buffer) + _ecore_main_fd_handlers_buf_call(); + } + + in_main_loop--; + _ecore_unlock(); + + return TRUE; /* what should be returned here? */ +} + +static void +_ecore_main_gsource_finalize(GSource *source __UNUSED__) +{ +} + +static GSourceFuncs ecore_gsource_funcs = +{ + .prepare = _ecore_main_gsource_prepare, + .check = _ecore_main_gsource_check, + .dispatch = _ecore_main_gsource_dispatch, + .finalize = _ecore_main_gsource_finalize, +}; + +#endif + +void +_ecore_main_loop_init(void) +{ + epoll_fd = epoll_create(1); + if (epoll_fd < 0) + WRN("Failed to create epoll fd!"); + epoll_pid = getpid(); + + /* add polls on all our file descriptors */ + Ecore_Fd_Handler *fdh; + EINA_INLIST_FOREACH(fd_handlers, fdh) + { + if (fdh->delete_me) + continue; + _ecore_epoll_add(epoll_fd, fdh->fd, + _ecore_poll_events_from_fdh(fdh), fdh); + _ecore_main_fdh_poll_add(fdh); + } + + /* setup for the g_main_loop only integration */ +#ifdef USE_G_MAIN_LOOP + ecore_glib_source = g_source_new(&ecore_gsource_funcs, sizeof (GSource)); + if (!ecore_glib_source) + CRIT("Failed to create glib source for epoll!"); + else + { + g_source_set_priority(ecore_glib_source, G_PRIORITY_HIGH_IDLE + 20); + if (HAVE_EPOLL && epoll_fd >= 0) + { + /* epoll multiplexes fds into the g_main_loop */ + ecore_epoll_fd.fd = epoll_fd; + ecore_epoll_fd.events = G_IO_IN; + ecore_epoll_fd.revents = 0; + g_source_add_poll(ecore_glib_source, &ecore_epoll_fd); + } + + /* timerfd gives us better than millisecond accuracy in g_main_loop */ + timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); + if (timer_fd < 0) + WRN("failed to create timer fd!"); + else + { + ecore_timer_fd.fd = timer_fd; + ecore_timer_fd.events = G_IO_IN; + ecore_timer_fd.revents = 0; + g_source_add_poll(ecore_glib_source, &ecore_timer_fd); + } + + ecore_glib_source_id = g_source_attach(ecore_glib_source, NULL); + if (ecore_glib_source_id <= 0) + CRIT("Failed to attach glib source to default context"); + } +#endif +} + +void +_ecore_main_loop_shutdown(void) +{ +#ifdef USE_G_MAIN_LOOP + if (ecore_glib_source) + { + g_source_destroy(ecore_glib_source); + ecore_glib_source = NULL; + } +#endif + + if (epoll_fd >= 0) + { + close(epoll_fd); + epoll_fd = -1; + } + epoll_pid = 0; + + if (timer_fd >= 0) + { + close(timer_fd); + timer_fd = -1; + } +} + +void * +_ecore_main_fd_handler_del(Ecore_Fd_Handler *fd_handler) +{ + if (fd_handler->delete_me) + { + ERR("fdh %p deleted twice", fd_handler); + return NULL; + } + + _ecore_main_fdh_poll_del(fd_handler); + fd_handler->delete_me = EINA_TRUE; + fd_handlers_to_delete = eina_list_append(fd_handlers_to_delete, fd_handler); + if (fd_handler->prep_func && fd_handlers_with_prep) + fd_handlers_with_prep = eina_list_remove(fd_handlers_with_prep, fd_handler); + if (fd_handler->buf_func && fd_handlers_with_buffer) + fd_handlers_with_buffer = eina_list_remove(fd_handlers_with_buffer, fd_handler); + return fd_handler->data; +} + +/** + * @addtogroup Ecore_Main_Loop_Group + * + * @{ + */ + +/** + * Runs a single iteration of the main loop to process everything on the + * queue. + * + * It does everything that is already done inside an @c Ecore main loop, like + * checking for expired timers, idlers, etc. But it will do it only once and + * return, instead of keep watching for new events. + * + * DO NOT use this function unless you are the person God comes to ask for + * advice when He has trouble managing the Universe. + * + * @see ecore_main_loop_iterate_may_block() + */ +EAPI void +ecore_main_loop_iterate(void) +{ + EINA_MAIN_LOOP_CHECK_RETURN; +#ifndef USE_G_MAIN_LOOP + _ecore_lock(); + _ecore_time_loop_time = ecore_time_get(); + _ecore_main_loop_iterate_internal(1); + _ecore_unlock(); +#else + g_main_context_iteration(NULL, 0); +#endif +} + +/** + * Runs a single iteration of the main loop to process everything on the + * queue with block/non-blocking status. + * + * @param may_block A flag if the main loop has a possibility of blocking. + * (@c EINA_TRUE = may block/@c EINA_FALSE = non block) + * + * This is an extension API for ecore_main_loop_iterate() with additional + * parameter. It does everything that is already done inside an + * @c Ecore main loop, like checking for expired timers, idlers, etc. But it + * will do it only once and return, instead of keep watching for new events. + * + * DO NOT use this function unless you are the person God comes to ask for + * advice when He has trouble managing the Universe. + * + * @see ecore_main_loop_iterate() + */ +EAPI int +ecore_main_loop_iterate_may_block(int may_block) +{ + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0); +#ifndef USE_G_MAIN_LOOP + _ecore_lock(); + _ecore_time_loop_time = ecore_time_get(); +in_main_loop++; + _ecore_main_loop_iterate_internal(!may_block); +in_main_loop--; + _ecore_unlock(); + return _ecore_event_exist(); +#else + return g_main_context_iteration(NULL, may_block); +#endif +} + +/** + * Runs the application main loop. + * + * This function will not return until @ref ecore_main_loop_quit is called. It + * will check for expired timers, idlers, file descriptors being watched by fd + * handlers, etc. Once everything is done, before entering again on idle state, + * any callback set as @c Idle_Enterer will be called. + * + * Each main loop iteration is done by calling ecore_main_loop_iterate() + * internally. + * + * The polling (select) function used can be changed with + * ecore_main_loop_select_func_set(). + * + * The function used to check for file descriptors, events, and that has a + * timeout for the timers can be changed using + * ecore_main_loop_select_func_set(). + */ +EAPI void +ecore_main_loop_begin(void) +{ + EINA_MAIN_LOOP_CHECK_RETURN; +#ifndef USE_G_MAIN_LOOP + _ecore_lock(); + in_main_loop++; + _ecore_time_loop_time = ecore_time_get(); + while (do_quit == 0) _ecore_main_loop_iterate_internal(0); + do_quit = 0; + in_main_loop--; + _ecore_unlock(); +#else + if (!do_quit) + { + if (!ecore_main_loop) + ecore_main_loop = g_main_loop_new(NULL, FALSE); + g_main_loop_run(ecore_main_loop); + } + do_quit = 0; +#endif +} + +/** + * Quits the main loop once all the events currently on the queue have + * been processed. + * + * This function returns immediately, but will mark the ecore_main_loop_begin() + * function to return at the end of the current main loop iteration. + */ +EAPI void +ecore_main_loop_quit(void) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + do_quit = 1; +#ifdef USE_G_MAIN_LOOP + if (ecore_main_loop) + g_main_loop_quit(ecore_main_loop); +#endif +} + +/** + * Sets the function to use when monitoring multiple file descriptors, + * and waiting until one of more of the file descriptors before ready + * for some class of I/O operation. + * + * This function will be used instead of the system call select and + * could possible be used to integrate the Ecore event loop with an + * external event loop. + * + * @warning you don't know how to use, don't even try to use it. + * + * @param func The function to be used. + */ +EAPI void +ecore_main_loop_select_func_set(Ecore_Select_Function func) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + main_loop_select = func; +} + +/** + * Gets the select function set by ecore_select_func_set(), + * or the native select function if none was set. + * + */ +EAPI Ecore_Select_Function +ecore_main_loop_select_func_get(void) +{ + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + return main_loop_select; +} + +EAPI Ecore_Fd_Handler * +ecore_main_fd_handler_add(int fd, + Ecore_Fd_Handler_Flags flags, + Ecore_Fd_Cb func, + const void *data, + Ecore_Fd_Cb buf_func, + const void *buf_data) +{ + Ecore_Fd_Handler *fdh = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); + + if ((fd < 0) || (flags == 0) || (!func)) goto unlock; + + fdh = ecore_fd_handler_calloc(1); + if (!fdh) goto unlock; + ECORE_MAGIC_SET(fdh, ECORE_MAGIC_FD_HANDLER); + fdh->next_ready = NULL; + fdh->fd = fd; + fdh->flags = flags; + if (_ecore_main_fdh_poll_add(fdh) < 0) + { + int err = errno; + ERR("Failed to add poll on fd %d (errno = %d: %s)!", fd, err, strerror(err)); + ecore_fd_handler_mp_free(fdh); + fdh = NULL; + goto unlock; + } + fdh->read_active = EINA_FALSE; + fdh->write_active = EINA_FALSE; + fdh->error_active = EINA_FALSE; + fdh->delete_me = EINA_FALSE; + fdh->func = func; + fdh->data = (void *)data; + fdh->buf_func = buf_func; + if (buf_func) + fd_handlers_with_buffer = eina_list_append(fd_handlers_with_buffer, fdh); + fdh->buf_data = (void *)buf_data; + fd_handlers = (Ecore_Fd_Handler *) + eina_inlist_append(EINA_INLIST_GET(fd_handlers), + EINA_INLIST_GET(fdh)); +unlock: + _ecore_unlock(); + + return fdh; +} + +EAPI Ecore_Fd_Handler * +ecore_main_fd_handler_file_add(int fd, + Ecore_Fd_Handler_Flags flags, + Ecore_Fd_Cb func, + const void *data, + Ecore_Fd_Cb buf_func, + const void *buf_data) +{ + Ecore_Fd_Handler *fdh = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); + + if ((fd < 0) || (flags == 0) || (!func)) goto unlock; + + fdh = ecore_fd_handler_calloc(1); + if (!fdh) goto unlock; + ECORE_MAGIC_SET(fdh, ECORE_MAGIC_FD_HANDLER); + fdh->next_ready = NULL; + fdh->fd = fd; + fdh->flags = flags; + fdh->file = EINA_TRUE; + if (_ecore_main_fdh_poll_add(fdh) < 0) + { + int err = errno; + ERR("Failed to add poll on fd %d (errno = %d: %s)!", fd, err, strerror(err)); + ecore_fd_handler_mp_free(fdh); + fdh = NULL; + goto unlock; + } + fdh->read_active = EINA_FALSE; + fdh->write_active = EINA_FALSE; + fdh->error_active = EINA_FALSE; + fdh->delete_me = EINA_FALSE; + fdh->func = func; + fdh->data = (void *)data; + fdh->buf_func = buf_func; + if (buf_func) + fd_handlers_with_buffer = eina_list_append(fd_handlers_with_buffer, fdh); + fdh->buf_data = (void *)buf_data; + fd_handlers = (Ecore_Fd_Handler *) + eina_inlist_append(EINA_INLIST_GET(fd_handlers), + EINA_INLIST_GET(fdh)); + file_fd_handlers = eina_list_append(file_fd_handlers, fdh); +unlock: + _ecore_unlock(); + + return fdh; +} + +#ifdef _WIN32 +EAPI Ecore_Win32_Handler * +ecore_main_win32_handler_add(void *h, + Ecore_Win32_Handle_Cb func, + const void *data) +{ + Ecore_Win32_Handler *wh; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + if (!h || !func) return NULL; + + wh = ecore_win32_handler_calloc(1); + if (!wh) return NULL; + ECORE_MAGIC_SET(wh, ECORE_MAGIC_WIN32_HANDLER); + wh->h = (HANDLE)h; + wh->delete_me = EINA_FALSE; + wh->func = func; + wh->data = (void *)data; + win32_handlers = (Ecore_Win32_Handler *) + eina_inlist_append(EINA_INLIST_GET(win32_handlers), + EINA_INLIST_GET(wh)); + return wh; +} + +#else +EAPI Ecore_Win32_Handler * +ecore_main_win32_handler_add(void *h __UNUSED__, + Ecore_Win32_Handle_Cb func __UNUSED__, + const void *data __UNUSED__) +{ + return NULL; +} + +#endif + +EAPI void * +ecore_main_fd_handler_del(Ecore_Fd_Handler *fd_handler) +{ + void *ret = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); + + if (!ECORE_MAGIC_CHECK(fd_handler, ECORE_MAGIC_FD_HANDLER)) + { + ECORE_MAGIC_FAIL(fd_handler, ECORE_MAGIC_FD_HANDLER, + "ecore_main_fd_handler_del"); + goto unlock; + } + ret = _ecore_main_fd_handler_del(fd_handler); +unlock: + _ecore_unlock(); + return ret; +} + +#ifdef _WIN32 +EAPI void * +ecore_main_win32_handler_del(Ecore_Win32_Handler *win32_handler) +{ + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + if (!ECORE_MAGIC_CHECK(win32_handler, ECORE_MAGIC_WIN32_HANDLER)) + { + ECORE_MAGIC_FAIL(win32_handler, ECORE_MAGIC_WIN32_HANDLER, + "ecore_main_win32_handler_del"); + return NULL; + } + win32_handler->delete_me = EINA_TRUE; + win32_handlers_delete_me = EINA_TRUE; + return win32_handler->data; +} + +#else +EAPI void * +ecore_main_win32_handler_del(Ecore_Win32_Handler *win32_handler __UNUSED__) +{ + return NULL; +} + +#endif + +EAPI void +ecore_main_fd_handler_prepare_callback_set(Ecore_Fd_Handler *fd_handler, + Ecore_Fd_Prep_Cb func, + const void *data) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + _ecore_lock(); + + if (!ECORE_MAGIC_CHECK(fd_handler, ECORE_MAGIC_FD_HANDLER)) + { + ECORE_MAGIC_FAIL(fd_handler, ECORE_MAGIC_FD_HANDLER, + "ecore_main_fd_handler_prepare_callback_set"); + goto unlock; + } + fd_handler->prep_func = func; + fd_handler->prep_data = (void *)data; + if ((!fd_handlers_with_prep) || + (fd_handlers_with_prep && (!eina_list_data_find(fd_handlers_with_prep, fd_handler)))) + /* FIXME: THIS WILL NOT SCALE WITH LOTS OF PREP FUNCTIONS!!! */ + fd_handlers_with_prep = eina_list_append(fd_handlers_with_prep, fd_handler); +unlock: + _ecore_unlock(); +} + +EAPI int +ecore_main_fd_handler_fd_get(Ecore_Fd_Handler *fd_handler) +{ + int fd = -1; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(-1); + _ecore_lock(); + + if (!ECORE_MAGIC_CHECK(fd_handler, ECORE_MAGIC_FD_HANDLER)) + { + ECORE_MAGIC_FAIL(fd_handler, ECORE_MAGIC_FD_HANDLER, + "ecore_main_fd_handler_fd_get"); + goto unlock; + } + fd = fd_handler->fd; +unlock: + _ecore_unlock(); + return fd; +} + +EAPI Eina_Bool +ecore_main_fd_handler_active_get(Ecore_Fd_Handler *fd_handler, + Ecore_Fd_Handler_Flags flags) +{ + int ret = EINA_FALSE; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(EINA_FALSE); + _ecore_lock(); + + if (!ECORE_MAGIC_CHECK(fd_handler, ECORE_MAGIC_FD_HANDLER)) + { + ECORE_MAGIC_FAIL(fd_handler, ECORE_MAGIC_FD_HANDLER, + "ecore_main_fd_handler_active_get"); + goto unlock; + } + if ((flags & ECORE_FD_READ) && (fd_handler->read_active)) ret = EINA_TRUE; + if ((flags & ECORE_FD_WRITE) && (fd_handler->write_active)) ret = EINA_TRUE; + if ((flags & ECORE_FD_ERROR) && (fd_handler->error_active)) ret = EINA_TRUE; +unlock: + _ecore_unlock(); + return ret; +} + +EAPI void +ecore_main_fd_handler_active_set(Ecore_Fd_Handler *fd_handler, + Ecore_Fd_Handler_Flags flags) +{ + int ret; + + EINA_MAIN_LOOP_CHECK_RETURN; + _ecore_lock(); + + if (!ECORE_MAGIC_CHECK(fd_handler, ECORE_MAGIC_FD_HANDLER)) + { + ECORE_MAGIC_FAIL(fd_handler, ECORE_MAGIC_FD_HANDLER, + "ecore_main_fd_handler_active_set"); + goto unlock; + } + fd_handler->flags = flags; + ret = _ecore_main_fdh_poll_modify(fd_handler); + if (ret < 0) + { + ERR("Failed to mod epoll fd %d: %s!", fd_handler->fd, strerror(ret)); + } +unlock: + _ecore_unlock(); +} + +/** + * @} + */ + +void +_ecore_main_shutdown(void) +{ + if (in_main_loop) + { + ERR("\n" + "*** ECORE WARNING: Calling ecore_shutdown() while still in the main loop.\n" + "*** Program may crash or behave strangely now."); + return; + } + while (fd_handlers) + { + Ecore_Fd_Handler *fdh; + + fdh = fd_handlers; + fd_handlers = (Ecore_Fd_Handler *)eina_inlist_remove(EINA_INLIST_GET(fd_handlers), + EINA_INLIST_GET(fdh)); + ECORE_MAGIC_SET(fdh, ECORE_MAGIC_NONE); + ecore_fd_handler_mp_free(fdh); + } + if (fd_handlers_with_buffer) + fd_handlers_with_buffer = eina_list_free(fd_handlers_with_buffer); + if (fd_handlers_with_prep) + fd_handlers_with_prep = eina_list_free(fd_handlers_with_prep); + if (fd_handlers_to_delete) + fd_handlers_to_delete = eina_list_free(fd_handlers_to_delete); + if (file_fd_handlers) + file_fd_handlers = eina_list_free(file_fd_handlers); + + fd_handlers_to_call = NULL; + fd_handlers_to_call_current = NULL; + fd_handlers_to_delete = NULL; + fd_handler_current = NULL; + +#ifdef _WIN32 + while (win32_handlers) + { + Ecore_Win32_Handler *wh; + + wh = win32_handlers; + win32_handlers = (Ecore_Win32_Handler *)eina_inlist_remove(EINA_INLIST_GET(win32_handlers), + EINA_INLIST_GET(wh)); + ECORE_MAGIC_SET(wh, ECORE_MAGIC_NONE); + ecore_win32_handler_mp_free(wh); + } + win32_handlers_delete_me = EINA_FALSE; + win32_handler_current = NULL; +#endif +} + +static void +_ecore_main_prepare_handlers(void) +{ + Ecore_Fd_Handler *fdh; + Eina_List *l, *l2; + + /* call the prepare callback for all handlers with prep functions */ + EINA_LIST_FOREACH_SAFE(fd_handlers_with_prep, l, l2, fdh) + { + if (!fdh) + { + fd_handlers_with_prep = eina_list_remove_list(l, fd_handlers_with_prep); + continue; + } + if (!fdh->delete_me && fdh->prep_func) + { + fdh->references++; + _ecore_call_prep_cb(fdh->prep_func, fdh->prep_data, fdh); + fdh->references--; + } + else + fd_handlers_with_prep = eina_list_remove_list(fd_handlers_with_prep, l); + } +} + +#ifndef USE_G_MAIN_LOOP +static int +_ecore_main_select(double timeout) +{ + struct timeval tv, *t; + fd_set rfds, wfds, exfds; + Ecore_Fd_Handler *fdh; + Eina_List *l; + int max_fd; + int ret; + + t = NULL; + if ((!ECORE_FINITE(timeout)) || (timeout == 0.0)) /* finite() tests for NaN, too big, too small, and infinity. */ + { + tv.tv_sec = 0; + tv.tv_usec = 0; + t = &tv; + } + else if (timeout > 0.0) + { + int sec, usec; + +#ifdef FIX_HZ + timeout += (0.5 / HZ); + sec = (int)timeout; + usec = (int)((timeout - (double)sec) * 1000000); +#else + sec = (int)timeout; + usec = (int)((timeout - (double)sec) * 1000000); +#endif + tv.tv_sec = sec; + tv.tv_usec = usec; + t = &tv; + } + max_fd = 0; + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&exfds); + + /* call the prepare callback for all handlers */ + if (fd_handlers_with_prep) + _ecore_main_prepare_handlers(); + + if (!HAVE_EPOLL || epoll_fd < 0) + { + EINA_INLIST_FOREACH(fd_handlers, fdh) + { + if (!fdh->delete_me) + { + if (fdh->flags & ECORE_FD_READ) + { + FD_SET(fdh->fd, &rfds); + if (fdh->fd > max_fd) max_fd = fdh->fd; + } + if (fdh->flags & ECORE_FD_WRITE) + { + FD_SET(fdh->fd, &wfds); + if (fdh->fd > max_fd) max_fd = fdh->fd; + } + if (fdh->flags & ECORE_FD_ERROR) + { + FD_SET(fdh->fd, &exfds); + if (fdh->fd > max_fd) max_fd = fdh->fd; + } + } + } + } + else + { + /* polling on the epoll fd will wake when an fd in the epoll set is active */ + max_fd = _ecore_get_epoll_fd(); + FD_SET(max_fd, &rfds); + } + EINA_LIST_FOREACH(file_fd_handlers, l, fdh) + if (!fdh->delete_me) + { + if (fdh->flags & ECORE_FD_READ) + { + FD_SET(fdh->fd, &rfds); + if (fdh->fd > max_fd) max_fd = fdh->fd; + } + if (fdh->flags & ECORE_FD_WRITE) + { + FD_SET(fdh->fd, &wfds); + if (fdh->fd > max_fd) max_fd = fdh->fd; + } + if (fdh->flags & ECORE_FD_ERROR) + { + FD_SET(fdh->fd, &exfds); + if (fdh->fd > max_fd) max_fd = fdh->fd; + } + if (fdh->fd > max_fd) max_fd = fdh->fd; + } + if (_ecore_signal_count_get()) return -1; + + _ecore_unlock(); + ret = main_loop_select(max_fd + 1, &rfds, &wfds, &exfds, t); + _ecore_lock(); + + _ecore_time_loop_time = ecore_time_get(); + if (ret < 0) + { +#ifndef _WIN32 + if (errno == EINTR) return -1; + else if (errno == EBADF) + _ecore_main_fd_handlers_bads_rem(); +#endif + } + if (ret > 0) + { + if (HAVE_EPOLL && epoll_fd >= 0) + _ecore_main_fdh_epoll_mark_active(); + else + { + EINA_INLIST_FOREACH(fd_handlers, fdh) + { + if (!fdh->delete_me) + { + if (FD_ISSET(fdh->fd, &rfds)) + fdh->read_active = EINA_TRUE; + if (FD_ISSET(fdh->fd, &wfds)) + fdh->write_active = EINA_TRUE; + if (FD_ISSET(fdh->fd, &exfds)) + fdh->error_active = EINA_TRUE; + _ecore_try_add_to_call_list(fdh); + } + } + } + EINA_LIST_FOREACH(file_fd_handlers, l, fdh) + { + if (!fdh->delete_me) + { + if (FD_ISSET(fdh->fd, &rfds)) + fdh->read_active = EINA_TRUE; + if (FD_ISSET(fdh->fd, &wfds)) + fdh->write_active = EINA_TRUE; + if (FD_ISSET(fdh->fd, &exfds)) + fdh->error_active = EINA_TRUE; + _ecore_try_add_to_call_list(fdh); + } + } + _ecore_main_fd_handlers_cleanup(); +#ifdef _WIN32 + _ecore_main_win32_handlers_cleanup(); +#endif + return 1; + } + return 0; +} + +#endif + +#ifndef _WIN32 +# ifndef USE_G_MAIN_LOOP +static void +_ecore_main_fd_handlers_bads_rem(void) +{ + Ecore_Fd_Handler *fdh; + Eina_Inlist *l; + int found = 0; + + ERR("Removing bad fds"); + for (l = EINA_INLIST_GET(fd_handlers); l; ) + { + fdh = (Ecore_Fd_Handler *)l; + l = l->next; + errno = 0; + + if ((fcntl(fdh->fd, F_GETFD) < 0) && (errno == EBADF)) + { + ERR("Found bad fd at index %d", fdh->fd); + if (fdh->flags & ECORE_FD_ERROR) + { + ERR("Fd set for error! calling user"); + fdh->references++; + if (!_ecore_call_fd_cb(fdh->func, fdh->data, fdh)) + { + ERR("Fd function err returned 0, remove it"); + if (!fdh->delete_me) + { + fdh->delete_me = EINA_TRUE; + fd_handlers_to_delete = eina_list_append(fd_handlers_to_delete, fdh); + } + found++; + } + fdh->references--; + } + else + { + ERR("Problematic fd found at %d! setting it for delete", fdh->fd); + if (!fdh->delete_me) + { + fdh->delete_me = EINA_TRUE; + fd_handlers_to_delete = eina_list_append(fd_handlers_to_delete, fdh); + } + + found++; + } + } + } + if (found == 0) + { +# ifdef HAVE_GLIB + ERR("No bad fd found. Maybe a foreign fd from glib?"); +# else + ERR("No bad fd found. EEEK!"); +# endif + } + _ecore_main_fd_handlers_cleanup(); +} + +# endif +#endif + +static void +_ecore_main_fd_handlers_cleanup(void) +{ + Ecore_Fd_Handler *fdh; + Eina_List *l, *l2; + + if (!fd_handlers_to_delete) return; + EINA_LIST_FOREACH_SAFE(fd_handlers_to_delete, l, l2, fdh) + { + if (!fdh) + { + fd_handlers_to_delete = eina_list_remove_list(l, fd_handlers_to_delete); + continue; + } + /* fdh->delete_me should be set for all fdhs at the start of the list */ + if (fdh->references) + continue; + if (fdh->buf_func && fd_handlers_with_buffer) + fd_handlers_with_buffer = eina_list_remove(fd_handlers_with_buffer, fdh); + if (fdh->prep_func && fd_handlers_with_prep) + fd_handlers_with_prep = eina_list_remove(fd_handlers_with_prep, fdh); + fd_handlers = (Ecore_Fd_Handler *) + eina_inlist_remove(EINA_INLIST_GET(fd_handlers), EINA_INLIST_GET(fdh)); + if (fdh->file) + file_fd_handlers = eina_list_remove(file_fd_handlers, fdh); + ECORE_MAGIC_SET(fdh, ECORE_MAGIC_NONE); + ecore_fd_handler_mp_free(fdh); + fd_handlers_to_delete = eina_list_remove_list(fd_handlers_to_delete, l); + } +} + +#ifdef _WIN32 +static void +_ecore_main_win32_handlers_cleanup(void) +{ + Ecore_Win32_Handler *wh; + Eina_Inlist *l; + int deleted_in_use = 0; + + if (!win32_handlers_delete_me) return; + for (l = EINA_INLIST_GET(win32_handlers); l; ) + { + wh = (Ecore_Win32_Handler *)l; + + l = l->next; + if (wh->delete_me) + { + if (wh->references) + { + deleted_in_use++; + continue; + } + + win32_handlers = (Ecore_Win32_Handler *) + eina_inlist_remove(EINA_INLIST_GET(win32_handlers), + EINA_INLIST_GET(wh)); + ECORE_MAGIC_SET(wh, ECORE_MAGIC_NONE); + ecore_win32_handler_mp_free(wh); + } + } + if (!deleted_in_use) win32_handlers_delete_me = EINA_FALSE; +} + +#endif + +static void +_ecore_main_fd_handlers_call(void) +{ + /* grab a new list */ + if (!fd_handlers_to_call_current) + { + fd_handlers_to_call_current = fd_handlers_to_call; + fd_handlers_to_call = NULL; + } + + while (fd_handlers_to_call_current) + { + Ecore_Fd_Handler *fdh = fd_handlers_to_call_current; + + if (!fdh->delete_me) + { + if ((fdh->read_active) || + (fdh->write_active) || + (fdh->error_active)) + { + fdh->references++; + if (!_ecore_call_fd_cb(fdh->func, fdh->data, fdh)) + { + if (!fdh->delete_me) + { + fdh->delete_me = EINA_TRUE; + fd_handlers_to_delete = eina_list_append(fd_handlers_to_delete, fdh); + } + } + fdh->references--; + _ecore_fd_valid(); + + fdh->read_active = EINA_FALSE; + fdh->write_active = EINA_FALSE; + fdh->error_active = EINA_FALSE; + } + } + + /* stop when we point to ourselves */ + if (fdh->next_ready == fdh) + { + fdh->next_ready = NULL; + fd_handlers_to_call_current = NULL; + break; + } + + fd_handlers_to_call_current = fdh->next_ready; + fdh->next_ready = NULL; + } +} + +static int +_ecore_main_fd_handlers_buf_call(void) +{ + Ecore_Fd_Handler *fdh; + Eina_List *l, *l2; + int ret; + + ret = 0; + EINA_LIST_FOREACH_SAFE(fd_handlers_with_buffer, l, l2, fdh) + { + if (!fdh) + { + fd_handlers_with_buffer = eina_list_remove_list(l, fd_handlers_with_buffer); + continue; + } + if ((!fdh->delete_me) && fdh->buf_func) + { + fdh->references++; + if (_ecore_call_fd_cb(fdh->buf_func, fdh->buf_data, fdh)) + { + ret |= _ecore_call_fd_cb(fdh->func, fdh->data, fdh); + fdh->read_active = EINA_TRUE; + _ecore_try_add_to_call_list(fdh); + } + fdh->references--; + } + else + fd_handlers_with_buffer = eina_list_remove_list(fd_handlers_with_buffer, l); + } + return ret; +} + +#ifndef USE_G_MAIN_LOOP + +enum { + SPIN_MORE, + SPIN_RESTART, + LOOP_CONTINUE +}; + +static int +_ecore_main_loop_spin_core(void) +{ + /* as we are spinning we need to update loop time per spin */ + _ecore_time_loop_time = ecore_time_get(); + /* call all idlers, which returns false if no more idelrs exist */ + if (!_ecore_idler_all_call()) return SPIN_RESTART; + /* sneaky - drop through or if checks - the first one to succeed + * drops through and returns "continue" so further ones dont run */ + if ((_ecore_main_select(0.0) > 0) || (_ecore_event_exist()) || + (_ecore_signal_count_get() > 0) || (do_quit)) + return LOOP_CONTINUE; + /* default - spin more */ + return SPIN_MORE; +} + +static int +_ecore_main_loop_spin_no_timers(void) +{ + /* if we have idlers we HAVE to spin and handle everything + * in a polling way - spin in a tight polling loop */ + for (;; ) + { + int action = _ecore_main_loop_spin_core(); + if (action != SPIN_MORE) return action; + /* if an idler has added a timer then we need to go through + * the start of the spin cycle again to handle cases properly */ + if (_ecore_timers_exists()) return SPIN_RESTART; + } + /* just contiune handling events etc. */ + return LOOP_CONTINUE; +} + +static int +_ecore_main_loop_spin_timers(void) +{ + /* if we have idlers we HAVE to spin and handle everything + * in a polling way - spin in a tight polling loop */ + for (;; ) + { + int action = _ecore_main_loop_spin_core(); + if (action != SPIN_MORE) return action; + /* if next timer expires now or in the past - stop spinning and + * continue the mainloop walk as our "select" timeout has + * expired now */ + if (_ecore_timer_next_get() <= 0.0) return LOOP_CONTINUE; + } + /* just contiune handling events etc. */ + return LOOP_CONTINUE; +} + +static void +_ecore_fps_marker_1(void) +{ + if (!_ecore_fps_debug) return; + t2 = ecore_time_get(); + if ((t1 > 0.0) && (t2 > 0.0)) _ecore_fps_debug_runtime_add(t2 - t1); +} + +static void +_ecore_fps_marker_2(void) +{ + if (!_ecore_fps_debug) return; + t1 = ecore_time_get(); +} + +static void +_ecore_main_loop_iterate_internal(int once_only) +{ + double next_time = -1.0; + + in_main_loop++; + /* expire any timers */ + _ecore_timer_expired_timers_call(_ecore_time_loop_time); + _ecore_timer_cleanup(); + + /* process signals into events .... */ + _ecore_signal_received_process(); + /* if as a result of timers/animators or signals we have accumulated + * events, then instantly handle them */ + if (_ecore_event_exist()) + { + /* but first conceptually enter an idle state */ + _ecore_idle_enterer_call(); + _ecore_throttle(); + /* now quickly poll to see which input fd's are active */ + _ecore_main_select(0.0); + /* allow newly queued timers to expire from now on */ + _ecore_timer_enable_new(); + /* go straight to processing the events we had queued */ + goto process_all; + } + + if (once_only) + { + /* in once_only mode we should quickly poll for inputs, signals + * if we got any events or signals, allow new timers to process. + * use bitwise or to force both conditions to be tested and + * merged together */ + if (_ecore_main_select(0.0) | _ecore_signal_count_get()) + { + _ecore_timer_enable_new(); + goto process_all; + } + } + else + { + /* call idle enterers ... */ + _ecore_idle_enterer_call(); + _ecore_throttle(); + } + + /* if these calls caused any buffered events to appear - deal with them */ + if (fd_handlers_with_buffer) + _ecore_main_fd_handlers_buf_call(); + + /* if there are any (buffered fd handling may generate them) + * then jump to processing them */ + if (_ecore_event_exist()) + { + _ecore_main_select(0.0); + _ecore_timer_enable_new(); + goto process_all; + } + + if (once_only) + { + /* in once_only mode enter idle here instead and then return */ + _ecore_idle_enterer_call(); + _ecore_throttle(); + _ecore_timer_enable_new(); + goto done; + } + + _ecore_fps_marker_1(); + + /* start of the sleeping or looping section */ +start_loop: /***************************************************************/ + /* any timers re-added as a result of these are allowed to go */ + _ecore_timer_enable_new(); + /* if we have been asked to quit the mainloop then exit at this point */ + if (do_quit) + { + _ecore_timer_enable_new(); + goto done; + } + if (!_ecore_event_exist()) + { + /* init flags */ + next_time = _ecore_timer_next_get(); + /* no idlers */ + if (!_ecore_idler_exist()) + { + /* sleep until timeout or forever (-1.0) waiting for on fds */ + _ecore_main_select(next_time); + } + else + { + int action = LOOP_CONTINUE; + + /* no timers - spin */ + if (next_time < 0) action = _ecore_main_loop_spin_no_timers(); + /* timers - spin */ + else action = _ecore_main_loop_spin_timers(); + if (action == SPIN_RESTART) goto start_loop; + } + } + _ecore_fps_marker_2(); + + /* actually wake up and deal with input, events etc. */ +process_all: /***********************************************************/ + + /* we came out of our "wait state" so idle has exited */ + if (!once_only) _ecore_idle_exiter_call(); + /* call the fd handler per fd that became alive... */ + /* this should read or write any data to the monitored fd and then */ + /* post events onto the ecore event pipe if necessary */ + _ecore_main_fd_handlers_call(); + if (fd_handlers_with_buffer) _ecore_main_fd_handlers_buf_call(); + /* process signals into events .... */ + _ecore_signal_received_process(); + /* handle events ... */ + _ecore_event_call(); + _ecore_main_fd_handlers_cleanup(); + + if (once_only) + { + /* if in once_only mode handle idle exiting */ + _ecore_idle_enterer_call(); + _ecore_throttle(); + } + +done: /*******************************************************************/ + in_main_loop--; +} + +#endif + +#ifdef _WIN32 +static int +_ecore_main_win32_select(int nfds __UNUSED__, + fd_set *readfds, + fd_set *writefds, + fd_set *exceptfds, + struct timeval *tv) +{ + HANDLE objects[MAXIMUM_WAIT_OBJECTS]; + int sockets[MAXIMUM_WAIT_OBJECTS]; + Ecore_Fd_Handler *fdh; + Ecore_Win32_Handler *wh; + unsigned int objects_nbr = 0; + unsigned int handles_nbr = 0; + unsigned int events_nbr = 0; + DWORD result; + DWORD timeout; + MSG msg; + unsigned int i; + int res; + + /* Create an event object per socket */ + EINA_INLIST_FOREACH(fd_handlers, fdh) + { + WSAEVENT event; + long network_event; + + network_event = 0; + if (readfds) + { + if (FD_ISSET(fdh->fd, readfds)) + network_event |= FD_READ; + } + if (writefds) + { + if (FD_ISSET(fdh->fd, writefds)) + network_event |= FD_WRITE; + } + if (exceptfds) + { + if (FD_ISSET(fdh->fd, exceptfds)) + network_event |= FD_OOB; + } + + if (network_event) + { + event = WSACreateEvent(); + WSAEventSelect(fdh->fd, event, network_event); + objects[objects_nbr] = event; + sockets[events_nbr] = fdh->fd; + events_nbr++; + objects_nbr++; + } + } + + /* store the HANDLEs in the objects to wait for */ + EINA_INLIST_FOREACH(win32_handlers, wh) + { + objects[objects_nbr] = wh->h; + handles_nbr++; + objects_nbr++; + } + + /* Empty the queue before waiting */ + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + /* Wait for any message sent or posted to this queue */ + /* or for one of the passed handles be set to signaled. */ + if (!tv) + timeout = INFINITE; + else + timeout = (DWORD)((tv->tv_sec * 1000.0) + (tv->tv_usec / 1000.0)); + + if (timeout == 0) return 0; + + result = MsgWaitForMultipleObjects(objects_nbr, (const HANDLE *)objects, EINA_FALSE, + timeout, QS_ALLINPUT); + + if (readfds) + FD_ZERO(readfds); + if (writefds) + FD_ZERO(writefds); + if (exceptfds) + FD_ZERO(exceptfds); + + /* The result tells us the type of event we have. */ + if (result == WAIT_FAILED) + { + char *m; + + m = evil_last_error_get(); + ERR("%s", m); + free(m); + res = -1; + } + else if (result == WAIT_TIMEOUT) + { + /* ERR("time out\n"); */ + res = 0; + } + else if (result == (WAIT_OBJECT_0 + objects_nbr)) + { + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + res = 0; + } + else if ((result >= 0) && (result < WAIT_OBJECT_0 + events_nbr)) + { + WSANETWORKEVENTS network_event; + + WSAEnumNetworkEvents(sockets[result], objects[result], &network_event); + + if ((network_event.lNetworkEvents & FD_READ) && readfds) + FD_SET(sockets[result], readfds); + if ((network_event.lNetworkEvents & FD_WRITE) && writefds) + FD_SET(sockets[result], writefds); + if ((network_event.lNetworkEvents & FD_OOB) && exceptfds) + FD_SET(sockets[result], exceptfds); + + res = 1; + } + else if ((result >= (WAIT_OBJECT_0 + events_nbr)) && + (result < (WAIT_OBJECT_0 + objects_nbr))) + { + if (!win32_handler_current) + { + /* regular main loop, start from head */ + win32_handler_current = win32_handlers; + } + else + { + /* recursive main loop, continue from where we were */ + win32_handler_current = (Ecore_Win32_Handler *)EINA_INLIST_GET(win32_handler_current)->next; + } + + while (win32_handler_current) + { + wh = win32_handler_current; + + if (objects[result - WAIT_OBJECT_0] == wh->h) + { + if (!wh->delete_me) + { + wh->references++; + if (!wh->func(wh->data, wh)) + { + wh->delete_me = EINA_TRUE; + win32_handlers_delete_me = EINA_TRUE; + } + wh->references--; + } + } + if (win32_handler_current) /* may have changed in recursive main loops */ + win32_handler_current = (Ecore_Win32_Handler *)EINA_INLIST_GET(win32_handler_current)->next; + } + res = 1; + } + else + { + ERR("unknown result...\n"); + res = -1; + } + + /* Remove event objects again */ + for (i = 0; i < events_nbr; i++) WSACloseEvent(objects[i]); + + return res; +} + +#endif diff --git a/src/lib/ecore/ecore_pipe.c b/src/lib/ecore/ecore_pipe.c new file mode 100644 index 0000000..debdbe8 --- /dev/null +++ b/src/lib/ecore/ecore_pipe.c @@ -0,0 +1,688 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_ISFINITE +# define ECORE_FINITE(t) isfinite(t) +#else +# ifdef _MSC_VER +# define ECORE_FINITE(t) _finite(t) +# else +# define ECORE_FINITE(t) finite(t) +# endif +#endif + +#define FIX_HZ 1 + +#ifdef FIX_HZ +# ifndef _MSC_VER +# include +# endif +# ifndef HZ +# define HZ 100 +# endif +#endif + +#ifdef HAVE_EVIL +# include +#endif + +#ifdef HAVE_ESCAPE +# include +#endif + +#ifdef HAVE_EXOTIC +# include +#endif + +#include "Ecore.h" +#include "ecore_private.h" + +/* How of then we should retry to write to the pipe */ +#define ECORE_PIPE_WRITE_RETRY 6 + +/* + * On Windows, pipe() is implemented with sockets. + * Contrary to Linux, Windows uses different functions + * for sockets and fd's: write() is for fd's and send + * is for sockets. So I need to put some win32 code + * here. I can't think of a solution where the win32 + * code is in Evil and not here. + */ + +#ifdef _WIN32 + +# include + +# define pipe_write(fd, buffer, size) send((fd), (char *)(buffer), size, 0) +# define pipe_read(fd, buffer, size) recv((fd), (char *)(buffer), size, 0) +# define pipe_close(fd) closesocket(fd) +# define PIPE_FD_INVALID INVALID_SOCKET +# define PIPE_FD_ERROR SOCKET_ERROR + +#else + +# include +# include + +# define pipe_write(fd, buffer, size) write((fd), buffer, size) +# define pipe_read(fd, buffer, size) read((fd), buffer, size) +# define pipe_close(fd) close(fd) +# define PIPE_FD_INVALID -1 +# define PIPE_FD_ERROR -1 + +#endif /* ! _WIN32 */ + +#include +#include "ecore_private.h" + +struct _Ecore_Pipe +{ + ECORE_MAGIC; + int fd_read; + int fd_write; + Ecore_Fd_Handler *fd_handler; + const void *data; + Ecore_Pipe_Cb handler; + unsigned int len; + int handling; + size_t already_read; + void *passed_data; + int message; + Eina_Bool delete_me : 1; +}; +GENERIC_ALLOC_SIZE_DECLARE(Ecore_Pipe); + +static Eina_Bool _ecore_pipe_read(void *data, + Ecore_Fd_Handler *fd_handler); + +/** + * @addtogroup Ecore_Pipe_Group + * + * @{ + */ + +/** + * Create two file descriptors (sockets on Windows). Add + * a callback that will be called when the file descriptor that + * is listened receives data. An event is also put in the event + * queue when data is received. + * + * @param handler The handler called when data is received. + * @param data Data to pass to @p handler when it is called. + * @return A newly created Ecore_Pipe object if successful. + * @c NULL otherwise. + */ +EAPI Ecore_Pipe * +ecore_pipe_add(Ecore_Pipe_Cb handler, + const void *data) +{ + Ecore_Pipe *p; + int fds[2]; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + if (!handler) return NULL; + + p = ecore_pipe_calloc(1); + if (!p) return NULL; + + if (pipe(fds)) + { + ecore_pipe_mp_free(p); + return NULL; + } + + ECORE_MAGIC_SET(p, ECORE_MAGIC_PIPE); + p->fd_read = fds[0]; + p->fd_write = fds[1]; + p->handler = handler; + p->data = data; + + fcntl(p->fd_read, F_SETFL, O_NONBLOCK); + p->fd_handler = ecore_main_fd_handler_add(p->fd_read, + ECORE_FD_READ, + _ecore_pipe_read, + p, + NULL, NULL); + return p; +} + +/** + * Free an Ecore_Pipe object created with ecore_pipe_add(). + * + * @param p The Ecore_Pipe object to be freed. + * @return The pointer to the private data + */ +EAPI void * +ecore_pipe_del(Ecore_Pipe *p) +{ + void *data; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE)) + { + ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_del"); + return NULL; + } + p->delete_me = EINA_TRUE; + if (p->handling > 0) return (void *)p->data; + if (p->fd_handler) _ecore_main_fd_handler_del(p->fd_handler); + if (p->fd_read != PIPE_FD_INVALID) pipe_close(p->fd_read); + if (p->fd_write != PIPE_FD_INVALID) pipe_close(p->fd_write); + data = (void *)p->data; + ecore_pipe_mp_free(p); + return data; +} + +/** + * Close the read end of an Ecore_Pipe object created with ecore_pipe_add(). + * + * @param p The Ecore_Pipe object. + */ +EAPI void +ecore_pipe_read_close(Ecore_Pipe *p) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE)) + { + ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_read_close"); + return; + } + if (p->fd_handler) + { + _ecore_main_fd_handler_del(p->fd_handler); + p->fd_handler = NULL; + } + if (p->fd_read != PIPE_FD_INVALID) + { + pipe_close(p->fd_read); + p->fd_read = PIPE_FD_INVALID; + } +} + +/** + * Stop monitoring if necessary the pipe for reading. See ecore_pipe_thaw() + * for monitoring it again. + * + * @param p The Ecore_Pipe object. + * @since 1.1 + */ +EAPI void +ecore_pipe_freeze(Ecore_Pipe *p) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE)) + { + ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_read_freeze"); + return; + } + if (p->fd_handler) + { + _ecore_main_fd_handler_del(p->fd_handler); + p->fd_handler = NULL; + } +} + +/** + * Start monitoring again the pipe for reading. See ecore_pipe_freeze() for + * stopping the monitoring activity. This will not work if + * ecore_pipe_read_close() was previously called on the same pipe. + * + * @param p The Ecore_Pipe object. + * @since 1.1 + */ +EAPI void +ecore_pipe_thaw(Ecore_Pipe *p) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE)) + { + ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_read_thaw"); + return; + } + if (!p->fd_handler && p->fd_read != PIPE_FD_INVALID) + { + p->fd_handler = ecore_main_fd_handler_add(p->fd_read, + ECORE_FD_READ, + _ecore_pipe_read, + p, + NULL, NULL); + } +} + +/** + * @brief Wait from another thread on the read side of a pipe. + * + * @param p The pipe to watch on. + * @param message_count The minimal number of message to wait before exiting. + * @param wait The amount of time in second to wait before exiting. + * @return the number of message catched during that wait call. + * @since 1.1 + * + * Negative value for @p wait means infite wait. + */ +EAPI int +ecore_pipe_wait(Ecore_Pipe *p, + int message_count, + double wait) +{ + struct timeval tv, *t; + fd_set rset; + double end = 0.0; + double timeout; + int ret; + int total = 0; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(-1); + if (p->fd_read == PIPE_FD_INVALID) + return -1; + + FD_ZERO(&rset); + FD_SET(p->fd_read, &rset); + + if (wait >= 0.0) + end = ecore_loop_time_get() + wait; + timeout = wait; + + while (message_count > 0 && (timeout > 0.0 || wait <= 0.0)) + { + if (wait >= 0.0) + { + /* finite() tests for NaN, too big, too small, and infinity. */ + if ((!ECORE_FINITE(timeout)) || (timeout == 0.0)) + { + tv.tv_sec = 0; + tv.tv_usec = 0; + } + else if (timeout > 0.0) + { + int sec, usec; +#ifdef FIX_HZ + timeout += (0.5 / HZ); + sec = (int)timeout; + usec = (int)((timeout - (double)sec) * 1000000); +#else + sec = (int)timeout; + usec = (int)((timeout - (double)sec) * 1000000); +#endif + tv.tv_sec = sec; + tv.tv_usec = usec; + } + t = &tv; + } + else + { + t = NULL; + } + + ret = main_loop_select(p->fd_read + 1, &rset, NULL, NULL, t); + + if (ret > 0) + { + _ecore_pipe_read(p, NULL); + message_count -= p->message; + total += p->message; + p->message = 0; + } + else if (ret == 0) + { + break; + } + else if (errno != EINTR) + { + close(p->fd_read); + p->fd_read = PIPE_FD_INVALID; + break; + } + + if (wait >= 0.0) + timeout = end - ecore_loop_time_get(); + } + + return total; +} + +/** + * Close the write end of an Ecore_Pipe object created with ecore_pipe_add(). + * + * @param p The Ecore_Pipe object. + */ +EAPI void +ecore_pipe_write_close(Ecore_Pipe *p) +{ + if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE)) + { + ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_write_close"); + return; + } + if (p->fd_write != PIPE_FD_INVALID) + { + pipe_close(p->fd_write); + p->fd_write = PIPE_FD_INVALID; + } +} + +/** + * Write on the file descriptor the data passed as parameter. + * + * @param p The Ecore_Pipe object. + * @param buffer The data to write into the pipe. + * @param nbytes The size of the @p buffer in bytes + * @return @c EINA_TRUE on a successful write, @c EINA_FALSE on error. + */ +EAPI Eina_Bool +ecore_pipe_write(Ecore_Pipe *p, + const void *buffer, + unsigned int nbytes) +{ + ssize_t ret; + size_t already_written = 0; + int retry = ECORE_PIPE_WRITE_RETRY; + + if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE)) + { + ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_write"); + return EINA_FALSE; + } + + if (p->delete_me) return EINA_FALSE; + + if (p->fd_write == PIPE_FD_INVALID) return EINA_FALSE; + + /* First write the len into the pipe */ + do + { + ret = pipe_write(p->fd_write, &nbytes, sizeof(nbytes)); + if (ret == sizeof(nbytes)) + { + retry = ECORE_PIPE_WRITE_RETRY; + break; + } + else if (ret > 0) + { + /* XXX What should we do here? */ + ERR("The length of the data was not written complete" + " to the pipe"); + return EINA_FALSE; + } + else if (ret == PIPE_FD_ERROR && errno == EPIPE) + { + pipe_close(p->fd_write); + p->fd_write = PIPE_FD_INVALID; + return EINA_FALSE; + } + else if (ret == PIPE_FD_ERROR && errno == EINTR) + /* try it again */ + ; + else + { + ERR("An unhandled error (ret: %zd errno: %d)" + "occurred while writing to the pipe the length", + ret, errno); + } + } + while (retry--); + + if (retry != ECORE_PIPE_WRITE_RETRY) return EINA_FALSE; + + /* and now pass the data to the pipe */ + do + { + ret = pipe_write(p->fd_write, + ((unsigned char *)buffer) + already_written, + nbytes - already_written); + + if (ret == (ssize_t)(nbytes - already_written)) + return EINA_TRUE; + else if (ret >= 0) + { + already_written -= ret; + continue; + } + else if (ret == PIPE_FD_ERROR && errno == EPIPE) + { + pipe_close(p->fd_write); + p->fd_write = PIPE_FD_INVALID; + return EINA_FALSE; + } + else if (ret == PIPE_FD_ERROR && errno == EINTR) + /* try it again */ + ; + else + { + ERR("An unhandled error (ret: %zd errno: %d)" + "occurred while writing to the pipe the length", + ret, errno); + } + } + while (retry--); + + return EINA_FALSE; +} + +/** + * @} + */ + +/* Private function */ +static void +_ecore_pipe_unhandle(Ecore_Pipe *p) +{ + p->handling--; + if (p->delete_me) + { + ecore_pipe_del(p); + } +} + +static Eina_Bool +_ecore_pipe_read(void *data, + Ecore_Fd_Handler *fd_handler __UNUSED__) +{ + Ecore_Pipe *p = (Ecore_Pipe *)data; + int i; + + p->handling++; + for (i = 0; i < 16; i++) + { + ssize_t ret; + + /* if we already have read some data we don't need to read the len + * but to finish the already started job + */ + if (p->len == 0) + { + /* read the len of the passed data */ + ret = pipe_read(p->fd_read, &p->len, sizeof(p->len)); + + /* catch the non error case first */ + /* read amount ok - nothing more to do */ + if (ret == sizeof(p->len)) + ; + else if (ret > 0) + { + /* we got more data than we asked for - definite error */ + ERR("Only read %i bytes from the pipe, although" + " we need to read %i bytes.", + (int)ret, (int)sizeof(p->len)); + _ecore_pipe_unhandle(p); + return ECORE_CALLBACK_CANCEL; + } + else if (ret == 0) + { + /* we got no data */ + if (i == 0) + { + /* no data on first try through means an error */ + if (!p->delete_me) + p->handler((void *)p->data, NULL, 0); + if (p->passed_data) free(p->passed_data); + p->passed_data = NULL; + p->already_read = 0; + p->len = 0; + p->message++; + pipe_close(p->fd_read); + p->fd_read = PIPE_FD_INVALID; + p->fd_handler = NULL; + _ecore_pipe_unhandle(p); + return ECORE_CALLBACK_CANCEL; + } + else + { + /* no data after first loop try is ok */ + _ecore_pipe_unhandle(p); + return ECORE_CALLBACK_RENEW; + } + } +#ifndef _WIN32 + else if ((ret == PIPE_FD_ERROR) && + ((errno == EINTR) || (errno == EAGAIN))) + { + return ECORE_CALLBACK_RENEW; + } + else + { + ERR("An unhandled error (ret: %i errno: %i [%s])" + "occurred while reading from the pipe the length", + (int)ret, errno, strerror(errno)); + return ECORE_CALLBACK_RENEW; + } +#else + else /* ret == PIPE_FD_ERROR is the only other case on Windows */ + { + if (WSAGetLastError() != WSAEWOULDBLOCK) + { + if (!p->delete_me) + p->handler((void *)p->data, NULL, 0); + if (p->passed_data) free(p->passed_data); + p->passed_data = NULL; + p->already_read = 0; + p->len = 0; + p->message++; + pipe_close(p->fd_read); + p->fd_read = PIPE_FD_INVALID; + p->fd_handler = NULL; + _ecore_pipe_unhandle(p); + return ECORE_CALLBACK_CANCEL; + } + } +#endif + } + + /* if somehow we got less than or equal to 0 we got an errnoneous + * messages so call callback with null and len we got. this case should + * never happen */ + if (p->len == 0) + { + if (!p->delete_me) + p->handler((void *)p->data, NULL, 0); + /* reset all values to 0 */ + if (p->passed_data) free(p->passed_data); + p->passed_data = NULL; + p->already_read = 0; + p->len = 0; + p->message++; + _ecore_pipe_unhandle(p); + return ECORE_CALLBACK_RENEW; + } + + /* we dont have a buffer to hold the data, so alloc it */ + if (!p->passed_data) + { + p->passed_data = malloc(p->len); + /* alloc failed - error case */ + if (!p->passed_data) + { + if (!p->delete_me) + p->handler((void *)p->data, NULL, 0); + /* close the pipe */ + p->already_read = 0; + p->len = 0; + p->message++; + pipe_close(p->fd_read); + p->fd_read = PIPE_FD_INVALID; + p->fd_handler = NULL; + _ecore_pipe_unhandle(p); + return ECORE_CALLBACK_CANCEL; + } + } + + /* and read the passed data */ + ret = pipe_read(p->fd_read, + ((unsigned char *)p->passed_data) + p->already_read, + p->len - p->already_read); + + /* catch the non error case first */ + /* if we read enough data to finish the message/buffer */ + if (ret == (ssize_t)(p->len - p->already_read)) + { + if (!p->delete_me) + p->handler((void *)p->data, p->passed_data, p->len); + free(p->passed_data); + /* reset all values to 0 */ + p->passed_data = NULL; + p->already_read = 0; + p->len = 0; + p->message++; + } + else if (ret > 0) + { + /* more data left to read */ + p->already_read += ret; + _ecore_pipe_unhandle(p); + return ECORE_CALLBACK_RENEW; + } + else if (ret == 0) + { + /* 0 bytes to read - could be more to read next select wake up */ + _ecore_pipe_unhandle(p); + return ECORE_CALLBACK_RENEW; + } +#ifndef _WIN32 + else if ((ret == PIPE_FD_ERROR) && + ((errno == EINTR) || (errno == EAGAIN))) + { + _ecore_pipe_unhandle(p); + return ECORE_CALLBACK_RENEW; + } + else + { + ERR("An unhandled error (ret: %zd errno: %d)" + "occurred while reading from the pipe the data", + ret, errno); + _ecore_pipe_unhandle(p); + return ECORE_CALLBACK_RENEW; + } +#else + else /* ret == PIPE_FD_ERROR is the only other case on Windows */ + { + if (WSAGetLastError() != WSAEWOULDBLOCK) + { + if (!p->delete_me) + p->handler((void *)p->data, NULL, 0); + if (p->passed_data) free(p->passed_data); + p->passed_data = NULL; + p->already_read = 0; + p->len = 0; + p->message++; + pipe_close(p->fd_read); + p->fd_read = PIPE_FD_INVALID; + p->fd_handler = NULL; + _ecore_pipe_unhandle(p); + return ECORE_CALLBACK_CANCEL; + } + else + break; + } +#endif + } + + _ecore_pipe_unhandle(p); + return ECORE_CALLBACK_RENEW; +} + diff --git a/src/lib/ecore/ecore_poll.c b/src/lib/ecore/ecore_poll.c new file mode 100644 index 0000000..384ee68 --- /dev/null +++ b/src/lib/ecore/ecore_poll.c @@ -0,0 +1,353 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "Ecore.h" +#include "ecore_private.h" + +struct _Ecore_Poller +{ + EINA_INLIST; + ECORE_MAGIC; + int ibit; + unsigned char delete_me : 1; + Ecore_Task_Cb func; + void *data; +}; +GENERIC_ALLOC_SIZE_DECLARE(Ecore_Poller); + +static Ecore_Timer *timer = NULL; +static int min_interval = -1; +static int interval_incr = 0; +static int at_tick = 0; +static int just_added_poller = 0; +static int poller_delete_count = 0; +static int poller_walking = 0; +static double poll_interval = 0.125; +static double poll_cur_interval = 0.0; +static double last_tick = 0.0; +static Ecore_Poller *pollers[16] = +{ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; +static unsigned short poller_counters[16] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static void _ecore_poller_next_tick_eval(void); +static Eina_Bool _ecore_poller_cb_timer(void *data); + +static void +_ecore_poller_next_tick_eval(void) +{ + int i; + double interval; + + min_interval = -1; + for (i = 0; i < 15; i++) + { + if (pollers[i]) + { + min_interval = i; + break; + } + } + if (min_interval < 0) + { + /* no pollers */ + if (timer) + { + ecore_timer_del(timer); + timer = NULL; + } + return; + } + interval_incr = (1 << min_interval); + interval = interval_incr * poll_interval; + /* we are at the tick callback - so no need to do inter-tick adjustments + * so we can fasttrack this as t -= last_tick in theory is 0.0 (though + * in practice it will be a very very very small value. also the tick + * callback will adjust the timer interval at the end anyway */ + if (at_tick) + { + if (!timer) + timer = ecore_timer_add(interval, _ecore_poller_cb_timer, NULL); + } + else + { + double t; + + if (!timer) + timer = ecore_timer_add(interval, _ecore_poller_cb_timer, NULL); + else + { + t = ecore_time_get(); + if (interval != poll_cur_interval) + { + t -= last_tick; /* time since we last ticked */ + /* delete the timer and reset it to tick off in the new + * time interval. at the tick this will be adjusted */ + ecore_timer_del(timer); + timer = ecore_timer_add(interval - t, + _ecore_poller_cb_timer, NULL); + } + } + } + poll_cur_interval = interval; +} + +static Eina_Bool +_ecore_poller_cb_timer(void *data __UNUSED__) +{ + int i; + Ecore_Poller *poller, *l; + int changes = 0; + + at_tick++; + last_tick = ecore_time_get(); + /* we have 16 counters - each increments every time the poller counter + * "ticks". it increments by the minimum interval (which can be 1, 2, 4, + * 7, 16 etc. up to 32768) */ + for (i = 0; i < 15; i++) + { + poller_counters[i] += interval_incr; + /* wrap back to 0 if we exceed out loop count for the counter */ + if (poller_counters[i] >= (1 << i)) poller_counters[i] = 0; + } + + just_added_poller = 0; + /* walk the pollers now */ + poller_walking++; + for (i = 0; i < 15; i++) + { + /* if the counter is @ 0 - this means that counter "went off" this + * tick interval, so run all pollers hooked to that counter */ + if (poller_counters[i] == 0) + { + EINA_INLIST_FOREACH(pollers[i], poller) + { + if (!poller->delete_me) + { + if (!poller->func(poller->data)) + { + if (!poller->delete_me) + { + poller->delete_me = 1; + poller_delete_count++; + } + } + } + } + } + } + poller_walking--; + + /* handle deletes afterwards */ + if (poller_delete_count > 0) + { + /* FIXME: walk all pollers and remove deleted ones */ + for (i = 0; i < 15; i++) + { + for (l = pollers[i]; l; ) + { + poller = l; + l = (Ecore_Poller *)EINA_INLIST_GET(l)->next; + if (poller->delete_me) + { + pollers[i] = (Ecore_Poller *)eina_inlist_remove(EINA_INLIST_GET(pollers[i]), EINA_INLIST_GET(poller)); + ecore_poller_mp_free(poller); + poller_delete_count--; + changes++; + if (poller_delete_count <= 0) break; + } + } + if (poller_delete_count <= 0) break; + } + } + /* if we deleted or added any pollers, then we need to re-evaluate our + * minimum poll interval */ + if ((changes > 0) || (just_added_poller > 0)) + _ecore_poller_next_tick_eval(); + + just_added_poller = 0; + poller_delete_count = 0; + + at_tick--; + + /* if the timer was deleted then there is no point returning 1 - ambiguous + * if we do as it implies keep running me" but we have been deleted + * anyway */ + if (!timer) return ECORE_CALLBACK_CANCEL; + + /* adjust interval */ + ecore_timer_interval_set(timer, poll_cur_interval); + return ECORE_CALLBACK_RENEW; +} + +EAPI void +ecore_poller_poll_interval_set(Ecore_Poller_Type type __UNUSED__, + double poll_time) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + poll_interval = poll_time; + _ecore_poller_next_tick_eval(); +} + +EAPI double +ecore_poller_poll_interval_get(Ecore_Poller_Type type __UNUSED__) +{ + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0.0); + return poll_interval; +} + +EAPI Ecore_Poller * +ecore_poller_add(Ecore_Poller_Type type __UNUSED__, + int interval, + Ecore_Task_Cb func, + const void *data) +{ + Ecore_Poller *poller; + int ibit; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + if (!func) return NULL; + if (interval < 1) interval = 1; + + poller = ecore_poller_calloc(1); + if (!poller) return NULL; + ECORE_MAGIC_SET(poller, ECORE_MAGIC_POLLER); + /* interval MUST be a power of 2, so enforce it */ + if (interval < 1) interval = 1; + ibit = -1; + while (interval != 0) + { + ibit++; + interval >>= 1; + } + /* only allow up to 32768 - i.e. ibit == 15, so limit it */ + if (ibit > 15) ibit = 15; + + poller->ibit = ibit; + poller->func = func; + poller->data = (void *)data; + pollers[poller->ibit] = (Ecore_Poller *)eina_inlist_prepend(EINA_INLIST_GET(pollers[poller->ibit]), EINA_INLIST_GET(poller)); + if (poller_walking) + just_added_poller++; + else + _ecore_poller_next_tick_eval(); + return poller; +} + +EAPI Eina_Bool +ecore_poller_poller_interval_set(Ecore_Poller *poller, + int interval) +{ + int ibit; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(EINA_FALSE); + if (!ECORE_MAGIC_CHECK(poller, ECORE_MAGIC_POLLER)) + { + ECORE_MAGIC_FAIL(poller, ECORE_MAGIC_POLLER, + "ecore_poller_poller_interval_set"); + return EINA_FALSE; + } + + /* interval MUST be a power of 2, so enforce it */ + if (interval < 1) interval = 1; + ibit = -1; + while (interval != 0) + { + ibit++; + interval >>= 1; + } + /* only allow up to 32768 - i.e. ibit == 15, so limit it */ + if (ibit > 15) ibit = 15; + /* if interval specified is the same as interval set, return true without wasting time */ + if (poller->ibit == ibit) + return EINA_TRUE; + pollers[poller->ibit] = (Ecore_Poller *)eina_inlist_remove(EINA_INLIST_GET(pollers[poller->ibit]), EINA_INLIST_GET(poller)); + poller->ibit = ibit; + pollers[poller->ibit] = (Ecore_Poller *)eina_inlist_prepend(EINA_INLIST_GET(pollers[poller->ibit]), EINA_INLIST_GET(poller)); + if (poller_walking) + just_added_poller++; + else + _ecore_poller_next_tick_eval(); + return EINA_TRUE; +} + +EAPI int +ecore_poller_poller_interval_get(Ecore_Poller *poller) +{ + int ibit, interval = 1; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0); + if (!ECORE_MAGIC_CHECK(poller, ECORE_MAGIC_POLLER)) + { + ECORE_MAGIC_FAIL(poller, ECORE_MAGIC_POLLER, + "ecore_poller_poller_interval_get"); + return 0; + } + + ibit = poller->ibit; + while (ibit != 0) + { + ibit--; + interval <<= 1; + } + return interval; +} + +EAPI void * +ecore_poller_del(Ecore_Poller *poller) +{ + void *data; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + if (!ECORE_MAGIC_CHECK(poller, ECORE_MAGIC_POLLER)) + { + ECORE_MAGIC_FAIL(poller, ECORE_MAGIC_POLLER, + "ecore_poller_del"); + return NULL; + } + /* we are walking the poller list - a bad idea to remove from it while + * walking it, so just flag it as delete_me and come back to it after + * the loop has finished */ + if (poller_walking > 0) + { + poller_delete_count++; + poller->delete_me = 1; + return poller->data; + } + /* not in loop so safe - delete immediately */ + data = poller->data; + pollers[poller->ibit] = (Ecore_Poller *)eina_inlist_remove(EINA_INLIST_GET(pollers[poller->ibit]), EINA_INLIST_GET(poller)); + ecore_poller_mp_free(poller); + _ecore_poller_next_tick_eval(); + return data; +} + +/** + * @} + */ + +void +_ecore_poller_shutdown(void) +{ + int i; + Ecore_Poller *poller; + + for (i = 0; i < 15; i++) + { + while ((poller = pollers[i])) + { + pollers[i] = (Ecore_Poller *)eina_inlist_remove(EINA_INLIST_GET(pollers[i]), EINA_INLIST_GET(pollers[i])); + ecore_poller_mp_free(poller); + } + } +} + diff --git a/src/lib/ecore/ecore_private.h b/src/lib/ecore/ecore_private.h new file mode 100644 index 0000000..d812e3a --- /dev/null +++ b/src/lib/ecore/ecore_private.h @@ -0,0 +1,380 @@ +#ifndef _ECORE_PRIVATE_H +#define _ECORE_PRIVATE_H + +#include + +extern int _ecore_log_dom; +#ifdef _ECORE_DEFAULT_LOG_DOM +# undef _ECORE_DEFAULT_LOG_DOM +#endif +#define _ECORE_DEFAULT_LOG_DOM _ecore_log_dom + +#ifdef ECORE_DEFAULT_LOG_COLOR +# undef ECORE_DEFAULT_LOG_COLOR +#endif +#define ECORE_DEFAULT_LOG_COLOR EINA_COLOR_BLUE + +#ifdef ERR +# undef ERR +#endif +#define ERR(...) EINA_LOG_DOM_ERR(_ECORE_DEFAULT_LOG_DOM, __VA_ARGS__) + +#ifdef DBG +# undef DBG +#endif +#define DBG(...) EINA_LOG_DOM_DBG(_ECORE_DEFAULT_LOG_DOM, __VA_ARGS__) + +#ifdef INF +# undef INF +#endif +#define INF(...) EINA_LOG_DOM_INFO(_ECORE_DEFAULT_LOG_DOM, __VA_ARGS__) + +#ifdef WRN +# undef WRN +#endif +#define WRN(...) EINA_LOG_DOM_WARN(_ECORE_DEFAULT_LOG_DOM, __VA_ARGS__) + +#ifdef CRIT +# undef CRIT +#endif +#define CRIT(...) EINA_LOG_DOM_CRIT(_ECORE_DEFAULT_LOG_DOM, __VA_ARGS__) + +#ifndef PATH_MAX +# define PATH_MAX 4096 +#endif + +#ifndef MIN +# define MIN(x, y) (((x) > (y)) ? (y) : (x)) +#endif + +#ifndef MAX +# define MAX(x, y) (((x) > (y)) ? (x) : (y)) +#endif + +#ifndef ABS +# define ABS(x) ((x) < 0 ? -(x) : (x)) +#endif + +#ifndef CLAMP +# define CLAMP(x, min, max) (((x) > (max)) ? (max) : (((x) < (min)) ? (min) : (x))) +#endif + +#define EVAS_FRAME_QUEUING 1 /* for test */ + +#define READBUFSIZ 65536 + +#define ECORE_MAGIC_NONE 0x1234fedc +#define ECORE_MAGIC_EXE 0xf7e812f5 +#define ECORE_MAGIC_TIMER 0xf7d713f4 +#define ECORE_MAGIC_IDLER 0xf7c614f3 +#define ECORE_MAGIC_IDLE_ENTERER 0xf7b515f2 +#define ECORE_MAGIC_IDLE_EXITER 0xf7601afd +#define ECORE_MAGIC_FD_HANDLER 0xf7a416f1 +#define ECORE_MAGIC_EVENT_HANDLER 0xf79317f0 +#define ECORE_MAGIC_EVENT_FILTER 0xf78218ff +#define ECORE_MAGIC_EVENT 0xf77119fe +#define ECORE_MAGIC_ANIMATOR 0xf7643ea5 +#define ECORE_MAGIC_POLLER 0xf7568127 +#define ECORE_MAGIC_PIPE 0xf7458226 +#define ECORE_MAGIC_WIN32_HANDLER 0xf7e8f1a3 +#define ECORE_MAGIC_JOB 0x76543210 + +typedef unsigned int Ecore_Magic; +#define ECORE_MAGIC Ecore_Magic __magic + +#define ECORE_MAGIC_SET(d, m) (d)->__magic = (m) +#define ECORE_MAGIC_CHECK(d, m) ((d) && ((d)->__magic == (m))) +#define ECORE_MAGIC_FAIL(d, m, fn) _ecore_magic_fail((d), (d) ? (d)->__magic : 0, (m), (fn)); + +/* undef the following, we want our version */ +#undef FREE +#define FREE(ptr) free(ptr); ptr = NULL; + +#undef IF_FREE +#define IF_FREE(ptr) if (ptr) free(ptr); ptr = NULL; + +#undef IF_FN_DEL +#define IF_FN_DEL(_fn, ptr) if (ptr) { _fn(ptr); ptr = NULL; } + +EAPI void +ecore_print_warning(const char *function, + const char *sparam); + +/* convenience macros for checking pointer parameters for non-NULL */ +#undef CHECK_PARAM_POINTER_RETURN +#define CHECK_PARAM_POINTER_RETURN(sparam, param, ret) \ + if (!(param)) \ + { \ + ecore_print_warning(__FUNCTION__, sparam); \ + return ret; \ + } + +#undef CHECK_PARAM_POINTER +#define CHECK_PARAM_POINTER(sparam, param) \ + if (!(param)) \ + { \ + ecore_print_warning(__FUNCTION__, sparam); \ + return; \ + } + +EAPI void _ecore_magic_fail(const void *d, + Ecore_Magic m, + Ecore_Magic req_m, + const char *fname); + +void _ecore_time_init(void); + +Ecore_Timer *_ecore_timer_loop_add(double in, + Ecore_Task_Cb func, + const void *data); +void *_ecore_timer_del(Ecore_Timer *timer); +void _ecore_timer_delay(Ecore_Timer *timer, + double add); +void _ecore_timer_shutdown(void); +void _ecore_timer_cleanup(void); +void _ecore_timer_enable_new(void); +double _ecore_timer_next_get(void); +void _ecore_timer_expired_timers_call(double when); +int _ecore_timers_exists(void); + +int _ecore_timer_expired_call(double when); + +void _ecore_idler_shutdown(void); +int _ecore_idler_all_call(void); +int _ecore_idler_exist(void); + +void _ecore_idle_enterer_shutdown(void); +void _ecore_idle_enterer_call(void); +int _ecore_idle_enterer_exist(void); + +void _ecore_idle_exiter_shutdown(void); +void _ecore_idle_exiter_call(void); +int _ecore_idle_exiter_exist(void); + +void _ecore_event_shutdown(void); +int _ecore_event_exist(void); +Ecore_Event *_ecore_event_add(int type, + void *ev, + Ecore_End_Cb func_free, + void *data); +void _ecore_event_call(void); +void *_ecore_event_handler_del(Ecore_Event_Handler *event_handler); + +Ecore_Timer *_ecore_exe_doomsday_clock_get(Ecore_Exe *exe); +void _ecore_exe_doomsday_clock_set(Ecore_Exe *exe, + Ecore_Timer *dc); + +void *_ecore_event_signal_user_new(void); +void *_ecore_event_signal_hup_new(void); +void *_ecore_event_signal_exit_new(void); +void *_ecore_event_signal_power_new(void); +void *_ecore_event_signal_realtime_new(void); + +void *_ecore_main_fd_handler_del(Ecore_Fd_Handler *fd_handler); + +void _ecore_main_shutdown(void); + +#if defined (_WIN32) || defined (__lv2ppu__) || defined (HAVE_EXOTIC) +static inline void _ecore_signal_shutdown(void) { } + +static inline void _ecore_signal_init(void) { } + +static inline void _ecore_signal_received_process(void) { } + +static inline int _ecore_signal_count_get(void) { return 0; } + +static inline void _ecore_signal_call(void) { } + +#else +void _ecore_signal_shutdown(void); +void _ecore_signal_init(void); +void _ecore_signal_received_process(void); +int _ecore_signal_count_get(void); +void _ecore_signal_call(void); +#endif + +void _ecore_exe_init(void); +void _ecore_exe_shutdown(void); +#ifndef _WIN32 +Ecore_Exe *_ecore_exe_find(pid_t pid); +void *_ecore_exe_event_del_new(void); +void _ecore_exe_event_del_free(void *data, + void *ev); +#endif + +void _ecore_animator_shutdown(void); + +void _ecore_poller_shutdown(void); + +void _ecore_fps_debug_init(void); +void _ecore_fps_debug_shutdown(void); +void _ecore_fps_debug_runtime_add(double t); + +void _ecore_thread_init(void); +void _ecore_thread_shutdown(void); + +void _ecore_glib_init(void); +void _ecore_glib_shutdown(void); + +void _ecore_job_init(void); +void _ecore_job_shutdown(void); + +void _ecore_main_loop_init(void); +void _ecore_main_loop_shutdown(void); + +void _ecore_throttle(void); + +void _ecore_main_call_flush(void); + +extern int _ecore_main_lock_count; +extern Eina_Lock _ecore_main_loop_lock; + +static inline void +_ecore_lock(void) +{ +#ifdef HAVE_THREAD_SAFETY + eina_lock_take(&_ecore_main_loop_lock); +#else + /* at least check we're not being called from a thread */ + EINA_MAIN_LOOP_CHECK_RETURN; +#endif + _ecore_main_lock_count++; + /* assert(_ecore_main_lock_count == 1); */ +} + +static inline void +_ecore_unlock(void) +{ + _ecore_main_lock_count--; + /* assert(_ecore_main_lock_count == 0); */ +#ifdef HAVE_THREAD_SAFETY + eina_lock_release(&_ecore_main_loop_lock); +#endif +} + +/* + * Callback wrappers all assume that ecore _ecore_lock has been called + */ +static inline Eina_Bool +_ecore_call_task_cb(Ecore_Task_Cb func, + void *data) +{ + Eina_Bool r; + + _ecore_unlock(); + r = func(data); + _ecore_lock(); + + return r; +} + +static inline void * +_ecore_call_data_cb(Ecore_Data_Cb func, + void *data) +{ + void *r; + + _ecore_unlock(); + r = func(data); + _ecore_lock(); + + return r; +} + +static inline void +_ecore_call_end_cb(Ecore_End_Cb func, + void *user_data, + void *func_data) +{ + _ecore_unlock(); + func(user_data, func_data); + _ecore_lock(); +} + +static inline Eina_Bool +_ecore_call_filter_cb(Ecore_Filter_Cb func, + void *data, + void *loop_data, + int type, + void *event) +{ + Eina_Bool r; + + _ecore_unlock(); + r = func(data, loop_data, type, event); + _ecore_lock(); + + return r; +} + +static inline Eina_Bool +_ecore_call_handler_cb(Ecore_Event_Handler_Cb func, + void *data, + int type, + void *event) +{ + Eina_Bool r; + + _ecore_unlock(); + r = func(data, type, event); + _ecore_lock(); + + return r; +} + +static inline void +_ecore_call_prep_cb(Ecore_Fd_Prep_Cb func, + void *data, + Ecore_Fd_Handler *fd_handler) +{ + _ecore_unlock(); + func(data, fd_handler); + _ecore_lock(); +} + +static inline Eina_Bool +_ecore_call_fd_cb(Ecore_Fd_Cb func, + void *data, + Ecore_Fd_Handler *fd_handler) +{ + Eina_Bool r; + + _ecore_unlock(); + r = func(data, fd_handler); + _ecore_lock(); + + return r; +} + +extern int _ecore_fps_debug; +extern double _ecore_time_loop_time; +extern Eina_Bool _ecore_glib_always_integrate; +extern Ecore_Select_Function main_loop_select; + +Eina_Bool ecore_mempool_init(void); +void ecore_mempool_shutdown(void); +#define GENERIC_ALLOC_FREE_HEADER(TYPE, Type) \ + TYPE *Type##_calloc(unsigned int); \ + void Type##_mp_free(TYPE *e); +#define GENERIC_ALLOC_SIZE_DECLARE(TYPE) \ + size_t _ecore_sizeof_##TYPE = sizeof (TYPE); + +GENERIC_ALLOC_FREE_HEADER(Ecore_Animator, ecore_animator); +GENERIC_ALLOC_FREE_HEADER(Ecore_Event_Handler, ecore_event_handler); +GENERIC_ALLOC_FREE_HEADER(Ecore_Event_Filter, ecore_event_filter); +GENERIC_ALLOC_FREE_HEADER(Ecore_Event, ecore_event); +GENERIC_ALLOC_FREE_HEADER(Ecore_Idle_Exiter, ecore_idle_exiter); +GENERIC_ALLOC_FREE_HEADER(Ecore_Idle_Enterer, ecore_idle_enterer); +GENERIC_ALLOC_FREE_HEADER(Ecore_Idler, ecore_idler); +GENERIC_ALLOC_FREE_HEADER(Ecore_Job, ecore_job); +GENERIC_ALLOC_FREE_HEADER(Ecore_Timer, ecore_timer); +GENERIC_ALLOC_FREE_HEADER(Ecore_Poller, ecore_poller); +GENERIC_ALLOC_FREE_HEADER(Ecore_Pipe, ecore_pipe); +GENERIC_ALLOC_FREE_HEADER(Ecore_Fd_Handler, ecore_fd_handler); +#ifdef _WIN32 +GENERIC_ALLOC_FREE_HEADER(Ecore_Win32_Handler, ecore_win32_handler); +#endif + +#undef GENERIC_ALLOC_FREE_HEADER + +#endif diff --git a/src/lib/ecore/ecore_signal.c b/src/lib/ecore/ecore_signal.c new file mode 100644 index 0000000..05fe3b7 --- /dev/null +++ b/src/lib/ecore/ecore_signal.c @@ -0,0 +1,594 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include + +#include "Ecore.h" +#include "ecore_private.h" + +/* make mono happy - this is evil though... */ +#undef SIGPWR +/* valgrind in some versions/setups uses SIGRT's... hmmm */ + +typedef void (*Signal_Handler)(int sig, siginfo_t *si, void *foo); + +static void _ecore_signal_callback_set(int sig, + Signal_Handler func); +static void _ecore_signal_callback_ignore(int sig, + siginfo_t *si, + void *foo); +static void _ecore_signal_callback_sigchld(int sig, + siginfo_t *si, + void *foo); +static void _ecore_signal_callback_sigusr1(int sig, + siginfo_t *si, + void *foo); +static void _ecore_signal_callback_sigusr2(int sig, + siginfo_t *si, + void *foo); +static void _ecore_signal_callback_sighup(int sig, + siginfo_t *si, + void *foo); +static void _ecore_signal_callback_sigquit(int sig, + siginfo_t *si, + void *foo); +static void _ecore_signal_callback_sigint(int sig, + siginfo_t *si, + void *foo); +static void _ecore_signal_callback_sigterm(int sig, + siginfo_t *si, + void *foo); +#ifdef SIGPWR +static void _ecore_signal_callback_sigpwr(int sig, + siginfo_t *si, + void *foo); +#endif + +static Eina_Bool _ecore_signal_exe_exit_delay(void *data); + +//#define MAXSIGQ 256 // 32k +#define MAXSIGQ 64 // 8k + +static volatile sig_atomic_t sig_count = 0; +static volatile sig_atomic_t sigchld_count = 0; +static volatile sig_atomic_t sigusr1_count = 0; +static volatile sig_atomic_t sigusr2_count = 0; +static volatile sig_atomic_t sighup_count = 0; +static volatile sig_atomic_t sigquit_count = 0; +static volatile sig_atomic_t sigint_count = 0; +static volatile sig_atomic_t sigterm_count = 0; +#ifdef SIGPWR +static volatile sig_atomic_t sigpwr_count = 0; +#endif + +static volatile siginfo_t sigchld_info[MAXSIGQ]; +static volatile siginfo_t sigusr1_info[MAXSIGQ]; +static volatile siginfo_t sigusr2_info[MAXSIGQ]; +static volatile siginfo_t sighup_info[MAXSIGQ]; +static volatile siginfo_t sigquit_info[MAXSIGQ]; +static volatile siginfo_t sigint_info[MAXSIGQ]; +static volatile siginfo_t sigterm_info[MAXSIGQ]; +#ifdef SIGPWR +static volatile siginfo_t sigpwr_info[MAXSIGQ]; +#endif + +void +_ecore_signal_shutdown(void) +{ + _ecore_signal_callback_set(SIGPIPE, (Signal_Handler)SIG_DFL); + _ecore_signal_callback_set(SIGALRM, (Signal_Handler)SIG_DFL); + _ecore_signal_callback_set(SIGCHLD, (Signal_Handler)SIG_DFL); + _ecore_signal_callback_set(SIGUSR1, (Signal_Handler)SIG_DFL); + _ecore_signal_callback_set(SIGUSR2, (Signal_Handler)SIG_DFL); + _ecore_signal_callback_set(SIGHUP, (Signal_Handler)SIG_DFL); + _ecore_signal_callback_set(SIGQUIT, (Signal_Handler)SIG_DFL); + _ecore_signal_callback_set(SIGINT, (Signal_Handler)SIG_DFL); + _ecore_signal_callback_set(SIGTERM, (Signal_Handler)SIG_DFL); +#ifdef SIGPWR + _ecore_signal_callback_set(SIGPWR, (Signal_Handler)SIG_DFL); + sigpwr_count = 0; +#endif + sigchld_count = 0; + sigusr1_count = 0; + sigusr2_count = 0; + sighup_count = 0; + sigquit_count = 0; + sigint_count = 0; + sigterm_count = 0; + sig_count = 0; +} + +void +_ecore_signal_init(void) +{ + _ecore_signal_callback_set(SIGPIPE, _ecore_signal_callback_ignore); + _ecore_signal_callback_set(SIGALRM, _ecore_signal_callback_ignore); + _ecore_signal_callback_set(SIGCHLD, _ecore_signal_callback_sigchld); + _ecore_signal_callback_set(SIGUSR1, _ecore_signal_callback_sigusr1); + _ecore_signal_callback_set(SIGUSR2, _ecore_signal_callback_sigusr2); + _ecore_signal_callback_set(SIGHUP, _ecore_signal_callback_sighup); + _ecore_signal_callback_set(SIGQUIT, _ecore_signal_callback_sigquit); + _ecore_signal_callback_set(SIGINT, _ecore_signal_callback_sigint); + _ecore_signal_callback_set(SIGTERM, _ecore_signal_callback_sigterm); +#ifdef SIGPWR + _ecore_signal_callback_set(SIGPWR, _ecore_signal_callback_sigpwr); +#endif +} + +void +_ecore_signal_received_process(void) +{ + while (_ecore_signal_count_get()) _ecore_signal_call(); +} + +int +_ecore_signal_count_get(void) +{ + return sig_count; +} + +static void +_ecore_signal_generic_free(void *data __UNUSED__, + void *event) +{ + free(event); +} + +void +_ecore_signal_call(void) +{ + volatile sig_atomic_t n; + sigset_t oldset, newset; + int tot; + + if (sig_count == 0) return; + sigemptyset(&newset); + sigaddset(&newset, SIGPIPE); + sigaddset(&newset, SIGALRM); + sigaddset(&newset, SIGCHLD); + sigaddset(&newset, SIGUSR1); + sigaddset(&newset, SIGUSR2); + sigaddset(&newset, SIGHUP); + sigaddset(&newset, SIGQUIT); + sigaddset(&newset, SIGINT); + sigaddset(&newset, SIGTERM); +#ifdef SIGPWR + sigaddset(&newset, SIGPWR); +#endif + sigprocmask(SIG_BLOCK, &newset, &oldset); + if (sigchld_count > MAXSIGQ) + WRN("%i SIGCHLD in queue. max queue size %i. losing " + "siginfo for extra signals.", sigchld_count, MAXSIGQ); + tot = sigchld_count + sigusr1_count + sigusr2_count + + sighup_count + sigquit_count + sigint_count + sigterm_count +#ifdef SIGPWR + + sigpwr_count +#endif + ; + + if (sig_count != tot) + { + ERR("sig_count (%i) != actual totals (%i) ", sig_count, tot); + sig_count = tot; + } + + for (n = 0; n < sigchld_count; n++) + { + pid_t pid; + int status; + + while ((pid = waitpid(-1, &status, WNOHANG)) > 0) + { + Ecore_Exe_Event_Del *e; + + /* FIXME: If this process is set respawn, respawn with a suitable backoff + * period for those that need too much respawning. + */ + e = _ecore_exe_event_del_new(); + if (e) + { + if (WIFEXITED(status)) + { + e->exit_code = WEXITSTATUS(status); + e->exited = 1; + } + else if (WIFSIGNALED(status)) + { + e->exit_signal = WTERMSIG(status); + e->signalled = 1; + } + e->pid = pid; + e->exe = _ecore_exe_find(pid); + + if ((n < MAXSIGQ) && (sigchld_info[n].si_signo)) + e->data = sigchld_info[n]; /* No need to clone this. */ + + if ((e->exe) && (ecore_exe_flags_get(e->exe) & (ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR))) + { + /* We want to report the Last Words of the exe, so delay this event. + * This is twice as relevant for stderr. + * There are three possibilities here - + * 1 There are no Last Words. + * 2 There are Last Words, they are not ready to be read. + * 3 There are Last Words, they are ready to be read. + * + * For 1 we don't want to delay, for 3 we want to delay. + * 2 is the problem. If we check for data now and there + * is none, then there is no way to differentiate 1 and 2. + * If we don't delay, we may loose data, but if we do delay, + * there may not be data and the exit event never gets sent. + * + * Any way you look at it, there has to be some time passed + * before the exit event gets sent. So the strategy here is + * to setup a timer event that will send the exit event after + * an arbitrary, but brief, time. + * + * This is probably paranoid, for the less paraniod, we could + * check to see for Last Words, and only delay if there are any. + * This has it's own set of problems. + */ + Ecore_Timer *doomsday_clock; + + doomsday_clock = _ecore_exe_doomsday_clock_get(e->exe); + IF_FN_DEL(ecore_timer_del, doomsday_clock); + _ecore_unlock(); + doomsday_clock = ecore_timer_add + (0.1, _ecore_signal_exe_exit_delay, e); + _ecore_lock(); + _ecore_exe_doomsday_clock_set(e->exe, doomsday_clock); + } + else + { + _ecore_event_add(ECORE_EXE_EVENT_DEL, e, + _ecore_exe_event_del_free, NULL); + } + } + } + sig_count--; + } + sigchld_count = 0; + + if (sigusr1_count > MAXSIGQ) + WRN("%i SIGUSR1 in queue. max queue size %i. losing " + "siginfo for extra signals.", sigusr1_count, MAXSIGQ); + for (n = 0; n < sigusr1_count; n++) + { + Ecore_Event_Signal_User *e; + + e = _ecore_event_signal_user_new(); + if (e) + { + e->number = 1; + + if ((n < MAXSIGQ) && (sigusr1_info[n].si_signo)) + e->data = sigusr1_info[n]; + + _ecore_event_add(ECORE_EVENT_SIGNAL_USER, e, + _ecore_signal_generic_free, NULL); + } + sig_count--; + } + sigusr1_count = 0; + + if (sigusr2_count > MAXSIGQ) + WRN("%i SIGUSR2 in queue. max queue size %i. losing " + "siginfo for extra signals.", sigusr2_count, MAXSIGQ); + for (n = 0; n < sigusr2_count; n++) + { + Ecore_Event_Signal_User *e; + + e = _ecore_event_signal_user_new(); + if (e) + { + e->number = 2; + + if ((n < MAXSIGQ) && (sigusr2_info[n].si_signo)) + e->data = sigusr2_info[n]; + + _ecore_event_add(ECORE_EVENT_SIGNAL_USER, e, + _ecore_signal_generic_free, NULL); + } + sig_count--; + } + sigusr2_count = 0; + + if (sighup_count > MAXSIGQ) + WRN("%i SIGHUP in queue. max queue size %i. losing " + "siginfo for extra signals.", sighup_count, MAXSIGQ); + for (n = 0; n < sighup_count; n++) + { + Ecore_Event_Signal_Hup *e; + + e = _ecore_event_signal_hup_new(); + if (e) + { + if ((n < MAXSIGQ) && (sighup_info[n].si_signo)) + e->data = sighup_info[n]; + + _ecore_event_add(ECORE_EVENT_SIGNAL_HUP, e, + _ecore_signal_generic_free, NULL); + } + sig_count--; + } + sighup_count = 0; + + if (sigquit_count > MAXSIGQ) + WRN("%i SIGQUIT in queue. max queue size %i. losing " + "siginfo for extra signals.", sigquit_count, MAXSIGQ); + for (n = 0; n < sigquit_count; n++) + { + Ecore_Event_Signal_Exit *e; + + e = _ecore_event_signal_exit_new(); + if (e) + { + e->quit = 1; + + if ((n < MAXSIGQ) && (sigquit_info[n].si_signo)) + e->data = sigquit_info[n]; + + _ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e, + _ecore_signal_generic_free, NULL); + } + sig_count--; + } + sigquit_count = 0; + + if (sigint_count > MAXSIGQ) + WRN("%i SIGINT in queue. max queue size %i. losing " + "siginfo for extra signals.", sigint_count, MAXSIGQ); + for (n = 0; n < sigint_count; n++) + { + Ecore_Event_Signal_Exit *e; + + e = _ecore_event_signal_exit_new(); + if (e) + { + e->interrupt = 1; + + if ((n < MAXSIGQ) && (sigint_info[n].si_signo)) + e->data = sigint_info[n]; + + _ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e, + _ecore_signal_generic_free, NULL); + } + sig_count--; + } + sigint_count = 0; + + if (sigterm_count > MAXSIGQ) + WRN("%i SIGTERM in queue. max queue size %i. losing " + "siginfo for extra signals.", sigterm_count, MAXSIGQ); + for (n = 0; n < sigterm_count; n++) + { + Ecore_Event_Signal_Exit *e; + + e = _ecore_event_signal_exit_new(); + if (e) + { + e->terminate = 1; + + if ((n < MAXSIGQ) && (sigterm_info[n].si_signo)) + e->data = sigterm_info[n]; + + _ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e, + _ecore_signal_generic_free, NULL); + } + sig_count--; + } + sigterm_count = 0; + +#ifdef SIGPWR + if (sigpwr_count > MAXSIGQ) + WRN("%i SIGPWR in queue. max queue size %i. losing " + "siginfo for extra signals.", sigpwr_count, MAXSIGQ); + for (n = 0; n < sigpwr_count; n++) + { + Ecore_Event_Signal_Power *e; + + e = _ecore_event_signal_power_new(); + if (e) + { + if ((n < MAXSIGQ) && (sigpwr_info[n].si_signo)) + e->data = sigpwr_info[n]; + + _ecore_event_add(ECORE_EVENT_SIGNAL_POWER, e, + _ecore_signal_generic_free, NULL); + } + sig_count--; + } + sigpwr_count = 0; +#endif + sig_count = 0; + + sigprocmask(SIG_SETMASK, &oldset, NULL); +} + +static void +_ecore_signal_callback_set(int sig, + Signal_Handler func) +{ + struct sigaction sa; + + sa.sa_sigaction = func; + sa.sa_flags = SA_RESTART | SA_SIGINFO; + sigemptyset(&sa.sa_mask); + sigaction(sig, &sa, NULL); +} + +static void +_ecore_signal_callback_ignore(int sig __UNUSED__, + siginfo_t *si __UNUSED__, + void *foo __UNUSED__) +{ +} + +static void +_ecore_signal_callback_sigchld(int sig __UNUSED__, + siginfo_t *si, + void *foo __UNUSED__) +{ + volatile sig_atomic_t n; + n = sigchld_count; + if (n < MAXSIGQ) + { + if (si) + sigchld_info[n] = *si; + else + sigchld_info[n].si_signo = 0; + } + + sigchld_count++; + sig_count++; +} + +static void +_ecore_signal_callback_sigusr1(int sig __UNUSED__, + siginfo_t *si, + void *foo __UNUSED__) +{ + volatile sig_atomic_t n; + n = sigusr1_count; + if (n < MAXSIGQ) + { + if (si) + sigusr1_info[n] = *si; + else + sigusr1_info[n].si_signo = 0; + } + sigusr1_count++; + sig_count++; +} + +static void +_ecore_signal_callback_sigusr2(int sig __UNUSED__, + siginfo_t *si, + void *foo __UNUSED__) +{ + volatile sig_atomic_t n; + n = sigusr2_count; + if (n < MAXSIGQ) + { + if (si) + sigusr2_info[n] = *si; + else + sigusr2_info[n].si_signo = 0; + } + sigusr2_count++; + sig_count++; +} + +static void +_ecore_signal_callback_sighup(int sig __UNUSED__, + siginfo_t *si, + void *foo __UNUSED__) +{ + volatile sig_atomic_t n; + n = sighup_count; + if (n < MAXSIGQ) + { + if (si) + sighup_info[n] = *si; + else + sighup_info[n].si_signo = 0; + } + sighup_count++; + sig_count++; +} + +static void +_ecore_signal_callback_sigquit(int sig __UNUSED__, + siginfo_t *si, + void *foo __UNUSED__) +{ + volatile sig_atomic_t n; + n = sigquit_count; + if (n < MAXSIGQ) + { + if (si) + sigquit_info[n] = *si; + else + sigquit_info[n].si_signo = 0; + } + sigquit_count++; + sig_count++; +} + +static void +_ecore_signal_callback_sigint(int sig __UNUSED__, + siginfo_t *si, + void *foo __UNUSED__) +{ + volatile sig_atomic_t n; + n = sigint_count; + if (n < MAXSIGQ) + { + if (si) + sigint_info[n] = *si; + else + sigint_info[n].si_signo = 0; + } + sigint_count++; + sig_count++; +} + +static void +_ecore_signal_callback_sigterm(int sig __UNUSED__, + siginfo_t *si, + void *foo __UNUSED__) +{ + volatile sig_atomic_t n; + n = sigterm_count; + if (n < MAXSIGQ) + { + if (si) + sigterm_info[n] = *si; + else + sigterm_info[n].si_signo = 0; + } + sigterm_count++; + sig_count++; +} + +#ifdef SIGPWR +static void +_ecore_signal_callback_sigpwr(int sig __UNUSED__, + siginfo_t *si, + void *foo __UNUSED__) +{ + volatile sig_atomic_t n; + n = sigpwr_count; + if (n < MAXSIGQ) + { + if (si) + sigpwr_info[n] = *si; + else + sigpwr_info[n].si_signo = 0; + } + sigpwr_count++; + sig_count++; +} + +#endif + +static Eina_Bool +_ecore_signal_exe_exit_delay(void *data) +{ + Ecore_Exe_Event_Del *e; + + e = data; + if (e) + { + _ecore_exe_doomsday_clock_set(e->exe, NULL); + _ecore_event_add(ECORE_EXE_EVENT_DEL, e, + _ecore_exe_event_del_free, NULL); + } + return ECORE_CALLBACK_CANCEL; +} + diff --git a/src/lib/ecore/ecore_thread.c b/src/lib/ecore/ecore_thread.c new file mode 100644 index 0000000..87688ed --- /dev/null +++ b/src/lib/ecore/ecore_thread.c @@ -0,0 +1,1611 @@ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#ifdef HAVE_EVIL +# include +#endif + +#include "Ecore.h" +#include "ecore_private.h" + +#ifdef EFL_HAVE_THREADS + +# define LK(x) Eina_Lock x +# define LKI(x) eina_lock_new(&(x)) +# define LKD(x) eina_lock_free(&(x)) +# define LKL(x) eina_lock_take(&(x)) +# define LKU(x) eina_lock_release(&(x)) + +# define CD(x) Eina_Condition x +# define CDI(x, m) eina_condition_new(&(x), &(m)) +# define CDD(x) eina_condition_free(&(x)) +# define CDB(x) eina_condition_broadcast(&(x)) +# define CDW(x, t) eina_condition_timedwait(&(x), t) + +# define LRWK(x) Eina_RWLock x +# define LRWKI(x) eina_rwlock_new(&(x)); +# define LRWKD(x) eina_rwlock_free(&(x)); +# define LRWKWL(x) eina_rwlock_take_write(&(x)); +# define LRWKRL(x) eina_rwlock_take_read(&(x)); +# define LRWKU(x) eina_rwlock_release(&(x)); + +# ifdef EFL_HAVE_POSIX_THREADS +# include +# ifdef __linux__ +# include +# include +# include +# include +# include +# endif + +# define PH(x) pthread_t x +# define PHE(x, y) pthread_equal(x, y) +# define PHS() pthread_self() +# define PHC(x, f, d) pthread_create(&(x), NULL, (void *)f, d) +# define PHJ(x) pthread_join(x, NULL) +# define PHA(x) pthread_cancel(x) + +# else /* EFL_HAVE_WIN32_THREADS */ + +# define WIN32_LEAN_AND_MEAN +# include +# undef WIN32_LEAN_AND_MEAN + +typedef struct +{ + HANDLE thread; + void *val; +} win32_thread; + +static Eina_List *_ecore_thread_win32_threads = NULL; +static Eina_Lock _ecore_thread_win32_lock; + +# define PH(x) win32_thread * x +# define PHE(x, y) ((x) == (y)) + +static win32_thread * +_ecore_thread_win32_self() +{ + win32_thread *t; + Eina_List *l; + + LKL(_ecore_thread_win32_lock); + EINA_LIST_FOREACH(_ecore_thread_win32_threads, l, t) + if (t->thread == GetCurrentThread()) + { + LKU(_ecore_thread_win32_lock); + return t; + } + + LKU(_ecore_thread_win32_lock); + return NULL; +} + +# define PHS() _ecore_thread_win32_self() + +static int +_ecore_thread_win32_create(win32_thread **x, + LPTHREAD_START_ROUTINE f, + void *d) +{ + win32_thread *t; + + t = (win32_thread *)calloc(1, sizeof(win32_thread)); + if (!t) + return -1; + + LKL(_ecore_thread_win32_lock); + (t)->thread = CreateThread(NULL, 0, f, d, 0, NULL); + if (!t->thread) + { + free(t); + LKU(_ecore_thread_win32_lock); + return -1; + } + t->val = d; + *x = t; + _ecore_thread_win32_threads = eina_list_append(_ecore_thread_win32_threads, t); + LKU(_ecore_thread_win32_lock); + + return 0; +} + +# define PHC(x, f, d) _ecore_thread_win32_create(&(x), (LPTHREAD_START_ROUTINE)f, d) + +static int +_ecore_thread_win32_join(win32_thread *x, + void **res) +{ + if (!PHE(x, PHS())) + { + WaitForSingleObject(x->thread, INFINITE); + CloseHandle(x->thread); + } + if (res) *res = x->val; + _ecore_thread_win32_threads = eina_list_remove(_ecore_thread_win32_threads, x); + free(x); + + return 0; +} + +# define PHJ(x) _ecore_thread_win32_join(x, NULL) +# define PHA(x) TerminateThread(x->thread, 0) + +# endif + +#endif + +typedef struct _Ecore_Pthread_Worker Ecore_Pthread_Worker; +typedef struct _Ecore_Pthread Ecore_Pthread; +typedef struct _Ecore_Thread_Data Ecore_Thread_Data; + +struct _Ecore_Thread_Data +{ + void *data; + Eina_Free_Cb cb; +}; + +struct _Ecore_Pthread_Worker +{ + union { + struct + { + Ecore_Thread_Cb func_blocking; + } short_run; + struct + { + Ecore_Thread_Cb func_heavy; + Ecore_Thread_Notify_Cb func_notify; + + Ecore_Pthread_Worker *direct_worker; + + int send; + int received; + } feedback_run; + struct { + Ecore_Thread_Cb func_main; + Ecore_Thread_Notify_Cb func_notify; + + Ecore_Pipe *send; + Ecore_Pthread_Worker *direct_worker; + + struct { + int send; + int received; + } from, to; + } message_run; + } u; + + Ecore_Thread_Cb func_cancel; + Ecore_Thread_Cb func_end; +#ifdef EFL_HAVE_THREADS + PH(self); + Eina_Hash *hash; + CD(cond); + LK(mutex); +#endif + + const void *data; + + int cancel; + +#ifdef EFL_HAVE_THREADS + LK(cancel_mutex); +#endif + + Eina_Bool message_run : 1; + Eina_Bool feedback_run : 1; + Eina_Bool kill : 1; + Eina_Bool reschedule : 1; + Eina_Bool no_queue : 1; +}; + +#ifdef EFL_HAVE_THREADS +typedef struct _Ecore_Pthread_Notify Ecore_Pthread_Notify; +struct _Ecore_Pthread_Notify +{ + Ecore_Pthread_Worker *work; + const void *user_data; +}; + +typedef void *(*Ecore_Thread_Sync_Cb)(void* data, Ecore_Thread *thread); + +typedef struct _Ecore_Pthread_Message Ecore_Pthread_Message; +struct _Ecore_Pthread_Message +{ + union { + Ecore_Thread_Cb async; + Ecore_Thread_Sync_Cb sync; + } u; + + const void *data; + + int code; + + Eina_Bool callback : 1; + Eina_Bool sync : 1; +}; + +#endif + +static int _ecore_thread_count_max = 0; + +#ifdef EFL_HAVE_THREADS + +static void _ecore_thread_handler(void *data); + +static int _ecore_thread_count = 0; + +static Eina_List *_ecore_running_job = NULL; +static Eina_List *_ecore_pending_job_threads = NULL; +static Eina_List *_ecore_pending_job_threads_feedback = NULL; +static LK(_ecore_pending_job_threads_mutex); +static LK(_ecore_running_job_mutex); + +static Eina_Hash *_ecore_thread_global_hash = NULL; +static LRWK(_ecore_thread_global_hash_lock); +static LK(_ecore_thread_global_hash_mutex); +static CD(_ecore_thread_global_hash_cond); + +static Eina_Bool have_main_loop_thread = 0; + +static Eina_Trash *_ecore_thread_worker_trash = NULL; +static int _ecore_thread_worker_count = 0; + +static void *_ecore_thread_worker(void *); +static Ecore_Pthread_Worker *_ecore_thread_worker_new(void); + +static PH(get_main_loop_thread) (void) +{ + static PH(main_loop_thread); + static pid_t main_loop_pid; + pid_t pid = getpid(); + + if (pid != main_loop_pid) + { + main_loop_pid = pid; + main_loop_thread = PHS(); + have_main_loop_thread = 1; + } + + return main_loop_thread; +} + +static void +_ecore_thread_worker_free(Ecore_Pthread_Worker *worker) +{ + LKD(worker->cancel_mutex); + CDD(worker->cond); + LKD(worker->mutex); + + if (_ecore_thread_worker_count > ((_ecore_thread_count_max + 1) * 16)) + { + _ecore_thread_worker_count--; + free(worker); + return; + } + + eina_trash_push(&_ecore_thread_worker_trash, worker); +} + +static void +_ecore_thread_data_free(void *data) +{ + Ecore_Thread_Data *d = data; + + if (d->cb) d->cb(d->data); + free(d); +} + +static void +_ecore_thread_join(PH(thread)) +{ + PHJ(thread); +} + +static void +_ecore_thread_kill(Ecore_Pthread_Worker *work) +{ + if (work->cancel) + { + if (work->func_cancel) + work->func_cancel((void *)work->data, (Ecore_Thread *)work); + } + else + { + if (work->func_end) + work->func_end((void *)work->data, (Ecore_Thread *)work); + } + + if (work->feedback_run) + { + if (work->u.feedback_run.direct_worker) + _ecore_thread_worker_free(work->u.feedback_run.direct_worker); + } + if (work->hash) + eina_hash_free(work->hash); + _ecore_thread_worker_free(work); +} + +static void +_ecore_thread_handler(void *data) +{ + Ecore_Pthread_Worker *work = data; + + if (work->feedback_run) + { + if (work->u.feedback_run.send != work->u.feedback_run.received) + { + work->kill = EINA_TRUE; + return; + } + } + + _ecore_thread_kill(work); +} + +#if 0 +static void +_ecore_nothing_handler(void *data __UNUSED__, void *buffer __UNUSED__, unsigned int nbyte __UNUSED__) +{ +} +#endif + +static void +_ecore_notify_handler(void *data) +{ + Ecore_Pthread_Notify *notify = data; + Ecore_Pthread_Worker *work = notify->work; + void *user_data = (void*) notify->user_data; + + work->u.feedback_run.received++; + + if (work->u.feedback_run.func_notify) + work->u.feedback_run.func_notify((void *)work->data, (Ecore_Thread *)work, user_data); + + /* Force reading all notify event before killing the thread */ + if (work->kill && work->u.feedback_run.send == work->u.feedback_run.received) + { + _ecore_thread_kill(work); + } + + free(notify); +} + +static void +_ecore_message_notify_handler(void *data) +{ + Ecore_Pthread_Notify *notify = data; + Ecore_Pthread_Worker *work = notify->work; + Ecore_Pthread_Message *user_data = (void *) notify->user_data; + Eina_Bool delete = EINA_TRUE; + + work->u.message_run.from.received++; + + if (!user_data->callback) + { + if (work->u.message_run.func_notify) + work->u.message_run.func_notify((void *) work->data, (Ecore_Thread *) work, (void *) user_data->data); + } + else + { + if (user_data->sync) + { + user_data->data = user_data->u.sync((void*) user_data->data, (Ecore_Thread *) work); + user_data->callback = EINA_FALSE; + user_data->code = INT_MAX; + ecore_pipe_write(work->u.message_run.send, &user_data, sizeof (Ecore_Pthread_Message *)); + + delete = EINA_FALSE; + } + else + { + user_data->u.async((void*) user_data->data, (Ecore_Thread *) work); + } + } + + if (delete) + { + free(user_data); + } + + /* Force reading all notify event before killing the thread */ + if (work->kill && work->u.message_run.from.send == work->u.message_run.from.received) + { + _ecore_thread_kill(work); + } + free(notify); +} + +static void +_ecore_short_job(PH(thread)) +{ + Ecore_Pthread_Worker *work; + int cancel; + + LKL(_ecore_pending_job_threads_mutex); + + if (!_ecore_pending_job_threads) + { + LKU(_ecore_pending_job_threads_mutex); + return; + } + + work = eina_list_data_get(_ecore_pending_job_threads); + _ecore_pending_job_threads = eina_list_remove_list(_ecore_pending_job_threads, + _ecore_pending_job_threads); + LKU(_ecore_pending_job_threads_mutex); + + LKL(_ecore_running_job_mutex); + _ecore_running_job = eina_list_append(_ecore_running_job, work); + LKU(_ecore_running_job_mutex); + + LKL(work->cancel_mutex); + cancel = work->cancel; + LKU(work->cancel_mutex); + work->self = thread; + if (!cancel) + work->u.short_run.func_blocking((void *) work->data, (Ecore_Thread*) work); + + LKL(_ecore_running_job_mutex); + _ecore_running_job = eina_list_remove(_ecore_running_job, work); + LKU(_ecore_running_job_mutex); + + if (work->reschedule) + { + work->reschedule = EINA_FALSE; + + LKL(_ecore_pending_job_threads_mutex); + _ecore_pending_job_threads = eina_list_append(_ecore_pending_job_threads, work); + LKU(_ecore_pending_job_threads_mutex); + } + else + { + ecore_main_loop_thread_safe_call_async(_ecore_thread_handler, work); + } +} + +static void +_ecore_feedback_job(PH(thread)) +{ + Ecore_Pthread_Worker *work; + int cancel; + + LKL(_ecore_pending_job_threads_mutex); + + if (!_ecore_pending_job_threads_feedback) + { + LKU(_ecore_pending_job_threads_mutex); + return; + } + + work = eina_list_data_get(_ecore_pending_job_threads_feedback); + _ecore_pending_job_threads_feedback = eina_list_remove_list(_ecore_pending_job_threads_feedback, + _ecore_pending_job_threads_feedback); + LKU(_ecore_pending_job_threads_mutex); + LKL(_ecore_running_job_mutex); + _ecore_running_job = eina_list_append(_ecore_running_job, work); + LKU(_ecore_running_job_mutex); + + LKL(work->cancel_mutex); + cancel = work->cancel; + LKU(work->cancel_mutex); + work->self = thread; + if (!cancel) + work->u.feedback_run.func_heavy((void *) work->data, (Ecore_Thread *) work); + + LKL(_ecore_running_job_mutex); + _ecore_running_job = eina_list_remove(_ecore_running_job, work); + LKU(_ecore_running_job_mutex); + + if (work->reschedule) + { + work->reschedule = EINA_FALSE; + + LKL(_ecore_pending_job_threads_mutex); + _ecore_pending_job_threads_feedback = eina_list_append(_ecore_pending_job_threads_feedback, work); + LKU(_ecore_pending_job_threads_mutex); + } + else + { + ecore_main_loop_thread_safe_call_async(_ecore_thread_handler, work); + } +} + +static void * +_ecore_direct_worker(Ecore_Pthread_Worker *work) +{ +#ifdef EFL_POSIX_THREADS + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); +#endif + + eina_sched_prio_drop(); + + work->self = PHS(); + if (work->message_run) + work->u.message_run.func_main((void *) work->data, (Ecore_Thread *) work); + else + work->u.feedback_run.func_heavy((void *) work->data, (Ecore_Thread *) work); + + ecore_main_loop_thread_safe_call_async(_ecore_thread_handler, work); + + ecore_main_loop_thread_safe_call_async((Ecore_Cb) _ecore_thread_join, + (void*) PHS()); + + return NULL; +} + +static void * +_ecore_thread_worker(void *data __UNUSED__) +{ +#ifdef EFL_POSIX_THREADS + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); +#endif + + eina_sched_prio_drop(); + +restart: + _ecore_short_job(PHS()); + _ecore_feedback_job(PHS()); + + /* FIXME: Check if there is feedback running task todo, and switch to feedback run handler. */ + + LKL(_ecore_pending_job_threads_mutex); + if (_ecore_pending_job_threads || _ecore_pending_job_threads_feedback) + { + LKU(_ecore_pending_job_threads_mutex); + goto restart; + } + LKU(_ecore_pending_job_threads_mutex); + + /* Sleep a little to prevent premature death */ +#ifdef _WIN32 + Sleep(1); /* around 50ms */ +#else + usleep(50); +#endif + + LKL(_ecore_pending_job_threads_mutex); + if (_ecore_pending_job_threads || _ecore_pending_job_threads_feedback) + { + LKU(_ecore_pending_job_threads_mutex); + goto restart; + } + _ecore_thread_count--; + + ecore_main_loop_thread_safe_call_async((Ecore_Cb) _ecore_thread_join, + (void*) PHS()); + LKU(_ecore_pending_job_threads_mutex); + + return NULL; +} + +#endif + +static Ecore_Pthread_Worker * +_ecore_thread_worker_new(void) +{ +#ifdef EFL_HAVE_THREADS + Ecore_Pthread_Worker *result; + + result = eina_trash_pop(&_ecore_thread_worker_trash); + + if (!result) + { + result = calloc(1, sizeof(Ecore_Pthread_Worker)); + _ecore_thread_worker_count++; + } + + LKI(result->cancel_mutex); + LKI(result->mutex); + CDI(result->cond, result->mutex); + + return result; +#else + return malloc(sizeof (Ecore_Pthread_Worker)); +#endif +} + +void +_ecore_thread_init(void) +{ + _ecore_thread_count_max = eina_cpu_count(); + if (_ecore_thread_count_max <= 0) + _ecore_thread_count_max = 1; + +#ifdef EFL_HAVE_THREADS +# ifdef EFL_HAVE_WIN32_THREADS + LKI(_ecore_thread_win32_lock); +# endif + LKI(_ecore_pending_job_threads_mutex); + LRWKI(_ecore_thread_global_hash_lock); + LKI(_ecore_thread_global_hash_mutex); + LKI(_ecore_running_job_mutex); + CDI(_ecore_thread_global_hash_cond, _ecore_thread_global_hash_mutex); +#endif +} + +void +_ecore_thread_shutdown(void) +{ + /* FIXME: If function are still running in the background, should we kill them ? */ +#ifdef EFL_HAVE_THREADS + Ecore_Pthread_Worker *work; + Eina_List *l; + Eina_Bool test; + int iteration = 0; + + LKL(_ecore_pending_job_threads_mutex); + + EINA_LIST_FREE(_ecore_pending_job_threads, work) + { + if (work->func_cancel) + work->func_cancel((void *)work->data, (Ecore_Thread *) work); + free(work); + } + + EINA_LIST_FREE(_ecore_pending_job_threads_feedback, work) + { + if (work->func_cancel) + work->func_cancel((void *)work->data, (Ecore_Thread *) work); + free(work); + } + + LKU(_ecore_pending_job_threads_mutex); + LKL(_ecore_running_job_mutex); + + EINA_LIST_FOREACH(_ecore_running_job, l, work) + ecore_thread_cancel((Ecore_Thread*) work); + + LKU(_ecore_running_job_mutex); + + do + { + LKL(_ecore_pending_job_threads_mutex); + if (_ecore_thread_count > 0) + { + test = EINA_TRUE; + } + else + { + test = EINA_FALSE; + } + LKU(_ecore_pending_job_threads_mutex); + iteration++; + if (test) usleep(50000); + } + while (test == EINA_TRUE && iteration < 20); + + if (iteration == 20 && _ecore_thread_count > 0) + { + ERR("%i of the child thread are still running after 1s. This can lead to a segv. Sorry.", _ecore_thread_count); + } + + if (_ecore_thread_global_hash) + eina_hash_free(_ecore_thread_global_hash); + have_main_loop_thread = 0; + + while ((work = eina_trash_pop(&_ecore_thread_worker_trash))) + { + free(work); + } + + LKD(_ecore_pending_job_threads_mutex); + LRWKD(_ecore_thread_global_hash_lock); + LKD(_ecore_thread_global_hash_mutex); + LKD(_ecore_running_job_mutex); + CDD(_ecore_thread_global_hash_cond); +# ifdef EFL_HAVE_WIN32_THREADS + LKU(_ecore_thread_win32_lock); +# endif +#endif +} + +EAPI Ecore_Thread * +ecore_thread_run(Ecore_Thread_Cb func_blocking, + Ecore_Thread_Cb func_end, + Ecore_Thread_Cb func_cancel, + const void *data) +{ + Ecore_Pthread_Worker *work; + Eina_Bool tried = EINA_FALSE; +#ifdef EFL_HAVE_THREADS + PH(thread); +#endif + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + + if (!func_blocking) return NULL; + + work = _ecore_thread_worker_new(); + if (!work) + { + if (func_cancel) + func_cancel((void *)data, NULL); + return NULL; + } + + work->u.short_run.func_blocking = func_blocking; + work->func_end = func_end; + work->func_cancel = func_cancel; + work->cancel = EINA_FALSE; + work->feedback_run = EINA_FALSE; + work->message_run = EINA_FALSE; + work->kill = EINA_FALSE; + work->reschedule = EINA_FALSE; + work->no_queue = EINA_FALSE; + work->data = data; + +#ifdef EFL_HAVE_THREADS + work->self = 0; + work->hash = NULL; + + LKL(_ecore_pending_job_threads_mutex); + _ecore_pending_job_threads = eina_list_append(_ecore_pending_job_threads, work); + + if (_ecore_thread_count == _ecore_thread_count_max) + { + LKU(_ecore_pending_job_threads_mutex); + return (Ecore_Thread *)work; + } + + LKU(_ecore_pending_job_threads_mutex); + + /* One more thread could be created. */ + eina_threads_init(); + + LKL(_ecore_pending_job_threads_mutex); + + retry: + if (PHC(thread, _ecore_thread_worker, NULL) == 0) + { + _ecore_thread_count++; + LKU(_ecore_pending_job_threads_mutex); + return (Ecore_Thread *)work; + } + if (!tried) + { + _ecore_main_call_flush(); + tried = EINA_TRUE; + goto retry; + } + + if (_ecore_thread_count == 0) + { + _ecore_pending_job_threads = eina_list_remove(_ecore_pending_job_threads, work); + + if (work->func_cancel) + work->func_cancel((void *) work->data, (Ecore_Thread *) work); + + CDD(work->cond); + LKD(work->mutex); + LKD(work->cancel_mutex); + free(work); + work = NULL; + } + LKU(_ecore_pending_job_threads_mutex); + + eina_threads_shutdown(); + + return (Ecore_Thread *)work; +#else + /* + If no thread and as we don't want to break app that rely on this + facility, we will lock the interface until we are done. + */ + do { + /* Handle reschedule by forcing it here. That would mean locking the app, + * would be better with an idler, but really to complex for a case where + * thread should really exist. + */ + work->reschedule = EINA_FALSE; + + func_blocking((void *)data, (Ecore_Thread *)work); + if (work->cancel == EINA_FALSE) func_end((void *)data, (Ecore_Thread *)work); + else func_cancel((void *)data, (Ecore_Thread *)work); + } while (work->reschedule == EINA_TRUE); + + free(work); + + return NULL; +#endif +} + +EAPI Eina_Bool +ecore_thread_cancel(Ecore_Thread *thread) +{ +#ifdef EFL_HAVE_THREADS + Ecore_Pthread_Worker *volatile work = (Ecore_Pthread_Worker *)thread; + Eina_List *l; + int cancel; + + if (!work) + return EINA_TRUE; + LKL(work->cancel_mutex); + cancel = work->cancel; + LKU(work->cancel_mutex); + if (cancel) + return EINA_FALSE; + + if (work->feedback_run) + { + if (work->kill) + return EINA_TRUE; + if (work->u.feedback_run.send != work->u.feedback_run.received) + goto on_exit; + } + + LKL(_ecore_pending_job_threads_mutex); + + if ((have_main_loop_thread) && + (PHE(get_main_loop_thread(), PHS()))) + { + if (!work->feedback_run) + EINA_LIST_FOREACH(_ecore_pending_job_threads, l, work) + { + if ((void *)work == (void *)thread) + { + _ecore_pending_job_threads = eina_list_remove_list(_ecore_pending_job_threads, l); + + LKU(_ecore_pending_job_threads_mutex); + + if (work->func_cancel) + work->func_cancel((void *)work->data, (Ecore_Thread *)work); + free(work); + + return EINA_TRUE; + } + } + else + EINA_LIST_FOREACH(_ecore_pending_job_threads_feedback, l, work) + { + if ((void *)work == (void *)thread) + { + _ecore_pending_job_threads_feedback = eina_list_remove_list(_ecore_pending_job_threads_feedback, l); + + LKU(_ecore_pending_job_threads_mutex); + + if (work->func_cancel) + work->func_cancel((void *)work->data, (Ecore_Thread *)work); + free(work); + + return EINA_TRUE; + } + } + } + + LKU(_ecore_pending_job_threads_mutex); + + work = (Ecore_Pthread_Worker *)thread; + + /* Delay the destruction */ + on_exit: + LKL(work->cancel_mutex); + work->cancel = EINA_TRUE; + LKU(work->cancel_mutex); + + return EINA_FALSE; +#else + (void) thread; + return EINA_TRUE; +#endif +} + +EAPI Eina_Bool +ecore_thread_check(Ecore_Thread *thread) +{ + Ecore_Pthread_Worker *volatile worker = (Ecore_Pthread_Worker *) thread; + int cancel; + + if (!worker) return EINA_TRUE; +#ifdef EFL_HAVE_THREADS + LKL(worker->cancel_mutex); +#endif + cancel = worker->cancel; + /* FIXME: there is an insane bug driving me nuts here. I don't know if + it's a race condition, some cache issue or some alien attack on our software. + But ecore_thread_check will only work correctly with a printf, all the volatile, + lock and even usleep don't help here... */ + /* fprintf(stderr, "wc: %i\n", cancel); */ +#ifdef EFL_HAVE_THREADS + LKU(worker->cancel_mutex); +#endif + return cancel; +} + +EAPI Ecore_Thread * +ecore_thread_feedback_run(Ecore_Thread_Cb func_heavy, + Ecore_Thread_Notify_Cb func_notify, + Ecore_Thread_Cb func_end, + Ecore_Thread_Cb func_cancel, + const void *data, + Eina_Bool try_no_queue) +{ +#ifdef EFL_HAVE_THREADS + Ecore_Pthread_Worker *worker; + Eina_Bool tried = EINA_FALSE; + PH(thread); + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + + if (!func_heavy) return NULL; + + worker = _ecore_thread_worker_new(); + if (!worker) goto on_error; + + worker->u.feedback_run.func_heavy = func_heavy; + worker->u.feedback_run.func_notify = func_notify; + worker->hash = NULL; + worker->func_cancel = func_cancel; + worker->func_end = func_end; + worker->data = data; + worker->cancel = EINA_FALSE; + worker->message_run = EINA_FALSE; + worker->feedback_run = EINA_TRUE; + worker->kill = EINA_FALSE; + worker->reschedule = EINA_FALSE; + worker->self = 0; + + worker->u.feedback_run.send = 0; + worker->u.feedback_run.received = 0; + + worker->u.feedback_run.direct_worker = NULL; + + if (try_no_queue) + { + PH(t); + + worker->u.feedback_run.direct_worker = _ecore_thread_worker_new(); + worker->no_queue = EINA_TRUE; + + eina_threads_init(); + + retry_direct: + if (PHC(t, _ecore_direct_worker, worker) == 0) + return (Ecore_Thread *)worker; + if (!tried) + { + _ecore_main_call_flush(); + tried = EINA_TRUE; + goto retry_direct; + } + + if (worker->u.feedback_run.direct_worker) + { + _ecore_thread_worker_free(worker->u.feedback_run.direct_worker); + worker->u.feedback_run.direct_worker = NULL; + } + + eina_threads_shutdown(); + } + + worker->no_queue = EINA_FALSE; + + LKL(_ecore_pending_job_threads_mutex); + _ecore_pending_job_threads_feedback = eina_list_append(_ecore_pending_job_threads_feedback, worker); + + if (_ecore_thread_count == _ecore_thread_count_max) + { + LKU(_ecore_pending_job_threads_mutex); + return (Ecore_Thread *)worker; + } + + LKU(_ecore_pending_job_threads_mutex); + + /* One more thread could be created. */ + eina_threads_init(); + + LKL(_ecore_pending_job_threads_mutex); + retry: + if (PHC(thread, _ecore_thread_worker, NULL) == 0) + { + _ecore_thread_count++; + LKU(_ecore_pending_job_threads_mutex); + return (Ecore_Thread *)worker; + } + if (!tried) + { + _ecore_main_call_flush(); + tried = EINA_TRUE; + goto retry; + } + LKU(_ecore_pending_job_threads_mutex); + + eina_threads_shutdown(); + +on_error: + LKL(_ecore_pending_job_threads_mutex); + if (_ecore_thread_count == 0) + { + _ecore_pending_job_threads_feedback = eina_list_remove(_ecore_pending_job_threads_feedback, + worker); + + if (func_cancel) func_cancel((void *)data, NULL); + + if (worker) + { + CDD(worker->cond); + LKD(worker->mutex); + free(worker); + worker = NULL; + } + } + LKU(_ecore_pending_job_threads_mutex); + + return (Ecore_Thread *)worker; +#else + Ecore_Pthread_Worker worker; + + (void)try_no_queue; + + /* + If no thread and as we don't want to break app that rely on this + facility, we will lock the interface until we are done. + */ + worker.u.feedback_run.func_heavy = func_heavy; + worker.u.feedback_run.func_notify = func_notify; + worker.u.feedback_run.send = 0; + worker.u.feedback_run.received = 0; + worker.func_cancel = func_cancel; + worker.func_end = func_end; + worker.data = data; + worker.cancel = EINA_FALSE; + worker.feedback_run = EINA_TRUE; + worker.message_run = EINA_FALSE; + worker.kill = EINA_FALSE; + + do { + worker.reschedule = EINA_FALSE; + + func_heavy((void *)data, (Ecore_Thread *)&worker); + + if (worker.cancel) func_cancel((void *)data, (Ecore_Thread *)&worker); + else func_end((void *)data, (Ecore_Thread *)&worker); + } while (worker.reschedule == EINA_TRUE); + + return NULL; +#endif +} + +EAPI Eina_Bool +ecore_thread_feedback(Ecore_Thread *thread, + const void *data) +{ + Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *)thread; + + if (!worker) return EINA_FALSE; + +#ifdef EFL_HAVE_THREADS + if (!PHE(worker->self, PHS())) return EINA_FALSE; + + if (worker->feedback_run) + { + Ecore_Pthread_Notify *notify; + + notify = malloc(sizeof (Ecore_Pthread_Notify)); + if (!notify) return EINA_FALSE; + + notify->user_data = data; + notify->work = worker; + worker->u.feedback_run.send++; + + ecore_main_loop_thread_safe_call_async(_ecore_notify_handler, notify); + } + else if (worker->message_run) + { + Ecore_Pthread_Message *msg; + Ecore_Pthread_Notify *notify; + + msg = malloc(sizeof (Ecore_Pthread_Message*)); + if (!msg) return EINA_FALSE; + msg->data = data; + msg->callback = EINA_FALSE; + msg->sync = EINA_FALSE; + + notify = malloc(sizeof (Ecore_Pthread_Notify)); + if (!notify) + { + free(msg); + return EINA_FALSE; + } + notify->work = worker; + notify->user_data = msg; + + worker->u.message_run.from.send++; + ecore_main_loop_thread_safe_call_async(_ecore_message_notify_handler, notify); + } + else + return EINA_FALSE; + + return EINA_TRUE; +#else + worker->u.feedback_run.func_notify((void *)worker->data, thread, (void *)data); + + return EINA_TRUE; +#endif +} + +#if 0 +EAPI Ecore_Thread * +ecore_thread_message_run(Ecore_Thread_Cb func_main, + Ecore_Thread_Notify_Cb func_notify, + Ecore_Thread_Cb func_end, + Ecore_Thread_Cb func_cancel, + const void *data) +{ +#ifdef EFL_HAVE_THREADS + Ecore_Pthread_Worker *worker; + PH(t); + + if (!func_main) return NULL; + + worker = _ecore_thread_worker_new(); + if (!worker) return NULL; + + worker->u.message_run.func_main = func_main; + worker->u.message_run.func_notify = func_notify; + worker->u.message_run.direct_worker = _ecore_thread_worker_new(); + worker->u.message_run.send = ecore_pipe_add(_ecore_nothing_handler, worker); + worker->u.message_run.from.send = 0; + worker->u.message_run.from.received = 0; + worker->u.message_run.to.send = 0; + worker->u.message_run.to.received = 0; + + ecore_pipe_freeze(worker->u.message_run.send); + + worker->func_cancel = func_cancel; + worker->func_end = func_end; + worker->hash = NULL; + worker->data = data; + + worker->cancel = EINA_FALSE; + worker->message_run = EINA_TRUE; + worker->feedback_run = EINA_FALSE; + worker->kill = EINA_FALSE; + worker->reschedule = EINA_FALSE; + worker->no_queue = EINA_FALSE; + worker->self = 0; + + eina_threads_init(); + + if (PHC(t, _ecore_direct_worker, worker) == 0) + return (Ecore_Thread*) worker; + + eina_threads_shutdown(); + + if (worker->u.message_run.direct_worker) _ecore_thread_worker_free(worker->u.message_run.direct_worker); + if (worker->u.message_run.send) ecore_pipe_del(worker->u.message_run.send); + + CDD(worker->cond); + LKD(worker->mutex); +#else + /* Note: This type of thread can't and never will work without thread support */ + WRN("ecore_thread_message_run called, but threads disable in Ecore, things will go wrong. Starting now !"); +# warning "You disabled threads support in ecore, I hope you know what you are doing !" +#endif + + func_cancel((void *) data, NULL); + + return NULL; +} +#endif + +EAPI Eina_Bool +ecore_thread_reschedule(Ecore_Thread *thread) +{ + Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *)thread; + + if (!worker) return EINA_FALSE; + +#ifdef EFL_HAVE_THREADS + if (!PHE(worker->self, PHS())) return EINA_FALSE; +#endif + + worker->reschedule = EINA_TRUE; + return EINA_TRUE; +} + +EAPI int +ecore_thread_active_get(void) +{ +#ifdef EFL_HAVE_THREADS + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0); + return _ecore_thread_count; +#else + return 0; +#endif +} + +EAPI int +ecore_thread_pending_get(void) +{ +#ifdef EFL_HAVE_THREADS + int ret; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0); + LKL(_ecore_pending_job_threads_mutex); + ret = eina_list_count(_ecore_pending_job_threads); + LKU(_ecore_pending_job_threads_mutex); + return ret; +#else + return 0; +#endif +} + +EAPI int +ecore_thread_pending_feedback_get(void) +{ +#ifdef EFL_HAVE_THREADS + int ret; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0); + LKL(_ecore_pending_job_threads_mutex); + ret = eina_list_count(_ecore_pending_job_threads_feedback); + LKU(_ecore_pending_job_threads_mutex); + return ret; +#else + return 0; +#endif +} + +EAPI int +ecore_thread_pending_total_get(void) +{ +#ifdef EFL_HAVE_THREADS + int ret; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0); + LKL(_ecore_pending_job_threads_mutex); + ret = eina_list_count(_ecore_pending_job_threads) + eina_list_count(_ecore_pending_job_threads_feedback); + LKU(_ecore_pending_job_threads_mutex); + return ret; +#else + return 0; +#endif +} + +EAPI int +ecore_thread_max_get(void) +{ + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0); + return _ecore_thread_count_max; +} + +EAPI void +ecore_thread_max_set(int num) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + if (num < 1) return; + /* avoid doing something hilarious by blocking dumb users */ + if (num > (16 * eina_cpu_count())) num = 16 * eina_cpu_count(); + + _ecore_thread_count_max = num; +} + +EAPI void +ecore_thread_max_reset(void) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + _ecore_thread_count_max = eina_cpu_count(); +} + +EAPI int +ecore_thread_available_get(void) +{ +#ifdef EFL_HAVE_THREADS + int ret; + + LKL(_ecore_pending_job_threads_mutex); + ret = _ecore_thread_count_max - _ecore_thread_count; + LKU(_ecore_pending_job_threads_mutex); + return ret; +#else + return 0; +#endif +} + +EAPI Eina_Bool +ecore_thread_local_data_add(Ecore_Thread *thread, + const char *key, + void *value, + Eina_Free_Cb cb, + Eina_Bool direct) +{ +#ifdef EFL_HAVE_THREADS + Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *)thread; + Ecore_Thread_Data *d; + Eina_Bool ret; +#endif + + if ((!thread) || (!key) || (!value)) + return EINA_FALSE; +#ifdef EFL_HAVE_THREADS + if (!PHE(worker->self, PHS())) return EINA_FALSE; + + if (!worker->hash) + worker->hash = eina_hash_string_small_new(_ecore_thread_data_free); + + if (!worker->hash) + return EINA_FALSE; + + if (!(d = malloc(sizeof(Ecore_Thread_Data)))) + return EINA_FALSE; + + d->data = value; + d->cb = cb; + + if (direct) + ret = eina_hash_direct_add(worker->hash, key, d); + else + ret = eina_hash_add(worker->hash, key, d); + CDB(worker->cond); + return ret; +#else + (void) cb; + (void) direct; + return EINA_FALSE; +#endif +} + +EAPI void * +ecore_thread_local_data_set(Ecore_Thread *thread, + const char *key, + void *value, + Eina_Free_Cb cb) +{ +#ifdef EFL_HAVE_THREADS + Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *)thread; + Ecore_Thread_Data *d, *r; + void *ret; +#endif + + if ((!thread) || (!key) || (!value)) + return NULL; +#ifdef EFL_HAVE_THREADS + if (!PHE(worker->self, PHS())) return NULL; + + if (!worker->hash) + worker->hash = eina_hash_string_small_new(_ecore_thread_data_free); + + if (!worker->hash) + return NULL; + + if (!(d = malloc(sizeof(Ecore_Thread_Data)))) + return NULL; + + d->data = value; + d->cb = cb; + + r = eina_hash_set(worker->hash, key, d); + CDB(worker->cond); + ret = r->data; + free(r); + return ret; +#else + (void) cb; + return NULL; +#endif +} + +EAPI void * +ecore_thread_local_data_find(Ecore_Thread *thread, + const char *key) +{ +#ifdef EFL_HAVE_THREADS + Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *)thread; + Ecore_Thread_Data *d; +#endif + + if ((!thread) || (!key)) + return NULL; +#ifdef EFL_HAVE_THREADS + if (!PHE(worker->self, PHS())) return NULL; + + if (!worker->hash) + return NULL; + + d = eina_hash_find(worker->hash, key); + if (d) + return d->data; + return NULL; +#else + return NULL; +#endif +} + +EAPI Eina_Bool +ecore_thread_local_data_del(Ecore_Thread *thread, + const char *key) +{ +#ifdef EFL_HAVE_THREADS + Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *)thread; +#endif + + if ((!thread) || (!key)) + return EINA_FALSE; +#ifdef EFL_HAVE_THREADS + if (!PHE(worker->self, PHS())) return EINA_FALSE; + + if (!worker->hash) + return EINA_FALSE; + return eina_hash_del_by_key(worker->hash, key); +#else + return EINA_TRUE; +#endif +} + +EAPI Eina_Bool +ecore_thread_global_data_add(const char *key, + void *value, + Eina_Free_Cb cb, + Eina_Bool direct) +{ +#ifdef EFL_HAVE_THREADS + Ecore_Thread_Data *d; + Eina_Bool ret; +#endif + + if ((!key) || (!value)) + return EINA_FALSE; +#ifdef EFL_HAVE_THREADS + LRWKWL(_ecore_thread_global_hash_lock); + if (!_ecore_thread_global_hash) + _ecore_thread_global_hash = eina_hash_string_small_new(_ecore_thread_data_free); + LRWKU(_ecore_thread_global_hash_lock); + + if (!(d = malloc(sizeof(Ecore_Thread_Data)))) + return EINA_FALSE; + + d->data = value; + d->cb = cb; + + if (!_ecore_thread_global_hash) + return EINA_FALSE; + LRWKWL(_ecore_thread_global_hash_lock); + if (direct) + ret = eina_hash_direct_add(_ecore_thread_global_hash, key, d); + else + ret = eina_hash_add(_ecore_thread_global_hash, key, d); + LRWKU(_ecore_thread_global_hash_lock); + CDB(_ecore_thread_global_hash_cond); + return ret; +#else + (void) cb; + (void) direct; + return EINA_TRUE; +#endif +} + +EAPI void * +ecore_thread_global_data_set(const char *key, + void *value, + Eina_Free_Cb cb) +{ +#ifdef EFL_HAVE_THREADS + Ecore_Thread_Data *d, *r; + void *ret; +#endif + + if ((!key) || (!value)) + return NULL; +#ifdef EFL_HAVE_THREADS + LRWKWL(_ecore_thread_global_hash_lock); + if (!_ecore_thread_global_hash) + _ecore_thread_global_hash = eina_hash_string_small_new(_ecore_thread_data_free); + LRWKU(_ecore_thread_global_hash_lock); + + if (!_ecore_thread_global_hash) + return NULL; + + if (!(d = malloc(sizeof(Ecore_Thread_Data)))) + return NULL; + + d->data = value; + d->cb = cb; + + LRWKWL(_ecore_thread_global_hash_lock); + r = eina_hash_set(_ecore_thread_global_hash, key, d); + LRWKU(_ecore_thread_global_hash_lock); + CDB(_ecore_thread_global_hash_cond); + + ret = r->data; + free(r); + return ret; +#else + (void) cb; + return NULL; +#endif +} + +EAPI void * +ecore_thread_global_data_find(const char *key) +{ +#ifdef EFL_HAVE_THREADS + Ecore_Thread_Data *ret; +#endif + + if (!key) + return NULL; +#ifdef EFL_HAVE_THREADS + if (!_ecore_thread_global_hash) return NULL; + + LRWKRL(_ecore_thread_global_hash_lock); + ret = eina_hash_find(_ecore_thread_global_hash, key); + LRWKU(_ecore_thread_global_hash_lock); + if (ret) + return ret->data; + return NULL; +#else + return NULL; +#endif +} + +EAPI Eina_Bool +ecore_thread_global_data_del(const char *key) +{ +#ifdef EFL_HAVE_THREADS + Eina_Bool ret; +#endif + + if (!key) + return EINA_FALSE; +#ifdef EFL_HAVE_THREADS + if (!_ecore_thread_global_hash) + return EINA_FALSE; + + LRWKWL(_ecore_thread_global_hash_lock); + ret = eina_hash_del_by_key(_ecore_thread_global_hash, key); + LRWKU(_ecore_thread_global_hash_lock); + return ret; +#else + return EINA_TRUE; +#endif +} + +EAPI void * +ecore_thread_global_data_wait(const char *key, + double seconds) +{ +#ifdef EFL_HAVE_THREADS + double tm = 0; + Ecore_Thread_Data *ret = NULL; +#endif + + if (!key) + return NULL; +#ifdef EFL_HAVE_THREADS + if (!_ecore_thread_global_hash) + return NULL; + if (seconds > 0) + tm = ecore_time_get() + seconds; + + while (1) + { + LRWKRL(_ecore_thread_global_hash_lock); + ret = eina_hash_find(_ecore_thread_global_hash, key); + LRWKU(_ecore_thread_global_hash_lock); + if ((ret) || (!seconds) || ((seconds > 0) && (tm <= ecore_time_get()))) + break; + LKL(_ecore_thread_global_hash_mutex); + CDW(_ecore_thread_global_hash_cond, tm); + LKU(_ecore_thread_global_hash_mutex); + } + if (ret) return ret->data; + return NULL; +#else + (void) seconds; + return NULL; +#endif +} + diff --git a/src/lib/ecore/ecore_throttle.c b/src/lib/ecore/ecore_throttle.c new file mode 100644 index 0000000..de0a43e --- /dev/null +++ b/src/lib/ecore/ecore_throttle.c @@ -0,0 +1,101 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "Ecore.h" +#include "ecore_private.h" + +static int throttle_val = 0; + +/** + * @addtogroup Ecore_Throttle_Group Ecore Throttle functions + * + * @{ + */ + +/** + * Increase throttle amount + * + * This will increase or decrease (if @p amount is positive or negative) the + * amount of "voluntary throttling" ecore will do to its main loop while + * running. This is intended to be used to limit animations and wakeups when + * in a strict power management state. The higher the current throttle value + * (which can be retrieved by ecore_throttle_get() ), the more throttling + * takes place. If the current throttle value is 0, then no throttling takes + * place at all. + * + * The value represents how long the ecore main loop will sleep (in seconds) + * before it goes into a fully idle state waiting for events, input or + * timing events to wake it up. For example, if the current throttle level + * is 0.5, then after every time the main loop cycles and goes into idle + * affter processing all events, the main loop will explicitly sleep for 0.5 + * seconds before sitting and waiting for incoming events or timeouts, thus + * preventing animation, async IO and network handling etc. for that period + * of time. Of course these events, data and timeouts will be buffered, + * thus not losing anything, simply delaying when they get handled by the + * throttle value. + * + * Example: + * @code + * void enter_powersave(void) { + * ecore_throttle_adjust(0.2); + * printf("Now at throttle level: %1.3f\n", ecore_throttle_get()); + * } + * + * void enter_deep_powersave(void) { + * ecore_throttle_adjust(0.5); + * printf("Now at throttle level: %1.3f\n", ecore_throttle_get()); + * } + * + * void exit_powersave(void) { + * ecore_throttle_adjust(-0.2); + * printf("Now at throttle level: %1.3f\n", ecore_throttle_get()); + * } + * + * void exit_deep_powersave(void) { + * ecore_throttle_adjust(-0.5); + * printf("Now at throttle level: %1.3f\n", ecore_throttle_get()); + * } + * @endcode + * + * @param amount Amount (in seconds) to adjust by + */ +EAPI void +ecore_throttle_adjust(double amount) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + int adj = amount * 1000000.0; + throttle_val += adj; + if (throttle_val < 0) throttle_val = 0; +} + +/** + * Get current throttle level + * + * This gets the current throttling level, which can be adjusted by + * ecore_throttle_adjust(). The value is in seconds. Please see + * ecore_throttle_adjust() for more information. + * + * @return The current throttle level + */ +EAPI double +ecore_throttle_get(void) +{ + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0.0); + return (double)throttle_val / 1000000.0; +} + +/** + * @} + */ + +void +_ecore_throttle(void) +{ + if (throttle_val <= 0) return; + usleep(throttle_val); +} + diff --git a/src/lib/ecore/ecore_time.c b/src/lib/ecore/ecore_time.c new file mode 100644 index 0000000..0eeb1d6 --- /dev/null +++ b/src/lib/ecore/ecore_time.c @@ -0,0 +1,184 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#ifdef HAVE_SYS_TIME_H +# include +#endif + +#ifdef HAVE_EVIL +# include +#endif + +#if defined(__APPLE__) && defined(__MACH__) +# include +#endif + +#include "Ecore.h" +#include "ecore_private.h" + +#include + +#if defined (HAVE_CLOCK_GETTIME) || defined (EXOTIC_PROVIDE_CLOCK_GETTIME) +static clockid_t _ecore_time_clock_id = -1; +#elif defined(__APPLE__) && defined(__MACH__) +static double _ecore_time_clock_conversion = 1e-9; +#endif +double _ecore_time_loop_time = -1.0; + +/** + * @addtogroup Ecore_Time_Group + * + * @{ + */ + +/** + * Retrieves the current system time as a floating point value in seconds. + * + * This uses a monotonic clock and thus never goes back in time while + * machine is live (even if user changes time or timezone changes, + * however it may be reset whenever the machine is restarted). + * + * @see ecore_loop_time_get(). + * @see ecore_time_unix_get(). + * + * @return The number of seconds. Start time is not defined (it may be + * when the machine was booted, unix time, etc), all it is + * defined is that it never goes backwards (unless you got big critical + * messages when the application started). + */ +EAPI double +ecore_time_get(void) +{ +#if defined (HAVE_CLOCK_GETTIME) || defined (EXOTIC_PROVIDE_CLOCK_GETTIME) + struct timespec t; + + if (EINA_UNLIKELY(_ecore_time_clock_id < 0)) + return ecore_time_unix_get(); + + if (EINA_UNLIKELY(clock_gettime(_ecore_time_clock_id, &t))) + { + CRIT("Cannot get current time."); + /* Try to at least return the latest value retrieved*/ + return _ecore_time_loop_time; + } + + return (double)t.tv_sec + (((double)t.tv_nsec) / 1000000000.0); +#elif defined(HAVE_EVIL) + return evil_time_get(); +#elif defined(__APPLE__) && defined(__MACH__) + return _ecore_time_clock_conversion * (double)mach_absolute_time(); +#else + return ecore_time_unix_get(); +#endif +} + +/** + * Retrieves the current UNIX time as a floating point value in seconds. + * + * @see ecore_time_get(). + * @see ecore_loop_time_get(). + * + * @return The number of seconds since 12.00AM 1st January 1970. + */ +EAPI double +ecore_time_unix_get(void) +{ +#ifdef HAVE_GETTIMEOFDAY + struct timeval timev; + + gettimeofday(&timev, NULL); + return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000); +#else +# error "Your platform isn't supported yet" +#endif +} + +/** + * Retrieves the time at which the last loop stopped waiting for timeouts or + * events. + * + * This gets the time that the main loop ceased waiting for timouts and/or + * events to come in or for signals or any other interrupt source. This should + * be considered a reference point for all time based activity that should + * calculate its timepoint from the return of ecore_loop_time_get(). Use this + * UNLESS you absolutely must get the current actual timepoint - then use + * ecore_time_get(). Note that this time is meant to be used as relative to + * other times obtained on this run. If you need absolute time references, use + * ecore_time_unix_get() instead. + * + * This function can be called before any loop has ever been run, but either + * ecore_init() or ecore_time_get() must have been called once. + * + * @return The number of seconds. Start time is not defined (it may be + * when the machine was booted, unix time, etc), all it is + * defined is that it never goes backwards (unless you got big critical + * messages when the application started). + */ +EAPI double +ecore_loop_time_get(void) +{ + return _ecore_time_loop_time; +} + +/** + * @} + */ + +/********************** Internal methods ********************************/ + +/* TODO: Documentation says "All implementations support the system-wide + * real-time clock, which is identified by CLOCK_REALTIME. Check if the fallback + * to unix time (without specifying the resolution) might be removed + */ +void +_ecore_time_init(void) +{ +#if defined (HAVE_CLOCK_GETTIME) || defined (EXOTIC_PROVIDE_CLOCK_GETTIME) + struct timespec t; + + if (_ecore_time_clock_id != -1) return; + + if (!clock_gettime(CLOCK_MONOTONIC, &t)) + { + _ecore_time_clock_id = CLOCK_MONOTONIC; + DBG("using CLOCK_MONOTONIC."); + } + else if (!clock_gettime(CLOCK_REALTIME, &t)) + { + /* may go backwards */ + _ecore_time_clock_id = CLOCK_REALTIME; + WRN("CLOCK_MONOTONIC not available. Fallback to CLOCK_REALTIME."); + } + else + { + _ecore_time_clock_id = -2; + CRIT("Cannot get a valid clock_gettime() clock id! " + "Fallback to unix time."); + } +#else +# ifndef HAVE_EVIL +# if defined(__APPLE__) && defined(__MACH__) + mach_timebase_info_data_t info; + kern_return_t err = mach_timebase_info(&info); + if (err == 0) + { + _ecore_time_clock_conversion = 1e-9 * (double)info.numer / (double)info.denom; + } + else + { + WRN("Unable to get timebase info. Fallback to nanoseconds."); + } +# else +# warning "Your platform isn't supported yet" + CRIT("Platform does not support clock_gettime. " + "Fallback to unix time."); +# endif +# endif +#endif + + _ecore_time_loop_time = ecore_time_get(); +} + diff --git a/src/lib/ecore/ecore_timer.c b/src/lib/ecore/ecore_timer.c new file mode 100644 index 0000000..b5b6e6d --- /dev/null +++ b/src/lib/ecore/ecore_timer.c @@ -0,0 +1,847 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "Ecore.h" +#include "ecore_private.h" + +#ifdef WANT_ECORE_TIMER_DUMP +# include +# include +# define ECORE_TIMER_DEBUG_BT_NUM 64 +typedef void (*Ecore_Timer_Bt_Func)(); +#endif + +struct _Ecore_Timer +{ + EINA_INLIST; + ECORE_MAGIC; + double in; + double at; + double pending; + Ecore_Task_Cb func; + void *data; + +#ifdef WANT_ECORE_TIMER_DUMP + Ecore_Timer_Bt_Func timer_bt[ECORE_TIMER_DEBUG_BT_NUM]; + int timer_bt_num; +#endif + + int references; + unsigned char delete_me : 1; + unsigned char just_added : 1; + unsigned char frozen : 1; +}; +GENERIC_ALLOC_SIZE_DECLARE(Ecore_Timer); + +static void _ecore_timer_set(Ecore_Timer *timer, + double at, + double in, + Ecore_Task_Cb func, + void *data); +#ifdef WANT_ECORE_TIMER_DUMP +static int _ecore_timer_cmp(const void *d1, + const void *d2); +#endif + +static int timers_added = 0; +static int timers_delete_me = 0; +static Ecore_Timer *timers = NULL; +static Ecore_Timer *timer_current = NULL; +static Ecore_Timer *suspended = NULL; +static double last_check = 0.0; +static double precision = 10.0 / 1000000.0; + +/** + * @addtogroup Ecore_Timer_Group + * + * @{ + */ + +/** + * Retrieves the current precision used by timer infrastructure. + * @return Current precision. + * @see ecore_timer_precision_set() + */ +EAPI double +ecore_timer_precision_get(void) +{ + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0.0); + return precision; +} + +/** + * @brief Sets the precision to be used by timer infrastructure. + * + * @param value allowed introduced timeout delay, in seconds. + * + * This sets the precision for @b all timers. The precision determines how much + * of an difference from the requested interval is acceptable. One common reason + * to use this function is to @b increase the allowed timeout and thus @b + * decrease precision of the timers, this is because less precise the timers + * result in the system waking up less often and thus consuming less resources. + * + * Be aware that kernel may delay delivery even further, these delays + * are always possible due other tasks having higher priorities or + * other scheduler policies. + * + * Example: + * We have 2 timers, one that expires in a 2.0s and another that + * expires in 2.1s, if precision is 0.1s, then the Ecore will request + * for the next expire to happen in 2.1s and not 2.0s and another one + * of 0.1 as it would before. + * + * @note Ecore is smart enough to see if there are timers in the + * precision range, if it does not, in our example if no second timer + * in (T + precision) existed, then it would use the minimum timeout. + */ +EAPI void +ecore_timer_precision_set(double value) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + _ecore_lock(); + + if (value < 0.0) + { + ERR("Precision %f less than zero, ignored", value); + goto unlock; + } + precision = value; + +unlock: + _ecore_unlock(); +} + +/** + * Creates a timer to call the given function in the given period of time. + * @param in The interval in seconds. + * @param func The given function. If @p func returns 1, the timer is + * rescheduled for the next interval @p in. + * @param data Data to pass to @p func when it is called. + * @return A timer object on success. @c NULL on failure. + * + * This function adds a timer and returns its handle on success and NULL on + * failure. The function @p func will be called every @p in seconds. The + * function will be passed the @p data pointer as its parameter. + * + * When the timer @p func is called, it must return a value of either 1 + * (or ECORE_CALLBACK_RENEW) or 0 (or ECORE_CALLBACK_CANCEL). + * If it returns 1, it will be called again at the next tick, or if it returns + * 0 it will be deleted automatically making any references/handles for it + * invalid. + */ +EAPI Ecore_Timer * +ecore_timer_add(double in, + Ecore_Task_Cb func, + const void *data) +{ + double now; + Ecore_Timer *timer = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); + if (!func) goto unlock; + if (in < 0.0) in = 0.0; + timer = ecore_timer_calloc(1); + if (!timer) goto unlock; + ECORE_MAGIC_SET(timer, ECORE_MAGIC_TIMER); + now = ecore_time_get(); + +#ifdef WANT_ECORE_TIMER_DUMP + timer->timer_bt_num = backtrace((void **)(timer->timer_bt), + ECORE_TIMER_DEBUG_BT_NUM); +#endif + + _ecore_timer_set(timer, now + in, in, func, (void *)data); +unlock: + _ecore_unlock(); + return timer; +} + +/** + * Creates a timer to call the given function in the given period of time. + * @param in The interval in seconds from current loop time. + * @param func The given function. If @p func returns 1, the timer is + * rescheduled for the next interval @p in. + * @param data Data to pass to @p func when it is called. + * @return A timer object on success. @c NULL on failure. + * + * This is the same as ecore_timer_add(), but "now" is the time from + * ecore_loop_time_get() not ecore_time_get() as ecore_timer_add() uses. See + * ecore_timer_add() for more details. + */ +EAPI Ecore_Timer * +ecore_timer_loop_add(double in, + Ecore_Task_Cb func, + const void *data) +{ + Ecore_Timer *timer; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); + timer = _ecore_timer_loop_add(in, func, data); + _ecore_unlock(); + + return timer; +} + +/** + * Delete the specified timer from the timer list. + * @param timer The timer to delete. + * @return The data pointer set for the timer when @ref ecore_timer_add was + * called. @c NULL is returned if the function is unsuccessful. + * + * Note: @p timer must be a valid handle. If the timer function has already + * returned 0, the handle is no longer valid (and does not need to be delete). + */ +EAPI void * +ecore_timer_del(Ecore_Timer *timer) +{ + void *data = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); + + if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER)) + { + ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER, + "ecore_timer_del"); + goto unlock; + } + + data = _ecore_timer_del(timer); + +unlock: + _ecore_unlock(); + return data; +} + +/** + * Change the interval the timer ticks of. If set during + * a timer call, this will affect the next interval. + * + * @param timer The timer to change. + * @param in The interval in seconds. + */ +EAPI void +ecore_timer_interval_set(Ecore_Timer *timer, + double in) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + _ecore_lock(); + + if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER)) + { + ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER, + "ecore_timer_interval_set"); + goto unlock; + } + timer->in = in; +unlock: + _ecore_unlock(); +} + +/** + * Get the interval the timer ticks on. + * + * @param timer The timer to retrieve the interval from + * @return The interval on success. -1 on failure. + */ +EAPI double +ecore_timer_interval_get(Ecore_Timer *timer) +{ + double interval; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0.0); + _ecore_lock(); + + if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER)) + { + ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER, + "ecore_timer_interval_get"); + interval = -1.0; + goto unlock; + } + + interval = timer->in; +unlock: + _ecore_unlock(); + return interval; +} + +/** + * Add some delay for the next occurrence of a timer. + * This doesn't affect the interval of a timer. + * + * @param timer The timer to change. + * @param add The delay to add to the next iteration. + */ +EAPI void +ecore_timer_delay(Ecore_Timer *timer, + double add) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER)) + { + ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER, + "ecore_timer_delay"); + return; + } + + _ecore_lock(); + _ecore_timer_delay(timer, add); + _ecore_unlock(); +} + +/** + * Reset a timer to its full interval + * This doesn't affect the interval of a timer + * @param timer The timer + * @since 1.2 + * @note This is equivalent to (but faster than) + * @code + * ecore_timer_delay(timer, ecore_timer_interval_get(timer) - ecore_timer_pending_get(timer)); + * @endcode + */ +EAPI void +ecore_timer_reset(Ecore_Timer *timer) +{ + double now, add; + EINA_MAIN_LOOP_CHECK_RETURN; + if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER)) + { + ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER, + __func__); + return; + } + _ecore_lock(); + now = ecore_time_get(); + + if (timer->frozen) + add = timer->pending; + else + add = timer->at - now; + _ecore_timer_delay(timer, timer->in - add); + _ecore_unlock(); +} + +/** + * Get the pending time regarding a timer. + * + * @param timer The timer to learn from. + * @return The pending time. + * @ingroup Ecore_Timer_Group + */ +EAPI double +ecore_timer_pending_get(Ecore_Timer *timer) +{ + double now; + double ret = 0.0; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0.0); + _ecore_lock(); + + if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER)) + { + ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER, + "ecore_timer_pending_get"); + goto unlock; + } + + now = ecore_time_get(); + + if (timer->frozen) + ret = timer->pending; + else + ret = timer->at - now; +unlock: + _ecore_unlock(); + return ret; +} + +/** + * Pauses a running timer. + * + * @param timer The timer to be paused. + * + * The timer callback won't be called while the timer is paused. The remaining + * time until the timer expires will be saved, so the timer can be resumed with + * that same remaining time to expire, instead of expiring instantly. Use + * ecore_timer_thaw() to resume it. + * + * @note Nothing happens if the timer was already paused. + * + * @see ecore_timer_thaw() + */ +EAPI void +ecore_timer_freeze(Ecore_Timer *timer) +{ + double now; + + EINA_MAIN_LOOP_CHECK_RETURN; + _ecore_lock(); + + if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER)) + { + ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER, + "ecore_timer_freeze"); + goto unlock; + } + + /* Timer already frozen */ + if (timer->frozen) + goto unlock; + + timers = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer)); + suspended = (Ecore_Timer *)eina_inlist_prepend(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer)); + + now = ecore_time_get(); + + timer->pending = timer->at - now; + timer->at = 0.0; + timer->frozen = 1; +unlock: + _ecore_unlock(); +} + +/** + * Resumes a frozen (paused) timer. + * + * @param timer The timer to be resumed. + * + * The timer will be resumed from its previous relative position in time. That + * means, if it had X seconds remaining until expire when it was paused, it will + * be started now with those same X seconds remaining to expire again. But + * notice that the interval time won't be touched by this call or by + * ecore_timer_freeze(). + * + * @see ecore_timer_freeze() + */ +EAPI void +ecore_timer_thaw(Ecore_Timer *timer) +{ + double now; + + EINA_MAIN_LOOP_CHECK_RETURN; + _ecore_lock(); + + if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER)) + { + ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER, + "ecore_timer_thaw"); + goto unlock; + } + + /* Timer not frozen */ + if (!timer->frozen) + goto unlock; + + suspended = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer)); + now = ecore_time_get(); + + _ecore_timer_set(timer, timer->pending + now, timer->in, timer->func, timer->data); +unlock: + _ecore_unlock(); +} + +EAPI char * +ecore_timer_dump(void) +{ +#ifdef WANT_ECORE_TIMER_DUMP + Eina_Strbuf *result; + char *out; + Ecore_Timer *tm; + Eina_List *tmp = NULL; + int living_timer = 0; + int unknow_timer = 0; + + EINA_MAIN_LOOP_CHECK_RETURN(NULL); + _ecore_lock(); + result = eina_strbuf_new(); + + EINA_INLIST_FOREACH(timers, tm) + tmp = eina_list_sorted_insert(tmp, _ecore_timer_cmp, tm); + + EINA_LIST_FREE(tmp, tm) + { + char **strings; + int j; + + if (!tm->frozen && !tm->delete_me) + living_timer++; + + strings = backtrace_symbols((void **)tm->timer_bt, tm->timer_bt_num); + if (tm->timer_bt_num <= 0 || strings == NULL) + { + unknow_timer++; + continue; + } + + eina_strbuf_append_printf(result, "*** timer: %f ***\n", tm->in); + if (tm->frozen) + eina_strbuf_append(result, "FROZEN\n"); + if (tm->delete_me) + eina_strbuf_append(result, "DELETED\n"); + for (j = 0; j < tm->timer_bt_num; j++) + eina_strbuf_append_printf(result, "%s\n", strings[j]); + + free(strings); + } + + eina_strbuf_append_printf(result, "\n***\nThere is %i living timer.\nWe did lost track of %i timers.\n", living_timer, unknow_timer); + + out = eina_strbuf_string_steal(result); + eina_strbuf_free(result); + _ecore_unlock(); + + return out; +#else + return NULL; +#endif +} + +/** + * @} + */ + +Ecore_Timer * +_ecore_timer_loop_add(double in, + Ecore_Task_Cb func, + const void *data) +{ + double now; + Ecore_Timer *timer = NULL; + + if (!func) return timer; + if (in < 0.0) in = 0.0; + timer = ecore_timer_calloc(1); + if (!timer) return timer; + ECORE_MAGIC_SET(timer, ECORE_MAGIC_TIMER); + now = ecore_loop_time_get(); + +#ifdef WANT_ECORE_TIMER_DUMP + timer->timer_bt_num = backtrace((void **)(timer->timer_bt), + ECORE_TIMER_DEBUG_BT_NUM); +#endif + _ecore_timer_set(timer, now + in, in, func, (void *)data); + return timer; +} + +EAPI void +_ecore_timer_delay(Ecore_Timer *timer, + double add) +{ + if (timer->frozen) + { + timer->pending += add; + } + else + { + timers = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer)); + _ecore_timer_set(timer, timer->at + add, timer->in, timer->func, timer->data); + } +} + +void * +_ecore_timer_del(Ecore_Timer *timer) +{ + if (timer->frozen && !timer->references) + { + void *data = timer->data; + + suspended = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer)); + + if (timer->delete_me) + timers_delete_me--; + + ecore_timer_mp_free(timer); + return data; + } + + EINA_SAFETY_ON_TRUE_RETURN_VAL(timer->delete_me, NULL); + timer->delete_me = 1; + timers_delete_me++; + return timer->data; +} + +void +_ecore_timer_shutdown(void) +{ + Ecore_Timer *timer; + + while ((timer = timers)) + { + timers = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timers)); + ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE); + ecore_timer_mp_free(timer); + } + + while ((timer = suspended)) + { + suspended = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(suspended)); + ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE); + ecore_timer_mp_free(timer); + } + + timer_current = NULL; +} + +void +_ecore_timer_cleanup(void) +{ + Ecore_Timer *l; + int in_use = 0, todo = timers_delete_me, done = 0; + + if (!timers_delete_me) return; + for (l = timers; l; ) + { + Ecore_Timer *timer = l; + + l = (Ecore_Timer *)EINA_INLIST_GET(l)->next; + if (timer->delete_me) + { + if (timer->references) + { + in_use++; + continue; + } + timers = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer)); + ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE); + ecore_timer_mp_free(timer); + timers_delete_me--; + done++; + if (timers_delete_me == 0) return; + } + } + for (l = suspended; l; ) + { + Ecore_Timer *timer = l; + + l = (Ecore_Timer *)EINA_INLIST_GET(l)->next; + if (timer->delete_me) + { + if (timer->references) + { + in_use++; + continue; + } + suspended = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer)); + ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE); + ecore_timer_mp_free(timer); + timers_delete_me--; + done++; + if (timers_delete_me == 0) return; + } + } + + if ((!in_use) && (timers_delete_me)) + { + ERR("%d timers to delete, but they were not found!" + "Stats: todo=%d, done=%d, pending=%d, in_use=%d. " + "reset counter.", + timers_delete_me, todo, done, todo - done, in_use); + timers_delete_me = 0; + } +} + +void +_ecore_timer_enable_new(void) +{ + Ecore_Timer *timer; + + if (!timers_added) return; + timers_added = 0; + EINA_INLIST_FOREACH(timers, timer) timer->just_added = 0; +} + +int +_ecore_timers_exists(void) +{ + Ecore_Timer *timer = timers; + + while ((timer) && (timer->delete_me)) + timer = (Ecore_Timer *)EINA_INLIST_GET(timer)->next; + + return !!timer; +} + +static inline Ecore_Timer * +_ecore_timer_first_get(void) +{ + Ecore_Timer *timer = timers; + + while ((timer) && ((timer->delete_me) || (timer->just_added))) + timer = (Ecore_Timer *)EINA_INLIST_GET(timer)->next; + + return timer; +} + +static inline Ecore_Timer * +_ecore_timer_after_get(Ecore_Timer *base) +{ + Ecore_Timer *timer = (Ecore_Timer *)EINA_INLIST_GET(base)->next; + Ecore_Timer *valid_timer = NULL; + double maxtime = base->at + precision; + + while ((timer) && (timer->at < maxtime)) + { + if (!((timer->delete_me) || (timer->just_added))) + valid_timer = timer; + timer = (Ecore_Timer *)EINA_INLIST_GET(timer)->next; + } + + return valid_timer; +} + +double +_ecore_timer_next_get(void) +{ + double now; + double in; + Ecore_Timer *first, *second; + + first = _ecore_timer_first_get(); + if (!first) return -1; + + second = _ecore_timer_after_get(first); + if (second) first = second; + + now = ecore_loop_time_get(); + in = first->at - now; + if (in < 0) in = 0; + return in; +} + +static inline void +_ecore_timer_reschedule(Ecore_Timer *timer, + double when) +{ + if ((timer->delete_me) || (timer->frozen)) return; + + timers = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer)); + + /* if the timer would have gone off more than 15 seconds ago, + * assume that the system hung and set the timer to go off + * timer->in from now. this handles system hangs, suspends + * and more, so ecore will only "replay" the timers while + * the system is suspended if it is suspended for less than + * 15 seconds (basically). this also handles if the process + * is stopped in a debugger or IO and other handling gets + * really slow within the main loop. + */ + if ((timer->at + timer->in) < (when - 15.0)) + _ecore_timer_set(timer, when + timer->in, timer->in, timer->func, timer->data); + else + _ecore_timer_set(timer, timer->at + timer->in, timer->in, timer->func, timer->data); +} + +/* assume that we hold the ecore lock when entering this function */ +void +_ecore_timer_expired_timers_call(double when) +{ + /* call the first expired timer until no expired timers exist */ + while (_ecore_timer_expired_call(when)) ; +} + +/* assume that we hold the ecore lock when entering this function */ +int +_ecore_timer_expired_call(double when) +{ + if (!timers) return 0; + if (last_check > when) + { + Ecore_Timer *timer; + /* User set time backwards */ + EINA_INLIST_FOREACH(timers, timer) timer->at -= (last_check - when); + } + last_check = when; + + if (!timer_current) + { + /* regular main loop, start from head */ + timer_current = timers; + } + else + { + /* recursive main loop, continue from where we were */ + Ecore_Timer *timer_old = timer_current; + timer_current = (Ecore_Timer *)EINA_INLIST_GET(timer_current)->next; + _ecore_timer_reschedule(timer_old, when); + } + + while (timer_current) + { + Ecore_Timer *timer = timer_current; + + if (timer->at > when) + { + timer_current = NULL; /* ended walk, next should restart. */ + return 0; + } + + if ((timer->just_added) || (timer->delete_me)) + { + timer_current = (Ecore_Timer *)EINA_INLIST_GET(timer_current)->next; + continue; + } + + timer->references++; + if (!_ecore_call_task_cb(timer->func, timer->data)) + { + if (!timer->delete_me) _ecore_timer_del(timer); + } + timer->references--; + + if (timer_current) /* may have changed in recursive main loops */ + timer_current = (Ecore_Timer *)EINA_INLIST_GET(timer_current)->next; + + _ecore_timer_reschedule(timer, when); + } + return 0; +} + +static void +_ecore_timer_set(Ecore_Timer *timer, + double at, + double in, + Ecore_Task_Cb func, + void *data) +{ + Ecore_Timer *t2; + + timers_added = 1; + timer->at = at; + timer->in = in; + timer->func = func; + timer->data = data; + timer->just_added = 1; + timer->frozen = 0; + timer->pending = 0.0; + if (timers) + { + EINA_INLIST_REVERSE_FOREACH(EINA_INLIST_GET(timers), t2) + { + if (timer->at > t2->at) + { + timers = (Ecore_Timer *)eina_inlist_append_relative(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer), EINA_INLIST_GET(t2)); + return; + } + } + } + timers = (Ecore_Timer *)eina_inlist_prepend(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer)); +} + +#ifdef WANT_ECORE_TIMER_DUMP +static int +_ecore_timer_cmp(const void *d1, + const void *d2) +{ + const Ecore_Timer *t1 = d1; + const Ecore_Timer *t2 = d2; + + return (int)((t1->in - t2->in) * 100); +} +#endif diff --git a/src/lib/ecore_cocoa/Ecore_Cocoa.h b/src/lib/ecore_cocoa/Ecore_Cocoa.h new file mode 100644 index 0000000..51c8ead --- /dev/null +++ b/src/lib/ecore_cocoa/Ecore_Cocoa.h @@ -0,0 +1,147 @@ +#ifndef __ECORE_COCOA_H__ +#define __ECORE_COCOA_H__ + +/* + * DO NOT USE THIS HEADER. IT IS WORK IN PROGRESS. IT IS NOT FINAL AND + * THE API MAY CHANGE. + */ + +#ifndef ECORE_COCOA_WIP_GNSIDNQI +# warning "You are using a work in progress API. This API is not stable" +# warning "and is subject to change. You use this at your own risk." +#endif + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +#else +# define EAPI +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _Ecore_Cocoa_Window Ecore_Cocoa_Window; + +EAPI extern int ECORE_COCOA_EVENT_GOT_FOCUS; +EAPI extern int ECORE_COCOA_EVENT_LOST_FOCUS; +EAPI extern int ECORE_COCOA_EVENT_RESIZE; +EAPI extern int ECORE_COCOA_EVENT_EXPOSE; + +typedef struct _Ecore_Cocoa_Event_Video_Resize Ecore_Cocoa_Event_Video_Resize; +struct _Ecore_Cocoa_Event_Video_Resize +{ + int w; + int h; +}; + + +/* Core */ + +EAPI int ecore_cocoa_init(void); +EAPI int ecore_cocoa_shutdown(void); +EAPI void ecore_cocoa_feed_events(void); + +/* Window */ + +EAPI Ecore_Cocoa_Window *ecore_cocoa_window_new(int x, + int y, + int width, + int height); + +EAPI void ecore_cocoa_window_free(Ecore_Cocoa_Window *window); + +EAPI void *ecore_cocoa_window_hwnd_get(Ecore_Cocoa_Window *window); + +EAPI void ecore_cocoa_window_move(Ecore_Cocoa_Window *window, + int x, + int y); + +EAPI void ecore_cocoa_window_resize(Ecore_Cocoa_Window *window, + int width, + int height); + +EAPI void ecore_cocoa_window_move_resize(Ecore_Cocoa_Window *window, + int x, + int y, + int width, + int height); + +EAPI void ecore_cocoa_window_geometry_get(Ecore_Cocoa_Window *window, + int *x, + int *y, + int *width, + int *height); + +EAPI void ecore_cocoa_window_size_get(Ecore_Cocoa_Window *window, + int *width, + int *height); + +EAPI void ecore_cocoa_window_size_min_set(Ecore_Cocoa_Window *window, + unsigned int min_width, + unsigned int min_height); + +EAPI void ecore_cocoa_window_size_min_get(Ecore_Cocoa_Window *window, + unsigned int *min_width, + unsigned int *min_height); + +EAPI void ecore_cocoa_window_size_max_set(Ecore_Cocoa_Window *window, + unsigned int max_width, + unsigned int max_height); + +EAPI void ecore_cocoa_window_size_max_get(Ecore_Cocoa_Window *window, + unsigned int *max_width, + unsigned int *max_height); + +EAPI void ecore_cocoa_window_size_base_set(Ecore_Cocoa_Window *window, + unsigned int base_width, + unsigned int base_height); + +EAPI void ecore_cocoa_window_size_base_get(Ecore_Cocoa_Window *window, + unsigned int *base_width, + unsigned int *base_height); + +EAPI void ecore_cocoa_window_size_step_set(Ecore_Cocoa_Window *window, + unsigned int step_width, + unsigned int step_height); + +EAPI void ecore_cocoa_window_size_step_get(Ecore_Cocoa_Window *window, + unsigned int *step_width, + unsigned int *step_height); + +EAPI void ecore_cocoa_window_show(Ecore_Cocoa_Window *window); + +EAPI void ecore_cocoa_window_hide(Ecore_Cocoa_Window *window); + +EAPI void ecore_cocoa_window_raise(Ecore_Cocoa_Window *window); + +EAPI void ecore_cocoa_window_lower(Ecore_Cocoa_Window *window); + +EAPI void ecore_cocoa_window_title_set(Ecore_Cocoa_Window *window, + const char *title); + +EAPI void ecore_cocoa_window_focus_set(Ecore_Cocoa_Window *window); + +EAPI void ecore_cocoa_window_iconified_set(Ecore_Cocoa_Window *window, + int on); + +EAPI void ecore_cocoa_window_borderless_set(Ecore_Cocoa_Window *window, + int on); + +EAPI void ecore_cocoa_window_view_set(Ecore_Cocoa_Window *window, + void *view); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/ecore_cocoa/Ecore_Cocoa_Keys.h b/src/lib/ecore_cocoa/Ecore_Cocoa_Keys.h new file mode 100644 index 0000000..7068bc2 --- /dev/null +++ b/src/lib/ecore_cocoa/Ecore_Cocoa_Keys.h @@ -0,0 +1,285 @@ +#ifndef ECORE_COCOA_KEYS_H__ +#define ECORE_COCOA_KEYS_H__ + +struct _ecore_cocoa_keys_s +{ + int code; + const char *name; + const char *compose; +}; + +static const struct _ecore_cocoa_keys_s keystable[] = +{ + +{ 0, "0x00", "" }, +{ 0, "First", "" }, +{ 3, "Return", "\015" }, +{ 8, "BackSpace", "\010" }, +{ 9, "Tab", "\011" }, +{ 12, "Clear", "" }, +{ 13, "Return", "\015" }, +{ 19, "Pause", "" }, +{ 25, "BackTab", ""}, +{ 27, "Escape", "" }, +{ 32, "space", " " }, +{ 33, "exclam", "!" }, +{ 34, "quotedbl", "\"" }, +{ 35, "numbersign", "#" }, +{ 36, "dollar", "$" }, +{ 37, "percent", "%%" }, +{ 38, "ampersand", "&" }, +{ 39, "apostrophe", "'" }, +{ 40, "parenleft", "(" }, +{ 41, "parenright", ")" }, +{ 42, "asterisk", "*" }, +{ 43, "plus", "+" }, +{ 44, "comma", "," }, +{ 45, "minus", "-" }, +{ 46, "period", "." }, +{ 47, "slash", "/" }, +{ 48, "0", "0" }, +{ 49, "1", "1" }, +{ 50, "2", "2" }, +{ 51, "3", "3" }, +{ 52, "4", "4" }, +{ 53, "5", "5" }, +{ 54, "6", "6" }, +{ 55, "7", "7" }, +{ 56, "8", "8" }, +{ 57, "9", "9" }, +{ 58, "colon", ";" }, +{ 59, "semicolon", ";" }, +{ 60, "less", "<" }, +{ 61, "equal", "=" }, +{ 62, "greater", ">" }, +{ 63, "question", "?" }, +{ 64, "at", "@" }, + +{ 91, "bracketleft", "[" }, +{ 92, "backslash", "\\" }, +{ 93, "bracketright", "]" }, +{ 94, "asciicircumm", "^" }, +{ 95, "underscore", "_" }, +{ 96, "backquote", "`" }, +{ 97, "a", "a" }, +{ 98, "b", "b" }, +{ 99, "c", "c" }, +{ 100, "d", "d" }, +{ 101, "e", "e" }, +{ 102, "f", "f" }, +{ 103, "g", "g" }, +{ 104, "h", "h" }, +{ 105, "i", "i" }, +{ 106, "j", "j" }, +{ 107, "k", "k" }, +{ 108, "l", "l" }, +{ 109, "m", "m" }, +{ 110, "n", "n" }, +{ 111, "o", "o" }, +{ 112, "p", "p" }, +{ 113, "q", "q" }, +{ 114, "r", "r" }, +{ 115, "s", "s" }, +{ 116, "t", "t" }, +{ 117, "u", "u" }, +{ 118, "v", "v" }, +{ 119, "w", "w" }, +{ 120, "x", "x" }, +{ 121, "y", "y" }, +{ 122, "z", "z" }, +{ 123, "braceleft", "" }, +{ 124, "pipe", "" }, +{ 125, "braceright", "" }, +{ 127, "Delete", "\177" }, +{ 126, "asciitilde", "~" }, + +{ 160, "w0", "" }, +{ 161, "w1", "" }, +{ 162, "w2", "" }, +{ 163, "w3", "" }, +{ 164, "w4", "" }, +{ 165, "w5", "" }, +{ 166, "w6", "" }, +{ 167, "w7", "" }, +{ 168, "w8", "" }, +{ 169, "w9", "" }, +{ 170, "w10", "" }, +{ 171, "w11", "" }, +{ 172, "w12", "" }, +{ 173, "w13", "" }, +{ 174, "w14", "" }, +{ 175, "w15", "" }, +{ 176, "w16", "" }, +{ 177, "w17", "" }, +{ 178, "w18", "" }, +{ 179, "w19", "" }, +{ 180, "w20", "" }, +{ 181, "w21", "" }, +{ 182, "w22", "" }, +{ 183, "w23", "" }, +{ 184, "w24", "" }, +{ 185, "w25", "" }, +{ 186, "w26", "" }, +{ 187, "w27", "" }, +{ 188, "w28", "" }, +{ 189, "w29", "" }, +{ 190, "w30", "" }, +{ 191, "w31", "" }, +{ 192, "w32", "" }, +{ 193, "w33", "" }, +{ 194, "w34", "" }, +{ 195, "w35", "" }, +{ 196, "w36", "" }, +{ 197, "w37", "" }, +{ 198, "w38", "" }, +{ 199, "w39", "" }, +{ 200, "w40", "" }, +{ 201, "w41", "" }, +{ 202, "w42", "" }, +{ 203, "w43", "" }, +{ 204, "w44", "" }, +{ 205, "w45", "" }, +{ 206, "w46", "" }, +{ 207, "w47", "" }, +{ 208, "w48", "" }, +{ 209, "w49", "" }, +{ 210, "w50", "" }, +{ 211, "w51", "" }, +{ 212, "w52", "" }, +{ 213, "w53", "" }, +{ 214, "w54", "" }, +{ 215, "w55", "" }, +{ 216, "w56", "" }, +{ 217, "w57", "" }, +{ 218, "w58", "" }, +{ 219, "w59", "" }, +{ 220, "w60", "" }, +{ 221, "w61", "" }, +{ 222, "w62", "" }, +{ 223, "w63", "" }, +{ 224, "w64", "" }, +{ 225, "w65", "" }, +{ 226, "w66", "" }, +{ 227, "w67", "" }, +{ 228, "w68", "" }, +{ 229, "w69", "" }, +{ 230, "w70", "" }, +{ 231, "w71", "" }, +{ 232, "w72", "" }, +{ 233, "w73", "" }, +{ 234, "w74", "" }, +{ 235, "w75", "" }, +{ 236, "w76", "" }, +{ 237, "w77", "" }, +{ 238, "w78", "" }, +{ 239, "w79", "" }, +{ 240, "w80", "" }, +{ 241, "w81", "" }, +{ 242, "w82", "" }, +{ 243, "w83", "" }, +{ 244, "w84", "" }, +{ 245, "w85", "" }, +{ 246, "w86", "" }, +{ 247, "w87", "" }, +{ 248, "w88", "" }, +{ 249, "w89", "" }, +{ 250, "w90", "" }, +{ 251, "w91", "" }, +{ 252, "w92", "" }, +{ 253, "w93", "" }, +{ 254, "w94", "" }, +{ 255, "w95", "" }, + +{ 256, "KP0", "0" }, +{ 257, "KP1", "1" }, +{ 258, "KP2", "2" }, +{ 259, "KP3", "3" }, +{ 260, "KP4", "4" }, +{ 261, "KP5", "5" }, +{ 262, "KP6", "6" }, +{ 263, "KP7", "7" }, +{ 264, "KP8", "8" }, +{ 265, "KP9", "9" }, +{ 266, "period", "." }, +{ 267, "KP_Divide", "/" }, +{ 268, "KP_Multiply", "*" }, +{ 269, "KP_Minus", "-" }, +{ 270, "KP_Plus", "+" }, +{ 271, "KP_Enter", "\015" }, +{ 272, "KP_Equals", "=" }, + +{ NSUpArrowFunctionKey, "Up", "" }, +{ NSDownArrowFunctionKey, "Down", "" }, +{ NSRightArrowFunctionKey, "Right", "" }, +{ NSLeftArrowFunctionKey, "Left", "" }, +{ NSInsertFunctionKey, "Insert", "" }, +{ NSHomeFunctionKey, "Home", "" }, +{ NSEndFunctionKey, "End", "" }, +{ NSPageUpFunctionKey, "Page_Up", "" }, +{ NSPageDownFunctionKey, "Page_Down", "" }, + +{ NSF1FunctionKey, "F1", "" }, +{ NSF2FunctionKey, "F2", "" }, +{ NSF3FunctionKey, "F3", "" }, +{ NSF4FunctionKey, "F4", "" }, +{ NSF5FunctionKey, "F5", "" }, +{ NSF6FunctionKey, "F6", "" }, +{ NSF7FunctionKey, "F7", "" }, +{ NSF8FunctionKey, "F8", "" }, +{ NSF9FunctionKey, "F9", "" }, +{ NSF10FunctionKey, "F10", "" }, +{ NSF11FunctionKey, "F11", "" }, +{ NSF12FunctionKey, "F12", "" }, +{ NSF13FunctionKey, "F13", "" }, +{ NSF14FunctionKey, "F14", "" }, +{ NSF15FunctionKey, "F15", "" }, +{ NSF16FunctionKey, "F16", "" }, +{ NSF17FunctionKey, "F17", "" }, +{ NSF18FunctionKey, "F18", "" }, +{ NSF19FunctionKey, "F19", "" }, +{ NSF20FunctionKey, "F20", "" }, +{ NSF21FunctionKey, "F21", "" }, +{ NSF22FunctionKey, "F22", "" }, +{ NSF23FunctionKey, "F23", "" }, +{ NSF24FunctionKey, "F24", "" }, +{ NSF25FunctionKey, "F25", "" }, +{ NSF26FunctionKey, "F26", "" }, +{ NSF27FunctionKey, "F27", "" }, +{ NSF28FunctionKey, "F28", "" }, +{ NSF29FunctionKey, "F29", "" }, +{ NSF30FunctionKey, "F30", "" }, +{ NSF31FunctionKey, "F31", "" }, +{ NSF32FunctionKey, "F32", "" }, +{ NSF33FunctionKey, "F33", "" }, +{ NSF34FunctionKey, "F34", "" }, +{ NSF35FunctionKey, "F35", "" }, + +{ NSClearLineFunctionKey, "Num_Lock", "" }, +{ 301, "Caps_Lock", "" }, +{ NSScrollLockFunctionKey, "Scroll_Lock", "" }, +{ 303, "Shift_R", "" }, +{ 304, "Shift_L", "" }, +{ 305, "Control_R", "" }, +{ 306, "Control_L", "" }, +{ 307, "Alt_R", "" }, +{ 308, "Alt_L", "" }, +{ 309, "Meta_R", "" }, +{ 310, "Meta_L", "" }, +{ 311, "Super_L", "" }, +{ 312, "Super_R", "" }, + +{ NSModeSwitchFunctionKey, "Mode", "" }, +{ 314, "Compose", "" }, + +{ NSHelpFunctionKey, "Help", "" }, +{ NSPrintFunctionKey, "Print", "" }, +{ NSSysReqFunctionKey, "SysReq", "" }, +{ NSBreakFunctionKey, "Break", "" }, +{ NSMenuFunctionKey, "Menu", "" }, +{ 320, "Power", "" }, +{ 321, "Euro", "" }, +{ NSUndoFunctionKey, "Undo", "" } + +}; + +#endif /* ECORE_COCOA_KEYS_H__ */ diff --git a/src/lib/ecore_cocoa/Makefile.am b/src/lib/ecore_cocoa/Makefile.am new file mode 100644 index 0000000..4ac7b11 --- /dev/null +++ b/src/lib/ecore_cocoa/Makefile.am @@ -0,0 +1,29 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore_input \ +-I$(top_builddir)/src/lib/ecore \ +-I$(top_builddir)/src/lib/ecore_input \ +@EVAS_CFLAGS@ \ +@EINA_CFLAGS@ + +lib_LTLIBRARIES = libecore_cocoa.la +includes_HEADERS = \ +Ecore_Cocoa.h \ +Ecore_Cocoa_Keys.h +includesdir = $(includedir)/ecore-@VMAJ@ + +libecore_cocoa_la_SOURCES = \ +ecore_cocoa.m \ +ecore_cocoa_window.m + +libecore_cocoa_la_LIBADD = \ +$(top_builddir)/src/lib/ecore/libecore.la \ +$(top_builddir)/src/lib/ecore_input/libecore_input.la \ +@EVAS_LIBS@ \ +@EINA_LIBS@ + +libecore_cocoa_la_LDFLAGS = @cocoa_ldflags@ -version-info @version_info@ @release_info@ + +EXTRA_DIST = ecore_cocoa_private.h diff --git a/src/lib/ecore_cocoa/ecore_cocoa.m b/src/lib/ecore_cocoa/ecore_cocoa.m new file mode 100644 index 0000000..3f6023a --- /dev/null +++ b/src/lib/ecore_cocoa/ecore_cocoa.m @@ -0,0 +1,283 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include + +#include +#include +#include + +#include "Ecore_Cocoa.h" +#include "Ecore_Cocoa_Keys.h" + + +EAPI int ECORE_COCOA_EVENT_GOT_FOCUS = 0; +EAPI int ECORE_COCOA_EVENT_LOST_FOCUS = 0; +EAPI int ECORE_COCOA_EVENT_RESIZE = 0; +EAPI int ECORE_COCOA_EVENT_EXPOSE = 0; + +static int _ecore_cocoa_init_count = 0; + +static int old_flags; + +EAPI int +ecore_cocoa_init(void) +{ + if (++_ecore_cocoa_init_count != 1) + return _ecore_cocoa_init_count; + + if (!ecore_event_init()) + return --_ecore_cocoa_init_count; + + NSApplicationLoad(); + + ECORE_COCOA_EVENT_GOT_FOCUS = ecore_event_type_new(); + ECORE_COCOA_EVENT_LOST_FOCUS = ecore_event_type_new(); + ECORE_COCOA_EVENT_RESIZE = ecore_event_type_new(); + ECORE_COCOA_EVENT_EXPOSE = ecore_event_type_new(); + + return _ecore_cocoa_init_count; +} + +/** + * Shuts down the Ecore_Cocoa library. + * @return @c The number of times the system has been initialised without + * being shut down. + * @ingroup Ecore_Cocoa_Library_Group + */ +EAPI int +ecore_cocoa_shutdown(void) +{ + if (--_ecore_cocoa_init_count != 0) + return _ecore_cocoa_init_count; + + ecore_event_shutdown(); + + return _ecore_cocoa_init_count; +} + +EAPI void +ecore_cocoa_feed_events(void) +{ + NSDate *date = [NSDate dateWithTimeIntervalSinceNow:0.001]; + NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:date + inMode:NSDefaultRunLoopMode + dequeue:YES]; + [date release]; + if (!event) return; // SDL loops until null; maybe we should do that too. or not. + + unsigned int time = (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff); + + switch([event type]) + { + case NSMouseMoved: + case NSLeftMouseDragged: + case NSRightMouseDragged: + case NSOtherMouseDragged: + { + Ecore_Event_Mouse_Move * ev = calloc(1, sizeof(Ecore_Event_Mouse_Move)); + if (!ev) return; + ev->x = [event locationInWindow].x; + ev->y = [event locationInWindow].y; + ev->root.x = ev->x; + ev->root.y = ev->y; + ev->timestamp = time; + ev->window = [event window]; + ev->modifiers = 0; /* FIXME: keep modifier around. */ + + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, ev, NULL, NULL); + + [NSApp sendEvent:event]; // pass along mouse events, for window manager + break; + } + case NSLeftMouseDown: + case NSRightMouseDown: + case NSOtherMouseDown: + { + Ecore_Event_Mouse_Button * ev = calloc(1, sizeof(Ecore_Event_Mouse_Button)); + if (!ev) return; + ev->x = [event locationInWindow].x; + ev->y = [event locationInWindow].y; + ev->root.x = ev->x; + ev->root.y = ev->y; + ev->timestamp = time; + ev->buttons = [event buttonNumber] + 1; // Apple indexes buttons from 0 + + if ([event clickCount] == 2) + ev->double_click = 1; + else + ev->double_click = 0; + + if ([event clickCount] >= 3) + ev->triple_click = 1; + else + ev->triple_click = 0; + + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, ev, NULL, NULL); + + [NSApp sendEvent:event]; // pass along mouse events, for window manager + break; + } + case NSLeftMouseUp: + case NSRightMouseUp: + case NSOtherMouseUp: + { + Ecore_Event_Mouse_Button * ev = calloc(1, sizeof(Ecore_Event_Mouse_Button)); + if (!ev) return; + ev->x = [event locationInWindow].x; + ev->y = [event locationInWindow].y; + ev->root.x = ev->x; + ev->root.y = ev->y; + ev->timestamp = time; + ev->buttons = [event buttonNumber] + 1; // Apple indexes buttons from 0 + + if ([event clickCount] == 2) + ev->double_click = 1; + else + ev->double_click = 0; + + if ([event clickCount] >= 3) + ev->triple_click = 1; + else + ev->triple_click = 0; + + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, ev, NULL, NULL); + + [NSApp sendEvent:event]; // pass along mouse events, for window manager + break; + } + case NSKeyDown: + { + Ecore_Event_Key *ev; + unsigned int i; + + ev = calloc(1, sizeof (Ecore_Event_Key)); + if (!ev) return; + ev->timestamp = time; + + for (i = 0; i < sizeof (keystable) / sizeof (struct _ecore_cocoa_keys_s); ++i) + { + if (keystable[i].code == tolower([[event charactersIgnoringModifiers] characterAtIndex:0])) + { + ev->keyname = keystable[i].name; + ev->string = keystable[i].compose; + + ecore_event_add(ECORE_EVENT_KEY_DOWN, ev, NULL, NULL); + return; + } + } + + break; + } + case NSKeyUp: + { + Ecore_Event_Key *ev; + unsigned int i; + + ev = calloc(1, sizeof (Ecore_Event_Key)); + if (!ev) return; + ev->timestamp = time; + + for (i = 0; i < sizeof (keystable) / sizeof (struct _ecore_cocoa_keys_s); ++i) + { + if (keystable[i].code == tolower([[event charactersIgnoringModifiers] characterAtIndex:0])) + { + ev->keyname = keystable[i].name; + ev->string = keystable[i].compose; + + ecore_event_add(ECORE_EVENT_KEY_UP, ev, NULL, NULL); + return; + } + } + + break; + } + case NSFlagsChanged: + { + int flags = [event modifierFlags]; + + Ecore_Event_Key *evDown = NULL; + Ecore_Event_Key *evUp = NULL; + + evDown = calloc(1, sizeof (Ecore_Event_Key)); + if (!evDown) return; + + evUp = calloc(1, sizeof (Ecore_Event_Key)); + if (!evUp) + { + free(evDown); + return; + } + + // Turn special key flags on + if (flags & NSShiftKeyMask) + evDown->keyname = "Shift_L"; + else if (flags & NSControlKeyMask) + evDown->keyname = "Control_L"; + else if (flags & NSAlternateKeyMask) + evDown->keyname = "Alt_L"; + else if (flags & NSCommandKeyMask) + evDown->keyname = "Super_L"; + else if (flags & NSAlphaShiftKeyMask) + evDown->keyname = "Caps_Lock"; + + if (evDown->keyname) + { + evDown->timestamp = time; + evDown->string = ""; + ecore_event_add(ECORE_EVENT_KEY_DOWN, evDown, NULL, NULL); + old_flags = flags; + break; + } + + int changed_flags = flags ^ old_flags; + + // Turn special key flags off + if (changed_flags & NSShiftKeyMask) + evUp->keyname = "Shift_L"; + else if (changed_flags & NSControlKeyMask) + evUp->keyname = "Control_L"; + else if (changed_flags & NSAlternateKeyMask) + evUp->keyname = "Alt_L"; + else if (changed_flags & NSCommandKeyMask) + evUp->keyname = "Super_L"; + else if (changed_flags & NSAlphaShiftKeyMask) + evUp->keyname = "Caps_Lock"; + + if (evUp->keyname) + { + evUp->timestamp = time; + evUp->string = ""; + ecore_event_add(ECORE_EVENT_KEY_UP, evUp, NULL, NULL); + old_flags = flags; + break; + } + + break; + } + case NSAppKitDefined: + { + if ([event subtype] == NSApplicationActivatedEventType) + ecore_event_add(ECORE_COCOA_EVENT_GOT_FOCUS, NULL, NULL, NULL); + else if ([event subtype] == NSApplicationDeactivatedEventType) + ecore_event_add(ECORE_COCOA_EVENT_LOST_FOCUS, NULL, NULL, NULL); + [NSApp sendEvent:event]; // pass along AppKit events, for window manager + break; + } + case NSScrollWheel: + { + break; + } + default: + { + [NSApp sendEvent:event]; + break; + } + } + + [event release]; +} diff --git a/src/lib/ecore_cocoa/ecore_cocoa_private.h b/src/lib/ecore_cocoa/ecore_cocoa_private.h new file mode 100644 index 0000000..0b4cf31 --- /dev/null +++ b/src/lib/ecore_cocoa/ecore_cocoa_private.h @@ -0,0 +1,11 @@ +#ifndef _ECORE_COCOA_PRIVATE_H +#define _ECORE_COCOA_PRIVATE_H + +struct _Ecore_Cocoa_Window +{ + NSWindow *window; + unsigned int borderless : 1; +}; + + +#endif diff --git a/src/lib/ecore_cocoa/ecore_cocoa_window.m b/src/lib/ecore_cocoa/ecore_cocoa_window.m new file mode 100644 index 0000000..2091a69 --- /dev/null +++ b/src/lib/ecore_cocoa/ecore_cocoa_window.m @@ -0,0 +1,163 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "Ecore_Cocoa.h" +#include "ecore_cocoa_private.h" + +Ecore_Cocoa_Window * +ecore_cocoa_window_new(int x, + int y, + int width, + int height) +{ + Ecore_Cocoa_Window *w; + + NSWindow *window = [[NSWindow alloc] + initWithContentRect:NSMakeRect(x, y, width, height) + styleMask:(NSTitledWindowMask | + NSClosableWindowMask | + NSResizableWindowMask | + NSMiniaturizableWindowMask) + backing:NSBackingStoreBuffered + defer:NO + screen:nil + ]; + + if (!window) + return NULL; + + [window setBackgroundColor:[NSColor whiteColor]]; + + w = calloc(1, sizeof(Ecore_Cocoa_Window)); + w->window = window; + w->borderless = 0; + + return w; +} + +void +ecore_cocoa_window_free(Ecore_Cocoa_Window *window) +{ + if (!window) + return; + + [window->window release]; + free(window); +} + +void +ecore_cocoa_window_move(Ecore_Cocoa_Window *window, + int x, + int y) +{ + NSRect win_frame; + + if (!window) + return; + + win_frame = [window->window frame]; + win_frame.origin.x = x; + win_frame.origin.y = y; + + [window->window setFrame:win_frame display:YES]; +} + +void +ecore_cocoa_window_resize(Ecore_Cocoa_Window *window, + int width, + int height) +{ + if (!window) + return; + + NSRect win_frame; + + if (!window) + return; + + win_frame = [window->window frame]; + win_frame.size.height = height; + win_frame.size.width = width; + + [window->window setFrame:win_frame display:YES]; +} + +void +ecore_cocoa_window_move_resize(Ecore_Cocoa_Window *window, + int x, + int y, + int width, + int height) +{ + if (!window) + return; + + NSRect win_frame; + + if (!window) + return; + + win_frame = [window->window frame]; + win_frame.size.height = height; + win_frame.size.width = width; + win_frame.origin.x = x; + win_frame.origin.y = y; + + [window->window setFrame:win_frame display:YES]; +} + +void +ecore_cocoa_window_title_set(Ecore_Cocoa_Window *window, const char *title) +{ + if (!window || !title) + return; + + [window->window setTitle:[NSString stringWithUTF8String:title]]; +} + +void +ecore_cocoa_window_show(Ecore_Cocoa_Window *window) +{ + if (!window || [window->window isVisible]) + { + printf("Window(%p) is not visible\n", window->window); + return; + } + + [window->window makeKeyAndOrderFront:NSApp]; +} + +void +ecore_cocoa_window_hide(Ecore_Cocoa_Window *window) +{ + if (!window || ![window->window isVisible]) + return; + + [window->window orderOut:NSApp]; +} + +void +ecore_cocoa_window_borderless_set(Ecore_Cocoa_Window *window, + int on) +{ + if (!window) + return; + + if (on) + [window->window setContentBorderThickness:0.0 + forEdje:NSMinXEdge | NSMinYEdge | NSMaxXEdge | NSMaxYEdge]; +} + +void +ecore_cocoa_window_view_set(Ecore_Cocoa_Window *window, + void *view) +{ + if (!window || !view) + return; + + [[window->window contentView] addSubview:view]; + +} diff --git a/src/lib/ecore_con/Ecore_Con.h b/src/lib/ecore_con/Ecore_Con.h new file mode 100644 index 0000000..0a832fc --- /dev/null +++ b/src/lib/ecore_con/Ecore_Con.h @@ -0,0 +1,1948 @@ +#ifndef _ECORE_CON_H +#define _ECORE_CON_H + +#include +#include +#ifdef _WIN32 +# include +#else +# include +#endif +#include + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_ECORE_CON_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif +# else +# define EAPI __declspec(dllimport) +# endif +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif + +/** + * @defgroup Ecore_Con_Group Ecore_Con - Connection functions + * + * The Ecore Connection Library ( @c Ecore_Con ) provides simple mechanisms + * for communications between programs using reliable sockets. It saves + * the programmer from having to worry about file descriptors and waiting + * for incoming connections. + * + * There are two main objects in the @c Ecore_Con library: the @c + * Ecore_Con_Server and the @c Ecore_Con_Client. + * + * The @c Ecore_Con_Server represents a server that can be connected to. + * It is used regardless of whether the program is acting as a server or + * client itself. + * + * To create a listening server call @c ecore_con_server_add(), optionally using + * an ECORE_CON_USE_* encryption type OR'ed with the type for encryption. + * + * To connect to a server, call @c ecore_con_server_connect(). Data can + * then be sent to the server using the @c ecore_con_server_send(). + * + * Functions are described in the following groupings: + * @li @ref Ecore_Con_Lib_Group + * @li @ref Ecore_Con_Server_Group + * @li @ref Ecore_Con_Client_Group + * @li @ref Ecore_Con_Url_Group + * + * Events are described in @ref Ecore_Con_Events_Group. + */ + + +/** + * @defgroup Ecore_Con_Events_Group Ecore Connection Events Functions + * + * @li ECORE_CON_CLIENT_ADD: Whenever a client connection is made to an + * @c Ecore_Con_Server, an event of this type is emitted, allowing the + * retrieval of the client's ip with @ref ecore_con_client_ip_get and + * associating data with the client using ecore_con_client_data_set. + * @li ECORE_CON_EVENT_CLIENT_DEL: Whenever a client connection to an + * @c Ecore_Con_Server, an event of this type is emitted. The contents of + * the data with this event are variable, but if the client object in the data + * is non-null, it must be freed with @ref ecore_con_client_del. + * @li ECORE_CON_EVENT_SERVER_ADD: Whenever a server object is created + * with @ref ecore_con_server_connect, an event of this type is emitted, + * allowing for data to be serialized and sent to the server using + * @ref ecore_con_server_send. At this point, the http handshake has + * occurred. + * @li ECORE_CON_EVENT_SERVER_DEL: Whenever a server object is destroyed, + * usually by the server connection being refused or dropped, an event of this + * type is emitted. The contents of the data with this event are variable, + * but if the server object in the data is non-null, it must be freed + * with @ref ecore_con_server_del. + * @li ECORE_CON_EVENT_CLIENT_DATA: Whenever a client connects to your server + * object and sends data, an event of this type is emitted. The data will contain both + * the size and contents of the message sent by the client. It should be noted that + * data within this object is transient, so it must be duplicated in order to be + * retained. This event will continue to occur until the client has stopped sending its + * message, so a good option for storing this data is an Eina_Strbuf. Once the message has + * been received in full, the client object must be freed with ecore_con_client_free. + * @li ECORE_CON_EVENT_SERVER_DATA: Whenever your server object connects to its destination + * and receives data, an event of this type is emitted. The data will contain both + * the size and contents of the message sent by the server. It should be noted that + * data within this object is transient, so it must be duplicated in order to be + * retained. This event will continue to occur until the server has stopped sending its + * message, so a good option for storing this data is an Eina_Strbuf. Once the message has + * been received in full, the server object must be freed with ecore_con_server_free. + * + */ + +/** + * @defgroup Ecore_Con_Buffer Ecore Connection Buffering + * + * As Ecore_Con works on an event driven design, as data arrives, events will + * be produced containing the data that arrived. It is up to the user of + * Ecore_Con to either parse as they go, append to a file to later parse the + * whole file in one go, or append to memory to parse or handle leter. + * + * To help with this Eina has some handy API's. The Eina_Binbuf and + * Eina_Strbuf APIs, abstract dynamic buffer management and make it trivial + * to handle buffers at runtime, without having to manage them. Eina_Binbuf + * makes it possible to create, expand, reset and slice a blob of memory - + * all via API. No system calls, no pointer manipulations and no size + * calculation. + * + * Additional functions include adding content at specified byte positions in + * the buffer, escaping the inputs, find and replace strings. This provides + * extreme flexibility to play around, with a dynamic blob of memory. + * + * It is good to free it (using eina_binbuf_free()) after using it. + * + * Eina_Binbuf compliments Ecore_Con use cases, where dynamic sizes of data + * arrive from the network (think http download in chunks). Using + * Eina_Binbuf provides enough flexibility to handle data as it arrives and + * to defer its processing until desired, without having to think about + * where to store the temporary data and how to manage its size. + * + * An example of how to use these with Ecore_Con follows. + * + * @code + * #include + * #include + * #include + * + * static Eina_Bool + * data_callback(void *data, int type, void *event) + * { + * Ecore_Con_Event_Url_Data *url_data = event; + * if ( url_data->size > 0) + * { + * // append data as it arrives - don't worry where or how it gets stored. + * // Also don't worry about size, expanding, reallocing etc. + * // just keep appending - size is automatically handled. + * + * eina_binbuf_append_length(data, url_data->data, url_data->size); + * + * fprintf(stderr, "Appended %d \n", url_data->size); + * } + * return EINA_TRUE; + * } + * + * + * + * static Eina_Bool + * completion_callback(void *data, int type, void *event) + * { + * Ecore_Con_Event_Url_Complete *url_complete = event; + * printf("download completed with status code: %d\n", url_complete->status); + * + * // get the data back from Eina_Binbuf + * char *ptr = eina_binbuf_string_get(data); + * size_t size = eina_binbuf_length_get(data); + * + * // process data as required (write to file) + * fprintf(stderr, "Size of data = %d bytes\n", size); + * int fd = open("./elm.png", O_CREAT); + * write(fd, ptr, size); + * close(fd); + * + * // free it when done. + * eina_binbuf_free(data); + * + * ecore_main_loop_quit(); + * + * return EINA_TRUE; + * } + * + * + * int + * main(int argc, char **argv) + * { + * + * const char *url = "http://www.enlightenment.org/p/index/d/logo.png"; + * + * ecore_init(); + * ecore_con_init(); + * ecore_con_url_init(); + * + * + * // This is single additional line to manage dynamic network data. + * Eina_Binbuf *data = eina_binbuf_new(); + * Ecore_Con_Url *url_con = ecore_con_url_new(url); + * + * ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, + * completion_callback, + * data); + * ecore_event_handler_add(ECORE_CON_EVENT_URL_DATA, + * data_callback, + * data); + * ecore_con_url_get(url_con); + * + * ecore_main_loop_begin(); + * return 0; + * } + * @endcode + */ + +#ifdef __cplusplus +extern "C" { +#endif +#define ECORE_CON_USE_SSL ECORE_CON_USE_SSL2 +#define ECORE_CON_REMOTE_SYSTEM ECORE_CON_REMOTE_TCP + + +/** + * @typedef Ecore_Con_Server + * A connection handle to a server + * @ingroup Ecore_Con_Server_Group + */ +typedef struct _Ecore_Con_Server Ecore_Con_Server; + +/** + * @typedef Ecore_Con_Client + * A connection handle to a client + * @ingroup Ecore_Con_Client_Group + */ +typedef struct _Ecore_Con_Client Ecore_Con_Client; + +/** + * @typedef Ecore_Con_Socks + * An object representing a SOCKS proxy + * @ingroup Ecore_Con_Socks_Group + * @since 1.2 + */ +typedef struct Ecore_Con_Socks Ecore_Con_Socks; + +/** + * @typedef Ecore_Con_Url + * A handle to an http upload/download object + * @ingroup Ecore_Con_Url_Group + */ +typedef struct _Ecore_Con_Url Ecore_Con_Url; + + +/** + * @addtogroup Ecore_Con_Events_Group + * @{ + */ + +/** + * @typedef Ecore_Con_Event_Client_Add + * Used as the @p data param for the corresponding event + */ +typedef struct _Ecore_Con_Event_Client_Add Ecore_Con_Event_Client_Add; + +/** + * @typedef Ecore_Con_Event_Client_Upgrade + * Used as the @p data param for the corresponding event + * @since 1.1 + */ +typedef struct _Ecore_Con_Event_Client_Upgrade Ecore_Con_Event_Client_Upgrade; + +/** + * @typedef Ecore_Con_Event_Client_Del + * Used as the @p data param for the corresponding event + */ +typedef struct _Ecore_Con_Event_Client_Del Ecore_Con_Event_Client_Del; + +/** + * @typedef Ecore_Con_Event_Client_Error + * Used as the @p data param for the corresponding event + * @since 1.1 + */ +typedef struct _Ecore_Con_Event_Client_Error Ecore_Con_Event_Client_Error; + +/** + * @typedef Ecore_Con_Event_Server_Add + * Used as the @p data param for the corresponding event + */ +typedef struct _Ecore_Con_Event_Server_Add Ecore_Con_Event_Server_Add; + +/** + * @typedef Ecore_Con_Event_Server_Upgrade + * Used as the @p data param for the corresponding event + * @since 1.1 + */ +typedef struct _Ecore_Con_Event_Server_Upgrade Ecore_Con_Event_Server_Upgrade; + +/** + * @typedef Ecore_Con_Event_Server_Del + * Used as the @p data param for the corresponding event + */ +typedef struct _Ecore_Con_Event_Server_Del Ecore_Con_Event_Server_Del; + +/** + * @typedef Ecore_Con_Event_Server_Error + * Used as the @p data param for the corresponding event + * @since 1.1 + */ +typedef struct _Ecore_Con_Event_Server_Error Ecore_Con_Event_Server_Error; + +/** + * @typedef Ecore_Con_Event_Client_Data + * Used as the @p data param for the corresponding event + */ +typedef struct _Ecore_Con_Event_Client_Data Ecore_Con_Event_Client_Data; + +/** + * @typedef Ecore_Con_Event_Server_Data + * Used as the @p data param for the corresponding event + */ +typedef struct _Ecore_Con_Event_Server_Data Ecore_Con_Event_Server_Data; + +/** + * @typedef Ecore_Con_Event_Client_Write + * Used as the @p data param for the corresponding event + * @since 1.1 + */ +typedef struct _Ecore_Con_Event_Client_Write Ecore_Con_Event_Client_Write; + +/** + * @typedef Ecore_Con_Event_Server_Write + * Used as the @p data param for the corresponding event + * @since 1.1 + */ +typedef struct _Ecore_Con_Event_Server_Write Ecore_Con_Event_Server_Write; + +/** + * @typedef Ecore_Con_Event_Proxy_Bind + * Used as the @p data param for the corresponding event + * @since 1.2 + */ +typedef struct _Ecore_Con_Event_Proxy_Bind Ecore_Con_Event_Proxy_Bind; + +/** + * @typedef Ecore_Con_Event_Url_Data + * Used as the @p data param for the corresponding event + * @ingroup Ecore_Con_Url_Group + */ +typedef struct _Ecore_Con_Event_Url_Data Ecore_Con_Event_Url_Data; + +/** + * @typedef Ecore_Con_Event_Url_Complete + * Used as the @p data param for the corresponding event + * @ingroup Ecore_Con_Url_Group + */ +typedef struct _Ecore_Con_Event_Url_Complete Ecore_Con_Event_Url_Complete; + +/** + * @typedef Ecore_Con_Event_Url_Progress + * Used as the @p data param for the corresponding event + * @ingroup Ecore_Con_Url_Group + */ +typedef struct _Ecore_Con_Event_Url_Progress Ecore_Con_Event_Url_Progress; + +/** + * @struct _Ecore_Con_Event_Client_Add + * Used as the @p data param for the @ref ECORE_CON_EVENT_CLIENT_ADD event + */ +struct _Ecore_Con_Event_Client_Add +{ + Ecore_Con_Client *client; /** the client that connected */ +}; + +/** + * @struct _Ecore_Con_Event_Client_Upgrade + * Used as the @p data param for the @ref ECORE_CON_EVENT_CLIENT_UPGRADE event + * @since 1.1 + */ +struct _Ecore_Con_Event_Client_Upgrade +{ + Ecore_Con_Client *client; /** the client that completed handshake */ +}; + +/** + * @struct _Ecore_Con_Event_Client_Del + * Used as the @p data param for the @ref ECORE_CON_EVENT_CLIENT_DEL event + */ +struct _Ecore_Con_Event_Client_Del +{ + Ecore_Con_Client *client; /** the client that was lost */ +}; + +/** + * @struct _Ecore_Con_Event_Client_Error + * Used as the @p data param for the @ref ECORE_CON_EVENT_CLIENT_ERROR event + */ +struct _Ecore_Con_Event_Client_Error +{ + Ecore_Con_Client *client; /** the client for which an error occurred */ + char *error; /**< the error string describing what happened */ +}; + +/** + * @struct _Ecore_Con_Event_Server_Add + * Used as the @p data param for the @ref ECORE_CON_EVENT_SERVER_ADD event + */ +struct _Ecore_Con_Event_Server_Add +{ + Ecore_Con_Server *server; /** the server that was connected to */ +}; + +/** + * @struct _Ecore_Con_Event_Server_Upgrade + * Used as the @p data param for the @ref ECORE_CON_EVENT_SERVER_UPGRADE event + * @since 1.1 + */ +struct _Ecore_Con_Event_Server_Upgrade +{ + Ecore_Con_Server *server; /** the server that was connected to */ +}; + +/** + * @struct _Ecore_Con_Event_Server_Del + * Used as the @p data param for the @ref ECORE_CON_EVENT_SERVER_DEL event + */ +struct _Ecore_Con_Event_Server_Del +{ + Ecore_Con_Server *server; /** the client that was lost */ +}; + +/** + * @struct _Ecore_Con_Event_Server_Error + * Used as the @p data param for the @ref ECORE_CON_EVENT_SERVER_ERROR event + */ +struct _Ecore_Con_Event_Server_Error +{ + Ecore_Con_Server *server; /** the server for which an error occurred */ + char *error; /**< the error string describing what happened */ +}; + +/** + * @struct _Ecore_Con_Event_Client_Data + * Used as the @p data param for the @ref ECORE_CON_EVENT_CLIENT_DATA event + */ +struct _Ecore_Con_Event_Client_Data +{ + Ecore_Con_Client *client; /**< the client that connected */ + void *data; /**< the data that the client sent */ + int size; /**< the length of the data sent */ +}; + +/** + * @struct _Ecore_Con_Event_Server_Data + * Used as the @p data param for the @ref ECORE_CON_EVENT_SERVER_DATA event + */ +struct _Ecore_Con_Event_Server_Data +{ + Ecore_Con_Server *server; /**< the server that was connected to */ + void *data; /**< the data that the server sent */ + int size; /**< the length of the data sent */ +}; + +/** + * @struct _Ecore_Con_Event_Client_Write + * Used as the @p data param for the @ref ECORE_CON_EVENT_CLIENT_WRITE event + */ +struct _Ecore_Con_Event_Client_Write +{ + Ecore_Con_Client *client; /**< the client that connected */ + int size; /**< the length of the data sent */ +}; + +/** + * @struct _Ecore_Con_Event_Server_Write + * Used as the @p data param for the @ref ECORE_CON_EVENT_SERVER_WRITE event + */ +struct _Ecore_Con_Event_Server_Write +{ + Ecore_Con_Server *server; /**< the server that was connected to */ + int size; /**< the length of the data sent */ +}; + +/** + * @struct _Ecore_Con_Event_Proxy_Bind + * Used as the @p data param for the @ref ECORE_CON_EVENT_PROXY_BIND event + * @ingroup Ecore_Con_Socks_Group + * @since 1.2 + */ +struct _Ecore_Con_Event_Proxy_Bind +{ + Ecore_Con_Server *server; /**< the server object connected to the proxy */ + const char *ip; /**< the proxy-bound ip address */ + int port; /**< the proxy-bound port */ +}; + +/** + * @struct _Ecore_Con_Event_Url_Data + * Used as the @p data param for the @ref ECORE_CON_EVENT_URL_DATA event + * @ingroup Ecore_Con_Url_Group + */ +struct _Ecore_Con_Event_Url_Data +{ + Ecore_Con_Url *url_con; /**< a pointer to the connection object */ + int size; /**< the size of the current received data (in bytes) */ + unsigned char data[1]; /**< the data received on this event */ +}; + +/** + * @struct _Ecore_Con_Event_Url_Complete + * Used as the @p data param for the @ref ECORE_CON_EVENT_URL_COMPLETE event + * @ingroup Ecore_Con_Url_Group + */ +struct _Ecore_Con_Event_Url_Complete +{ + Ecore_Con_Url *url_con; /**< a pointer to the connection object */ + int status; /**< HTTP status code of the operation (200, 404, 401, etc.) */ +}; + +/** + * @struct _Ecore_Con_Event_Url_Progress + * Used as the @p data param for the @ref ECORE_CON_EVENT_URL_PROGRESS event + * @ingroup Ecore_Con_Url_Group + */ +struct _Ecore_Con_Event_Url_Progress +{ + Ecore_Con_Url *url_con; /**< a pointer to the connection object */ + struct + { + double total; /**< total size of the downloading data (in bytes) */ + double now; /**< current size of the downloading data (in bytes) */ + } down; /**< download info */ + struct + { + double total; /**< total size of the uploading data (in bytes) */ + double now; /**< current size of the uploading data (in bytes) */ + } up; /**< upload info */ +}; + +/** A client has connected to the server */ +EAPI extern int ECORE_CON_EVENT_CLIENT_ADD; +/** A client has disconnected from the server */ +EAPI extern int ECORE_CON_EVENT_CLIENT_DEL; +/** A client experienced an error + * @since 1.1 + */ +EAPI extern int ECORE_CON_EVENT_CLIENT_ERROR; +/** A client connection has been upgraded to SSL + * @since 1.1 + */ +EAPI extern int ECORE_CON_EVENT_CLIENT_UPGRADE; +/** A server was created */ +EAPI extern int ECORE_CON_EVENT_SERVER_ADD; +/** A server connection was lost */ +EAPI extern int ECORE_CON_EVENT_SERVER_DEL; +/** A server experienced an error + * @since 1.1 + */ +EAPI extern int ECORE_CON_EVENT_SERVER_ERROR; +/** A server connection has been upgraded to SSL + * @since 1.1 + */ +EAPI extern int ECORE_CON_EVENT_SERVER_UPGRADE; +/** A server connection has sent data to its client + * @since 1.1 + */ +EAPI extern int ECORE_CON_EVENT_CLIENT_WRITE; +/** A server connection object has sent data + * @since 1.1 + */ +EAPI extern int ECORE_CON_EVENT_SERVER_WRITE; +/** A client connected to the server has sent data */ +EAPI extern int ECORE_CON_EVENT_CLIENT_DATA; +/** A server connection object has data */ +EAPI extern int ECORE_CON_EVENT_SERVER_DATA; +/** A server connection has successfully negotiated an ip:port binding + * @since 1.2 + */ +EAPI extern int ECORE_CON_EVENT_PROXY_BIND; +/** A URL object has data */ +EAPI extern int ECORE_CON_EVENT_URL_DATA; +/** A URL object has completed its transfer to and from the server and can be reused */ +EAPI extern int ECORE_CON_EVENT_URL_COMPLETE; +/** A URL object has made progress in its transfer */ +EAPI extern int ECORE_CON_EVENT_URL_PROGRESS; + +/** + * @} + */ + +/** + * @defgroup Ecore_Con_Lib_Group Ecore Connection Library Functions + * + * Utility functions that set up and shut down the Ecore Connection + * library. + * + * There's also ecore_con_lookup() that can be used to make simple asynchronous + * DNS lookups. + * + * A simple example of how to use these functions: + * @li @ref ecore_con_lookup_example_c + * + * @{ + */ + +/** + * @typedef Ecore_Con_Dns_Cb + * A callback type for use with @ref ecore_con_lookup. + */ +typedef void (*Ecore_Con_Dns_Cb)(const char *canonname, + const char *ip, + struct sockaddr *addr, + int addrlen, + void *data); + +/** + * @typedef Ecore_Con_Type + * @enum _Ecore_Con_Type + * Types for an ecore_con client/server object. A correct way to set this type is + * with an ECORE_CON_$TYPE, optionally OR'ed with an ECORE_CON_$USE if encryption is desired, + * and LOAD_CERT if the previously loaded certificate should be used. + * @code + * ECORE_CON_REMOTE_TCP | ECORE_CON_USE_TLS | ECORE_CON_LOAD_CERT + * @endcode + * @ingroup Ecore_Con_Server_Group + */ +typedef enum _Ecore_Con_Type +{ + /** Socket in ~/.ecore */ + ECORE_CON_LOCAL_USER = 0, + /** Socket in /tmp */ + ECORE_CON_LOCAL_SYSTEM = 1, + /** Abstract socket */ + ECORE_CON_LOCAL_ABSTRACT = 2, + /** Remote server using TCP */ + ECORE_CON_REMOTE_TCP = 3, + /** Remote multicast server */ + ECORE_CON_REMOTE_MCAST = 4, + /** Remote server using UDP */ + ECORE_CON_REMOTE_UDP = 5, + /** Remote broadcast using UDP */ + ECORE_CON_REMOTE_BROADCAST = 6, + /** Remote connection sending packets immediately */ + ECORE_CON_REMOTE_NODELAY = 7, + /** Remote connection sending data in large chunks + * @note Only available on Linux + * @since 1.2 + */ + ECORE_CON_REMOTE_CORK = 8, + /** Use SSL2: UNSUPPORTED. **/ + ECORE_CON_USE_SSL2 = (1 << 4), + /** Use SSL3 */ + ECORE_CON_USE_SSL3 = (1 << 5), + /** Use TLS */ + ECORE_CON_USE_TLS = (1 << 6), + /** Use both TLS and SSL3 */ + ECORE_CON_USE_MIXED = ECORE_CON_USE_SSL3 | ECORE_CON_USE_TLS, + /** Attempt to use the loaded certificate */ + ECORE_CON_LOAD_CERT = (1 << 7), + /** Disable all types of proxy on the server + * @note Only functional for clients + * @since 1.2 + */ + ECORE_CON_NO_PROXY = (1 << 8) +} Ecore_Con_Type; + +/** + * Initialises the Ecore_Con library. + * @return Number of times the library has been initialised without being + * shut down. + * + * @note This function already calls ecore_init() internally, so you don't need + * to call it explicitly. + */ +EAPI int ecore_con_init(void); + +/** + * Shuts down the Ecore_Con library. + * @return Number of times the library has been initialised without being + * shut down. + * @note This function already calls ecore_shutdown() internally, so you don't + * need to call it explicitly unless you called ecore_init() explicitly too. + */ +EAPI int ecore_con_shutdown(void); + +/** + * Do an asynchronous DNS lookup. + * + * @param name IP address or server name to translate. + * @param done_cb Callback to notify when done. + * @param data User data to be given to done_cb. + * @return @c EINA_TRUE if the request did not fail to be set up, @c EINA_FALSE + * if it failed. + * + * This function performs a DNS lookup on the hostname specified by @p name, + * then calls @p done_cb with the result and the @p data given as parameter. + * The result will be given to the @p done_cb as follows: + * @li @c canonname - the canonical name of the address + * @li @c ip - the resolved ip address + * @li @c addr - a pointer to the socket address + * @li @c addrlen - the length of the socket address, in bytes + * @li @c data - the data pointer given as parameter to ecore_con_lookup() + */ +EAPI Eina_Bool ecore_con_lookup(const char *name, + Ecore_Con_Dns_Cb done_cb, + const void *data); + +/** + * @} + */ + +/** + * @defgroup Ecore_Con_SSL_Group Ecore Connection SSL Functions + * + * @{ + */ +EAPI int ecore_con_ssl_available_get(void); +EAPI Eina_Bool ecore_con_ssl_server_cert_add(Ecore_Con_Server *svr, const char *cert); +EAPI Eina_Bool ecore_con_ssl_server_privkey_add(Ecore_Con_Server *svr, const char *key_file); +EAPI Eina_Bool ecore_con_ssl_server_crl_add(Ecore_Con_Server *svr, const char *crl_file); +EAPI Eina_Bool ecore_con_ssl_server_cafile_add(Ecore_Con_Server *svr, const char *ca_file); +EAPI void ecore_con_ssl_server_verify(Ecore_Con_Server *svr); +EAPI void ecore_con_ssl_server_verify_basic(Ecore_Con_Server *svr); +EAPI void ecore_con_ssl_server_verify_name_set(Ecore_Con_Server *svr, const char *name); +EAPI const char *ecore_con_ssl_server_verify_name_get(Ecore_Con_Server *svr); +EAPI Eina_Bool ecore_con_ssl_server_upgrade(Ecore_Con_Server *svr, Ecore_Con_Type compl_type); +EAPI Eina_Bool ecore_con_ssl_client_upgrade(Ecore_Con_Client *cl, Ecore_Con_Type compl_type); + +/** + * @} + */ + +EAPI Ecore_Con_Socks *ecore_con_socks4_remote_add(const char *ip, int port, const char *username); +EAPI Eina_Bool ecore_con_socks4_remote_exists(const char *ip, int port, const char *username); +EAPI void ecore_con_socks4_remote_del(const char *ip, int port, const char *username); +EAPI Ecore_Con_Socks *ecore_con_socks5_remote_add(const char *ip, int port, const char *username, const char *password); +EAPI Eina_Bool ecore_con_socks5_remote_exists(const char *ip, int port, const char *username, const char *password); +EAPI void ecore_con_socks5_remote_del(const char *ip, int port, const char *username, const char *password); +EAPI void ecore_con_socks_lookup_set(Ecore_Con_Socks *ecs, Eina_Bool enable); +EAPI Eina_Bool ecore_con_socks_lookup_get(Ecore_Con_Socks *ecs); +EAPI void ecore_con_socks_bind_set(Ecore_Con_Socks *ecs, Eina_Bool is_bind); +EAPI Eina_Bool ecore_con_socks_bind_get(Ecore_Con_Socks *ecs); +EAPI unsigned int ecore_con_socks_version_get(Ecore_Con_Socks *ecs); +EAPI void ecore_con_socks_remote_del(Ecore_Con_Socks *ecs); +EAPI void ecore_con_socks_apply_once(Ecore_Con_Socks *ecs); +EAPI void ecore_con_socks_apply_always(Ecore_Con_Socks *ecs); + +/** + * @defgroup Ecore_Con_Server_Group Ecore Connection Server Functions + * + * This group of functions is applied to an @ref Ecore_Con_Server object. It + * doesn't mean that they should be used in the server application, but on the + * server object. In fact, most of them should be used in the client + * application, when retrieving information or sending data. + * + * Setting up a server is very simple: you just need to start it with + * ecore_con_server_add() and setup some callbacks to the events + * @ref ECORE_CON_EVENT_CLIENT_ADD, @ref ECORE_CON_EVENT_CLIENT_DEL and + * @ref ECORE_CON_EVENT_CLIENT_DATA, that will be called when a client is + * communicating with the server: + * + * @code + * if (!(svr = ecore_con_server_add(ECORE_CON_REMOTE_TCP, "127.0.0.1", 8080, NULL))) + * exit(1); + * + * ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_ADD, _add_cb, NULL); + * ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DEL, _del_cb, NULL); + * ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DATA, _data_cb, NULL); + * + * ecore_main_loop_begin(); + * @endcode + * + * The function ecore_con_server_connect() can be used to write a client that + * connects to a server. The resulting code will be very similar to the server + * code: + * + * @code + * if (!(svr = ecore_con_server_connect(ECORE_CON_REMOTE_TCP, "127.0.0.1", 8080, NULL))) + * exit(1); + * + * ecore_event_handler_add(ECORE_CON_EVENT_SERVER_ADD, _add_cb, NULL); + * ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DEL, _del_cb, NULL); + * ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DATA, _data_cb, NULL); + * + * ecore_main_loop_begin(); + * @endcode + * + * After these two pieces of code are executed, respectively, in the server and + * client code, the server will be up and running and the client will try to + * connect to it. The connection, with its subsequent messages being sent from + * server to client and client to server, can be represented in the following + * sequence diagram: + * + * @htmlonly + * + * Full size + * @endhtmlonly + * + * @image rtf ecore_con-client-server.png + * @image latex ecore_con-client-server.eps width=\textwidth + * + * Please notice the important difference between these two codes: the first is + * used for writing a @b server, while the second should be used for writing a + * @b client. + * + * A reference for the @c client functions can be found at @ref + * Ecore_Con_Client_Group. + * + * Examples of usage for this API can be found here: + * @li @ref ecore_con_server_simple_example_c + * @li @ref ecore_con_client_simple_example_c + * + * @{ + */ + +/** + * Creates a server to listen for connections. + * + * @param type The connection type. + * @param name Name to associate with the socket. It is used when + * generating the socket name of a Unix socket, or for + * determining what host to listen on for TCP sockets. + * @c NULL will not be accepted. + * @param port Number to identify socket. When a Unix socket is used, + * it becomes part of the socket name. When a TCP socket + * is used, it is used as the TCP port. + * @param data Data to associate with the created Ecore_Con_Server + * object. + * @return A new Ecore_Con_Server. + * + * The socket on which the server listens depends on the connection + * type: + * @li If @a type is @c ECORE_CON_LOCAL_USER, the server will listen on + * the Unix socket "~/.ecore/[name]/[port]". + * @li If @a type is @c ECORE_CON_LOCAL_SYSTEM, the server will listen + * on Unix socket "/tmp/.ecore_service|[name]|[port]". + * @li If @a type is @c ECORE_CON_REMOTE_TCP, the server will listen + * on TCP port @c port. + * + * More information about the @p type can be found at @ref _Ecore_Con_Type. + * + * The @p data parameter can be fetched later using ecore_con_server_data_get() + * or changed with ecore_con_server_data_set(). + */ +EAPI Ecore_Con_Server *ecore_con_server_add(Ecore_Con_Type type, + const char *name, int port, + const void *data); + +/** + * Creates a connection to the specified server and returns an associated object. + * + * @param type The connection type. + * @param name Name used when determining what socket to connect to. + * It is used to generate the socket name when the socket + * is a Unix socket. It is used as the hostname when + * connecting with a TCP socket. + * @param port Number to identify the socket to connect to. Used when + * generating the socket name for a Unix socket, or as the + * TCP port when connecting to a TCP socket. + * @param data Data to associate with the created Ecore_Con_Server + * object. + * @return A new Ecore_Con_Server. + * + * The socket to which the connection is made depends on the connection type: + * @li If @a type is @c ECORE_CON_LOCAL_USER, the function will + * connect to the server at the Unix socket + * "~/.ecore/[name]/[port]". + * @li If @a type is @c ECORE_CON_LOCAL_SYSTEM, the function will + * connect to the server at the Unix socket + * "/tmp/.ecore_service|[name]|[port]". + * @li If @a type is @c ECORE_CON_REMOTE_TCP, the function will + * connect to the server at the TCP port "[name]:[port]". + * + * More information about the @p type can be found at @ref _Ecore_Con_Type. + * + * This function won't block. It will either succeed, or fail due to invalid + * parameters, failed memory allocation, etc., returning @c NULL on that case. + * + * However, even if this call returns a valid @ref Ecore_Con_Server, the + * connection will only be successfully completed if an event of type + * @ref ECORE_CON_EVENT_SERVER_ADD is received. If it fails to complete, an + * @ref ECORE_CON_EVENT_SERVER_DEL will be received. + * + * The @p data parameter can be fetched later using ecore_con_server_data_get() + * or changed with ecore_con_server_data_set(). + */ +EAPI Ecore_Con_Server *ecore_con_server_connect(Ecore_Con_Type type, + const char *name, int port, + const void *data); +/** + * Closes the connection and frees the given server. + * + * @param svr The given server. + * @return Data associated with the server when it was created. + * + * All the clients connected to this server will be disconnected. + * + * @see ecore_con_server_add, ecore_con_server_connect + */ +EAPI void * ecore_con_server_del(Ecore_Con_Server *svr); + +/** + * Retrieves the data associated with the given server. + * + * @param svr The given server. + * @return The associated data. + * + * @see ecore_con_server_data_set() + */ +EAPI void * ecore_con_server_data_get(Ecore_Con_Server *svr); +/** + * Sets the data associated with the given server. + * + * @param svr The given server. + * @param data The data to associate with @p svr + * @return The previously associated data, if any. + * + * @see ecore_con_server_data_get() + */ +EAPI void * ecore_con_server_data_set(Ecore_Con_Server *svr, + void *data); +/** + * Retrieves whether the given server is currently connected. + * + * @param svr The given server. + * @return @c EINA_TRUE if the server is connected, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool ecore_con_server_connected_get(Ecore_Con_Server *svr); +/** + * Retrieves the current list of clients. + * + * @param svr The given server. + * @return The list of clients on this server. + * + * Each node in the returned list points to an @ref Ecore_Con_Client. This list + * cannot be modified or freed. It can also change if new clients are connected + * or disconnected, and will become invalid when the server is deleted/freed. + */ +EAPI const Eina_List * ecore_con_server_clients_get(Ecore_Con_Server *svr); + +/** + * Retrieves the name of server. + * + * @param svr The given server. + * @return The name of the server. + * + * The name returned is the name used to connect on this server. + */ +EAPI const char * ecore_con_server_name_get(Ecore_Con_Server *svr); + +/** + * Retrieves the server port in use. + * + * @param svr The given server. + * @return The server port in use. + * + * The port where the server is listening for connections. + */ +EAPI int ecore_con_server_port_get(Ecore_Con_Server *svr); +/** + * @brief Check how long a server has been connected + * + * @param svr The server to check + * @return The total time, in seconds, that the server has been + * connected/running + * + * This function is used to find out the time that has been elapsed since + * ecore_con_server_add() succeeded. + */ +EAPI double ecore_con_server_uptime_get(Ecore_Con_Server *svr); +/** + * Sends the given data to the given server. + * + * @param svr The given server. + * @param data The given data. + * @param size Length of the data, in bytes, to send. + * @return The number of bytes sent. @c 0 will be returned if there is an + * error. + * + * This function will send the given data to the server as soon as the program + * is back to the main loop. Thus, this function returns immediately + * (non-blocking). If the data needs to be sent @b now, call + * ecore_con_server_flush() after this one. + * + * @see ecore_con_client_send() + * @see ecore_con_server_flush() + */ +EAPI int ecore_con_server_send(Ecore_Con_Server *svr, + const void *data, + int size); +/** + * Sets a limit on the number of clients that can be handled concurrently + * by the given server, and a policy on what to do if excess clients try to + * connect. + * + * @param svr The given server. + * @param client_limit The maximum number of clients to handle + * concurrently. -1 means unlimited (default). 0 + * effectively disables the server. + * @param reject_excess_clients Set to 1 to automatically disconnect + * excess clients as soon as they connect if you are + * already handling client_limit clients. Set to 0 + * (default) to just hold off on the "accept()" + * system call until the number of active clients + * drops. This causes the kernel to queue up to 4096 + * connections (or your kernel's limit, whichever is + * lower). + * + * Beware that if you set this once ecore is already running, you may + * already have pending CLIENT_ADD events in your event queue. Those + * clients have already connected and will not be affected by this call. + * Only clients subsequently trying to connect will be affected. + */ +EAPI void ecore_con_server_client_limit_set(Ecore_Con_Server *svr, + int client_limit, + char reject_excess_clients); +/** + * Gets the IP address of a server that has been connected to. + * + * @param svr The given server. + * @return A pointer to an internal string that contains the IP address of + * the connected server in the form "XXX.YYY.ZZZ.AAA" IP notation. + * This string should not be modified or trusted to stay valid after + * deletion for the @p svr object. If no IP is known @c NULL is + * returned. + */ +EAPI const char * ecore_con_server_ip_get(Ecore_Con_Server *svr); +/** + * Flushes all pending data to the given server. + * + * @param svr The given server. + * + * This function will block until all data is sent to the server. + * + * @see ecore_con_server_send() + * @see ecore_con_client_flush() + */ +EAPI void ecore_con_server_flush(Ecore_Con_Server *svr); +/** + * Set the default time after which an inactive client will be disconnected + * + * @param svr The server object + * @param timeout The timeout, in seconds, to disconnect after + * + * This function is used by the server to set the default idle timeout on + * clients. If the any of the clients becomes idle for a time higher than this + * value, it will be disconnected. A value of < 1 disables the idle timeout. + * + * This timeout is not affected by the one set by + * ecore_con_client_timeout_set(). A client will be disconnected whenever the + * client or the server timeout is reached. That means, the lower timeout value + * will be used for that client if ecore_con_client_timeout_set() is used on it. + * + * @see ecore_con_server_timeout_get() + * @see ecore_con_client_timeout_set() + */ +EAPI void ecore_con_server_timeout_set(Ecore_Con_Server *svr, double timeout); +/** + * Get the default time after which an inactive client will be disconnected + * + * @param svr The server object + * @return The timeout, in seconds, to disconnect after + * + * This function is used to get the idle timeout for clients. A value of < 1 + * means the idle timeout is disabled. + * + * @see ecore_con_server_timeout_set() + * @see ecore_con_client_timeout_get() + */ +EAPI double ecore_con_server_timeout_get(Ecore_Con_Server *svr); + +/** + * Get the fd that the server is connected to + * + * @param svr The server object + * @return The fd, or -1 on failure + * + * This function returns the fd which is used by the underlying server connection. + * It should not be tampered with unless you REALLY know what you are doing. + * @note This function is only valid for servers created with ecore_con_server_connect() + * @warning Seriously. Don't use this unless you know what you are doing. + * @since 1.1 + */ +EAPI int ecore_con_server_fd_get(Ecore_Con_Server *svr); + +/** + * Get the fd that the client is connected to + * + * @param cl The client object + * @return The fd, or -1 on failure + * + * This function returns the fd which is used by the underlying client connection. + * It should not be tampered with unless you REALLY know what you are doing. + * @since 1.1 + */ +EAPI int ecore_con_client_fd_get(Ecore_Con_Client *cl); +/** + * @} + */ + +/** + * @defgroup Ecore_Con_Client_Group Ecore Connection Client Functions + * + * Functions to communicate with and/or set options on a client. + * + * This set of functions, as explained in @ref Ecore_Con_Server_Group, is used + * to send data to a client, or to set options and get information about this + * client. Most of them should be used on the server, applied on the client + * object. + * + * If you need to implement a client, the way to connect to a server is + * described in @ref Ecore_Con_Server_Group. + * + * An example of usage of these functions can be found at: + * @li @ref ecore_con_client_simple_example_c + * + * @{ + */ + +/** + * Sends the given data to the given client. + * + * @param cl The given client. + * @param data The given data. + * @param size Length of the data, in bytes, to send. + * @return The number of bytes sent. @c 0 will be returned if there is an + * error. + * + * This function will send the given data to the client as soon as the program + * is back to the main loop. Thus, this function returns immediately + * (non-blocking). If the data needs to be sent @b now, call + * ecore_con_client_flush() after this one. + * + * @see ecore_con_server_send() + * @see ecore_con_client_flush() + */ +EAPI int ecore_con_client_send(Ecore_Con_Client *cl, + const void *data, + int size); +/** + * Retrieves the server representing the socket the client has + * connected to. + * + * @param cl The given client. + * @return The server that the client connected to. + */ +EAPI Ecore_Con_Server *ecore_con_client_server_get(Ecore_Con_Client *cl); +/** + * Closes the connection and frees memory allocated to the given client. + * + * @param cl The given client. + * @return Data associated with the client. + */ +EAPI void * ecore_con_client_del(Ecore_Con_Client *cl); +/** + * Sets the data associated with the given client to @p data. + * + * @param cl The given client. + * @param data What to set the data to. + */ +EAPI void ecore_con_client_data_set(Ecore_Con_Client *cl, + const void *data); +/** + * Retrieves the data associated with the given client. + * + * @param cl The given client. + * @return The data associated with @p cl. + */ +EAPI void * ecore_con_client_data_get(Ecore_Con_Client *cl); + +/** + * Gets the IP address of a client that has connected. + * + * @param cl The given client. + * @return A pointer to an internal string that contains the IP address of + * the connected client in the form "XXX.YYY.ZZZ.AAA" IP notation. + * + * The returned string should not be modified, freed or trusted to stay valid + * after deletion for the @p cl object. If no IP is known @c NULL is returned. + */ +EAPI const char * ecore_con_client_ip_get(Ecore_Con_Client *cl); +/** + * Flushes all pending data to the given client. + * + * @param cl The given client. + * + * This function will block until all data is sent to the server. + * + * @see ecore_con_client_send() + * @see ecore_con_server_flush() + */ +EAPI void ecore_con_client_flush(Ecore_Con_Client *cl); +/** + * @brief Check how long a client has been connected + * + * @param cl The client to check + * @return The total time, in seconds, that the client has been connected to + * the server + * + * This function is used to find out how long a client has been connected for. + */ +EAPI double ecore_con_client_uptime_get(Ecore_Con_Client *cl); +/** + * Get the default time after which the client will be disconnected when + * inactive + * + * @param cl The client object + * @return The timeout, in seconds, to disconnect after + * + * This function is used to get the idle timeout for a client. A value of < 1 + * means the idle timeout is disabled. + * + * @see ecore_con_client_timeout_set() + */ +EAPI double ecore_con_client_timeout_get(Ecore_Con_Client *cl); +/** + * Set the time after which the client will be disconnected when inactive + * + * @param cl The client object + * @param timeout The timeout, in seconds, to disconnect after + * + * This function is used by the server to set the idle timeout on a specific + * client. If the client becomes idle for a time higher than this value, it will + * be disconnected. A value of < 1 disables the idle timeout. + * + * This timeout is not affected by the one set by + * ecore_con_server_timeout_set(). A client will be disconnected whenever the + * client or the server timeout is reached. That means, the lower timeout value + * will be used for that client if ecore_con_server_timeout_set() is used on the + * server. + * + * @see ecore_con_client_timeout_get() + * @see ecore_con_server_timeout_set() + */ +EAPI void ecore_con_client_timeout_set(Ecore_Con_Client *cl, double timeout); +/** + * Returns whether the client is still connected + * + * @param cl The given client. + * @return @c EINA_TRUE if connected, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool ecore_con_client_connected_get(Ecore_Con_Client *cl); +/** + * @brief Return the port that the client has connected to + * + * @param cl The client + * @return The port that @p cl has connected to, or -1 on error + * Use this function to return the port on which a given client has connected. + */ +EAPI int ecore_con_client_port_get(Ecore_Con_Client *cl); + + + +/** + * @} + */ + +/** + * @defgroup Ecore_Con_Url_Group Ecore URL Connection Functions + * + * Utility functions that set up, use and shut down the Ecore URL + * Connection library. + * + * These functions are a shortcut to make it easy to perform http requests + * (POST, GET, etc). + * + * Brief usage: + * 1. Create an Ecore_Con_Url object with ecore_con_url_new(url); + * 2. Register to receive the #ECORE_CON_EVENT_URL_COMPLETE event + * (and optionally the #ECORE_CON_EVENT_URL_DATA and + * #ECORE_CON_EVENT_URL_PROGRESS event to receive + * the response, e.g. for HTTP/FTP downloads) + * 3. Perform the operation with ecore_con_url_get(...); + * + * Note that it is good to reuse @ref Ecore_Con_Url objects wherever possible, + * but bear in mind that each one can only perform one operation at a time. You + * need to wait for the #ECORE_CON_EVENT_URL_COMPLETE event before re-using or + * destroying the object. + * + * If it's necessary to change the @ref Ecore_Con_Url object url, use + * ecore_con_url_url_set(). + * + * Simple Usage 1 (HTTP GET): + * @code + * ecore_con_url_url_set(url_con, "http://www.google.com"); + * ecore_con_url_get(url_con); + * @endcode + * + * Simple usage 2 (HTTP POST): + * @code + * ecore_con_url_url_set(url_con, "http://www.example.com/post_handler.cgi"); + * ecore_con_url_post(url_con, data, data_length, "multipart/form-data"); + * @endcode + * + * Simple Usage 3 (FTP download): + * @code + * fd = creat(filename, 0644) + * ecore_con_url_url_set(url_con, "ftp://ftp.example.com/pub/myfile"); + * ecore_con_url_fd_set(url_con, fd); + * ecore_con_url_get(url_con); + * @endcode + * + * Simple Usage 4 (FTP upload as ftp://ftp.example.com/file): + * @code + * ecore_con_url_url_set(url_con, "ftp://ftp.example.com"); + * ecore_con_url_ftp_upload(url_con, "/tmp/file", "user", "pass", NULL); + * @endcode + * + * Simple Usage 5 (FTP upload as ftp://ftp.example.com/dir/file): + * @code + * ecore_con_url_url_set(url_con, "ftp://ftp.example.com"); + * ecore_con_url_ftp_upload(url_con, "/tmp/file", "user", "pass","dir"); + * @endcode + * + * These are complete examples for the API: + * @li @ref ecore_con_url_download_example.c "Downloading a file" + * @li @ref ecore_con_url_headers_example.c "Setting many options for the connection" + * + * @{ + */ + +/** + * @typedef Ecore_Con_Url_Time + * @enum _Ecore_Con_Url_Time + * The type of condition to use when making an HTTP request dependent on time, + * so that headers such as "If-Modified-Since" are used. + */ +typedef enum _Ecore_Con_Url_Time +{ + /** + * Do not place time restrictions on the HTTP requests. + */ + ECORE_CON_URL_TIME_NONE = 0, + /** + * Add the "If-Modified-Since" HTTP header, so that the request is performed + * by the server only if the target has been modified since the time value + * passed to it in the request. + */ + ECORE_CON_URL_TIME_IFMODSINCE, + /** + * Add the "If-Unmodified-Since" HTTP header, so that the request is + * performed by the server only if the target has NOT been modified since + * the time value passed to it in the request. + */ + ECORE_CON_URL_TIME_IFUNMODSINCE +} Ecore_Con_Url_Time; + +/** + * @typedef Ecore_Con_Url_Http_Version + * @enum _Ecore_Con_Url_Http_Version + * The http version to use + * @since 1.2 + */ +typedef enum _Ecore_Con_Url_Http_Version +{ + /** + * HTTP version 1.0 + * @since 1.2 + */ + ECORE_CON_URL_HTTP_VERSION_1_0, + /** + * HTTP version 1.1 (default) + * @since 1.2 + */ + ECORE_CON_URL_HTTP_VERSION_1_1 +} Ecore_Con_Url_Http_Version; + +/** + * Change the HTTP version used for the request + * @param url_con Connection object through which the request will be sent. + * @param version The version to be used + * @return @c EINA_TRUE on success, @c EINA_FALSE on failure to change version. + * @since 1.2 + * @see ecore_con_url_pipeline_get() + */ +EAPI Eina_Bool ecore_con_url_http_version_set(Ecore_Con_Url *url_con, Ecore_Con_Url_Http_Version version); + +/** + * Initialises the Ecore_Con_Url library. + * @return Number of times the library has been initialised without being + * shut down. + * + * @note This function doesn't call ecore_con_init(). You still need to call it + * explicitly before calling this one. + */ +EAPI int ecore_con_url_init(void); + +/** + * Shuts down the Ecore_Con_Url library. + * @return Number of calls that still uses Ecore_Con_Url + * + * @note This function doesn't call ecore_con_shutdown(). You still need to call + * it explicitly after calling this one. + */ +EAPI int ecore_con_url_shutdown(void); + +/** + * Enable or disable HTTP 1.1 pipelining. + * @param enable @c EINA_TRUE will turn it on, @c EINA_FALSE will disable it. + * + * Pipelining allows to send one request after another one, without having to + * wait for the reply of the first request. The respective replies are received + * in the order that the requests were sent. + * + * Enabling this feature will be valid for all requests done using @c + * ecore_con_url. + * + * See http://en.wikipedia.org/wiki/HTTP_pipelining for more info. + * + * @see ecore_con_url_pipeline_get() + */ +EAPI void ecore_con_url_pipeline_set(Eina_Bool enable); +/** + * Is HTTP 1.1 pipelining enable ? + * @return @c EINA_TRUE if it is enable. + * + * @see ecore_con_url_pipeline_set() + */ +EAPI Eina_Bool ecore_con_url_pipeline_get(void); + +/** + * Creates and initializes a new Ecore_Con_Url connection object. + * + * @param url URL that will receive requests. Can be changed using + * ecore_con_url_url_set. + * + * @return @c NULL on error, a new Ecore_Con_Url on success. + * + * Creates and initializes a new Ecore_Con_Url connection object that can be + * used for sending requests. + * + * @see ecore_con_url_custom_new() + * @see ecore_con_url_url_set() + */ +EAPI Ecore_Con_Url * ecore_con_url_new(const char *url); +/** + * Creates a custom connection object. + * + * @param url URL that will receive requests + * @param custom_request Custom request (e.g. GET, POST, HEAD, PUT, etc) + * + * @return @c NULL on error, a new Ecore_Con_Url on success. + * + * Creates and initializes a new Ecore_Con_Url for a custom request (e.g. HEAD, + * SUBSCRIBE and other obscure HTTP requests). This object should be used like + * one created with ecore_con_url_new(). + * + * @see ecore_con_url_new() + * @see ecore_con_url_url_set() + */ +EAPI Ecore_Con_Url * ecore_con_url_custom_new(const char *url, + const char *custom_request); +/** + * Destroys a Ecore_Con_Url connection object. + * + * @param url_con Connection object to free. + * + * @see ecore_con_url_new() + */ +EAPI void ecore_con_url_free(Ecore_Con_Url *url_con); +/** + * Sets the URL to send the request to. + * + * @param url_con Connection object through which the request will be sent. + * @param url URL that will receive the request + * + * @return @c EINA_TRUE on success, @c EINA_FALSE on error. + */ +EAPI Eina_Bool ecore_con_url_url_set(Ecore_Con_Url *url_con, + const char *url); +/** + * Gets the URL to send the request to. + * + * @param url_con Connection object through which the request will be sent. + * @return URL that will receive the request, @c NULL on failure. URL is + * stringshared. + * @since 1.1 + */ +EAPI const char *ecore_con_url_url_get(Ecore_Con_Url *url_con); +/** + * Associates data with a connection object. + * + * @param url_con Connection object to associate data. + * @param data Data to be set. + * + * Associates data with a connection object, which can be retrieved later with + * ecore_con_url_data_get()). + * + * @see ecore_con_url_data_get() + */ +EAPI void ecore_con_url_data_set(Ecore_Con_Url *url_con, + void *data); +/** + * Retrieves data associated with a Ecore_Con_Url connection object. + * + * @param url_con Connection object to retrieve data from. + * + * @return Data associated with the given object. + * + * Retrieves data associated with a Ecore_Con_Url connection object (previously + * set with ecore_con_url_data_set()). + * + * @see ecore_con_url_data_set() + */ +EAPI void * ecore_con_url_data_get(Ecore_Con_Url *url_con); +/** + * Adds an additional header to the request connection object. + * + * @param url_con Connection object + * @param key Header key + * @param value Header value + * + * Adds an additional header (User-Agent, Content-Type, etc.) to the request + * connection object. This addition will be valid for only one + * ecore_con_url_get() or ecore_con_url_post() call. + * + * Some functions like ecore_con_url_time() also add headers to the request. + * + * @see ecore_con_url_get() + * @see ecore_con_url_post() + * @see ecore_con_url_additional_headers_clear() + */ +EAPI void ecore_con_url_additional_header_add(Ecore_Con_Url *url_con, + const char *key, + const char *value); +/** + * Cleans additional headers. + * + * @param url_con Connection object to clean additional headers. + * + * Cleans additional headers associated with a connection object (previously + * added with ecore_con_url_additional_header_add()). + * + * @see ecore_con_url_additional_header_add() + * @see ecore_con_url_get() + * @see ecore_con_url_post() + */ +EAPI void ecore_con_url_additional_headers_clear(Ecore_Con_Url *url_con); +/** + * Retrieves headers from last request sent. + * + * @param url_con Connection object to retrieve response headers from. + * + * Retrieves a list containing the response headers. This function should be + * used after an ECORE_CON_EVENT_URL_COMPLETE event (headers should normally be + * ready at that time). + * + * @return List of response headers. This list must not be modified by the user. + */ +EAPI const Eina_List * ecore_con_url_response_headers_get(Ecore_Con_Url *url_con); +/** + * Setup a file for receiving response data. + * + * @param url_con Connection object to set file + * @param fd File descriptor associated with the file. A negative value will + * unset any previously set fd. + * + * Sets up a file to have response data written into. Note that + * ECORE_CON_EVENT_URL_DATA events will not be emitted if a file has been set to + * receive the response data. + * + * This call can be used to easily setup a file where the downloaded data will + * be saved. + */ +EAPI void ecore_con_url_fd_set(Ecore_Con_Url *url_con, int fd); +/** + * Retrieves the number of bytes received. + * + * Retrieves the number of bytes received on the last request of the given + * connection object. + * + * @param url_con Connection object which the request was sent on. + * + * @return Number of bytes received on request. + * + * @see ecore_con_url_get() + * @see ecore_con_url_post() + */ +EAPI int ecore_con_url_received_bytes_get(Ecore_Con_Url *url_con); +/** + * Sets url_con to use http auth, with given username and password, "safely" or not. + * + * @param url_con Connection object to perform a request on, previously created + * with ecore_con_url_new() or ecore_con_url_custom_new(). + * @param username Username to use in authentication + * @param password Password to use in authentication + * @param safe Whether to use "safer" methods (eg, NOT http basic auth) + * + * @return @c EINA_TRUE on success, @c EINA_FALSE on error. + * + * @attention Requires libcurl >= 7.19.1 to work, otherwise will always return + * @c 0. + */ +EAPI Eina_Bool ecore_con_url_httpauth_set(Ecore_Con_Url *url_con, + const char *username, + const char *password, + Eina_Bool safe); +/** + * Sends a get request. + * + * @param url_con Connection object to perform a request on, previously created + * + * @return @c EINA_TRUE on success, @c EINA_FALSE on error. + * + * The request is performed immediately, but you need to setup event handlers + * for #ECORE_CON_EVENT_URL_DATA, #ECORE_CON_EVENT_URL_COMPLETE or + * #ECORE_CON_EVENT_URL_PROGRESS to get more information about its result. + * + * @see ecore_con_url_custom_new() + * @see ecore_con_url_additional_headers_clear() + * @see ecore_con_url_additional_header_add() + * @see ecore_con_url_data_set() + * @see ecore_con_url_data_get() + * @see ecore_con_url_response_headers_get() + * @see ecore_con_url_time() + * @see ecore_con_url_post() + */ +EAPI Eina_Bool ecore_con_url_get(Ecore_Con_Url *url_con); +/** + * Sends a post request. + * + * @param url_con Connection object to perform a request on, previously created + * with ecore_con_url_new() or ecore_con_url_custom_new(). + * @param data Payload (data sent on the request). Can be @c NULL. + * @param length Payload length. If @c -1, rely on automatic length + * calculation via @c strlen() on @p data. + * @param content_type Content type of the payload (e.g. text/xml). Can be @c + * NULL. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE on error. + * + * The request starts immediately, but you need to setup event handlers + * for #ECORE_CON_EVENT_URL_DATA, #ECORE_CON_EVENT_URL_COMPLETE or + * #ECORE_CON_EVENT_URL_PROGRESS to get more information about its result. + * + * This call won't block your main loop. + * + * @see ecore_con_url_custom_new() + * @see ecore_con_url_additional_headers_clear() + * @see ecore_con_url_additional_header_add() + * @see ecore_con_url_data_set() + * @see ecore_con_url_data_get() + * @see ecore_con_url_response_headers_get() + * @see ecore_con_url_time() + * @see ecore_con_url_get() + */ +EAPI Eina_Bool ecore_con_url_post(Ecore_Con_Url *url_con, + const void *data, long length, + const char *content_type); +/** + * Sets whether HTTP requests should be conditional, dependent on + * modification time. + * + * @param url_con Ecore_Con_Url to act upon. + * @param time_condition Condition to use for HTTP requests. + * @param timestamp Time since 1 Jan 1970 to use in the condition. + * + * This function may set the header "If-Modified-Since" or + * "If-Unmodified-Since", depending on the value of @p time_condition, with the + * value @p timestamp. + * + * @sa ecore_con_url_get() + * @sa ecore_con_url_post() + */ +EAPI void ecore_con_url_time(Ecore_Con_Url *url_con, + Ecore_Con_Url_Time time_condition, + double timestamp); + +/** + * @brief Uploads a file to an ftp site. + * + * @param url_con The Ecore_Con_Url object to send with + * @param filename The path to the file to send + * @param user The username to log in with + * @param pass The password to log in with + * @param upload_dir The directory to which the file should be uploaded + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * Upload @p filename to an ftp server set in @p url_con using @p user + * and @p pass to directory @p upload_dir + */ +EAPI Eina_Bool ecore_con_url_ftp_upload(Ecore_Con_Url *url_con, + const char *filename, + const char *user, + const char *pass, + const char *upload_dir); +/** + * Toggle libcurl's verbose output. + * + * @param url_con Ecore_Con_Url instance which will be acted upon. + * @param verbose Whether or not to enable libcurl's verbose output. + * + * If @p verbose is @c EINA_TRUE, libcurl will output a lot of verbose + * information about its operations, which is useful for + * debugging. The verbose information will be sent to stderr. + */ +EAPI void ecore_con_url_verbose_set(Ecore_Con_Url *url_con, + Eina_Bool verbose); +/** + * Enable or disable EPSV extension + * @param url_con The Ecore_Con_Url instance which will be acted upon. + * @param use_epsv Boolean to enable/disable the EPSV extension. + */ +EAPI void ecore_con_url_ftp_use_epsv_set(Ecore_Con_Url *url_con, + Eina_Bool use_epsv); + +/** + * Enables the cookie engine for subsequent HTTP requests. + * + * @param url_con Ecore_Con_Url instance which will be acted upon. + * + * After this function is called, cookies set by the server in HTTP responses + * will be parsed and stored, as well as sent back to the server in new HTTP + * requests. + * + * @note Even though this function is called @c ecore_con_url_cookies_init(), + * there is no symmetrical shutdown operation. + */ +EAPI void ecore_con_url_cookies_init(Ecore_Con_Url *url_con); +/** + * Controls whether session cookies from previous sessions shall be loaded. + * + * @param url_con Ecore_Con_Url instance which will be acted upon. + * @param ignore If @c EINA_TRUE, ignore session cookies when loading cookies + * from files. If @c EINA_FALSE, all cookies will be loaded. + * + * Session cookies are cookies with no expire date set, which usually means + * they are removed after the current session is closed. + * + * By default, when Ecore_Con_Url loads cookies from a file, all cookies are + * loaded, including session cookies, which, most of the time, were supposed + * to be loaded and valid only for that session. + * + * If @p ignore is set to @c EINA_TRUE, when Ecore_Con_Url loads cookies from + * the files passed to @c ecore_con_url_cookies_file_add(), session cookies + * will not be loaded. + * + * @see ecore_con_url_cookies_file_add() + */ +EAPI void ecore_con_url_cookies_ignore_old_session_set(Ecore_Con_Url *url_con, + Eina_Bool ignore); +/** + * Clears currently loaded cookies. + * @param url_con Ecore_Con_Url instance which will be acted upon. + * + * The cleared cookies are removed and will not be sent in subsequent HTTP + * requests, nor will they be written to the cookiejar file set via + * @c ecore_con_url_cookies_jar_file_set(). + * + * @note This function will initialize the cookie engine if it has not been + * initialized yet. + * @note The cookie files set by ecore_con_url_cookies_file_add() aren't loaded + * immediately, just when the request is started. Thus, if you ask to + * clear the cookies, but has a file already set by that function, the + * cookies will then be loaded and you will have old cookies set. In order + * to don't have any old cookie set, you need to don't call + * ecore_con_url_cookies_file_add() ever on the @p url_con handler, and + * call this function to clear any cookie set by a previous request on + * this handler. + * + * @see ecore_con_url_cookies_session_clear() + * @see ecore_con_url_cookies_ignore_old_session_set() + */ +EAPI void ecore_con_url_cookies_clear(Ecore_Con_Url *url_con); +/** + * Clears currently loaded session cookies. + * + * @param url_con Ecore_Con_Url instance which will be acted upon. + * + * Session cookies are cookies with no expire date set, which usually means + * they are removed after the current session is closed. + * + * The cleared cookies are removed and will not be sent in subsequent HTTP + * requests, nor will they be written to the cookiejar file set via + * @c ecore_con_url_cookies_jar_file_set(). + * + * @note This function will initialize the cookie engine if it has not been + * initialized yet. + * @note The cookie files set by ecore_con_url_cookies_file_add() aren't loaded + * immediately, just when the request is started. Thus, if you ask to + * clear the session cookies, but has a file already set by that function, + * the session cookies will then be loaded and you will have old cookies + * set. In order to don't have any old session cookie set, you need to + * don't call ecore_con_url_cookies_file_add() ever on the @p url_con + * handler, and call this function to clear any session cookie set by a + * previous request on this handler. An easier way to don't use old + * session cookies is by using the function + * ecore_con_url_cookies_ignore_old_session_set(). + * + * @see ecore_con_url_cookies_clear() + * @see ecore_con_url_cookies_ignore_old_session_set() + */ +EAPI void ecore_con_url_cookies_session_clear(Ecore_Con_Url *url_con); +/** + * Adds a file to the list of files from which to load cookies. + * + * @param url_con Ecore_Con_Url instance which will be acted upon. + * @param file_name Name of the file that will be added to the list. + * + * Files must contain cookies defined according to two possible formats: + * + * @li HTTP-style header ("Set-Cookie: ..."). + * @li Netscape/Mozilla cookie data format. + * + * Cookies will only be @b read from this file. If you want to save cookies to a + * file, use ecore_con_url_cookies_jar_file_set(). Also notice that this + * function supports the both types of cookie file cited above, while + * ecore_con_url_cookies_jar_file_set() will save only in the Netscape/Mozilla's + * format. + * + * Please notice that the file will not be read immediately, but rather added + * to a list of files that will be loaded and parsed at a later time. + * + * @note This function will initialize the cookie engine if it has not been + * initialized yet. + * + * @see ecore_con_url_cookies_ignore_old_session_set() + * @see ecore_con_url_cookies_jar_file_set() + */ +EAPI void ecore_con_url_cookies_file_add(Ecore_Con_Url *url_con, + const char * const file_name); +/** + * Sets the name of the file to which all current cookies will be written when + * either cookies are flushed or Ecore_Con is shut down. + * + * @param url_con Ecore_Con_Url instance which will be acted upon. + * @param cookiejar_file File to which the cookies will be written. + * + * @return @c EINA_TRUE is the file name has been set successfully, + * @c EINA_FALSE otherwise. + * + * Cookies are written following Netscape/Mozilla's data format, also known as + * cookie-jar. + * + * Cookies will only be @b saved to this file. If you need to read cookies from + * a file, use ecore_con_url_cookies_file_add() instead. + * + * @note This function will initialize the cookie engine if it has not been + * initialized yet. + * + * @see ecore_con_url_cookies_jar_write() + */ +EAPI Eina_Bool ecore_con_url_cookies_jar_file_set(Ecore_Con_Url *url_con, + const char * const cookiejar_file); +/** + * Writes all current cookies to the cookie jar immediately. + * + * @param url_con Ecore_Con_Url instance which will be acted upon. + * + * A cookie-jar file must have been previously set by + * @c ecore_con_url_jar_file_set, otherwise nothing will be done. + * + * @note This function will initialize the cookie engine if it has not been + * initialized yet. + * + * @see ecore_con_url_cookies_jar_file_set() + */ +EAPI void ecore_con_url_cookies_jar_write(Ecore_Con_Url *url_con); + +EAPI void ecore_con_url_ssl_verify_peer_set(Ecore_Con_Url *url_con, + Eina_Bool verify); +EAPI int ecore_con_url_ssl_ca_set(Ecore_Con_Url *url_con, + const char *ca_path); + +/** + * Set HTTP proxy to use. + * + * The parameter should be a char * to a zero terminated string holding + * the host name or dotted IP address. To specify port number in this string, + * append :[port] to the end of the host name. + * The proxy string may be prefixed with [protocol]:// since any such prefix + * will be ignored. + * The proxy's port number may optionally be specified with the separate option. + * If not specified, libcurl will default to using port 1080 for proxies. + * + * @param url_con Connection object that will use the proxy. + * @param proxy Porxy string or @c NULL to disable + * + * @return @c EINA_TRUE on success, @c EINA_FALSE on error. + * @since 1.2 + */ +EAPI Eina_Bool ecore_con_url_proxy_set(Ecore_Con_Url *url_con, const char *proxy); + +/** + * Set zero terminated username to use for proxy. + * + * if socks protocol is used for proxy, protocol should be socks5 and above. + * + * @param url_con Connection object that will use the proxy. + * @param username Username string. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE on error. + * + * @see ecore_con_url_proxy_set() + * + * @since 1.2 + */ +EAPI Eina_Bool ecore_con_url_proxy_username_set(Ecore_Con_Url *url_con, const char *username); + +/** + * Set zero terminated password to use for proxy. + * + * if socks protocol is used for proxy, protocol should be socks5 and above. + * + * @param url_con Connection object that will use the proxy. + * @param password Password string. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE on error. + * + * @see ecore_con_url_proxy_set() + * + * @since 1.2 + */ +EAPI Eina_Bool ecore_con_url_proxy_password_set(Ecore_Con_Url *url_con, const char *password); + +/** + * Set timeout in seconds. + * + * the maximum time in seconds that you allow the ecore con url transfer + * operation to take. Normally, name lookups can take a considerable time + * and limiting operations to less than a few minutes risk aborting perfectly + * normal operations. + * + * @param url_con Connection object that will use the timeout. + * @param timeout time in seconds. + * + * @see ecore_con_url_cookies_jar_file_set() + * + * @since 1.2 + */ +EAPI void ecore_con_url_timeout_set(Ecore_Con_Url *url_con, double timeout); + +/** + * Get the returned HTTP STATUS code + * + * This is used to, at any time, try to return the status code for a transmission. + * @param url_con Connection object + * @return A valid HTTP STATUS code, or 0 on failure + * + * @since 1.2 + */ +EAPI int ecore_con_url_status_code_get(Ecore_Con_Url *url_con); +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/ecore_con/Makefile.am b/src/lib/ecore_con/Makefile.am new file mode 100644 index 0000000..0e8e071 --- /dev/null +++ b/src/lib/ecore_con/Makefile.am @@ -0,0 +1,53 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_builddir)/src/lib/ecore \ +-I$(top_builddir)/src/lib/ecore_con \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore_con \ +@EFL_ECORE_CON_BUILD@ \ +@SSL_CFLAGS@ \ +@CURL_CFLAGS@ \ +@EVIL_CFLAGS@ \ +@EINA_CFLAGS@ \ +@TLS_CFLAGS@ \ +@CARES_CFLAGS@ \ +@WIN32_CPPFLAGS@ + +lib_LTLIBRARIES = libecore_con.la +includes_HEADERS = Ecore_Con.h +includesdir = $(includedir)/ecore-@VMAJ@ + +libecore_con_la_SOURCES = \ +ecore_con.c \ +ecore_con_socks.c \ +ecore_con_ssl.c \ +ecore_con_url.c \ +ecore_con_alloc.c + +libecore_con_la_CFLAGS = @WIN32_CFLAGS@ + +if ECORE_HAVE_WIN32 +libecore_con_la_SOURCES += ecore_con_local_win32.c +else +libecore_con_la_SOURCES += ecore_con_local.c +endif + +if HAVE_CARES +libecore_con_la_SOURCES += ecore_con_ares.c +else +if HAVE_IPV6 +libecore_con_la_CFLAGS += @ECORE_CON_CFLAGS@ +libecore_con_la_SOURCES += ecore_con_dns.c dns.c dns.h +else +libecore_con_la_SOURCES += ecore_con_info.c +endif +endif + +libecore_con_la_LIBADD = \ +$(top_builddir)/src/lib/ecore/libecore.la \ +@SSL_LIBS@ @CURL_LIBS@ @EINA_LIBS@ @EVIL_LIBS@ @TLS_LIBS@ @CARES_LIBS@ @WIN32_LIBS@ + +libecore_con_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ + +EXTRA_DIST = ecore_con_private.h diff --git a/src/lib/ecore_con/dns.c b/src/lib/ecore_con/dns.c new file mode 100644 index 0000000..b92a315 --- /dev/null +++ b/src/lib/ecore_con/dns.c @@ -0,0 +1,7878 @@ +/* ========================================================================== + * dns.c - Recursive, Reentrant DNS Resolver. + * -------------------------------------------------------------------------- + * Copyright (c) 2008, 2009, 2010 William Ahern + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * ========================================================================== + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#if !defined(__FreeBSD__) +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 600 +#endif + +#undef _BSD_SOURCE +#define _BSD_SOURCE + +#undef _DARWIN_C_SOURCE +#define _DARWIN_C_SOURCE + +#undef _NETBSD_SOURCE +#define _NETBSD_SOURCE +#endif + +#include /* offsetof() */ +#include /* uint32_t */ +#include /* malloc(3) realloc(3) free(3) rand(3) random(3) arc4random(3) */ +#include /* FILE fopen(3) fclose(3) getc(3) rewind(3) */ + +#include /* memcpy(3) strlen(3) memmove(3) memchr(3) memcmp(3) strchr(3) strsep(3) strcspn(3) */ +#include /* strcasecmp(3) strncasecmp(3) */ + +#include /* isspace(3) isdigit(3) */ + +#include /* time_t time(2) */ + +#include /* sig_atomic_t */ + +#include /* errno EINVAL ENOENT */ + +#undef NDEBUG +#include /* assert(3) */ + +#if _WIN32 +#include +#include +#else +#include /* FD_SETSIZE socklen_t */ +#include /* FD_ZERO FD_SET fd_set select(2) */ +#include /* AF_INET AF_INET6 AF_UNIX struct sockaddr struct sockaddr_in struct sockaddr_in6 socket(2) */ + +#if defined(AF_UNIX) +#include /* struct sockaddr_un */ +#endif + +#include /* F_SETFD F_GETFL F_SETFL O_NONBLOCK fcntl(2) */ + +#include /* gethostname(3) close(2) */ + +#include /* POLLIN POLLOUT */ + +#include /* struct sockaddr_in struct sockaddr_in6 */ + +#include /* inet_pton(3) inet_ntop(3) htons(3) ntohs(3) */ + +#include /* struct addrinfo */ +#endif + +#include "dns.h" + + +/* + * S T A N D A R D M A C R O S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef MIN +#define MIN(a, b) (((a) < (b))? (a) : (b)) +#endif + + +#ifndef MAX +#define MAX(a, b) (((a) > (b))? (a) : (b)) +#endif + + +#ifndef lengthof +#define lengthof(a) (sizeof (a) / sizeof (a)[0]) +#endif + +#ifndef endof +#define endof(a) (&(a)[lengthof((a))]) +#endif + + +/* + * D E B U G M A C R O S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +int dns_debug = 0; + +#if DNS_DEBUG + +#undef DNS_DEBUG +#define DNS_DEBUG dns_debug + +#define DNS_SAY_(fmt, ...) \ + do { if (DNS_DEBUG > 0) fprintf(stderr, fmt "%.1s", __func__, __LINE__, __VA_ARGS__); } while (0) +#define DNS_SAY(...) DNS_SAY_("@@ (%s:%d) " __VA_ARGS__, "\n") +#define DNS_HAI DNS_SAY("HAI") + +#define DNS_SHOW_(P, fmt, ...) do { \ + if (DNS_DEBUG > 1) { \ + fprintf(stderr, "@@ BEGIN * * * * * * * * * * * *\n"); \ + fprintf(stderr, "@@ " fmt "%.0s\n", __VA_ARGS__); \ + dns_p_dump((P), stderr); \ + fprintf(stderr, "@@ END * * * * * * * * * * * * *\n\n"); \ + } \ +} while (0) + +#define DNS_SHOW(...) DNS_SHOW_(__VA_ARGS__, "") + +#else /* !DNS_DEBUG */ + +#undef DNS_DEBUG +#define DNS_DEBUG 0 + +#define DNS_SAY(...) +#define DNS_HAI +#define DNS_SHOW(...) + +#endif /* DNS_DEBUG */ + + +/* + * V E R S I O N R O U T I N E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +const char *dns_vendor(void) { + return DNS_VENDOR; +} /* dns_vendor() */ + + +int dns_v_rel(void) { + return DNS_V_REL; +} /* dns_v_rel() */ + + +int dns_v_abi(void) { + return DNS_V_ABI; +} /* dns_v_abi() */ + + +int dns_v_api(void) { + return DNS_V_API; +} /* dns_v_api() */ + + +/* + * E R R O R R O U T I N E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#if _WIN32 + +#define DNS_EINTR WSAEINTR +#define DNS_EINPROGRESS WSAEINPROGRESS +#define DNS_EISCONN WSAEISCONN +#define DNS_EWOULDBLOCK WSAEWOULDBLOCK +#define DNS_EALREADY WSAEALREADY +#define DNS_EAGAIN EAGAIN +#define DNS_ETIMEDOUT WSAETIMEDOUT + +#define dns_syerr() ((int)GetLastError()) +#define dns_soerr() ((int)WSAGetLastError()) + +#else + +#define DNS_EINTR EINTR +#define DNS_EINPROGRESS EINPROGRESS +#define DNS_EISCONN EISCONN +#define DNS_EWOULDBLOCK EWOULDBLOCK +#define DNS_EALREADY EALREADY +#define DNS_EAGAIN EAGAIN +#define DNS_ETIMEDOUT ETIMEDOUT + +#define dns_syerr() errno +#define dns_soerr() errno + +#endif + + +const char *dns_strerror(int error) { + switch (error) { + case DNS_ENOBUFS: + return "DNS packet buffer too small"; + case DNS_EILLEGAL: + return "Illegal DNS RR name or data"; + case DNS_EORDER: + return "Attempt to push RR out of section order"; + case DNS_ESECTION: + return "Invalid section specified"; + case DNS_EUNKNOWN: + return "Unknown DNS error"; + default: + return strerror(error); + } /* switch() */ +} /* dns_strerror() */ + + +/* + * A T O M I C R O U T I N E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +static unsigned dns_atomic_inc(dns_atomic_t *i) { + return (*i)++; +} /* dns_atomic_inc() */ + + +static unsigned dns_atomic_dec(dns_atomic_t *i) { + return (*i)--; +} /* dns_atomic_dec() */ + + +/* + * C R Y P T O R O U T I N E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * P R N G + */ + +#ifndef DNS_RANDOM +#if defined(HAVE_ARC4RANDOM) \ + || defined(__OpenBSD__) \ + || defined(__FreeBSD__) \ + || defined(__NetBSD__) \ + || defined(__APPLE__) +#define DNS_RANDOM arc4random +#elif __linux +#define DNS_RANDOM random +#else +#define DNS_RANDOM rand +#endif +#endif + +#define DNS_RANDOM_arc4random 1 +#define DNS_RANDOM_random 2 +#define DNS_RANDOM_rand 3 +#define DNS_RANDOM_RAND_bytes 4 + +#define DNS_RANDOM_OPENSSL (DNS_RANDOM_RAND_bytes == DNS_PP_XPASTE(DNS_RANDOM_, DNS_RANDOM)) + +#if DNS_RANDOM_OPENSSL +#include +#endif + +static unsigned dns_random_(void) { +#if DNS_RANDOM_OPENSSL + unsigned r; + + assert(1 == RAND_bytes((unsigned char *)&r, sizeof r)); + + return r; +#else + return DNS_RANDOM(); +#endif +} /* dns_random_() */ + +unsigned (*dns_random)(void) __attribute__((weak)) = &dns_random_; + + +/* + * P E R M U T A T I O N G E N E R A T O R + */ + +#define DNS_K_TEA_KEY_SIZE 16 +#define DNS_K_TEA_BLOCK_SIZE 8 +#define DNS_K_TEA_CYCLES 32 +#define DNS_K_TEA_MAGIC 0x9E3779B9U + +struct dns_k_tea { + uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)]; + unsigned cycles; +}; /* struct dns_k_tea */ + + +static void dns_k_tea_init(struct dns_k_tea *tea, uint32_t key[], unsigned cycles) { + memcpy(tea->key, key, sizeof tea->key); + + tea->cycles = (cycles)? cycles : DNS_K_TEA_CYCLES; +} /* dns_k_tea_init() */ + + +static void dns_k_tea_encrypt(struct dns_k_tea *tea, uint32_t v[], uint32_t *w) { + uint32_t y, z, sum, n; + + y = v[0]; + z = v[1]; + sum = 0; + + for (n = 0; n < tea->cycles; n++) { + sum += DNS_K_TEA_MAGIC; + y += ((z << 4) + tea->key[0]) ^ (z + sum) ^ ((z >> 5) + tea->key[1]); + z += ((y << 4) + tea->key[2]) ^ (y + sum) ^ ((y >> 5) + tea->key[3]); + } + + w[0] = y; + w[1] = z; + + return /* void */; +} /* dns_k_tea_encrypt() */ + + +/* + * Permutation generator, based on a Luby-Rackoff Feistel construction. + * + * Specifically, this is a generic balanced Feistel block cipher using TEA + * (another block cipher) as the pseudo-random function, F. At best it's as + * strong as F (TEA), notwithstanding the seeding. F could be AES, SHA-1, or + * perhaps Bernstein's Salsa20 core; I am naively trying to keep things + * simple. + * + * The generator can create a permutation of any set of numbers, as long as + * the size of the set is an even power of 2. This limitation arises either + * out of an inherent property of balanced Feistel constructions, or by my + * own ignorance. I'll tackle an unbalanced construction after I wrap my + * head around Schneier and Kelsey's paper. + * + * CAVEAT EMPTOR. IANAC. + */ +#define DNS_K_PERMUTOR_ROUNDS 8 + +struct dns_k_permutor { + unsigned stepi, length, limit; + unsigned shift, mask, rounds; + + struct dns_k_tea tea; +}; /* struct dns_k_permutor */ + + +static inline unsigned dns_k_permutor_powof(unsigned n) { + unsigned m, i = 0; + + for (m = 1; m < n; m <<= 1, i++) + ;; + + return i; +} /* dns_k_permutor_powof() */ + +static void dns_k_permutor_init(struct dns_k_permutor *p, unsigned low, unsigned high) { + uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)]; + unsigned width, i; + + p->stepi = 0; + + p->length = (high - low) + 1; + p->limit = high; + + width = dns_k_permutor_powof(p->length); + width += width % 2; + + p->shift = width / 2; + p->mask = (1U << p->shift) - 1; + p->rounds = DNS_K_PERMUTOR_ROUNDS; + + for (i = 0; i < lengthof(key); i++) + key[i] = dns_random(); + + dns_k_tea_init(&p->tea, key, 0); + + return /* void */; +} /* dns_k_permutor_init() */ + + +static unsigned dns_k_permutor_F(struct dns_k_permutor *p, unsigned k, unsigned x) { + uint32_t in[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)], out[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)]; + + memset(in, '\0', sizeof in); + + in[0] = k; + in[1] = x; + + dns_k_tea_encrypt(&p->tea, in, out); + + return p->mask & out[0]; +} /* dns_k_permutor_F() */ + + +static unsigned dns_k_permutor_E(struct dns_k_permutor *p, unsigned n) { + unsigned l[2], r[2]; + unsigned i; + + i = 0; + l[i] = p->mask & (n >> p->shift); + r[i] = p->mask & (n >> 0); + + do { + l[(i + 1) % 2] = r[i % 2]; + r[(i + 1) % 2] = l[i % 2] ^ dns_k_permutor_F(p, i, r[i % 2]); + + i++; + } while (i < p->rounds - 1); + + return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0); +} /* dns_k_permutor_E() */ + +static unsigned dns_k_permutor_step(struct dns_k_permutor *p) { + unsigned n; + + do { + n = dns_k_permutor_E(p, p->stepi++); + } while (n >= p->length); + + return n + (p->limit + 1 - p->length); +} /* dns_k_permutor_step() */ + + +/* + * Simple permutation box. Useful for shuffling rrsets from an iterator. + * Uses AES s-box to provide good diffusion. + * + * Seems to pass muster under runs test. + * + * $ for i in 0 1 2 3 4 5 6 7 8 9; do ./dns shuffle-16 > /tmp/out; done + * $ R -q -f /dev/stdin 2>/dev/null <<-EOF | awk '/p-value/{ print $8 }' + * library(lawstat) + * runs.test(scan(file="/tmp/out")) + * EOF + */ +static unsigned short dns_k_shuffle16(unsigned short n, unsigned s) { + static const unsigned char sbox[256] = + { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, + 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, + 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, + 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, + 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, + 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, + 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, + 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, + 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, + 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, + 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, + 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, + 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; + unsigned char a, b; + unsigned i; + + a = 0xff & (n >> 0); + b = 0xff & (n >> 8); + + for (i = 0; i < 4; i++) { + a ^= 0xff & s; + a = sbox[a] ^ b; + b = sbox[b] ^ a; + s >>= 8; + } + + return ((0xff00 & (a << 8)) | (0x00ff & (b << 0))); +} /* dns_k_shuffle16() */ + + +/* + * U T I L I T Y R O U T I N E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Monotonic Time + * + */ +static time_t dns_now(void) { + /* XXX: Assumes sizeof (time_t) <= sizeof (sig_atomic_t) */ + static volatile sig_atomic_t last, tick; + volatile sig_atomic_t tmp_last, tmp_tick; + time_t now; + + time(&now); + + tmp_last = last; + + if (now > tmp_last) { + tmp_tick = tick; + tmp_tick += now - tmp_last; + tick = tmp_tick; + } + + last = now; + + return tick; +} /* dns_now() */ + +static time_t dns_elapsed(time_t from) { + time_t now = dns_now(); + + return (now > from)? now - from : 0; +} /* dns_elpased() */ + + +static size_t dns_af_len(int af) { + static const size_t table[AF_MAX] = { + [AF_INET6] = sizeof (struct sockaddr_in6), + [AF_INET] = sizeof (struct sockaddr_in), +#if defined(AF_UNIX) && !defined(_WIN32) + [AF_UNIX] = sizeof (struct sockaddr_un), +#endif + }; + + return table[af]; +} /* dns_af_len() */ + +#define dns_sa_len(sa) dns_af_len(dns_sa_family(sa)) + + +#define DNS_SA_NOPORT &dns_sa_noport +static unsigned short dns_sa_noport; + +unsigned short *dns_sa_port(int af, void *sa) { + switch (af) { + case AF_INET6: + return &((struct sockaddr_in6 *)sa)->sin6_port; + case AF_INET: + return &((struct sockaddr_in *)sa)->sin_port; + default: + return DNS_SA_NOPORT; + } +} /* dns_sa_port() */ + + +void *dns_sa_addr(int af, void *sa) { + switch (af) { + case AF_INET6: + return &((struct sockaddr_in6 *)sa)->sin6_addr; + case AF_INET: + return &((struct sockaddr_in *)sa)->sin_addr; + default: + return 0; + } +} /* dns_sa_addr() */ + + +#if _WIN32 +static int dns_inet_pton(int af, const void *src, void *dst) { + union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u; + + u.sin.sin_family = af; + + if (0 != WSAStringToAddressA((void *)src, af, (void *)0, (struct sockaddr *)&u, &(int){ sizeof u })) + return -1; + + switch (af) { + case AF_INET6: + *(struct in6_addr *)dst = u.sin6.sin6_addr; + + return 1; + case AF_INET: + *(struct in_addr *)dst = u.sin.sin_addr; + + return 1; + default: + return 0; + } +} /* dns_inet_pton() */ + +const char *dns_inet_ntop(int af, const void *src, void *dst, unsigned long lim) { + union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u; + + /* NOTE: WSAAddressToString will print .sin_port unless zeroed. */ + memset(&u, 0, sizeof u); + + u.sin.sin_family = af; + + switch (af) { + case AF_INET6: + u.sin6.sin6_addr = *(struct in6_addr *)src; + break; + case AF_INET: + u.sin.sin_addr = *(struct in_addr *)src; + + break; + default: + return 0; + } + + if (0 != WSAAddressToStringA((struct sockaddr *)&u, dns_sa_len(&u), (void *)0, dst, &lim)) + return 0; + + return dst; +} /* dns_inet_ntop() */ +#endif + + +size_t dns_strlcpy(char *dst, const char *src, size_t lim) { + char *d = dst; + char *e = &dst[lim]; + const char *s = src; + + if (d < e) { + do { + if ('\0' == (*d++ = *s++)) + return s - src - 1; + } while (d < e); + + d[-1] = '\0'; + } + + while (*s++ != '\0') + ;; + + return s - src - 1; +} /* dns_strlcpy() */ + + +size_t dns_strlcat(char *dst, const char *src, size_t lim) { + char *d = memchr(dst, '\0', lim); + char *e = &dst[lim]; + const char *s = src; + const char *p; + + if (d && d < e) { + do { + if ('\0' == (*d++ = *s++)) + return d - dst - 1; + } while (d < e); + + d[-1] = '\0'; + } + + p = s; + + while (*s++ != '\0') + ;; + + return lim + (s - p - 1); +} /* dns_strlcat() */ + + +#if _WIN32 + +static char *dns_strsep(char **sp, const char *delim) { + char *p; + + if (!(p = *sp)) + return 0; + + *sp += strcspn(p, delim); + + if (**sp != '\0') { + **sp = '\0'; + ++*sp; + } else + *sp = NULL; + + return p; +} /* dns_strsep() */ + +#else +#define dns_strsep(...) strsep(__VA_ARGS__) +#endif + + +#if _WIN32 +#define strcasecmp(...) _stricmp(__VA_ARGS__) +#define strncasecmp(...) _strnicmp(__VA_ARGS__) +#endif + + +static int dns_poll(int fd, short events, int timeout) { + fd_set rset, wset; + + if (!events) + return 0; + + assert(fd >= 0 && fd < FD_SETSIZE); + + FD_ZERO(&rset); + FD_ZERO(&wset); + + if (events & DNS_POLLIN) + FD_SET(fd, &rset); + + if (events & DNS_POLLOUT) + FD_SET(fd, &wset); + + select(fd + 1, &rset, &wset, 0, (timeout >= 0)? &(struct timeval){ timeout, 0 } : NULL); + + return 0; +} /* dns_poll() */ + + +/* + * P A C K E T R O U T I N E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +unsigned dns_p_count(struct dns_packet *P, enum dns_section section) { + unsigned count; + + switch (section) { + case DNS_S_QD: + return ntohs(dns_header(P)->qdcount); + case DNS_S_AN: + return ntohs(dns_header(P)->ancount); + case DNS_S_NS: + return ntohs(dns_header(P)->nscount); + case DNS_S_AR: + return ntohs(dns_header(P)->arcount); + default: + count = 0; + + if (section & DNS_S_QD) + count += ntohs(dns_header(P)->qdcount); + if (section & DNS_S_AN) + count += ntohs(dns_header(P)->ancount); + if (section & DNS_S_NS) + count += ntohs(dns_header(P)->nscount); + if (section & DNS_S_AR) + count += ntohs(dns_header(P)->arcount); + + return count; + } +} /* dns_p_count() */ + + +struct dns_packet *dns_p_init(struct dns_packet *P, size_t size) { + if (!P) + return 0; + + assert(size >= offsetof(struct dns_packet, data) + 12); + + memset(P, 0, sizeof *P); + P->size = size - offsetof(struct dns_packet, data); + P->end = 12; + + memset(P->data, '\0', 12); + + return P; +} /* dns_p_init() */ + + +static unsigned short dns_p_qend(struct dns_packet *P) { + unsigned short qend = 12; + unsigned i, count = dns_p_count(P, DNS_S_QD); + + for (i = 0; i < count && qend < P->end; i++) { + if (P->end == (qend = dns_d_skip(qend, P))) + goto invalid; + + if (P->end - qend < 4) + goto invalid; + + qend += 4; + } + + return MIN(qend, P->end); +invalid: + return P->end; +} /* dns_p_qend() */ + + +struct dns_packet *dns_p_make(size_t len, int *error) { + struct dns_packet *P; + size_t size = dns_p_calcsize(len); + + if (!(P = dns_p_init(malloc(size), size))) + *error = dns_syerr(); + + return P; +} /* dns_p_make() */ + + +int dns_p_grow(struct dns_packet **P) { + struct dns_packet *tmp; + size_t size; + int error; + + if (!*P) { + if (!(*P = dns_p_make(DNS_P_QBUFSIZ, &error))) + return error; + + return 0; + } + + size = dns_p_sizeof(*P); + size |= size >> 1; + size |= size >> 2; + size |= size >> 4; + size |= size >> 8; + size++; + + if (size > 65536) + return DNS_ENOBUFS; + + if (!(tmp = realloc(*P, dns_p_calcsize(size)))) + return dns_syerr(); + + tmp->size = size; + *P = tmp; + + return 0; +} /* dns_p_grow() */ + + +struct dns_packet *dns_p_copy(struct dns_packet *P, const struct dns_packet *P0) { + if (!P) + return 0; + + P->end = MIN(P->size, P0->end); + + memcpy(P->data, P0->data, P->end); + + return P; +} /* dns_p_copy() */ + + +struct dns_packet *dns_p_merge(struct dns_packet *A, enum dns_section Amask, struct dns_packet *B, enum dns_section Bmask, int *error_) { + size_t bufsiz = MIN(65535, ((A)? A->end : 0) + ((B)? B->end : 0)); + struct dns_packet *M; + enum dns_section section; + struct dns_rr rr, mr; + int error, copy; + + if (!A && B) { + A = B; + Amask = Bmask; + B = 0; + } + +merge: + if (!(M = dns_p_make(bufsiz, &error))) + goto error; + + for (section = DNS_S_QD; (DNS_S_ALL & section); section <<= 1) { + if (A && (section & Amask)) { + dns_rr_foreach(&rr, A, .section = section) { + if ((error = dns_rr_copy(M, &rr, A))) + goto error; + } + } + + if (B && (section & Bmask)) { + dns_rr_foreach(&rr, B, .section = section) { + copy = 1; + + dns_rr_foreach(&mr, M, .type = rr.type, .section = DNS_S_ALL) { + if (!(copy = dns_rr_cmp(&rr, B, &mr, M))) + break; + } + + if (copy && (error = dns_rr_copy(M, &rr, B))) + goto error; + } + } + } + + return M; +error: + free(M); M = 0; + + if (error == DNS_ENOBUFS && bufsiz < 65535) { + bufsiz = MIN(65535, bufsiz * 2); + + goto merge; + } + + *error_ = error; + + return 0; +} /* dns_p_merge() */ + + +static unsigned short dns_l_skip(unsigned short, const unsigned char *, size_t); + +void dns_p_dictadd(struct dns_packet *P, unsigned short dn) { + unsigned short lp, lptr, i; + + lp = dn; + + while (lp < P->end) { + if (0xc0 == (0xc0 & P->data[lp]) && P->end - lp >= 2 && lp != dn) { + lptr = ((0x3f & P->data[lp + 0]) << 8) + | ((0xff & P->data[lp + 1]) << 0); + + for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) { + if (P->dict[i] == lptr) { + P->dict[i] = dn; + + return; + } + } + } + + lp = dns_l_skip(lp, P->data, P->end); + } + + for (i = 0; i < lengthof(P->dict); i++) { + if (!P->dict[i]) { + P->dict[i] = dn; + + break; + } + } +} /* dns_p_dictadd() */ + + +int dns_p_push(struct dns_packet *P, enum dns_section section, const void *dn, size_t dnlen, enum dns_type type, enum dns_class class, unsigned ttl, const void *any) { + size_t end = P->end; + int error; + + if ((error = dns_d_push(P, dn, dnlen))) + goto error; + + if (P->size - P->end < 4) + goto nobufs; + + P->data[P->end++] = 0xff & (type >> 8); + P->data[P->end++] = 0xff & (type >> 0); + + P->data[P->end++] = 0xff & (class >> 8); + P->data[P->end++] = 0xff & (class >> 0); + + if (section == DNS_S_QD) + goto update; + + if (P->size - P->end < 6) + goto nobufs; + + P->data[P->end++] = 0x7f & (ttl >> 24); + P->data[P->end++] = 0xff & (ttl >> 16); + P->data[P->end++] = 0xff & (ttl >> 8); + P->data[P->end++] = 0xff & (ttl >> 0); + + if ((error = dns_any_push(P, (union dns_any *)any, type))) + goto error; + +update: + switch (section) { + case DNS_S_QD: + if (dns_p_count(P, DNS_S_AN|DNS_S_NS|DNS_S_AR)) + goto order; + + if (!P->qd.base && (error = dns_p_study(P))) + goto error; + + dns_header(P)->qdcount = htons(ntohs(dns_header(P)->qdcount) + 1); + + P->qd.end = P->end; + P->an.base = P->end; + P->an.end = P->end; + P->ns.base = P->end; + P->ns.end = P->end; + P->ar.base = P->end; + P->ar.end = P->end; + + break; + case DNS_S_AN: + if (dns_p_count(P, DNS_S_NS|DNS_S_AR)) + goto order; + + if (!P->an.base && (error = dns_p_study(P))) + goto error; + + dns_header(P)->ancount = htons(ntohs(dns_header(P)->ancount) + 1); + + P->an.end = P->end; + P->ns.base = P->end; + P->ns.end = P->end; + P->ar.base = P->end; + P->ar.end = P->end; + + break; + case DNS_S_NS: + if (dns_p_count(P, DNS_S_AR)) + goto order; + + if (!P->ns.base && (error = dns_p_study(P))) + goto error; + + dns_header(P)->nscount = htons(ntohs(dns_header(P)->nscount) + 1); + + P->ns.end = P->end; + P->ar.base = P->end; + P->ar.end = P->end; + + break; + case DNS_S_AR: + if (!P->ar.base && (error = dns_p_study(P))) + goto error; + + dns_header(P)->arcount = htons(ntohs(dns_header(P)->arcount) + 1); + + P->ar.end = P->end; + + break; + default: + error = DNS_ESECTION; + + goto error; + } /* switch() */ + + return 0; +nobufs: + error = DNS_ENOBUFS; + + goto error; +order: + error = DNS_EORDER; + + goto error; +error: + P->end = end; + + return error; +} /* dns_p_push() */ + + +static void dns_p_dump3(struct dns_packet *P, struct dns_rr_i *I, FILE *fp) { + enum dns_section section; + struct dns_rr rr; + int error; + union dns_any any; + char pretty[sizeof any * 2]; + size_t len; + + fputs(";; [HEADER]\n", fp); + fprintf(fp, ";; qr : %s(%d)\n", (dns_header(P)->qr)? "RESPONSE" : "QUERY", dns_header(P)->qr); + fprintf(fp, ";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode); + fprintf(fp, ";; aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa); + fprintf(fp, ";; tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc); + fprintf(fp, ";; rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd); + fprintf(fp, ";; ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra); + fprintf(fp, ";; rcode : %s(%d)\n", dns_strrcode(dns_header(P)->rcode), dns_header(P)->rcode); + + section = 0; + + while (dns_rr_grep(&rr, 1, I, P, &error)) { + if (section != rr.section) + fprintf(fp, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section)); + + if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error))) + fprintf(fp, "%s\n", pretty); + + section = rr.section; + } +} /* dns_p_dump3() */ + + +void dns_p_dump(struct dns_packet *P, FILE *fp) { + dns_p_dump3(P, dns_rr_i_new(P, .section = 0), fp); +} /* dns_p_dump() */ + + +static void dns_s_unstudy(struct dns_s_memo *m) + { m->base = 0; m->end = 0; } + +static void dns_p_unstudy(struct dns_packet *P) { + dns_s_unstudy(&P->qd); + dns_s_unstudy(&P->an); + dns_s_unstudy(&P->ns); + dns_s_unstudy(&P->ar); +} /* dns_p_unstudy() */ + +static int dns_s_study(struct dns_s_memo *m, enum dns_section section, unsigned base, struct dns_packet *P) { + unsigned short count, rp; + + count = dns_p_count(P, section); + + for (rp = base; count && rp < P->end; count--) + rp = dns_rr_skip(rp, P); + + m->base = base; + m->end = rp; + + return 0; +} /* dns_s_study() */ + +int dns_p_study(struct dns_packet *P) { + int error; + + if ((error = dns_s_study(&P->qd, DNS_S_QD, 12, P))) + goto error; + + if ((error = dns_s_study(&P->an, DNS_S_AN, P->qd.end, P))) + goto error; + + if ((error = dns_s_study(&P->ns, DNS_S_NS, P->an.end, P))) + goto error; + + if ((error = dns_s_study(&P->ar, DNS_S_AR, P->ns.end, P))) + goto error; + + return 0; +error: + dns_p_unstudy(P); + + return error; +} /* dns_p_study() */ + + +/* + * D O M A I N N A M E R O U T I N E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef DNS_D_MAXPTRS +#define DNS_D_MAXPTRS 127 /* Arbitrary; possible, valid depth is something like packet size / 2 + fudge. */ +#endif + +static size_t dns_l_expand(unsigned char *dst, size_t lim, unsigned short src, unsigned short *nxt, const unsigned char *data, size_t end) { + unsigned short len; + unsigned nptrs = 0; + +retry: + if (src >= end) + goto invalid; + + switch (0x03 & (data[src] >> 6)) { + case 0x00: + len = (0x3f & (data[src++])); + + if (end - src < len) + goto invalid; + + if (lim > 0) { + memcpy(dst, &data[src], MIN(lim, len)); + + dst[MIN(lim - 1, len)] = '\0'; + } + + *nxt = src + len; + + return len; + case 0x01: + goto invalid; + case 0x02: + goto invalid; + case 0x03: + if (++nptrs > DNS_D_MAXPTRS) + goto invalid; + + if (end - src < 2) + goto invalid; + + src = ((0x3f & data[src + 0]) << 8) + | ((0xff & data[src + 1]) << 0); + + goto retry; + } /* switch() */ + + /* NOT REACHED */ +invalid: + *nxt = end; + + return 0; +} /* dns_l_expand() */ + + +static unsigned short dns_l_skip(unsigned short src, const unsigned char *data, size_t end) { + unsigned short len; + + if (src >= end) + goto invalid; + + switch (0x03 & (data[src] >> 6)) { + case 0x00: + len = (0x3f & (data[src++])); + + if (end - src < len) + goto invalid; + + return (len)? src + len : end; + case 0x01: + goto invalid; + case 0x02: + goto invalid; + case 0x03: + return end; + } /* switch() */ + + /* NOT REACHED */ +invalid: + return end; +} /* dns_l_skip() */ + + +size_t dns_d_trim(void *dst_, size_t lim, const void *src_, size_t len, int flags) { + unsigned char *dst = dst_; + const unsigned char *src = src_; + size_t dp = 0, sp = 0; + int lc; + + /* trim any leading dot(s) */ + while (sp < len && src[sp] == '.') + sp++; + + for (lc = 0; sp < len; lc = src[sp]) { + if (dp < lim) + dst[dp] = src[sp]; + + sp++; + dp++; + + /* trim extra dot(s) */ + while (sp < len && src[sp] == '.') + sp++; + } + + if ((flags & DNS_D_ANCHOR) && lc != '.') { + if (dp < lim) + dst[dp] = '.'; + + dp++; + } + + if (lim > 0) + dst[MIN(dp, lim - 1)] = '\0'; + + return dp; +} /* dns_d_trim() */ + + +char *dns_d_init(void *dst, size_t lim, const void *src, size_t len, int flags) { + if (flags & DNS_D_TRIM) { + dns_d_trim(dst, lim, src, len, flags); + } if (flags & DNS_D_ANCHOR) { + dns_d_anchor(dst, lim, src, len); + } else { + memmove(dst, src, MIN(lim, len)); + + if (lim > 0) + ((char *)dst)[MIN(len, lim - 1)] = '\0'; + } + + return dst; +} /* dns_d_init() */ + + +size_t dns_d_anchor(void *dst, size_t lim, const void *src, size_t len) { + if (len == 0) + return 0; + + memmove(dst, src, MIN(lim, len)); + + if (((const char *)src)[len - 1] != '.') { + if (len < lim) + ((char *)dst)[len] = '.'; + len++; + } + + if (lim > 0) + ((char *)dst)[MIN(lim - 1, len)] = '\0'; + + return len; +} /* dns_d_anchor() */ + + +size_t dns_d_cleave(void *dst, size_t lim, const void *src, size_t len) { + const char *dot; + + /* XXX: Skip any leading dot. Handles cleaving root ".". */ + if (len == 0 || !(dot = memchr((const char *)src + 1, '.', len - 1))) + return 0; + + len -= dot - (const char *)src; + + /* XXX: Unless root, skip the label's trailing dot. */ + if (len > 1) { + src = ++dot; + len--; + } else + src = dot; + + memmove(dst, src, MIN(lim, len)); + + if (lim > 0) + ((char *)dst)[MIN(lim - 1, len)] = '\0'; + + return len; +} /* dns_d_cleave() */ + + +size_t dns_d_comp(void *dst_, size_t lim, const void *src_, size_t len, struct dns_packet *P, int *error __UNUSED__) { + struct { unsigned char *b; size_t p, x; } dst, src; + unsigned char ch = '.'; + + dst.b = dst_; + dst.p = 0; + dst.x = 1; + + src.b = (unsigned char *)src_; + src.p = 0; + src.x = 0; + + while (src.x < len) { + ch = src.b[src.x]; + + if (ch == '.') { + if (dst.p < lim) + dst.b[dst.p] = (0x3f & (src.x - src.p)); + + dst.p = dst.x++; + src.p = ++src.x; + } else { + if (dst.x < lim) + dst.b[dst.x] = ch; + + dst.x++; + src.x++; + } + } /* while() */ + + if (src.x > src.p) { + if (dst.p < lim) + dst.b[dst.p] = (0x3f & (src.x - src.p)); + + dst.p = dst.x; + } + + if (dst.p > 1) { + if (dst.p < lim) + dst.b[dst.p] = 0x00; + + dst.p++; + } + +#if 1 + if (dst.p < lim) { + struct { unsigned char label[DNS_D_MAXLABEL + 1]; size_t len; unsigned short p, x, y; } a, b; + unsigned i; + + a.p = 0; + + while ((a.len = dns_l_expand(a.label, sizeof a.label, a.p, &a.x, dst.b, lim))) { + for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) { + b.p = P->dict[i]; + + while ((b.len = dns_l_expand(b.label, sizeof b.label, b.p, &b.x, P->data, P->end))) { + a.y = a.x; + b.y = b.x; + + while (a.len && b.len && 0 == strcasecmp((char *)a.label, (char *)b.label)) { + a.len = dns_l_expand(a.label, sizeof a.label, a.y, &a.y, dst.b, lim); + b.len = dns_l_expand(b.label, sizeof b.label, b.y, &b.y, P->data, P->end); + } + + if (a.len == 0 && b.len == 0 && b.p <= 0x3fff) { + dst.b[a.p++] = 0xc0 + | (0x3f & (b.p >> 8)); + dst.b[a.p++] = (0xff & (b.p >> 0)); + + return a.p; + } + + b.p = b.x; + } /* while() */ + } /* for() */ + + a.p = a.x; + } /* while() */ + } /* if () */ +#endif + + return dst.p; +} /* dns_d_comp() */ + + +unsigned short dns_d_skip(unsigned short src, struct dns_packet *P) { + unsigned short len; + + while (src < P->end) { + switch (0x03 & (P->data[src] >> 6)) { + case 0x00: /* FOLLOWS */ + len = (0x3f & P->data[src++]); + + if (0 == len) { +/* success ==> */ return src; + } else if (P->end - src > len) { + src += len; + + break; + } else + goto invalid; + + /* NOT REACHED */ + case 0x01: /* RESERVED */ + goto invalid; + case 0x02: /* RESERVED */ + goto invalid; + case 0x03: /* POINTER */ + if (P->end - src < 2) + goto invalid; + + src += 2; + +/* success ==> */ return src; + } /* switch() */ + } /* while() */ + +invalid: +//assert(0); + return P->end; +} /* dns_d_skip() */ + + +#include + +size_t dns_d_expand(void *dst, size_t lim, unsigned short src, struct dns_packet *P, int *error) { + size_t dstp = 0; + unsigned nptrs = 0; + unsigned char len; + + while (src < P->end) { + switch ((0x03 & (P->data[src] >> 6))) { + case 0x00: /* FOLLOWS */ + len = (0x3f & P->data[src]); + + if (0 == len) { + if (dstp == 0) { + if (dstp < lim) + ((unsigned char *)dst)[dstp] = '.'; + + dstp++; + } + + /* NUL terminate */ + if (lim > 0) + ((unsigned char *)dst)[MIN(dstp, lim - 1)] = '\0'; + +/* success ==> */ return dstp; + } + + src++; + + if (P->end - src < len) + goto toolong; + + if (dstp < lim) + memcpy(&((unsigned char *)dst)[dstp], &P->data[src], MIN(len, lim - dstp)); + + src += len; + dstp += len; + + if (dstp < lim) + ((unsigned char *)dst)[dstp] = '.'; + + dstp++; + + nptrs = 0; + + continue; + case 0x01: /* RESERVED */ + goto reserved; + case 0x02: /* RESERVED */ + goto reserved; + case 0x03: /* POINTER */ + if (++nptrs > DNS_D_MAXPTRS) + goto toolong; + + if (P->end - src < 2) + goto toolong; + + src = ((0x3f & P->data[src + 0]) << 8) + | ((0xff & P->data[src + 1]) << 0); + + continue; + } /* switch() */ + } /* while() */ + +toolong: + *error = DNS_EILLEGAL; + + if (lim > 0) + ((unsigned char *)dst)[MIN(dstp, lim - 1)] = '\0'; + + return 0; +reserved: + *error = DNS_EILLEGAL; + + if (lim > 0) + ((unsigned char *)dst)[MIN(dstp, lim - 1)] = '\0'; + + return 0; +} /* dns_d_expand() */ + + +int dns_d_push(struct dns_packet *P, const void *dn, size_t len) { + size_t lim = P->size - P->end; + unsigned dp = P->end; + int error; + + len = dns_d_comp(&P->data[dp], lim, dn, len, P, &error); + + if (len == 0) + return error; + if (len > lim) + return DNS_ENOBUFS; + + P->end += len; + + dns_p_dictadd(P, dp); + + return 0; +} /* dns_d_push() */ + + +size_t dns_d_cname(void *dst, size_t lim, const void *dn, size_t len, struct dns_packet *P, int *error_) { + char host[DNS_D_MAXNAME + 1]; + struct dns_rr_i i; + struct dns_rr rr; + unsigned depth; + int error; + + if (sizeof host <= dns_d_anchor(host, sizeof host, dn, len)) + { error = ENAMETOOLONG; goto error; } + + for (depth = 0; depth < 7; depth++) { + dns_rr_i_init(memset(&i, 0, sizeof i), P); + + i.section = DNS_S_ALL & ~DNS_S_QD; + i.name = host; + i.type = DNS_T_CNAME; + + if (!dns_rr_grep(&rr, 1, &i, P, &error)) + break; + + if ((error = dns_cname_parse((struct dns_cname *)host, &rr, P))) + goto error; + } + + return dns_strlcpy(dst, host, lim); +error: + *error_ = error; + + return 0; +} /* dns_d_cname() */ + + +/* + * R E S O U R C E R E C O R D R O U T I N E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +int dns_rr_copy(struct dns_packet *P, struct dns_rr *rr, struct dns_packet *Q) { + unsigned char dn[DNS_D_MAXNAME + 1]; + union dns_any any; + size_t len; + int error; + + if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, Q, &error))) + return error; + else if (len >= sizeof dn) + return DNS_EILLEGAL; + + if (rr->section != DNS_S_QD && (error = dns_any_parse(dns_any_init(&any, sizeof any), rr, Q))) + return error; + + return dns_p_push(P, rr->section, dn, len, rr->type, rr->class, rr->ttl, &any); +} /* dns_rr_copy() */ + + +int dns_rr_parse(struct dns_rr *rr, unsigned short src, struct dns_packet *P) { + unsigned short p = src; + + if (src >= P->end) + goto invalid; + + rr->dn.p = p; + rr->dn.len = (p = dns_d_skip(p, P)) - rr->dn.p; + + if (P->end - p < 4) + goto invalid; + + rr->type = ((0xff & P->data[p + 0]) << 8) + | ((0xff & P->data[p + 1]) << 0); + + rr->class = ((0xff & P->data[p + 2]) << 8) + | ((0xff & P->data[p + 3]) << 0); + + p += 4; + + if (src < dns_p_qend(P)) { + rr->section = DNS_S_QUESTION; + + rr->ttl = 0; + rr->rd.p = 0; + rr->rd.len = 0; + + return 0; + } + + if (P->end - p < 4) + goto invalid; + + rr->ttl = ((0x7f & P->data[p + 0]) << 24) + | ((0xff & P->data[p + 1]) << 16) + | ((0xff & P->data[p + 2]) << 8) + | ((0xff & P->data[p + 3]) << 0); + + p += 4; + + if (P->end - p < 2) + goto invalid; + + rr->rd.len = ((0xff & P->data[p + 0]) << 8) + | ((0xff & P->data[p + 1]) << 0); + rr->rd.p = p + 2; + + p += 2; + + if (P->end - p < rr->rd.len) + goto invalid; + + return 0; +invalid: +//assert(0); + return DNS_EILLEGAL; +} /* dns_rr_parse() */ + + +static unsigned short dns_rr_len(const unsigned short src, struct dns_packet *P) { + unsigned short rp, rdlen; + + rp = dns_d_skip(src, P); + + if (P->end - rp < 4) + return P->end - src; + + rp += 4; /* TYPE, CLASS */ + + if (rp <= dns_p_qend(P)) + return rp - src; + + if (P->end - rp < 6) + return P->end - src; + + rp += 6; /* TTL, RDLEN */ + + rdlen = ((0xff & P->data[rp - 2]) << 8) + | ((0xff & P->data[rp - 1]) << 0); + + if (P->end - rp < rdlen) + return P->end - src; + + rp += rdlen; + + return rp - src; +} /* dns_rr_len() */ + + +unsigned short dns_rr_skip(unsigned short src, struct dns_packet *P) { + return src + dns_rr_len(src, P); +} /* dns_rr_skip() */ + + +static enum dns_section dns_rr_section(unsigned short src, struct dns_packet *P) { + enum dns_section section; + unsigned count, ind; + unsigned short rp; + + if (src >= P->qd.base && src < P->qd.end) + return DNS_S_QD; + if (src >= P->an.base && src < P->an.end) + return DNS_S_AN; + if (src >= P->ns.base && src < P->ns.end) + return DNS_S_NS; + if (src >= P->ar.base && src < P->ar.end) + return DNS_S_AR; + + /* NOTE: Possibly bad memoization. Try it the hard-way. */ + + for (rp = 12, ind = 0; rp < src && rp < P->end; ind++) + rp = dns_rr_skip(rp, P); + + section = DNS_S_QD; + count = dns_p_count(P, section); + + while (ind >= count && section <= DNS_S_AR) { + section <<= 1; + count += dns_p_count(P, section); + } + + return DNS_S_ALL & section; +} /* dns_rr_section() */ + + +static enum dns_type dns_rr_type(unsigned short src, struct dns_packet *P) { + struct dns_rr rr; + int error; + + if ((error = dns_rr_parse(&rr, src, P))) + return 0; + + return rr.type; +} /* dns_rr_type() */ + + +int dns_rr_cmp(struct dns_rr *r0, struct dns_packet *P0, struct dns_rr *r1, struct dns_packet *P1) { + char host0[DNS_D_MAXNAME + 1], host1[DNS_D_MAXNAME + 1]; + union dns_any any0, any1; + int cmp, error; + size_t len; + + if ((cmp = r0->type - r1->type)) + return cmp; + + if ((cmp = r0->class - r1->class)) + return cmp; + + /* + * FIXME: Do label-by-label comparison to handle illegally long names? + */ + + if (!(len = dns_d_expand(host0, sizeof host0, r0->dn.p, P0, &error)) + || len >= sizeof host0) + return -1; + + if (!(len = dns_d_expand(host1, sizeof host1, r1->dn.p, P1, &error)) + || len >= sizeof host1) + return 1; + + if ((cmp = strcasecmp(host0, host1))) + return cmp; + + if (DNS_S_QD & (r0->section | r1->section)) { + if (r0->section == r1->section) + return 0; + + return (r0->section == DNS_S_QD)? -1 : 1; + } + + if ((error = dns_any_parse(&any0, r0, P0))) + return -1; + + if ((error = dns_any_parse(&any1, r1, P1))) + return 1; + + return dns_any_cmp(&any0, r0->type, &any1, r1->type); +} /* dns_rr_cmp() */ + + +static _Bool dns_rr_exists(struct dns_rr *rr0, struct dns_packet *P0, struct dns_packet *P1) { + struct dns_rr rr1; + + dns_rr_foreach(&rr1, P1, .section = rr0->section, .type = rr0->type) { + if (0 == dns_rr_cmp(rr0, P0, &rr1, P1)) + return 1; + } + + return 0; +} /* dns_rr_exists() */ + + +static unsigned short dns_rr_offset(struct dns_rr *rr) { + return rr->dn.p; +} /* dns_rr_offset() */ + + +static _Bool dns_rr_i_match(struct dns_rr *rr, struct dns_rr_i *i, struct dns_packet *P) { + if (i->section && !(rr->section & i->section)) + return 0; + + if (i->type && rr->type != i->type && i->type != DNS_T_ALL) + return 0; + + if (i->class && rr->class != i->class && i->class != DNS_C_ANY) + return 0; + + if (i->name) { + char dn[DNS_D_MAXNAME + 1]; + size_t len; + int error; + + if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, P, &error)) + || len >= sizeof dn) + return 0; + + if (0 != strcasecmp(dn, i->name)) + return 0; + } + + if (i->data && i->type && rr->section > DNS_S_QD) { + union dns_any rd; + int error; + + if ((error = dns_any_parse(&rd, rr, P))) + return 0; + + if (0 != dns_any_cmp(&rd, rr->type, i->data, i->type)) + return 0; + } + + return 1; +} /* dns_rr_i_match() */ + + +static unsigned short dns_rr_i_start(struct dns_rr_i *i, struct dns_packet *P) { + unsigned short rp; + struct dns_rr r0, rr; + int error; + + if ((i->section & DNS_S_QD) && P->qd.base) + rp = P->qd.base; + else if ((i->section & DNS_S_AN) && P->an.base) + rp = P->an.base; + else if ((i->section & DNS_S_NS) && P->ns.base) + rp = P->ns.base; + else if ((i->section & DNS_S_AR) && P->ar.base) + rp = P->ar.base; + else + rp = 12; + + for (rp = 12; rp < P->end; rp = dns_rr_skip(rp, P)) { + if ((error = dns_rr_parse(&rr, rp, P))) + continue; + + rr.section = dns_rr_section(rp, P); + + if (!dns_rr_i_match(&rr, i, P)) + continue; + + r0 = rr; + + goto lower; + } + + return P->end; +lower: + if (i->sort == &dns_rr_i_packet) + return dns_rr_offset(&r0); + + while ((rp = dns_rr_skip(rp, P)) < P->end) { + if ((error = dns_rr_parse(&rr, rp, P))) + continue; + + rr.section = dns_rr_section(rp, P); + + if (!dns_rr_i_match(&rr, i, P)) + continue; + + if (i->sort(&rr, &r0, i, P) < 0) + r0 = rr; + } + + return dns_rr_offset(&r0); +} /* dns_rr_i_start() */ + + +static unsigned short dns_rr_i_skip(unsigned short rp, struct dns_rr_i *i, struct dns_packet *P) { + struct dns_rr r0, r1, rr; + int error; + + if ((error = dns_rr_parse(&r0, rp, P))) + return P->end; + + r0.section = dns_rr_section(rp, P); + + rp = (i->sort == &dns_rr_i_packet)? dns_rr_skip(rp, P) : 12; + + for (; rp < P->end; rp = dns_rr_skip(rp, P)) { + if ((error = dns_rr_parse(&rr, rp, P))) + continue; + + rr.section = dns_rr_section(rp, P); + + if (!dns_rr_i_match(&rr, i, P)) + continue; + + if (i->sort(&rr, &r0, i, P) <= 0) + continue; + + r1 = rr; + + goto lower; + } + + return P->end; +lower: + if (i->sort == &dns_rr_i_packet) + return dns_rr_offset(&r1); + + while ((rp = dns_rr_skip(rp, P)) < P->end) { + if ((error = dns_rr_parse(&rr, rp, P))) + continue; + + rr.section = dns_rr_section(rp, P); + + if (!dns_rr_i_match(&rr, i, P)) + continue; + + if (i->sort(&rr, &r0, i, P) <= 0) + continue; + + if (i->sort(&rr, &r1, i, P) >= 0) + continue; + + r1 = rr; + } + + return dns_rr_offset(&r1); +} /* dns_rr_i_skip() */ + + +int dns_rr_i_packet(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i __UNUSED__, struct dns_packet *P __UNUSED__) { + return (int)a->dn.p - (int)b->dn.p; +} /* dns_rr_i_packet() */ + + +int dns_rr_i_order(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i __UNUSED__, struct dns_packet *P) { + int cmp; + + if ((cmp = a->section - b->section)) + return cmp; + + if (a->type != b->type) + return (int)a->dn.p - (int)b->dn.p; + + return dns_rr_cmp(a, P, b, P); +} /* dns_rr_i_order() */ + + +int dns_rr_i_shuffle(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P __UNUSED__) { + int cmp; + + while (!i->state.regs[0]) + i->state.regs[0] = dns_random(); + + if ((cmp = a->section - b->section)) + return cmp; + + return dns_k_shuffle16(a->dn.p, i->state.regs[0]) - dns_k_shuffle16(b->dn.p, i->state.regs[0]); +} /* dns_rr_i_shuffle() */ + + +struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *i, struct dns_packet *P __UNUSED__) { + static const struct dns_rr_i i_initializer; + + i->state = i_initializer.state; + i->saved = i->state; + + return i; +} /* dns_rr_i_init() */ + + +unsigned dns_rr_grep(struct dns_rr *rr, unsigned lim, struct dns_rr_i *i, struct dns_packet *P, int *error_) { + unsigned count = 0; + int error; + + switch (i->state.exec) { + case 0: + if (!i->sort) + i->sort = &dns_rr_i_packet; + + i->state.next = dns_rr_i_start(i, P); + i->state.exec++; + + /* FALL THROUGH */ + case 1: + while (count < lim && i->state.next < P->end) { + if ((error = dns_rr_parse(rr, i->state.next, P))) + goto error; + + rr->section = dns_rr_section(i->state.next, P); + + rr++; + count++; + i->state.count++; + + i->state.next = dns_rr_i_skip(i->state.next, i, P); + } /* while() */ + + break; + } /* switch() */ + + return count; +error: + *error_ = error; + + return count; +} /* dns_rr_grep() */ + + +static size_t dns__printchar(void *dst, size_t lim, size_t cp, unsigned char ch) { + if (cp < lim) + ((unsigned char *)dst)[cp] = ch; + + return 1; +} /* dns__printchar() */ + + +static size_t dns__printstring(void *dst, size_t lim, size_t cp, const void *src, size_t len) { + if (cp < lim) + memcpy(&((unsigned char *)dst)[cp], src, MIN(len, lim - cp)); + + return len; +} /* dns__printstring() */ + +#define dns__printstring5(a, b, c, d, e) dns__printstring((a), (b), (c), (d), (e)) +#define dns__printstring4(a, b, c, d) dns__printstring((a), (b), (c), (d), strlen((d))) +#define dns__printstring(...) DNS_PP_CALL(DNS_PP_XPASTE(dns__printstring, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__) + + +static void dns__printnul(void *dst, size_t lim, size_t off) { + if (lim > 0) + ((unsigned char *)dst)[MIN(off, lim - 1)] = '\0'; +} /* dns__printnul() */ + + +static size_t dns__print10(void *dst, size_t lim, size_t off, unsigned n, unsigned pad) { + unsigned char tmp[32]; + unsigned dp = off; + unsigned cp = 0; + unsigned d = 1000000000; + unsigned ch; + + pad = MAX(1, pad); + + while (d) { + if ((ch = n / d) || cp > 0) { + n -= ch * d; + + tmp[cp] = '0' + ch; + + cp++; + } + + d /= 10; + } + + while (cp < pad) { + dp += dns__printchar(dst, lim, dp, '0'); + pad--; + } + + dp += dns__printstring(dst, lim, dp, tmp, cp); + + return dp - off; +} /* dns__print10() */ + + +size_t dns_rr_print(void *dst, size_t lim, struct dns_rr *rr, struct dns_packet *P, int *error_) { + union dns_any any; + size_t cp, n, rdlen; + void *rd; + int error; + + cp = 0; + + if (rr->section == DNS_S_QD) + cp += dns__printchar(dst, lim, cp, ';'); + + if (!(n = dns_d_expand(&((unsigned char *)dst)[cp], (cp < lim)? lim - cp : 0, rr->dn.p, P, &error))) + goto error; + + cp += n; + + if (rr->section != DNS_S_QD) { + cp += dns__printchar(dst, lim, cp, ' '); + cp += dns__print10(dst, lim, cp, rr->ttl, 0); + } + + cp += dns__printchar(dst, lim, cp, ' '); + cp += dns__printstring(dst, lim, cp, dns_strclass(rr->class), strlen(dns_strclass(rr->class))); + cp += dns__printchar(dst, lim, cp, ' '); + cp += dns__printstring(dst, lim, cp, dns_strtype(rr->type), strlen(dns_strtype(rr->type))); + + if (rr->section == DNS_S_QD) + goto epilog; + + cp += dns__printchar(dst, lim, cp, ' '); + + if ((error = dns_any_parse(dns_any_init(&any, sizeof any), rr, P))) + goto error; + + if (cp < lim) { + rd = &((unsigned char *)dst)[cp]; + rdlen = lim - cp; + } else { + rd = 0; + rdlen = 0; + } + + cp += dns_any_print(rd, rdlen, &any, rr->type); + +epilog: + dns__printnul(dst, lim, cp); + + return cp; +error: + *error_ = error; + + return 0; +} /* dns_rr_print() */ + + +int dns_a_parse(struct dns_a *a, struct dns_rr *rr, struct dns_packet *P) { + unsigned long addr; + + if (rr->rd.len != 4) + return DNS_EILLEGAL; + + addr = ((0xff & P->data[rr->rd.p + 0]) << 24) + | ((0xff & P->data[rr->rd.p + 1]) << 16) + | ((0xff & P->data[rr->rd.p + 2]) << 8) + | ((0xff & P->data[rr->rd.p + 3]) << 0); + + a->addr.s_addr = htonl(addr); + + return 0; +} /* dns_a_parse() */ + + +int dns_a_push(struct dns_packet *P, struct dns_a *a) { + unsigned long addr; + + if (P->size - P->end < 6) + return DNS_ENOBUFS; + + P->data[P->end++] = 0x00; + P->data[P->end++] = 0x04; + + addr = ntohl(a->addr.s_addr); + + P->data[P->end++] = 0xff & (addr >> 24); + P->data[P->end++] = 0xff & (addr >> 16); + P->data[P->end++] = 0xff & (addr >> 8); + P->data[P->end++] = 0xff & (addr >> 0); + + return 0; +} /* dns_a_push() */ + + +size_t dns_a_arpa(void *dst, size_t lim, const struct dns_a *a) { + unsigned long a4 = ntohl(a->addr.s_addr); + size_t cp = 0; + unsigned i; + + for (i = 4; i > 0; i--) { + cp += dns__print10(dst, lim, cp, (0xff & a4), 0); + cp += dns__printchar(dst, lim, cp, '.'); + a4 >>= 8; + } + + cp += dns__printstring(dst, lim, cp, "in-addr.arpa."); + + dns__printnul(dst, lim, cp); + + return cp; +} /* dns_a_arpa() */ + + +int dns_a_cmp(const struct dns_a *a, const struct dns_a *b) { + if (ntohl(a->addr.s_addr) < ntohl(b->addr.s_addr)) + return -1; + if (ntohl(a->addr.s_addr) > ntohl(b->addr.s_addr)) + return 1; + + return 0; +} /* dns_a_cmp() */ + + +size_t dns_a_print(void *dst, size_t lim, struct dns_a *a) { + char addr[INET_ADDRSTRLEN + 1] = "0.0.0.0"; + size_t len; + + dns_inet_ntop(AF_INET, &a->addr, addr, sizeof addr); + + dns__printnul(dst, lim, (len = dns__printstring(dst, lim, 0, addr))); + + return len; +} /* dns_a_print() */ + + +int dns_aaaa_parse(struct dns_aaaa *aaaa, struct dns_rr *rr, struct dns_packet *P) { + if (rr->rd.len != sizeof aaaa->addr.s6_addr) + return DNS_EILLEGAL; + + memcpy(aaaa->addr.s6_addr, &P->data[rr->rd.p], sizeof aaaa->addr.s6_addr); + + return 0; +} /* dns_aaaa_parse() */ + + +int dns_aaaa_push(struct dns_packet *P, struct dns_aaaa *aaaa) { + if (P->size - P->end < 2 + sizeof aaaa->addr.s6_addr) + return DNS_ENOBUFS; + + P->data[P->end++] = 0x00; + P->data[P->end++] = 0x10; + + memcpy(&P->data[P->end], aaaa->addr.s6_addr, sizeof aaaa->addr.s6_addr); + + P->end += sizeof aaaa->addr.s6_addr; + + return 0; +} /* dns_aaaa_push() */ + + +int dns_aaaa_cmp(const struct dns_aaaa *a, const struct dns_aaaa *b) { + unsigned i; + int cmp; + + for (i = 0; i < lengthof(a->addr.s6_addr); i++) { + if ((cmp = (a->addr.s6_addr[i] - b->addr.s6_addr[i]))) + return cmp; + } + + return 0; +} /* dns_aaaa_cmp() */ + + +size_t dns_aaaa_arpa(void *dst, size_t lim, const struct dns_aaaa *aaaa) { + static const unsigned char hex[16] = "0123456789abcdef"; + size_t cp = 0; + unsigned nyble; + int i, j; + + for (i = sizeof aaaa->addr.s6_addr - 1; i >= 0; i--) { + nyble = aaaa->addr.s6_addr[i]; + + for (j = 0; j < 2; j++) { + cp += dns__printchar(dst, lim, cp, hex[0x0f & nyble]); + cp += dns__printchar(dst, lim, cp, '.'); + nyble >>= 4; + } + } + + cp += dns__printstring(dst, lim, cp, "ip6.arpa."); + + dns__printnul(dst, lim, cp); + + return cp; +} /* dns_aaaa_arpa() */ + + +size_t dns_aaaa_print(void *dst, size_t lim, struct dns_aaaa *aaaa) { + char addr[INET6_ADDRSTRLEN + 1] = "::"; + size_t len; + + dns_inet_ntop(AF_INET6, &aaaa->addr, addr, sizeof addr); + + dns__printnul(dst, lim, (len = dns__printstring(dst, lim, 0, addr))); + + return len; +} /* dns_aaaa_print() */ + + +int dns_mx_parse(struct dns_mx *mx, struct dns_rr *rr, struct dns_packet *P) { + size_t len; + int error; + + if (rr->rd.len < 3) + return DNS_EILLEGAL; + + mx->preference = (0xff00 & (P->data[rr->rd.p + 0] << 8)) + | (0x00ff & (P->data[rr->rd.p + 1] << 0)); + + if (!(len = dns_d_expand(mx->host, sizeof mx->host, rr->rd.p + 2, P, &error))) + return error; + else if (len >= sizeof mx->host) + return DNS_EILLEGAL; + + return 0; +} /* dns_mx_parse() */ + + +int dns_mx_push(struct dns_packet *P, struct dns_mx *mx) { + size_t end, len; + int error; + + if (P->size - P->end < 5) + return DNS_ENOBUFS; + + end = P->end; + P->end += 2; + + P->data[P->end++] = 0xff & (mx->preference >> 8); + P->data[P->end++] = 0xff & (mx->preference >> 0); + + if ((error = dns_d_push(P, mx->host, strlen(mx->host)))) + goto error; + + len = P->end - end - 2; + + P->data[end + 0] = 0xff & (len >> 8); + P->data[end + 1] = 0xff & (len >> 0); + + return 0; +error: + P->end = end; + + return error; +} /* dns_mx_push() */ + + +int dns_mx_cmp(const struct dns_mx *a, const struct dns_mx *b) { + int cmp; + + if ((cmp = a->preference - b->preference)) + return cmp; + + return strcasecmp(a->host, b->host); +} /* dns_mx_cmp() */ + + +size_t dns_mx_print(void *dst, size_t lim, struct dns_mx *mx) { + size_t cp = 0; + + cp += dns__print10(dst, lim, cp, mx->preference, 0); + cp += dns__printchar(dst, lim, cp, ' '); + cp += dns__printstring(dst, lim, cp, mx->host, strlen(mx->host)); + + dns__printnul(dst, lim, cp); + + return cp; +} /* dns_mx_print() */ + + +size_t dns_mx_cname(void *dst, size_t lim, struct dns_mx *mx) { + return dns_strlcpy(dst, mx->host, lim); +} /* dns_mx_cname() */ + + +int dns_ns_parse(struct dns_ns *ns, struct dns_rr *rr, struct dns_packet *P) { + size_t len; + int error; + + if (!(len = dns_d_expand(ns->host, sizeof ns->host, rr->rd.p, P, &error))) + return error; + else if (len >= sizeof ns->host) + return DNS_EILLEGAL; + + return 0; +} /* dns_ns_parse() */ + + +int dns_ns_push(struct dns_packet *P, struct dns_ns *ns) { + size_t end, len; + int error; + + if (P->size - P->end < 3) + return DNS_ENOBUFS; + + end = P->end; + P->end += 2; + + if ((error = dns_d_push(P, ns->host, strlen(ns->host)))) + goto error; + + len = P->end - end - 2; + + P->data[end + 0] = 0xff & (len >> 8); + P->data[end + 1] = 0xff & (len >> 0); + + return 0; +error: + P->end = end; + + return error; +} /* dns_ns_push() */ + + +int dns_ns_cmp(const struct dns_ns *a, const struct dns_ns *b) { + return strcasecmp(a->host, b->host); +} /* dns_ns_cmp() */ + + +size_t dns_ns_print(void *dst, size_t lim, struct dns_ns *ns) { + size_t cp; + + cp = dns__printstring(dst, lim, 0, ns->host, strlen(ns->host)); + + dns__printnul(dst, lim, cp); + + return cp; +} /* dns_ns_print() */ + + +size_t dns_ns_cname(void *dst, size_t lim, struct dns_ns *ns) { + return dns_strlcpy(dst, ns->host, lim); +} /* dns_ns_cname() */ + + +int dns_cname_parse(struct dns_cname *cname, struct dns_rr *rr, struct dns_packet *P) { + return dns_ns_parse((struct dns_ns *)cname, rr, P); +} /* dns_cname_parse() */ + + +int dns_cname_push(struct dns_packet *P, struct dns_cname *cname) { + return dns_ns_push(P, (struct dns_ns *)cname); +} /* dns_cname_push() */ + + +int dns_cname_cmp(const struct dns_cname *a, const struct dns_cname *b) { + return strcasecmp(a->host, b->host); +} /* dns_cname_cmp() */ + + +size_t dns_cname_print(void *dst, size_t lim, struct dns_cname *cname) { + return dns_ns_print(dst, lim, (struct dns_ns *)cname); +} /* dns_cname_print() */ + + +size_t dns_cname_cname(void *dst, size_t lim, struct dns_cname *cname) { + return dns_strlcpy(dst, cname->host, lim); +} /* dns_cname_cname() */ + + +int dns_soa_parse(struct dns_soa *soa, struct dns_rr *rr, struct dns_packet *P) { + struct { void *dst; size_t lim; } dn[] = + { { soa->mname, sizeof soa->mname }, + { soa->rname, sizeof soa->rname } }; + unsigned *ts[] = + { &soa->serial, &soa->refresh, &soa->retry, &soa->expire, &soa->minimum }; + unsigned short rp; + unsigned i, j, n; + int error; + + /* MNAME / RNAME */ + if ((rp = rr->rd.p) >= P->end) + return DNS_EILLEGAL; + + for (i = 0; i < lengthof(dn); i++) { + if (!(n = dns_d_expand(dn[i].dst, dn[i].lim, rp, P, &error))) + return error; + else if (n >= dn[i].lim) + return DNS_EILLEGAL; + + if ((rp = dns_d_skip(rp, P)) >= P->end) + return DNS_EILLEGAL; + } + + /* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */ + for (i = 0; i < lengthof(ts); i++) { + for (j = 0; j < 4; j++, rp++) { + if (rp >= P->end) + return DNS_EILLEGAL; + + *ts[i] <<= 8; + *ts[i] |= (0xff & P->data[rp]); + } + } + + return 0; +} /* dns_soa_parse() */ + + +int dns_soa_push(struct dns_packet *P, struct dns_soa *soa) { + void *dn[] = { soa->mname, soa->rname }; + unsigned ts[] = { (0xffffffff & soa->serial), + (0x7fffffff & soa->refresh), + (0x7fffffff & soa->retry), + (0x7fffffff & soa->expire), + (0xffffffff & soa->minimum) }; + unsigned i, j; + size_t end, len; + int error; + + end = P->end; + + if ((P->end += 2) >= P->size) + goto toolong; + + /* MNAME / RNAME */ + for (i = 0; i < lengthof(dn); i++) { + if ((error = dns_d_push(P, dn[i], strlen(dn[i])))) + goto error; + } + + /* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */ + for (i = 0; i < lengthof(ts); i++) { + if ((P->end += 4) >= P->size) + goto toolong; + + for (j = 1; j <= 4; j++) { + P->data[P->end - j] = (0xff & ts[i]); + ts[i] >>= 8; + } + } + + len = P->end - end - 2; + P->data[end + 0] = (0xff & (len >> 8)); + P->data[end + 1] = (0xff & (len >> 0)); + + return 0; +toolong: + error = DNS_ENOBUFS; + + /* FALL THROUGH */ +error: + P->end = end; + + return error; +} /* dns_soa_push() */ + + +int dns_soa_cmp(const struct dns_soa *a, const struct dns_soa *b) { + int cmp; + + if ((cmp = strcasecmp(a->mname, b->mname))) + return cmp; + + if ((cmp = strcasecmp(a->rname, b->rname))) + return cmp; + + if (a->serial > b->serial) + return -1; + else if (a->serial < b->serial) + return 1; + + if (a->refresh > b->refresh) + return -1; + else if (a->refresh < b->refresh) + return 1; + + if (a->retry > b->retry) + return -1; + else if (a->retry < b->retry) + return 1; + + if (a->expire > b->expire) + return -1; + else if (a->expire < b->expire) + return 1; + + if (a->minimum > b->minimum) + return -1; + else if (a->minimum < b->minimum) + return 1; + + return 0; +} /* dns_soa_cmp() */ + + +size_t dns_soa_print(void *dst, size_t lim, struct dns_soa *soa) { + size_t cp = 0; + + cp += dns__printstring(dst, lim, cp, soa->mname, strlen(soa->mname)); + cp += dns__printchar(dst, lim, cp, ' '); + cp += dns__printstring(dst, lim, cp, soa->rname, strlen(soa->rname)); + cp += dns__printchar(dst, lim, cp, ' '); + cp += dns__print10(dst, lim, cp, soa->serial, 0); + cp += dns__printchar(dst, lim, cp, ' '); + cp += dns__print10(dst, lim, cp, soa->refresh, 0); + cp += dns__printchar(dst, lim, cp, ' '); + cp += dns__print10(dst, lim, cp, soa->retry, 0); + cp += dns__printchar(dst, lim, cp, ' '); + cp += dns__print10(dst, lim, cp, soa->expire, 0); + cp += dns__printchar(dst, lim, cp, ' '); + cp += dns__print10(dst, lim, cp, soa->minimum, 0); + + dns__printnul(dst, lim, cp); + + return cp; +} /* dns_soa_print() */ + + +int dns_srv_parse(struct dns_srv *srv, struct dns_rr *rr, struct dns_packet *P) { + unsigned short rp; + unsigned i; + size_t n; + int error; + + memset(srv, '\0', sizeof *srv); + + rp = rr->rd.p; + + if (P->size - P->end < 6) + return DNS_EILLEGAL; + + for (i = 0; i < 2; i++, rp++) { + srv->priority <<= 8; + srv->priority |= (0xff & P->data[rp]); + } + + for (i = 0; i < 2; i++, rp++) { + srv->weight <<= 8; + srv->weight |= (0xff & P->data[rp]); + } + + for (i = 0; i < 2; i++, rp++) { + srv->port <<= 8; + srv->port |= (0xff & P->data[rp]); + } + + if (!(n = dns_d_expand(srv->target, sizeof srv->target, rp, P, &error))) + return error; + else if (n >= sizeof srv->target) + return DNS_EILLEGAL; + + return 0; +} /* dns_srv_parse() */ + + +int dns_srv_push(struct dns_packet *P, struct dns_srv *srv) { + size_t end, len; + int error; + + end = P->end; + + if (P->size - P->end < 2) + goto toolong; + + P->end += 2; + + if (P->size - P->end < 6) + goto toolong; + + P->data[P->end++] = 0xff & (srv->priority >> 8); + P->data[P->end++] = 0xff & (srv->priority >> 0); + + P->data[P->end++] = 0xff & (srv->weight >> 8); + P->data[P->end++] = 0xff & (srv->weight >> 0); + + P->data[P->end++] = 0xff & (srv->port >> 8); + P->data[P->end++] = 0xff & (srv->port >> 0); + + if (0 == (len = dns_d_comp(&P->data[P->end], P->size - P->end, srv->target, strlen(srv->target), P, &error))) + goto error; + else if (P->size - P->end < len) + goto toolong; + + P->end += len; + + if (P->end > 65535) + goto toolong; + + len = P->end - end - 2; + + P->data[end + 0] = 0xff & (len >> 8); + P->data[end + 1] = 0xff & (len >> 0); + + return 0; +toolong: + error = DNS_ENOBUFS; + + /* FALL THROUGH */ +error: + P->end = end; + + return error; +} /* dns_srv_push() */ + + +int dns_srv_cmp(const struct dns_srv *a, const struct dns_srv *b) { + int cmp; + + if ((cmp = a->priority - b->priority)) + return cmp; + + /* + * FIXME: We need some sort of random seed to implement the dynamic + * weighting required by RFC 2782. + */ + if ((cmp = a->weight - b->weight)) + return cmp; + + if ((cmp = a->port - b->port)) + return cmp; + + return strcasecmp(a->target, b->target); +} /* dns_srv_cmp() */ + + +size_t dns_srv_print(void *dst, size_t lim, struct dns_srv *srv) { + size_t cp = 0; + + cp += dns__print10(dst, lim, cp, srv->priority, 0); + cp += dns__printchar(dst, lim, cp, ' '); + cp += dns__print10(dst, lim, cp, srv->weight, 0); + cp += dns__printchar(dst, lim, cp, ' '); + cp += dns__print10(dst, lim, cp, srv->port, 0); + cp += dns__printchar(dst, lim, cp, ' '); + cp += dns__printstring(dst, lim, cp, srv->target, strlen(srv->target)); + + dns__printnul(dst, lim, cp); + + return cp; +} /* dns_srv_print() */ + + +size_t dns_srv_cname(void *dst, size_t lim, struct dns_srv *srv) { + return dns_strlcpy(dst, srv->target, lim); +} /* dns_srv_cname() */ + + +int dns_ptr_parse(struct dns_ptr *ptr, struct dns_rr *rr, struct dns_packet *P) { + return dns_ns_parse((struct dns_ns *)ptr, rr, P); +} /* dns_ptr_parse() */ + + +int dns_ptr_push(struct dns_packet *P, struct dns_ptr *ptr) { + return dns_ns_push(P, (struct dns_ns *)ptr); +} /* dns_ptr_push() */ + + +size_t dns_ptr_qname(void *dst, size_t lim, int af, void *addr) { + unsigned len = (af == AF_INET6) + ? dns_aaaa_arpa(dst, lim, addr) + : dns_a_arpa(dst, lim, addr); + + dns__printnul(dst, lim, len); + + return len; +} /* dns_ptr_qname() */ + + +int dns_ptr_cmp(const struct dns_ptr *a, const struct dns_ptr *b) { + return strcasecmp(a->host, b->host); +} /* dns_ptr_cmp() */ + + +size_t dns_ptr_print(void *dst, size_t lim, struct dns_ptr *ptr) { + return dns_ns_print(dst, lim, (struct dns_ns *)ptr); +} /* dns_ptr_print() */ + + +size_t dns_ptr_cname(void *dst, size_t lim, struct dns_ptr *ptr) { + return dns_strlcpy(dst, ptr->host, lim); +} /* dns_ptr_cname() */ + + +int dns_sshfp_parse(struct dns_sshfp *fp, struct dns_rr *rr, struct dns_packet *P) { + unsigned p = rr->rd.p, pe = rr->rd.p + rr->rd.len; + + if (pe - p < 2) + return DNS_EILLEGAL; + + fp->algo = P->data[p++]; + fp->type = P->data[p++]; + + switch (fp->type) { + case DNS_SSHFP_SHA1: + if (pe - p < sizeof fp->digest.sha1) + return DNS_EILLEGAL; + + memcpy(fp->digest.sha1, &P->data[p], sizeof fp->digest.sha1); + + break; + default: + break; + } /* switch() */ + + return 0; +} /* dns_sshfp_parse() */ + + +int dns_sshfp_push(struct dns_packet *P, struct dns_sshfp *fp) { + unsigned p = P->end, pe = P->size, n; + + if (pe - p < 4) + return DNS_ENOBUFS; + + p += 2; + P->data[p++] = 0xff & fp->algo; + P->data[p++] = 0xff & fp->type; + + switch (fp->type) { + case DNS_SSHFP_SHA1: + if (pe - p < sizeof fp->digest.sha1) + return DNS_ENOBUFS; + + memcpy(&P->data[p], fp->digest.sha1, sizeof fp->digest.sha1); + p += sizeof fp->digest.sha1; + + break; + default: + return DNS_EILLEGAL; + } /* switch() */ + + n = p - P->end - 2; + P->data[P->end++] = 0xff & (n >> 8); + P->data[P->end++] = 0xff & (n >> 0); + P->end = p; + + return 0; +} /* dns_sshfp_push() */ + + +int dns_sshfp_cmp(const struct dns_sshfp *a, const struct dns_sshfp *b) { + int cmp; + + if ((cmp = a->algo - b->algo) || (cmp - a->type - b->type)) + return cmp; + + switch (a->type) { + case DNS_SSHFP_SHA1: + return memcmp(a->digest.sha1, b->digest.sha1, sizeof a->digest.sha1); + default: + return 0; + } /* switch() */ + + /* NOT REACHED */ +} /* dns_sshfp_cmp() */ + + +size_t dns_sshfp_print(void *dst, size_t lim, struct dns_sshfp *fp) { + static const unsigned char hex[16] = "0123456789abcdef"; + size_t i, p = 0; + + p += dns__print10(dst, lim, p, fp->algo, 0); + p += dns__printchar(dst, lim, p, ' '); + p += dns__print10(dst, lim, p, fp->type, 0); + p += dns__printchar(dst, lim, p, ' '); + + switch (fp->type) { + case DNS_SSHFP_SHA1: + for (i = 0; i < sizeof fp->digest.sha1; i++) { + p += dns__printchar(dst, lim, p, hex[0x0f & (fp->digest.sha1[i] >> 4)]); + p += dns__printchar(dst, lim, p, hex[0x0f & (fp->digest.sha1[i] >> 0)]); + } + + break; + default: + p += dns__printchar(dst, lim, p, '0'); + + break; + } /* switch() */ + + dns__printnul(dst, lim, p); + + return p; +} /* dns_sshfp_print() */ + + +struct dns_txt *dns_txt_init(struct dns_txt *txt, size_t size) { + assert(size > offsetof(struct dns_txt, data)); + + txt->size = size - offsetof(struct dns_txt, data); + txt->len = 0; + + return txt; +} /* dns_txt_init() */ + + +int dns_txt_parse(struct dns_txt *txt, struct dns_rr *rr, struct dns_packet *P) { + struct { unsigned char *b; size_t p, end; } dst, src; + unsigned n; + + dst.b = txt->data; + dst.p = 0; + dst.end = txt->size; + + src.b = P->data; + src.p = rr->rd.p; + src.end = src.p + rr->rd.len; + + while (src.p < src.end) { + n = 0xff & P->data[src.p++]; + + if (src.end - src.p < n || dst.end - dst.p < n) + return DNS_EILLEGAL; + + memcpy(&dst.b[dst.p], &src.b[src.p], n); + + dst.p += n; + src.p += n; + } + + txt->len = dst.p; + + return 0; +} /* dns_txt_parse() */ + + +int dns_txt_push(struct dns_packet *P, struct dns_txt *txt) { + struct { unsigned char *b; size_t p, end; } dst, src; + unsigned n; + + dst.b = P->data; + dst.p = P->end; + dst.end = P->size; + + src.b = txt->data; + src.p = 0; + src.end = txt->len; + + if (dst.end - dst.p < 2) + return DNS_ENOBUFS; + + n = txt->len + ((txt->len + 254) / 255); + + dst.b[dst.p++] = 0xff & (n >> 8); + dst.b[dst.p++] = 0xff & (n >> 0); + + while (src.p < src.end) { + n = MIN(255, src.end - src.p); + + if (dst.p >= dst.end) + return DNS_ENOBUFS; + + dst.b[dst.p++] = n; + + if (dst.end - dst.p < n) + return DNS_ENOBUFS; + + memcpy(&dst.b[dst.p], &src.b[src.p], n); + + dst.p += n; + src.p += n; + } + + P->end = dst.p; + + return 0; +} /* dns_txt_push() */ + + +int dns_txt_cmp(const struct dns_txt *a __UNUSED__, const struct dns_txt *b __UNUSED__) { + return -1; +} /* dns_txt_cmp() */ + + +size_t dns_txt_print(void *dst_, size_t lim, struct dns_txt *txt) { + struct { unsigned char *b; size_t p, end; } dst, src; + unsigned ch; + + dst.b = dst_; + dst.end = lim; + dst.p = 0; + + src.b = txt->data; + src.end = txt->len; + src.p = 0; + + dst.p += dns__printchar(dst.b, dst.end, dst.p, '"'); + + while (src.p < src.end) { + ch = src.b[src.p]; + + if (0 == (src.p++ % 255) && src.p != 1) { + dst.p += dns__printchar(dst.b, dst.end, dst.p, '"'); + dst.p += dns__printchar(dst.b, dst.end, dst.p, ' '); + dst.p += dns__printchar(dst.b, dst.end, dst.p, '"'); + } + + if (ch < 32 || ch > 126 || ch == '"' || ch == '\\') { + dst.p += dns__printchar(dst.b, dst.end, dst.p, '\\'); + dst.p += dns__print10(dst.b, dst.end, dst.p, ch, 3); + } else { + dst.p += dns__printchar(dst.b, dst.end, dst.p, ch); + } + } + + dst.p += dns__printchar(dst.b, dst.end, dst.p, '"'); + + dns__printnul(dst.b, dst.end, dst.p); + + return dst.p; +} /* dns_txt_print() */ + + +static const struct { + enum dns_type type; + const char *name; + int (*parse)(); + int (*push)(); + int (*cmp)(); + size_t (*print)(); + size_t (*cname)(); +} dns_rrtypes[] = { + { DNS_T_A, "A", &dns_a_parse, &dns_a_push, &dns_a_cmp, &dns_a_print, 0 }, + { DNS_T_AAAA, "AAAA", &dns_aaaa_parse, &dns_aaaa_push, &dns_aaaa_cmp, &dns_aaaa_print, 0 }, + { DNS_T_MX, "MX", &dns_mx_parse, &dns_mx_push, &dns_mx_cmp, &dns_mx_print, &dns_mx_cname }, + { DNS_T_NS, "NS", &dns_ns_parse, &dns_ns_push, &dns_ns_cmp, &dns_ns_print, &dns_ns_cname }, + { DNS_T_CNAME, "CNAME", &dns_cname_parse, &dns_cname_push, &dns_cname_cmp, &dns_cname_print, &dns_cname_cname }, + { DNS_T_SOA, "SOA", &dns_soa_parse, &dns_soa_push, &dns_soa_cmp, &dns_soa_print, 0 }, + { DNS_T_SRV, "SRV", &dns_srv_parse, &dns_srv_push, &dns_srv_cmp, &dns_srv_print, &dns_srv_cname }, + { DNS_T_PTR, "PTR", &dns_ptr_parse, &dns_ptr_push, &dns_ptr_cmp, &dns_ptr_print, &dns_ptr_cname }, + { DNS_T_TXT, "TXT", &dns_txt_parse, &dns_txt_push, &dns_txt_cmp, &dns_txt_print, 0 }, + { DNS_T_SPF, "SPF", &dns_txt_parse, &dns_txt_push, &dns_txt_cmp, &dns_txt_print, 0 }, + { DNS_T_SSHFP, "SSHFP", &dns_sshfp_parse, &dns_sshfp_push, &dns_sshfp_cmp, &dns_sshfp_print, 0 }, +}; /* dns_rrtypes[] */ + + +union dns_any *dns_any_init(union dns_any *any, size_t size) { + return (union dns_any *)dns_txt_init(&any->rdata, size); +} /* dns_any_init() */ + + +int dns_any_parse(union dns_any *any, struct dns_rr *rr, struct dns_packet *P) { + unsigned i; + + for (i = 0; i < lengthof(dns_rrtypes); i++) { + if (dns_rrtypes[i].type == rr->type) + return dns_rrtypes[i].parse(any, rr, P); + } + + if (rr->rd.len > any->rdata.size) + return DNS_EILLEGAL; + + memcpy(any->rdata.data, &P->data[rr->rd.p], rr->rd.len); + any->rdata.len = rr->rd.len; + + return 0; +} /* dns_any_parse() */ + + +int dns_any_push(struct dns_packet *P, union dns_any *any, enum dns_type type) { + unsigned i; + + for (i = 0; i < lengthof(dns_rrtypes); i++) { + if (dns_rrtypes[i].type == type) + return dns_rrtypes[i].push(P, any); + } + + if (P->size - P->end < any->rdata.len + 2) + return DNS_ENOBUFS; + + P->data[P->end++] = 0xff & (any->rdata.len >> 8); + P->data[P->end++] = 0xff & (any->rdata.len >> 0); + + memcpy(&P->data[P->end], any->rdata.data, any->rdata.len); + P->end += any->rdata.len; + + return 0; +} /* dns_any_push() */ + + +int dns_any_cmp(const union dns_any *a, enum dns_type x, const union dns_any *b, enum dns_type y) { + unsigned i; + int cmp; + + if ((cmp = x - y)) + return cmp; + + for (i = 0; i < lengthof(dns_rrtypes); i++) { + if (dns_rrtypes[i].type == x) + return dns_rrtypes[i].cmp(a, b); + } + + return -1; +} /* dns_any_cmp() */ + + +size_t dns_any_print(void *dst_, size_t lim, union dns_any *any, enum dns_type type) { + struct { unsigned char *b; size_t p, end; } dst, src; + unsigned i, ch; + + for (i = 0; i < lengthof(dns_rrtypes); i++) { + if (dns_rrtypes[i].type == type) + return dns_rrtypes[i].print(dst_, lim, any); + } + + dst.b = dst_; + dst.end = lim; + dst.p = 0; + + src.b = any->rdata.data; + src.end = any->rdata.len; + src.p = 0; + + dst.p += dns__printchar(dst.b, dst.end, dst.p, '"'); + + while (src.p < src.end) { + ch = src.b[src.p++]; + + dst.p += dns__printchar(dst.b, dst.end, dst.p, '\\'); + dst.p += dns__print10(dst.b, dst.end, dst.p, ch, 3); + } + + dst.p += dns__printchar(dst.b, dst.end, dst.p, '"'); + + dns__printnul(dst.b, dst.end, dst.p); + + return dst.p; +} /* dns_any_print() */ + + +size_t dns_any_cname(void *dst, size_t lim, union dns_any *any, enum dns_type type) { + unsigned i; + + for (i = 0; i < lengthof(dns_rrtypes); i++) { + if (dns_rrtypes[i].type == type) + return (dns_rrtypes[i].cname)? dns_rrtypes[i].cname(dst, lim, any) : 0; + } + + return 0; +} /* dns_any_cname() */ + + +/* + * H O S T S R O U T I N E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +struct dns_hosts { + struct dns_hosts_entry { + char host[DNS_D_MAXNAME + 1]; + char arpa[73 + 1]; + + int af; + + union { + struct in_addr a4; + struct in6_addr a6; + } addr; + + _Bool alias; + + struct dns_hosts_entry *next; + } *head, **tail; + + dns_atomic_t refcount; +}; /* struct dns_hosts */ + + +struct dns_hosts *dns_hosts_open(int *error) { + static const struct dns_hosts hosts_initializer = { .refcount = 1 }; + struct dns_hosts *hosts; + + if (!(hosts = malloc(sizeof *hosts))) + goto syerr; + + *hosts = hosts_initializer; + + hosts->tail = &hosts->head; + + return hosts; +syerr: + *error = dns_syerr(); + + free(hosts); + + return 0; +} /* dns_hosts_open() */ + + +void dns_hosts_close(struct dns_hosts *hosts) { + struct dns_hosts_entry *ent, *xnt; + + if (!hosts || 1 != dns_hosts_release(hosts)) + return; + + for (ent = hosts->head; ent; ent = xnt) { + xnt = ent->next; + + free(ent); + } + + free(hosts); + + return; +} /* dns_hosts_close() */ + + +unsigned dns_hosts_acquire(struct dns_hosts *hosts) { + return dns_atomic_inc(&hosts->refcount); +} /* dns_hosts_acquire() */ + + +unsigned dns_hosts_release(struct dns_hosts *hosts) { + return dns_atomic_dec(&hosts->refcount); +} /* dns_hosts_release() */ + + +struct dns_hosts *dns_hosts_mortal(struct dns_hosts *hosts) { + if (hosts) + dns_hosts_release(hosts); + + return hosts; +} /* dns_hosts_mortal() */ + + +struct dns_hosts *dns_hosts_local(int *error_) { + struct dns_hosts *hosts; + int error; + + if (!(hosts = dns_hosts_open(&error))) + goto error; + + if ((error = dns_hosts_loadpath(hosts, "/etc/hosts"))) + goto error; + + return hosts; +error: + *error_ = error; + + dns_hosts_close(hosts); + + return 0; +} /* dns_hosts_local() */ + + +#define dns_hosts_issep(ch) (isspace(ch)) +#define dns_hosts_iscom(ch) ((ch) == '#' || (ch) == ';') + +int dns_hosts_loadfile(struct dns_hosts *hosts, FILE *fp) { + struct dns_hosts_entry ent; + char word[MAX(INET6_ADDRSTRLEN, DNS_D_MAXNAME) + 1]; + unsigned wp, wc, skip; + int ch, error; + + rewind(fp); + + do { + memset(&ent, '\0', sizeof ent); + wc = 0; + skip = 0; + + do { + memset(word, '\0', sizeof word); + wp = 0; + + while (EOF != (ch = fgetc(fp)) && ch != '\n') { + skip |= !!dns_hosts_iscom(ch); + + if (skip) + continue; + + if (dns_hosts_issep(ch)) + break; + + if (wp < sizeof word - 1) + word[wp] = ch; + wp++; + } + + if (!wp) + continue; + + wc++; + + switch (wc) { + case 0: + break; + case 1: + ent.af = (strchr(word, ':'))? AF_INET6 : AF_INET; + skip = (1 != dns_inet_pton(ent.af, word, &ent.addr)); + + break; + default: + if (!wp) + break; + + dns_d_anchor(ent.host, sizeof ent.host, word, wp); + + if ((error = dns_hosts_insert(hosts, ent.af, &ent.addr, ent.host, (wc > 2)))) + return error; + + break; + } /* switch() */ + } while (ch != EOF && ch != '\n'); + } while (ch != EOF); + + return 0; +} /* dns_hosts_loadfile() */ + + +int dns_hosts_loadpath(struct dns_hosts *hosts, const char *path) { + FILE *fp; + int error; + + if (!(fp = fopen(path, "r"))) + return dns_syerr(); + + error = dns_hosts_loadfile(hosts, fp); + + fclose(fp); + + return error; +} /* dns_hosts_loadpath() */ + + +int dns_hosts_dump(struct dns_hosts *hosts, FILE *fp) { + struct dns_hosts_entry *ent, *xnt; + char addr[INET6_ADDRSTRLEN + 1]; + unsigned i; + + for (ent = hosts->head; ent; ent = xnt) { + xnt = ent->next; + + dns_inet_ntop(ent->af, &ent->addr, addr, sizeof addr); + + fputs(addr, fp); + + for (i = strlen(addr); i < INET_ADDRSTRLEN; i++) + fputc(' ', fp); + + fputc(' ', fp); + + fputs(ent->host, fp); + fputc('\n', fp); + } + + return 0; +} /* dns_hosts_dump() */ + + +int dns_hosts_insert(struct dns_hosts *hosts, int af, const void *addr, const void *host, _Bool alias) { + struct dns_hosts_entry *ent; + int error; + + if (!(ent = malloc(sizeof *ent))) + goto syerr; + + dns_d_anchor(ent->host, sizeof ent->host, host, strlen(host)); + + switch ((ent->af = af)) { + case AF_INET6: + memcpy(&ent->addr.a6, addr, sizeof ent->addr.a6); + + dns_aaaa_arpa(ent->arpa, sizeof ent->arpa, addr); + + break; + case AF_INET: + memcpy(&ent->addr.a4, addr, sizeof ent->addr.a4); + + dns_a_arpa(ent->arpa, sizeof ent->arpa, addr); + + break; + default: + error = EINVAL; + + goto error; + } /* switch() */ + + ent->alias = alias; + + ent->next = 0; + *hosts->tail = ent; + hosts->tail = &ent->next; + + return 0; +syerr: + error = dns_syerr(); +error: + free(ent); + + return error; +} /* dns_hosts_insert() */ + + +struct dns_packet *dns_hosts_query(struct dns_hosts *hosts, struct dns_packet *Q, int *error_) { + struct dns_packet *P = dns_p_new(512); + struct dns_packet *A = 0; + struct dns_rr rr; + struct dns_hosts_entry *ent; + int error, af; + char qname[DNS_D_MAXNAME + 1]; + size_t qlen; + + if ((error = dns_rr_parse(&rr, 12, Q))) + goto error; + + if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, Q, &error))) + goto error; + else if (qlen >= sizeof qname) + goto toolong; + + if ((error = dns_p_push(P, DNS_S_QD, qname, qlen, rr.type, rr.class, 0, 0))) + goto error; + + switch (rr.type) { + case DNS_T_PTR: + for (ent = hosts->head; ent; ent = ent->next) { + if (ent->alias || 0 != strcasecmp(qname, ent->arpa)) + continue; + + if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, ent->host))) + goto error; + } + + break; + case DNS_T_AAAA: + af = AF_INET6; + + goto loop; + case DNS_T_A: + af = AF_INET; + +loop: for (ent = hosts->head; ent; ent = ent->next) { + if (ent->af != af || 0 != strcasecmp(qname, ent->host)) + continue; + + if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, &ent->addr))) + goto error; + } + + break; + default: + break; + } /* switch() */ + + + if (!(A = dns_p_copy(dns_p_make(P->end, &error), P))) + goto error; + + return A; +toolong: + error = DNS_EILLEGAL; +error: + *error_ = error; + + free(A); + + return 0; +} /* dns_hosts_query() */ + + +/* + * R E S O L V . C O N F R O U T I N E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +struct dns_resolv_conf *dns_resconf_open(int *error) { + static const struct dns_resolv_conf resconf_initializer + = { .lookup = "bf", .options = { .ndots = 1, .timeout = 5, .attempts = 2, .tcp = DNS_RESCONF_TCP_ENABLE, }, + .iface = { .ss_family = AF_INET }, }; + struct dns_resolv_conf *resconf; + struct sockaddr_in *sin; + + if (!(resconf = malloc(sizeof *resconf))) + goto syerr; + + *resconf = resconf_initializer; + + sin = (struct sockaddr_in *)&resconf->nameserver[0]; + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = INADDR_ANY; + sin->sin_port = htons(53); +#if defined(SA_LEN) + sin->sin_len = sizeof *sin; +#endif + + if (0 != gethostname(resconf->search[0], sizeof resconf->search[0])) + goto syerr; + + dns_d_anchor(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0])); + dns_d_cleave(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0])); + + /* + * XXX: If gethostname() returned a string without any label + * separator, then search[0][0] should be NUL. + */ + + dns_resconf_acquire(resconf); + + return resconf; +syerr: + *error = dns_syerr(); + + free(resconf); + + return 0; +} /* dns_resconf_open() */ + + +void dns_resconf_close(struct dns_resolv_conf *resconf) { + if (!resconf || 1 != dns_resconf_release(resconf)) + return /* void */; + + free(resconf); +} /* dns_resconf_close() */ + + +unsigned dns_resconf_acquire(struct dns_resolv_conf *resconf) { + return dns_atomic_inc(&resconf->_.refcount); +} /* dns_resconf_acquire() */ + + +unsigned dns_resconf_release(struct dns_resolv_conf *resconf) { + return dns_atomic_dec(&resconf->_.refcount); +} /* dns_resconf_release() */ + + +struct dns_resolv_conf *dns_resconf_mortal(struct dns_resolv_conf *resconf) { + if (resconf) + dns_resconf_release(resconf); + + return resconf; +} /* dns_resconf_mortal() */ + + +struct dns_resolv_conf *dns_resconf_local(int *error_) { + struct dns_resolv_conf *resconf; + int error; + + if (!(resconf = dns_resconf_open(&error))) + goto error; + + if ((error = dns_resconf_loadpath(resconf, "/etc/resolv.conf"))) + goto error; + + return resconf; +error: + *error_ = error; + + dns_resconf_close(resconf); + + return 0; +} /* dns_resconf_local() */ + + +struct dns_resolv_conf *dns_resconf_root(int *error_) { + struct dns_resolv_conf *resconf; + int error; + + if (!(resconf = dns_resconf_open(&error))) + goto error; + + if ((error = dns_resconf_loadpath(resconf, "/etc/resolv.conf"))) + goto error; + + resconf->options.recurse = 1; + + return resconf; +error: + *error_ = error; + + dns_resconf_close(resconf); + + return 0; +} /* dns_resconf_root() */ + + +enum dns_resconf_keyword { + DNS_RESCONF_NAMESERVER, + DNS_RESCONF_DOMAIN, + DNS_RESCONF_SEARCH, + DNS_RESCONF_LOOKUP, + DNS_RESCONF_FILE, + DNS_RESCONF_BIND, + DNS_RESCONF_CACHE, + DNS_RESCONF_OPTIONS, + DNS_RESCONF_EDNS0, + DNS_RESCONF_NDOTS, + DNS_RESCONF_TIMEOUT, + DNS_RESCONF_ATTEMPTS, + DNS_RESCONF_ROTATE, + DNS_RESCONF_RECURSE, + DNS_RESCONF_SMART, + DNS_RESCONF_TCP, + DNS_RESCONF_TCPx, + DNS_RESCONF_INTERFACE, + DNS_RESCONF_ZERO, + DNS_RESCONF_ONE, + DNS_RESCONF_ENABLE, + DNS_RESCONF_ONLY, + DNS_RESCONF_DISABLE, +}; /* enum dns_resconf_keyword */ + +static enum dns_resconf_keyword dns_resconf_keyword(const char *word) { + static const char *words[] = { + [DNS_RESCONF_NAMESERVER] = "nameserver", + [DNS_RESCONF_DOMAIN] = "domain", + [DNS_RESCONF_SEARCH] = "search", + [DNS_RESCONF_LOOKUP] = "lookup", + [DNS_RESCONF_FILE] = "file", + [DNS_RESCONF_BIND] = "bind", + [DNS_RESCONF_CACHE] = "cache", + [DNS_RESCONF_OPTIONS] = "options", + [DNS_RESCONF_EDNS0] = "edns0", + [DNS_RESCONF_ROTATE] = "rotate", + [DNS_RESCONF_RECURSE] = "recurse", + [DNS_RESCONF_SMART] = "smart", + [DNS_RESCONF_TCP] = "tcp", + [DNS_RESCONF_INTERFACE] = "interface", + [DNS_RESCONF_ZERO] = "0", + [DNS_RESCONF_ONE] = "1", + [DNS_RESCONF_ENABLE] = "enable", + [DNS_RESCONF_ONLY] = "only", + [DNS_RESCONF_DISABLE] = "disable", + }; + unsigned i; + + for (i = 0; i < lengthof(words); i++) { + if (words[i] && 0 == strcasecmp(words[i], word)) + return i; + } + + if (0 == strncasecmp(word, "ndots:", sizeof "ndots:" - 1)) + return DNS_RESCONF_NDOTS; + + if (0 == strncasecmp(word, "timeout:", sizeof "timeout:" - 1)) + return DNS_RESCONF_TIMEOUT; + + if (0 == strncasecmp(word, "attempts:", sizeof "attempts:" - 1)) + return DNS_RESCONF_ATTEMPTS; + + if (0 == strncasecmp(word, "tcp:", sizeof "tcp:" - 1)) + return DNS_RESCONF_TCPx; + + return -1; +} /* dns_resconf_keyword() */ + + +/** OpenBSD-style "[1.2.3.4]:53" nameserver syntax */ +static int dns_resconf_pton(struct sockaddr_storage *ss, const char *src) { + struct { char buf[128], *p; } addr = { "", addr.buf }; + unsigned short port = 0; + int ch, af = AF_INET; + + while ((ch = *src++)) { + switch (ch) { + case ' ': + /* FALL THROUGH */ + case '\t': + break; + case '[': + break; + case ']': + while ((ch = *src++)) { + if (isdigit((unsigned char)ch)) { + port *= 10; + port += ch - '0'; + } + } + + goto inet; + case ':': + af = AF_INET6; + + /* FALL THROUGH */ + default: + if (addr.p < endof(addr.buf) - 1) + *addr.p++ = ch; + + break; + } /* switch() */ + } /* while() */ +inet: + + switch (dns_inet_pton(af, addr.buf, dns_sa_addr(af, ss))) { + case -1: + return errno; + case 0: + return EINVAL; + } /* switch() */ + + port = (!port)? 53 : port; + *dns_sa_port(af, ss) = htons(port); + dns_sa_family(ss) = af; + + return 0; +} /* dns_resconf_pton() */ + +#define dns_resconf_issep(ch) (isspace(ch) || (ch) == ',') +#define dns_resconf_iscom(ch) ((ch) == '#' || (ch) == ';') + +int dns_resconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) { + unsigned sa_count = 0; + char words[6][DNS_D_MAXNAME + 1]; + unsigned wp, wc, i, j, n; + int ch, error; + + rewind(fp); + + do { + memset(words, '\0', sizeof words); + wp = 0; + wc = 0; + + while (EOF != (ch = getc(fp)) && ch != '\n') { + if (dns_resconf_issep(ch)) { + if (wp > 0) { + wp = 0; + + if (++wc >= lengthof(words)) + goto skip; + } + } else if (dns_resconf_iscom(ch)) { +skip: + do { + ch = getc(fp); + } while (ch != EOF && ch != '\n'); + + break; + } else { + dns__printchar(words[wc], sizeof words[wc], wp, ch); + wp++; + } + } + + if (wp > 0) + wc++; + + if (wc < 2) + continue; + + switch (dns_resconf_keyword(words[0])) { + case DNS_RESCONF_NAMESERVER: + if (sa_count >= lengthof(resconf->nameserver)) + continue; + + if ((error = dns_resconf_pton(&resconf->nameserver[sa_count], words[1]))) + continue; + + sa_count++; + + break; + case DNS_RESCONF_DOMAIN: + case DNS_RESCONF_SEARCH: + memset(resconf->search, '\0', sizeof resconf->search); + + for (i = 1, j = 0; i < wc && j < lengthof(resconf->search); i++, j++) + dns_d_anchor(resconf->search[j], sizeof resconf->search[j], words[i], strlen(words[i])); + + break; + case DNS_RESCONF_LOOKUP: + for (i = 1, j = 0; i < wc && j < lengthof(resconf->lookup); i++) { + switch (dns_resconf_keyword(words[i])) { + case DNS_RESCONF_FILE: + resconf->lookup[j++] = 'f'; + + break; + case DNS_RESCONF_BIND: + resconf->lookup[j++] = 'b'; + + break; + case DNS_RESCONF_CACHE: + resconf->lookup[j++] = 'c'; + + break; + default: + break; + } /* switch() */ + } /* for() */ + + break; + case DNS_RESCONF_OPTIONS: + for (i = 1; i < wc; i++) { + switch (dns_resconf_keyword(words[i])) { + case DNS_RESCONF_EDNS0: + resconf->options.edns0 = 1; + + break; + case DNS_RESCONF_NDOTS: + for (j = sizeof "ndots:" - 1, n = 0; isdigit((int)words[i][j]); j++) { + n *= 10; + n += words[i][j] - '0'; + } /* for() */ + + resconf->options.ndots = n; + + break; + case DNS_RESCONF_TIMEOUT: + for (j = sizeof "timeout:" - 1, n = 0; isdigit((int)words[i][j]); j++) { + n *= 10; + n += words[i][j] - '0'; + } /* for() */ + + resconf->options.timeout = n; + + break; + case DNS_RESCONF_ATTEMPTS: + for (j = sizeof "attempts:" - 1, n = 0; isdigit((int)words[i][j]); j++) { + n *= 10; + n += words[i][j] - '0'; + } /* for() */ + + resconf->options.attempts = n; + + break; + case DNS_RESCONF_ROTATE: + resconf->options.rotate = 1; + + break; + case DNS_RESCONF_RECURSE: + resconf->options.recurse = 1; + + break; + case DNS_RESCONF_SMART: + resconf->options.smart = 1; + + break; + case DNS_RESCONF_TCP: + resconf->options.tcp = DNS_RESCONF_TCP_ONLY; + + break; + case DNS_RESCONF_TCPx: + switch (dns_resconf_keyword(&words[i][sizeof "tcp:" - 1])) { + case DNS_RESCONF_ENABLE: + resconf->options.tcp = DNS_RESCONF_TCP_ENABLE; + + break; + case DNS_RESCONF_ONE: + case DNS_RESCONF_ONLY: + resconf->options.tcp = DNS_RESCONF_TCP_ONLY; + + break; + case DNS_RESCONF_ZERO: + case DNS_RESCONF_DISABLE: + resconf->options.tcp = DNS_RESCONF_TCP_DISABLE; + + break; + default: + break; + } /* switch() */ + + break; + default: + break; + } /* switch() */ + } /* for() */ + + break; + case DNS_RESCONF_INTERFACE: + for (i = 0, n = 0; isdigit((int)words[2][i]); i++) { + n *= 10; + n += words[2][i] - '0'; + } + + dns_resconf_setiface(resconf, words[1], n); + + break; + default: + break; + } /* switch() */ + } while (ch != EOF); + + return 0; +} /* dns_resconf_loadfile() */ + + +int dns_resconf_loadpath(struct dns_resolv_conf *resconf, const char *path) { + FILE *fp; + int error; + + if (!(fp = fopen(path, "r"))) + return dns_syerr(); + + error = dns_resconf_loadfile(resconf, fp); + + fclose(fp); + + return error; +} /* dns_resconf_loadpath() */ + + +int dns_resconf_setiface(struct dns_resolv_conf *resconf, const char *addr, unsigned short port) { + int af = (strchr(addr, ':'))? AF_INET6 : AF_INET; + + if (1 != dns_inet_pton(af, addr, dns_sa_addr(af, &resconf->iface))) + return dns_soerr(); + + *dns_sa_port(af, &resconf->iface) = htons(port); + resconf->iface.ss_family = af; + + return 0; +} /* dns_resconf_setiface() */ + + +size_t dns_resconf_search(void *dst, size_t lim, const void *qname, size_t qlen, struct dns_resolv_conf *resconf, dns_resconf_i_t *state) { + unsigned srchi = 0xff & (*state >> 8); + unsigned ndots = 0xff & (*state >> 16); + unsigned slen, len = 0; + const char *qp, *qe; + +// assert(0xff > lengthof(resconf->search)); + + switch (0xff & *state) { + case 0: + qp = qname; + qe = qp + qlen; + + while ((qp = memchr(qp, '.', qe - qp))) + { ndots++; qp++; } + + ++*state; + + if (ndots >= resconf->options.ndots) { + len = dns_d_anchor(dst, lim, qname, qlen); + + break; + } + + /* FALL THROUGH */ + case 1: + if (srchi < lengthof(resconf->search) && (slen = strlen(resconf->search[srchi]))) { + len = dns__printstring(dst, lim, 0, qname, qlen); + len = dns_d_anchor(dst, lim, dst, len); + len += dns__printstring(dst, lim, len, resconf->search[srchi], slen); + + srchi++; + + break; + } + + ++*state; + + /* FALL THROUGH */ + case 2: + ++*state; + + if (ndots < resconf->options.ndots) { + len = dns_d_anchor(dst, lim, qname, qlen); + + break; + } + + /* FALL THROUGH */ + default: + break; + } /* switch() */ + + dns__printnul(dst, lim, len); + + *state = ((0xff & *state) << 0) + | ((0xff & srchi) << 8) + | ((0xff & ndots) << 16); + + return len; +} /* dns_resconf_search() */ + + +int dns_resconf_dump(struct dns_resolv_conf *resconf, FILE *fp) { + unsigned i; + int af; + + for (i = 0; i < lengthof(resconf->nameserver) && (af = resconf->nameserver[i].ss_family) != AF_UNSPEC; i++) { + char addr[INET6_ADDRSTRLEN + 1] = "[INVALID]"; + unsigned short port; + + dns_inet_ntop(af, dns_sa_addr(af, &resconf->nameserver[i]), addr, sizeof addr); + port = ntohs(*dns_sa_port(af, &resconf->nameserver[i])); + + if (port == 53) + fprintf(fp, "nameserver %s\n", addr); + else + fprintf(fp, "nameserver [%s]:%hu\n", addr, port); + } + + + fprintf(fp, "search"); + + for (i = 0; i < lengthof(resconf->search) && resconf->search[i][0]; i++) + fprintf(fp, " %s", resconf->search[i]); + + fputc('\n', fp); + + + fprintf(fp, "lookup"); + + for (i = 0; i < lengthof(resconf->lookup) && resconf->lookup[i]; i++) { + switch (resconf->lookup[i]) { + case 'b': + fprintf(fp, " bind"); break; + case 'f': + fprintf(fp, " file"); break; + case 'c': + fprintf(fp, " cache"); break; + } + } + + fputc('\n', fp); + + + fprintf(fp, "options ndots:%u timeout:%u attempts:%u", resconf->options.ndots, resconf->options.timeout, resconf->options.attempts); + + if (resconf->options.edns0) + fprintf(fp, " edns0"); + if (resconf->options.rotate) + fprintf(fp, " rotate"); + if (resconf->options.recurse) + fprintf(fp, " recurse"); + if (resconf->options.smart) + fprintf(fp, " smart"); + + fputc('\n', fp); + + + if ((af = resconf->iface.ss_family) != AF_UNSPEC) { + char addr[INET6_ADDRSTRLEN + 1] = "[INVALID]"; + + dns_inet_ntop(af, dns_sa_addr(af, &resconf->iface), addr, sizeof addr); + + fprintf(fp, "interface %s %hu\n", addr, ntohs(*dns_sa_port(af, &resconf->iface))); + } + + return 0; +} /* dns_resconf_dump() */ + + +/* + * H I N T S E R V E R R O U T I N E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +struct dns_hints_soa { + unsigned char zone[DNS_D_MAXNAME + 1]; + + struct { + struct sockaddr_storage ss; + unsigned priority; + } addrs[16]; + + unsigned count; + + struct dns_hints_soa *next; +}; /* struct dns_hints_soa */ + + +struct dns_hints { + dns_atomic_t refcount; + + struct dns_hints_soa *head; +}; /* struct dns_hints */ + + +struct dns_hints *dns_hints_open(struct dns_resolv_conf *resconf __UNUSED__, int *error) { + static const struct dns_hints H_initializer; + struct dns_hints *H; + + if (!(H = malloc(sizeof *H))) + goto syerr; + + *H = H_initializer; + + dns_hints_acquire(H); + + return H; +syerr: + *error = dns_syerr(); + + free(H); + + return 0; +} /* dns_hints_open() */ + + +void dns_hints_close(struct dns_hints *H) { + struct dns_hints_soa *soa, *nxt; + + if (!H || 1 != dns_hints_release(H)) + return /* void */; + + for (soa = H->head; soa; soa = nxt) { + nxt = soa->next; + + free(soa); + } + + free(H); + + return /* void */; +} /* dns_hints_close() */ + + +unsigned dns_hints_acquire(struct dns_hints *H) { + return dns_atomic_inc(&H->refcount); +} /* dns_hints_acquire() */ + + +unsigned dns_hints_release(struct dns_hints *H) { + return dns_atomic_dec(&H->refcount); +} /* dns_hints_release() */ + + +struct dns_hints *dns_hints_mortal(struct dns_hints *hints) { + if (hints) + dns_hints_release(hints); + + return hints; +} /* dns_hints_mortal() */ + + +struct dns_hints *dns_hints_local(struct dns_resolv_conf *resconf, int *error_) { + struct dns_hints *hints = 0; + int error; + + if (resconf) + dns_resconf_acquire(resconf); + else if (!(resconf = dns_resconf_local(&error))) + goto error; + + if (!(hints = dns_hints_open(resconf, &error))) + goto error; + + error = 0; + + if (0 == dns_hints_insert_resconf(hints, ".", resconf, &error) && error) + goto error; + + dns_resconf_close(resconf); + + return hints; +error: + *error_ = error; + + dns_resconf_close(resconf); + dns_hints_close(hints); + + return 0; +} /* dns_hints_local() */ + + +struct dns_hints *dns_hints_root(struct dns_resolv_conf *resconf, int *error_) { + static const struct { + int af; + char addr[INET6_ADDRSTRLEN]; + } root_hints[] = { + { AF_INET, "198.41.0.4" }, /* A.ROOT-SERVERS.NET. */ + { AF_INET6, "2001:503:ba3e::2:30" }, /* A.ROOT-SERVERS.NET. */ + { AF_INET, "192.228.79.201" }, /* B.ROOT-SERVERS.NET. */ + { AF_INET, "192.33.4.12" }, /* C.ROOT-SERVERS.NET. */ + { AF_INET, "128.8.10.90" }, /* D.ROOT-SERVERS.NET. */ + { AF_INET, "192.203.230.10" }, /* E.ROOT-SERVERS.NET. */ + { AF_INET, "192.5.5.241" }, /* F.ROOT-SERVERS.NET. */ + { AF_INET6, "2001:500:2f::f" }, /* F.ROOT-SERVERS.NET. */ + { AF_INET, "192.112.36.4" }, /* G.ROOT-SERVERS.NET. */ + { AF_INET, "128.63.2.53" }, /* H.ROOT-SERVERS.NET. */ + { AF_INET6, "2001:500:1::803f:235" }, /* H.ROOT-SERVERS.NET. */ + { AF_INET, "192.36.148.17" }, /* I.ROOT-SERVERS.NET. */ + { AF_INET, "192.58.128.30" }, /* J.ROOT-SERVERS.NET. */ + { AF_INET6, "2001:503:c27::2:30" }, /* J.ROOT-SERVERS.NET. */ + }; + struct dns_hints *hints = 0; + struct sockaddr_storage ss; + unsigned i; + int error, af; + + if (!(hints = dns_hints_open(resconf, &error))) + goto error; + + for (i = 0; i < lengthof(root_hints); i++) { + af = root_hints[i].af; + + if (1 != dns_inet_pton(af, root_hints[i].addr, dns_sa_addr(af, &ss))) + goto soerr; + + *dns_sa_port(af, &ss) = htons(53); + ss.ss_family = af; + + if ((error = dns_hints_insert(hints, ".", (struct sockaddr *)&ss, 1))) + goto error; + } + + return hints; +soerr: + error = dns_soerr(); + + goto error; +error: + *error_ = error; + + dns_hints_close(hints); + + return 0; +} /* dns_hints_root() */ + + +static struct dns_hints_soa *dns_hints_fetch(struct dns_hints *H, const char *zone) { + struct dns_hints_soa *soa; + + for (soa = H->head; soa; soa = soa->next) { + if (0 == strcasecmp(zone, (char *)soa->zone)) + return soa; + } + + return 0; +} /* dns_hints_fetch() */ + + +int dns_hints_insert(struct dns_hints *H, const char *zone, const struct sockaddr *sa, unsigned priority) { + static const struct dns_hints_soa soa_initializer; + struct dns_hints_soa *soa; + unsigned i; + + if (!(soa = dns_hints_fetch(H, zone))) { + if (!(soa = malloc(sizeof *soa))) + return dns_syerr(); + + *soa = soa_initializer; + + dns__printstring(soa->zone, sizeof soa->zone, 0, zone); + + soa->next = H->head; + H->head = soa; + } + + i = soa->count % lengthof(soa->addrs); + + memcpy(&soa->addrs[i].ss, sa, dns_sa_len(sa)); + + soa->addrs[i].priority = MAX(1, priority); + + if (soa->count < lengthof(soa->addrs)) + soa->count++; + + return 0; +} /* dns_hints_insert() */ + + +unsigned dns_hints_insert_resconf(struct dns_hints *H, const char *zone, const struct dns_resolv_conf *resconf, int *error_) { + unsigned i, n, p; + int error; + + for (i = 0, n = 0, p = 1; i < lengthof(resconf->nameserver) && resconf->nameserver[i].ss_family != AF_UNSPEC; i++, n++) { + if ((error = dns_hints_insert(H, zone, (struct sockaddr *)&resconf->nameserver[i], p))) + goto error; + + p += !resconf->options.rotate; + } + + return n; +error: + *error_ = error; + + return n; +} /* dns_hints_insert_resconf() */ + + +static int dns_hints_i_cmp(unsigned a, unsigned b, struct dns_hints_i *i, struct dns_hints_soa *soa) { + int cmp; + + if ((cmp = soa->addrs[a].priority - soa->addrs[b].priority)) + return cmp; + + return dns_k_shuffle16(a, i->state.seed) - dns_k_shuffle16(b, i->state.seed); +} /* dns_hints_i_cmp() */ + + +static unsigned dns_hints_i_start(struct dns_hints_i *i, struct dns_hints_soa *soa) { + unsigned p0, p; + + p0 = 0; + + for (p = 1; p < soa->count; p++) { + if (dns_hints_i_cmp(p, p0, i, soa) < 0) + p0 = p; + } + + return p0; +} /* dns_hints_i_start() */ + + +static unsigned dns_hints_i_skip(unsigned p0, struct dns_hints_i *i, struct dns_hints_soa *soa) { + unsigned pZ, p; + + for (pZ = 0; pZ < soa->count; pZ++) { + if (dns_hints_i_cmp(pZ, p0, i, soa) > 0) + goto cont; + } + + return soa->count; +cont: + for (p = pZ + 1; p < soa->count; p++) { + if (dns_hints_i_cmp(p, p0, i, soa) <= 0) + continue; + + if (dns_hints_i_cmp(p, pZ, i, soa) >= 0) + continue; + + pZ = p; + } + + + return pZ; +} /* dns_hints_i_skip() */ + + +struct dns_hints_i *dns_hints_i_init(struct dns_hints_i *i, struct dns_hints *hints) { + static const struct dns_hints_i i_initializer; + struct dns_hints_soa *soa; + + i->state = i_initializer.state; + + do { + i->state.seed = dns_random(); + } while (0 == i->state.seed); + + if ((soa = dns_hints_fetch(hints, i->zone))) { + i->state.next = dns_hints_i_start(i, soa); + } + + return i; +} /* dns_hints_i_init() */ + + +unsigned dns_hints_grep(struct sockaddr **sa, socklen_t *sa_len, unsigned lim, struct dns_hints_i *i, struct dns_hints *H) { + struct dns_hints_soa *soa; + unsigned n; + + if (!(soa = dns_hints_fetch(H, i->zone))) + return 0; + + n = 0; + + while (i->state.next < soa->count && n < lim) { + *sa = (struct sockaddr *)&soa->addrs[i->state.next].ss; + *sa_len = dns_sa_len(*sa); + + sa++; + sa_len++; + n++; + + i->state.next = dns_hints_i_skip(i->state.next, i, soa); + } + + return n; +} /* dns_hints_grep() */ + + +struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q, int *error_) { + struct dns_packet *A, *P; + struct dns_rr rr; + char zone[DNS_D_MAXNAME + 1]; + size_t zlen; + struct dns_hints_i i; + struct sockaddr *sa; + socklen_t slen; + int error; + + if (!dns_rr_grep(&rr, 1, dns_rr_i_new(Q, .section = DNS_S_QUESTION), Q, &error)) + goto error; + + if (!(zlen = dns_d_expand(zone, sizeof zone, rr.dn.p, Q, &error))) + goto error; + else if (zlen >= sizeof zone) + goto toolong; + + P = dns_p_new(512); + dns_header(P)->qr = 1; + + if ((error = dns_rr_copy(P, &rr, Q))) + goto error; + + if ((error = dns_p_push(P, DNS_S_AUTHORITY, ".", strlen("."), DNS_T_NS, DNS_C_IN, 0, "hints.local."))) + goto error; + + do { + i.zone = zone; + + dns_hints_i_init(&i, hints); + + while (dns_hints_grep(&sa, &slen, 1, &i, hints)) { + int af = sa->sa_family; + int rtype = (af == AF_INET6)? DNS_T_AAAA : DNS_T_A; + + if ((error = dns_p_push(P, DNS_S_ADDITIONAL, "hints.local.", strlen("hints.local."), rtype, DNS_C_IN, 0, dns_sa_addr(af, sa)))) + goto error; + } + } while ((zlen = dns_d_cleave(zone, sizeof zone, zone, zlen))); + + if (!(A = dns_p_copy(dns_p_make(P->end, &error), P))) + goto error; + + return A; +toolong: + error = DNS_EILLEGAL; +error: + *error_ = error; + + return 0; +} /* dns_hints_query() */ + + +/** ugly hack to support specifying ports other than 53 in resolv.conf. */ +static unsigned short dns_hints_port(struct dns_hints *hints, int af, void *addr) { + struct dns_hints_soa *soa; + unsigned short port; + unsigned i; + + for (soa = hints->head; soa; soa = soa->next) { + for (i = 0; i < soa->count; i++) { + if (af != soa->addrs[i].ss.ss_family) + continue; + + if (memcmp(addr, dns_sa_addr(af, &soa->addrs[i].ss), (af == AF_INET6)? sizeof (struct in6_addr) : sizeof (struct in_addr))) + continue; + + port = *dns_sa_port(af, &soa->addrs[i].ss); + + return (port)? port : htons(53); + } + } + + return htons(53); +} /* dns_hints_port() */ + + +int dns_hints_dump(struct dns_hints *hints, FILE *fp) { + struct dns_hints_soa *soa; + char addr[INET6_ADDRSTRLEN]; + unsigned i; + int af; + + for (soa = hints->head; soa; soa = soa->next) { + fprintf(fp, "ZONE \"%s\"\n", soa->zone); + + for (i = 0; i < soa->count; i++) { + af = soa->addrs[i].ss.ss_family; + if (!dns_inet_ntop(af, dns_sa_addr(af, &soa->addrs[i].ss), addr, sizeof addr)) + return dns_soerr(); + + fprintf(fp, "\t(%d) [%s]:%hu\n", (int)soa->addrs[i].priority, addr, ntohs(*dns_sa_port(af, &soa->addrs[i].ss))); + } + } + + return 0; +} /* dns_hints_dump() */ + + +/* + * C A C H E R O U T I N E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +static dns_atomic_t dns_cache_acquire(struct dns_cache *cache __UNUSED__) { + return 0; +} /* dns_cache_acquire() */ + + +static dns_atomic_t dns_cache_release(struct dns_cache *cache __UNUSED__) { + return 0; +} /* dns_cache_release() */ + + +static struct dns_packet *dns_cache_query(struct dns_packet *query __UNUSED__, struct dns_cache *cache __UNUSED__, int *error __UNUSED__) { + return 0; +} /* dns_cache_submit() */ + + +static int dns_cache_submit(struct dns_packet *query __UNUSED__, struct dns_cache *cache __UNUSED__) { + return 0; +} /* dns_cache_submit() */ + + +static int dns_cache_check(struct dns_cache *cache __UNUSED__) { + return 0; +} /* dns_cache_check() */ + + +static struct dns_packet *dns_cache_fetch(struct dns_cache *cache __UNUSED__, int *error __UNUSED__) { + return 0; +} /* dns_cache_fetch() */ + + +static int dns_cache_pollfd(struct dns_cache *cache __UNUSED__) { + return -1; +} /* dns_cache_pollfd() */ + + +static short dns_cache_events(struct dns_cache *cache __UNUSED__) { + return 0; +} /* dns_cache_events() */ + + +static void dns_cache_clear(struct dns_cache *cache __UNUSED__) { + return; +} /* dns_cache_clear() */ + + +struct dns_cache *dns_cache_init(struct dns_cache *cache) { + static const struct dns_cache c_init = { + .acquire = &dns_cache_acquire, + .release = &dns_cache_release, + .query = &dns_cache_query, + .submit = &dns_cache_submit, + .check = &dns_cache_check, + .fetch = &dns_cache_fetch, + .pollfd = &dns_cache_pollfd, + .events = &dns_cache_events, + .clear = &dns_cache_clear, + }; + + *cache = c_init; + + return cache; +} /* dns_cache_init() */ + + +void dns_cache_close(struct dns_cache *cache) { + if (cache) + cache->release(cache); +} /* dns_cache_close() */ + + +/* + * S O C K E T R O U T I N E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +static void dns_socketclose(int *fd) { + if (*fd != -1) { +#if _WIN32 + closesocket(*fd); +#else + close(*fd); +#endif + *fd = -1; + } +} /* dns_socketclose() */ + + +#define DNS_SO_MAXTRY 7 + +static int dns_socket(struct sockaddr *local, int type, int *error_) { + int error, fd = -1; +#if defined(O_NONBLOCK) + int flags; +#elif defined(FIONBIO) + unsigned long opt; +#endif + + if (-1 == (fd = socket(local->sa_family, type, 0))) + goto soerr; + +#if defined(F_SETFD) + if (-1 == fcntl(fd, F_SETFD, 1)) + goto syerr; +#endif + +#if defined(O_NONBLOCK) + if (-1 == (flags = fcntl(fd, F_GETFL))) + goto syerr; + + if (-1 == fcntl(fd, F_SETFL, flags | O_NONBLOCK)) + goto syerr; +#elif defined(FIONBIO) + opt = 1; + + if (0 != ioctlsocket(fd, FIONBIO, &opt)) + goto soerr; +#endif + + if (local->sa_family != AF_INET && local->sa_family != AF_INET6) + return fd; + + if (type != SOCK_DGRAM) + return fd; + + if (*dns_sa_port(local->sa_family, local) == 0) { + struct sockaddr_storage tmp; + unsigned i, port; + + memcpy(&tmp, local, dns_sa_len(local)); + + for (i = 0; i < DNS_SO_MAXTRY; i++) { + port = 1025 + (dns_random() % 64510); + + *dns_sa_port(tmp.ss_family, &tmp) = htons(port); + + if (0 == bind(fd, (struct sockaddr *)&tmp, dns_sa_len(&tmp))) + return fd; + } + } + + if (0 == bind(fd, local, dns_sa_len(local))) + return fd; + + /* FALL THROUGH */ +soerr: + error = dns_soerr(); + + goto error; +syerr: + error = dns_syerr(); + + goto error; +error: + *error_ = error; + + dns_socketclose(&fd); + + return -1; +} /* dns_socket() */ + + +enum { + DNS_SO_UDP_INIT = 1, + DNS_SO_UDP_CONN, + DNS_SO_UDP_SEND, + DNS_SO_UDP_RECV, + DNS_SO_UDP_DONE, + + DNS_SO_TCP_INIT, + DNS_SO_TCP_CONN, + DNS_SO_TCP_SEND, + DNS_SO_TCP_RECV, + DNS_SO_TCP_DONE, +}; + +struct dns_socket { + struct dns_options opts; + + int udp; + int tcp; + + int *old; + unsigned onum, olim; + + int type; + + struct sockaddr_storage local, remote; + + struct dns_k_permutor qids; + + struct dns_stat stat; + + /* + * NOTE: dns_so_reset() zeroes everything from here down. + */ + int state; + + unsigned short qid; + char qname[DNS_D_MAXNAME + 1]; + size_t qlen; + enum dns_type qtype; + enum dns_class qclass; + + struct dns_packet *query; + size_t qout; + + time_t began; + + struct dns_packet *answer; + size_t alen, apos; +}; /* struct dns_socket() */ + + +/* + * NOTE: Actual closure delayed so that kqueue(2) and epoll(2) callers have + * a chance to recognize a state change after installing a persistent event + * and where sequential descriptors with the same integer value returned + * from _pollfd() would be ambiguous. See dns_so_closefds(). + */ +static int dns_so_closefd(struct dns_socket *so, int *fd) { + int error; + + if (*fd == -1) + return 0; + + if (so->opts.closefd.cb) { + if ((error = so->opts.closefd.cb(fd, so->opts.closefd.arg))) { + return error; + } else if (*fd == -1) + return 0; + } + + if (!(so->onum < so->olim)) { + unsigned olim = MAX(4, so->olim * 2); + void *old; + + if (!(old = realloc(so->old, sizeof so->old[0] * olim))) + return dns_syerr(); + + so->old = old; + so->olim = olim; + } + + so->old[so->onum++] = *fd; + *fd = -1; + + return 0; +} /* dns_so_closefd() */ + + +#define DNS_SO_CLOSE_UDP 0x01 +#define DNS_SO_CLOSE_TCP 0x02 +#define DNS_SO_CLOSE_OLD 0x04 +#define DNS_SO_CLOSE_ALL (DNS_SO_CLOSE_UDP|DNS_SO_CLOSE_TCP|DNS_SO_CLOSE_OLD) + +static void dns_so_closefds(struct dns_socket *so, int which) { + if (DNS_SO_CLOSE_UDP & which) + dns_socketclose(&so->udp); + if (DNS_SO_CLOSE_TCP & which) + dns_socketclose(&so->tcp); + if (DNS_SO_CLOSE_OLD & which) { + unsigned i; + for (i = 0; i < so->onum; i++) + dns_socketclose(&so->old[i]); + so->onum = 0; + free(so->old); + so->old = 0; + so->olim = 0; + } +} /* dns_so_closefds() */ + + +static void dns_so_destroy(struct dns_socket *); + +static struct dns_socket *dns_so_init(struct dns_socket *so, const struct sockaddr *local, int type, const struct dns_options *opts, int *error) { + static const struct dns_socket so_initializer = { .opts = DNS_OPTS_INITIALIZER, .udp = -1, .tcp = -1, }; + + *so = so_initializer; + so->type = type; + + if (opts) + so->opts = *opts; + + if (local) + memcpy(&so->local, local, dns_sa_len(local)); + + if (-1 == (so->udp = dns_socket((struct sockaddr *)&so->local, SOCK_DGRAM, error))) + goto error; + + dns_k_permutor_init(&so->qids, 1, 65535); + + return so; +error: + dns_so_destroy(so); + + return 0; +} /* dns_so_init() */ + + +struct dns_socket *dns_so_open(const struct sockaddr *local, int type, const struct dns_options *opts, int *error) { + struct dns_socket *so; + + if (!(so = malloc(sizeof *so))) + goto syerr; + + if (!dns_so_init(so, local, type, opts, error)) + goto error; + + return so; +syerr: + *error = dns_syerr(); +error: + dns_so_close(so); + + return 0; +} /* dns_so_open() */ + + +static void dns_so_destroy(struct dns_socket *so) { + dns_so_reset(so); + dns_so_closefds(so, DNS_SO_CLOSE_ALL); +} /* dns_so_destroy() */ + + +void dns_so_close(struct dns_socket *so) { + if (!so) + return; + + dns_so_destroy(so); + + free(so); +} /* dns_so_close() */ + + +void dns_so_reset(struct dns_socket *so) { + free(so->answer); + + memset(&so->state, '\0', sizeof *so - offsetof(struct dns_socket, state)); +} /* dns_so_reset() */ + + +unsigned short dns_so_mkqid(struct dns_socket *so) { + return dns_k_permutor_step(&so->qids); +} /* dns_so_mkqid() */ + + +#define DNS_SO_MINBUF 768 + +static int dns_so_newanswer(struct dns_socket *so, size_t len) { + size_t size = offsetof(struct dns_packet, data) + MAX(len, DNS_SO_MINBUF); + void *p; + + if (!(p = realloc(so->answer, size))) + return dns_syerr(); + + so->answer = dns_p_init(p, size); + + return 0; +} /* dns_so_newanswer() */ + + +int dns_so_submit(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host) { + struct dns_rr rr; + int error = -1; + + dns_so_reset(so); + + if ((error = dns_rr_parse(&rr, 12, Q))) + goto error; + + if (!(so->qlen = dns_d_expand(so->qname, sizeof so->qname, rr.dn.p, Q, &error))) + goto error; + /* + * NOTE: don't bail if expansion is too long; caller may be + * intentionally sending long names. However, we won't be able to + * verify it on return. + */ + + so->qtype = rr.type; + so->qclass = rr.class; + + if ((error = dns_so_newanswer(so, DNS_SO_MINBUF))) + goto syerr; + + memcpy(&so->remote, host, dns_sa_len(host)); + + so->query = Q; + so->qout = 0; + so->began = dns_now(); + + if (dns_header(so->query)->qid == 0) + dns_header(so->query)->qid = dns_so_mkqid(so); + + so->qid = dns_header(so->query)->qid; + so->state = (so->type == SOCK_STREAM)? DNS_SO_TCP_INIT : DNS_SO_UDP_INIT; + + so->stat.queries++; + + return 0; +syerr: + error = dns_syerr(); +error: + dns_so_reset(so); + + return error; +} /* dns_so_submit() */ + + +static int dns_so_verify(struct dns_socket *so, struct dns_packet *P) { + char qname[DNS_D_MAXNAME + 1]; + size_t qlen; + struct dns_rr rr; + int error = -1; + + if (so->qid != dns_header(so->answer)->qid) + return DNS_EUNKNOWN; + + if (!dns_p_count(so->answer, DNS_S_QD)) + return DNS_EUNKNOWN; + + if (0 != dns_rr_parse(&rr, 12, so->answer)) + return DNS_EUNKNOWN; + + if (rr.type != so->qtype || rr.class != so->qclass) + return DNS_EUNKNOWN; + + if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, P, &error))) + return error; + else if (qlen >= sizeof qname || qlen != so->qlen) + return DNS_EUNKNOWN; + + if (0 != strcasecmp(so->qname, qname)) + return DNS_EUNKNOWN; + + return 0; +} /* dns_so_verify() */ + + +static int dns_so_tcp_send(struct dns_socket *so) { + unsigned char *qsrc; + size_t qend; + long n; + + so->query->data[-2] = 0xff & (so->query->end >> 8); + so->query->data[-1] = 0xff & (so->query->end >> 0); + + qsrc = &so->query->data[-2] + so->qout; + qend = so->query->end + 2; + + while (so->qout < qend) { + if (0 > (n = send(so->tcp, (void *)&qsrc[so->qout], qend - so->qout, 0))) + return dns_soerr(); + + so->qout += n; + so->stat.tcp.sent.bytes += n; + } + + so->stat.tcp.sent.count++; + + return 0; +} /* dns_so_tcp_send() */ + + +static int dns_so_tcp_recv(struct dns_socket *so) { + unsigned char *asrc; + size_t aend, alen; + int error; + long n; + + aend = so->alen + 2; + + while (so->apos < aend) { + asrc = &so->answer->data[-2]; + + if (0 > (n = recv(so->tcp, (void *)&asrc[so->apos], aend - so->apos, 0))) + return dns_soerr(); + else if (n == 0) + return DNS_EUNKNOWN; /* FIXME */ + + so->apos += n; + so->stat.tcp.rcvd.bytes += n; + + if (so->alen == 0 && so->apos >= 2) { + alen = ((0xff & so->answer->data[-2]) << 8) + | ((0xff & so->answer->data[-1]) << 0); + + if ((error = dns_so_newanswer(so, alen))) + return error; + + so->alen = alen; + aend = alen + 2; + } + } + + so->answer->end = so->alen; + so->stat.tcp.rcvd.count++; + + return 0; +} /* dns_so_tcp_recv() */ + + +int dns_so_check(struct dns_socket *so) { + int error; + long n; + +retry: + switch (so->state) { + case DNS_SO_UDP_INIT: + so->state++; + case DNS_SO_UDP_CONN: + if (0 != connect(so->udp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote))) + goto soerr; + + so->state++; + case DNS_SO_UDP_SEND: + if (0 > (n = send(so->udp, (void *)so->query->data, so->query->end, 0))) + goto soerr; + + so->stat.udp.sent.bytes += n; + so->stat.udp.sent.count++; + + so->state++; + case DNS_SO_UDP_RECV: + if (0 > (n = recv(so->udp, (void *)so->answer->data, so->answer->size, 0))) + goto soerr; + + so->stat.udp.rcvd.bytes += n; + so->stat.udp.rcvd.count++; + + if ((so->answer->end = n) < 12) + goto trash; + + if ((error = dns_so_verify(so, so->answer))) + goto trash; + + so->state++; + case DNS_SO_UDP_DONE: + if (!dns_header(so->answer)->tc || so->type == SOCK_DGRAM) + return 0; + + so->state++; + case DNS_SO_TCP_INIT: + if ((error = dns_so_closefd(so, &so->tcp))) + goto error; + + if (-1 == (so->tcp = dns_socket((struct sockaddr *)&so->local, SOCK_STREAM, &error))) + goto error; + + so->state++; + case DNS_SO_TCP_CONN: + if (0 != connect(so->tcp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote))) { + if (dns_soerr() != DNS_EISCONN) + goto soerr; + } + + so->state++; + case DNS_SO_TCP_SEND: + if ((error = dns_so_tcp_send(so))) + goto error; + + so->state++; + case DNS_SO_TCP_RECV: + if ((error = dns_so_tcp_recv(so))) + goto error; + + so->state++; + case DNS_SO_TCP_DONE: + if ((error = dns_so_closefd(so, &so->tcp))) + goto error; + + if (so->answer->end < 12) + return DNS_EILLEGAL; + + if ((error = dns_so_verify(so, so->answer))) + goto error; + + return 0; + default: + error = DNS_EUNKNOWN; + + goto error; + } /* switch() */ + +trash: + goto retry; +soerr: + error = dns_soerr(); + + goto error; +error: + switch (error) { + case DNS_EINTR: + goto retry; + case DNS_EINPROGRESS: + /* FALL THROUGH */ + case DNS_EALREADY: + /* FALL THROUGH */ +#if DNS_EWOULDBLOCK != DNS_EAGAIN + case DNS_EWOULDBLOCK: + /* FALL THROUGH */ +#endif + error = DNS_EAGAIN; + + break; + } /* switch() */ + + return error; +} /* dns_so_check() */ + + +struct dns_packet *dns_so_fetch(struct dns_socket *so, int *error) { + struct dns_packet *answer; + + switch (so->state) { + case DNS_SO_UDP_DONE: + case DNS_SO_TCP_DONE: + answer = so->answer; + so->answer = 0; + + return answer; + default: + *error = DNS_EUNKNOWN; + + return 0; + } +} /* dns_so_fetch() */ + + +struct dns_packet *dns_so_query(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host, int *error_) { + struct dns_packet *A; + int error; + + if (!so->state) { + if ((error = dns_so_submit(so, Q, host))) + goto error; + } + + if ((error = dns_so_check(so))) + goto error; + + if (!(A = dns_so_fetch(so, &error))) + goto error; + + dns_so_reset(so); + + return A; +error: + *error_ = error; + + return 0; +} /* dns_so_query() */ + + +time_t dns_so_elapsed(struct dns_socket *so) { + return dns_elapsed(so->began); +} /* dns_so_elapsed() */ + + +void dns_so_clear(struct dns_socket *so) { + dns_so_closefds(so, DNS_SO_CLOSE_OLD); +} /* dns_so_clear() */ + + +static int dns_so_events2(struct dns_socket *so, enum dns_events type) { + int events = 0; + + switch (so->state) { + case DNS_SO_UDP_CONN: + case DNS_SO_UDP_SEND: + events |= DNS_POLLOUT; + + break; + case DNS_SO_UDP_RECV: + events |= DNS_POLLIN; + + break; + case DNS_SO_TCP_CONN: + case DNS_SO_TCP_SEND: + events |= DNS_POLLOUT; + + break; + case DNS_SO_TCP_RECV: + events |= DNS_POLLIN; + + break; + } /* switch() */ + + switch (type) { + case DNS_LIBEVENT: + return DNS_POLL2EV(events); + default: + return events; + } /* switch() */ +} /* dns_so_events2() */ + + +int dns_so_events(struct dns_socket *so) { + return dns_so_events2(so, so->opts.events); +} /* dns_so_events() */ + + +int dns_so_pollfd(struct dns_socket *so) { + switch (so->state) { + case DNS_SO_UDP_CONN: + case DNS_SO_UDP_SEND: + case DNS_SO_UDP_RECV: + return so->udp; + case DNS_SO_TCP_CONN: + case DNS_SO_TCP_SEND: + case DNS_SO_TCP_RECV: + return so->tcp; + } /* switch() */ + + return -1; +} /* dns_so_pollfd() */ + + +int dns_so_poll(struct dns_socket *so, int timeout) { + return dns_poll(dns_so_pollfd(so), dns_so_events2(so, DNS_SYSPOLL), timeout); +} /* dns_so_poll() */ + + +const struct dns_stat *dns_so_stat(struct dns_socket *so) { + return &so->stat; +} /* dns_so_stat() */ + + +/* + * R E S O L V E R R O U T I N E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +enum dns_res_state { + DNS_R_INIT, + DNS_R_GLUE, + DNS_R_SWITCH, /* (B)IND, (F)ILE, (C)ACHE */ + + DNS_R_FILE, /* Lookup in local hosts database */ + + DNS_R_CACHE, /* Lookup in application cache */ + DNS_R_SUBMIT, + DNS_R_CHECK, + DNS_R_FETCH, + + DNS_R_BIND, /* Lookup in the network */ + DNS_R_SEARCH, + DNS_R_HINTS, + DNS_R_ITERATE, + DNS_R_FOREACH_NS, + DNS_R_RESOLV0_NS, /* Prologue: Setup next frame and recurse */ + DNS_R_RESOLV1_NS, /* Epilog: Inspect answer */ + DNS_R_FOREACH_A, + DNS_R_QUERY_A, + DNS_R_CNAME0_A, + DNS_R_CNAME1_A, + + DNS_R_FINISH, + DNS_R_SMART0_A, + DNS_R_SMART1_A, + DNS_R_DONE, + DNS_R_SERVFAIL, +}; /* enum dns_res_state */ + + +#define DNS_R_MAXDEPTH 8 +#define DNS_R_ENDFRAME (DNS_R_MAXDEPTH - 1) + +struct dns_resolver { + struct dns_socket so; + + struct dns_resolv_conf *resconf; + struct dns_hosts *hosts; + struct dns_hints *hints; + struct dns_cache *cache; + + dns_atomic_t refcount; + + /* Reset zeroes everything below here. */ + + char qname[DNS_D_MAXNAME + 1]; + size_t qlen; + + enum dns_type qtype; + enum dns_class qclass; + + time_t began; + + dns_resconf_i_t search; + + struct dns_rr_i smart; + + struct dns_res_frame { + enum dns_res_state state; + + int error; + int which; /* (B)IND, (F)ILE; index into resconf->lookup */ + + unsigned attempts; + + struct dns_packet *query, *answer, *hints; + + struct dns_rr_i hints_i, hints_j; + struct dns_rr hints_ns, ans_cname; + } stack[DNS_R_MAXDEPTH]; + + unsigned sp; +}; /* struct dns_resolver */ + + +static int dns_res_tcp2type(int tcp) { + switch (tcp) { + case DNS_RESCONF_TCP_ONLY: + return SOCK_STREAM; + case DNS_RESCONF_TCP_DISABLE: + return SOCK_DGRAM; + default: + return 0; + } +} /* dns_res_tcp2type() */ + +struct dns_resolver *dns_res_open(struct dns_resolv_conf *resconf, struct dns_hosts *hosts, struct dns_hints *hints, struct dns_cache *cache, const struct dns_options *opts, int *error_) { + static const struct dns_resolver R_initializer + = { .refcount = 1, }; + struct dns_resolver *R = 0; + int type, error; + + /* + * Grab ref count early because the caller may have passed us a mortal + * reference, and we want to do the right thing if we return early + * from an error. + */ + if (resconf) + dns_resconf_acquire(resconf); + if (hosts) + dns_hosts_acquire(hosts); + if (hints) + dns_hints_acquire(hints); + if (cache) + dns_cache_acquire(cache); + + /* + * Don't try to load it ourselves because a NULL object might be an + * error from, say, dns_resconf_root(), and loading + * dns_resconf_local() by default would create undesirable surpises. + */ + if (!resconf || !hosts || !hints) + goto error; + + if (!(R = malloc(sizeof *R))) + goto syerr; + + *R = R_initializer; + type = dns_res_tcp2type(resconf->options.tcp); + + if (!dns_so_init(&R->so, (struct sockaddr *)&resconf->iface, type, opts, &error)) + goto error; + + R->resconf = resconf; + R->hosts = hosts; + R->hints = hints; + R->cache = cache; + + return R; +syerr: + error = dns_syerr(); +error: + *error_ = error; + + dns_res_close(R); + + dns_resconf_close(resconf); + dns_hosts_close(hosts); + dns_hints_close(hints); + dns_cache_close(cache); + + return 0; +} /* dns_res_open() */ + + +struct dns_resolver *dns_res_stub(const struct dns_options *opts, int *error) { + struct dns_resolv_conf *resconf = 0; + struct dns_hosts *hosts = 0; + struct dns_hints *hints = 0; + struct dns_resolver *res = 0; + + if (!(resconf = dns_resconf_local(error))) + goto epilog; + + if (!(hosts = dns_hosts_local(error))) + goto epilog; + + if (!(hints = dns_hints_local(resconf, error))) + goto epilog; + + if (!(res = dns_res_open(resconf, hosts, hints, NULL, opts, error))) + goto epilog; + +epilog: + dns_resconf_close(resconf); + dns_hosts_close(hosts); + dns_hints_close(hints); + + return res; +} /* dns_res_stub() */ + + +static void dns_res_reset_frame(struct dns_resolver *R __UNUSED__, struct dns_res_frame *frame) { + free(frame->query); + free(frame->answer); + free(frame->hints); + + memset(frame, '\0', sizeof *frame); +} /* dns_res_reset_frame() */ + + +void dns_res_reset(struct dns_resolver *R) { + unsigned i; + + dns_so_reset(&R->so); + + for (i = 0; i < lengthof(R->stack); i++) + dns_res_reset_frame(R, &R->stack[i]); + + memset(&R->qname, '\0', sizeof *R - offsetof(struct dns_resolver, qname)); +} /* dns_res_reset() */ + + +void dns_res_close(struct dns_resolver *R) { + if (!R || 1 < dns_res_release(R)) + return; + + dns_res_reset(R); + + dns_so_destroy(&R->so); + + dns_hints_close(R->hints); + dns_hosts_close(R->hosts); + dns_resconf_close(R->resconf); + dns_cache_close(R->cache); + + free(R); +} /* dns_res_close() */ + + +unsigned dns_res_acquire(struct dns_resolver *R) { + return dns_atomic_inc(&R->refcount); +} /* dns_res_acquire() */ + + +unsigned dns_res_release(struct dns_resolver *R) { + return dns_atomic_dec(&R->refcount); +} /* dns_res_release() */ + + +struct dns_resolver *dns_res_mortal(struct dns_resolver *res) { + if (res) + dns_res_release(res); + return res; +} /* dns_res_mortal() */ + + +static struct dns_packet *dns_res_merge(struct dns_packet *P0, struct dns_packet *P1, int *error_) { + size_t bufsiz = P0->end + P1->end; + struct dns_packet *P[3] = { P0, P1, 0 }; + struct dns_rr rr[3]; + int error, copy, i; + enum dns_section section; + +retry: + if (!(P[2] = dns_p_make(bufsiz, &error))) + goto error; + + dns_rr_foreach(&rr[0], P[0], .section = DNS_S_QD) { + if ((error = dns_rr_copy(P[2], &rr[0], P[0]))) + goto error; + } + + for (section = DNS_S_AN; (DNS_S_ALL & section); section <<= 1) { + for (i = 0; i < 2; i++) { + dns_rr_foreach(&rr[i], P[i], .section = section) { + copy = 1; + + dns_rr_foreach(&rr[2], P[2], .type = rr[i].type, .section = (DNS_S_ALL & ~DNS_S_QD)) { + if (0 == dns_rr_cmp(&rr[i], P[i], &rr[2], P[2])) { + copy = 0; + + break; + } + } + + if (copy && (error = dns_rr_copy(P[2], &rr[i], P[i]))) { + if (error == DNS_ENOBUFS && bufsiz < 65535) { + free(P[2]); P[2] = 0; + + bufsiz = MAX(65535, bufsiz * 2); + + goto retry; + } + + goto error; + } + } /* foreach(rr) */ + } /* foreach(packet) */ + } /* foreach(section) */ + + return P[2]; +error: + *error_ = error; + + free(P[2]); + + return 0; +} /* dns_res_merge() */ + + +static struct dns_packet *dns_res_glue(struct dns_resolver *R, struct dns_packet *Q) { + struct dns_packet *P = dns_p_new(512); + char qname[DNS_D_MAXNAME + 1]; + size_t qlen; + enum dns_type qtype; + struct dns_rr rr; + unsigned sp; + int error; + + if (!(qlen = dns_d_expand(qname, sizeof qname, 12, Q, &error)) + || qlen >= sizeof qname) + return 0; + + if (!(qtype = dns_rr_type(12, Q))) + return 0; + + if ((error = dns_p_push(P, DNS_S_QD, qname, strlen(qname), qtype, DNS_C_IN, 0, 0))) + return 0; + + for (sp = 0; sp <= R->sp; sp++) { + if (!R->stack[sp].answer) + continue; + + dns_rr_foreach(&rr, R->stack[sp].answer, .name = qname, .type = qtype, .section = (DNS_S_ALL & ~DNS_S_QD)) { + rr.section = DNS_S_AN; + + if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer))) + return 0; + } + } + + if (dns_p_count(P, DNS_S_AN) > 0) + goto copy; + + /* Otherwise, look for a CNAME */ + for (sp = 0; sp <= R->sp; sp++) { + if (!R->stack[sp].answer) + continue; + + dns_rr_foreach(&rr, R->stack[sp].answer, .name = qname, .type = DNS_T_CNAME, .section = (DNS_S_ALL & ~DNS_S_QD)) { + rr.section = DNS_S_AN; + + if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer))) + return 0; + } + } + + if (!dns_p_count(P, DNS_S_AN)) + return 0; + +copy: + return dns_p_copy(dns_p_make(P->end, &error), P); +} /* dns_res_glue() */ + + +static struct dns_packet *dns_res_mkquery(struct dns_resolver *R, const char *qname, enum dns_type qtype, enum dns_class qclass, int *error_) { + struct dns_packet *Q = 0; + int error; + + if (!(Q = dns_p_init(malloc(DNS_P_QBUFSIZ), DNS_P_QBUFSIZ))) + goto syerr; + + if ((error = dns_p_push(Q, DNS_S_QD, qname, strlen(qname), qtype, qclass, 0, 0))) + goto error; + + dns_header(Q)->rd = !R->resconf->options.recurse; + + return Q; +syerr: + error = dns_syerr(); +error: + free(Q); + + *error_ = error; + + return 0; +} /* dns_res_mkquery() */ + + +/* + * Sort NS records by three criteria: + * + * 1) Whether glue is present. + * 2) Whether glue record is original or of recursive lookup. + * 3) Randomly shuffle records which share the above criteria. + * + * NOTE: Assumes only NS records passed, AND ASSUMES no new NS records will + * be added during an iteration. + * + * FIXME: Only groks A glue, not AAAA glue. + */ +static int dns_res_nameserv_cmp(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) { + _Bool glued[2] = { 0 }; + struct dns_ns ns; + struct dns_rr x, y; + int cmp, error; + + if (!(error = dns_ns_parse(&ns, a, P))) + if (!(glued[0] = !!dns_rr_grep(&x, 1, dns_rr_i_new(P, .section = (DNS_S_ALL & ~DNS_S_QD), .name = ns.host, .type = DNS_T_A), P, &error))) + x.dn.p = 0; + + if (!(error = dns_ns_parse(&ns, b, P))) + if (!(glued[1] = !!dns_rr_grep(&y, 1, dns_rr_i_new(P, .section = (DNS_S_ALL & ~DNS_S_QD), .name = ns.host, .type = DNS_T_A), P, &error))) + y.dn.p = 0; + + if ((cmp = glued[1] - glued[0])) + return cmp; + else if ((cmp = (dns_rr_offset(&y) < i->args[0]) - (dns_rr_offset(&x) < i->args[0]))) + return cmp; + else + return dns_rr_i_shuffle(a, b, i, P); +} /* dns_res_nameserv_cmp() */ + + +#define goto(sp, i) \ + do { R->stack[(sp)].state = (i); goto exec; } while (0) + +static int dns_res_exec(struct dns_resolver *R) { + struct dns_res_frame *F; + struct dns_packet *P; + char host[DNS_D_MAXNAME + 1]; + size_t len; + struct dns_rr rr; + struct sockaddr_in sin; + int error; + +exec: + + F = &R->stack[R->sp]; + + switch (F->state) { + case DNS_R_INIT: + F->state++; + case DNS_R_GLUE: + if (R->sp == 0) + goto(R->sp, DNS_R_SWITCH); + + assert(F->query); + + if (!(F->answer = dns_res_glue(R, F->query))) + goto(R->sp, DNS_R_SWITCH); + + if (!(len = dns_d_expand(host, sizeof host, 12, F->query, &error))) + goto error; + else if (len >= sizeof host) + goto toolong; + + dns_rr_foreach(&rr, F->answer, .name = host, .type = dns_rr_type(12, F->query), .section = DNS_S_AN) { + goto(R->sp, DNS_R_FINISH); + } + + dns_rr_foreach(&rr, F->answer, .name = host, .type = DNS_T_CNAME, .section = DNS_S_AN) { + F->ans_cname = rr; + + goto(R->sp, DNS_R_CNAME0_A); + } + + F->state++; + case DNS_R_SWITCH: + while (F->which < (int)sizeof R->resconf->lookup) { + switch (R->resconf->lookup[F->which++]) { + case 'b': case 'B': + goto(R->sp, DNS_R_BIND); + case 'f': case 'F': + goto(R->sp, DNS_R_FILE); + case 'c': case 'C': + if (R->cache) + goto(R->sp, DNS_R_CACHE); + + break; + default: + break; + } + } + + goto(R->sp, DNS_R_SERVFAIL); /* FIXME: Right behavior? */ + case DNS_R_FILE: + if (R->sp > 0) { + free(F->answer); + + if (!(F->answer = dns_hosts_query(R->hosts, F->query, &error))) + goto error; + + if (dns_p_count(F->answer, DNS_S_AN) > 0) + goto(R->sp, DNS_R_FINISH); + + free(F->answer); F->answer = 0; + } else { + R->search = 0; + + while ((len = dns_resconf_search(host, sizeof host, R->qname, R->qlen, R->resconf, &R->search))) { +/* + * FIXME: Some sort of bug, either with this code or with GCC 3.3.5 on + * OpenBSD 4.4, overwites the stack guard. If the bug is in this file, it + * appears to be localized somewhere around here. It can also be mitigated + * in dns_hosts_query(). In any event, the bug manifests only when using + * compound literals. alloca(), malloc(), calloc(), etc, all work fine. + * Valgrind (tested on Linux) cannot detect any issues, but stack issues are + * not Valgrind's forte. Neither can I spot anything in the assembly, but + * that's not my forte. + */ +#if __OpenBSD__ && __GNUC__ + struct dns_packet *query = __builtin_alloca(DNS_P_QBUFSIZ); + + dns_p_init(query, DNS_P_QBUFSIZ); +#else + struct dns_packet *query = dns_p_new(DNS_P_QBUFSIZ); +#endif + + if ((error = dns_p_push(query, DNS_S_QD, host, len, R->qtype, R->qclass, 0, 0))) + goto error; + + free(F->answer); + + if (!(F->answer = dns_hosts_query(R->hosts, query, &error))) + goto error; + + if (dns_p_count(F->answer, DNS_S_AN) > 0) + goto(R->sp, DNS_R_FINISH); + + free(F->answer); F->answer = 0; + } + } + + goto(R->sp, DNS_R_SWITCH); + case DNS_R_CACHE: + error = 0; + + if (!F->query && !(F->query = dns_res_mkquery(R, R->qname, R->qtype, R->qclass, &error))) + goto error; + + free(F->answer); + + if ((F->answer = R->cache->query(F->query, R->cache, &error))) { + if (dns_p_count(F->answer, DNS_S_AN) > 0) + goto(R->sp, DNS_R_FINISH); + + free(F->answer); F->answer = 0; + + goto(R->sp, DNS_R_SWITCH); + } else if (error) + goto error; + + F->state++; + case DNS_R_SUBMIT: + if ((error = R->cache->submit(F->query, R->cache))) + goto error; + + F->state++; + case DNS_R_CHECK: + if ((error = R->cache->check(R->cache))) + goto error; + + F->state++; + case DNS_R_FETCH: + error = 0; + + free(F->answer); + + if ((F->answer = R->cache->fetch(R->cache, &error))) { + if (dns_p_count(F->answer, DNS_S_AN) > 0) + goto(R->sp, DNS_R_FINISH); + + free(F->answer); F->answer = 0; + + goto(R->sp, DNS_R_SWITCH); + } else if (error) + goto error; + + goto(R->sp, DNS_R_SWITCH); + case DNS_R_BIND: + if (R->sp > 0) { + assert(F->query); + + goto(R->sp, DNS_R_HINTS); + } + + R->search = 0; + + F->state++; + case DNS_R_SEARCH: + if (!(len = dns_resconf_search(host, sizeof host, R->qname, R->qlen, R->resconf, &R->search))) + goto(R->sp, DNS_R_SWITCH); + + if (!(P = dns_p_make(DNS_P_QBUFSIZ, &error))) + goto error; + + dns_header(P)->rd = !R->resconf->options.recurse; + + free(F->query); F->query = P; + + if ((error = dns_p_push(F->query, DNS_S_QD, host, len, R->qtype, R->qclass, 0, 0))) + goto error; + + F->state++; + case DNS_R_HINTS: + if (!(F->hints = dns_hints_query(R->hints, F->query, &error))) + goto error; + + F->state++; + case DNS_R_ITERATE: + dns_rr_i_init(&F->hints_i, F->hints); + + F->hints_i.section = DNS_S_AUTHORITY; + F->hints_i.type = DNS_T_NS; + F->hints_i.sort = &dns_res_nameserv_cmp; + F->hints_i.args[0] = F->hints->end; + + F->state++; + case DNS_R_FOREACH_NS: + dns_rr_i_save(&F->hints_i); + + /* Load our next nameserver host. */ + if (!dns_rr_grep(&F->hints_ns, 1, &F->hints_i, F->hints, &error)) { + if (++F->attempts < R->resconf->options.attempts) + goto(R->sp, DNS_R_ITERATE); + + goto(R->sp, DNS_R_SWITCH); + } + + dns_rr_i_init(&F->hints_j, F->hints); + + /* Assume there are glue records */ + goto(R->sp, DNS_R_FOREACH_A); + case DNS_R_RESOLV0_NS: + /* Have we reached our max depth? */ + if (&F[1] >= endof(R->stack)) + goto(R->sp, DNS_R_FOREACH_NS); + + dns_res_reset_frame(R, &F[1]); + + if (!(F[1].query = dns_p_make(DNS_P_QBUFSIZ, &error))) + goto error; + + if ((error = dns_ns_parse((struct dns_ns *)host, &F->hints_ns, F->hints))) + goto error; + + if ((error = dns_p_push(F[1].query, DNS_S_QD, host, strlen(host), DNS_T_A, DNS_C_IN, 0, 0))) + goto error; + + F->state++; + + goto(++R->sp, DNS_R_INIT); + case DNS_R_RESOLV1_NS: + if (!(len = dns_d_expand(host, sizeof host, 12, F[1].query, &error))) + goto error; + else if (len >= sizeof host) + goto toolong; + + dns_rr_foreach(&rr, F[1].answer, .name = host, .type = DNS_T_A, .section = (DNS_S_ALL & ~DNS_S_QD)) { + rr.section = DNS_S_AR; + + if ((error = dns_rr_copy(F->hints, &rr, F[1].answer))) + goto error; + + dns_rr_i_rewind(&F->hints_i); /* Now there's glue. */ + } + + goto(R->sp, DNS_R_FOREACH_NS); + case DNS_R_FOREACH_A: + /* + * NOTE: Iterator initialized in DNS_R_FOREACH_NS because + * this state is re-entrant, but we need to reset + * .name to a valid pointer each time. + */ + if ((error = dns_ns_parse((struct dns_ns *)host, &F->hints_ns, F->hints))) + goto error; + + F->hints_j.name = host; + F->hints_j.type = DNS_T_A; + F->hints_j.section = DNS_S_ALL & ~DNS_S_QD; + + if (!dns_rr_grep(&rr, 1, &F->hints_j, F->hints, &error)) { + if (!dns_rr_i_count(&F->hints_j)) + goto(R->sp, DNS_R_RESOLV0_NS); + + goto(R->sp, DNS_R_FOREACH_NS); + } + + sin.sin_family = AF_INET; + + if ((error = dns_a_parse((struct dns_a *)&sin.sin_addr, &rr, F->hints))) + goto error; + + if (R->sp == 0) + sin.sin_port = dns_hints_port(R->hints, AF_INET, (struct sockaddr *)&sin.sin_addr); + else + sin.sin_port = htons(53); + + if (DNS_DEBUG) { + char addr[INET_ADDRSTRLEN + 1]; + dns_a_print(addr, sizeof addr, (struct dns_a *)&sin.sin_addr); + DNS_SHOW(F->query, "ASKING: %s/%s @ DEPTH: %u)", host, addr, R->sp); + } + + if ((error = dns_so_submit(&R->so, F->query, (struct sockaddr *)&sin))) + goto error; + + F->state++; + case DNS_R_QUERY_A: + if (dns_so_elapsed(&R->so) >= (time_t)R->resconf->options.timeout) + goto(R->sp, DNS_R_FOREACH_A); + + if ((error = dns_so_check(&R->so))) + goto error; + + free(F->answer); + + if (!(F->answer = dns_so_fetch(&R->so, &error))) + goto error; + + if (DNS_DEBUG) { + DNS_SHOW(F->answer, "ANSWER @ DEPTH: %u)", R->sp); + } + + if ((error = dns_rr_parse(&rr, 12, F->query))) + goto error; + + if (!(len = dns_d_expand(host, sizeof host, rr.dn.p, F->query, &error))) + goto error; + else if (len >= sizeof host) + goto toolong; + + dns_rr_foreach(&rr, F->answer, .section = DNS_S_AN, .name = host, .type = rr.type) { + goto(R->sp, DNS_R_FINISH); /* Found */ + } + + dns_rr_foreach(&rr, F->answer, .section = DNS_S_AN, .name = host, .type = DNS_T_CNAME) { + F->ans_cname = rr; + + goto(R->sp, DNS_R_CNAME0_A); + } + + if (!R->resconf->options.recurse) + goto(R->sp, DNS_R_SWITCH); + + dns_rr_foreach(&rr, F->answer, .section = DNS_S_NS, .type = DNS_T_NS) { + free(F->hints); + + F->hints = F->answer; + F->answer = 0; + + goto(R->sp, DNS_R_ITERATE); + } + + /* XXX: Should this go further up? */ + if (dns_header(F->answer)->aa) + goto(R->sp, DNS_R_FINISH); + + goto(R->sp, DNS_R_FOREACH_A); + case DNS_R_CNAME0_A: + if (&F[1] >= endof(R->stack)) + goto(R->sp, DNS_R_FINISH); + + if ((error = dns_cname_parse((struct dns_cname *)host, &F->ans_cname, F->answer))) + goto error; + + dns_res_reset_frame(R, &F[1]); + + if (!(F[1].query = dns_p_make(DNS_P_QBUFSIZ, &error))) + goto error; + + if ((error = dns_p_push(F[1].query, DNS_S_QD, host, strlen(host), dns_rr_type(12, F->query), DNS_C_IN, 0, 0))) + goto error; + + F->state++; + + goto(++R->sp, DNS_R_INIT); + case DNS_R_CNAME1_A: + if (!(P = dns_res_merge(F->answer, F[1].answer, &error))) + goto error; + + free(F->answer); F->answer = P; + + goto(R->sp, DNS_R_FINISH); + case DNS_R_FINISH: + assert(F->answer); + + if (!R->resconf->options.smart || R->sp > 0) + goto(R->sp, DNS_R_DONE); + + R->smart.section = DNS_S_AN; + R->smart.type = R->qtype; + + dns_rr_i_init(&R->smart, F->answer); + + F->state++; + case DNS_R_SMART0_A: + if (&F[1] >= endof(R->stack)) + goto(R->sp, DNS_R_DONE); + + while (dns_rr_grep(&rr, 1, &R->smart, F->answer, &error)) { + union { + struct dns_ns ns; + struct dns_mx mx; + struct dns_srv srv; + } rd; + const char *qname; + enum dns_type qtype; + enum dns_class qclass; + + switch (rr.type) { + case DNS_T_NS: + if ((error = dns_ns_parse(&rd.ns, &rr, F->answer))) + goto error; + + qname = rd.ns.host; + qtype = DNS_T_A; + qclass = DNS_C_IN; + + break; + case DNS_T_MX: + if ((error = dns_mx_parse(&rd.mx, &rr, F->answer))) + goto error; + + qname = rd.mx.host; + qtype = DNS_T_A; + qclass = DNS_C_IN; + + break; + case DNS_T_SRV: + if ((error = dns_srv_parse(&rd.srv, &rr, F->answer))) + goto error; + + qname = rd.srv.target; + qtype = DNS_T_A; + qclass = DNS_C_IN; + + break; + default: + continue; + } /* switch() */ + + dns_res_reset_frame(R, &F[1]); + + if (!(F[1].query = dns_res_mkquery(R, qname, qtype, qclass, &error))) + goto error; + + F->state++; + + goto(++R->sp, DNS_R_INIT); + } /* while() */ + + /* + * NOTE: SMTP specification says to fallback to A record. + * + * XXX: Should we add a mock MX answer? + */ + if (R->qtype == DNS_T_MX && R->smart.state.count == 0) { + dns_res_reset_frame(R, &F[1]); + + if (!(F[1].query = dns_res_mkquery(R, R->qname, DNS_T_A, DNS_C_IN, &error))) + goto error; + + R->smart.state.count++; + F->state++; + + goto(++R->sp, DNS_R_INIT); + } + + goto(R->sp, DNS_R_DONE); + case DNS_R_SMART1_A: + assert(F[1].answer); + + /* + * FIXME: For CNAME chains (which are typically illegal in + * this context), we should rewrite the record host name + * to the original smart qname. All the user cares about + * is locating that A/AAAA record. + */ + dns_rr_foreach(&rr, F[1].answer, .section = DNS_S_AN, .type = DNS_T_A) { + rr.section = DNS_S_AR; + + if (dns_rr_exists(&rr, F[1].answer, F->answer)) + continue; + + while ((error = dns_rr_copy(F->answer, &rr, F[1].answer))) { + if (error != DNS_ENOBUFS) + goto error; + if ((error = dns_p_grow(&F->answer))) + goto error; + } + } + + goto(R->sp, DNS_R_SMART0_A); + case DNS_R_DONE: + assert(F->answer); + + if (R->sp > 0) + goto(--R->sp, F[-1].state); + + break; + case DNS_R_SERVFAIL: + free(F->answer); + + if (!(F->answer = dns_p_make(DNS_P_QBUFSIZ, &error))) + goto error; + + dns_header(F->answer)->qr = 1; + dns_header(F->answer)->rcode = DNS_RC_SERVFAIL; + + if ((error = dns_p_push(F->answer, DNS_S_QD, R->qname, strlen(R->qname), R->qtype, R->qclass, 0, 0))) + goto error; + + goto(R->sp, DNS_R_DONE); + default: + error = EINVAL; + + goto error; + } /* switch () */ + + return 0; +toolong: + error = DNS_EILLEGAL; +error: + return error; +} /* dns_res_exec() */ + +#undef goto + + +void dns_res_clear(struct dns_resolver *R) { + switch (R->stack[R->sp].state) { + case DNS_R_CHECK: + return R->cache->clear(R->cache); + default: + return dns_so_clear(&R->so); + } +} /* dns_res_clear() */ + + +static int dns_res_events2(struct dns_resolver *R, enum dns_events type) { + int events; + + switch (R->stack[R->sp].state) { + case DNS_R_CHECK: + events = R->cache->events(R->cache); + + return (type == DNS_LIBEVENT)? DNS_POLL2EV(events) : events; + default: + return dns_so_events2(&R->so, type); + } +} /* dns_res_events2() */ + + +int dns_res_events(struct dns_resolver *R) { + return dns_res_events2(R, R->so.opts.events); +} /* dns_res_events() */ + + +int dns_res_pollfd(struct dns_resolver *R) { + switch (R->stack[R->sp].state) { + case DNS_R_CHECK: + return R->cache->pollfd(R->cache); + default: + return dns_so_pollfd(&R->so); + } +} /* dns_res_pollfd() */ + + +time_t dns_res_elapsed(struct dns_resolver *R) { + return dns_elapsed(R->began); +} /* dns_res_elapsed() */ + + +int dns_res_poll(struct dns_resolver *R, int timeout) { + return dns_poll(dns_res_pollfd(R), dns_res_events2(R, DNS_SYSPOLL), timeout); +} /* dns_res_poll() */ + + +int dns_res_submit(struct dns_resolver *R, const char *qname, enum dns_type qtype, enum dns_class qclass) { + dns_res_reset(R); + + /* Don't anchor; that can conflict with searchlist generation. */ + dns_d_init(R->qname, sizeof R->qname, qname, (R->qlen = strlen(qname)), 0); + + R->qtype = qtype; + R->qclass = qclass; + + R->began = dns_now(); + + return 0; +} /* dns_res_submit() */ + + +int dns_res_check(struct dns_resolver *R) { + int error; + + if ((error = dns_res_exec(R))) + return error; + + return 0; +} /* dns_res_check() */ + + +struct dns_packet *dns_res_fetch(struct dns_resolver *R, int *error) { + struct dns_packet *answer; + + if (R->stack[0].state != DNS_R_DONE) { + *error = DNS_EUNKNOWN; + + return 0; + } + + answer = R->stack[0].answer; + R->stack[0].answer = 0; + + return answer; +} /* dns_res_fetch() */ + + +struct dns_packet *dns_res_query(struct dns_resolver *res, const char *qname, enum dns_type qtype, enum dns_class qclass, int timeout, int *error_) { + int error; + + if ((error = dns_res_submit(res, qname, qtype, qclass))) + goto error; + + while ((error = dns_res_check(res))) { + if (dns_res_elapsed(res) > timeout) + error = DNS_ETIMEDOUT; + + if (error != DNS_EAGAIN) + goto error; + + if ((error = dns_res_poll(res, 1))) + goto error; + } + + return dns_res_fetch(res, error_); +error: + *error_ = error; + + return 0; +} /* dns_res_query() */ + + +const struct dns_stat *dns_res_stat(struct dns_resolver *res) { + return dns_so_stat(&res->so); +} /* dns_res_stat() */ + + +/* + * A D D R I N F O R O U T I N E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +struct dns_addrinfo { + struct addrinfo hints; + struct dns_resolver *res; + + char qname[DNS_D_MAXNAME + 1]; + enum dns_type qtype; + unsigned short qport, port; + + struct dns_packet *answer; + struct dns_packet *glue; + + struct dns_rr_i i, g; + struct dns_rr rr; + + char cname[DNS_D_MAXNAME + 1]; + + int state; +}; /* struct dns_addrinfo */ + + +struct dns_addrinfo *dns_ai_open(const char *host, const char *serv, enum dns_type qtype, const struct addrinfo *hints, struct dns_resolver *res, int *error_) { + static const struct dns_addrinfo ai_initializer; + struct dns_addrinfo *ai; + int error; + + if (!res) + return 0; + + dns_res_acquire(res); + + if (!(ai = malloc(sizeof *ai))) + goto syerr; + + *ai = ai_initializer; + ai->hints = *hints; + + ai->res = res; + res = 0; + + if (sizeof ai->qname <= dns_strlcpy(ai->qname, host, sizeof ai->qname)) + { error = ENAMETOOLONG; goto error; } + + ai->qtype = qtype; + ai->qport = 0; + + if (serv) { + while (isdigit((unsigned char)*serv)) { + ai->qport *= 10; + ai->qport += *serv++ - '0'; + } + } + + ai->port = ai->qport; + + return ai; +syerr: + error = dns_syerr(); +error: + *error_ = error; + + dns_ai_close(ai); + dns_res_close(res); + + return 0; +} /* dns_ai_open() */ + + +void dns_ai_close(struct dns_addrinfo *ai) { + if (!ai) + return; + + dns_res_close(ai->res); + + if (ai->answer != ai->glue) + free(ai->glue); + + free(ai->answer); + free(ai); +} /* dns_ai_close() */ + + +static int dns_ai_setent(struct addrinfo **ent, union dns_any *any, enum dns_type type, struct dns_addrinfo *ai) { + struct sockaddr *saddr; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + const char *cname; + size_t clen; + + switch (type) { + case DNS_T_A: + saddr = memset(&sin, '\0', sizeof sin); + + sin.sin_family = AF_INET; + sin.sin_port = htons(ai->port); + + memcpy(&sin.sin_addr, any, sizeof sin.sin_addr); + + break; + case DNS_T_AAAA: + saddr = memset(&sin6, '\0', sizeof sin6); + + sin6.sin6_family = AF_INET6; + sin6.sin6_port = htons(ai->port); + + memcpy(&sin6.sin6_addr, any, sizeof sin6.sin6_addr); + + break; + default: + return EINVAL; + } /* switch() */ + + if (ai->hints.ai_flags & AI_CANONNAME) { + cname = (*ai->cname)? ai->cname : ai->qname; + clen = strlen(cname); + } else { + cname = NULL; + clen = 0; + } + + if (!(*ent = malloc(sizeof **ent + dns_sa_len(saddr) + ((ai->hints.ai_flags & AI_CANONNAME)? clen + 1 : 0)))) + return dns_syerr(); + + memset(*ent, '\0', sizeof **ent); + + (*ent)->ai_family = saddr->sa_family; + (*ent)->ai_socktype = ai->hints.ai_socktype; + (*ent)->ai_protocol = ai->hints.ai_protocol; + + (*ent)->ai_addr = memcpy((unsigned char *)*ent + sizeof **ent, saddr, dns_sa_len(saddr)); + (*ent)->ai_addrlen = dns_sa_len(saddr); + + if (ai->hints.ai_flags & AI_CANONNAME) + (*ent)->ai_canonname = memcpy((unsigned char *)*ent + sizeof **ent + dns_sa_len(saddr), cname, clen + 1); + + return 0; +} /* dns_ai_setent() */ + + +enum dns_ai_state { + DNS_AI_S_INIT, + DNS_AI_S_NUMERIC, + DNS_AI_S_SUBMIT, + DNS_AI_S_CHECK, + DNS_AI_S_FETCH, + DNS_AI_S_FOREACH_I, + DNS_AI_S_FOREACH_G, + DNS_AI_S_SUBMIT_G, + DNS_AI_S_CHECK_G, + DNS_AI_S_FETCH_G, + DNS_AI_S_DONE, +}; /* enum dns_ai_state */ + +#define dns_ai_goto(which) do { ai->state = (which); goto exec; } while (0) + +int dns_ai_nextent(struct addrinfo **ent, struct dns_addrinfo *ai) { + struct dns_packet *ans, *glue; + struct dns_rr rr; + char qname[DNS_D_MAXNAME + 1]; + union dns_any any; + size_t len; + int error; + + *ent = 0; + +exec: + + switch (ai->state) { + case DNS_AI_S_INIT: + ai->state++; + case DNS_AI_S_NUMERIC: + if (1 == dns_inet_pton(AF_INET, ai->qname, &any.a)) { + ai->state = DNS_AI_S_DONE; + + return dns_ai_setent(ent, &any, DNS_T_A, ai); + } + + if (1 == dns_inet_pton(AF_INET6, ai->qname, &any.aaaa)) { + ai->state = DNS_AI_S_DONE; + + return dns_ai_setent(ent, &any, DNS_T_AAAA, ai); + } + + if (ai->hints.ai_flags & AI_NUMERICHOST) + dns_ai_goto(DNS_AI_S_DONE); + + ai->state++; + case DNS_AI_S_SUBMIT: + if ((error = dns_res_submit(ai->res, ai->qname, ai->qtype, DNS_C_IN))) + return error; + + ai->state++; + case DNS_AI_S_CHECK: + if ((error = dns_res_check(ai->res))) + return error; + + ai->state++; + case DNS_AI_S_FETCH: + if (!(ai->answer = dns_res_fetch(ai->res, &error))) + return error; + + if ((error = dns_p_study(ai->answer))) + return error; + + ai->glue = ai->answer; + + dns_rr_i_init(&ai->i, ai->answer); + + ai->i.section = DNS_S_AN; + ai->i.type = ai->qtype; + ai->i.sort = &dns_rr_i_order; + + ai->state++; + case DNS_AI_S_FOREACH_I: + /* Search generator may have changed our qname. */ + if (!(len = dns_d_expand(qname, sizeof qname, 12, ai->answer, &error))) + return error; + else if (len >= sizeof qname) + return DNS_EILLEGAL; + + if (!dns_d_cname(ai->cname, sizeof ai->cname, qname, strlen(qname), ai->answer, &error)) + return error; + + ai->i.name = ai->cname; + + if (!dns_rr_grep(&rr, 1, &ai->i, ai->answer, &error)) + dns_ai_goto(DNS_AI_S_DONE); + + if ((error = dns_any_parse(&any, &rr, ai->answer))) + return error; + + ai->port = ai->qport; + + switch (rr.type) { + case DNS_T_A: + case DNS_T_AAAA: + return dns_ai_setent(ent, &any, rr.type, ai); + default: + if (!dns_any_cname(ai->cname, sizeof ai->cname, &any, rr.type)) + dns_ai_goto(DNS_AI_S_FOREACH_I); + + /* + * Find the "real" canonical name. Some authorities + * publish aliases where an RFC defines a canonical + * name. We trust that the resolver followed any + * CNAME chains on it's own, regardless of whether + * the "smart" option is enabled. + */ + if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->cname, strlen(ai->cname), ai->answer, &error)) + return error; + + if (rr.type == DNS_T_SRV) + ai->port = any.srv.port; + + break; + } /* switch() */ + + dns_rr_i_init(&ai->g, ai->glue); + + ai->g.section = DNS_S_ALL & ~DNS_S_QD; + ai->g.name = ai->cname; + ai->g.type = (ai->hints.ai_family == AF_INET6)? DNS_T_AAAA : DNS_T_A; + + ai->state++; + case DNS_AI_S_FOREACH_G: + if (!dns_rr_grep(&rr, 1, &ai->g, ai->glue, &error)) { + if (dns_rr_i_count(&ai->g) > 0) + dns_ai_goto(DNS_AI_S_FOREACH_I); + else + dns_ai_goto(DNS_AI_S_SUBMIT_G); + } + + if ((error = dns_any_parse(&any, &rr, ai->glue))) + return error; + + return dns_ai_setent(ent, &any, rr.type, ai); + case DNS_AI_S_SUBMIT_G: + if (dns_rr_grep(&rr, 1, dns_rr_i_new(ai->glue, .section = DNS_S_QD, .name = ai->g.name, .type = ai->g.type), ai->glue, &error)) + dns_ai_goto(DNS_AI_S_FOREACH_I); + + if ((error = dns_res_submit(ai->res, ai->g.name, ai->g.type, DNS_C_IN))) + return error; + + ai->state++; + case DNS_AI_S_CHECK_G: + if ((error = dns_res_check(ai->res))) + return error; + + ai->state++; + case DNS_AI_S_FETCH_G: + if (!(ans = dns_res_fetch(ai->res, &error))) + return error; + + dns_p_study(ans); + + glue = dns_p_merge(ai->glue, DNS_S_ALL, ans, DNS_S_ALL, &error); + + free(ans); + + if (!glue) + return error; + + if (ai->glue != ai->answer) + free(ai->glue); + + ai->glue = glue; + + dns_rr_i_init(&ai->g, ai->glue); + + /* ai->g.name should already point to ai->cname */ + if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->cname, strlen(ai->cname), ai->glue, &error)) + dns_ai_goto(DNS_AI_S_FOREACH_I); + + /* NOTE: Keep all the other iterator filters */ + + dns_ai_goto(DNS_AI_S_FOREACH_G); + case DNS_AI_S_DONE: + return ENOENT; + default: + return EINVAL; + } /* switch() */ +} /* dns_ai_nextent() */ + + +time_t dns_ai_elapsed(struct dns_addrinfo *ai) { + return dns_res_elapsed(ai->res); +} /* dns_ai_elapsed() */ + + +void dns_ai_clear(struct dns_addrinfo *ai) { + return dns_res_clear(ai->res); +} /* dns_ai_clear() */ + + +int dns_ai_events(struct dns_addrinfo *ai) { + return dns_res_events(ai->res); +} /* dns_ai_events() */ + + +int dns_ai_pollfd(struct dns_addrinfo *ai) { + return dns_res_pollfd(ai->res); +} /* dns_ai_pollfd() */ + + +int dns_ai_poll(struct dns_addrinfo *ai, int timeout) { + return dns_res_poll(ai->res, timeout); +} /* dns_ai_poll() */ + + +size_t dns_ai_print(void *dst, size_t lim, struct addrinfo *ent, struct dns_addrinfo *ai) { + char addr[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1]; + size_t cp = 0; + + cp += dns__printstring(dst, lim, cp, "[ "); + cp += dns__printstring(dst, lim, cp, ai->qname); + cp += dns__printstring(dst, lim, cp, " IN "); + cp += dns__printstring(dst, lim, cp, dns_strtype(ai->qtype)); + cp += dns__printstring(dst, lim, cp, " ]\n"); + + cp += dns__printstring(dst, lim, cp, ".ai_family = "); + + switch (ent->ai_family) { + case AF_INET: + cp += dns__printstring(dst, lim, cp, "AF_INET"); + break; + case AF_INET6: + cp += dns__printstring(dst, lim, cp, "AF_INET6"); + break; + default: + cp += dns__print10(dst, lim, cp, ent->ai_family, 0); + break; + } + + cp += dns__printchar(dst, lim, cp, '\n'); + + cp += dns__printstring(dst, lim, cp, ".ai_socktype = "); + + switch (ent->ai_socktype) { + case SOCK_STREAM: + cp += dns__printstring(dst, lim, cp, "SOCK_STREAM"); + break; + case SOCK_DGRAM: + cp += dns__printstring(dst, lim, cp, "SOCK_DGRAM"); + break; + default: + cp += dns__print10(dst, lim, cp, ent->ai_socktype, 0); + break; + } + + cp += dns__printchar(dst, lim, cp, '\n'); + + cp += dns__printstring(dst, lim, cp, ".ai_addr = ["); + + dns_inet_ntop(dns_sa_family(ent->ai_addr), dns_sa_addr(dns_sa_family(ent->ai_addr), ent->ai_addr), addr, sizeof addr); + + cp += dns__printstring(dst, lim, cp, addr); + cp += dns__printstring(dst, lim, cp, "]:"); + + cp += dns__print10(dst, lim, cp, ntohs(*dns_sa_port(dns_sa_family(ent->ai_addr), ent->ai_addr)), 0); + cp += dns__printchar(dst, lim, cp, '\n'); + + cp += dns__printstring(dst, lim, cp, ".ai_canonname = "); + cp += dns__printstring(dst, lim, cp, (ent->ai_canonname)? ent->ai_canonname : "[NULL]"); + cp += dns__printchar(dst, lim, cp, '\n'); + + dns__printnul(dst, lim, cp); + + return cp; +} /* dns_ai_print() */ + + +const struct dns_stat *dns_ai_stat(struct dns_addrinfo *ai) { + return dns_res_stat(ai->res); +} /* dns_ai_stat() */ + + +/* + * M I S C E L L A N E O U S R O U T I N E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +static const struct { + char name[16]; + enum dns_section type; +} dns_sections[] = { + { "QUESTION", DNS_S_QUESTION }, + { "QD", DNS_S_QUESTION }, + { "ANSWER", DNS_S_ANSWER }, + { "AN", DNS_S_ANSWER }, + { "AUTHORITY", DNS_S_AUTHORITY }, + { "NS", DNS_S_AUTHORITY }, + { "ADDITIONAL", DNS_S_ADDITIONAL }, + { "AR", DNS_S_ADDITIONAL }, +}; + +const char *(dns_strsection)(enum dns_section section, void *dst, size_t lim) { + unsigned i, p = 0; + + for (i = 0; i < lengthof(dns_sections); i++) { + if (dns_sections[i].type & section) { + if (p > 0) + p += dns__printchar(dst, lim, p, '|'); + + p += dns__printstring(dst, lim, p, dns_sections[i].name); + + section &= ~dns_sections[i].type; + } + } + + if (!p) + p += dns__print10(dst, lim, 0, (0xffff & section), 0); + + dns__printnul(dst, lim, p); + + return dst; +} /* dns_strsection() */ + + +enum dns_section dns_isection(const char *src) { + enum dns_section section = 0; + char sbuf[128]; + char *name, *next; + unsigned i; + + dns_strlcpy(sbuf, src, sizeof sbuf); + next = sbuf; + + while ((name = dns_strsep(&next, "|+, \t"))) { + for (i = 0; i < lengthof(dns_sections); i++) { + if (!strcasecmp(dns_sections[i].name, name)) { + section |= dns_sections[i].type; + break; + } + } + } + + return section; +} /* dns_isection() */ + + +static const struct { + char name[8]; + enum dns_class type; +} dns_classes[] = { + { "IN", DNS_C_IN }, +}; + +const char *(dns_strclass)(enum dns_class type, void *dst, size_t lim) { + unsigned i; + + for (i = 0; i < lengthof(dns_classes); i++) { + if (dns_classes[i].type == type) { + dns__printnul(dst, lim, dns__printstring(dst, lim, 0, dns_classes[i].name)); + + return dst; + } + } + + dns__printnul(dst, lim, dns__print10(dst, lim, 0, (0xffff & type), 0)); + + return dst; +} /* dns_strclass() */ + + +enum dns_class dns_iclass(const char *name) { + unsigned i; + + for (i = 0; i < lengthof(dns_classes); i++) { + if (!strcasecmp(dns_classes[i].name, name)) + return dns_classes[i].type; + } + + return 0; +} /* dns_iclass() */ + + +const char *(dns_strtype)(enum dns_type type, void *dst, size_t lim) { + unsigned i; + + for (i = 0; i < lengthof(dns_rrtypes); i++) { + if (dns_rrtypes[i].type == type) { + dns__printnul(dst, lim, dns__printstring(dst, lim, 0, dns_rrtypes[i].name)); + + return dst; + } + } + + dns__printnul(dst, lim, dns__print10(dst, lim, 0, (0xffff & type), 0)); + + return dst; +} /* dns_strtype() */ + + +enum dns_type dns_itype(const char *type) { + unsigned i; + + for (i = 0; i < lengthof(dns_rrtypes); i++) { + if (!strcasecmp(dns_rrtypes[i].name, type)) + return dns_rrtypes[i].type; + } + + return 0; +} /* dns_itype() */ + + +static char dns_opcodes[16][16] = { + [DNS_OP_QUERY] = "QUERY", + [DNS_OP_IQUERY] = "IQUERY", + [DNS_OP_STATUS] = "STATUS", + [DNS_OP_NOTIFY] = "NOTIFY", + [DNS_OP_UPDATE] = "UPDATE", +}; + +const char *dns_stropcode(enum dns_opcode opcode) { + opcode &= 0xf; + + if ('\0' == dns_opcodes[opcode][0]) + dns__printnul(dns_opcodes[opcode], sizeof dns_opcodes[opcode], dns__print10(dns_opcodes[opcode], sizeof dns_opcodes[opcode], 0, opcode, 0)); + + return dns_opcodes[opcode]; +} /* dns_stropcode() */ + + +enum dns_opcode dns_iopcode(const char *name) { + unsigned opcode; + + for (opcode = 0; opcode < lengthof(dns_opcodes); opcode++) { + if (!strcasecmp(name, dns_opcodes[opcode])) + return opcode; + } + + return lengthof(dns_opcodes) - 1; +} /* dns_iopcode() */ + + +static char dns_rcodes[16][16] = { + [DNS_RC_NOERROR] = "NOERROR", + [DNS_RC_FORMERR] = "FORMERR", + [DNS_RC_SERVFAIL] = "SERVFAIL", + [DNS_RC_NXDOMAIN] = "NXDOMAIN", + [DNS_RC_NOTIMP] = "NOTIMP", + [DNS_RC_REFUSED] = "REFUSED", + [DNS_RC_YXDOMAIN] = "YXDOMAIN", + [DNS_RC_YXRRSET] = "YXRRSET", + [DNS_RC_NXRRSET] = "NXRRSET", + [DNS_RC_NOTAUTH] = "NOTAUTH", + [DNS_RC_NOTZONE] = "NOTZONE", +}; + +const char *dns_strrcode(enum dns_rcode rcode) { + rcode &= 0xf; + + if ('\0' == dns_rcodes[rcode][0]) + dns__printnul(dns_rcodes[rcode], sizeof dns_rcodes[rcode], dns__print10(dns_rcodes[rcode], sizeof dns_rcodes[rcode], 0, rcode, 0)); + + return dns_rcodes[rcode]; +} /* dns_strrcode() */ + + +enum dns_rcode dns_ircode(const char *name) { + unsigned rcode; + + for (rcode = 0; rcode < lengthof(dns_rcodes); rcode++) { + if (!strcasecmp(name, dns_rcodes[rcode])) + return rcode; + } + + return lengthof(dns_rcodes) - 1; +} /* dns_ircode() */ + + +/* + * C O M M A N D - L I N E / R E G R E S S I O N R O U T I N E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#if DNS_MAIN + +#include +#include +#include + +#include + +#if _WIN32 +#include +#endif + +#if !_WIN32 +#include +#endif + + +struct { + struct { + const char *path[8]; + unsigned count; + } resconf; + + struct { + const char *path[8]; + unsigned count; + } hosts; + + struct { + const char *path[8]; + unsigned count; + } cache; + + const char *qname; + enum dns_type qtype; + + int (*sort)(); + + int verbose; +} MAIN = { + .sort = &dns_rr_i_packet, +}; + + +void hexdump(const unsigned char *src, size_t len, FILE *fp) { + static const unsigned char hex[] = "0123456789abcdef"; + static const unsigned char tmpl[] = " | |\n"; + unsigned char ln[sizeof tmpl]; + const unsigned char *sp, *se; + unsigned char *h, *g; + unsigned i, n; + + sp = src; + se = sp + len; + + while (sp < se) { + memcpy(ln, tmpl, sizeof ln); + + h = &ln[2]; + g = &ln[53]; + + for (n = 0; n < 2; n++) { + for (i = 0; i < 8 && se - sp > 0; i++, sp++) { + h[0] = hex[0x0f & (*sp >> 4)]; + h[1] = hex[0x0f & (*sp >> 0)]; + h += 3; + + *g++ = (isgraph(*sp))? *sp : '.'; + } + + h++; + } + + fputs((char *)ln, fp); + } + + return /* void */; +} /* hexdump() */ + + +static void panic(const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + +#if _WIN32 + vfprintf(stderr, fmt, ap); + + exit(EXIT_FAILURE); +#else + verrx(EXIT_FAILURE, fmt, ap); +#endif +} /* panic() */ + +#define panic_(fn, ln, fmt, ...) \ + panic(fmt "%0s", (fn), (ln), __VA_ARGS__) +#define panic(...) \ + panic_(__func__, __LINE__, "(%s:%d) " __VA_ARGS__, "") + + +static void *grow(unsigned char *p, size_t size) { + void *tmp; + + if (!(tmp = realloc(p, size))) + panic("realloc(%zu): %s", size, dns_strerror(errno)); + + return tmp; +} /* grow() */ + + +static size_t add(size_t a, size_t b) { + if (~a < b) + panic("%zu + %zu: integer overflow", a, b); + + return a + b; +} /* add() */ + + +static size_t append(unsigned char **dst, size_t osize, const void *src, size_t len) { + size_t size = add(osize, len); + + *dst = grow(*dst, size); + memcpy(*dst + osize, src, len); + + return size; +} /* append() */ + + +static size_t slurp(unsigned char **dst, size_t osize, FILE *fp, const char *path) { + size_t size = osize; + unsigned char buf[1024]; + size_t count; + + while ((count = fread(buf, 1, sizeof buf, fp))) + size = append(dst, size, buf, count); + + if (ferror(fp)) + panic("%s: %s", path, dns_strerror(errno)); + + return size; +} /* slurp() */ + + +static struct dns_resolv_conf *resconf(void) { + static struct dns_resolv_conf *resconf; + const char *path; + unsigned i; + int error; + + if (resconf) + return resconf; + + if (!(resconf = dns_resconf_open(&error))) + panic("dns_resconf_open: %s", dns_strerror(error)); + + if (!MAIN.resconf.count) + MAIN.resconf.path[MAIN.resconf.count++] = "/etc/resolv.conf"; + + for (i = 0; i < MAIN.resconf.count; i++) { + path = MAIN.resconf.path[i]; + + if (0 == strcmp(path, "-")) + error = dns_resconf_loadfile(resconf, stdin); + else + error = dns_resconf_loadpath(resconf, path); + + if (error) + panic("%s: %s", path, dns_strerror(error)); + } + + return resconf; +} /* resconf() */ + + +static struct dns_hosts *hosts(void) { + static struct dns_hosts *hosts; + const char *path; + unsigned i; + int error; + + if (hosts) + return hosts; + + if (!MAIN.hosts.count) { + MAIN.hosts.path[MAIN.hosts.count++] = "/etc/hosts"; + + /* Explicitly test dns_hosts_local() */ + if (!(hosts = dns_hosts_local(&error))) + panic("%s: %s", "/etc/hosts", dns_strerror(error)); + + return hosts; + } + + if (!(hosts = dns_hosts_open(&error))) + panic("dns_hosts_open: %s", dns_strerror(error)); + + for (i = 0; i < MAIN.hosts.count; i++) { + path = MAIN.hosts.path[i]; + + if (0 == strcmp(path, "-")) + error = dns_hosts_loadfile(hosts, stdin); + else + error = dns_hosts_loadpath(hosts, path); + + if (error) + panic("%s: %s", path, dns_strerror(error)); + } + + return hosts; +} /* hosts() */ + + +#if DNS_CACHE +#include "cache.h" + +struct dns_cache *cache(void) { + static struct cache *cache; + const char *path; + unsigned i; + int error; + + if (cache) + return cache_resi(cache); + if (!MAIN.cache.count) + return NULL; + + if (!(cache = cache_open(&error))) + panic("%s: %s", MAIN.cache.path[0], dns_strerror(error)); + + for (i = 0; i < MAIN.cache.count; i++) { + path = MAIN.cache.path[i]; + + if (!strcmp(path, "-")) { + if ((error = cache_loadfile(cache, stdin, NULL, 0))) + panic("%s: %s", path, dns_strerror(error)); + } else if ((error = cache_loadpath(cache, path, NULL, 0))) + panic("%s: %s", path, dns_strerror(error)); + } + + return cache_resi(cache); +} /* cache() */ +#else +struct dns_cache *cache(void) { return NULL; } +#endif + + +static void print_packet(struct dns_packet *P, FILE *fp) { + dns_p_dump3(P, dns_rr_i_new(P, .sort = MAIN.sort), fp); + + if (MAIN.verbose > 2) + hexdump(P->data, P->end, fp); +} /* print_packet() */ + + +static int parse_packet(int argc, char *argv[]) { + struct dns_packet *P = dns_p_new(512); + struct dns_packet *Q = dns_p_new(512); + enum dns_section section; + struct dns_rr rr; + int error; + union dns_any any; + char pretty[sizeof any * 2]; + size_t len; + + P->end = fread(P->data, 1, P->size, stdin); + + fputs(";; [HEADER]\n", stdout); + fprintf(stdout, ";; qr : %s(%d)\n", (dns_header(P)->qr)? "QUERY" : "RESPONSE", dns_header(P)->qr); + fprintf(stdout, ";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode); + fprintf(stdout, ";; aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa); + fprintf(stdout, ";; tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc); + fprintf(stdout, ";; rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd); + fprintf(stdout, ";; ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra); + fprintf(stdout, ";; rcode : %s(%d)\n", dns_strrcode(dns_header(P)->rcode), dns_header(P)->rcode); + + section = 0; + + dns_rr_foreach(&rr, P, .sort = MAIN.sort) { + if (section != rr.section) + fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section)); + + if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error))) + fprintf(stdout, "%s\n", pretty); + + dns_rr_copy(Q, &rr, P); + + section = rr.section; + } + + fputs("; ; ; ; ; ; ; ;\n\n", stdout); + + section = 0; + +#if 0 + dns_rr_foreach(&rr, Q, .name = "ns8.yahoo.com.") { +#else + struct dns_rr rrset[32]; + struct dns_rr_i *rri = dns_rr_i_new(Q, .name = dns_d_new("ns8.yahoo.com", DNS_D_ANCHOR), .sort = MAIN.sort); + unsigned rrcount = dns_rr_grep(rrset, lengthof(rrset), rri, Q, &error); + unsigned i; + + for (i = 0; i < rrcount; i++) { + rr = rrset[i]; +#endif + if (section != rr.section) + fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(Q, rr.section)); + + if ((len = dns_rr_print(pretty, sizeof pretty, &rr, Q, &error))) + fprintf(stdout, "%s\n", pretty); + + section = rr.section; + } + + if (MAIN.verbose > 1) { + fprintf(stderr, "orig:%zu\n", P->end); + hexdump(P->data, P->end, stdout); + + fprintf(stderr, "copy:%zu\n", Q->end); + hexdump(Q->data, Q->end, stdout); + } + + return 0; +} /* parse_packet() */ + + +static int parse_domain(int argc, char *argv[]) { + char *dn; + + dn = (argc > 1)? argv[1] : "f.l.google.com"; + + printf("[%s]\n", dn); + + dn = dns_d_new(dn); + + do { + puts(dn); + } while (dns_d_cleave(dn, strlen(dn) + 1, dn, strlen(dn))); + + return 0; +} /* parse_domain() */ + + +static int expand_domain(int argc, char *argv[]) { + unsigned short rp = 0; + unsigned char *src = NULL; + unsigned char *dst; + struct dns_packet *pkt; + size_t lim = 0, len; + int error; + + if (argv[1]) + rp = atoi(argv[1]); + + len = slurp(&src, 0, stdin, "-"); + + if (!(pkt = dns_p_make(len, &error))) + panic("malloc(%zu): %s", len, dns_strerror(error)); + + memcpy(pkt->data, src, len); + pkt->end = len; + + lim = 1; + dst = grow(NULL, lim); + + while (lim <= (len = dns_d_expand(dst, lim, rp, pkt, &error))) { + lim = add(len, 1); + dst = grow(dst, lim); + } + + if (!len) + panic("expand: %s", dns_strerror(error)); + + fwrite(dst, 1, len, stdout); + fflush(stdout); + + free(src); + free(dst); + free(pkt); + + return 0; +} /* expand_domain() */ + + +static int show_resconf(int argc, char *argv[]) { + unsigned i; + + resconf(); /* load it */ + + fputs("; SOURCES\n", stdout); + + for (i = 0; i < MAIN.resconf.count; i++) + fprintf(stdout, "; %s\n", MAIN.resconf.path[i]); + + fputs(";\n", stdout); + + dns_resconf_dump(resconf(), stdout); + + return 0; +} /* show_resconf() */ + + +static int show_hosts(int argc, char *argv[]) { + unsigned i; + + hosts(); + + fputs("# SOURCES\n", stdout); + + for (i = 0; i < MAIN.hosts.count; i++) + fprintf(stdout, "# %s\n", MAIN.hosts.path[i]); + + fputs("#\n", stdout); + + dns_hosts_dump(hosts(), stdout); + + return 0; +} /* show_hosts() */ + + +static int query_hosts(int argc, char *argv[]) { + struct dns_packet *Q = dns_p_new(512); + struct dns_packet *A; + char qname[DNS_D_MAXNAME + 1]; + size_t qlen; + int error; + + if (!MAIN.qname) + MAIN.qname = (argc > 1)? argv[1] : "localhost"; + if (!MAIN.qtype) + MAIN.qtype = DNS_T_A; + + hosts(); + + if (MAIN.qtype == DNS_T_PTR && !strstr(MAIN.qname, "arpa")) { + union { struct in_addr a; struct in6_addr a6; } addr; + int af = (strchr(MAIN.qname, ':'))? AF_INET6 : AF_INET; + + if (1 != dns_inet_pton(af, MAIN.qname, &addr)) + panic("%s: %s", MAIN.qname, dns_strerror(error)); + + qlen = dns_ptr_qname(qname, sizeof qname, af, &addr); + } else + qlen = dns__printstring(qname, sizeof qname, 0, MAIN.qname); + + if ((error = dns_p_push(Q, DNS_S_QD, qname, qlen, MAIN.qtype, DNS_C_IN, 0, 0))) + panic("%s: %s", qname, dns_strerror(error)); + + if (!(A = dns_hosts_query(hosts(), Q, &error))) + panic("%s: %s", qname, dns_strerror(error)); + + print_packet(A, stdout); + + free(A); + + return 0; +} /* query_hosts() */ + + +static int search_list(int argc, char *argv[]) { + const char *qname = (argc > 1)? argv[1] : "f.l.google.com"; + unsigned long i = 0; + char name[DNS_D_MAXNAME + 1]; + + printf("[%s]\n", qname); + + while (dns_resconf_search(name, sizeof name, qname, strlen(qname), resconf(), &i)) + puts(name); + + return 0; +} /* search_list() */ + + +int permute_set(int argc, char *argv[]) { + unsigned lo, hi, i; + struct dns_k_permutor p; + + hi = (--argc > 0)? atoi(argv[argc]) : 8; + lo = (--argc > 0)? atoi(argv[argc]) : 0; + + fprintf(stderr, "[%u .. %u]\n", lo, hi); + + dns_k_permutor_init(&p, lo, hi); + + for (i = lo; i <= hi; i++) + fprintf(stdout, "%u\n", dns_k_permutor_step(&p)); +// printf("%u -> %u -> %u\n", i, dns_k_permutor_E(&p, i), dns_k_permutor_D(&p, dns_k_permutor_E(&p, i))); + + return 0; +} /* permute_set() */ + + +int shuffle_16(int argc, char *argv[]) { + unsigned n, r; + + if (--argc > 0) { + n = 0xffff & atoi(argv[argc]); + r = (--argc > 0)? (unsigned)atoi(argv[argc]) : dns_random(); + + fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r)); + } else { + r = dns_random(); + + for (n = 0; n < 65536; n++) + fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r)); + } + + return 0; +} /* shuffle_16() */ + + +int dump_random(int argc, char *argv[]) { + unsigned char b[32]; + unsigned i, j, n, r; + + n = (argc > 1)? atoi(argv[1]) : 32; + + while (n) { + i = 0; + + do { + r = dns_random(); + + for (j = 0; j < sizeof r && i < n && i < sizeof b; i++, j++) { + b[i] = 0xff & r; + r >>= 8; + } + } while (i < n && i < sizeof b); + + hexdump(b, i, stdout); + + n -= i; + } + + return 0; +} /* dump_random() */ + + +static int send_query(int argc, char *argv[]) { + struct dns_packet *A, *Q = dns_p_new(512); + char host[INET6_ADDRSTRLEN + 1]; + struct sockaddr_storage ss; + struct dns_socket *so; + int error, type; + + if (argc > 1) { + ss.ss_family = (strchr(argv[1], ':'))? AF_INET6 : AF_INET; + + if (1 != dns_inet_pton(ss.ss_family, argv[1], dns_sa_addr(ss.ss_family, &ss))) + panic("%s: invalid host address", argv[1]); + + *dns_sa_port(ss.ss_family, &ss) = htons(53); + } else + memcpy(&ss, &resconf()->nameserver[0], dns_sa_len(&resconf()->nameserver[0])); + + if (!dns_inet_ntop(ss.ss_family, dns_sa_addr(ss.ss_family, &ss), host, sizeof host)) + panic("bad host address, or none provided"); + + if (!MAIN.qname) + MAIN.qname = "ipv6.google.com"; + if (!MAIN.qtype) + MAIN.qtype = DNS_T_AAAA; + + if ((error = dns_p_push(Q, DNS_S_QD, MAIN.qname, strlen(MAIN.qname), MAIN.qtype, DNS_C_IN, 0, 0))) + panic("dns_p_push: %s", dns_strerror(error)); + + dns_header(Q)->rd = 1; + + if (strstr(argv[0], "udp")) + type = SOCK_DGRAM; + else if (strstr(argv[0], "tcp")) + type = SOCK_STREAM; + else + type = dns_res_tcp2type(resconf()->options.tcp); + + fprintf(stderr, "querying %s for %s IN %s\n", host, MAIN.qname, dns_strtype(MAIN.qtype)); + + if (!(so = dns_so_open((struct sockaddr *)&resconf()->iface, type, dns_opts(), &error))) + panic("dns_so_open: %s", dns_strerror(error)); + + while (!(A = dns_so_query(so, Q, (struct sockaddr *)&ss, &error))) { + if (error != EAGAIN) + panic("dns_so_query: %s (%d)", dns_strerror(error), error); + if (dns_so_elapsed(so) > 10) + panic("query timed-out"); + + dns_so_poll(so, 1); + } + + print_packet(A, stdout); + + dns_so_close(so); + + return 0; +} /* send_query() */ + + +static int print_arpa(int argc, char *argv[]) { + const char *ip = (argc > 1)? argv[1] : "::1"; + int af = (strchr(ip, ':'))? AF_INET6 : AF_INET; + union { struct in_addr a4; struct in6_addr a6; } addr; + char host[DNS_D_MAXNAME + 1]; + + if (1 != dns_inet_pton(af, ip, &addr) || 0 == dns_ptr_qname(host, sizeof host, af, &addr)) + panic("%s: invalid address", ip); + + fprintf(stdout, "%s\n", host); + + return 0; +} /* print_arpa() */ + + +static int show_hints(int argc, char *argv[]) { + struct dns_hints *(*load)(struct dns_resolv_conf *, int *); + const char *which, *how, *who; + struct dns_hints *hints; + int error; + + which = (argc > 1)? argv[1] : "local"; + how = (argc > 2)? argv[2] : "plain"; + who = (argc > 3)? argv[3] : "google.com"; + + load = (0 == strcmp(which, "local")) + ? &dns_hints_local + : &dns_hints_root; + + if (!(hints = load(resconf(), &error))) + panic("%s: %s", argv[0], dns_strerror(error)); + + if (0 == strcmp(how, "plain")) { + dns_hints_dump(hints, stdout); + } else { + struct dns_packet *query, *answer; + + query = dns_p_new(512); + + if ((error = dns_p_push(query, DNS_S_QUESTION, who, strlen(who), DNS_T_A, DNS_C_IN, 0, 0))) + panic("%s: %s", who, dns_strerror(error)); + + if (!(answer = dns_hints_query(hints, query, &error))) + panic("%s: %s", who, dns_strerror(error)); + + print_packet(answer, stdout); + + free(answer); + } + + dns_hints_close(hints); + + return 0; +} /* show_hints() */ + + +static int resolve_query(int argc, char *argv[]) { + struct dns_hints *(*hints)() = (strstr(argv[0], "recurse"))? &dns_hints_root : &dns_hints_local; + struct dns_resolver *R; + struct dns_packet *ans; + const struct dns_stat *st; + int error; + + if (!MAIN.qname) + MAIN.qname = "www.google.com"; + if (!MAIN.qtype) + MAIN.qtype = DNS_T_A; + + resconf()->options.recurse = (0 != strstr(argv[0], "recurse")); + + if (!(R = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), dns_opts(), &error))) + panic("%s: %s", MAIN.qname, dns_strerror(error)); + + if ((error = dns_res_submit(R, MAIN.qname, MAIN.qtype, DNS_C_IN))) + panic("%s: %s", MAIN.qname, dns_strerror(error)); + + while ((error = dns_res_check(R))) { + if (error != EAGAIN) + panic("dns_res_check: %s (%d)", dns_strerror(error), error); + if (dns_res_elapsed(R) > 30) + panic("query timed-out"); + + dns_res_poll(R, 1); + } + + ans = dns_res_fetch(R, &error); + print_packet(ans, stdout); + free(ans); + + st = dns_res_stat(R); + putchar('\n'); + printf(";; queries: %zu\n", st->queries); + printf(";; udp sent: %zu in %zu bytes\n", st->udp.sent.count, st->udp.sent.bytes); + printf(";; udp rcvd: %zu in %zu bytes\n", st->udp.rcvd.count, st->udp.rcvd.bytes); + printf(";; tcp sent: %zu in %zu bytes\n", st->tcp.sent.count, st->tcp.sent.bytes); + printf(";; tcp rcvd: %zu in %zu bytes\n", st->tcp.rcvd.count, st->tcp.rcvd.bytes); + + dns_res_close(R); + + return 0; +} /* resolve_query() */ + + +static int resolve_addrinfo(int argc, char *argv[]) { + struct dns_hints *(*hints)() = (strstr(argv[0], "recurse"))? &dns_hints_root : &dns_hints_local; + struct dns_resolver *res = 0; + struct dns_addrinfo *ai = 0; + struct addrinfo ai_hints = { .ai_family = PF_UNSPEC, .ai_socktype = SOCK_STREAM, .ai_flags = AI_CANONNAME }; + struct addrinfo *ent; + char pretty[512]; + int error; + + if (!MAIN.qname) + MAIN.qname = "www.google.com"; + if (!MAIN.qtype) + MAIN.qtype = DNS_T_A; + + resconf()->options.recurse = (0 != strstr(argv[0], "recurse")); + + if (!(res = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), dns_opts(), &error))) + panic("%s: %s", MAIN.qname, dns_strerror(error)); + + if (!(ai = dns_ai_open(MAIN.qname, "80", MAIN.qtype, &ai_hints, res, &error))) + panic("%s: %s", MAIN.qname, dns_strerror(error)); + + do { + switch (error = dns_ai_nextent(&ent, ai)) { + case 0: + dns_ai_print(pretty, sizeof pretty, ent, ai); + + fputs(pretty, stdout); + + free(ent); + + break; + case ENOENT: + break; + case EAGAIN: + if (dns_ai_elapsed(ai) > 30) + panic("query timed-out"); + + dns_ai_poll(ai, 1); + + break; + default: + panic("dns_ai_nextent: %s (%d)", dns_strerror(error), error); + } + } while (error != ENOENT); + + dns_res_close(res); + dns_ai_close(ai); + + return 0; +} /* resolve_addrinfo() */ + + +static int echo_port(int argc, char *argv[]) { + union { + struct sockaddr sa; + struct sockaddr_in sin; + } port; + int fd; + + memset(&port, 0, sizeof port); + port.sin.sin_family = AF_INET; + port.sin.sin_port = htons(5354); + port.sin.sin_addr.s_addr = inet_addr("127.0.0.1"); + + if (-1 == (fd = socket(PF_INET, SOCK_DGRAM, 0))) + panic("socket: %s", strerror(errno)); + + if (0 != bind(fd, &port.sa, sizeof port.sa)) + panic("127.0.0.1:5353: %s", dns_strerror(errno)); + + for (;;) { + struct dns_packet *pkt = dns_p_new(512); + struct sockaddr_storage ss; + socklen_t slen = sizeof ss; + ssize_t count; +#if defined(MSG_WAITALL) /* MinGW issue */ + int rflags = MSG_WAITALL; +#else + int rflags = 0; +#endif + + count = recvfrom(fd, (char *)pkt->data, pkt->size, rflags, (struct sockaddr *)&ss, &slen); + + + if (!count || count < 0) + panic("recvfrom: %s", strerror(errno)); + + pkt->end = count; + + dns_p_dump(pkt, stdout); + + (void)sendto(fd, (char *)pkt->data, pkt->end, 0, (struct sockaddr *)&ss, slen); + } + + return 0; +} /* echo_port() */ + + +static int isection(int argc, char *argv[]) { + const char *name = (argv[1])? argv[1] : ""; + int type; + + type = dns_isection(name); + name = dns_strsection(type); + + printf("%s (%d)\n", name, type); + + return 0; +} /* isection() */ + + +static int iclass(int argc, char *argv[]) { + const char *name = (argv[1])? argv[1] : ""; + int type; + + type = dns_iclass(name); + name = dns_strclass(type); + + printf("%s (%d)\n", name, type); + + return 0; +} /* iclass() */ + + +static int itype(int argc, char *argv[]) { + const char *name = (argv[1])? argv[1] : ""; + int type; + + type = dns_itype(name); + name = dns_strtype(type); + + printf("%s (%d)\n", name, type); + + return 0; +} /* itype() */ + + +static int iopcode(int argc, char *argv[]) { + const char *name = (argv[1])? argv[1] : ""; + int type; + + type = dns_iopcode(name); + name = dns_stropcode(type); + + printf("%s (%d)\n", name, type); + + return 0; +} /* iopcode() */ + + +static int ircode(int argc, char *argv[]) { + const char *name = (argv[1])? argv[1] : ""; + int type; + + type = dns_ircode(name); + name = dns_strrcode(type); + + printf("%s (%d)\n", name, type); + + return 0; +} /* ircode() */ + + +#define SIZE1(x) { DNS_PP_STRINGIFY(x), sizeof (x) } +#define SIZE2(x, ...) SIZE1(x), SIZE1(__VA_ARGS__) +#define SIZE3(x, ...) SIZE1(x), SIZE2(__VA_ARGS__) +#define SIZE4(x, ...) SIZE1(x), SIZE3(__VA_ARGS__) +#define SIZE(...) DNS_PP_CALL(DNS_PP_XPASTE(SIZE, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__) + +static int sizes(int argc, char *argv[]) { + static const struct { const char *name; size_t size; } type[] = { + SIZE(struct dns_header, struct dns_packet, struct dns_rr, struct dns_rr_i), + SIZE(struct dns_a, struct dns_aaaa, struct dns_mx, struct dns_ns), + SIZE(struct dns_cname, struct dns_soa, struct dns_ptr, struct dns_srv), + SIZE(struct dns_sshfp, struct dns_txt, union dns_any), + SIZE(struct dns_resolv_conf, struct dns_hosts, struct dns_hints, struct dns_hints_i), + SIZE(struct dns_options, struct dns_socket, struct dns_resolver, struct dns_addrinfo), + SIZE(struct dns_cache), + }; + unsigned i, max; + + for (i = 0, max = 0; i < lengthof(type); i++) + max = MAX(max, strlen(type[i].name)); + + for (i = 0; i < lengthof(type); i++) + printf("%*s : %zu\n", max, type[i].name, type[i].size); + + return 0; +} /* sizes() */ + + +static const struct { const char *cmd; int (*run)(); const char *help; } cmds[] = { + { "parse-packet", &parse_packet, "parse binary packet from stdin" }, + { "parse-domain", &parse_domain, "anchor and iteratively cleave domain" }, + { "expand-domain", &expand_domain, "expand domain at offset NN in packet from stdin" }, + { "show-resconf", &show_resconf, "show resolv.conf data" }, + { "show-hosts", &show_hosts, "show hosts data" }, + { "query-hosts", &query_hosts, "query A, AAAA or PTR in hosts data" }, + { "search-list", &search_list, "generate query search list from domain" }, + { "permute-set", &permute_set, "generate random permutation -> (0 .. N or N .. M)" }, + { "shuffle-16", &shuffle_16, "simple 16-bit permutation" }, + { "dump-random", &dump_random, "generate random bytes" }, + { "send-query", &send_query, "send query to host" }, + { "send-query-udp", &send_query, "send udp query to host" }, + { "send-query-tcp", &send_query, "send tcp query to host" }, + { "print-arpa", &print_arpa, "print arpa. zone name of address" }, + { "show-hints", &show_hints, "print hints: show-hints [local|root] [plain|packet]" }, + { "resolve-stub", &resolve_query, "resolve as stub resolver" }, + { "resolve-recurse", &resolve_query, "resolve as recursive resolver" }, + { "addrinfo-stub", &resolve_addrinfo, "resolve through getaddrinfo clone" }, + { "addrinfo-recurse", &resolve_addrinfo, "resolve through getaddrinfo clone" }, +/* { "resolve-nameinfo", &resolve_query, "resolve as recursive resolver" }, */ + { "echo", &echo_port, "server echo mode, for nmap fuzzing" }, + { "isection", &isection, "parse section string" }, + { "iclass", &iclass, "parse class string" }, + { "itype", &itype, "parse type string" }, + { "iopcode", &iopcode, "parse opcode string" }, + { "ircode", &ircode, "parse rcode string" }, + { "sizes", &sizes, "print data structure sizes" }, +}; + + +static void print_usage(const char *progname, FILE *fp) { + static const char *usage = + " [OPTIONS] COMMAND [ARGS]\n" + " -c PATH Path to resolv.conf\n" + " -l PATH Path to local hosts\n" + " -z PATH Path to zone cache\n" + " -q QNAME Query name\n" + " -t QTYPE Query type\n" + " -s HOW Sort records\n" + " -v Be more verbose (-vv show packets; -vvv hexdump packets)\n" + " -V Print version info\n" + " -h Print this usage message\n" + "\n"; + unsigned i, n, m; + + fputs(progname, fp); + fputs(usage, fp); + + for (i = 0, m = 0; i < lengthof(cmds); i++) { + if (strlen(cmds[i].cmd) > m) + m = strlen(cmds[i].cmd); + } + + for (i = 0; i < lengthof(cmds); i++) { + fprintf(fp, " %s ", cmds[i].cmd); + + for (n = strlen(cmds[i].cmd); n < m; n++) + putc(' ', fp); + + fputs(cmds[i].help, fp); + putc('\n', fp); + } + + fputs("\nReport bugs to William Ahern \n", fp); +} /* print_usage() */ + + +static void print_version(const char *progname, FILE *fp) { + fprintf(fp, "%s (dns.c) %.8X\n", progname, dns_v_rel()); + fprintf(fp, "vendor %s\n", dns_vendor()); + fprintf(fp, "release %.8X\n", dns_v_rel()); + fprintf(fp, "abi %.8X\n", dns_v_abi()); + fprintf(fp, "api %.8X\n", dns_v_api()); +} /* print_version() */ + + +int main(int argc, char **argv) { + extern int optind; + extern char *optarg; + const char *progname = argv[0]; + unsigned i; + int ch; + + while (-1 != (ch = getopt(argc, argv, "q:t:c:l:z:s:vVh"))) { + switch (ch) { + case 'c': + assert(MAIN.resconf.count < lengthof(MAIN.resconf.path)); + + MAIN.resconf.path[MAIN.resconf.count++] = optarg; + + break; + case 'l': + assert(MAIN.hosts.count < lengthof(MAIN.hosts.path)); + + MAIN.hosts.path[MAIN.hosts.count++] = optarg; + + break; + case 'z': + assert(MAIN.cache.count < lengthof(MAIN.cache.path)); + + MAIN.cache.path[MAIN.cache.count++] = optarg; + + break; + case 'q': + MAIN.qname = optarg; + + break; + case 't': + for (i = 0; i < lengthof(dns_rrtypes); i++) { + if (0 == strcasecmp(dns_rrtypes[i].name, optarg)) + { MAIN.qtype = dns_rrtypes[i].type; break; } + } + + if (MAIN.qtype) + break; + + for (i = 0; isdigit((int)optarg[i]); i++) { + MAIN.qtype *= 10; + MAIN.qtype += optarg[i] - '0'; + } + + if (!MAIN.qtype) + panic("%s: invalid query type", optarg); + + break; + case 's': + if (0 == strcasecmp(optarg, "packet")) + MAIN.sort = &dns_rr_i_packet; + else if (0 == strcasecmp(optarg, "shuffle")) + MAIN.sort = &dns_rr_i_shuffle; + else if (0 == strcasecmp(optarg, "order")) + MAIN.sort = &dns_rr_i_order; + else + panic("%s: invalid sort method", optarg); + + break; + case 'v': + dns_debug = ++MAIN.verbose; + + break; + case 'V': + print_version(progname, stdout); + + return 0; + case 'h': + print_usage(progname, stdout); + + return 0; + default: + print_usage(progname, stderr); + + return EXIT_FAILURE; + } /* switch() */ + } /* while() */ + + argc -= optind; + argv += optind; + + for (i = 0; i < lengthof(cmds) && argv[0]; i++) { + if (0 == strcmp(cmds[i].cmd, argv[0])) + return cmds[i].run(argc, argv); + } + + print_usage(progname, stderr); + + return EXIT_FAILURE; +} /* main() */ + + +#endif /* DNS_MAIN */ diff --git a/src/lib/ecore_con/dns.h b/src/lib/ecore_con/dns.h new file mode 100644 index 0000000..2b7315f --- /dev/null +++ b/src/lib/ecore_con/dns.h @@ -0,0 +1,1074 @@ +/* ========================================================================== + * dns.h - Recursive, Reentrant DNS Resolver. + * -------------------------------------------------------------------------- + * Copyright (c) 2009, 2010 William Ahern + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * ========================================================================== + */ +#ifndef DNS_H +#define DNS_H + +#include /* size_t offsetof() */ +#include /* FILE */ + +#include /* strlen(3) */ + +#include /* time_t */ + +#if _WIN32 +#include +#include +#else +#include /* socklen_t */ +#include /* struct socket */ + +#include /* POLLIN POLLOUT */ + +#include /* struct in_addr struct in6_addr */ + +#include /* struct addrinfo */ +#endif + + +/* + * V E R S I O N + * + * Vendor: Entity for which versions numbers are relevant. (If forking + * change DNS_VENDOR to avoid confusion.) + * + * Three versions: + * + * REL Official "release"--bug fixes, new features, etc. + * ABI Changes to existing object sizes or parameter types. + * API Changes that might effect application source. + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#define DNS_VENDOR "william@25thandClement.com" + +#define DNS_V_REL 0x20110117 +#define DNS_V_ABI 0x20100709 +#define DNS_V_API 0x20100709 + + +const char *dns_vendor(void); + +int dns_v_rel(void); +int dns_v_abi(void); +int dns_v_api(void); + + +/* + * E R R O R S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +enum dns_errno { + DNS_ENOBUFS = -(('d' << 24) | ('n' << 16) | ('s' << 8) | 64), + DNS_EILLEGAL, + DNS_EORDER, + DNS_ESECTION, + DNS_EUNKNOWN, +}; /* dns_errno */ + +const char *dns_strerror(int); + +extern int dns_debug; + + +/* + * E V E N T S I N T E R F A C E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#if defined(POLLIN) +#define DNS_POLLIN POLLIN +#else +#define DNS_POLLIN 1 +#endif + +#if defined(POLLOUT) +#define DNS_POLLOUT POLLOUT +#else +#define DNS_POLLOUT 2 +#endif + + +/* + * See Application Interface below for configuring libevent bitmasks instead + * of poll(2) bitmasks. + */ +#define DNS_EVREAD 2 +#define DNS_EVWRITE 4 + + +#define DNS_POLL2EV(set) \ + (((set) & DNS_POLLIN)? DNS_EVREAD : 0) | (((set) & DNS_POLLOUT)? DNS_EVWRITE : 0) + +#define DNS_EV2POLL(set) \ + (((set) & DNS_EVREAD)? DNS_POLLIN : 0) | (((set) & DNS_EVWRITE)? DNS_POLLOUT : 0) + + +/* + * E N U M E R A T I O N I N T E R F A C E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +enum dns_section { + DNS_S_QD = 0x01, +#define DNS_S_QUESTION DNS_S_QD + + DNS_S_AN = 0x02, +#define DNS_S_ANSWER DNS_S_AN + + DNS_S_NS = 0x04, +#define DNS_S_AUTHORITY DNS_S_NS + + DNS_S_AR = 0x08, +#define DNS_S_ADDITIONAL DNS_S_AR + + DNS_S_ALL = 0x0f +}; /* enum dns_section */ + + +enum dns_class { + DNS_C_IN = 1, + + DNS_C_ANY = 255 +}; /* enum dns_class */ + + +enum dns_type { + DNS_T_A = 1, + DNS_T_NS = 2, + DNS_T_CNAME = 5, + DNS_T_SOA = 6, + DNS_T_PTR = 12, + DNS_T_MX = 15, + DNS_T_TXT = 16, + DNS_T_AAAA = 28, + DNS_T_SRV = 33, + DNS_T_SSHFP = 44, + DNS_T_SPF = 99, + + DNS_T_ALL = 255 +}; /* enum dns_type */ + + +enum dns_opcode { + DNS_OP_QUERY = 0, + DNS_OP_IQUERY = 1, + DNS_OP_STATUS = 2, + DNS_OP_NOTIFY = 4, + DNS_OP_UPDATE = 5, +}; /* dns_opcode */ + + +enum dns_rcode { + DNS_RC_NOERROR = 0, + DNS_RC_FORMERR = 1, + DNS_RC_SERVFAIL = 2, + DNS_RC_NXDOMAIN = 3, + DNS_RC_NOTIMP = 4, + DNS_RC_REFUSED = 5, + DNS_RC_YXDOMAIN = 6, + DNS_RC_YXRRSET = 7, + DNS_RC_NXRRSET = 8, + DNS_RC_NOTAUTH = 9, + DNS_RC_NOTZONE = 10, +}; /* dns_rcode */ + + +/* + * NOTE: These string functions need a small buffer in case the literal + * integer value needs to be printed and returned. UNLESS this buffer is + * SPECIFIED, the returned string has ONLY BLOCK SCOPE. + */ +#define DNS_STRMAXLEN 47 /* "QUESTION|ANSWER|AUTHORITY|ADDITIONAL" */ + +const char *dns_strsection(enum dns_section, void *, size_t); +#define dns_strsection3(a, b, c) \ + dns_strsection((a), (b), (c)) +#define dns_strsection1(a) dns_strsection((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1) +#define dns_strsection(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strsection, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__) + +enum dns_section dns_isection(const char *); + +const char *dns_strclass(enum dns_class, void *, size_t); +#define dns_strclass3(a, b, c) dns_strclass((a), (b), (c)) +#define dns_strclass1(a) dns_strclass((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1) +#define dns_strclass(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strclass, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__) + +enum dns_class dns_iclass(const char *); + +const char *dns_strtype(enum dns_type, void *, size_t); +#define dns_strtype3(a, b, c) dns_strtype((a), (b), (c)) +#define dns_strtype1(a) dns_strtype((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1) +#define dns_strtype(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strtype, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__) + +enum dns_type dns_itype(const char *); + +const char *dns_stropcode(enum dns_opcode); + +enum dns_opcode dns_iopcode(const char *); + +const char *dns_strrcode(enum dns_rcode); + +enum dns_rcode dns_ircode(const char *); + + +/* + * A T O M I C I N T E R F A C E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +typedef unsigned long dns_atomic_t; + + +/* + * C R Y P T O I N T E R F A C E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +extern unsigned (*dns_random)(void); + + +/* + * P A C K E T I N T E R F A C E + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +struct dns_header { + unsigned qid:16; + +#if BYTE_ORDER == BIG_ENDIAN + unsigned qr:1; + unsigned opcode:4; + unsigned aa:1; + unsigned tc:1; + unsigned rd:1; + + unsigned ra:1; + unsigned unused:3; + unsigned rcode:4; +#else + unsigned rd:1; + unsigned tc:1; + unsigned aa:1; + unsigned opcode:4; + unsigned qr:1; + + unsigned rcode:4; + unsigned unused:3; + unsigned ra:1; +#endif + + unsigned qdcount:16; + unsigned ancount:16; + unsigned nscount:16; + unsigned arcount:16; +}; /* struct dns_header */ + +#define dns_header(p) (&(p)->header) + + +#ifndef DNS_P_QBUFSIZ +#define DNS_P_QBUFSIZ dns_p_calcsize(256 + 4) +#endif + +#ifndef DNS_P_DICTSIZE +#define DNS_P_DICTSIZE 16 +#endif + +struct dns_packet { + unsigned short dict[DNS_P_DICTSIZE]; + + struct dns_s_memo { + unsigned short base, end; + } qd, an, ns, ar; + + struct { struct dns_packet *cqe_next, *cqe_prev; } cqe; + + size_t size, end; + + int:16; /* tcp padding */ + + union { + struct dns_header header; + unsigned char data[1]; + }; +}; /* struct dns_packet */ + +#define dns_p_calcsize(n) (offsetof(struct dns_packet, data) + DNS_PP_MAX(12, (n))) + +#define dns_p_sizeof(P) dns_p_calcsize((P)->end) + +/** takes size of maximum desired payload */ +#define dns_p_new(n) (dns_p_init((struct dns_packet *)&(union { unsigned char b[dns_p_calcsize((n))]; struct dns_packet p; }){ { 0 } }, dns_p_calcsize((n)))) + +/** takes size of entire packet structure as allocated */ +struct dns_packet *dns_p_init(struct dns_packet *, size_t); + +/** takes size of maximum desired payload */ +struct dns_packet *dns_p_make(size_t, int *); + +int dns_p_grow(struct dns_packet **); + +struct dns_packet *dns_p_copy(struct dns_packet *, const struct dns_packet *); + +#define dns_p_opcode(P) (dns_header(P)->opcode) + +#define dns_p_rcode(P) (dns_header(P)->rcode) + +unsigned dns_p_count(struct dns_packet *, enum dns_section); + +int dns_p_push(struct dns_packet *, enum dns_section, const void *, size_t, enum dns_type, enum dns_class, unsigned, const void *); + +void dns_p_dictadd(struct dns_packet *, unsigned short); + +struct dns_packet *dns_p_merge(struct dns_packet *, enum dns_section, struct dns_packet *, enum dns_section, int *); + +void dns_p_dump(struct dns_packet *, FILE *); + +int dns_p_study(struct dns_packet *); + + +/* + * D O M A I N N A M E I N T E R F A C E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#define DNS_D_MAXLABEL 63 /* + 1 '\0' */ +#define DNS_D_MAXNAME 255 /* + 1 '\0' */ + +#define DNS_D_ANCHOR 1 /* anchor domain w/ root "." */ +#define DNS_D_CLEAVE 2 /* cleave sub-domain */ +#define DNS_D_TRIM 4 /* remove superfluous dots */ + +#define dns_d_new3(a, b, f) dns_d_init(&(char[DNS_D_MAXNAME + 1]){ 0 }, DNS_D_MAXNAME + 1, (a), (b), (f)) +#define dns_d_new2(a, f) dns_d_new3((a), strlen((a)), (f)) +#define dns_d_new1(a) dns_d_new3((a), strlen((a)), DNS_D_ANCHOR) +#define dns_d_new(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_d_new, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__) + +char *dns_d_init(void *, size_t, const void *, size_t, int); + +size_t dns_d_anchor(void *, size_t, const void *, size_t); + +size_t dns_d_cleave(void *, size_t, const void *, size_t); + +size_t dns_d_comp(void *, size_t, const void *, size_t, struct dns_packet *, int *); + +size_t dns_d_expand(void *, size_t, unsigned short, struct dns_packet *, int *); + +unsigned short dns_d_skip(unsigned short, struct dns_packet *); + +int dns_d_push(struct dns_packet *, const void *, size_t); + +size_t dns_d_cname(void *, size_t, const void *, size_t, struct dns_packet *, int *error); + + +/* + * R E S O U R C E R E C O R D I N T E R F A C E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +struct dns_rr { + enum dns_section section; + + struct { + unsigned short p; + unsigned short len; + } dn; + + enum dns_type type; + enum dns_class class; + unsigned ttl; + + struct { + unsigned short p; + unsigned short len; + } rd; +}; /* struct dns_rr */ + + +int dns_rr_copy(struct dns_packet *, struct dns_rr *, struct dns_packet *); + +int dns_rr_parse(struct dns_rr *, unsigned short, struct dns_packet *); + +unsigned short dns_rr_skip(unsigned short, struct dns_packet *); + +int dns_rr_cmp(struct dns_rr *, struct dns_packet *, struct dns_rr *, struct dns_packet *); + +size_t dns_rr_print(void *, size_t, struct dns_rr *, struct dns_packet *, int *); + + +#define dns_rr_i_new(P, ...) dns_rr_i_init(&(struct dns_rr_i){ 0, __VA_ARGS__ }, (P)) + +struct dns_rr_i { + enum dns_section section; + const void *name; + enum dns_type type; + enum dns_class class; + const void *data; + + int follow; + + int (*sort)(); + unsigned args[2]; + + struct { + unsigned short next; + unsigned short count; + + unsigned exec; + unsigned regs[2]; + } state, saved; +}; /* struct dns_rr_i */ + +int dns_rr_i_packet(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *); + +int dns_rr_i_order(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *); + +int dns_rr_i_shuffle(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *); + +struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *, struct dns_packet *); + +#define dns_rr_i_save(i) ((i)->saved = (i)->state) +#define dns_rr_i_rewind(i) ((i)->state = (i)->saved) +#define dns_rr_i_count(i) ((i)->state.count) + +unsigned dns_rr_grep(struct dns_rr *, unsigned, struct dns_rr_i *, struct dns_packet *, int *); + +#define dns_rr_foreach_(rr, P, ...) \ + for (struct dns_rr_i DNS_PP_XPASTE(i, __LINE__) = *dns_rr_i_new((P), __VA_ARGS__); dns_rr_grep((rr), 1, &DNS_PP_XPASTE(i, __LINE__), (P), &(int){ 0 }); ) + +#define dns_rr_foreach(...) dns_rr_foreach_(__VA_ARGS__) + + +/* + * A R E S O U R C E R E C O R D + */ + +struct dns_a { + struct in_addr addr; +}; /* struct dns_a */ + +int dns_a_parse(struct dns_a *, struct dns_rr *, struct dns_packet *); + +int dns_a_push(struct dns_packet *, struct dns_a *); + +int dns_a_cmp(const struct dns_a *, const struct dns_a *); + +size_t dns_a_print(void *, size_t, struct dns_a *); + + +/* + * AAAA R E S O U R C E R E C O R D + */ + +struct dns_aaaa { + struct in6_addr addr; +}; /* struct dns_aaaa */ + +int dns_aaaa_parse(struct dns_aaaa *, struct dns_rr *, struct dns_packet *); + +int dns_aaaa_push(struct dns_packet *, struct dns_aaaa *); + +int dns_aaaa_cmp(const struct dns_aaaa *, const struct dns_aaaa *); + +size_t dns_aaaa_print(void *, size_t, struct dns_aaaa *); + + +/* + * MX R E S O U R C E R E C O R D + */ + +struct dns_mx { + unsigned short preference; + char host[DNS_D_MAXNAME + 1]; +}; /* struct dns_mx */ + +int dns_mx_parse(struct dns_mx *, struct dns_rr *, struct dns_packet *); + +int dns_mx_push(struct dns_packet *, struct dns_mx *); + +int dns_mx_cmp(const struct dns_mx *, const struct dns_mx *); + +size_t dns_mx_print(void *, size_t, struct dns_mx *); + +size_t dns_mx_cname(void *, size_t, struct dns_mx *); + + +/* + * NS R E S O U R C E R E C O R D + */ + +struct dns_ns { + char host[DNS_D_MAXNAME + 1]; +}; /* struct dns_ns */ + +int dns_ns_parse(struct dns_ns *, struct dns_rr *, struct dns_packet *); + +int dns_ns_push(struct dns_packet *, struct dns_ns *); + +int dns_ns_cmp(const struct dns_ns *, const struct dns_ns *); + +size_t dns_ns_print(void *, size_t, struct dns_ns *); + +size_t dns_ns_cname(void *, size_t, struct dns_ns *); + + +/* + * CNAME R E S O U R C E R E C O R D + */ + +struct dns_cname { + char host[DNS_D_MAXNAME + 1]; +}; /* struct dns_cname */ + +int dns_cname_parse(struct dns_cname *, struct dns_rr *, struct dns_packet *); + +int dns_cname_push(struct dns_packet *, struct dns_cname *); + +int dns_cname_cmp(const struct dns_cname *, const struct dns_cname *); + +size_t dns_cname_print(void *, size_t, struct dns_cname *); + +size_t dns_cname_cname(void *, size_t, struct dns_cname *); + + +/* + * SOA R E S O U R C E R E C O R D + */ + +struct dns_soa { + char mname[DNS_D_MAXNAME + 1]; + char rname[DNS_D_MAXNAME + 1]; + unsigned serial, refresh, retry, expire, minimum; +}; /* struct dns_soa */ + +int dns_soa_parse(struct dns_soa *, struct dns_rr *, struct dns_packet *); + +int dns_soa_push(struct dns_packet *, struct dns_soa *); + +int dns_soa_cmp(const struct dns_soa *, const struct dns_soa *); + +size_t dns_soa_print(void *, size_t, struct dns_soa *); + + +/* + * PTR R E S O U R C E R E C O R D + */ + +struct dns_ptr { + char host[DNS_D_MAXNAME + 1]; +}; /* struct dns_ptr */ + +int dns_ptr_parse(struct dns_ptr *, struct dns_rr *, struct dns_packet *); + +int dns_ptr_push(struct dns_packet *, struct dns_ptr *); + +int dns_ptr_cmp(const struct dns_ptr *, const struct dns_ptr *); + +size_t dns_ptr_print(void *, size_t, struct dns_ptr *); + +size_t dns_ptr_cname(void *, size_t, struct dns_ptr *); + + +/* + * SRV R E S O U R C E R E C O R D + */ + +struct dns_srv { + unsigned short priority; + unsigned short weight; + unsigned short port; + char target[DNS_D_MAXNAME + 1]; +}; /* struct dns_srv */ + +int dns_srv_parse(struct dns_srv *, struct dns_rr *, struct dns_packet *); + +int dns_srv_push(struct dns_packet *, struct dns_srv *); + +int dns_srv_cmp(const struct dns_srv *, const struct dns_srv *); + +size_t dns_srv_print(void *, size_t, struct dns_srv *); + +size_t dns_srv_cname(void *, size_t, struct dns_srv *); + + +/* + * SSHFP R E S O U R C E R E C O R D + */ + +struct dns_sshfp { + enum dns_sshfp_key { + DNS_SSHFP_RSA = 1, + DNS_SSHFP_DSA = 2, + } algo; + + enum dns_sshfp_digest { + DNS_SSHFP_SHA1 = 1, + } type; + + union { + unsigned char sha1[20]; + } digest; +}; /* struct dns_sshfp */ + +int dns_sshfp_parse(struct dns_sshfp *, struct dns_rr *, struct dns_packet *); + +int dns_sshfp_push(struct dns_packet *, struct dns_sshfp *); + +int dns_sshfp_cmp(const struct dns_sshfp *, const struct dns_sshfp *); + +size_t dns_sshfp_print(void *, size_t, struct dns_sshfp *); + + +/* + * TXT R E S O U R C E R E C O R D + */ + +#ifndef DNS_TXT_MINDATA +#define DNS_TXT_MINDATA 1024 +#endif + +struct dns_txt { + size_t size, len; + unsigned char data[DNS_TXT_MINDATA]; +}; /* struct dns_txt */ + +struct dns_txt *dns_txt_init(struct dns_txt *, size_t); + +int dns_txt_parse(struct dns_txt *, struct dns_rr *, struct dns_packet *); + +int dns_txt_push(struct dns_packet *, struct dns_txt *); + +int dns_txt_cmp(const struct dns_txt *, const struct dns_txt *); + +size_t dns_txt_print(void *, size_t, struct dns_txt *); + + +/* + * ANY R E S O U R C E R E C O R D + */ + +union dns_any { + struct dns_a a; + struct dns_aaaa aaaa; + struct dns_mx mx; + struct dns_ns ns; + struct dns_cname cname; + struct dns_soa soa; + struct dns_ptr ptr; + struct dns_srv srv; + struct dns_sshfp sshfp; + struct dns_txt txt, spf, rdata; +}; /* union dns_any */ + +#define DNS_ANY_INIT(any) { .rdata = { .size = sizeof *(any) } } + +union dns_any *dns_any_init(union dns_any *, size_t); + +int dns_any_parse(union dns_any *, struct dns_rr *, struct dns_packet *); + +int dns_any_push(struct dns_packet *, union dns_any *, enum dns_type); + +int dns_any_cmp(const union dns_any *, enum dns_type, const union dns_any *, enum dns_type); + +size_t dns_any_print(void *, size_t, union dns_any *, enum dns_type); + +size_t dns_any_cname(void *, size_t, union dns_any *, enum dns_type); + + +/* + * H O S T S I N T E R F A C E + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +struct dns_hosts; + +struct dns_hosts *dns_hosts_open(int *); + +void dns_hosts_close(struct dns_hosts *); + +unsigned dns_hosts_acquire(struct dns_hosts *); + +unsigned dns_hosts_release(struct dns_hosts *); + +struct dns_hosts *dns_hosts_mortal(struct dns_hosts *); + +struct dns_hosts *dns_hosts_local(int *); + +int dns_hosts_loadfile(struct dns_hosts *, FILE *); + +int dns_hosts_loadpath(struct dns_hosts *, const char *); + +int dns_hosts_dump(struct dns_hosts *, FILE *); + +int dns_hosts_insert(struct dns_hosts *, int, const void *, const void *, _Bool); + +struct dns_packet *dns_hosts_query(struct dns_hosts *, struct dns_packet *, int *); + + +/* + * R E S O L V . C O N F I N T E R F A C E + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +struct dns_resolv_conf { + struct sockaddr_storage nameserver[3]; + + char search[4][DNS_D_MAXNAME + 1]; + + /* (f)ile, (b)ind, (c)ache */ + char lookup[3]; + + struct { + _Bool edns0; + + unsigned ndots; + + unsigned timeout; + + unsigned attempts; + + _Bool rotate; + + _Bool recurse; + + _Bool smart; + + enum { + DNS_RESCONF_TCP_ENABLE, + DNS_RESCONF_TCP_ONLY, + DNS_RESCONF_TCP_DISABLE, + } tcp; + } options; + + struct sockaddr_storage iface; + + struct { /* PRIVATE */ + dns_atomic_t refcount; + } _; +}; /* struct dns_resolv_conf */ + +struct dns_resolv_conf *dns_resconf_open(int *); + +void dns_resconf_close(struct dns_resolv_conf *); + +unsigned dns_resconf_acquire(struct dns_resolv_conf *); + +unsigned dns_resconf_release(struct dns_resolv_conf *); + +struct dns_resolv_conf *dns_resconf_mortal(struct dns_resolv_conf *); + +struct dns_resolv_conf *dns_resconf_local(int *); + +struct dns_resolv_conf *dns_resconf_root(int *); + +int dns_resconf_loadfile(struct dns_resolv_conf *, FILE *); + +int dns_resconf_loadpath(struct dns_resolv_conf *, const char *); + +int dns_resconf_dump(struct dns_resolv_conf *, FILE *); + +int dns_resconf_setiface(struct dns_resolv_conf *, const char *, unsigned short); + +typedef unsigned long dns_resconf_i_t; + +size_t dns_resconf_search(void *, size_t, const void *, size_t, struct dns_resolv_conf *, dns_resconf_i_t *); + + +/* + * H I N T S E R V E R I N T E R F A C E + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +struct dns_hints; + +struct dns_hints *dns_hints_open(struct dns_resolv_conf *, int *); + +void dns_hints_close(struct dns_hints *); + +unsigned dns_hints_acquire(struct dns_hints *); + +unsigned dns_hints_release(struct dns_hints *); + +struct dns_hints *dns_hints_mortal(struct dns_hints *); + +int dns_hints_insert(struct dns_hints *, const char *, const struct sockaddr *, unsigned); + +unsigned dns_hints_insert_resconf(struct dns_hints *, const char *, const struct dns_resolv_conf *, int *); + +struct dns_hints *dns_hints_local(struct dns_resolv_conf *, int *); + +struct dns_hints *dns_hints_root(struct dns_resolv_conf *, int *); + + +struct dns_hints_i { + const char *zone; + + struct { + unsigned next; + unsigned seed; + } state; +}; /* struct dns_hints_i */ + +#define dns_hints_i_new(...) (&(struct dns_hints_i){ __VA_ARGS__ }) + +unsigned dns_hints_grep(struct sockaddr **, socklen_t *, unsigned, struct dns_hints_i *, struct dns_hints *); + + +/* + * C A C H E I N T E R F A C E + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +struct dns_cache { + void *state; + + dns_atomic_t (*acquire)(struct dns_cache *); + dns_atomic_t (*release)(struct dns_cache *); + + struct dns_packet *(*query)(struct dns_packet *, struct dns_cache *, int *); + + int (*submit)(struct dns_packet *, struct dns_cache *); + int (*check)(struct dns_cache *); + struct dns_packet *(*fetch)(struct dns_cache *, int *); + + int (*pollfd)(struct dns_cache *); + short (*events)(struct dns_cache *); + void (*clear)(struct dns_cache *); + + union { + long i; + void *p; + } arg[3]; +}; /* struct dns_cache */ + + +struct dns_cache *dns_cache_init(struct dns_cache *); + +void dns_cache_close(struct dns_cache *); + + +/* + * A P P L I C A T I O N I N T E R F A C E + * + * Options to change the behavior of the API. Applies across all the + * different components. + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#define DNS_OPTS_INITIALIZER_ { 0, 0 }, 0 +#define DNS_OPTS_INITIALIZER { DNS_OPTS_INITIALIZER_ } +#define DNS_OPTS_INIT(...) { DNS_OPTS_INITIALIZER_, __VA_ARGS__ } + +#define dns_opts(...) (&(struct dns_options)DNS_OPTS_INIT(__VA_ARGS__)) + +struct dns_options { + /* + * If the callback closes *fd, it must set it to -1. Otherwise, the + * descriptor is queued and lazily closed at object destruction or + * by an explicit call to _clear(). This allows safe use of + * kqueue(2), epoll(2), et al -style persistent events. + */ + struct { + void *arg; + int (*cb)(int *fd, void *arg); + } closefd; + + /* bitmask for _events() routines */ + enum dns_events { + DNS_SYSPOLL, + DNS_LIBEVENT, + } events; +}; /* struct dns_options */ + + +/* + * S T A T S I N T E R F A C E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +struct dns_stat { + size_t queries; + + struct { + struct { + size_t count, bytes; + } sent, rcvd; + } udp, tcp; +}; /* struct dns_stat */ + + +/* + * S O C K E T I N T E R F A C E + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +struct dns_socket; + +struct dns_socket *dns_so_open(const struct sockaddr *, int, const struct dns_options *, int *error); + +void dns_so_close(struct dns_socket *); + +void dns_so_reset(struct dns_socket *); + +unsigned short dns_so_mkqid(struct dns_socket *so); + +struct dns_packet *dns_so_query(struct dns_socket *, struct dns_packet *, struct sockaddr *, int *); + +int dns_so_submit(struct dns_socket *, struct dns_packet *, struct sockaddr *); + +int dns_so_check(struct dns_socket *); + +struct dns_packet *dns_so_fetch(struct dns_socket *, int *); + +time_t dns_so_elapsed(struct dns_socket *); + +void dns_so_clear(struct dns_socket *); + +int dns_so_events(struct dns_socket *); + +int dns_so_pollfd(struct dns_socket *); + +int dns_so_poll(struct dns_socket *, int); + +const struct dns_stat *dns_so_stat(struct dns_socket *); + + +/* + * R E S O L V E R I N T E R F A C E + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +struct dns_resolver; + +struct dns_resolver *dns_res_open(struct dns_resolv_conf *, struct dns_hosts *hosts, struct dns_hints *, struct dns_cache *, const struct dns_options *, int *); + +struct dns_resolver *dns_res_stub(const struct dns_options *, int *); + +void dns_res_reset(struct dns_resolver *); + +void dns_res_close(struct dns_resolver *); + +unsigned dns_res_acquire(struct dns_resolver *); + +unsigned dns_res_release(struct dns_resolver *); + +struct dns_resolver *dns_res_mortal(struct dns_resolver *); + +int dns_res_submit(struct dns_resolver *, const char *, enum dns_type, enum dns_class); + +int dns_res_check(struct dns_resolver *); + +struct dns_packet *dns_res_fetch(struct dns_resolver *, int *); + +time_t dns_res_elapsed(struct dns_resolver *); + +void dns_res_clear(struct dns_resolver *); + +int dns_res_events(struct dns_resolver *); + +int dns_res_pollfd(struct dns_resolver *); + +int dns_res_poll(struct dns_resolver *, int); + +struct dns_packet *dns_res_query(struct dns_resolver *, const char *, enum dns_type, enum dns_class, int, int *); + +const struct dns_stat *dns_res_stat(struct dns_resolver *); + + +/* + * A D D R I N F O I N T E R F A C E + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +struct dns_addrinfo; + +struct dns_addrinfo *dns_ai_open(const char *, const char *, enum dns_type, const struct addrinfo *, struct dns_resolver *, int *); + +void dns_ai_close(struct dns_addrinfo *); + +int dns_ai_nextent(struct addrinfo **, struct dns_addrinfo *); + +size_t dns_ai_print(void *, size_t, struct addrinfo *, struct dns_addrinfo *); + +time_t dns_ai_elapsed(struct dns_addrinfo *); + +void dns_ai_clear(struct dns_addrinfo *); + +int dns_ai_events(struct dns_addrinfo *); + +int dns_ai_pollfd(struct dns_addrinfo *); + +int dns_ai_poll(struct dns_addrinfo *, int); + +const struct dns_stat *dns_ai_stat(struct dns_addrinfo *); + +void *dns_sa_addr(int af, void *sa); +unsigned short *dns_sa_port(int af, void *sa); +#if _WIN32 +const char *dns_inet_ntop(int af, const void *src, void *dst, unsigned long lim); +#else +#define dns_inet_pton(...) inet_pton(__VA_ARGS__) +#define dns_inet_ntop(...) inet_ntop(__VA_ARGS__) +#endif +#define dns_sa_family(sa) (((struct sockaddr *)(sa))->sa_family) +/* + * U T I L I T Y I N T E R F A C E S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +size_t dns_strlcpy(char *, const char *, size_t); + +size_t dns_strlcat(char *, const char *, size_t); + + +/* + * M A C R O M A G I C S + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#define DNS_PP_MAX(a, b) (((a) > (b))? (a) : (b)) +#define DNS_PP_NARG_(a, b, c, d, e, f, g, h, i, j, k, N,...) N +#define DNS_PP_NARG(...) DNS_PP_NARG_(__VA_ARGS__, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) +#define DNS_PP_CALL(F, ...) F(__VA_ARGS__) +#define DNS_PP_PASTE(x, y) x##y +#define DNS_PP_XPASTE(x, y) DNS_PP_PASTE(x, y) +#define DNS_PP_STRINGIFY_(s) #s +#define DNS_PP_STRINGIFY(s) DNS_PP_STRINGIFY_(s) +#define DNS_PP_D1 0 +#define DNS_PP_D2 1 +#define DNS_PP_D3 2 +#define DNS_PP_D4 3 +#define DNS_PP_D5 4 +#define DNS_PP_D6 5 +#define DNS_PP_D7 6 +#define DNS_PP_D8 7 +#define DNS_PP_D9 8 +#define DNS_PP_D10 9 +#define DNS_PP_D11 10 +#define DNS_PP_DEC(N) DNS_PP_XPASTE(DNS_PP_D, N) + +#endif /* DNS_H */ diff --git a/src/lib/ecore_con/ecore_con.c b/src/lib/ecore_con/ecore_con.c new file mode 100644 index 0000000..b4e01cb --- /dev/null +++ b/src/lib/ecore_con/ecore_con.c @@ -0,0 +1,2586 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_NETINET_TCP_H +# include +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#ifdef HAVE_ARPA_INET_H +# include +#endif + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif + +#ifdef HAVE_SYS_UN_H +# include +#endif + +#ifdef HAVE_WS2TCPIP_H +# include +#endif + +#ifdef HAVE_EVIL +# include +#endif + +#include "Ecore.h" +#include "ecore_private.h" +#include "Ecore_Con.h" +#include "ecore_con_private.h" + +static Eina_Bool _ecore_con_client_timer(Ecore_Con_Client *cl); +static void _ecore_con_cl_timer_update(Ecore_Con_Client *cl); +static Eina_Bool _ecore_con_server_timer(Ecore_Con_Server *svr); +static void _ecore_con_server_timer_update(Ecore_Con_Server *svr); + +static void _ecore_con_cb_tcp_connect(void *data, + Ecore_Con_Info *info); +static void _ecore_con_cb_udp_connect(void *data, + Ecore_Con_Info *info); +static void _ecore_con_cb_tcp_listen(void *data, + Ecore_Con_Info *info); +static void _ecore_con_cb_udp_listen(void *data, + Ecore_Con_Info *info); + +static void _ecore_con_server_free(Ecore_Con_Server *svr); +static void _ecore_con_client_free(Ecore_Con_Client *cl); + +static void _ecore_con_cl_read(Ecore_Con_Server *svr); +static Eina_Bool _ecore_con_svr_tcp_handler(void *data, + Ecore_Fd_Handler *fd_handler); +static Eina_Bool _ecore_con_cl_handler(void *data, + Ecore_Fd_Handler *fd_handler); +static Eina_Bool _ecore_con_cl_udp_handler(void *data, + Ecore_Fd_Handler *fd_handler); +static Eina_Bool _ecore_con_svr_udp_handler(void *data, + Ecore_Fd_Handler *fd_handler); + +static void _ecore_con_svr_cl_read(Ecore_Con_Client *cl); +static Eina_Bool _ecore_con_svr_cl_handler(void *data, + Ecore_Fd_Handler *fd_handler); + +static void _ecore_con_server_flush(Ecore_Con_Server *svr); +static void _ecore_con_client_flush(Ecore_Con_Client *cl); + +static void _ecore_con_event_client_add_free(Ecore_Con_Server *svr, + void *ev); +static void _ecore_con_event_client_del_free(Ecore_Con_Server *svr, + void *ev); +static void _ecore_con_event_client_data_free(Ecore_Con_Server *svr, + void *ev); +static void _ecore_con_event_server_add_free(void *data, + void *ev); +static void _ecore_con_event_server_del_free(void *data, + void *ev); +static void _ecore_con_event_server_data_free(void *data, + void *ev); +static void _ecore_con_event_server_error_free(void *data, + Ecore_Con_Event_Server_Error *e); +static void _ecore_con_event_client_error_free(Ecore_Con_Server *svr, + Ecore_Con_Event_Client_Error *e); +static void _ecore_con_event_server_write_free(void *data, + Ecore_Con_Event_Server_Write *e); +static void _ecore_con_event_client_write_free(Ecore_Con_Server *svr, + Ecore_Con_Event_Client_Write *e); + +static void _ecore_con_lookup_done(void *data, + Ecore_Con_Info *infos); + +static const char * _ecore_con_pretty_ip(struct sockaddr *client_addr); + + +void +_ecore_con_client_kill(Ecore_Con_Client *cl) +{ + if (cl->delete_me) + DBG("Multi kill request for client %p", cl); + else + { + ecore_con_event_client_del(cl); + if (cl->buf) return; + } + INF("Lost client %s", (cl->ip) ? cl->ip : ""); + if (cl->fd_handler) + ecore_main_fd_handler_del(cl->fd_handler); + + cl->fd_handler = NULL; +} + +void +_ecore_con_server_kill(Ecore_Con_Server *svr) +{ + if (svr->delete_me) + DBG("Multi kill request for svr %p", svr); + else + ecore_con_event_server_del(svr); + + if (svr->fd_handler) + ecore_main_fd_handler_del(svr->fd_handler); + + svr->fd_handler = NULL; +} + +#define _ecore_con_server_kill(svr) do { \ + DBG("KILL %p", (svr)); \ + _ecore_con_server_kill((svr)); \ +} while (0) + +#define _ecore_con_client_kill(cl) do { \ + DBG("KILL %p", (cl)); \ + _ecore_con_client_kill((cl)); \ +} while (0) + +EAPI int ECORE_CON_EVENT_CLIENT_ADD = 0; +EAPI int ECORE_CON_EVENT_CLIENT_DEL = 0; +EAPI int ECORE_CON_EVENT_SERVER_ADD = 0; +EAPI int ECORE_CON_EVENT_SERVER_DEL = 0; +EAPI int ECORE_CON_EVENT_CLIENT_DATA = 0; +EAPI int ECORE_CON_EVENT_SERVER_DATA = 0; +EAPI int ECORE_CON_EVENT_CLIENT_WRITE = 0; +EAPI int ECORE_CON_EVENT_SERVER_WRITE = 0; +EAPI int ECORE_CON_EVENT_CLIENT_ERROR = 0; +EAPI int ECORE_CON_EVENT_SERVER_ERROR = 0; +EAPI int ECORE_CON_EVENT_PROXY_BIND = 0; + +static Eina_List *servers = NULL; +static int _ecore_con_init_count = 0; +static int _ecore_con_event_count = 0; +int _ecore_con_log_dom = -1; +Ecore_Con_Socks *_ecore_con_proxy_once = NULL; +Ecore_Con_Socks *_ecore_con_proxy_global = NULL; + +EAPI int +ecore_con_init(void) +{ + if (++_ecore_con_init_count != 1) + return _ecore_con_init_count; + +#ifdef HAVE_EVIL + if (!evil_init()) + return --_ecore_con_init_count; + +#endif + + if (!ecore_init()) + return --_ecore_con_init_count; + + _ecore_con_log_dom = eina_log_domain_register + ("ecore_con", ECORE_CON_DEFAULT_LOG_COLOR); + if (_ecore_con_log_dom < 0) + { + EINA_LOG_ERR("Impossible to create a log domain for Ecore Con."); + ecore_shutdown(); + return --_ecore_con_init_count; + } + + ecore_con_mempool_init(); + + ECORE_CON_EVENT_CLIENT_ADD = ecore_event_type_new(); + ECORE_CON_EVENT_CLIENT_DEL = ecore_event_type_new(); + ECORE_CON_EVENT_SERVER_ADD = ecore_event_type_new(); + ECORE_CON_EVENT_SERVER_DEL = ecore_event_type_new(); + ECORE_CON_EVENT_CLIENT_DATA = ecore_event_type_new(); + ECORE_CON_EVENT_SERVER_DATA = ecore_event_type_new(); + ECORE_CON_EVENT_CLIENT_WRITE = ecore_event_type_new(); + ECORE_CON_EVENT_SERVER_WRITE = ecore_event_type_new(); + ECORE_CON_EVENT_CLIENT_ERROR = ecore_event_type_new(); + ECORE_CON_EVENT_SERVER_ERROR = ecore_event_type_new(); + ECORE_CON_EVENT_PROXY_BIND = ecore_event_type_new(); + + + eina_magic_string_set(ECORE_MAGIC_CON_SERVER, "Ecore_Con_Server"); + eina_magic_string_set(ECORE_MAGIC_CON_CLIENT, "Ecore_Con_Client"); + eina_magic_string_set(ECORE_MAGIC_CON_URL, "Ecore_Con_Url"); + + /* TODO Remember return value, if it fails, use gethostbyname() */ + ecore_con_socks_init(); + ecore_con_ssl_init(); + ecore_con_info_init(); + + return _ecore_con_init_count; +} + +EAPI int +ecore_con_shutdown(void) +{ + Eina_List *l, *l2; + Ecore_Con_Server *svr; + + if (--_ecore_con_init_count != 0) + return _ecore_con_init_count; + + EINA_LIST_FOREACH_SAFE(servers, l, l2, svr) + { + Ecore_Con_Event_Server_Add *ev; + + svr->delete_me = EINA_TRUE; + INF("svr %p is dead", svr); + /* some pointer hacks here to prevent double frees if people are being stupid */ + EINA_LIST_FREE(svr->event_count, ev) + ev->server = NULL; + _ecore_con_server_free(svr); + } + + ecore_con_socks_shutdown(); + if (!_ecore_con_event_count) ecore_con_mempool_shutdown(); + + ecore_con_info_shutdown(); + ecore_con_ssl_shutdown(); + eina_log_domain_unregister(_ecore_con_log_dom); + _ecore_con_log_dom = -1; + ecore_shutdown(); +#ifdef HAVE_EVIL + evil_shutdown(); +#endif + + return _ecore_con_init_count; +} + +EAPI Eina_Bool +ecore_con_lookup(const char *name, + Ecore_Con_Dns_Cb done_cb, + const void *data) +{ + Ecore_Con_Server *svr; + Ecore_Con_Lookup *lk; + struct addrinfo hints; + + if (!name || !done_cb) + return EINA_FALSE; + + svr = calloc(1, sizeof(Ecore_Con_Server)); + if (!svr) + return EINA_FALSE; + + lk = malloc(sizeof (Ecore_Con_Lookup)); + if (!lk) + { + free(svr); + return EINA_FALSE; + } + + lk->done_cb = done_cb; + lk->data = data; + + svr->name = strdup(name); + if (!svr->name) + goto on_error; + + svr->type = ECORE_CON_REMOTE_TCP; + svr->port = 1025; + svr->data = lk; + svr->created = EINA_TRUE; + svr->reject_excess_clients = EINA_FALSE; + svr->client_limit = -1; + svr->clients = NULL; + svr->ppid = getpid(); + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + hints.ai_addr = NULL; + + if (ecore_con_info_get(svr, _ecore_con_lookup_done, svr, + &hints)) + return EINA_TRUE; + + free(svr->name); +on_error: + free(lk); + free(svr); + return EINA_FALSE; +} + +/** + * @addtogroup Ecore_Con_Server_Group Ecore Connection Server Functions + * + * Functions that operate on Ecore server objects. + * + * @{ + */ + +/** + * @example ecore_con_server_example.c + * Shows how to write a simple server using the Ecore_Con library. + */ + +EAPI Ecore_Con_Server * +ecore_con_server_add(Ecore_Con_Type compl_type, + const char *name, + int port, + const void *data) +{ + Ecore_Con_Server *svr; + Ecore_Con_Type type; + + if (port < 0 || !name) + return NULL; /* local user socket: FILE: ~/.ecore/[name]/[port] */ + + /* local system socket: FILE: /tmp/.ecore_service|[name]|[port] */ + /* remote system socket: TCP/IP: [name]:[port] */ + svr = calloc(1, sizeof(Ecore_Con_Server)); + if (!svr) + return NULL; + + svr->name = strdup(name); + if (!svr->name) + goto error; + + svr->type = compl_type; + svr->port = port; + svr->data = (void *)data; + svr->created = EINA_TRUE; + svr->use_cert = (compl_type & ECORE_CON_SSL & ECORE_CON_LOAD_CERT) == ECORE_CON_LOAD_CERT; + svr->reject_excess_clients = EINA_FALSE; + svr->client_limit = -1; + svr->clients = NULL; + svr->ppid = getpid(); + if (ecore_con_ssl_server_prepare(svr, compl_type & ECORE_CON_SSL)) + goto error; + + type = compl_type & ECORE_CON_TYPE; + + if ((type == ECORE_CON_LOCAL_USER) || + (type == ECORE_CON_LOCAL_SYSTEM) || + (type == ECORE_CON_LOCAL_ABSTRACT)) + /* Local */ +#ifdef _WIN32 + if (!ecore_con_local_listen(svr)) + goto error; +#else + if (!ecore_con_local_listen(svr, _ecore_con_svr_tcp_handler, svr)) + goto error; +#endif + + if ((type == ECORE_CON_REMOTE_TCP) || + (type == ECORE_CON_REMOTE_NODELAY) || + (type == ECORE_CON_REMOTE_CORK)) + { + /* TCP */ + if (!ecore_con_info_tcp_listen(svr, _ecore_con_cb_tcp_listen, + svr)) + goto error; + } + else if ((type == ECORE_CON_REMOTE_MCAST) || + (type == ECORE_CON_REMOTE_UDP)) + /* UDP and MCAST */ + if (!ecore_con_info_udp_listen(svr, _ecore_con_cb_udp_listen, + svr)) + goto error; + + servers = eina_list_append(servers, svr); + ECORE_MAGIC_SET(svr, ECORE_MAGIC_CON_SERVER); + + return svr; + +error: + if (svr->name) + free(svr->name); + + if (svr->path) + free(svr->path); + + + if (svr->fd_handler) + ecore_main_fd_handler_del(svr->fd_handler); + + if (svr->fd > 0) + close(svr->fd); + + if (svr->buf) + eina_binbuf_free(svr->buf); + + if (svr->ip) + eina_stringshare_del(svr->ip); + + ecore_con_ssl_server_shutdown(svr); + free(svr); + return NULL; +} + +EAPI Ecore_Con_Server * +ecore_con_server_connect(Ecore_Con_Type compl_type, + const char *name, + int port, + const void *data) +{ + Ecore_Con_Server *svr; + Ecore_Con_Type type; + + if ((!name) || (!name[0])) + return NULL; + /* local user socket: FILE: ~/.ecore/[name]/[port] */ + /* local system socket: FILE: /tmp/.ecore_service|[name]|[port] */ + /* remote system socket: TCP/IP: [name]:[port] */ + svr = calloc(1, sizeof(Ecore_Con_Server)); + if (!svr) + return NULL; + + svr->name = strdup(name); + if (!svr->name) + goto error; + + svr->type = compl_type; + svr->port = port; + svr->data = (void *)data; + svr->created = EINA_FALSE; + svr->use_cert = (compl_type & ECORE_CON_SSL & ECORE_CON_LOAD_CERT) == ECORE_CON_LOAD_CERT; + svr->disable_proxy = (compl_type & ECORE_CON_SUPER_SSL & ECORE_CON_NO_PROXY) == ECORE_CON_NO_PROXY; + svr->reject_excess_clients = EINA_FALSE; + svr->clients = NULL; + svr->client_limit = -1; + + type = compl_type & ECORE_CON_TYPE; + + if ((!svr->disable_proxy) && (type > ECORE_CON_LOCAL_ABSTRACT)) + { + /* never use proxies on local connections */ + if (_ecore_con_proxy_once) + svr->ecs = _ecore_con_proxy_once; + else if (_ecore_con_proxy_global) + svr->ecs = _ecore_con_proxy_global; + _ecore_con_proxy_once = NULL; + if (svr->ecs) + { + if ((!svr->ecs->lookup) && + (!ecore_con_lookup(svr->name, (Ecore_Con_Dns_Cb)ecore_con_socks_dns_cb, svr))) + goto error; + if (svr->ecs->lookup) + svr->ecs_state = ECORE_CON_PROXY_STATE_RESOLVED; + } + } + EINA_SAFETY_ON_TRUE_GOTO(ecore_con_ssl_server_prepare(svr, compl_type & ECORE_CON_SSL), error); + + EINA_SAFETY_ON_TRUE_GOTO(((type == ECORE_CON_REMOTE_TCP) || + (type == ECORE_CON_REMOTE_NODELAY) || + (type == ECORE_CON_REMOTE_CORK) || + (type == ECORE_CON_REMOTE_UDP) || + (type == ECORE_CON_REMOTE_BROADCAST)) && + (port < 0), error); + + if ((type == ECORE_CON_LOCAL_USER) || + (type == ECORE_CON_LOCAL_SYSTEM) || + (type == ECORE_CON_LOCAL_ABSTRACT)) + /* Local */ +#ifdef _WIN32 + EINA_SAFETY_ON_FALSE_GOTO(ecore_con_local_connect(svr, _ecore_con_cl_handler), error); +#else + EINA_SAFETY_ON_FALSE_GOTO(ecore_con_local_connect(svr, _ecore_con_cl_handler, svr), error); +#endif + + if ((type == ECORE_CON_REMOTE_TCP) || + (type == ECORE_CON_REMOTE_NODELAY) || + (type == ECORE_CON_REMOTE_CORK)) + { + /* TCP */ + EINA_SAFETY_ON_FALSE_GOTO(ecore_con_info_tcp_connect(svr, _ecore_con_cb_tcp_connect, svr), error); + } + else if ((type == ECORE_CON_REMOTE_UDP) || (type == ECORE_CON_REMOTE_BROADCAST)) + /* UDP and MCAST */ + EINA_SAFETY_ON_FALSE_GOTO(ecore_con_info_udp_connect(svr, _ecore_con_cb_udp_connect, svr), error); + + servers = eina_list_append(servers, svr); + ECORE_MAGIC_SET(svr, ECORE_MAGIC_CON_SERVER); + + return svr; + +error: + if (svr->name) + free(svr->name); + + if (svr->path) + free(svr->path); + + if (svr->fd_handler) + ecore_main_fd_handler_del(svr->fd_handler); + + if (svr->fd > 0) + close(svr->fd); + + ecore_con_ssl_server_shutdown(svr); + free(svr); + return NULL; +} + +EAPI void +ecore_con_server_timeout_set(Ecore_Con_Server *svr, + double timeout) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_timeout_set"); + return; + } + + if (svr->created) + svr->client_disconnect_time = timeout; + else + svr->disconnect_time = timeout; +} + +EAPI double +ecore_con_server_timeout_get(Ecore_Con_Server *svr) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_timeout_get"); + return 0; + } + + return svr->created ? svr->client_disconnect_time : svr->disconnect_time; +} + +EAPI void * +ecore_con_server_del(Ecore_Con_Server *svr) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_del"); + return NULL; + } + + if (svr->delete_me) + return NULL; + + _ecore_con_server_kill(svr); + return svr->data; +} + +EAPI void * +ecore_con_server_data_get(Ecore_Con_Server *svr) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_data_get"); + return NULL; + } + + return svr->data; +} + +EAPI void * +ecore_con_server_data_set(Ecore_Con_Server *svr, + void *data) +{ + void *ret = NULL; + + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_data_get"); + return NULL; + } + + ret = svr->data; + svr->data = data; + return ret; +} + +EAPI Eina_Bool +ecore_con_server_connected_get(Ecore_Con_Server *svr) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_connected_get"); + return EINA_FALSE; + } + + if (svr->connecting) + return EINA_FALSE; + + return EINA_TRUE; +} + +EAPI const Eina_List * +ecore_con_server_clients_get(Ecore_Con_Server *svr) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, + "ecore_con_server_clients_get"); + return NULL; + } + + return svr->clients; +} + +EAPI const char * +ecore_con_server_name_get(Ecore_Con_Server *svr) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, + "ecore_con_server_name_get"); + return NULL; + } + + return svr->name; +} + +EAPI int +ecore_con_server_port_get(Ecore_Con_Server *svr) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, + "ecore_con_server_port_get"); + return -1; + } + return svr->port; +} + +EAPI int +ecore_con_server_send(Ecore_Con_Server *svr, + const void *data, + int size) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_send"); + return 0; + } + + EINA_SAFETY_ON_TRUE_RETURN_VAL(svr->delete_me, 0); + + EINA_SAFETY_ON_NULL_RETURN_VAL(data, 0); + + EINA_SAFETY_ON_TRUE_RETURN_VAL(size < 1, 0); + + if (svr->fd_handler) + ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ | ECORE_FD_WRITE); + + if (!svr->buf) + { + svr->buf = eina_binbuf_new(); + EINA_SAFETY_ON_NULL_RETURN_VAL(svr->buf, 0); +#ifdef TCP_CORK + if ((svr->fd >= 0) && ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_CORK)) + { + int state = 1; + if (setsockopt(svr->fd, IPPROTO_TCP, TCP_CORK, (char *)&state, sizeof(int)) < 0) + /* realistically this isn't anything serious so we can just log and continue */ + ERR("corking failed! %s", strerror(errno)); + } +#endif + } + eina_binbuf_append_length(svr->buf, data, size); + + return size; +} + +EAPI void +ecore_con_server_client_limit_set(Ecore_Con_Server *svr, + int client_limit, + char reject_excess_clients) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, + "ecore_con_server_client_limit_set"); + return; + } + + svr->client_limit = client_limit; + svr->reject_excess_clients = reject_excess_clients; +} + +EAPI const char * +ecore_con_server_ip_get(Ecore_Con_Server *svr) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_ip_get"); + return NULL; + } + + return svr->ip; +} + +EAPI double +ecore_con_server_uptime_get(Ecore_Con_Server *svr) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_uptime_get"); + return -1; + } + + return ecore_time_get() - svr->start_time; +} + +EAPI void +ecore_con_server_flush(Ecore_Con_Server *svr) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_flush"); + return; + } + + _ecore_con_server_flush(svr); +} + +/** + * @} + */ + +/** + * @addtogroup Ecore_Con_Client_Group Ecore Connection Client Functions + * + * Functions that operate on Ecore connection client objects. + * + * @{ + */ + +/** + * @example ecore_con_client_example.c + * Shows how to write a simple client that connects to the example server. + */ + +EAPI int +ecore_con_client_send(Ecore_Con_Client *cl, + const void *data, + int size) +{ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_send"); + return 0; + } + + EINA_SAFETY_ON_TRUE_RETURN_VAL(cl->delete_me, 0); + + EINA_SAFETY_ON_NULL_RETURN_VAL(data, 0); + + EINA_SAFETY_ON_TRUE_RETURN_VAL(size < 1, 0); + + if (cl->fd_handler) + ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ | ECORE_FD_WRITE); + + if (cl->host_server && ((cl->host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_UDP)) + sendto(cl->host_server->fd, data, size, 0, (struct sockaddr *)cl->client_addr, + cl->client_addr_len); + else if (!cl->buf) + { + cl->buf = eina_binbuf_new(); + EINA_SAFETY_ON_NULL_RETURN_VAL(cl->buf, 0); +#ifdef TCP_CORK + if ((cl->fd >= 0) && ((cl->host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_CORK)) + { + int state = 1; + if (setsockopt(cl->fd, IPPROTO_TCP, TCP_CORK, (char *)&state, sizeof(int)) < 0) + /* realistically this isn't anything serious so we can just log and continue */ + ERR("corking failed! %s", strerror(errno)); + } +#endif + } + eina_binbuf_append_length(cl->buf, data, size); + + return size; +} + +EAPI Ecore_Con_Server * +ecore_con_client_server_get(Ecore_Con_Client *cl) +{ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, + "ecore_con_client_server_get"); + return NULL; + } + + return cl->host_server; +} + +EAPI Eina_Bool +ecore_con_client_connected_get(Ecore_Con_Client *cl) +{ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, + "ecore_con_client_connected_get"); + return EINA_FALSE; + } + + return !cl->delete_me; +} + +EAPI void +ecore_con_client_timeout_set(Ecore_Con_Client *cl, + double timeout) +{ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, + "ecore_con_client_timeout_set"); + return; + } + + cl->disconnect_time = timeout; + + _ecore_con_cl_timer_update(cl); +} + +EAPI double +ecore_con_client_timeout_get(Ecore_Con_Client *cl) +{ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_timeout_get"); + return 0; + } + + return cl->disconnect_time; +} + +EAPI void * +ecore_con_client_del(Ecore_Con_Client *cl) +{ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_del"); + return NULL; + } + + _ecore_con_client_kill(cl); + return cl->data; +} + +EAPI void +ecore_con_client_data_set(Ecore_Con_Client *cl, + const void *data) +{ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_data_set"); + return; + } + + cl->data = (void *)data; +} + +EAPI void * +ecore_con_client_data_get(Ecore_Con_Client *cl) +{ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_data_get"); + return NULL; + } + + return cl->data; +} + +EAPI const char * +ecore_con_client_ip_get(Ecore_Con_Client *cl) +{ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_ip_get"); + return NULL; + } + if (!cl->ip) + cl->ip = _ecore_con_pretty_ip(cl->client_addr); + + return cl->ip; +} + +EAPI int +ecore_con_client_port_get(Ecore_Con_Client *cl) +{ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_port_get"); + return -1; + } + if (cl->client_addr->sa_family == AF_INET) + return ((struct sockaddr_in*)cl->client_addr)->sin_port; +#ifdef HAVE_IPV6 + return ((struct sockaddr_in6*)cl->client_addr)->sin6_port; +#else + return -1; +#endif +} + +EAPI double +ecore_con_client_uptime_get(Ecore_Con_Client *cl) +{ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_uptime_get"); + return -1; + } + + return ecore_time_get() - cl->start_time; +} + +EAPI void +ecore_con_client_flush(Ecore_Con_Client *cl) +{ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_flush"); + return; + } + + _ecore_con_client_flush(cl); +} + +EAPI int +ecore_con_server_fd_get(Ecore_Con_Server *svr) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, __func__); + return -1; + } + if (svr->created) return -1; + return ecore_main_fd_handler_fd_get(svr->fd_handler); +} + +EAPI int +ecore_con_client_fd_get(Ecore_Con_Client *cl) +{ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, __func__); + return -1; + } + return ecore_main_fd_handler_fd_get(cl->fd_handler); +} + +/** + * @} + */ + +void +ecore_con_event_proxy_bind(Ecore_Con_Server *svr) +{ + Ecore_Con_Event_Proxy_Bind *e; + int ev = ECORE_CON_EVENT_PROXY_BIND; + + e = ecore_con_event_proxy_bind_alloc(); + EINA_SAFETY_ON_NULL_RETURN(e); + + svr->event_count = eina_list_append(svr->event_count, e); + _ecore_con_server_timer_update(svr); + e->server = svr; + e->ip = svr->proxyip; + e->port = svr->proxyport; + ecore_event_add(ev, e, + _ecore_con_event_server_add_free, NULL); + _ecore_con_event_count++; +} + +void +ecore_con_event_server_add(Ecore_Con_Server *svr) +{ + /* we got our server! */ + Ecore_Con_Event_Server_Add *e; + int ev = ECORE_CON_EVENT_SERVER_ADD; + + e = ecore_con_event_server_add_alloc(); + EINA_SAFETY_ON_NULL_RETURN(e); + + svr->connecting = EINA_FALSE; + svr->start_time = ecore_time_get(); + svr->event_count = eina_list_append(svr->event_count, e); + _ecore_con_server_timer_update(svr); + e->server = svr; + if (svr->upgrade) ev = ECORE_CON_EVENT_SERVER_UPGRADE; + ecore_event_add(ev, e, + _ecore_con_event_server_add_free, NULL); + _ecore_con_event_count++; +} + +void +ecore_con_event_server_del(Ecore_Con_Server *svr) +{ + Ecore_Con_Event_Server_Del *e; + + svr->delete_me = EINA_TRUE; + INF("svr %p is dead", svr); + e = ecore_con_event_server_del_alloc(); + EINA_SAFETY_ON_NULL_RETURN(e); + + svr->event_count = eina_list_append(svr->event_count, e); + _ecore_con_server_timer_update(svr); + e->server = svr; + if (svr->ecs) + { + svr->ecs_state = svr->ecs->lookup ? ECORE_CON_PROXY_STATE_RESOLVED : ECORE_CON_PROXY_STATE_DONE; + eina_stringshare_replace(&svr->proxyip, NULL); + svr->proxyport = 0; + } + ecore_event_add(ECORE_CON_EVENT_SERVER_DEL, e, + _ecore_con_event_server_del_free, NULL); + _ecore_con_event_count++; +} + +void +ecore_con_event_server_write(Ecore_Con_Server *svr, int num) +{ + Ecore_Con_Event_Server_Write *e; + + e = ecore_con_event_server_write_alloc(); + EINA_SAFETY_ON_NULL_RETURN(e); + + INF("Wrote %d bytes", num); + svr->event_count = eina_list_append(svr->event_count, e); + e->server = svr; + e->size = num; + ecore_event_add(ECORE_CON_EVENT_SERVER_WRITE, e, + (Ecore_End_Cb)_ecore_con_event_server_write_free, NULL); + _ecore_con_event_count++; +} + +void +ecore_con_event_server_data(Ecore_Con_Server *svr, unsigned char *buf, int num, Eina_Bool duplicate) +{ + Ecore_Con_Event_Server_Data *e; + + e = ecore_con_event_server_data_alloc(); + EINA_SAFETY_ON_NULL_RETURN(e); + + svr->event_count = eina_list_append(svr->event_count, e); + _ecore_con_server_timer_update(svr); + e->server = svr; + if (duplicate) + { + e->data = malloc(num); + if (!e->data) + { + ERR("server data allocation failure !"); + _ecore_con_event_server_data_free(NULL, e); + return; + } + memcpy(e->data, buf, num); + } + else + e->data = buf; + e->size = num; + ecore_event_add(ECORE_CON_EVENT_SERVER_DATA, e, + _ecore_con_event_server_data_free, NULL); + _ecore_con_event_count++; +} + +void +ecore_con_event_client_add(Ecore_Con_Client *cl) +{ + Ecore_Con_Event_Client_Add *e; + int ev = ECORE_CON_EVENT_CLIENT_ADD; + + e = ecore_con_event_client_add_alloc(); + EINA_SAFETY_ON_NULL_RETURN(e); + + cl->event_count = eina_list_append(cl->event_count, e); + cl->host_server->event_count = eina_list_append(cl->host_server->event_count, e); + _ecore_con_cl_timer_update(cl); + e->client = cl; + if (cl->upgrade) ev = ECORE_CON_EVENT_CLIENT_UPGRADE; + ecore_event_add(ev, e, + (Ecore_End_Cb)_ecore_con_event_client_add_free, cl->host_server); + _ecore_con_event_count++; +} + +void +ecore_con_event_client_del(Ecore_Con_Client *cl) +{ + Ecore_Con_Event_Client_Del *e; + + if (!cl) return; + cl->delete_me = EINA_TRUE; + INF("cl %p is dead", cl); + e = ecore_con_event_client_del_alloc(); + EINA_SAFETY_ON_NULL_RETURN(e); + cl->event_count = eina_list_append(cl->event_count, e); + + cl->host_server->event_count = eina_list_append(cl->host_server->event_count, e); + _ecore_con_cl_timer_update(cl); + e->client = cl; + ecore_event_add(ECORE_CON_EVENT_CLIENT_DEL, e, + (Ecore_End_Cb)_ecore_con_event_client_del_free, cl->host_server); + _ecore_con_event_count++; +} + +void +ecore_con_event_client_write(Ecore_Con_Client *cl, int num) +{ + Ecore_Con_Event_Client_Write *e; + + e = ecore_con_event_client_write_alloc(); + EINA_SAFETY_ON_NULL_RETURN(e); + + cl->event_count = eina_list_append(cl->event_count, e); + cl->host_server->event_count = eina_list_append(cl->host_server->event_count, e); + e->client = cl; + e->size = num; + ecore_event_add(ECORE_CON_EVENT_CLIENT_WRITE, e, + (Ecore_End_Cb)_ecore_con_event_client_write_free, cl->host_server); + _ecore_con_event_count++; +} + +void +ecore_con_event_client_data(Ecore_Con_Client *cl, unsigned char *buf, int num, Eina_Bool duplicate) +{ + Ecore_Con_Event_Client_Data *e; + + e = ecore_con_event_client_data_alloc(); + EINA_SAFETY_ON_NULL_RETURN(e); + + cl->event_count = eina_list_append(cl->event_count, e); + cl->host_server->event_count = eina_list_append(cl->host_server->event_count, e); + _ecore_con_cl_timer_update(cl); + e->client = cl; + if (duplicate) + { + e->data = malloc(num); + if (!e->data) + { + ERR("client data allocation failure !"); + _ecore_con_event_client_data_free(cl->host_server, e); + return; + } + memcpy(e->data, buf, num); + } + else + e->data = buf; + e->size = num; + ecore_event_add(ECORE_CON_EVENT_CLIENT_DATA, e, + (Ecore_End_Cb)_ecore_con_event_client_data_free, cl->host_server); + _ecore_con_event_count++; +} + + +void +ecore_con_server_infos_del(Ecore_Con_Server *svr, void *info) +{ + svr->infos = eina_list_remove(svr->infos, info); +} + +void +_ecore_con_event_server_error(Ecore_Con_Server *svr, char *error, Eina_Bool duplicate) +{ + Ecore_Con_Event_Server_Error *e; + + e = ecore_con_event_server_error_alloc(); + EINA_SAFETY_ON_NULL_RETURN(e); + + e->server = svr; + e->error = duplicate ? strdup(error) : error; + ERR("%s", error); + svr->event_count = eina_list_append(svr->event_count, e); + ecore_event_add(ECORE_CON_EVENT_SERVER_ERROR, e, (Ecore_End_Cb)_ecore_con_event_server_error_free, NULL); + _ecore_con_event_count++; +} + +void +ecore_con_event_client_error(Ecore_Con_Client *cl, const char *error) +{ + Ecore_Con_Event_Client_Error *e; + + e = ecore_con_event_client_error_alloc(); + EINA_SAFETY_ON_NULL_RETURN(e); + + e->client = cl; + e->error = strdup(error); + ERR("%s", error); + cl->event_count = eina_list_append(cl->event_count, e); + cl->host_server->event_count = eina_list_append(cl->host_server->event_count, e); + ecore_event_add(ECORE_CON_EVENT_CLIENT_ERROR, e, (Ecore_End_Cb)_ecore_con_event_client_error_free, cl->host_server); + _ecore_con_event_count++; +} + +static void +_ecore_con_server_free(Ecore_Con_Server *svr) +{ + Ecore_Con_Client *cl; + double t_start, t; + + if (svr->event_count) return; + + while (svr->infos) + { + ecore_con_info_data_clear(svr->infos->data); + svr->infos = eina_list_remove_list(svr->infos, svr->infos); + } + + t_start = ecore_time_get(); + while (svr->buf && (!svr->delete_me)) + { + _ecore_con_server_flush(svr); + t = ecore_time_get(); + if ((t - t_start) > 0.5) + { + WRN("ECORE_CON: EEK - stuck in _ecore_con_server_free() trying\n" + " to flush data out from the server, and have been for\n" + " %1.1f seconds. This is taking too long. Aborting flush.", + (t - t_start)); + break; + } + } + +#ifdef _WIN32 + ecore_con_local_win32_server_del(svr); +#endif + if (svr->event_count) return; + ECORE_MAGIC_SET(svr, ECORE_MAGIC_NONE); + + if (svr->buf) + eina_binbuf_free(svr->buf); + + EINA_LIST_FREE(svr->clients, cl) + { + Ecore_Con_Event_Server_Add *ev; + + /* some pointer hacks here to prevent double frees if people are being stupid */ + EINA_LIST_FREE(cl->event_count, ev) + ev->server = NULL; + cl->delete_me = EINA_TRUE; + INF("cl %p is dead", cl); + _ecore_con_client_free(cl); + } + if ((svr->created) && (svr->path) && (svr->ppid == getpid())) + unlink(svr->path); + + ecore_con_ssl_server_shutdown(svr); + free(svr->name); + + free(svr->path); + + eina_stringshare_del(svr->ip); + eina_stringshare_del(svr->verify_name); + + if (svr->ecs_buf) eina_binbuf_free(svr->ecs_buf); + if (svr->ecs_recvbuf) eina_binbuf_free(svr->ecs_recvbuf); + + if (svr->fd_handler) + ecore_main_fd_handler_del(svr->fd_handler); + + if (svr->fd > 0) + close(svr->fd); + + if (svr->until_deletion) + ecore_timer_del(svr->until_deletion); + + servers = eina_list_remove(servers, svr); + svr->data = NULL; + free(svr); +} + +static void +_ecore_con_client_free(Ecore_Con_Client *cl) +{ + double t_start, t; + + if (cl->event_count) return; + + t_start = ecore_time_get(); + while ((cl->buf) && (!cl->delete_me)) + { + _ecore_con_client_flush(cl); + t = ecore_time_get(); + if ((t - t_start) > 0.5) + { + WRN("EEK - stuck in _ecore_con_client_free() trying\n" + " to flush data out from the client, and have been for\n" + " %1.1f seconds. This is taking too long. Aborting flush.", + (t - t_start)); + break; + } + } + cl->host_server->clients = eina_list_remove(cl->host_server->clients, cl); + +#ifdef _WIN32 + ecore_con_local_win32_client_del(cl); +#endif + + if (cl->event_count) return; + ECORE_MAGIC_SET(cl, ECORE_MAGIC_NONE); + + if (cl->buf) eina_binbuf_free(cl->buf); + + if (cl->host_server->type & ECORE_CON_SSL) + ecore_con_ssl_client_shutdown(cl); + + if (cl->fd_handler) + ecore_main_fd_handler_del(cl->fd_handler); + + if (cl->fd > 0) + close(cl->fd); + + free(cl->client_addr); + cl->client_addr = NULL; + + if (cl->until_deletion) + ecore_timer_del(cl->until_deletion); + + eina_stringshare_del(cl->ip); + cl->data = NULL; + free(cl); + return; +} + +static Eina_Bool +_ecore_con_server_timer(Ecore_Con_Server *svr) +{ + ecore_con_server_del(svr); + + svr->until_deletion = NULL; + return ECORE_CALLBACK_CANCEL; +} + +static void +_ecore_con_server_timer_update(Ecore_Con_Server *svr) +{ + if (svr->disconnect_time) + { + if (svr->disconnect_time > 0) + { + if (svr->until_deletion) + ecore_timer_interval_set(svr->until_deletion, svr->disconnect_time); + else + svr->until_deletion = ecore_timer_add(svr->disconnect_time, (Ecore_Task_Cb)_ecore_con_server_timer, svr); + } + else if (svr->until_deletion) + { + ecore_timer_del(svr->until_deletion); + svr->until_deletion = NULL; + } + } + else + { + if (svr->until_deletion) + { + ecore_timer_del(svr->until_deletion); + svr->until_deletion = NULL; + } + } +} + +static Eina_Bool +_ecore_con_client_timer(Ecore_Con_Client *cl) +{ + ecore_con_client_del(cl); + + cl->until_deletion = NULL; + return ECORE_CALLBACK_CANCEL; +} + +static void +_ecore_con_cl_timer_update(Ecore_Con_Client *cl) +{ + if (cl->disconnect_time) + { + if (cl->disconnect_time > 0) + { + if (cl->until_deletion) + ecore_timer_interval_set(cl->until_deletion, cl->disconnect_time); + else + cl->until_deletion = ecore_timer_add(cl->disconnect_time, (Ecore_Task_Cb)_ecore_con_client_timer, cl); + } + else if (cl->until_deletion) + { + ecore_timer_del(cl->until_deletion); + cl->until_deletion = NULL; + } + } + else + { + if (cl->host_server->client_disconnect_time > 0) + { + if (cl->until_deletion) + ecore_timer_interval_set(cl->until_deletion, cl->host_server->client_disconnect_time); + else + cl->until_deletion = ecore_timer_add(cl->host_server->client_disconnect_time, (Ecore_Task_Cb)_ecore_con_client_timer, cl); + } + else if (cl->until_deletion) + { + ecore_timer_del(cl->until_deletion); + cl->until_deletion = NULL; + } + } +} + +static void +_ecore_con_cb_tcp_listen(void *data, + Ecore_Con_Info *net_info) +{ + Ecore_Con_Server *svr; + struct linger lin; + const char *memerr = NULL; + + svr = data; + + errno = 0; + if (!net_info) /* error message has already been handled */ + { + svr->delete_me = EINA_TRUE; + goto error; + } + + svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype, + net_info->info.ai_protocol); + if (svr->fd < 0) goto error; + if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error; + if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error; + + lin.l_onoff = 1; + lin.l_linger = 0; + if (setsockopt(svr->fd, SOL_SOCKET, SO_LINGER, (const void *)&lin, + sizeof(struct linger)) < 0) + goto error; + + if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_NODELAY) + { +#ifdef HAVE_NETINET_TCP_H + int flag = 1; + + if (setsockopt(svr->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, + sizeof(int)) < 0) +#endif + { + goto error; + } + } + + if (bind(svr->fd, net_info->info.ai_addr, net_info->info.ai_addrlen) < 0) + goto error; + + if (listen(svr->fd, 4096) < 0) goto error; + + svr->fd_handler = ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ, + _ecore_con_svr_tcp_handler, svr, NULL, NULL); + if (!svr->fd_handler) + { + memerr = "Memory allocation failure"; + goto error; + } + + return; + +error: + if (errno || memerr) ecore_con_event_server_error(svr, memerr ?: strerror(errno)); + ecore_con_ssl_server_shutdown(svr); + _ecore_con_server_kill(svr); +} + +static void +_ecore_con_cb_udp_listen(void *data, + Ecore_Con_Info *net_info) +{ + Ecore_Con_Server *svr; + Ecore_Con_Type type; + struct ip_mreq mreq; +#ifdef HAVE_IPV6 + struct ipv6_mreq mreq6; +#endif + const int on = 1; + const char *memerr = NULL; + + svr = data; + type = svr->type; + type &= ECORE_CON_TYPE; + + errno = 0; + if (!net_info) /* error message has already been handled */ + { + svr->delete_me = EINA_TRUE; + goto error; + } + + svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype, + net_info->info.ai_protocol); + if (svr->fd < 0) goto error; + + if (type == ECORE_CON_REMOTE_MCAST) + { + if (net_info->info.ai_family == AF_INET) + { + if (!inet_pton(net_info->info.ai_family, net_info->ip, + &mreq.imr_multiaddr)) + goto error; + + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + if (setsockopt(svr->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (const void *)&mreq, sizeof(mreq)) != 0) + goto error; + } +#ifdef HAVE_IPV6 + else if (net_info->info.ai_family == AF_INET6) + { + if (!inet_pton(net_info->info.ai_family, net_info->ip, + &mreq6.ipv6mr_multiaddr)) + goto error; + mreq6.ipv6mr_interface = htonl(INADDR_ANY); + if (setsockopt(svr->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (const void *)&mreq6, sizeof(mreq6)) != 0) + goto error; + } +#endif + } + + if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof(on)) != 0) + goto error; + if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error; + if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error; + + if (bind(svr->fd, net_info->info.ai_addr, net_info->info.ai_addrlen) < 0) + goto error; + + svr->fd_handler = + ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ, + _ecore_con_svr_udp_handler, svr, NULL, NULL); + if (!svr->fd_handler) + { + memerr = "Memory allocation failure"; + goto error; + } + + svr->ip = eina_stringshare_add(net_info->ip); + + return; + +error: + if (errno || memerr) ecore_con_event_server_error(svr, memerr ?: strerror(errno)); + ecore_con_ssl_server_shutdown(svr); + _ecore_con_server_kill(svr); +} + +static void +_ecore_con_cb_tcp_connect(void *data, + Ecore_Con_Info *net_info) +{ + Ecore_Con_Server *svr; + int res; + int curstate = 0; + const char *memerr = NULL; + + svr = data; + + errno = 0; + if (!net_info) /* error message has already been handled */ + { + svr->delete_me = EINA_TRUE; + goto error; + } + + svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype, + net_info->info.ai_protocol); + if (svr->fd < 0) goto error; + + if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error; + if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error; + + if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&curstate, sizeof(curstate)) < 0) + goto error; + + if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_NODELAY) + { +#ifdef HAVE_NETINET_TCP_H + int flag = 1; + + if (setsockopt(svr->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int)) < 0) +#endif + { + goto error; + } + } + + res = connect(svr->fd, net_info->info.ai_addr, net_info->info.ai_addrlen); +#ifdef _WIN32 + if (res == SOCKET_ERROR) + { + if (WSAGetLastError() != WSAEINPROGRESS) + { + char *err; + err = evil_format_message(WSAGetLastError()); + _ecore_con_event_server_error(svr, err, EINA_FALSE); + ecore_con_ssl_server_shutdown(svr); + _ecore_con_server_kill(svr); + return; + } + +#else + if (res < 0) + { + if (errno != EINPROGRESS) goto error; +#endif + svr->connecting = EINA_TRUE; + svr->fd_handler = + ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ | ECORE_FD_WRITE, + _ecore_con_cl_handler, svr, NULL, NULL); + } + else + svr->fd_handler = ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ, + _ecore_con_cl_handler, svr, NULL, NULL); + + if (svr->type & ECORE_CON_SSL) + { + svr->handshaking = EINA_TRUE; + svr->ssl_state = ECORE_CON_SSL_STATE_INIT; + DBG("%s ssl handshake", svr->ecs_state ? "Queuing" : "Beginning"); + if ((!svr->ecs_state) && ecore_con_ssl_server_init(svr)) + goto error; + } + + if (!svr->fd_handler) + { + memerr = "Memory allocation failure"; + goto error; + } + + if ((!svr->ecs) || (svr->ecs->lookup)) + svr->ip = eina_stringshare_add(net_info->ip); + + return; + +error: + if (errno || memerr) ecore_con_event_server_error(svr, memerr ?: strerror(errno)); + ecore_con_ssl_server_shutdown(svr); + _ecore_con_server_kill(svr); +} + +static void +_ecore_con_cb_udp_connect(void *data, + Ecore_Con_Info *net_info) +{ + Ecore_Con_Server *svr; + int curstate = 0; + int broadcast = 1; + const char *memerr = NULL; + svr = data; + + errno = 0; + if (!net_info) /* error message has already been handled */ + { + svr->delete_me = EINA_TRUE; + goto error; + } + + svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype, + net_info->info.ai_protocol); + if (svr->fd < 0) goto error; + if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error; + if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error; + if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_BROADCAST) + { + if (setsockopt(svr->fd, SOL_SOCKET, SO_BROADCAST, + (const void *)&broadcast, + sizeof(broadcast)) < 0) + { + goto error; + } + } + if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, + (const void *)&curstate, sizeof(curstate)) < 0) + goto error; + + if (connect(svr->fd, net_info->info.ai_addr, net_info->info.ai_addrlen) < 0) + goto error; + + svr->fd_handler = ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ | ECORE_FD_WRITE, + _ecore_con_cl_udp_handler, svr, NULL, NULL); + + if (!svr->fd_handler) + { + memerr = "Memory allocation failure"; + goto error; + } + + if ((!svr->ecs) || (svr->ecs->lookup)) + svr->ip = eina_stringshare_add(net_info->ip); + + return; + +error: + if (errno || memerr) ecore_con_event_server_error(svr, memerr ?: strerror(errno)); + ecore_con_ssl_server_shutdown(svr); + _ecore_con_server_kill(svr); +} + +static Ecore_Con_State +svr_try_connect_plain(Ecore_Con_Server *svr) +{ + int res; + int so_err = 0; + socklen_t size = sizeof(int); + + res = getsockopt(svr->fd, SOL_SOCKET, SO_ERROR, (void *)&so_err, &size); +#ifdef _WIN32 + if (res == SOCKET_ERROR) + so_err = WSAGetLastError(); + + if ((so_err == WSAEINPROGRESS) && !svr->delete_me) + return ECORE_CON_INPROGRESS; + +#else + if (res < 0) + so_err = errno; + + if ((so_err == EINPROGRESS) && !svr->delete_me) + return ECORE_CON_INPROGRESS; + +#endif + + if (so_err) + { + /* we lost our server! */ + ecore_con_event_server_error(svr, strerror(so_err)); + ERR("Connection lost: %s", strerror(so_err)); + _ecore_con_server_kill(svr); + return ECORE_CON_DISCONNECTED; + } + + if ((!svr->delete_me) && (!svr->handshaking) && svr->connecting) + { + if (svr->ecs) + { + if (ecore_con_socks_svr_init(svr)) + return ECORE_CON_INPROGRESS; + } + else + ecore_con_event_server_add(svr); + } + + if (svr->fd_handler && (!svr->buf)) + ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ); + + if (!svr->delete_me) + return ECORE_CON_CONNECTED; + else + return ECORE_CON_DISCONNECTED; +} + +static const char * +_ecore_con_pretty_ip(struct sockaddr *client_addr) +{ +#ifndef HAVE_IPV6 + char ipbuf[INET_ADDRSTRLEN + 1]; +#else + char ipbuf[INET6_ADDRSTRLEN + 1]; +#endif + int family = client_addr->sa_family; + void *src; + + switch(family) + { + case AF_INET: + src = &(((struct sockaddr_in *)client_addr)->sin_addr); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + src = &(((struct sockaddr_in6 *)client_addr)->sin6_addr); + + if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src)) + { + family = AF_INET; + src = (char*)src + 12; + } + break; +#endif + default: + return eina_stringshare_add("0.0.0.0"); + } + + if (!inet_ntop(family, src, ipbuf, sizeof(ipbuf))) + return eina_stringshare_add("0.0.0.0"); + + ipbuf[sizeof(ipbuf) - 1] = 0; + return eina_stringshare_add(ipbuf); +} + +static Eina_Bool +_ecore_con_svr_tcp_handler(void *data, + Ecore_Fd_Handler *fd_handler __UNUSED__) +{ + Ecore_Con_Server *svr; + Ecore_Con_Client *cl = NULL; + unsigned char client_addr[256]; + unsigned int client_addr_len; + const char *clerr = NULL; + + svr = data; + if (svr->delete_me) + return ECORE_CALLBACK_RENEW; + + if ((svr->client_limit >= 0) && (!svr->reject_excess_clients) && + (svr->client_count >= (unsigned int)svr->client_limit)) + return ECORE_CALLBACK_RENEW; + + /* a new client */ + + cl = calloc(1, sizeof(Ecore_Con_Client)); + if (!cl) + { + ecore_con_event_server_error(svr, "Memory allocation failure when attempting to add a new client"); + return ECORE_CALLBACK_RENEW; + } + cl->host_server = svr; + + client_addr_len = sizeof(client_addr); + memset(&client_addr, 0, client_addr_len); + cl->fd = accept(svr->fd, (struct sockaddr *)&client_addr, (socklen_t *)&client_addr_len); + if (cl->fd < 0) goto error; + if ((svr->client_limit >= 0) && (svr->reject_excess_clients) && + (svr->client_count >= (unsigned int)svr->client_limit)) + { + clerr = "Maximum client limit reached"; + goto error; + } + + if (fcntl(cl->fd, F_SETFL, O_NONBLOCK) < 0) goto error; + if (fcntl(cl->fd, F_SETFD, FD_CLOEXEC) < 0) goto error; + cl->fd_handler = ecore_main_fd_handler_add(cl->fd, ECORE_FD_READ, + _ecore_con_svr_cl_handler, cl, NULL, NULL); + if (!cl->fd_handler) goto error; + ECORE_MAGIC_SET(cl, ECORE_MAGIC_CON_CLIENT); + + if ((!svr->upgrade) && (svr->type & ECORE_CON_SSL)) + { + cl->handshaking = EINA_TRUE; + cl->ssl_state = ECORE_CON_SSL_STATE_INIT; + if (ecore_con_ssl_client_init(cl)) + goto error; + } + + cl->client_addr = malloc(client_addr_len); + if (!cl->client_addr) + { + clerr = "Memory allocation failure when attempting to add a new client"; + goto error; + } + cl->client_addr_len = client_addr_len; + memcpy(cl->client_addr, &client_addr, client_addr_len); + + svr->clients = eina_list_append(svr->clients, cl); + svr->client_count++; + + if ((!cl->delete_me) && (!cl->handshaking)) + ecore_con_event_client_add(cl); + + return ECORE_CALLBACK_RENEW; + +error: + if (cl->fd_handler) ecore_main_fd_handler_del(cl->fd_handler); + if (cl->fd >= 0) close(cl->fd); + free(cl); + if (clerr || errno) ecore_con_event_server_error(svr, clerr ?: strerror(errno)); + return ECORE_CALLBACK_RENEW; +} + +static void +_ecore_con_cl_read(Ecore_Con_Server *svr) +{ + int num = 0; + Eina_Bool lost_server = EINA_TRUE; + unsigned char buf[READBUFSIZ]; + + DBG("svr=%p", svr); + + /* only possible with non-ssl connections */ + if (svr->connecting && (svr_try_connect_plain(svr) != ECORE_CON_CONNECTED)) + return; + + if (svr->handshaking && (!svr->ecs_state)) + { + DBG("Continuing ssl handshake"); + if (!ecore_con_ssl_server_init(svr)) + lost_server = EINA_FALSE; + _ecore_con_server_timer_update(svr); + } + + if (svr->ecs_state || !(svr->type & ECORE_CON_SSL)) + { + errno = 0; + num = read(svr->fd, buf, sizeof(buf)); + /* 0 is not a valid return value for a tcp socket */ + if ((num > 0) || ((num < 0) && (errno == EAGAIN))) + lost_server = EINA_FALSE; + else if (num < 0) + ecore_con_event_server_error(svr, strerror(errno)); + } + else + { + num = ecore_con_ssl_server_read(svr, buf, sizeof(buf)); + /* this is not an actual 0 return, 0 here just means non-fatal error such as EAGAIN */ + if (num >= 0) + lost_server = EINA_FALSE; + } + + if ((!svr->delete_me) && (num > 0)) + { + if (svr->ecs_state) + ecore_con_socks_read(svr, buf, num); + else + ecore_con_event_server_data(svr, buf, num, EINA_TRUE); + } + + if (lost_server) + _ecore_con_server_kill(svr); +} + +static Eina_Bool +_ecore_con_cl_handler(void *data, + Ecore_Fd_Handler *fd_handler) +{ + Ecore_Con_Server *svr; + Eina_Bool want_read, want_write; + + svr = data; + if (svr->delete_me) + return ECORE_CALLBACK_RENEW; + + if (svr->delete_me) + return ECORE_CALLBACK_RENEW; + + want_read = ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ); + want_write = ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE); + + if ((!svr->ecs_state) && svr->handshaking && (want_read || want_write)) + { + DBG("Continuing ssl handshake: preparing to %s...", want_read ? "read" : "write"); +#ifdef ISCOMFITOR + if (want_read) + { + char buf[READBUFSIZ]; + ssize_t len; + len = recv(svr->fd, buf, sizeof(buf), MSG_DONTWAIT | MSG_PEEK); + DBG("%zu bytes in buffer", len); + } +#endif + if (ecore_con_ssl_server_init(svr)) + { + ERR("ssl handshaking failed!"); + svr->handshaking = EINA_FALSE; + } + else if (!svr->ssl_state) + ecore_con_event_server_add(svr); + return ECORE_CALLBACK_RENEW; + } + if (svr->ecs && svr->ecs_state && (svr->ecs_state < ECORE_CON_PROXY_STATE_READ) && (!svr->ecs_buf)) + { + if (svr->ecs_state < ECORE_CON_PROXY_STATE_INIT) + { + INF("PROXY STATE++"); + svr->ecs_state++; + } + if (ecore_con_socks_svr_init(svr)) return ECORE_CALLBACK_RENEW; + } + if (want_read) + _ecore_con_cl_read(svr); + else if (want_write) /* only possible with non-ssl connections */ + { + if (svr->connecting && (!svr_try_connect_plain(svr)) && (!svr->ecs_state)) + return ECORE_CALLBACK_RENEW; + + _ecore_con_server_flush(svr); + } + + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +_ecore_con_cl_udp_handler(void *data, + Ecore_Fd_Handler *fd_handler) +{ + unsigned char buf[READBUFSIZ]; + int num; + Ecore_Con_Server *svr; + Eina_Bool want_read, want_write; + + want_read = ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ); + want_write = ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE); + + svr = data; + if (svr->delete_me || svr->delete_me || ((!want_read) && (!want_write))) + return ECORE_CALLBACK_RENEW; + + if (want_write) + { + _ecore_con_server_flush(svr); + return ECORE_CALLBACK_RENEW; + } + + num = read(svr->fd, buf, READBUFSIZ); + + if ((!svr->delete_me) && (num > 0)) + ecore_con_event_server_data(svr, buf, num, EINA_TRUE); + + if (num < 0 && (errno != EAGAIN) && (errno != EINTR)) + { + ecore_con_event_server_error(svr, strerror(errno)); + _ecore_con_server_kill(svr); + } + + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +_ecore_con_svr_udp_handler(void *data, + Ecore_Fd_Handler *fd_handler) +{ + unsigned char buf[READBUFSIZ]; + unsigned char client_addr[256]; + socklen_t client_addr_len = sizeof(client_addr); + int num; + Ecore_Con_Server *svr; + Ecore_Con_Client *cl = NULL; + + svr = data; + + if (svr->delete_me) + return ECORE_CALLBACK_RENEW; + + if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE)) + { + _ecore_con_client_flush(cl); + return ECORE_CALLBACK_RENEW; + } + + if (!ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) + return ECORE_CALLBACK_RENEW; + +#ifdef _WIN32 + num = fcntl(svr->fd, F_SETFL, O_NONBLOCK); + if (num >= 0) + num = recvfrom(svr->fd, (char *)buf, sizeof(buf), 0, + (struct sockaddr *)&client_addr, + &client_addr_len); + +#else + num = recvfrom(svr->fd, buf, sizeof(buf), MSG_DONTWAIT, + (struct sockaddr *)&client_addr, + &client_addr_len); +#endif + + if (num < 0 && (errno != EAGAIN) && (errno != EINTR)) + { + ecore_con_event_server_error(svr, strerror(errno)); + if (!svr->delete_me) + ecore_con_event_client_del(NULL); + _ecore_con_server_kill(svr); + return ECORE_CALLBACK_CANCEL; + } + + +/* Create a new client for use in the client data event */ + cl = calloc(1, sizeof(Ecore_Con_Client)); + EINA_SAFETY_ON_NULL_RETURN_VAL(cl, ECORE_CALLBACK_RENEW); + + cl->host_server = svr; + cl->client_addr = malloc(client_addr_len); + if (!cl->client_addr) + { + free(cl); + return ECORE_CALLBACK_RENEW; + } + cl->client_addr_len = client_addr_len; + + memcpy(cl->client_addr, &client_addr, client_addr_len); + ECORE_MAGIC_SET(cl, ECORE_MAGIC_CON_CLIENT); + svr->clients = eina_list_append(svr->clients, cl); + svr->client_count++; + + ecore_con_event_client_add(cl); + ecore_con_event_client_data(cl, buf, num, EINA_TRUE); + + return ECORE_CALLBACK_RENEW; +} + +static void +_ecore_con_svr_cl_read(Ecore_Con_Client *cl) +{ + int num = 0; + Eina_Bool lost_client = EINA_TRUE; + unsigned char buf[READBUFSIZ]; + + DBG("cl=%p", cl); + + if (cl->handshaking) + { + /* add an extra handshake attempt just before read, even though + * read also attempts to handshake, to try to finish sooner + */ + if (ecore_con_ssl_client_init(cl)) + lost_client = EINA_FALSE; + + _ecore_con_cl_timer_update(cl); + } + + if (!(cl->host_server->type & ECORE_CON_SSL) || (!cl->upgrade)) + { + num = read(cl->fd, buf, sizeof(buf)); + /* 0 is not a valid return value for a tcp socket */ + if ((num > 0) || ((num < 0) && ((errno == EAGAIN) || (errno == EINTR)))) + lost_client = EINA_FALSE; + else if (num < 0) + ecore_con_event_client_error(cl, strerror(errno)); + } + else + { + num = ecore_con_ssl_client_read(cl, buf, sizeof(buf)); + /* this is not an actual 0 return, 0 here just means non-fatal error such as EAGAIN */ + if (num >= 0) + lost_client = EINA_FALSE; + } + + if ((!cl->delete_me) && (num > 0)) + ecore_con_event_client_data(cl, buf, num, EINA_TRUE); + + if (lost_client) _ecore_con_client_kill(cl); +} + +static Eina_Bool +_ecore_con_svr_cl_handler(void *data, + Ecore_Fd_Handler *fd_handler) +{ + Ecore_Con_Client *cl; + + cl = data; + if (cl->delete_me) + return ECORE_CALLBACK_RENEW; + + if (cl->handshaking && ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ | ECORE_FD_WRITE)) + { + if (ecore_con_ssl_client_init(cl)) + { + ERR("ssl handshaking failed!"); + _ecore_con_client_kill(cl); + return ECORE_CALLBACK_RENEW; + } + else if (!cl->ssl_state) + ecore_con_event_client_add(cl); + } + else if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) + _ecore_con_svr_cl_read(cl); + + else if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE)) + _ecore_con_client_flush(cl); + + return ECORE_CALLBACK_RENEW; +} + +static void +_ecore_con_server_flush(Ecore_Con_Server *svr) +{ + int count, num; + size_t buf_len, buf_offset; + const void *buf; + + DBG("(svr=%p,buf=%p)", svr, svr->buf); +#ifdef _WIN32 + if (ecore_con_local_win32_server_flush(svr)) + return; +#endif + + if ((!svr->buf) && (!svr->ecs_buf) && svr->fd_handler) + { + ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ); + return; + } + + buf = svr->buf ? eina_binbuf_string_get(svr->buf) : eina_binbuf_string_get(svr->ecs_buf); + buf_len = svr->buf ? eina_binbuf_length_get(svr->buf) : eina_binbuf_length_get(svr->ecs_buf); + buf_offset = svr->buf ? svr->write_buf_offset : svr->ecs_buf_offset; + num = buf_len - buf_offset; + + /* check whether we need to write anything at all. + * we must not write zero bytes with SSL_write() since it + * causes undefined behaviour + */ + /* we thank Tommy[D] for needing to check negative buffer sizes + * here because his system is amazing. + */ + if (num <= 0) return; + + if ((!svr->ecs_state) && svr->handshaking) + { + DBG("Continuing ssl handshake"); + if (ecore_con_ssl_server_init(svr)) + _ecore_con_server_kill(svr); + _ecore_con_server_timer_update(svr); + return; + } + + if (svr->ecs_state || (!(svr->type & ECORE_CON_SSL))) + count = write(svr->fd, buf + buf_offset, num); + else + count = ecore_con_ssl_server_write(svr, buf + buf_offset, num); + + if (count < 0) + { + if ((errno != EAGAIN) && (errno != EINTR)) + { + ecore_con_event_server_error(svr, strerror(errno)); + _ecore_con_server_kill(svr); + } + return; + } + + if (count && (!svr->ecs_state)) ecore_con_event_server_write(svr, count); + if (svr->ecs_buf) + buf_offset = svr->ecs_buf_offset += count; + else + buf_offset = svr->write_buf_offset += count; + if (buf_offset >= buf_len) + { + if (svr->ecs_buf) + { + svr->ecs_buf_offset = 0; + eina_binbuf_free(svr->ecs_buf); + svr->ecs_buf = NULL; + INF("PROXY STATE++"); + svr->ecs_state++; + } + else + { + svr->write_buf_offset = 0; + eina_binbuf_free(svr->buf); + svr->buf = NULL; +#ifdef TCP_CORK + if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_CORK) + { + int state = 0; + if (setsockopt(svr->fd, IPPROTO_TCP, TCP_CORK, (char *)&state, sizeof(int)) < 0) + /* realistically this isn't anything serious so we can just log and continue */ + ERR("uncorking failed! %s", strerror(errno)); + } +#endif + } + if (svr->fd_handler) + ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ); + } + else if ((count < num) && svr->fd_handler) + ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE); +} + +static void +_ecore_con_client_flush(Ecore_Con_Client *cl) +{ + int num = 0, count = 0; + +#ifdef _WIN32 + if (ecore_con_local_win32_client_flush(cl)) + return; +#endif + + if (!cl->buf && cl->fd_handler) + { + ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ); + return; + } + + if (cl->handshaking) + { + if (ecore_con_ssl_client_init(cl)) + count = -1; + + _ecore_con_cl_timer_update(cl); + } + + if (!count) + { + if (!cl->buf) return; + num = eina_binbuf_length_get(cl->buf) - cl->buf_offset; + if (num <= 0) return; + if (!(cl->host_server->type & ECORE_CON_SSL) || (!cl->upgrade)) + count = write(cl->fd, eina_binbuf_string_get(cl->buf) + cl->buf_offset, num); + else + count = ecore_con_ssl_client_write(cl, eina_binbuf_string_get(cl->buf) + cl->buf_offset, num); + } + + if (count < 0) + { + if ((errno != EAGAIN) && (errno != EINTR) && (!cl->delete_me)) + { + ecore_con_event_client_error(cl, strerror(errno)); + _ecore_con_client_kill(cl); + } + + return; + } + + if (count) ecore_con_event_client_write(cl, count); + cl->buf_offset += count, num -= count; + if (cl->buf_offset >= eina_binbuf_length_get(cl->buf)) + { + cl->buf_offset = 0; + eina_binbuf_free(cl->buf); + cl->buf = NULL; +#ifdef TCP_CORK + if ((cl->host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_CORK) + { + int state = 0; + if (setsockopt(cl->fd, IPPROTO_TCP, TCP_CORK, (char *)&state, sizeof(int)) < 0) + /* realistically this isn't anything serious so we can just log and continue */ + ERR("uncorking failed! %s", strerror(errno)); + } +#endif + if (cl->fd_handler) + ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ); + } + else if (cl->fd_handler && (num >= 0)) + ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_WRITE); +} + +static void +_ecore_con_event_client_add_free(Ecore_Con_Server *svr, + void *ev) +{ + Ecore_Con_Event_Client_Add *e; + + e = ev; + if (e->client) + { + e->client->event_count = eina_list_remove(e->client->event_count, e); + if (e->client->host_server) + { + e->client->host_server->event_count = eina_list_remove(e->client->host_server->event_count, ev); + if ((!svr->event_count) && (svr->delete_me)) + _ecore_con_server_free(svr); + } + if ((!e->client->event_count) && (e->client->delete_me)) + ecore_con_client_del(e->client); + } + + ecore_con_event_client_add_free(e); + _ecore_con_event_count--; + if ((!_ecore_con_event_count) && (!_ecore_con_init_count)) + ecore_con_mempool_shutdown(); +} + +static void +_ecore_con_event_client_del_free(Ecore_Con_Server *svr, + void *ev) +{ + Ecore_Con_Event_Client_Del *e; + + e = ev; + if (e->client) + { + e->client->event_count = eina_list_remove(e->client->event_count, e); + if (e->client->host_server) + { + e->client->host_server->event_count = eina_list_remove(e->client->host_server->event_count, ev); + if ((!svr->event_count) && (svr->delete_me)) + _ecore_con_server_free(svr); + } + if (!e->client->event_count) + _ecore_con_client_free(e->client); + } + ecore_con_event_client_del_free(e); + _ecore_con_event_count--; + if ((!_ecore_con_event_count) && (!_ecore_con_init_count)) + ecore_con_mempool_shutdown(); +} + +static void +_ecore_con_event_client_write_free(Ecore_Con_Server *svr, + Ecore_Con_Event_Client_Write *e) +{ + if (e->client) + { + e->client->event_count = eina_list_remove(e->client->event_count, e); + if (e->client->host_server) + { + e->client->host_server->event_count = eina_list_remove(e->client->host_server->event_count, e); + if ((!svr->event_count) && (svr->delete_me)) + _ecore_con_server_free(svr); + } + if (((!e->client->event_count) && (e->client->delete_me)) || + ((e->client->host_server && + ((e->client->host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_UDP || + (e->client->host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_MCAST)))) + ecore_con_client_del(e->client); + } + ecore_con_event_client_write_free(e); + _ecore_con_event_count--; + if ((!_ecore_con_event_count) && (!_ecore_con_init_count)) + ecore_con_mempool_shutdown(); +} + +static void +_ecore_con_event_client_data_free(Ecore_Con_Server *svr, + void *ev) +{ + Ecore_Con_Event_Client_Data *e; + + e = ev; + if (e->client) + { + e->client->event_count = eina_list_remove(e->client->event_count, e); + if (e->client->host_server) + { + e->client->host_server->event_count = eina_list_remove(e->client->host_server->event_count, ev); + } + if ((!svr->event_count) && (svr->delete_me)) + _ecore_con_server_free(svr); + if (((!e->client->event_count) && (e->client->delete_me)) || + ((e->client->host_server && + ((e->client->host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_UDP || + (e->client->host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_MCAST)))) + ecore_con_client_del(e->client); + } + free(e->data); + ecore_con_event_client_data_free(e); + _ecore_con_event_count--; + if ((!_ecore_con_event_count) && (!_ecore_con_init_count)) + ecore_con_mempool_shutdown(); +} + +static void +_ecore_con_event_server_add_free(void *data __UNUSED__, + void *ev) +{ + Ecore_Con_Event_Server_Add *e; + + e = ev; + if (e->server) + { + e->server->event_count = eina_list_remove(e->server->event_count, ev); + if ((!e->server->event_count) && (e->server->delete_me)) + _ecore_con_server_free(e->server); + } + ecore_con_event_server_add_free(e); + _ecore_con_event_count--; + if ((!_ecore_con_event_count) && (!_ecore_con_init_count)) + ecore_con_mempool_shutdown(); +} + +static void +_ecore_con_event_server_del_free(void *data __UNUSED__, + void *ev) +{ + Ecore_Con_Event_Server_Del *e; + + e = ev; + if (e->server) + { + e->server->event_count = eina_list_remove(e->server->event_count, ev); + if (!e->server->event_count) + _ecore_con_server_free(e->server); + } + ecore_con_event_server_del_free(e); + _ecore_con_event_count--; + if ((!_ecore_con_event_count) && (!_ecore_con_init_count)) + ecore_con_mempool_shutdown(); +} + +static void +_ecore_con_event_server_write_free(void *data __UNUSED__, + Ecore_Con_Event_Server_Write *e) +{ + if (e->server) + { + e->server->event_count = eina_list_remove(e->server->event_count, e); + if ((!e->server->event_count) && (e->server->delete_me)) + _ecore_con_server_free(e->server); + } + + ecore_con_event_server_write_free(e); + _ecore_con_event_count--; + if ((!_ecore_con_event_count) && (!_ecore_con_init_count)) + ecore_con_mempool_shutdown(); +} + +static void +_ecore_con_event_server_data_free(void *data __UNUSED__, + void *ev) +{ + Ecore_Con_Event_Server_Data *e; + + e = ev; + if (e->server) + { + e->server->event_count = eina_list_remove(e->server->event_count, ev); + if ((!e->server->event_count) && (e->server->delete_me)) + _ecore_con_server_free(e->server); + } + + free(e->data); + ecore_con_event_server_data_free(e); + _ecore_con_event_count--; + if ((!_ecore_con_event_count) && (!_ecore_con_init_count)) + ecore_con_mempool_shutdown(); +} + + +static void +_ecore_con_event_server_error_free(void *data __UNUSED__, Ecore_Con_Event_Server_Error *e) +{ + if (e->server) + { + e->server->event_count = eina_list_remove(e->server->event_count, e); + if ((!e->server->event_count) && (e->server->delete_me)) + _ecore_con_server_free(e->server); + } + free(e->error); + ecore_con_event_server_error_free(e); + _ecore_con_event_count--; + if ((!_ecore_con_event_count) && (!_ecore_con_init_count)) + ecore_con_mempool_shutdown(); +} + +static void +_ecore_con_event_client_error_free(Ecore_Con_Server *svr, Ecore_Con_Event_Client_Error *e) +{ + if (e->client) + { + e->client->host_server->event_count = eina_list_remove(e->client->host_server->event_count, e); + if ((!e->client->event_count) && (e->client->delete_me)) + _ecore_con_client_free(e->client); + if (e->client->host_server) + { + e->client->host_server->event_count = eina_list_remove(e->client->host_server->event_count, e); + if ((!svr->event_count) && (svr->delete_me)) + _ecore_con_server_free(svr); + } + } + free(e->error); + ecore_con_event_client_error_free(e); + _ecore_con_event_count--; + if ((!_ecore_con_event_count) && (!_ecore_con_init_count)) + ecore_con_mempool_shutdown(); +} + +static void +_ecore_con_lookup_done(void *data, + Ecore_Con_Info *infos) +{ + Ecore_Con_Server *svr; + Ecore_Con_Lookup *lk; + + svr = data; + lk = svr->data; + + if (infos) + lk->done_cb(infos->info.ai_canonname, infos->ip, + infos->info.ai_addr, infos->info.ai_addrlen, + (void *)lk->data); + else + lk->done_cb(NULL, NULL, NULL, 0, (void *)lk->data); + + free(svr->name); + free(lk); + free(svr); +} + diff --git a/src/lib/ecore_con/ecore_con_alloc.c b/src/lib/ecore_con/ecore_con_alloc.c new file mode 100644 index 0000000..324d47d --- /dev/null +++ b/src/lib/ecore_con/ecore_con_alloc.c @@ -0,0 +1,101 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "Ecore.h" +#include "ecore_private.h" +#include "Ecore_Con.h" +#include "ecore_con_private.h" + +typedef struct _Ecore_Con_Mempool Ecore_Con_Mempool; +struct _Ecore_Con_Mempool +{ + const char *name; + Eina_Mempool *mp; + size_t size; +}; + +#define GENERIC_ALLOC_FREE(TYPE, Type) \ + Ecore_Con_Mempool Type##_mp = { #TYPE, NULL, sizeof (TYPE) }; \ + \ + TYPE * \ + Type##_alloc(void) \ + { \ + return eina_mempool_malloc(Type##_mp.mp, sizeof (TYPE)); \ + } \ + \ + void \ + Type##_free(TYPE *e) \ + { \ + eina_mempool_free(Type##_mp.mp, e); \ + } + +GENERIC_ALLOC_FREE(Ecore_Con_Event_Client_Add, ecore_con_event_client_add); +GENERIC_ALLOC_FREE(Ecore_Con_Event_Client_Del, ecore_con_event_client_del); +GENERIC_ALLOC_FREE(Ecore_Con_Event_Client_Write, ecore_con_event_client_write); +GENERIC_ALLOC_FREE(Ecore_Con_Event_Client_Data, ecore_con_event_client_data); +GENERIC_ALLOC_FREE(Ecore_Con_Event_Server_Error, ecore_con_event_server_error); +GENERIC_ALLOC_FREE(Ecore_Con_Event_Client_Error, ecore_con_event_client_error); +GENERIC_ALLOC_FREE(Ecore_Con_Event_Server_Add, ecore_con_event_server_add); +GENERIC_ALLOC_FREE(Ecore_Con_Event_Server_Del, ecore_con_event_server_del); +GENERIC_ALLOC_FREE(Ecore_Con_Event_Server_Write, ecore_con_event_server_write); +GENERIC_ALLOC_FREE(Ecore_Con_Event_Server_Data, ecore_con_event_server_data); +GENERIC_ALLOC_FREE(Ecore_Con_Event_Proxy_Bind, ecore_con_event_proxy_bind); + +static Ecore_Con_Mempool *mempool_array[] = { + &ecore_con_event_client_add_mp, + &ecore_con_event_client_del_mp, + &ecore_con_event_client_write_mp, + &ecore_con_event_client_data_mp, + &ecore_con_event_server_error_mp, + &ecore_con_event_client_error_mp, + &ecore_con_event_server_add_mp, + &ecore_con_event_server_del_mp, + &ecore_con_event_server_write_mp, + &ecore_con_event_server_data_mp, + &ecore_con_event_proxy_bind_mp +}; + +void +ecore_con_mempool_init(void) +{ + const char *choice; + unsigned int i; + + choice = getenv("EINA_MEMPOOL"); + if (!choice || !choice[0]) + choice = "chained_mempool"; + + for (i = 0; i < sizeof (mempool_array) / sizeof (mempool_array[0]); ++i) + { + retry: + mempool_array[i]->mp = eina_mempool_add(choice, mempool_array[i]->name, NULL, mempool_array[i]->size, 16); + if (!mempool_array[i]->mp) + { + if (!(!strcmp(choice, "pass_through"))) + { + ERR("Falling back to pass through ! Previously tried '%s' mempool.", choice); + choice = "pass_through"; + goto retry; + } + else + { + ERR("Impossible to allocate mempool '%s' !", choice); + return ; + } + } + } +} + +void +ecore_con_mempool_shutdown(void) +{ + unsigned int i; + + for (i = 0; i < sizeof (mempool_array) / sizeof (mempool_array[0]); ++i) + { + eina_mempool_del(mempool_array[i]->mp); + mempool_array[i]->mp = NULL; + } +} + diff --git a/src/lib/ecore_con/ecore_con_ares.c b/src/lib/ecore_con/ecore_con_ares.c new file mode 100644 index 0000000..5dfe70b --- /dev/null +++ b/src/lib/ecore_con/ecore_con_ares.c @@ -0,0 +1,628 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +/* + * This version of ecore_con_info use c-ares to provide asynchronous dns lookup. + * + * Note: It doesn't fork nor does it use libc getaddrinfo. + * http://c-ares.haxx.se/docs.html + */ + +#include +#include + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#ifdef HAVE_ARPA_INET_H +# include +#endif + +#include + +#include "Ecore.h" +#include "Ecore_Con.h" +#include "ecore_con_private.h" + +typedef struct _Ecore_Con_FD Ecore_Con_FD; +typedef struct _Ecore_Con_CAres Ecore_Con_CAres; + +struct _Ecore_Con_FD +{ + Ecore_Fd_Handler *handler; + Ecore_Timer *timer; + int fd; +}; + +struct _Ecore_Con_CAres +{ + Ecore_Con_Server *svr; + Ecore_Con_Info_Cb done_cb; + void *data; + struct addrinfo hints; + Ecore_Con_Info *result; + + union { + struct in_addr v4; +#ifdef HAVE_IPV6 + struct in6_addr v6; +#endif + } addr; + + Eina_Bool byaddr : 1; + Eina_Bool isv6 : 1; +}; + +static ares_channel info_channel; +static int info_init = 0; +static Eina_List *info_fds = NULL; + +static void _ecore_con_info_ares_nameinfo(Ecore_Con_CAres *arg, + int status, + int timeouts, + char *node, + char *service); +static void _ecore_con_info_ares_host_cb(Ecore_Con_CAres *arg, + int status, + int timeouts, + struct hostent *hostent); +static Eina_Bool _ecore_con_info_cares_fd_cb(Ecore_Con_FD *ecf, + Ecore_Fd_Handler *fd_handler); +static Eina_Bool _ecore_con_info_cares_timeout_cb(void *data); + +static void +_ecore_con_info_cares_state_cb(void *data, + ares_socket_t fd, + int readable, + int writable); +static int +_ecore_con_info_fds_search(const Ecore_Con_FD *fd1, + const Ecore_Con_FD *fd2); + +int +ecore_con_info_init(void) +{ + struct ares_options opts; + + if (!info_init) + { + if (ares_library_init(ARES_LIB_INIT_ALL)) + return 0; + + opts.lookups = "fb"; /* hosts file then dns */ + opts.sock_state_cb = _ecore_con_info_cares_state_cb; + + if (ares_init_options(&info_channel, &opts, + ARES_OPT_LOOKUPS | ARES_OPT_SOCK_STATE_CB) != ARES_SUCCESS) + { + ares_library_cleanup(); + return 0; + } + } + + info_init++; + return info_init; +} + +int +ecore_con_info_shutdown(void) +{ + info_init--; + if (info_init == 0) + { + /* Cancel all ongoing request */ + ares_cancel(info_channel); + ares_destroy(info_channel); + + /* Shutdown ares */ + ares_library_cleanup(); + } + + return info_init; +} + +int +ecore_con_info_tcp_connect(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data) +{ + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); +#ifdef HAVE_IPV6 + hints.ai_family = AF_INET6; +#else + hints.ai_family = AF_INET; +#endif + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + hints.ai_addr = NULL; + + return ecore_con_info_get(svr, done_cb, data, &hints); +} + +int +ecore_con_info_tcp_listen(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data) +{ + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); +#ifdef HAVE_IPV6 + hints.ai_family = AF_INET6; +#else + hints.ai_family = AF_INET; +#endif + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + hints.ai_addr = NULL; + + return ecore_con_info_get(svr, done_cb, data, &hints); +} + +int +ecore_con_info_udp_connect(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data) +{ + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); +#ifdef HAVE_IPV6 + hints.ai_family = AF_INET6; +#else + hints.ai_family = AF_INET; +#endif + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + hints.ai_addr = NULL; + + return ecore_con_info_get(svr, done_cb, data, &hints); +} + +int +ecore_con_info_udp_listen(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data) +{ + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); +#ifdef HAVE_IPV6 + hints.ai_family = AF_INET6; +#else + hints.ai_family = AF_INET; +#endif + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_PASSIVE; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + hints.ai_addr = NULL; + + return ecore_con_info_get(svr, done_cb, data, &hints); +} + +int +ecore_con_info_mcast_listen(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data) +{ + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); +#ifdef HAVE_IPV6 + hints.ai_family = AF_INET6; +#else + hints.ai_family = AF_INET; +#endif + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = 0; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + hints.ai_addr = NULL; + + return ecore_con_info_get(svr, done_cb, data, &hints); +} + +static Eina_Bool +_ecore_con_info_ares_getnameinfo(Ecore_Con_CAres *arg, + int addrtype, + const char *name, + struct sockaddr *addr, + int addrlen) +{ + int length = 0; + + if (name) + length = strlen(name) + 1; + else + length = 1; + + arg->result = malloc(sizeof(Ecore_Con_Info) + length); + if (!arg->result) + return EINA_FALSE; + + /* FIXME: What to do when hint is not set ? */ + arg->result->info.ai_flags = arg->hints.ai_flags; + arg->result->info.ai_socktype = arg->hints.ai_socktype; + arg->result->info.ai_protocol = arg->hints.ai_protocol; + + arg->result->info.ai_family = addrtype; + arg->result->info.ai_addrlen = addrlen; + arg->result->info.ai_addr = addr; + arg->result->info.ai_canonname = (char *)(arg->result + 1); + + if (!name) + *arg->result->info.ai_canonname = '\0'; + else + strcpy(arg->result->info.ai_canonname, name); + + arg->result->info.ai_next = NULL; + + ares_getnameinfo( + info_channel, addr, addrlen, + ARES_NI_NUMERICSERV | ARES_NI_NUMERICHOST | + ARES_NI_LOOKUPSERVICE | ARES_NI_LOOKUPHOST, + (ares_nameinfo_callback)_ecore_con_info_ares_nameinfo, arg); + + return EINA_TRUE; +} + +EAPI int +ecore_con_info_get(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data, + struct addrinfo *hints) +{ + Ecore_Con_CAres *cares; +#ifdef HAVE_IPV6 + int ai_family = AF_INET6; +#else + int ai_family = AF_INET; +#endif + + cares = calloc(1, sizeof(Ecore_Con_CAres)); + if (!cares) + return 0; + + cares->svr = svr; + cares->done_cb = done_cb; + cares->data = data; + + if (hints) + { + ai_family = hints->ai_family; + memcpy(&cares->hints, hints, sizeof(struct addrinfo)); + } + + if (inet_pton(AF_INET, svr->ecs ? svr->ecs->ip : svr->name, &cares->addr.v4) == 1) + { + cares->byaddr = EINA_TRUE; + cares->isv6 = EINA_FALSE; + ares_gethostbyaddr(info_channel, &cares->addr.v4, + sizeof(cares->addr.v4), + AF_INET, + (ares_host_callback)_ecore_con_info_ares_host_cb, + cares); + } +#ifdef HAVE_IPV6 + else if (inet_pton(AF_INET6, svr->ecs ? svr->ecs->ip : svr->name, &cares->addr.v6) == 1) + { + cares->byaddr = EINA_TRUE; + cares->isv6 = EINA_TRUE; + ares_gethostbyaddr(info_channel, &cares->addr.v6, + sizeof(cares->addr.v6), + AF_INET6, + (ares_host_callback)_ecore_con_info_ares_host_cb, + cares); + } +#endif + else + { + cares->byaddr = EINA_FALSE; + ares_gethostbyname(info_channel, svr->ecs ? svr->ecs->ip : svr->name, ai_family, + (ares_host_callback)_ecore_con_info_ares_host_cb, + cares); + } + + svr->infos = eina_list_append(svr->infos, cares); + return 1; +} + +void +ecore_con_info_data_clear(void *info) +{ + Ecore_Con_CAres *cares = info; + if (cares) cares->data = NULL; +} + +static Eina_Bool +_ecore_con_info_cares_timeout_cb(void *data __UNUSED__) +{ + ares_process_fd(info_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +_ecore_con_info_cares_fd_cb(Ecore_Con_FD *ecf, + Ecore_Fd_Handler *fd_handler) +{ + ares_socket_t read_fd, write_fd; + + read_fd = write_fd = ARES_SOCKET_BAD; + + if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) + read_fd = ecf->fd; + if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE)) + write_fd = ecf->fd; + + ares_process_fd(info_channel, read_fd, write_fd); + + return ECORE_CALLBACK_RENEW; +} + +static int +_ecore_con_info_fds_search(const Ecore_Con_FD *fd1, + const Ecore_Con_FD *fd2) +{ + return fd1->fd - fd2->fd; +} + +static void +_ecore_con_info_cares_state_cb(void *data __UNUSED__, + ares_socket_t fd, + int readable, + int writable) +{ + int flags = 0; + Ecore_Con_FD *search = NULL, *ecf = NULL; + + search = eina_list_search_unsorted(info_fds, + (Eina_Compare_Cb)_ecore_con_info_fds_search, &ecf); + + if (!(readable | writable)) + { + ares_process_fd(info_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); + if (search) + { + info_fds = eina_list_remove(info_fds, search); + ecore_timer_del(search->timer); + ecore_main_fd_handler_del(search->handler); + free(search); + } + return; + } + + if (!search) + { + search = malloc(sizeof(Ecore_Con_FD)); + EINA_SAFETY_ON_NULL_RETURN(search); + + search->fd = fd; + search->handler = ecore_main_fd_handler_add(fd, ECORE_FD_WRITE | ECORE_FD_READ, + (Ecore_Fd_Cb)_ecore_con_info_cares_fd_cb, search, NULL, NULL); + /* c-ares default timeout is 5 seconds */ + search->timer = ecore_timer_add(5, _ecore_con_info_cares_timeout_cb, NULL); + info_fds = eina_list_append(info_fds, search); + } + + if (readable) flags |= ECORE_FD_READ; + if (writable) flags |= ECORE_FD_WRITE; + ecore_main_fd_handler_active_set(search->handler, flags); +} + +static void +_ecore_con_info_ares_host_cb(Ecore_Con_CAres *arg, + int status, + int timeouts __UNUSED__, + struct hostent *hostent) +{ + struct sockaddr *addr; + int addrlen; + + /* Found something ? */ + switch (status) + { + case ARES_SUCCESS: + if (!hostent->h_addr_list[0]) + { + ERR("No IP found"); + goto on_error; + } + + switch (hostent->h_addrtype) + { + case AF_INET: + { + struct sockaddr_in *addri; + + addrlen = sizeof(struct sockaddr_in); + addri = malloc(addrlen); + + if (!addri) + goto on_mem_error; + + addri->sin_family = AF_INET; + addri->sin_port = htons(arg->svr->ecs ? arg->svr->ecs->port : arg->svr->port); + + memcpy(&addri->sin_addr.s_addr, + hostent->h_addr_list[0], sizeof(struct in_addr)); + + addr = (struct sockaddr *)addri; + break; + } +#ifdef HAVE_IPV6 + case AF_INET6: + { + struct sockaddr_in6 *addri6; + + addrlen = sizeof(struct sockaddr_in6); + addri6 = malloc(addrlen); + + if (!addri6) + goto on_mem_error; + + addri6->sin6_family = AF_INET6; + addri6->sin6_port = htons(arg->svr->ecs ? arg->svr->ecs->port : arg->svr->port); + addri6->sin6_flowinfo = 0; + addri6->sin6_scope_id = 0; + + memcpy(&addri6->sin6_addr.s6_addr, + hostent->h_addr_list[0], sizeof(struct in6_addr)); + + addr = (struct sockaddr *)addri6; + break; + } +#endif + default: + ERR("Unknown addrtype %i", hostent->h_addrtype); + goto on_error; + } + + if (!_ecore_con_info_ares_getnameinfo(arg, hostent->h_addrtype, + hostent->h_name, + addr, addrlen)) + goto on_error; + + break; + + case ARES_ENOTFOUND: /* address notfound */ + if (arg->byaddr) + { +#ifdef HAVE_IPV6 + /* This happen when host doesn't have a reverse. */ + if (arg->isv6) + { + struct sockaddr_in6 *addri6; + + addrlen = sizeof(struct sockaddr_in6); + addri6 = malloc(addrlen); + + if (!addri6) + goto on_mem_error; + + addri6->sin6_family = AF_INET6; + addri6->sin6_port = htons(arg->svr->ecs ? arg->svr->ecs->port : arg->svr->port); + addri6->sin6_flowinfo = 0; + addri6->sin6_scope_id = 0; + + memcpy(&addri6->sin6_addr.s6_addr, + &arg->addr.v6, sizeof(struct in6_addr)); + + addr = (struct sockaddr *)addri6; + } + else +#endif + { + struct sockaddr_in *addri; + + addrlen = sizeof(struct sockaddr_in); + addri = malloc(addrlen); + + if (!addri) + goto on_mem_error; + + addri->sin_family = AF_INET; + addri->sin_port = htons(arg->svr->ecs ? arg->svr->ecs->port : arg->svr->port); + + memcpy(&addri->sin_addr.s_addr, + &arg->addr.v4, sizeof(struct in_addr)); + + addr = (struct sockaddr *)addri; + } + + if (!_ecore_con_info_ares_getnameinfo(arg, +#ifdef HAVE_IPV6 + arg->isv6 ? AF_INET6 : +#endif + AF_INET, + NULL, addr, + addrlen)) + goto on_error; + + break; + } + + case ARES_ENOTIMP: /* unknown family */ + case ARES_EBADNAME: /* not a valid internet address */ + case ARES_ENOMEM: /* not enough memory */ + case ARES_EDESTRUCTION: /* request canceled, shuting down */ + case ARES_ENODATA: /* no data returned */ + case ARES_ECONNREFUSED: /* connection refused */ + case ARES_ETIMEOUT: /* connection timed out */ + ecore_con_event_server_error(arg->svr, ares_strerror(status)); + goto on_error; + + default: + ERR("Unknown status returned by c-ares: %i assuming error", status); + ecore_con_event_server_error(arg->svr, ares_strerror(status)); + goto on_error; + } + + return; + +on_mem_error: + ERR("Not enough memory"); + +on_error: + if (arg->data) + { + ecore_con_server_infos_del(arg->data, arg); + arg->done_cb(arg->data, NULL); + } + free(arg); +} + +static void +_ecore_con_info_ares_nameinfo(Ecore_Con_CAres *arg, + int status, + int timeouts __UNUSED__, + char *node, + char *service) +{ + switch (status) + { + case ARES_SUCCESS: + if (node) + strcpy(arg->result->ip, node); + else + *arg->result->ip = '\0'; + + if (service) + strcpy(arg->result->service, service); + else + *arg->result->service = '\0'; + + if (arg->data) arg->done_cb(arg->data, arg->result); + break; + + case ARES_ENOTIMP: + case ARES_ENOTFOUND: + case ARES_ENOMEM: + case ARES_EDESTRUCTION: + case ARES_EBADFLAGS: + ecore_con_event_server_error(arg->svr, ares_strerror(status)); + if (arg->data) arg->done_cb(arg->data, NULL); + break; + } + + free(arg->result->info.ai_addr); + free(arg->result); + if (arg->data) ecore_con_server_infos_del(arg->data, arg); + free(arg); +} + diff --git a/src/lib/ecore_con/ecore_con_dns.c b/src/lib/ecore_con/ecore_con_dns.c new file mode 100644 index 0000000..3671576 --- /dev/null +++ b/src/lib/ecore_con/ecore_con_dns.c @@ -0,0 +1,344 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +/* + * This version of ecore_con_info uses dns.c to provide asynchronous dns lookup. + * + * dns.c is written by William Ahern: + * http://25thandclement.com/~william/projects/dns.c.html + */ + +#include +#include + +#ifdef HAVE_ERRNO_H +# include /* for EAGAIN */ +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#ifdef HAVE_ARPA_INET_H +# include +#endif + +#ifdef HAVE_ERRNO_H +# include +#endif + +#include "dns.h" + +#include "Ecore.h" +#include "Ecore_Con.h" +#include "ecore_con_private.h" + +typedef struct dns_addrinfo dns_addrinfo; +typedef struct dns_resolv_conf dns_resolv_conf; +typedef struct dns_resolver dns_resolver; +typedef struct dns_hosts dns_hosts; + +typedef struct _Ecore_Con_DNS Ecore_Con_DNS; + +struct _Ecore_Con_DNS +{ + Ecore_Con_Server *svr; + Ecore_Con_Info_Cb done_cb; + void *data; + dns_addrinfo *ai; + dns_resolver *resolv; + struct addrinfo hints; + Ecore_Fd_Handler *fdh; + Ecore_Timer *timer; +}; + +static int _ecore_con_dns_init = 0; +static dns_resolv_conf *resconf = NULL; +static dns_hosts *hosts = NULL; + +static void +_ecore_con_dns_free(Ecore_Con_DNS *dns) +{ + if (dns->svr->infos) dns->svr->infos = eina_list_remove(dns->svr->infos, dns); + if (dns->timer) ecore_timer_del(dns->timer); + if (dns->fdh) ecore_main_fd_handler_del(dns->fdh); + dns_res_close(dns_res_mortal(dns->resolv)); + free(dns); +} + +static Eina_Bool +_dns_addrinfo_get(Ecore_Con_DNS *dns, const char *addr, int port) +{ + int error = 0; + char service[NI_MAXSERV]; + + snprintf(service, sizeof(service), "%d", port); + dns->ai = dns_ai_open(addr, service, DNS_T_A, (const struct addrinfo *)&dns->hints, dns->resolv, &error); + return error; +} + +static int +_ecore_con_dns_check(Ecore_Con_DNS *dns) +{ + struct addrinfo *ent = NULL; + int error = 0; + + error = dns_ai_nextent(&ent, dns->ai); + + switch (error) + { + case 0: + break; + case EAGAIN: + return 1; + default: + ERR("resolve failed: %s", dns_strerror(error)); + goto error; + } + + { + Ecore_Con_Info result = {0, .ip = {0}, .service = {0}}; +#if 0 + char pretty[512]; + dns_ai_print(pretty, sizeof(pretty), ent, dns->ai); + printf("%s\n", pretty); +#endif + result.size = 0; + dns_inet_ntop(dns_sa_family(ent->ai_addr), dns_sa_addr(dns_sa_family(ent->ai_addr), ent->ai_addr), result.ip, sizeof(result.ip)); + snprintf(result.service, sizeof(result.service), "%u", ntohs(*dns_sa_port(dns_sa_family(ent->ai_addr), ent->ai_addr))); + memcpy(&result.info, ent, sizeof(result.info)); + if (dns->fdh) ecore_main_fd_handler_del(dns->fdh); + dns->fdh = NULL; + dns->done_cb(dns->data, &result); + free(ent); + _ecore_con_dns_free(dns); + } + + return 0; +error: + dns->done_cb(dns->data, NULL); + _ecore_con_dns_free(dns); + return -1; +} + +static Eina_Bool +_dns_fd_cb(Ecore_Con_DNS *dns, Ecore_Fd_Handler *fdh __UNUSED__) +{ + if (_ecore_con_dns_check(dns) != 1) return ECORE_CALLBACK_RENEW; + if (ecore_main_fd_handler_fd_get(dns->fdh) != dns_ai_pollfd(dns->ai)) + { + ecore_main_fd_handler_del(dns->fdh); + dns->fdh = ecore_main_fd_handler_add(dns_ai_pollfd(dns->ai), dns_ai_events(dns->ai), (Ecore_Fd_Cb)_dns_fd_cb, dns, NULL, NULL); + } + else + ecore_main_fd_handler_active_set(dns->fdh, dns_ai_events(dns->ai)); + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +_dns_timer_cb(Ecore_Con_DNS *dns) +{ + dns->done_cb(dns->data, NULL); + _ecore_con_dns_free(dns); + dns->timer = NULL; + return EINA_FALSE; +} + +int +ecore_con_info_init(void) +{ + int err; + if (_ecore_con_dns_init) return ++_ecore_con_dns_init; + + resconf = dns_resconf_local(&err); + if (!resconf) + { + ERR("resconf_open: %s", dns_strerror(err)); + return 0; + } + hosts = dns_hosts_local(&err); + if (!hosts) + { + ERR("hosts_open: %s", dns_strerror(err)); + dns_resconf_close(resconf); + resconf = NULL; + return 0; + } + /* this is super slow don't do it */ + //resconf->options.recurse = 1; + return ++_ecore_con_dns_init; +} + +int +ecore_con_info_shutdown(void) +{ + if (!_ecore_con_dns_init) return 0; + if (--_ecore_con_dns_init) return _ecore_con_dns_init; + dns_resconf_close(resconf); + resconf = NULL; + dns_hosts_close(hosts); + hosts = NULL; + return 0; +} + +void +ecore_con_info_data_clear(void *info) +{ + Ecore_Con_DNS *dns = info; + if (dns) dns->data = NULL; +} + +int +ecore_con_info_tcp_connect(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data) +{ + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); +#ifdef HAVE_IPV6 + hints.ai_family = AF_INET6; +#else + hints.ai_family = AF_INET; +#endif + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = IPPROTO_TCP; + + return ecore_con_info_get(svr, done_cb, data, &hints); +} + +int +ecore_con_info_tcp_listen(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data) +{ + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); +#ifdef HAVE_IPV6 + hints.ai_family = AF_INET6; +#else + hints.ai_family = AF_INET; +#endif + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + hints.ai_protocol = IPPROTO_TCP; + + return ecore_con_info_get(svr, done_cb, data, &hints); +} + +int +ecore_con_info_udp_connect(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data) +{ + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); +#ifdef HAVE_IPV6 + hints.ai_family = AF_INET6; +#else + hints.ai_family = AF_INET; +#endif + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = IPPROTO_UDP; + + return ecore_con_info_get(svr, done_cb, data, &hints); +} + +int +ecore_con_info_udp_listen(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data) +{ + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); +#ifdef HAVE_IPV6 + hints.ai_family = AF_INET6; +#else + hints.ai_family = AF_INET; +#endif + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_PASSIVE; + hints.ai_protocol = IPPROTO_UDP; + + return ecore_con_info_get(svr, done_cb, data, &hints); +} + +int +ecore_con_info_mcast_listen(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data) +{ + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); +#ifdef HAVE_IPV6 + hints.ai_family = AF_INET6; +#else + hints.ai_family = AF_INET; +#endif + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + + return ecore_con_info_get(svr, done_cb, data, &hints); +} + +EAPI int +ecore_con_info_get(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data, + struct addrinfo *hints) +{ + Ecore_Con_DNS *dns; + int error = 0; + + dns = calloc(1, sizeof(Ecore_Con_DNS)); + if (!dns) return 0; + + dns->svr = svr; + dns->done_cb = done_cb; + dns->data = data; + + if (hints) + memcpy(&dns->hints, hints, sizeof(struct addrinfo)); + + if (!(dns->resolv = dns_res_open(resconf, hosts, dns_hints_mortal(dns_hints_local(resconf, &error)), NULL, dns_opts(), &error))) + { + ERR("res_open: %s", dns_strerror(error)); + goto reserr; + + } + + error = _dns_addrinfo_get(dns, svr->ecs ? svr->ecs->ip : svr->name, dns->svr->ecs ? dns->svr->ecs->port : dns->svr->port); + if (error && (error != EAGAIN)) + { + ERR("resolver: %s", dns_strerror(error)); + goto seterr; + } + + switch (_ecore_con_dns_check(dns)) + { + case 0: + break; + case 1: + dns->fdh = ecore_main_fd_handler_add(dns_ai_pollfd(dns->ai), dns_ai_events(dns->ai), (Ecore_Fd_Cb)_dns_fd_cb, dns, NULL, NULL); + svr->infos = eina_list_append(svr->infos, dns); + dns->timer = ecore_timer_add(5.0, (Ecore_Task_Cb)_dns_timer_cb, dns); + break; + default: + return 0; + } + + return 1; +seterr: + if (dns->resolv) dns_res_close(dns_res_mortal(dns->resolv)); +reserr: + free(dns); + return 0; +} + diff --git a/src/lib/ecore_con/ecore_con_info.c b/src/lib/ecore_con/ecore_con_info.c new file mode 100644 index 0000000..fdcf0b9 --- /dev/null +++ b/src/lib/ecore_con/ecore_con_info.c @@ -0,0 +1,449 @@ +/* + * getaddrinfo with callback + * + * man getaddrinfo + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_ALLOCA_H +# include +#elif defined __GNUC__ +# define alloca __builtin_alloca +#elif defined _AIX +# define alloca __alloca +#elif defined _MSC_VER +# include +# define alloca _alloca +#else +# include +# ifdef __cplusplus +extern "C" +# endif +void *alloca(size_t); +#endif + +#include +#include +#include +#include +#ifdef __OpenBSD__ +# include +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#ifdef HAVE_ARPA_INET_H +# include +#endif + +#ifdef HAVE_ARPA_NAMESER_H +# include +#endif + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif + +#ifdef HAVE_NETDB_H +# include +#endif + +#include + +#include "Ecore.h" +#include "ecore_private.h" +#include "ecore_con_private.h" + +typedef struct _CB_Data CB_Data; + +struct _CB_Data +{ + EINA_INLIST; + Ecore_Con_Info_Cb cb_done; + void *data; + Ecore_Fd_Handler *fdh; + pid_t pid; + Ecore_Event_Handler *handler; + int fd2; +}; + +static void _ecore_con_info_readdata(CB_Data *cbdata); +static void _ecore_con_info_slave_free(CB_Data *cbdata); +static Eina_Bool _ecore_con_info_data_handler(void *data, + Ecore_Fd_Handler *fd_handler); +static Eina_Bool _ecore_con_info_exit_handler(void *data, + int type __UNUSED__, + void *event); + +static int info_init = 0; +static CB_Data *info_slaves = NULL; + +int +ecore_con_info_init(void) +{ + info_init++; + return info_init; +} + +int +ecore_con_info_shutdown(void) +{ + info_init--; + if (info_init == 0) + while (info_slaves) _ecore_con_info_slave_free(info_slaves); + + return info_init; +} + +int +ecore_con_info_tcp_connect(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data) +{ + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + hints.ai_addr = NULL; + + return ecore_con_info_get(svr, done_cb, data, &hints); +} + +int +ecore_con_info_tcp_listen(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data) +{ + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + hints.ai_addr = NULL; + + return ecore_con_info_get(svr, done_cb, data, &hints); +} + +int +ecore_con_info_udp_connect(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data) +{ + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + hints.ai_addr = NULL; + + return ecore_con_info_get(svr, done_cb, data, &hints); +} + +int +ecore_con_info_udp_listen(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data) +{ + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_PASSIVE; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + hints.ai_addr = NULL; + + return ecore_con_info_get(svr, done_cb, data, &hints); +} + +int +ecore_con_info_mcast_listen(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data) +{ + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = 0; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + hints.ai_addr = NULL; + + return ecore_con_info_get(svr, done_cb, data, &hints); +} + +EAPI int +ecore_con_info_get(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data, + struct addrinfo *hints) +{ + CB_Data *cbdata; + int fd[2]; + + if (pipe(fd) < 0) + { + ecore_con_event_server_error(svr, strerror(errno)); + return 0; + } + + cbdata = calloc(1, sizeof(CB_Data)); + if (!cbdata) + { + close(fd[0]); + close(fd[1]); + return 0; + } + + cbdata->cb_done = done_cb; + cbdata->data = data; + cbdata->fd2 = fd[1]; + if (!(cbdata->fdh = ecore_main_fd_handler_add(fd[0], ECORE_FD_READ, + _ecore_con_info_data_handler, + cbdata, + NULL, NULL))) + { + ecore_con_event_server_error(svr, "Memory allocation failure"); + free(cbdata); + close(fd[0]); + close(fd[1]); + return 0; + } + + if ((cbdata->pid = fork()) == 0) + { + Ecore_Con_Info *container; + struct addrinfo *result = NULL; + char service[NI_MAXSERV] = {0}; + char hbuf[NI_MAXHOST] = {0}; + char sbuf[NI_MAXSERV] = {0}; + unsigned char *tosend = NULL; + int tosend_len; + int canonname_len = 0; + + eina_convert_itoa(svr->ecs ? svr->ecs->port : svr->port, service); + /* CHILD */ + if (!getaddrinfo(svr->ecs ? svr->ecs->ip : svr->name, service, hints, &result) && result) + { + if (result->ai_canonname) + canonname_len = strlen(result->ai_canonname) + 1; + + tosend_len = sizeof(Ecore_Con_Info) + result->ai_addrlen + + canonname_len; + + tosend = alloca(tosend_len); + memset(tosend, 0, tosend_len); + + container = (Ecore_Con_Info *)tosend; + container->size = tosend_len; + + memcpy(&container->info, + result, + sizeof(struct addrinfo)); + memcpy(tosend + sizeof(Ecore_Con_Info), + result->ai_addr, + result->ai_addrlen); + if (result->ai_canonname) /* FIXME: else... */ + memcpy(tosend + sizeof(Ecore_Con_Info) + result->ai_addrlen, + result->ai_canonname, + canonname_len); + + if (!getnameinfo(result->ai_addr, result->ai_addrlen, + hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), + NI_NUMERICHOST | NI_NUMERICSERV)) + { + memcpy(container->ip, hbuf, sizeof(container->ip)); + memcpy(container->service, sbuf, sizeof(container->service)); + } + + if (write(fd[1], tosend, tosend_len) < 0) perror("write"); + } + + if (result) + freeaddrinfo(result); + + if (write(fd[1], "", 1) < 0) perror("write"); + close(fd[1]); +#if defined(__USE_ISOC99) && !defined(__UCLIBC__) + _Exit(0); +#else + _exit(0); +#endif + } + + /* PARENT */ + cbdata->handler = + ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _ecore_con_info_exit_handler, + cbdata); + close(fd[1]); + if (!cbdata->handler) + { + ecore_main_fd_handler_del(cbdata->fdh); + free(cbdata); + close(fd[0]); + return 0; + } + + info_slaves = (CB_Data *)eina_inlist_append(EINA_INLIST_GET( + info_slaves), + EINA_INLIST_GET(cbdata)); + svr->infos = eina_list_append(svr->infos, cbdata); + return 1; +} + +void +ecore_con_info_data_clear(void *info) +{ + CB_Data *cbdata = info; + cbdata->data = NULL; +} + +static void +_ecore_con_info_readdata(CB_Data *cbdata) +{ + Ecore_Con_Info container; + Ecore_Con_Info *recv_info; + unsigned char *torecv; + int torecv_len; + + ssize_t size; + + size = read(ecore_main_fd_handler_fd_get(cbdata->fdh), &container, + sizeof(Ecore_Con_Info)); + if (size == sizeof(Ecore_Con_Info)) + { + torecv_len = container.size; + torecv = malloc(torecv_len); + + memcpy(torecv, &container, sizeof(Ecore_Con_Info)); + + size = read(ecore_main_fd_handler_fd_get(cbdata->fdh), + torecv + sizeof(Ecore_Con_Info), + torecv_len - sizeof(Ecore_Con_Info)); + if ((size > 0) && + ((size_t)size == torecv_len - sizeof(Ecore_Con_Info))) + { + recv_info = (Ecore_Con_Info *)torecv; + + recv_info->info.ai_addr = + (struct sockaddr *)(torecv + sizeof(Ecore_Con_Info)); + if ((size_t)torecv_len != + (sizeof(Ecore_Con_Info) + recv_info->info.ai_addrlen)) + recv_info->info.ai_canonname = (char *) + (torecv + sizeof(Ecore_Con_Info) + recv_info->info.ai_addrlen); + else + recv_info->info.ai_canonname = NULL; + + recv_info->info.ai_next = NULL; + + if (cbdata->data) + { + cbdata->cb_done(cbdata->data, recv_info); + ecore_con_server_infos_del(cbdata->data, cbdata); + } + + free(torecv); + } + else + { + if (cbdata->data) + { + cbdata->cb_done(cbdata->data, NULL); + ecore_con_server_infos_del(cbdata->data, cbdata); + } + } + } + else + { + if (cbdata->data) + { + ecore_con_event_server_error(cbdata->data, strerror(errno)); + cbdata->cb_done(cbdata->data, NULL); + ecore_con_server_infos_del(cbdata->data, cbdata); + } + } + + cbdata->cb_done = NULL; +} + +static void +_ecore_con_info_slave_free(CB_Data *cbdata) +{ + info_slaves = (CB_Data *)eina_inlist_remove(EINA_INLIST_GET(info_slaves), + EINA_INLIST_GET(cbdata)); + ecore_main_fd_handler_del(cbdata->fdh); + ecore_event_handler_del(cbdata->handler); + close(ecore_main_fd_handler_fd_get(cbdata->fdh)); + if (cbdata->data) ecore_con_server_infos_del(cbdata->data, cbdata); + free(cbdata); +} + +static Eina_Bool +_ecore_con_info_data_handler(void *data, + Ecore_Fd_Handler *fd_handler) +{ + CB_Data *cbdata; + + cbdata = data; + if (cbdata->cb_done) + { + if (ecore_main_fd_handler_active_get(fd_handler, + ECORE_FD_READ)) + _ecore_con_info_readdata(cbdata); + else + { + if (cbdata->data) + { + cbdata->cb_done(cbdata->data, NULL); + cbdata->cb_done = NULL; + ecore_con_server_infos_del(cbdata->data, cbdata); + } + } + } + + _ecore_con_info_slave_free(cbdata); + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool +_ecore_con_info_exit_handler(void *data, + int type __UNUSED__, + void *event) +{ + CB_Data *cbdata; + Ecore_Exe_Event_Del *ev; + + ev = event; + cbdata = data; + if (cbdata->pid != ev->pid) + return ECORE_CALLBACK_RENEW; + + return ECORE_CALLBACK_CANCEL; /* FIXME: Woot ??? */ + _ecore_con_info_slave_free(cbdata); + return ECORE_CALLBACK_CANCEL; +} + diff --git a/src/lib/ecore_con/ecore_con_local.c b/src/lib/ecore_con/ecore_con_local.c new file mode 100644 index 0000000..ac97fb1 --- /dev/null +++ b/src/lib/ecore_con/ecore_con_local.c @@ -0,0 +1,325 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_ERRNO_H +# include +#endif + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif + +#ifdef HAVE_SYS_UN_H +# include +#endif + +#ifdef HAVE_WS2TCPIP_H +# include +#endif + +#include +#include + +#include "Ecore_Con.h" +#include "ecore_con_private.h" + +#define LENGTH_OF_SOCKADDR_UN(s) (strlen((s)->sun_path) + \ + (size_t)(((struct sockaddr_un *)NULL)-> \ + sun_path)) +#define LENGTH_OF_ABSTRACT_SOCKADDR_UN(s, path) (strlen(path) + 1 + \ + (size_t)(((struct sockaddr_un \ + *)NULL)->sun_path)) + +static int _ecore_con_local_init_count = 0; + +int +ecore_con_local_init(void) +{ + if (++_ecore_con_local_init_count != 1) + return _ecore_con_local_init_count; + + return _ecore_con_local_init_count; +} + +int +ecore_con_local_shutdown(void) +{ + if (--_ecore_con_local_init_count != 0) + return _ecore_con_local_init_count; + + return _ecore_con_local_init_count; +} + +int +ecore_con_local_connect(Ecore_Con_Server *svr, + Eina_Bool (*cb_done)(void *data, Ecore_Fd_Handler *fd_handler), + void *data __UNUSED__) +{ +#ifndef HAVE_LOCAL_SOCKETS + return 0; +#else + char buf[4096]; + struct sockaddr_un socket_unix; + int curstate = 0; + const char *homedir; + int socket_unix_len; + + if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_USER) + { + homedir = getenv("HOME"); + if (!homedir) + homedir = getenv("TMP"); + + if (!homedir) + homedir = "/tmp"; + + snprintf(buf, sizeof(buf), "%s/.ecore/%s/%i", homedir, svr->name, + svr->port); + } + else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_SYSTEM) + { + if (svr->port < 0) + { + if (svr->name[0] == '/') + strncpy(buf, svr->name, sizeof(buf)); + else + snprintf(buf, sizeof(buf), "/tmp/.ecore_service|%s", svr->name); + } + else + { + if (svr->name[0] == + '/') + snprintf(buf, sizeof(buf), "%s|%i", svr->name, + svr->port); + else + snprintf(buf, sizeof(buf), "/tmp/.ecore_service|%s|%i", + svr->name, + svr->port); + } + } + else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT) + strncpy(buf, svr->name, + sizeof(buf)); + + svr->fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (svr->fd < 0) + return 0; + + if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) + return 0; + + if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) + return 0; + + if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&curstate, + sizeof(curstate)) < 0) + return 0; + + socket_unix.sun_family = AF_UNIX; + + if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT) + { +#ifdef HAVE_ABSTRACT_SOCKETS + /* copy name insto sun_path, prefixed by null to indicate abstract namespace */ + snprintf(socket_unix.sun_path, sizeof(socket_unix.sun_path), ".%s", + svr->name); + socket_unix.sun_path[0] = '\0'; + socket_unix_len = LENGTH_OF_ABSTRACT_SOCKADDR_UN(&socket_unix, + svr->name); +#else + WRN("Your system does not support abstract sockets!"); + return 0; +#endif + } + else + { + strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path)); + socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix); + } + + if (connect(svr->fd, (struct sockaddr *)&socket_unix, + socket_unix_len) < 0) + { + ERR("local connection failed: %s", strerror(errno)); + return 0; + } + + svr->path = strdup(buf); + if (!svr->path) + return 0; + + if (svr->type & ECORE_CON_SSL) + ecore_con_ssl_server_init(svr); + + svr->fd_handler = + ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ, + cb_done, svr, NULL, NULL); + if (!svr->fd_handler) + return 0; + + if (!svr->delete_me) ecore_con_event_server_add(svr); + + return 1; +#endif +} + +int +ecore_con_local_listen( + Ecore_Con_Server *svr, + Eina_Bool (* + cb_listen)(void *data, + Ecore_Fd_Handler * + fd_handler), + void *data + __UNUSED__) +{ +#ifdef HAVE_LOCAL_SOCKETS + char buf[4096]; + struct sockaddr_un socket_unix; + struct linger lin; + mode_t pmode; + const char *homedir; + struct stat st; + mode_t mask; + int socket_unix_len; + + mask = S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH; + + if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_USER) + { + homedir = getenv("HOME"); + if (!homedir) + homedir = getenv("TMP"); + + if (!homedir) + homedir = "/tmp"; + + mask = S_IRUSR | S_IWUSR | S_IXUSR; + snprintf(buf, sizeof(buf), "%s/.ecore", homedir); + if (stat(buf, &st) < 0) + mkdir(buf, mask); + + snprintf(buf, sizeof(buf), "%s/.ecore/%s", homedir, svr->name); + if (stat(buf, &st) < 0) + mkdir(buf, mask); + + snprintf(buf, + sizeof(buf), + "%s/.ecore/%s/%i", + homedir, + svr->name, + svr->port); + mask = S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH; + } + else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_SYSTEM) + { + mask = 0; + if (svr->name[0] == '/') + { + if (svr->port >= 0) + snprintf(buf, + sizeof(buf), + "%s|%i", + svr->name, + svr->port); + else + snprintf(buf, + sizeof(buf), + "%s", + svr->name); + } + else + snprintf(buf, + sizeof(buf), + "/tmp/.ecore_service|%s|%i", + svr->name, + svr->port); + } + else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT) + strncpy(buf, svr->name, + sizeof(buf)); + + pmode = umask(mask); +start: + svr->fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (svr->fd < 0) + goto error_umask; + + if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) + goto error_umask; + + if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) + goto error_umask; + + lin.l_onoff = 1; + lin.l_linger = 0; + if (setsockopt(svr->fd, SOL_SOCKET, SO_LINGER, (const void *)&lin, + sizeof(struct linger)) < 0) + goto error_umask; + + socket_unix.sun_family = AF_UNIX; + if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT) + { +#ifdef HAVE_ABSTRACT_SOCKETS + /* . is a placeholder */ + snprintf(socket_unix.sun_path, sizeof(socket_unix.sun_path), ".%s", + svr->name); + /* first char null indicates abstract namespace */ + socket_unix.sun_path[0] = '\0'; + socket_unix_len = LENGTH_OF_ABSTRACT_SOCKADDR_UN(&socket_unix, + svr->name); +#else + ERR("Your system does not support abstract sockets!"); + goto error_umask; +#endif + } + else + { + strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path)); + socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix); + } + + if (bind(svr->fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0) + { + if ((((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_USER) || + ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_SYSTEM)) && + (connect(svr->fd, (struct sockaddr *)&socket_unix, + socket_unix_len) < 0) && + (unlink(buf) >= 0)) + goto start; + else + goto error_umask; + } + + if (listen(svr->fd, 4096) < 0) + goto error_umask; + + svr->path = strdup(buf); + if (!svr->path) + goto error_umask; + + svr->fd_handler = + ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ, + cb_listen, svr, NULL, NULL); + umask(pmode); + if (!svr->fd_handler) + goto error; + + return 1; + +error_umask: + umask(pmode); +error: +#endif /* HAVE_LOCAL_SOCKETS */ + return 0; +} + diff --git a/src/lib/ecore_con/ecore_con_local_win32.c b/src/lib/ecore_con/ecore_con_local_win32.c new file mode 100644 index 0000000..2b7e5c5 --- /dev/null +++ b/src/lib/ecore_con/ecore_con_local_win32.c @@ -0,0 +1,754 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include +#include + +#include "Ecore_Con.h" +#include "ecore_con_private.h" + +#define BUFSIZE 512 + + +static int _ecore_con_local_init_count = 0; + +int +ecore_con_local_init(void) +{ + if (++_ecore_con_local_init_count != 1) + return _ecore_con_local_init_count; + + return _ecore_con_local_init_count; +} + +int +ecore_con_local_shutdown(void) +{ + if (--_ecore_con_local_init_count != 0) + return _ecore_con_local_init_count; + + return _ecore_con_local_init_count; +} + + +static Eina_Bool +_ecore_con_local_win32_server_read_client_handler(void *data, Ecore_Win32_Handler *wh) +{ + Ecore_Con_Client *cl; + void *buf; + DWORD n; + Eina_Bool broken_pipe = EINA_FALSE; + + cl = (Ecore_Con_Client *)data; + + if (!ResetEvent(cl->host_server->event_read)) + return ECORE_CALLBACK_RENEW; + + buf = malloc(cl->host_server->nbr_bytes); + if (!buf) + return ECORE_CALLBACK_RENEW; + + if (ReadFile(cl->host_server->pipe, buf, cl->host_server->nbr_bytes, &n, NULL)) + { + if (!cl->delete_me) + ecore_con_event_client_data(cl, buf, cl->host_server->nbr_bytes, EINA_FALSE); + cl->host_server->want_write = 1; + } + else + { + if (GetLastError() == ERROR_BROKEN_PIPE) + broken_pipe = EINA_TRUE; + } + + if (broken_pipe) + { +#if 0 + char *msg; + + msg = evil_last_error_get(); + if (msg) + { + ecore_con_event_client_error(cl, msg); + free(msg); + } +#endif + _ecore_con_client_kill(cl); + return ECORE_CALLBACK_CANCEL; + } + + if (cl->host_server->want_write) + ecore_con_local_win32_client_flush(cl); + + ecore_main_win32_handler_del(wh); + + return ECORE_CALLBACK_DONE; +} + +static Eina_Bool +_ecore_con_local_win32_server_peek_client_handler(void *data, Ecore_Win32_Handler *wh) +{ + Ecore_Con_Client *cl; +#if 0 + char *msg; +#endif + + cl = (Ecore_Con_Client *)data; + + if (!ResetEvent(cl->host_server->event_peek)) + return ECORE_CALLBACK_RENEW; + +#if 0 + msg = evil_last_error_get(); + if (msg) + { + ecore_con_event_server_error(cl->host_server, msg); + free(msg); + } +#endif + _ecore_con_server_kill(cl->host_server); + return ECORE_CALLBACK_CANCEL; + + ecore_main_win32_handler_del(wh); + + return ECORE_CALLBACK_DONE; +} + +static Eina_Bool +_ecore_con_local_win32_client_peek_server_handler(void *data, Ecore_Win32_Handler *wh) +{ + Ecore_Con_Server *svr; +#if 0 + char *msg; +#endif + + svr = (Ecore_Con_Server *)data; + + if (!ResetEvent(svr->event_peek)) + return ECORE_CALLBACK_RENEW; +#if 0 + msg = evil_last_error_get(); + if (msg) + { + ecore_con_event_server_error(svr, msg); + free(msg); + } +#endif + _ecore_con_server_kill(svr); + return ECORE_CALLBACK_CANCEL; + + ecore_main_win32_handler_del(wh); + + return ECORE_CALLBACK_DONE; +} + +static Eina_Bool +_ecore_con_local_win32_client_read_server_handler(void *data, Ecore_Win32_Handler *wh) +{ + Ecore_Con_Server *svr; + void *buf; + DWORD n; + Eina_Bool broken_pipe = EINA_FALSE; + + svr = (Ecore_Con_Server *)data; + + if (!ResetEvent(svr->event_read)) + return ECORE_CALLBACK_RENEW; + + buf = malloc(svr->nbr_bytes); + if (!buf) + return ECORE_CALLBACK_RENEW; + + if (ReadFile(svr->pipe, buf, svr->nbr_bytes, &n, NULL)) + { + if (!svr->delete_me) + ecore_con_event_server_data(svr, buf, svr->nbr_bytes, EINA_FALSE); + svr->want_write = 1; + } + else + { + if (GetLastError() == ERROR_BROKEN_PIPE) + broken_pipe = EINA_TRUE; + } + + if (broken_pipe) + { +#if 0 + char *msg; + + msg = evil_last_error_get(); + if (msg) + { + ecore_con_event_server_error(svr, msg); + free(msg); + } +#endif + _ecore_con_server_kill(svr); + return ECORE_CALLBACK_CANCEL; + } + + if (svr->want_write) + ecore_con_local_win32_server_flush(svr); + + ecore_main_win32_handler_del(wh); + + return ECORE_CALLBACK_DONE; +} + +/* thread to read data sent by the server to the client */ +static unsigned int __stdcall +_ecore_con_local_win32_client_read_server_thread(void *data) +{ + Ecore_Con_Server *svr; + DWORD nbr_bytes = 0; + + svr = (Ecore_Con_Server *)data; + + svr->read_stopped = EINA_FALSE; + + while (!svr->read_stop) + { + if (PeekNamedPipe(svr->pipe, NULL, 0, NULL, &nbr_bytes, NULL)) + { + if (nbr_bytes <= 0) + continue; + + svr->nbr_bytes = nbr_bytes; + if (!SetEvent(svr->event_read)) + continue; + } + else + { + if (GetLastError() == ERROR_BROKEN_PIPE) + { + if (!SetEvent(svr->event_peek)) + continue; + break; + } + } + } + + printf(" ### %s\n", __FUNCTION__); + svr->read_stopped = EINA_TRUE; + _endthreadex(0); + return 0; +} + +/* thread to read data sent by the client to the server */ +static unsigned int __stdcall +_ecore_con_local_win32_server_read_client_thread(void *data) +{ + Ecore_Con_Client *cl; + DWORD nbr_bytes = 0; + + cl = (Ecore_Con_Client *)data; + + cl->host_server->read_stopped = EINA_FALSE; + + while (!cl->host_server->read_stop) + { + if (PeekNamedPipe(cl->host_server->pipe, NULL, 0, NULL, &nbr_bytes, NULL)) + { + if (nbr_bytes <= 0) + continue; + + cl->host_server->nbr_bytes = nbr_bytes; + if (!SetEvent(cl->host_server->event_read)) + continue; + } + else + { + if (GetLastError() == ERROR_BROKEN_PIPE) + { + if (!SetEvent(cl->host_server->event_peek)) + continue; + break; + } + } + } + + printf(" ### %s\n", __FUNCTION__); + cl->host_server->read_stopped = EINA_TRUE; + _endthreadex(0); + return 0; +} + +static Eina_Bool +_ecore_con_local_win32_client_add(void *data, Ecore_Win32_Handler *wh) +{ + Ecore_Con_Client *cl = NULL; + Ecore_Con_Server *svr; + Ecore_Win32_Handler *handler_read; + Ecore_Win32_Handler *handler_peek; + + svr = (Ecore_Con_Server *)data; + + if (!svr->pipe) + return ECORE_CALLBACK_CANCEL; + + if (svr->delete_me) + return ECORE_CALLBACK_CANCEL; + + if ((svr->client_limit >= 0) && (!svr->reject_excess_clients) && + (svr->client_count >= (unsigned int)svr->client_limit)) + return ECORE_CALLBACK_CANCEL; + + cl = calloc(1, sizeof(Ecore_Con_Client)); + if (!cl) + { + ERR("allocation failed"); + return ECORE_CALLBACK_CANCEL; + } + + cl->host_server = svr; + ECORE_MAGIC_SET(cl, ECORE_MAGIC_CON_CLIENT); + + cl->host_server->event_read = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!cl->host_server->event_read) + { + ERR("Can not create event read"); + goto free_cl; + } + + handler_read = ecore_main_win32_handler_add(cl->host_server->event_read, + _ecore_con_local_win32_server_read_client_handler, + cl); + if (!handler_read) + { + ERR("Can not create handler read"); + goto close_event_read; + } + + cl->host_server->event_peek = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!cl->host_server->event_peek) + { + ERR("Can not create event peek"); + goto del_handler_read; + } + + handler_peek = ecore_main_win32_handler_add(cl->host_server->event_peek, + _ecore_con_local_win32_server_peek_client_handler, + cl); + if (!handler_peek) + { + ERR("Can not create handler peek"); + goto close_event_peek; + } + + cl->host_server->read_stopped = EINA_TRUE; + cl->host_server->thread_read = (HANDLE)_beginthreadex(NULL, 0, _ecore_con_local_win32_server_read_client_thread, cl, CREATE_SUSPENDED, NULL); + if (!cl->host_server->thread_read) + { + ERR("Can not launch thread"); + goto del_handler_peek; + } + + svr->clients = eina_list_append(svr->clients, cl); + svr->client_count++; + + if (!cl->delete_me) + ecore_con_event_client_add(cl); + + ecore_main_win32_handler_del(wh); + + ResumeThread(cl->host_server->thread_read); + return ECORE_CALLBACK_DONE; + + del_handler_peek: + ecore_main_win32_handler_del(handler_peek); + close_event_peek: + CloseHandle(cl->host_server->event_peek); + del_handler_read: + ecore_main_win32_handler_del(handler_read); + close_event_read: + CloseHandle(cl->host_server->event_read); + free_cl: + free(cl); + + return ECORE_CALLBACK_CANCEL; +} + +static unsigned int __stdcall +_ecore_con_local_win32_listening(void *data) +{ + Ecore_Con_Server *svr; + BOOL res; + + svr = (Ecore_Con_Server *)data; + + while (1) + { + res = ConnectNamedPipe(svr->pipe, NULL); + if (!res) + { + ERR("Opening the connection to the client failed"); + CloseHandle(svr->pipe); + svr->pipe = NULL; + } + break; + } + + DBG("Client connected"); + + printf(" ### %s\n", __FUNCTION__); + _endthreadex(0); + return 0; +} + +Eina_Bool +ecore_con_local_listen(Ecore_Con_Server *svr) +{ + char buf[256]; + HANDLE thread_listening; + Ecore_Win32_Handler *handler; + + if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT) + { + ERR("Your system does not support abstract sockets!"); + return EINA_FALSE; + } + + if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_USER) + snprintf(buf, sizeof(buf), "\\\\.\\pipe\\%s", svr->name); + else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_SYSTEM) + { + const char *computername; + + computername = getenv("CoMPUTERNAME"); + snprintf(buf, sizeof(buf), "\\\\%s\\pipe\\%s", computername, svr->name); + } + + svr->path = strdup(buf); + if (!svr->path) + { + ERR("Allocation failed"); + return EINA_FALSE; + } + + /* + * synchronuous + * block mode + * wait mode + */ + svr->pipe = CreateNamedPipe(svr->path, + PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, + BUFSIZE, + BUFSIZE, + 5000, + NULL); + if (svr->pipe == INVALID_HANDLE_VALUE) + { + ERR("Creation of the named pipe failed"); + goto free_path; + } + + /* + * We use ConnectNamedPipe() to wait for a client to connect. + * As the function is blocking, to let the main loop continuing + * its iterations, we call ConnectNamedPipe() in a thread + */ + thread_listening = (HANDLE)_beginthreadex(NULL, 0, _ecore_con_local_win32_listening, svr, CREATE_SUSPENDED, NULL); + if (!thread_listening) + { + ERR("Creation of the listening thread failed"); + goto close_pipe; + } + + handler = ecore_main_win32_handler_add(thread_listening, + _ecore_con_local_win32_client_add, + svr); + if (!handler) + { + ERR("Creation of the client add handler failed"); + goto del_handler; + } + + svr->read_stopped = EINA_TRUE; + ResumeThread(thread_listening); + + return EINA_TRUE; + + del_handler: + ecore_main_win32_handler_del(handler); + close_pipe: + CloseHandle(svr->pipe); + free_path: + free(svr->path); + svr->path = NULL; + + return EINA_FALSE; +} + +void +ecore_con_local_win32_server_del(Ecore_Con_Server *svr) +{ + if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT) + return; + + if (((svr->type & ECORE_CON_TYPE) != ECORE_CON_LOCAL_USER) && + ((svr->type & ECORE_CON_TYPE) != ECORE_CON_LOCAL_SYSTEM)) + return; + + svr->read_stop = 1; + while (!svr->read_stopped) + Sleep(100); + + if (svr->event_peek) + CloseHandle(svr->event_peek); + svr->event_peek = NULL; + if (svr->event_read) + CloseHandle(svr->event_read); + svr->event_read = NULL; + free(svr->path); + svr->path = NULL; + if (svr->pipe) + CloseHandle(svr->pipe); + svr->pipe = NULL; +} + +void +ecore_con_local_win32_client_del(Ecore_Con_Client *cl) +{ + if ((cl->host_server->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT) + return; + + if (((cl->host_server->type & ECORE_CON_TYPE) != ECORE_CON_LOCAL_USER) && + ((cl->host_server->type & ECORE_CON_TYPE) != ECORE_CON_LOCAL_SYSTEM)) + return; + + cl->host_server->read_stop = 1; + while (!cl->host_server->read_stopped) + Sleep(100); + + if (cl->host_server->event_peek) + CloseHandle(cl->host_server->event_peek); + cl->host_server->event_peek = NULL; + if (cl->host_server->event_read) + CloseHandle(cl->host_server->event_read); + cl->host_server->event_read = NULL; + free(cl->host_server->path); + cl->host_server->path = NULL; + if (cl->host_server->pipe) + CloseHandle(cl->host_server->pipe); + cl->host_server->pipe = NULL; +} + +Eina_Bool +ecore_con_local_connect(Ecore_Con_Server *svr, + Eina_Bool (*cb_done)(void *data, + Ecore_Fd_Handler *fd_handler)) +{ + char buf[256]; + Ecore_Win32_Handler *handler_read; + Ecore_Win32_Handler *handler_peek; + + if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT) + { + ERR("Your system does not support abstract sockets!"); + return EINA_FALSE; + } + + if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_USER) + snprintf(buf, sizeof(buf), "\\\\.\\pipe\\%s", svr->name); + else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_SYSTEM) + { + const char *computername; + + computername = getenv("COMPUTERNAME"); + snprintf(buf, sizeof(buf), "\\\\%s\\pipe\\%s", computername, svr->name); + } + + while (1) + { + svr->pipe = CreateFile(buf, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + 0, + NULL); + if (svr->pipe != INVALID_HANDLE_VALUE) + break; + + /* if pipe not busy, we exit */ + if (GetLastError() != ERROR_PIPE_BUSY) + { + ERR("Connection to a server failed"); + return EINA_FALSE; + } + + /* pipe busy, so we wait for it */ + if (!WaitNamedPipe(buf, NMPWAIT_WAIT_FOREVER)) + { + ERR("Can not wait for a server"); + goto close_pipe; + } + } + + svr->path = strdup(buf); + if (!svr->path) + { + ERR("Allocation failed"); + goto close_pipe; + } + + svr->event_read = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!svr->event_read) + { + ERR("Can not create event read"); + goto free_path; + } + + handler_read = ecore_main_win32_handler_add(svr->event_read, + _ecore_con_local_win32_client_read_server_handler, + svr); + if (!handler_read) + { + ERR("Can not create handler read"); + goto close_event_read; + } + + svr->event_peek = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!svr->event_peek) + { + ERR("Can not create event peek"); + goto del_handler_read; + } + + handler_peek = ecore_main_win32_handler_add(svr->event_peek, + _ecore_con_local_win32_client_peek_server_handler, + svr); + if (!handler_peek) + { + ERR("Can not create handler peek"); + goto close_event_peek; + } + + svr->thread_read = (HANDLE)_beginthreadex(NULL, 0, _ecore_con_local_win32_client_read_server_thread, svr, CREATE_SUSPENDED, NULL); + if (!svr->thread_read) + { + ERR("Can not launch thread"); + goto del_handler_peek; + } + + if (!svr->delete_me) ecore_con_event_server_add(svr); + + ResumeThread(svr->thread_read); + + return EINA_TRUE; + + del_handler_peek: + ecore_main_win32_handler_del(handler_peek); + close_event_peek: + CloseHandle(svr->event_peek); + del_handler_read: + ecore_main_win32_handler_del(handler_read); + close_event_read: + CloseHandle(svr->event_read); + free_path: + free(svr->path); + svr->path = NULL; + close_pipe: + CloseHandle(svr->pipe); + + return EINA_FALSE; +} + +Eina_Bool +ecore_con_local_win32_server_flush(Ecore_Con_Server *svr) +{ + int num; + BOOL res; + DWORD written; + + /* This check should never be true */ + if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT) + return EINA_TRUE; + + if (((svr->type & ECORE_CON_TYPE) != ECORE_CON_LOCAL_USER) && + ((svr->type & ECORE_CON_TYPE) != ECORE_CON_LOCAL_SYSTEM)) + return EINA_FALSE; + + num = eina_binbuf_length_get(svr->buf) - svr->write_buf_offset; + if (num <= 0) return EINA_TRUE; + + res = WriteFile(svr->pipe, eina_binbuf_string_get(svr->buf) + svr->write_buf_offset, num, &written, NULL); + if (!res) + { + char *msg; + + msg = evil_last_error_get(); + if (msg) + { + ecore_con_event_server_error(svr, msg); + free(msg); + } + _ecore_con_server_kill(svr); + } + + svr->write_buf_offset += written; + if (svr->write_buf_offset >= eina_binbuf_length_get(svr->buf)) + { + svr->write_buf_offset = 0; + eina_binbuf_free(svr->buf); + svr->buf = NULL; + svr->want_write = 0; + } + else if (written < (DWORD)num) + svr->want_write = 1; + + return EINA_TRUE; +} + +Eina_Bool +ecore_con_local_win32_client_flush(Ecore_Con_Client *cl) +{ + Ecore_Con_Type type; + int num; + BOOL res; + DWORD written; + + type = cl->host_server->type & ECORE_CON_TYPE; + + /* This check should never be true */ + if (type == ECORE_CON_LOCAL_ABSTRACT) + return EINA_TRUE; + + if ((type != ECORE_CON_LOCAL_USER) && + (type != ECORE_CON_LOCAL_SYSTEM)) + return EINA_FALSE; + + num = eina_binbuf_length_get(cl->buf) - cl->buf_offset; + if (num <= 0) return EINA_TRUE; + + res = WriteFile(cl->host_server->pipe, eina_binbuf_string_get(cl->buf) + cl->buf_offset, num, &written, NULL); + if (!res) + { + char *msg; + + msg = evil_last_error_get(); + if (msg) + { + ecore_con_event_client_error(cl, msg); + free(msg); + } + _ecore_con_client_kill(cl); + } + + cl->buf_offset += written; + if (cl->buf_offset >= eina_binbuf_length_get(cl->buf)) + { + cl->buf_offset = 0; + eina_binbuf_free(cl->buf); + cl->buf = NULL; + cl->host_server->want_write = 0; + } + else if (written < (DWORD)num) + cl->host_server->want_write = 1; + + return EINA_TRUE; +} diff --git a/src/lib/ecore_con/ecore_con_private.h b/src/lib/ecore_con/ecore_con_private.h new file mode 100644 index 0000000..26e9970 --- /dev/null +++ b/src/lib/ecore_con/ecore_con_private.h @@ -0,0 +1,399 @@ +#ifndef _ECORE_CON_PRIVATE_H +#define _ECORE_CON_PRIVATE_H + +#include "ecore_private.h" +#include "Ecore_Con.h" + +#define ECORE_MAGIC_CON_SERVER 0x77665544 +#define ECORE_MAGIC_CON_CLIENT 0x77556677 +#define ECORE_MAGIC_CON_URL 0x77074255 + +#define ECORE_CON_TYPE 0x0f +#define ECORE_CON_SSL 0xf0 +#define ECORE_CON_SUPER_SSL 0xf00 + +#if USE_GNUTLS +# include +#elif USE_OPENSSL +# include +#endif +#ifdef HAVE_CURL +#include +#endif + +#define READBUFSIZ 65536 + +extern int _ecore_con_log_dom; + +#ifdef ECORE_CON_DEFAULT_LOG_COLOR +#undef ECORE_LOG_DEFAULT_LOG_COLOR +#endif +#define ECORE_CON_DEFAULT_LOG_COLOR EINA_COLOR_BLUE + +#ifdef ERR +# undef ERR +#endif +#define ERR(...) EINA_LOG_DOM_ERR(_ecore_con_log_dom, __VA_ARGS__) + +#ifdef DBG +# undef DBG +#endif +#define DBG(...) EINA_LOG_DOM_DBG(_ecore_con_log_dom, __VA_ARGS__) + +#ifdef INF +# undef INF +#endif +#define INF(...) EINA_LOG_DOM_INFO(_ecore_con_log_dom, __VA_ARGS__) + +#ifdef WRN +# undef WRN +#endif +#define WRN(...) EINA_LOG_DOM_WARN(_ecore_con_log_dom, __VA_ARGS__) + +#ifdef CRIT +# undef CRIT +#endif +#define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_con_log_dom, __VA_ARGS__) + +typedef struct _Ecore_Con_Lookup Ecore_Con_Lookup; +typedef struct _Ecore_Con_Info Ecore_Con_Info; +typedef struct Ecore_Con_Socks Ecore_Con_Socks_v4; +typedef struct Ecore_Con_Socks_v5 Ecore_Con_Socks_v5; +typedef void (*Ecore_Con_Info_Cb)(void *data, Ecore_Con_Info *infos); + +typedef enum _Ecore_Con_State +{ + ECORE_CON_CONNECTED, + ECORE_CON_DISCONNECTED, + ECORE_CON_INPROGRESS +} Ecore_Con_State; + +typedef enum _Ecore_Con_Ssl_Error +{ + ECORE_CON_SSL_ERROR_NONE = 0, + ECORE_CON_SSL_ERROR_NOT_SUPPORTED, + ECORE_CON_SSL_ERROR_INIT_FAILED, + ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED, + ECORE_CON_SSL_ERROR_SSL2_NOT_SUPPORTED +} Ecore_Con_Ssl_Error; + +typedef enum _Ecore_Con_Ssl_Handshake +{ + ECORE_CON_SSL_STATE_DONE = 0, + ECORE_CON_SSL_STATE_HANDSHAKING, + ECORE_CON_SSL_STATE_INIT +} Ecore_Con_Ssl_State; + +typedef enum Ecore_Con_Proxy_State +{ /* named PROXY instead of SOCKS in case some handsome and enterprising + * developer decides to add HTTP CONNECT support + */ + ECORE_CON_PROXY_STATE_DONE = 0, + ECORE_CON_PROXY_STATE_RESOLVED, + ECORE_CON_PROXY_STATE_INIT, + ECORE_CON_PROXY_STATE_READ, + ECORE_CON_PROXY_STATE_AUTH, + ECORE_CON_PROXY_STATE_REQUEST, + ECORE_CON_PROXY_STATE_CONFIRM, +} Ecore_Con_Proxy_State; + +struct _Ecore_Con_Client +{ + ECORE_MAGIC; + int fd; + Ecore_Con_Server *host_server; + void *data; + Ecore_Fd_Handler *fd_handler; + unsigned int buf_offset; + Eina_Binbuf *buf; + const char *ip; + Eina_List *event_count; + struct sockaddr *client_addr; + int client_addr_len; + double start_time; + Ecore_Timer *until_deletion; + double disconnect_time; +#if USE_GNUTLS + gnutls_datum_t session_ticket; + gnutls_session_t session; +#elif USE_OPENSSL + SSL *ssl; + int ssl_err; +#endif + Ecore_Con_Ssl_State ssl_state; + Eina_Bool handshaking : 1; + Eina_Bool upgrade : 1; /* STARTTLS queued */ + Eina_Bool delete_me : 1; /* del event has been queued */ +}; + +struct _Ecore_Con_Server +{ + ECORE_MAGIC; + int fd; + Ecore_Con_Type type; + char *name; + int port; + char *path; + void *data; + Ecore_Fd_Handler *fd_handler; + Eina_List *clients; + unsigned int client_count; + Eina_Binbuf *buf; + unsigned int write_buf_offset; + Eina_List *infos; + Eina_List *event_count; + int client_limit; + pid_t ppid; + /* socks */ + Ecore_Con_Socks *ecs; + Ecore_Con_Proxy_State ecs_state; + int ecs_addrlen; + unsigned char ecs_addr[16]; + unsigned int ecs_buf_offset; + Eina_Binbuf *ecs_buf; + Eina_Binbuf *ecs_recvbuf; + const char *proxyip; + int proxyport; + /* endsocks */ + const char *verify_name; +#if USE_GNUTLS + gnutls_session_t session; + gnutls_anon_client_credentials_t anoncred_c; + gnutls_anon_server_credentials_t anoncred_s; + gnutls_psk_client_credentials_t pskcred_c; + gnutls_psk_server_credentials_t pskcred_s; + gnutls_certificate_credentials_t cert; + char *cert_file; + gnutls_dh_params_t dh_params; +#elif USE_OPENSSL + SSL_CTX *ssl_ctx; + SSL *ssl; + int ssl_err; +#endif + double start_time; + Ecore_Timer *until_deletion; + double disconnect_time; + double client_disconnect_time; + const char *ip; + Eina_Bool created : 1; /* @c EINA_TRUE if server is our listening server */ + Eina_Bool connecting : 1; /* @c EINA_FALSE if just initialized or connected */ + Eina_Bool handshaking : 1; /* @c EINA_TRUE if server is ssl handshaking */ + Eina_Bool upgrade : 1; /* STARTTLS queued */ + Eina_Bool disable_proxy : 1; /* proxy should never be used with this connection */ + Eina_Bool ssl_prepared : 1; + Eina_Bool use_cert : 1; /* @c EINA_TRUE if using certificate auth */ + Ecore_Con_Ssl_State ssl_state; /* current state of ssl handshake on the server */ + Eina_Bool verify : 1; /* @c EINA_TRUE if certificates will be verified */ + Eina_Bool verify_basic : 1; /* @c EINA_TRUE if certificates will be verified only against the hostname */ + Eina_Bool reject_excess_clients : 1; + Eina_Bool delete_me : 1; /* del event has been queued */ +#ifdef _WIN32 + Eina_Bool want_write : 1; + Eina_Bool read_stop : 1; + Eina_Bool read_stopped : 1; + HANDLE pipe; + HANDLE thread_read; + HANDLE event_read; + HANDLE event_peek; + DWORD nbr_bytes; +#endif +}; + +#ifdef HAVE_CURL +struct _Ecore_Con_Url +{ + ECORE_MAGIC; + CURL *curl_easy; + struct curl_slist *headers; + Eina_List *additional_headers; + Eina_List *response_headers; + const char *url; + long proxy_type; + int status; + + Ecore_Timer *timer; + + Ecore_Con_Url_Time time_condition; + double timestamp; + void *data; + + void *post_data; + + int received; + int write_fd; + + unsigned int event_count; + Eina_Bool dead : 1; + Eina_Bool multi : 1; +}; +#endif + +struct _Ecore_Con_Info +{ + unsigned int size; + struct addrinfo info; + char ip[NI_MAXHOST]; + char service[NI_MAXSERV]; +}; + +struct _Ecore_Con_Lookup +{ + Ecore_Con_Dns_Cb done_cb; + const void *data; +}; + +#define ECORE_CON_SOCKS_CAST_ELSE(X) \ + Ecore_Con_Socks_v4 *v4 = NULL; \ + Ecore_Con_Socks_v5 *v5 = NULL; \ + if ((X) && ((X)->version == 4)) \ + v4 = (Ecore_Con_Socks_v4*)(X); \ + else if ((X) && ((X)->version == 5)) \ + v5 = (Ecore_Con_Socks_v5*)(X); \ + else + +struct Ecore_Con_Socks /* v4 */ +{ + unsigned char version; + + const char *ip; + int port; + const char *username; + unsigned int ulen; + Eina_Bool lookup : 1; + Eina_Bool bind : 1; +}; + +struct Ecore_Con_Socks_v5 +{ + unsigned char version; + + const char *ip; + int port; + const char *username; + unsigned int ulen; + Eina_Bool lookup : 1; + Eina_Bool bind : 1; + /* v5 only */ + unsigned char method; + const char *password; + unsigned int plen; +}; + +extern Ecore_Con_Socks *_ecore_con_proxy_once; +extern Ecore_Con_Socks *_ecore_con_proxy_global; +void ecore_con_socks_init(void); +void ecore_con_socks_shutdown(void); +Eina_Bool ecore_con_socks_svr_init(Ecore_Con_Server *svr); +void ecore_con_socks_read(Ecore_Con_Server *svr, unsigned char *buf, int num); +void ecore_con_socks_dns_cb(const char *canonname, const char *ip, struct sockaddr *addr, int addrlen, Ecore_Con_Server *svr); +/* from ecore_con.c */ +void ecore_con_server_infos_del(Ecore_Con_Server *svr, void *info); +void ecore_con_event_proxy_bind(Ecore_Con_Server *svr); +void ecore_con_event_server_data(Ecore_Con_Server *svr, unsigned char *buf, int num, Eina_Bool duplicate); +void ecore_con_event_server_del(Ecore_Con_Server *svr); +#define ecore_con_event_server_error(svr, error) _ecore_con_event_server_error((svr), (char*)(error), EINA_TRUE) +void _ecore_con_event_server_error(Ecore_Con_Server *svr, char *error, Eina_Bool duplicate); +void ecore_con_event_client_add(Ecore_Con_Client *cl); +void ecore_con_event_client_data(Ecore_Con_Client *cl, unsigned char *buf, int num, Eina_Bool duplicate); +void ecore_con_event_client_del(Ecore_Con_Client *cl); +void ecore_con_event_client_error(Ecore_Con_Client *cl, const char *error); +void _ecore_con_server_kill(Ecore_Con_Server *svr); +void _ecore_con_client_kill(Ecore_Con_Client *cl); +/* from ecore_local_win32.c */ +#ifdef _WIN32 +Eina_Bool ecore_con_local_listen(Ecore_Con_Server *svr); +Eina_Bool ecore_con_local_connect(Ecore_Con_Server *svr, + Eina_Bool (*cb_done)(void *data, + Ecore_Fd_Handler *fd_handler)); +Eina_Bool ecore_con_local_win32_server_flush(Ecore_Con_Server *svr); +Eina_Bool ecore_con_local_win32_client_flush(Ecore_Con_Client *cl); +void ecore_con_local_win32_server_del(Ecore_Con_Server *svr); +void ecore_con_local_win32_client_del(Ecore_Con_Client *cl); +#else +/* from ecore_local.c */ +int ecore_con_local_init(void); +int ecore_con_local_shutdown(void); +int ecore_con_local_connect(Ecore_Con_Server *svr, + Eina_Bool (*cb_done)( + void *data, + Ecore_Fd_Handler *fd_handler), + void *data); +int ecore_con_local_listen(Ecore_Con_Server *svr, + Eina_Bool (*cb_listen)( + void *data, + Ecore_Fd_Handler *fd_handler), + void *data); +#endif + +/* from ecore_con_info.c */ +int ecore_con_info_init(void); +int ecore_con_info_shutdown(void); +int ecore_con_info_tcp_connect(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data); +int ecore_con_info_tcp_listen(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data); +int ecore_con_info_udp_connect(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data); +int ecore_con_info_udp_listen(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data); +int ecore_con_info_mcast_listen(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data); +void ecore_con_info_data_clear(void *info); + +void ecore_con_event_server_add(Ecore_Con_Server *svr); + + +/* from ecore_con_ssl.c */ +Ecore_Con_Ssl_Error ecore_con_ssl_init(void); +Ecore_Con_Ssl_Error ecore_con_ssl_shutdown(void); +Ecore_Con_Ssl_Error ecore_con_ssl_server_prepare(Ecore_Con_Server *svr, int ssl_type); +Ecore_Con_Ssl_Error ecore_con_ssl_server_init(Ecore_Con_Server *svr); +Ecore_Con_Ssl_Error ecore_con_ssl_server_shutdown(Ecore_Con_Server *svr); +int ecore_con_ssl_server_read(Ecore_Con_Server *svr, + unsigned char *buf, + int size); +int ecore_con_ssl_server_write(Ecore_Con_Server *svr, + const unsigned char *buf, + int size); +Ecore_Con_Ssl_Error ecore_con_ssl_client_init(Ecore_Con_Client *svr); +Ecore_Con_Ssl_Error ecore_con_ssl_client_shutdown(Ecore_Con_Client *svr); +int ecore_con_ssl_client_read(Ecore_Con_Client *svr, + unsigned char *buf, + int size); +int ecore_con_ssl_client_write(Ecore_Con_Client *svr, + const unsigned char *buf, + int size); + +int ecore_con_info_get(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data, + struct addrinfo *hints); + + +#define GENERIC_ALLOC_FREE_HEADER(TYPE, Type) \ + TYPE *Type##_alloc(void); \ + void Type##_free(TYPE *e); + +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Client_Add, ecore_con_event_client_add); +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Client_Del, ecore_con_event_client_del); +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Client_Write, ecore_con_event_client_write); +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Client_Data, ecore_con_event_client_data); +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Error, ecore_con_event_server_error); +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Client_Error, ecore_con_event_client_error); +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Add, ecore_con_event_server_add); +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Del, ecore_con_event_server_del); +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Write, ecore_con_event_server_write); +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Data, ecore_con_event_server_data); +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Proxy_Bind, ecore_con_event_proxy_bind); + +void ecore_con_mempool_init(void); +void ecore_con_mempool_shutdown(void); + +#undef GENERIC_ALLOC_FREE_HEADER + +#endif diff --git a/src/lib/ecore_con/ecore_con_socks.c b/src/lib/ecore_con/ecore_con_socks.c new file mode 100644 index 0000000..e609a6a --- /dev/null +++ b/src/lib/ecore_con/ecore_con_socks.c @@ -0,0 +1,940 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif + +#ifdef HAVE_NETINET_TCP_H +# include +#endif + +#ifdef HAVE_NET_IF_H +# include +#endif + +/* if net/if.h is not found or if an older versions of net/if.h is provided + which does not define IF_NAMESIZE. We must define it ourselves */ +#ifndef IF_NAMESIZE +# ifdef IFNAMSIZ +# define IF_NAMESIZE IFNAMSIZ +# else +# define IF_NAMESIZE 16 +# endif +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#ifdef HAVE_ARPA_INET_H +# include +#endif + +#ifdef HAVE_SYS_UN_H +# include +#endif + +#ifdef HAVE_WS2TCPIP_H +# include +#endif + +#ifdef HAVE_EVIL +# include +#endif + +#include "Ecore.h" +#include "ecore_private.h" +#include "Ecore_Con.h" +#include "ecore_con_private.h" + +/* http://tools.ietf.org/html/rfc1928 + o X'00' NO AUTHENTICATION REQUIRED + o X'01' GSSAPI + o X'02' USERNAME/PASSWORD + o X'03' to X'7F' IANA ASSIGNED + o X'80' to X'FE' RESERVED FOR PRIVATE METHODS + o X'FF' NO ACCEPTABLE METHODS +*/ +#define ECORE_CON_SOCKS_V5_METHOD_NONE 0 +#define ECORE_CON_SOCKS_V5_METHOD_GSSAPI 1 +#define ECORE_CON_SOCKS_V5_METHOD_USERPASS 2 + +static int ECORE_CON_SOCKS_V5_METHODS[] = +{ + ECORE_CON_SOCKS_V5_METHOD_NONE, +// ECORE_CON_SOCKS_V5_METHOD_GSSAPI, TODO + ECORE_CON_SOCKS_V5_METHOD_USERPASS +}; + +#define ECORE_CON_SOCKS_V5_TOTAL_METHODS sizeof(ECORE_CON_SOCKS_V5_METHODS) + +#define _ecore_con_server_kill(svr) do { \ + DBG("KILL %p", (svr)); \ + _ecore_con_server_kill((svr)); \ +} while (0) + +Eina_List *ecore_con_socks_proxies = NULL; + +static Ecore_Con_Socks * +_ecore_con_socks_find(unsigned char version, const char *ip, int port, const char *username, size_t ulen, const char *password, size_t plen) +{ + Eina_List *l; + Ecore_Con_Socks_v5 *ecs; + + if (!ecore_con_socks_proxies) return NULL; + + EINA_LIST_FOREACH(ecore_con_socks_proxies, l, ecs) + { + if (ecs->version != version) continue; + if (strcmp(ecs->ip, ip)) continue; + if ((port != -1) && (port != ecs->port)) continue; + if (ulen != ecs->ulen) continue; + if (username && strcmp(ecs->username, username)) continue; + if (version == 5) + { + if (plen != ecs->plen) continue; + if (password && strcmp(ecs->password, password)) continue; + } + return (Ecore_Con_Socks*)ecs; + } + return NULL; +} + +static void +_ecore_con_socks_free(Ecore_Con_Socks *ecs) +{ + ECORE_CON_SOCKS_CAST_ELSE(ecs) return; + + if (_ecore_con_proxy_once == ecs) _ecore_con_proxy_once = NULL; + if (_ecore_con_proxy_global == ecs) _ecore_con_proxy_global = NULL; + eina_stringshare_del(ecs->ip); + eina_stringshare_del(ecs->username); + free(ecs); +} + +static Eina_Bool +_ecore_con_socks_svr_init_v4(Ecore_Con_Server *svr, Ecore_Con_Socks_v4 *v4) +{ + size_t addrlen, buflen, ulen = 1; + unsigned char *sbuf; + + addrlen = v4->lookup ? strlen(svr->name) + 1 : 0; + if (v4->username) ulen += v4->ulen; + buflen = sizeof(char) * (8 + ulen + addrlen); + sbuf = malloc(buflen); + if (!sbuf) + { + ecore_con_event_server_error(svr, "Memory allocation failure!"); + _ecore_con_server_kill(svr); + return EINA_FALSE; + } + /* http://en.wikipedia.org/wiki/SOCKS */ + sbuf[0] = 4; + sbuf[1] = v4->bind ? 2 : 1; + sbuf[2] = svr->port >> 8; + sbuf[3] = svr->port & 0xff; + if (addrlen) + { + sbuf[4] = sbuf[5] = sbuf[6] = 0; + sbuf[7] = 1; + } + else + /* SOCKSv4 only handles IPV4, so addrlen is always 4 */ + memcpy(sbuf + 4, svr->ecs_addr, 4); + if (v4->username) + memcpy(sbuf + 8, v4->username, ulen); + else + sbuf[8] = 0; + if (addrlen) memcpy(sbuf + 8 + ulen, svr->name, addrlen); + + svr->ecs_buf = eina_binbuf_manage_new_length(sbuf, buflen); + return EINA_TRUE; +} + +static Eina_Bool +_ecore_con_socks_svr_init_v5(Ecore_Con_Server *svr, Ecore_Con_Socks_v5 *v5) +{ + size_t buflen; + unsigned int x; + unsigned char *sbuf; + + if (v5->username) + buflen = sizeof(char) * (2 + ECORE_CON_SOCKS_V5_TOTAL_METHODS); + else + buflen = 3; + sbuf = malloc(buflen); + if (!sbuf) + { + ecore_con_event_server_error(svr, "Memory allocation failure!"); + _ecore_con_server_kill(svr); + return EINA_FALSE; + } + /* http://en.wikipedia.org/wiki/SOCKS + * http://tools.ietf.org/html/rfc1928 + */ + sbuf[0] = 5; + if (v5->username) + { + sbuf[1] = ECORE_CON_SOCKS_V5_TOTAL_METHODS; + for (x = 2; x < 2 + ECORE_CON_SOCKS_V5_TOTAL_METHODS; x++) + sbuf[x] = ECORE_CON_SOCKS_V5_METHODS[x - 2]; + } + else + { + sbuf[1] = 1; + sbuf[2] = ECORE_CON_SOCKS_V5_METHOD_NONE; + } + + svr->ecs_buf = eina_binbuf_manage_new_length(sbuf, buflen); + return EINA_TRUE; +} + +#define ECORE_CON_SOCKS_READ(EXACT) \ + if (num < EXACT) \ + { \ + if (!svr->ecs_recvbuf) svr->ecs_recvbuf = eina_binbuf_new(); \ + if (!svr->ecs_recvbuf) goto error; \ + eina_binbuf_append_length(svr->ecs_recvbuf, buf, num); \ + /* the slowest connection on earth */ \ + if (eina_binbuf_length_get(svr->ecs_recvbuf) != EXACT) return; \ + data = eina_binbuf_string_get(svr->ecs_recvbuf); \ + } \ + else if (num > EXACT) goto error; \ + else \ + data = buf + +static void +_ecore_con_socks_read_v4(Ecore_Con_Server *svr, Ecore_Con_Socks_v4 *v4 __UNUSED__, const unsigned char *buf, unsigned int num) +{ + const unsigned char *data; + DBG("SOCKS: %d bytes", num); + ECORE_CON_SOCKS_READ(8); + +/* http://ufasoft.com/doc/socks4_protocol.htm */ + if (data[0]) goto error; + switch (data[1]) + { + case 90: + /* success! */ + break; + case 91: + ecore_con_event_server_error(svr, "proxy request rejected or failed"); + goto error; + case 92: + ecore_con_event_server_error(svr, "proxying SOCKS server could not perform authentication"); + goto error; + case 93: + ecore_con_event_server_error(svr, "proxy request authentication rejected"); + goto error; + default: + ecore_con_event_server_error(svr, "garbage data from proxy"); + goto error; + } + if (svr->ecs->bind) + { + unsigned int nport; + char naddr[IF_NAMESIZE]; + + memcpy(&nport, &data[2], 2); + svr->proxyport = ntohl(nport); + + if (!inet_ntop(AF_INET, &data[4], naddr, sizeof(naddr))) goto error; + svr->proxyip = eina_stringshare_add(naddr); + ecore_con_event_proxy_bind(svr); + } + svr->ecs_state = ECORE_CON_PROXY_STATE_DONE; + INF("PROXY CONNECTED"); + if (svr->ecs_recvbuf) eina_binbuf_free(svr->ecs_recvbuf); + svr->ecs_recvbuf = NULL; + svr->ecs_buf_offset = svr->ecs_addrlen = 0; + memset(svr->ecs_addr, 0, sizeof(svr->ecs_addr)); + if (!svr->ssl_state) + ecore_con_event_server_add(svr); + if (svr->ssl_state || (svr->buf && eina_binbuf_length_get(svr->buf))) + ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ | ECORE_FD_WRITE); + return; +error: + _ecore_con_server_kill(svr); +} + +static Eina_Bool +_ecore_con_socks_auth_v5(Ecore_Con_Server *svr, Ecore_Con_Socks_v5 *v5) +{ + size_t size; + unsigned char *data; + switch (v5->method) + { + case ECORE_CON_SOCKS_V5_METHOD_NONE: + svr->ecs_state = ECORE_CON_PROXY_STATE_REQUEST; + return EINA_TRUE; + case ECORE_CON_SOCKS_V5_METHOD_GSSAPI: + return EINA_TRUE; + case ECORE_CON_SOCKS_V5_METHOD_USERPASS: + if (!v5->username) return EINA_FALSE; + if (!v5->password) v5->plen = 1; + /* http://tools.ietf.org/html/rfc1929 */ + size = sizeof(char) * (3 + v5->ulen + v5->plen); + data = malloc(size); + if (!data) break; + data[0] = 1; + data[1] = v5->ulen; + memcpy(&data[2], v5->username, v5->ulen); + data[1 + v5->ulen] = v5->plen; + if (v5->password) + memcpy(&data[2 + v5->ulen], v5->password, v5->plen); + else + data[2 + v5->ulen] = 0; + svr->ecs_buf = eina_binbuf_manage_new_length(data, size); + return EINA_TRUE; + default: + break; + } + return EINA_FALSE; +} + +static void +_ecore_con_socks_read_v5(Ecore_Con_Server *svr, Ecore_Con_Socks_v5 *v5, const unsigned char *buf, unsigned int num) +{ + const unsigned char *data; + + DBG("SOCKS: %d bytes", num); + switch (svr->ecs_state) + { + + case ECORE_CON_PROXY_STATE_READ: + ECORE_CON_SOCKS_READ(2); + /* http://en.wikipedia.org/wiki/SOCKS */ + if (data[0] != 5) goto error; + if (data[1] == 0xFF) + { + ecore_con_event_server_error(svr, "proxy authentication methods rejected"); + goto error; + } + v5->method = data[1]; + if (!_ecore_con_socks_auth_v5(svr, v5)) goto error; + if (svr->ecs_state == ECORE_CON_PROXY_STATE_REQUEST) + { + /* run again to skip auth reading */ + _ecore_con_socks_read_v5(svr, v5, NULL, 0); + return; + } + ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE); + svr->ecs_state = ECORE_CON_PROXY_STATE_AUTH; + break; + case ECORE_CON_PROXY_STATE_AUTH: + ECORE_CON_SOCKS_READ(2); + switch (v5->method) + { + case ECORE_CON_SOCKS_V5_METHOD_NONE: + CRIT("HOW DID THIS HAPPEN?????????"); + goto error; + case ECORE_CON_SOCKS_V5_METHOD_GSSAPI: + /* TODO: this */ + break; + case ECORE_CON_SOCKS_V5_METHOD_USERPASS: + if (data[0] != 1) + { + ecore_con_event_server_error(svr, "protocol error"); + goto error; /* wrong version */ + } + if (data[1]) + { + ecore_con_event_server_error(svr, "proxy request authentication rejected"); + goto error; + } + default: + break; + } + case ECORE_CON_PROXY_STATE_REQUEST: + { + size_t addrlen, buflen; + unsigned char *sbuf; + addrlen = v5->lookup ? strlen(svr->name) + 1 : (unsigned int)svr->ecs_addrlen; + buflen = sizeof(char) * (6 + addrlen); + sbuf = malloc(buflen); + if (!sbuf) + { + ecore_con_event_server_error(svr, "Memory allocation failure!"); + goto error; + } + sbuf[0] = 5; + sbuf[1] = v5->bind ? 2 : 1; /* TODO: 0x03 for UDP port association */ + sbuf[2] = 0; + if (v5->lookup) /* domain name */ + { + sbuf[3] = 3; + sbuf[4] = addrlen - 1; + memcpy(sbuf + 5, svr->name, addrlen - 1); + } + else + { + sbuf[3] = (svr->ecs_addrlen == 4) ? 1 : 4; + memcpy(sbuf + 4, svr->ecs_addr, addrlen); + } + sbuf[addrlen + 4] = svr->port >> 8; + sbuf[addrlen + 5] = svr->port & 0xff; + + svr->ecs_buf = eina_binbuf_manage_new_length(sbuf, buflen); + ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE); + break; + } + case ECORE_CON_PROXY_STATE_CONFIRM: + { + /* this is ugly because we have to read an exact number of bytes, + * but we don't know what that number is until we've already read + * at least 5 bytes to determine the length of the unknown stream. + * yep. + */ + size_t to_read, len = svr->ecs_recvbuf ? eina_binbuf_length_get(svr->ecs_recvbuf) : 0; + if (num + len < 5) + { + /* guarantees we get called again */ + ECORE_CON_SOCKS_READ(5); + } + if (len >= 5) + { + data = eina_binbuf_string_get(svr->ecs_recvbuf); + data += 3; + } + else + data = buf + 3 - len; + switch (data[0]) + { + case 1: + to_read = 4; + break; + case 3: + to_read = data[1] + 1; + break; + case 4: + to_read = 16; + /* lazy debugging stub comment */ + break; + default: + ecore_con_event_server_error(svr, "protocol error"); + goto error; + } + /* at this point, we finally know exactly how much we need to read */ + ECORE_CON_SOCKS_READ(6 + to_read); + + if (data[0] != 5) + { + ecore_con_event_server_error(svr, "protocol error"); + goto error; /* wrong version */ + } + switch (data[1]) + { + case 0: + break; + case 1: + ecore_con_event_server_error(svr, "general proxy failure"); + goto error; + case 2: + ecore_con_event_server_error(svr, "connection not allowed by ruleset"); + goto error; + case 3: + ecore_con_event_server_error(svr, "network unreachable"); + goto error; + case 4: + ecore_con_event_server_error(svr, "host unreachable"); + goto error; + case 5: + ecore_con_event_server_error(svr, "connection refused by destination host"); + goto error; + case 6: + ecore_con_event_server_error(svr, "TTL expired"); + goto error; + case 7: + ecore_con_event_server_error(svr, "command not supported / protocol error"); + goto error; + case 8: + ecore_con_event_server_error(svr, "address type not supported"); + default: + goto error; + } + if (data[2]) + { + ecore_con_event_server_error(svr, "protocol error"); + goto error; + } + memset(svr->ecs_addr, 0, sizeof(svr->ecs_addr)); + if (!svr->ssl_state) + ecore_con_event_server_add(svr); + if (svr->ssl_state || (svr->buf && eina_binbuf_length_get(svr->buf))) + ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ | ECORE_FD_WRITE); + svr->ecs_buf_offset = svr->ecs_addrlen = 0; + svr->ecs_state = ECORE_CON_PROXY_STATE_DONE; + INF("PROXY CONNECTED"); + break; + } + default: + break; + } + if (svr->ecs_recvbuf) eina_binbuf_free(svr->ecs_recvbuf); + svr->ecs_recvbuf = NULL; + + return; +error: + _ecore_con_server_kill(svr); +} + +///////////////////////////////////////////////////////////////////////////////////// +void +ecore_con_socks_shutdown(void) +{ + Ecore_Con_Socks *ecs; + EINA_LIST_FREE(ecore_con_socks_proxies, ecs) + _ecore_con_socks_free(ecs); + _ecore_con_proxy_once = NULL; + _ecore_con_proxy_global = NULL; +} + +void +ecore_con_socks_read(Ecore_Con_Server *svr, unsigned char *buf, int num) +{ + ECORE_CON_SOCKS_CAST_ELSE(svr->ecs) return; + + if (svr->ecs_state < ECORE_CON_PROXY_STATE_READ) return; + + if (v4) _ecore_con_socks_read_v4(svr, v4, buf, (unsigned int)num); + else _ecore_con_socks_read_v5(svr, v5, buf, (unsigned int)num); +} + +Eina_Bool +ecore_con_socks_svr_init(Ecore_Con_Server *svr) +{ + ECORE_CON_SOCKS_CAST_ELSE(svr->ecs) return EINA_FALSE; + + if (!svr->ip) return EINA_FALSE; + if (svr->ecs_buf) return EINA_FALSE; + if (svr->ecs_state != ECORE_CON_PROXY_STATE_INIT) return EINA_FALSE; + ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE); + if (v4) return _ecore_con_socks_svr_init_v4(svr, v4); + return _ecore_con_socks_svr_init_v5(svr, v5); +} + +void +ecore_con_socks_dns_cb(const char *canonname __UNUSED__, const char *ip, struct sockaddr *addr, int addrlen __UNUSED__, Ecore_Con_Server *svr) +{ + svr->ip = eina_stringshare_add(ip); + svr->ecs_state++; + if (addr->sa_family == AF_INET) + { + memcpy(svr->ecs_addr, &((struct sockaddr_in *)addr)->sin_addr.s_addr, 4); + svr->ecs_addrlen = 4; + } +#ifdef HAVE_IPV6 + else + { + memcpy(svr->ecs_addr, &((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr, 16); + svr->ecs_addrlen = 16; + } +#endif + ecore_con_socks_svr_init(svr); +} + +void +ecore_con_socks_init(void) +{ + const char *socks; + char *h, *p, *l, *u = NULL; + char buf[512]; + int port, lookup = 0; + Eina_Bool v5 = EINA_FALSE; + Ecore_Con_Socks *ecs; + unsigned char addr[sizeof(struct in_addr)]; +#ifdef HAVE_IPV6 + unsigned char addr6[sizeof(struct in6_addr)]; +#endif + + /* ECORE_CON_SOCKS_V4=[user@]host-port:[1|0] */ + socks = getenv("ECORE_CON_SOCKS_V4"); + if (!socks) + { + /* ECORE_CON_SOCKS_V5=[user@]host-port:[1|0] */ + socks = getenv("ECORE_CON_SOCKS_V5"); + v5 = EINA_TRUE; + } + if ((!socks) || (!socks[0]) || (strlen(socks) > 512)) return; + strncpy(buf, socks, sizeof(buf)); + h = strchr(buf, '@'); + /* username */ + if (h && (h - buf > 0)) *h++ = 0, u = buf; + else h = buf; + + /* host ip; I ain't resolvin shit here */ + p = strchr(h, '-'); + if (!p) return; + *p++ = 0; + if (!inet_pton(AF_INET, h, addr)) +#ifdef HAVE_IPV6 + { + if (!v5) return; + if (!inet_pton(AF_INET6, h, addr6)) + return; + } +#else + return; +#endif + + errno = 0; + port = strtol(p, &l, 10); + if (errno || (port < 0) || (port > 65535)) return; + if (l && (l[0] == ':')) + lookup = (l[1] == '1'); + if (v5) + ecs = ecore_con_socks5_remote_add(h, port, u, NULL); + else + ecs = ecore_con_socks4_remote_add(h, port, u); + if (!ecs) return; + ecore_con_socks_lookup_set(ecs, lookup); + ecore_con_socks_apply_always(ecs); + INF("Added global proxy server %s%s%s:%d - DNS lookup %s", + u ?: "", u ? "@" : "", h, port, lookup ? "ENABLED" : "DISABLED"); +} + +///////////////////////////////////////////////////////////////////////////////////// + +/** + * @defgroup Ecore_Con_Socks_Group Ecore Connection SOCKS functions + * @{ + */ + +/** + * Add a SOCKS v4 proxy to the proxy list + * + * Use this to create (or return, if previously added) a SOCKS proxy + * object which can be used by any ecore_con servers. + * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.) + * @param port The port to connect to on the proxy + * @param username The username to use for the proxy (OPTIONAL) + * @return An allocated proxy object, or NULL on failure + * @note This object NEVER needs to be explicitly freed. + * @since 1.2 + */ +EAPI Ecore_Con_Socks * +ecore_con_socks4_remote_add(const char *ip, int port, const char *username) +{ + Ecore_Con_Socks *ecs; + size_t ulen = 0; + + if ((!ip) || (!ip[0]) || (port < 0) || (port > 65535)) return NULL; + + if (username) + { + ulen = strlen(username); + /* max length for protocol */ + if ((!ulen) || (ulen > 255)) return NULL; + } + ecs = _ecore_con_socks_find(4, ip, port, username, ulen, NULL, 0); + if (ecs) return ecs; + + ecs = calloc(1, sizeof(Ecore_Con_Socks_v4)); + if (!ecs) return NULL; + + ecs->version = 4; + ecs->ip = eina_stringshare_add(ip); + ecs->port = port; + ecs->username = eina_stringshare_add(username); + ecs->ulen = ulen; + ecore_con_socks_proxies = eina_list_append(ecore_con_socks_proxies, ecs); + return ecs; +} + +/** + * Find a SOCKS v4 proxy in the proxy list + * + * Use this to determine if a SOCKS proxy was previously added by checking + * the proxy list against the parameters given. + * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.) + * @param port The port to connect to on the proxy, or -1 to match the first proxy with @p ip + * @param username The username used for the proxy (OPTIONAL) + * @return true only if a proxy exists matching the given params + * @note This function matches slightly more loosely than ecore_con_socks4_remote_add(), and + * ecore_con_socks4_remote_add() should be used to return the actual object. + * @since 1.2 + */ +EAPI Eina_Bool +ecore_con_socks4_remote_exists(const char *ip, int port, const char *username) +{ + if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0]))) + return EINA_FALSE; + return !!_ecore_con_socks_find(4, ip, port, username, username ? strlen(username) : 0, NULL, 0); +} + +/** + * Remove a SOCKS v4 proxy from the proxy list and delete it + * + * Use this to remove a SOCKS proxy from the proxy list by checking + * the list against the parameters given. The proxy will then be deleted. + * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.) + * @param port The port to connect to on the proxy, or -1 to match the first proxy with @p ip + * @param username The username used for the proxy (OPTIONAL) + * @note This function matches in the same way as ecore_con_socks4_remote_exists(). + * @warning Be aware that deleting a proxy which is being used WILL ruin your life. + * @since 1.2 + */ +EAPI void +ecore_con_socks4_remote_del(const char *ip, int port, const char *username) +{ + Ecore_Con_Socks_v4 *v4; + + if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0]))) return; + if (!ecore_con_socks_proxies) return; + + v4 = (Ecore_Con_Socks_v4*)_ecore_con_socks_find(4, ip, port, username, username ? strlen(username) : 0, NULL, 0); + if (!v4) return; + ecore_con_socks_proxies = eina_list_remove(ecore_con_socks_proxies, v4); + _ecore_con_socks_free((Ecore_Con_Socks*)v4); +} +/** + * Add a SOCKS v5 proxy to the proxy list + * + * Use this to create (or return, if previously added) a SOCKS proxy + * object which can be used by any ecore_con servers. + * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.) + * @param port The port to connect to on the proxy + * @param username The username to use for the proxy (OPTIONAL) + * @param password The password to use for the proxy (OPTIONAL) + * @return An allocated proxy object, or NULL on failure + * @note This object NEVER needs to be explicitly freed. + * @since 1.2 + */ +EAPI Ecore_Con_Socks * +ecore_con_socks5_remote_add(const char *ip, int port, const char *username, const char *password) +{ + Ecore_Con_Socks_v5 *ecs5; + size_t ulen = 0, plen = 0; + + if ((!ip) || (!ip[0]) || (port < 0) || (port > 65535)) return NULL; + + if (username) + { + ulen = strlen(username); + /* max length for protocol */ + if ((!ulen) || (ulen > 255)) return NULL; + } + if (password) + { + plen = strlen(password); + /* max length for protocol */ + if ((!plen) || (plen > 255)) return NULL; + } + ecs5 = (Ecore_Con_Socks_v5*)_ecore_con_socks_find(5, ip, port, username, ulen, password, plen); + if (ecs5) return (Ecore_Con_Socks*)ecs5; + + ecs5 = calloc(1, sizeof(Ecore_Con_Socks_v5)); + if (!ecs5) return NULL; + + ecs5->version = 5; + ecs5->ip = eina_stringshare_add(ip); + ecs5->port = port; + ecs5->username = eina_stringshare_add(username); + ecs5->ulen = ulen; + ecs5->password = eina_stringshare_add(password); + ecs5->plen = plen; + ecore_con_socks_proxies = eina_list_append(ecore_con_socks_proxies, ecs5); + return (Ecore_Con_Socks*)ecs5; +} + +/** + * Find a SOCKS v5 proxy in the proxy list + * + * Use this to determine if a SOCKS proxy was previously added by checking + * the proxy list against the parameters given. + * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.) + * @param port The port to connect to on the proxy, or -1 to match the first proxy with @p ip + * @param username The username used for the proxy (OPTIONAL) + * @param password The password used for the proxy (OPTIONAL) + * @return true only if a proxy exists matching the given params + * @note This function matches slightly more loosely than ecore_con_socks5_remote_add(), and + * ecore_con_socks5_remote_add() should be used to return the actual object. + * @since 1.2 + */ +EAPI Eina_Bool +ecore_con_socks5_remote_exists(const char *ip, int port, const char *username, const char *password) +{ + if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0])) || (password && (!password[0]))) + return EINA_FALSE; + return !!_ecore_con_socks_find(5, ip, port, username, username ? strlen(username) : 0, password, password ? strlen(password) : 0); +} + +/** + * Remove a SOCKS v5 proxy from the proxy list and delete it + * + * Use this to remove a SOCKS proxy from the proxy list by checking + * the list against the parameters given. The proxy will then be deleted. + * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.) + * @param port The port to connect to on the proxy, or -1 to match the first proxy with @p ip + * @param username The username used for the proxy (OPTIONAL) + * @param password The password used for the proxy (OPTIONAL) + * @note This function matches in the same way as ecore_con_socks4_remote_exists(). + * @warning Be aware that deleting a proxy which is being used WILL ruin your life. + * @since 1.2 + */ +EAPI void +ecore_con_socks5_remote_del(const char *ip, int port, const char *username, const char *password) +{ + Ecore_Con_Socks_v5 *v5; + + if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0])) || (password && (!password[0]))) + return; + if (!ecore_con_socks_proxies) return; + + v5 = (Ecore_Con_Socks_v5*)_ecore_con_socks_find(5, ip, port, username, username ? strlen(username) : 0, password, password ? strlen(password) : 0); + if (!v5) return; + ecore_con_socks_proxies = eina_list_remove(ecore_con_socks_proxies, v5); + _ecore_con_socks_free((Ecore_Con_Socks*)v5); +} + +/** + * Set DNS lookup mode on an existing SOCKS proxy + * + * According to RFC, SOCKS v4 does not require that a proxy perform + * its own DNS lookups for addresses. SOCKS v4a specifies the protocol + * for this. SOCKS v5 allows DNS lookups. + * If you want to enable remote DNS lookup and are sure that your + * proxy supports it, use this function. + * @param ecs The proxy object + * @param enable If true, the proxy will perform the dns lookup + * @note By default, this setting is DISABLED. + * @since 1.2 + */ +EAPI void +ecore_con_socks_lookup_set(Ecore_Con_Socks *ecs, Eina_Bool enable) +{ + ECORE_CON_SOCKS_CAST_ELSE(ecs) return; + ecs->lookup = !!enable; +} + +/** + * Get DNS lookup mode on an existing SOCKS proxy + * + * According to RFC, SOCKS v4 does not require that a proxy perform + * its own DNS lookups for addresses. SOCKS v4a specifies the protocol + * for this. SOCKS v5 allows DNS lookups. + * This function returns whether lookups are enabled on a proxy object. + * @param ecs The proxy object + * @return If true, the proxy will perform the dns lookup + * @note By default, this setting is DISABLED. + * @since 1.2 + */ +EAPI Eina_Bool +ecore_con_socks_lookup_get(Ecore_Con_Socks *ecs) +{ + ECORE_CON_SOCKS_CAST_ELSE(ecs) return EINA_FALSE; + return ecs->lookup; +} + +/** + * Enable bind mode on a SOCKS proxy + * + * Use this function to enable binding a remote port for use with a remote server. + * For more information, see http://ufasoft.com/doc/socks4_protocol.htm + * @param ecs The proxy object + * @param is_bind If true, the connection established will be a port binding + * @warning Be aware that changing the operation mode of an active proxy may result in undefined behavior + * @since 1.2 + */ +EAPI void +ecore_con_socks_bind_set(Ecore_Con_Socks *ecs, Eina_Bool is_bind) +{ + EINA_SAFETY_ON_NULL_RETURN(ecs); + ecs->bind = !!is_bind; +} + +/** + * Return bind mode of a SOCKS proxy + * + * Use this function to return bind mode of a proxy (binding a remote port for use with a remote server). + * For more information, see http://ufasoft.com/doc/socks4_protocol.htm + * @param ecs The proxy object + * @return If true, the connection established will be a port binding + * @since 1.2 + */ +EAPI Eina_Bool +ecore_con_socks_bind_get(Ecore_Con_Socks *ecs) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(ecs, EINA_FALSE); + return ecs->bind; +} + +/** + * Return SOCKS version of a SOCKS proxy + * + * Use this function to return the SOCKS protocol version of a proxy + * @param ecs The proxy object + * @return 0 on error, else 4/5 + * @since 1.2 + */ +EAPI unsigned int +ecore_con_socks_version_get(Ecore_Con_Socks *ecs) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(ecs, 0); + return ecs->version; +} + +/** + * Remove a SOCKS v4 proxy from the proxy list and delete it + * + * Use this to remove a SOCKS proxy from the proxy list by directly deleting the object given. + * @param ecs The proxy object to delete + * @warning Be aware that deleting a proxy which is being used WILL ruin your life. + * @since 1.2 + */ +EAPI void +ecore_con_socks_remote_del(Ecore_Con_Socks *ecs) +{ + EINA_SAFETY_ON_NULL_RETURN(ecs); + if (!ecore_con_socks_proxies) return; + + ecore_con_socks_proxies = eina_list_remove(ecore_con_socks_proxies, ecs); + _ecore_con_socks_free(ecs); +} + +/** + * Set a proxy object to be used with the next server created with ecore_con_server_connect() + * + * This function sets a proxy for the next ecore_con connection. After the next server is created, + * the proxy will NEVER be applied again unless explicitly enabled. + * @param ecs The proxy object + * @see ecore_con_socks_apply_always() + * @since 1.2 + */ +EAPI void +ecore_con_socks_apply_once(Ecore_Con_Socks *ecs) +{ + _ecore_con_proxy_once = ecs; +} + +/** + * Set a proxy object to be used with all servers created with ecore_con_server_connect() + * + * This function sets a proxy for all ecore_con connections. It will always be used. + * @param ecs The proxy object + * @see ecore_con_socks_apply_once() + * @since 1.2 + * @note ecore-con supports setting this through environment variables like so: + * ECORE_CON_SOCKS_V4=[user@]server-port:lookup + * ECORE_CON_SOCKS_V5=[user@]server-port:lookup + * user is the OPTIONAL string that would be passed to the proxy as the username + * server is the IP_ADDRESS of the proxy server + * port is the port to connect to on the proxy server + * lookup is 1 if the proxy should perform all DNS lookups, otherwise 0 or omitted + */ +EAPI void +ecore_con_socks_apply_always(Ecore_Con_Socks *ecs) +{ + _ecore_con_proxy_global = ecs; +} +/** @} */ diff --git a/src/lib/ecore_con/ecore_con_ssl.c b/src/lib/ecore_con/ecore_con_ssl.c new file mode 100644 index 0000000..fd4c9dd --- /dev/null +++ b/src/lib/ecore_con/ecore_con_ssl.c @@ -0,0 +1,2112 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#if USE_GNUTLS +# include +# include +# include +#elif USE_OPENSSL +# include +# include +# include +#endif + +#ifdef HAVE_WS2TCPIP_H +# include +#endif + +#include +#include "Ecore.h" +#include "ecore_con_private.h" + +EAPI int ECORE_CON_EVENT_CLIENT_UPGRADE = 0; +EAPI int ECORE_CON_EVENT_SERVER_UPGRADE = 0; + +static int _init_con_ssl_init_count = 0; + +#ifdef USE_GNUTLS +# ifdef EINA_HAVE_THREADS +GCRY_THREAD_OPTION_PTHREAD_IMPL; +# endif + +static int _client_connected = 0; + +# define SSL_SUFFIX(ssl_func) ssl_func ## _gnutls +# define _ECORE_CON_SSL_AVAILABLE 1 + +#elif USE_OPENSSL + +# define SSL_SUFFIX(ssl_func) ssl_func ## _openssl +# define _ECORE_CON_SSL_AVAILABLE 2 + +#else +# define SSL_SUFFIX(ssl_func) ssl_func ## _none +# define _ECORE_CON_SSL_AVAILABLE 0 + +#endif + +#if USE_GNUTLS +static void +_gnutls_print_errors(void *conn, int type, int ret) +{ + char buf[1024]; + + if (!ret) return; + + snprintf(buf, sizeof(buf), "GNUTLS error: %s - %s", gnutls_strerror_name(ret), gnutls_strerror(ret)); + if (type == ECORE_CON_EVENT_CLIENT_ERROR) + ecore_con_event_client_error(conn, buf); + else + ecore_con_event_server_error(conn, buf); +} + +static void +_gnutls_print_session(const gnutls_datum_t *cert_list, unsigned int cert_list_size) +{ + char *c = NULL; + gnutls_x509_crt_t crt; + unsigned int x; + + if (!eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG)) return; + for (x = 0; x < cert_list_size; x++) + { + gnutls_x509_crt_init(&crt); + gnutls_x509_crt_import(crt, &cert_list[x], GNUTLS_X509_FMT_DER); + gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_FULL, (gnutls_datum_t*)&c); + INF("CERTIFICATE:\n%s", c); + gnutls_free(c); + gnutls_x509_crt_deinit(crt); + crt = NULL; + } +} + +#ifdef ISCOMFITOR +static void +_gnutls_log_func(int level, + const char *str) +{ + char buf[128]; + strncat(buf, str, strlen(str) - 1); + DBG("|<%d>| %s", level, buf); +} +#endif + +static const char * +SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_description_t status) +{ + switch (status) + { + case GNUTLS_HANDSHAKE_HELLO_REQUEST: + return "Hello request"; + + case GNUTLS_HANDSHAKE_CLIENT_HELLO: + return "Client hello"; + + case GNUTLS_HANDSHAKE_SERVER_HELLO: + return "Server hello"; + + case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: + return "New session ticket"; + + case GNUTLS_HANDSHAKE_CERTIFICATE_PKT: + return "Certificate packet"; + + case GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE: + return "Server key exchange"; + + case GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST: + return "Certificate request"; + + case GNUTLS_HANDSHAKE_SERVER_HELLO_DONE: + return "Server hello done"; + + case GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY: + return "Certificate verify"; + + case GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE: + return "Client key exchange"; + + case GNUTLS_HANDSHAKE_FINISHED: + return "Finished"; + + case GNUTLS_HANDSHAKE_SUPPLEMENTAL: + return "Supplemental"; + } + return NULL; +} + +#elif USE_OPENSSL + +static void +_openssl_print_verify_error(int error) +{ + switch (error) + { +#define ERROR(X) \ + case (X): \ + ERR("%s", #X); \ + break +#ifdef X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT + ERROR(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT); +#endif +#ifdef X509_V_ERR_UNABLE_TO_GET_CRL + ERROR(X509_V_ERR_UNABLE_TO_GET_CRL); +#endif +#ifdef X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE + ERROR(X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE); +#endif +#ifdef X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE + ERROR(X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE); +#endif +#ifdef X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY + ERROR(X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY); +#endif +#ifdef X509_V_ERR_CERT_SIGNATURE_FAILURE + ERROR(X509_V_ERR_CERT_SIGNATURE_FAILURE); +#endif +#ifdef X509_V_ERR_CRL_SIGNATURE_FAILURE + ERROR(X509_V_ERR_CRL_SIGNATURE_FAILURE); +#endif +#ifdef X509_V_ERR_CERT_NOT_YET_VALID + ERROR(X509_V_ERR_CERT_NOT_YET_VALID); +#endif +#ifdef X509_V_ERR_CERT_HAS_EXPIRED + ERROR(X509_V_ERR_CERT_HAS_EXPIRED); +#endif +#ifdef X509_V_ERR_CRL_NOT_YET_VALID + ERROR(X509_V_ERR_CRL_NOT_YET_VALID); +#endif +#ifdef X509_V_ERR_CRL_HAS_EXPIRED + ERROR(X509_V_ERR_CRL_HAS_EXPIRED); +#endif +#ifdef X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD + ERROR(X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD); +#endif +#ifdef X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD + ERROR(X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD); +#endif +#ifdef X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD + ERROR(X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD); +#endif +#ifdef X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD + ERROR(X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD); +#endif +#ifdef X509_V_ERR_OUT_OF_MEM + ERROR(X509_V_ERR_OUT_OF_MEM); +#endif +#ifdef X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT + ERROR(X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT); +#endif +#ifdef X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN + ERROR(X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN); +#endif +#ifdef X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY + ERROR(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY); +#endif +#ifdef X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE + ERROR(X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE); +#endif +#ifdef X509_V_ERR_CERT_CHAIN_TOO_LONG + ERROR(X509_V_ERR_CERT_CHAIN_TOO_LONG); +#endif +#ifdef X509_V_ERR_CERT_REVOKED + ERROR(X509_V_ERR_CERT_REVOKED); +#endif +#ifdef X509_V_ERR_INVALID_CA + ERROR(X509_V_ERR_INVALID_CA); +#endif +#ifdef X509_V_ERR_PATH_LENGTH_EXCEEDED + ERROR(X509_V_ERR_PATH_LENGTH_EXCEEDED); +#endif +#ifdef X509_V_ERR_INVALID_PURPOSE + ERROR(X509_V_ERR_INVALID_PURPOSE); +#endif +#ifdef X509_V_ERR_CERT_UNTRUSTED + ERROR(X509_V_ERR_CERT_UNTRUSTED); +#endif +#ifdef X509_V_ERR_CERT_REJECTED + ERROR(X509_V_ERR_CERT_REJECTED); +#endif + /* These are 'informational' when looking for issuer cert */ +#ifdef X509_V_ERR_SUBJECT_ISSUER_MISMATCH + ERROR(X509_V_ERR_SUBJECT_ISSUER_MISMATCH); +#endif +#ifdef X509_V_ERR_AKID_SKID_MISMATCH + ERROR(X509_V_ERR_AKID_SKID_MISMATCH); +#endif +#ifdef X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH + ERROR(X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH); +#endif +#ifdef X509_V_ERR_KEYUSAGE_NO_CERTSIGN + ERROR(X509_V_ERR_KEYUSAGE_NO_CERTSIGN); +#endif + +#ifdef X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER + ERROR(X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER); +#endif +#ifdef X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION + ERROR(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION); +#endif +#ifdef X509_V_ERR_KEYUSAGE_NO_CRL_SIGN + ERROR(X509_V_ERR_KEYUSAGE_NO_CRL_SIGN); +#endif +#ifdef X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION + ERROR(X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION); +#endif +#ifdef X509_V_ERR_INVALID_NON_CA + ERROR(X509_V_ERR_INVALID_NON_CA); +#endif +#ifdef X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED + ERROR(X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED); +#endif +#ifdef X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE + ERROR(X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE); +#endif +#ifdef X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED + ERROR(X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED); +#endif + +#ifdef X509_V_ERR_INVALID_EXTENSION + ERROR(X509_V_ERR_INVALID_EXTENSION); +#endif +#ifdef X509_V_ERR_INVALID_POLICY_EXTENSION + ERROR(X509_V_ERR_INVALID_POLICY_EXTENSION); +#endif +#ifdef X509_V_ERR_NO_EXPLICIT_POLICY + ERROR(X509_V_ERR_NO_EXPLICIT_POLICY); +#endif +#ifdef X509_V_ERR_DIFFERENT_CRL_SCOPE + ERROR(X509_V_ERR_DIFFERENT_CRL_SCOPE); +#endif +#ifdef X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE + ERROR(X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE); +#endif + +#ifdef X509_V_ERR_UNNESTED_RESOURCE + ERROR(X509_V_ERR_UNNESTED_RESOURCE); +#endif + +#ifdef X509_V_ERR_PERMITTED_VIOLATION + ERROR(X509_V_ERR_PERMITTED_VIOLATION); +#endif +#ifdef X509_V_ERR_EXCLUDED_VIOLATION + ERROR(X509_V_ERR_EXCLUDED_VIOLATION); +#endif +#ifdef X509_V_ERR_SUBTREE_MINMAX + ERROR(X509_V_ERR_SUBTREE_MINMAX); +#endif +#ifdef X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE + ERROR(X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE); +#endif +#ifdef X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX + ERROR(X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX); +#endif +#ifdef X509_V_ERR_UNSUPPORTED_NAME_SYNTAX + ERROR(X509_V_ERR_UNSUPPORTED_NAME_SYNTAX); +#endif +#ifdef X509_V_ERR_CRL_PATH_VALIDATION_ERROR + ERROR(X509_V_ERR_CRL_PATH_VALIDATION_ERROR); +#endif + + /* The application is not happy */ +#ifdef X509_V_ERR_APPLICATION_VERIFICATION + ERROR(X509_V_ERR_APPLICATION_VERIFICATION); +#endif + } +#undef ERROR +} + +static void +_openssl_print_errors(void *conn, int type) +{ + char buf[1024]; + do + { + unsigned long err; + + err = ERR_get_error(); + if (!err) break; + snprintf(buf, sizeof(buf), "OpenSSL error: %s", ERR_reason_error_string(err)); + if (type == ECORE_CON_EVENT_CLIENT_ERROR) + ecore_con_event_client_error(conn, buf); + else + ecore_con_event_server_error(conn, buf); + + } while (1); +} + +static Eina_Bool +_openssl_name_verify(const char *name, const char *svrname) +{ + if (name[0] == '*') + { + /* we allow *.domain.TLD with a wildcard, but nothing else */ + const char *p, *s; + + EINA_SAFETY_ON_TRUE_RETURN_VAL((name[1] != '.') || (!name[2]), EINA_FALSE); + p = strchr(name + 1, '*'); + EINA_SAFETY_ON_TRUE_RETURN_VAL(!!p, EINA_FALSE); + /* verify that we have a domain of at least *.X.TLD and not *.TLD */ + p = strchr(name + 2, '.'); + EINA_SAFETY_ON_TRUE_RETURN_VAL(!p, EINA_FALSE); + s = strchr(svrname, '.'); + EINA_SAFETY_ON_TRUE_RETURN_VAL(!s, EINA_FALSE); + /* same as above for the stored name */ + EINA_SAFETY_ON_TRUE_RETURN_VAL(!strchr(s + 1, '.'), EINA_FALSE); + if (strcasecmp(s, name + 1)) + { + ERR("%s != %s", s, name + 1); + return EINA_FALSE; + } + } + else + if (strcasecmp(name, svrname)) + { + ERR("%s != %s", name, svrname); + return EINA_FALSE; + } + return EINA_TRUE; +} + +static void +_openssl_print_session(SSL *ssl) +{ + /* print session info into DBG */ + SSL_SESSION *s; + STACK_OF(X509) *sk; + BIO *b; + char log[4096], *p; + int x; + + if (!eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG)) return; + + memset(log, 0, sizeof(log)); + b = BIO_new(BIO_s_mem()); + sk = SSL_get_peer_cert_chain(ssl); + if (sk) + { + DBG("CERTIFICATES:"); + for (x = 0; x < sk_X509_num(sk); x++) + { + p = X509_NAME_oneline(X509_get_subject_name(sk_X509_value(sk, x)), log, sizeof(log)); + DBG("%2d s:%s", x, p); + p = X509_NAME_oneline(X509_get_issuer_name(sk_X509_value(sk, x)), log, sizeof(log)); + DBG(" i:%s", p); + PEM_write_X509(stderr, sk_X509_value(sk, x)); + } + } + s = SSL_get_session(ssl); + SSL_SESSION_print(b, s); + fprintf(stderr, "\n"); + while (BIO_read(b, log, sizeof(log)) > 0) + fprintf(stderr, "%s", log); + + BIO_free(b); +} + +#endif + +#define SSL_ERROR_CHECK_GOTO_ERROR(X) \ + do \ + { \ + if ((X)) \ + { \ + ERR("Error at %s:%s:%d!", __FILE__, __PRETTY_FUNCTION__, __LINE__); \ + goto error; \ + } \ + } \ + while (0) + +static Ecore_Con_Ssl_Error + SSL_SUFFIX(_ecore_con_ssl_init) (void); +static Ecore_Con_Ssl_Error + SSL_SUFFIX(_ecore_con_ssl_shutdown) (void); + +static Eina_Bool SSL_SUFFIX(_ecore_con_ssl_server_cafile_add) (Ecore_Con_Server * svr, const char *ca_file); +static Eina_Bool SSL_SUFFIX(_ecore_con_ssl_server_crl_add) (Ecore_Con_Server * svr, const char *crl_file); +static Eina_Bool SSL_SUFFIX(_ecore_con_ssl_server_cert_add) (Ecore_Con_Server * svr, const char *cert); +static Eina_Bool SSL_SUFFIX(_ecore_con_ssl_server_privkey_add) (Ecore_Con_Server * svr, const char *key_file); + +static Ecore_Con_Ssl_Error SSL_SUFFIX(_ecore_con_ssl_server_prepare) (Ecore_Con_Server * svr, int ssl_type); +static Ecore_Con_Ssl_Error SSL_SUFFIX(_ecore_con_ssl_server_init) (Ecore_Con_Server * svr); +static Ecore_Con_Ssl_Error SSL_SUFFIX(_ecore_con_ssl_server_shutdown) (Ecore_Con_Server *svr); +static int SSL_SUFFIX(_ecore_con_ssl_server_read) (Ecore_Con_Server *svr, unsigned char *buf, int size); +static int SSL_SUFFIX(_ecore_con_ssl_server_write) (Ecore_Con_Server *svr, const unsigned char *buf, int size); + +static Ecore_Con_Ssl_Error SSL_SUFFIX(_ecore_con_ssl_client_init) (Ecore_Con_Client * cl); +static Ecore_Con_Ssl_Error SSL_SUFFIX(_ecore_con_ssl_client_shutdown) (Ecore_Con_Client *cl); +static int SSL_SUFFIX(_ecore_con_ssl_client_read) (Ecore_Con_Client * cl, + unsigned char *buf, int size); +static int SSL_SUFFIX(_ecore_con_ssl_client_write) (Ecore_Con_Client * cl, + const unsigned char *buf, int size); + +/* + * General SSL API + */ + +Ecore_Con_Ssl_Error +ecore_con_ssl_init(void) +{ + if (!_init_con_ssl_init_count++) + { + SSL_SUFFIX(_ecore_con_ssl_init) (); +#if _ECORE_CON_SSL_AVAILABLE != 0 + ECORE_CON_EVENT_CLIENT_UPGRADE = ecore_event_type_new(); + ECORE_CON_EVENT_SERVER_UPGRADE = ecore_event_type_new(); +#endif + } + + return _init_con_ssl_init_count; +} + +Ecore_Con_Ssl_Error +ecore_con_ssl_shutdown(void) +{ + if (!--_init_con_ssl_init_count) + SSL_SUFFIX(_ecore_con_ssl_shutdown) (); + + return _init_con_ssl_init_count; +} + +Ecore_Con_Ssl_Error +ecore_con_ssl_server_prepare(Ecore_Con_Server *svr, + int ssl_type) +{ + if (!ssl_type) + return ECORE_CON_SSL_ERROR_NONE; + return SSL_SUFFIX(_ecore_con_ssl_server_prepare) (svr, ssl_type); +} + +Ecore_Con_Ssl_Error +ecore_con_ssl_server_init(Ecore_Con_Server *svr) +{ + if (!(svr->type & ECORE_CON_SSL)) + return ECORE_CON_SSL_ERROR_NONE; + return SSL_SUFFIX(_ecore_con_ssl_server_init) (svr); +} + +Ecore_Con_Ssl_Error +ecore_con_ssl_server_shutdown(Ecore_Con_Server *svr) +{ + if (!(svr->type & ECORE_CON_SSL)) + return ECORE_CON_SSL_ERROR_NONE; + return SSL_SUFFIX(_ecore_con_ssl_server_shutdown) (svr); +} + +int +ecore_con_ssl_server_read(Ecore_Con_Server *svr, + unsigned char *buf, + int size) +{ + return SSL_SUFFIX(_ecore_con_ssl_server_read) (svr, buf, size); +} + +int +ecore_con_ssl_server_write(Ecore_Con_Server *svr, + const unsigned char *buf, + int size) +{ + return SSL_SUFFIX(_ecore_con_ssl_server_write) (svr, buf, size); +} + +Ecore_Con_Ssl_Error +ecore_con_ssl_client_init(Ecore_Con_Client *cl) +{ + if (!(cl->host_server->type & ECORE_CON_SSL)) + return ECORE_CON_SSL_ERROR_NONE; + return SSL_SUFFIX(_ecore_con_ssl_client_init) (cl); +} + +Ecore_Con_Ssl_Error +ecore_con_ssl_client_shutdown(Ecore_Con_Client *cl) +{ + if (!(cl->host_server->type & ECORE_CON_SSL)) + return ECORE_CON_SSL_ERROR_NONE; + return SSL_SUFFIX(_ecore_con_ssl_client_shutdown) (cl); +} + +int +ecore_con_ssl_client_read(Ecore_Con_Client *cl, + unsigned char *buf, + int size) +{ + return SSL_SUFFIX(_ecore_con_ssl_client_read) (cl, buf, size); +} + +int +ecore_con_ssl_client_write(Ecore_Con_Client *cl, + const unsigned char *buf, + int size) +{ + return SSL_SUFFIX(_ecore_con_ssl_client_write) (cl, buf, size); +} + +/** + * Returns if SSL support is available + * @return 1 if SSL is available and provided by gnutls, 2 if provided by openssl, + * 0 if it is not available. + * @ingroup Ecore_Con_Client_Group + */ +EAPI int +ecore_con_ssl_available_get(void) +{ + return _ECORE_CON_SSL_AVAILABLE; +} + +/** + * @addtogroup Ecore_Con_SSL_Group Ecore Connection SSL Functions + * + * Functions that operate on Ecore connection objects pertaining to SSL. + * + * @{ + */ + +/** + * @brief Enable certificate verification on a server object + * + * Call this function on a server object before main loop has started + * to enable verification of certificates against loaded certificates. + * @param svr The server object + */ +EAPI void +ecore_con_ssl_server_verify(Ecore_Con_Server *svr) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_ssl_server_verify"); + return; + } + svr->verify = EINA_TRUE; +} + +/** + * @brief Enable hostname-based certificate verification on a server object + * + * Call this function on a server object before main loop has started + * to enable verification of certificates using ONLY their hostnames. + * @param svr The server object + * @note This function has no effect when used on a listening server created by + * ecore_con_server_add + * @since 1.1 + */ +EAPI void +ecore_con_ssl_server_verify_basic(Ecore_Con_Server *svr) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, __func__); + return; + } + svr->verify_basic = EINA_TRUE; +} + +/** + * @brief Set the hostname to verify against in certificate verification + * + * Sometimes the certificate hostname will not match the hostname that you are + * connecting to, and will instead match a different name. An example of this is + * that if you connect to talk.google.com to use Google Talk, you receive Google's + * certificate for gmail.com. This certificate should be trusted, and so you must call + * this function with "gmail.com" as @p name. + * See RFC2818 for more details. + * @param svr The server object + * @param name The hostname to verify against + * @since 1.2 + */ +EAPI void +ecore_con_ssl_server_verify_name_set(Ecore_Con_Server *svr, const char *name) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, __func__); + return; + } + eina_stringshare_replace(&svr->verify_name, name); +} + +/** + * @brief Get the hostname to verify against in certificate verification + * + * This function returns the name which will be used to validate the SSL certificate + * common name (CN) or alt name (subjectAltName). It will default to the @p name + * param in ecore_con_server_connect(), but can be changed with ecore_con_ssl_server_verify_name_set(). + * @param svr The server object + * @return The hostname which will be used + * @since 1.2 + */ +EAPI const char * +ecore_con_ssl_server_verify_name_get(Ecore_Con_Server *svr) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, __func__); + return NULL; + } + return svr->verify_name ?: svr->name; +} + +/** + * @brief Add an ssl certificate for use in ecore_con functions. + * + * Use this function to add a SSL PEM certificate. + * Simply specify the cert here to use it in the server object for connecting or listening. + * If there is an error loading the certificate, an error will automatically be logged. + * @param svr The server object + * @param cert The path to the certificate. + * @return @c EINA_FALSE if the file cannot be loaded, otherwise @c EINA_TRUE. + */ + +EAPI Eina_Bool +ecore_con_ssl_server_cert_add(Ecore_Con_Server *svr, + const char *cert) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_ssl_server_cert_add"); + return EINA_FALSE; + } + + if (!svr->ssl_prepared) + { + svr->use_cert = EINA_TRUE; + svr->type |= ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT; + if (ecore_con_ssl_server_prepare(svr, svr->type & ECORE_CON_SSL)) + return EINA_FALSE; + } + + return SSL_SUFFIX(_ecore_con_ssl_server_cert_add) (svr, cert); +} + +/** + * @brief Add an ssl CA file for use in ecore_con functions. + * + * Use this function to add a SSL PEM CA file. + * Simply specify the file here to use it in the server object for connecting or listening. + * If there is an error loading the CAs, an error will automatically be logged. + * @param svr The server object + * @param ca_file The path to the CA file. + * @return @c EINA_FALSE if the file cannot be loaded, otherwise @c EINA_TRUE. + * @note since 1.2, this function can load directores + */ + +EAPI Eina_Bool +ecore_con_ssl_server_cafile_add(Ecore_Con_Server *svr, + const char *ca_file) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_ssl_server_cafile_add"); + return EINA_FALSE; + } + + if (!svr->ssl_prepared) + { + svr->use_cert = EINA_TRUE; + svr->type |= ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT; + if (ecore_con_ssl_server_prepare(svr, svr->type & ECORE_CON_SSL)) + return EINA_FALSE; + } + + return SSL_SUFFIX(_ecore_con_ssl_server_cafile_add) (svr, ca_file); +} + +/** + * @brief Add an ssl private key for use in ecore_con functions. + * + * Use this function to add a SSL PEM private key + * Simply specify the key file here to use it in the server object for connecting or listening. + * If there is an error loading the key, an error will automatically be logged. + * @param svr The server object + * @param key_file The path to the key file. + * @return @c EINA_FALSE if the file cannot be loaded, otherwise @c EINA_TRUE. + */ + +EAPI Eina_Bool +ecore_con_ssl_server_privkey_add(Ecore_Con_Server *svr, + const char *key_file) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_ssl_server_privkey_add"); + return EINA_FALSE; + } + + if (!svr->ssl_prepared) + { + svr->use_cert = EINA_TRUE; + svr->type |= ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT; + if (ecore_con_ssl_server_prepare(svr, svr->type & ECORE_CON_SSL)) + return EINA_FALSE; + } + + return SSL_SUFFIX(_ecore_con_ssl_server_privkey_add) (svr, key_file); +} + +/** + * @brief Add an ssl CRL for use in ecore_con functions. + * + * Use this function to add a SSL PEM CRL file + * Simply specify the CRL file here to use it in the server object for connecting or listening. + * If there is an error loading the CRL, an error will automatically be logged. + * @param svr The server object + * @param crl_file The path to the CRL file. + * @return @c EINA_FALSE if the file cannot be loaded, otherwise @c EINA_TRUE. + */ + +EAPI Eina_Bool +ecore_con_ssl_server_crl_add(Ecore_Con_Server *svr, + const char *crl_file) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_ssl_server_crl_add"); + return EINA_FALSE; + } + + if (!svr->ssl_prepared) + { + svr->use_cert = EINA_TRUE; + svr->type |= ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT; + if (ecore_con_ssl_server_prepare(svr, svr->type & ECORE_CON_SSL)) + return EINA_FALSE; + } + + return SSL_SUFFIX(_ecore_con_ssl_server_crl_add) (svr, crl_file); +} + +/** + * @brief Upgrade a connection to a specified level of encryption + * + * Use this function to begin an SSL handshake on a connection (STARTTLS or similar). + * Once the upgrade has been completed, an ECORE_CON_EVENT_SERVER_UPGRADE event will be emitted. + * The connection should be treated as disconnected until the next event. + * @param svr The server object + * @param ssl_type The SSL connection type (ONLY). + * @return @c EINA_FALSE if the connection cannot be upgraded, otherwise @c EINA_TRUE. + * @note This function is NEVER to be used on a server object created with ecore_con_server_add + * @warning Setting a wrong value for @p compl_type WILL mess up your program. + * @since 1.1 + */ + +EAPI Eina_Bool +ecore_con_ssl_server_upgrade(Ecore_Con_Server *svr, Ecore_Con_Type ssl_type) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, __func__); + return EINA_FALSE; + } +#if _ECORE_CON_SSL_AVAILABLE == 0 + return EINA_FALSE; +#endif + + if (!svr->ssl_prepared) + { + if (ecore_con_ssl_server_prepare(svr, ssl_type)) + return EINA_FALSE; + } + if (!svr->use_cert) + svr->type |= ssl_type; + svr->upgrade = EINA_TRUE; + svr->handshaking = EINA_TRUE; + svr->ssl_state = ECORE_CON_SSL_STATE_INIT; + return !SSL_SUFFIX(_ecore_con_ssl_server_init) (svr); +} + +/** + * @brief Upgrade a connection to a specified level of encryption + * + * Use this function to begin an SSL handshake on a connection (STARTTLS or similar). + * Once the upgrade has been completed, an ECORE_CON_EVENT_CLIENT_UPGRADE event will be emitted. + * The connection should be treated as disconnected until the next event. + * @param cl The client object + * @param ssl_type The SSL connection type (ONLY). + * @return @c EINA_FALSE if the connection cannot be upgraded, otherwise @c EINA_TRUE. + * @warning Setting a wrong value for @p compl_type WILL mess up your program. + * @since 1.1 + */ + +EAPI Eina_Bool +ecore_con_ssl_client_upgrade(Ecore_Con_Client *cl, Ecore_Con_Type ssl_type) +{ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, __func__); + return EINA_FALSE; + } +#if _ECORE_CON_SSL_AVAILABLE == 0 + return EINA_FALSE; +#endif + + if (!cl->host_server->ssl_prepared) + { + if (ecore_con_ssl_server_prepare(cl->host_server, ssl_type)) + return EINA_FALSE; + } + if (!cl->host_server->use_cert) + cl->host_server->type |= ssl_type; + cl->upgrade = EINA_TRUE; + cl->host_server->upgrade = EINA_TRUE; + cl->handshaking = EINA_TRUE; + cl->ssl_state = ECORE_CON_SSL_STATE_INIT; + return SSL_SUFFIX(_ecore_con_ssl_client_init) (cl); +} + +/** + * @} + */ + +#if USE_GNUTLS + +/* + * GnuTLS + */ + +static Ecore_Con_Ssl_Error +_ecore_con_ssl_init_gnutls(void) +{ +#ifdef EINA_HAVE_THREADS + if (gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread)) + WRN("YOU ARE USING PTHREADS, BUT I CANNOT INITIALIZE THREADSAFE GCRYPT OPERATIONS!"); +#endif + if (gnutls_global_init()) + return ECORE_CON_SSL_ERROR_INIT_FAILED; + +#ifdef ISCOMFITOR + if (eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG)) + { + gnutls_global_set_log_level(9); + gnutls_global_set_log_function(_gnutls_log_func); + } +#endif + return ECORE_CON_SSL_ERROR_NONE; +} + +static Ecore_Con_Ssl_Error +_ecore_con_ssl_shutdown_gnutls(void) +{ + gnutls_global_deinit(); + + return ECORE_CON_SSL_ERROR_NONE; +} + +static Ecore_Con_Ssl_Error +_ecore_con_ssl_server_prepare_gnutls(Ecore_Con_Server *svr, + int ssl_type) +{ + int ret; + + if (ssl_type & ECORE_CON_USE_SSL2) + return ECORE_CON_SSL_ERROR_SSL2_NOT_SUPPORTED; + + switch (ssl_type) + { + case ECORE_CON_USE_SSL3: + case ECORE_CON_USE_SSL3 | ECORE_CON_LOAD_CERT: + case ECORE_CON_USE_TLS: + case ECORE_CON_USE_TLS | ECORE_CON_LOAD_CERT: + case ECORE_CON_USE_MIXED: + case ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT: + break; + + default: + return ECORE_CON_SSL_ERROR_NONE; + } + + SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_certificate_allocate_credentials(&svr->cert)); + + if (svr->use_cert) + { + if (svr->created) + { + SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_dh_params_init(&svr->dh_params)); + INF("Generating DH params"); + SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_dh_params_generate2(svr->dh_params, 1024)); + + SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_anon_allocate_server_credentials(&svr->anoncred_s)); + /* TODO: implement PSK */ + // SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_psk_allocate_server_credentials(&svr->pskcred_s)); + + gnutls_anon_set_server_dh_params(svr->anoncred_s, svr->dh_params); + gnutls_certificate_set_dh_params(svr->cert, svr->dh_params); + //gnutls_psk_set_server_dh_params(svr->pskcred_s, svr->dh_params); + INF("DH params successfully generated and applied!"); + } + else + { + //SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_psk_allocate_client_credentials(&svr->pskcred_c)); + SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_anon_allocate_client_credentials(&svr->anoncred_c)); + } + } + + svr->ssl_prepared = EINA_TRUE; + return ECORE_CON_SSL_ERROR_NONE; + +error: + _gnutls_print_errors(svr, ECORE_CON_EVENT_SERVER_ERROR, ret); + _ecore_con_ssl_server_shutdown_gnutls(svr); + return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED; +} + + +static Ecore_Con_Ssl_Error +_ecore_con_ssl_server_init_gnutls(Ecore_Con_Server *svr) +{ + const gnutls_datum_t *cert_list; + unsigned int iter, cert_list_size; + gnutls_x509_crt_t cert = NULL; + const char *priority = "NONE:%VERIFY_ALLOW_X509_V1_CA_CRT:+RSA:+DHE-RSA:+DHE-DSS:+ANON-DH:+COMP-DEFLATE:+COMP-NULL:+CTYPE-X509:+SHA1:+SHA256:+SHA384:+SHA512:+AES-256-CBC:+AES-128-CBC:+3DES-CBC:+VERS-TLS1.2:+VERS-TLS1.1:+VERS-TLS1.0:+VERS-SSL3.0"; + int ret = 0; + + switch (svr->ssl_state) + { + case ECORE_CON_SSL_STATE_DONE: + return ECORE_CON_SSL_ERROR_NONE; + + case ECORE_CON_SSL_STATE_INIT: + if (svr->type & ECORE_CON_USE_SSL2) /* not supported because of security issues */ + return ECORE_CON_SSL_ERROR_SSL2_NOT_SUPPORTED; + + switch (svr->type & ECORE_CON_SSL) + { + case ECORE_CON_USE_SSL3: + case ECORE_CON_USE_SSL3 | ECORE_CON_LOAD_CERT: + priority = "NONE:%VERIFY_ALLOW_X509_V1_CA_CRT:+RSA:+DHE-RSA:+DHE-DSS:+ANON-DH:+COMP-DEFLATE:+COMP-NULL:+CTYPE-X509:+SHA1:+SHA256:+SHA384:+SHA512:+AES-256-CBC:+AES-128-CBC:+3DES-CBC:!VERS-TLS1.0:!VERS-TLS1.1"; + break; + + case ECORE_CON_USE_TLS: + case ECORE_CON_USE_TLS | ECORE_CON_LOAD_CERT: + priority = "NONE:%VERIFY_ALLOW_X509_V1_CA_CRT:+RSA:+DHE-RSA:+DHE-DSS:+ANON-DH:+COMP-DEFLATE:+COMP-NULL:+CTYPE-X509:+SHA1:+SHA256:+SHA384:+SHA512:+AES-256-CBC:+AES-128-CBC:+3DES-CBC:!VERS-SSL3.0"; + break; + + case ECORE_CON_USE_MIXED: + case ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT: + break; + + default: + return ECORE_CON_SSL_ERROR_NONE; + } + + SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_init(&svr->session, GNUTLS_CLIENT)); + SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_session_ticket_enable_client(svr->session)); + SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_server_name_set(svr->session, GNUTLS_NAME_DNS, svr->name, strlen(svr->name))); + INF("Applying priority string: %s", priority); + SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_priority_set_direct(svr->session, priority, NULL)); + SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(svr->session, GNUTLS_CRD_CERTIFICATE, svr->cert)); + // SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(svr->session, GNUTLS_CRD_PSK, svr->pskcred_c)); + if (!svr->use_cert) + SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(svr->session, GNUTLS_CRD_ANON, svr->anoncred_c)); + + gnutls_dh_set_prime_bits(svr->session, 512); + gnutls_transport_set_ptr(svr->session, (gnutls_transport_ptr_t)((intptr_t)svr->fd)); + svr->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING; + + case ECORE_CON_SSL_STATE_HANDSHAKING: + if (!svr->session) + { + DBG("Server was previously lost, going to error condition"); + goto error; + } + ret = gnutls_handshake(svr->session); + DBG("calling gnutls_handshake(): returned with '%s'", gnutls_strerror_name(ret)); + SSL_ERROR_CHECK_GOTO_ERROR(gnutls_error_is_fatal(ret)); + if (!ret) + { + svr->handshaking = EINA_FALSE; + svr->ssl_state = ECORE_CON_SSL_STATE_DONE; + } + else + { + if (gnutls_record_get_direction(svr->session)) + ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE); + else + ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ); + return ECORE_CON_SSL_ERROR_NONE; + } + + default: + break; + } + + if ((!svr->verify) && (!svr->verify_basic)) + /* not verifying certificates, so we're done! */ + return ECORE_CON_SSL_ERROR_NONE; + if (svr->verify) + { + /* use CRL/CA lists to verify */ + SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_certificate_verify_peers2(svr->session, &iter)); + if (iter & GNUTLS_CERT_INVALID) + ERR("The certificate is not trusted."); + else if (iter & GNUTLS_CERT_SIGNER_NOT_FOUND) + ERR("The certificate hasn't got a known issuer."); + else if (iter & GNUTLS_CERT_REVOKED) + ERR("The certificate has been revoked."); + else if (iter & GNUTLS_CERT_EXPIRED) + ERR("The certificate has expired"); + else if (iter & GNUTLS_CERT_NOT_ACTIVATED) + ERR("The certificate is not yet activated"); + + if (iter) + goto error; + } + if (gnutls_certificate_type_get(svr->session) != GNUTLS_CRT_X509) + { + ERR("Warning: PGP certificates are not yet supported!"); + goto error; + } + + SSL_ERROR_CHECK_GOTO_ERROR(!(cert_list = gnutls_certificate_get_peers(svr->session, &cert_list_size))); + SSL_ERROR_CHECK_GOTO_ERROR(!cert_list_size); + + _gnutls_print_session(cert_list, cert_list_size); + + SSL_ERROR_CHECK_GOTO_ERROR(gnutls_x509_crt_init(&cert)); + SSL_ERROR_CHECK_GOTO_ERROR(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER)); + + SSL_ERROR_CHECK_GOTO_ERROR(!gnutls_x509_crt_check_hostname(cert, svr->verify_name ?: svr->name)); + gnutls_x509_crt_deinit(cert); + DBG("SSL certificate verification succeeded!"); + return ECORE_CON_SSL_ERROR_NONE; + +error: + _gnutls_print_errors(svr, ECORE_CON_EVENT_SERVER_ERROR, ret); + if ((ret == GNUTLS_E_WARNING_ALERT_RECEIVED) || (ret == GNUTLS_E_FATAL_ALERT_RECEIVED)) + ERR("Also received alert: %s", gnutls_alert_get_name(gnutls_alert_get(svr->session))); + if (svr->session && (svr->ssl_state != ECORE_CON_SSL_STATE_DONE)) + { + ERR("last out: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_out(svr->session))); + ERR("last in: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_in(svr->session))); + } + if (cert) + gnutls_x509_crt_deinit(cert); + _ecore_con_ssl_server_shutdown_gnutls(svr); + return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED; +} + +static Eina_Bool +_ecore_con_ssl_server_cafile_add_gnutls(Ecore_Con_Server *svr, + const char *ca_file) +{ + struct stat st; + Eina_Iterator *it; + const char *file; + Eina_Bool error = EINA_FALSE; + + if (stat(ca_file, &st)) return EINA_FALSE; + if (S_ISDIR(st.st_mode)) + { + it = eina_file_ls(ca_file); + SSL_ERROR_CHECK_GOTO_ERROR(!it); + EINA_ITERATOR_FOREACH(it, file) + { + if (!error) + { + if (gnutls_certificate_set_x509_trust_file(svr->cert, file, GNUTLS_X509_FMT_PEM) < 1) + error++; + } + eina_stringshare_del(file); + } + eina_iterator_free(it); + } + else + SSL_ERROR_CHECK_GOTO_ERROR(gnutls_certificate_set_x509_trust_file(svr->cert, ca_file, + GNUTLS_X509_FMT_PEM) < 1); + + return !error; +error: + ERR("Could not load CA file!"); + return EINA_FALSE; +} + +static Eina_Bool +_ecore_con_ssl_server_crl_add_gnutls(Ecore_Con_Server *svr, + const char *crl_file) +{ + SSL_ERROR_CHECK_GOTO_ERROR(gnutls_certificate_set_x509_crl_file(svr->cert, crl_file, + GNUTLS_X509_FMT_PEM) < 1); + + return EINA_TRUE; +error: + ERR("Could not load CRL file!"); + return EINA_FALSE; +} + +static Eina_Bool +_ecore_con_ssl_server_privkey_add_gnutls(Ecore_Con_Server *svr, + const char *key_file) +{ + SSL_ERROR_CHECK_GOTO_ERROR(gnutls_certificate_set_x509_key_file(svr->cert, svr->cert_file, key_file, + GNUTLS_X509_FMT_PEM)); + + return EINA_TRUE; +error: + ERR("Could not load certificate/key file!"); + return EINA_FALSE; +} + +static Eina_Bool +_ecore_con_ssl_server_cert_add_gnutls(Ecore_Con_Server *svr, + const char *cert_file) +{ + if (!(svr->cert_file = strdup(cert_file))) + return EINA_FALSE; + + return EINA_TRUE; +} + +static Ecore_Con_Ssl_Error +_ecore_con_ssl_server_shutdown_gnutls(Ecore_Con_Server *svr) +{ + if (svr->session) + { + gnutls_bye(svr->session, GNUTLS_SHUT_RDWR); + gnutls_deinit(svr->session); + } + + free(svr->cert_file); + svr->cert_file = NULL; + if (svr->cert) + gnutls_certificate_free_credentials(svr->cert); + svr->cert = NULL; + + if ((svr->type & ECORE_CON_SSL) && svr->created) + { + if (svr->dh_params) + { + gnutls_dh_params_deinit(svr->dh_params); + svr->dh_params = NULL; + } + if (svr->anoncred_s) + gnutls_anon_free_server_credentials(svr->anoncred_s); + // if (svr->pskcred_s) + // gnutls_psk_free_server_credentials(svr->pskcred_s); + + svr->anoncred_s = NULL; + svr->pskcred_s = NULL; + } + else if (svr->type & ECORE_CON_SSL) + { + if (svr->anoncred_c) + gnutls_anon_free_client_credentials(svr->anoncred_c); + // if (svr->pskcred_c) + // gnutls_psk_free_client_credentials(svr->pskcred_c); + + svr->anoncred_c = NULL; + svr->pskcred_c = NULL; + } + + svr->session = NULL; + + return ECORE_CON_SSL_ERROR_NONE; +} + +static int +_ecore_con_ssl_server_read_gnutls(Ecore_Con_Server *svr, + unsigned char *buf, + int size) +{ + int num; + + if (svr->ssl_state == ECORE_CON_SSL_STATE_HANDSHAKING) + { + DBG("Continuing gnutls handshake"); + if (!_ecore_con_ssl_server_init_gnutls(svr)) + return 0; + return -1; + } + + num = gnutls_record_recv(svr->session, buf, size); + if (num > 0) + return num; + + if (num == GNUTLS_E_REHANDSHAKE) + { + WRN("Rehandshake request ignored"); + return 0; + + svr->handshaking = EINA_TRUE; + svr->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING; + if (!_ecore_con_ssl_server_init_gnutls(svr)) + return 0; + } + else if ((!gnutls_error_is_fatal(num)) && (num != GNUTLS_E_SUCCESS)) + return 0; + + return -1; +} + +static int +_ecore_con_ssl_server_write_gnutls(Ecore_Con_Server *svr, + const unsigned char *buf, + int size) +{ + int num; + + if (svr->ssl_state == ECORE_CON_SSL_STATE_HANDSHAKING) + { + DBG("Continuing gnutls handshake"); + if (!_ecore_con_ssl_server_init_gnutls(svr)) + return 0; + return -1; + } + + num = gnutls_record_send(svr->session, buf, size); + if (num > 0) + return num; + + if (num == GNUTLS_E_REHANDSHAKE) + { + WRN("Rehandshake request ignored"); + return 0; +/* this is only partly functional I think? */ + svr->handshaking = EINA_TRUE; + svr->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING; + if (!_ecore_con_ssl_server_init_gnutls(svr)) + return 0; + } + else if (!gnutls_error_is_fatal(num)) + return 0; + + return -1; +} + +static Ecore_Con_Ssl_Error +_ecore_con_ssl_client_init_gnutls(Ecore_Con_Client *cl) +{ + const gnutls_datum_t *cert_list; + unsigned int iter, cert_list_size; + const char *priority = "NONE:%VERIFY_ALLOW_X509_V1_CA_CRT:+RSA:+DHE-RSA:+DHE-DSS:+ANON-DH:+COMP-DEFLATE:+COMP-NULL:+CTYPE-X509:+SHA1:+SHA256:+SHA384:+SHA512:+AES-256-CBC:+AES-128-CBC:+3DES-CBC:+VERS-TLS1.2:+VERS-TLS1.1:+VERS-TLS1.0:+VERS-SSL3.0"; + int ret = 0; + + switch (cl->ssl_state) + { + case ECORE_CON_SSL_STATE_DONE: + return ECORE_CON_SSL_ERROR_NONE; + + case ECORE_CON_SSL_STATE_INIT: + if (cl->host_server->type & ECORE_CON_USE_SSL2) /* not supported because of security issues */ + return ECORE_CON_SSL_ERROR_SSL2_NOT_SUPPORTED; + + switch (cl->host_server->type & ECORE_CON_SSL) + { + case ECORE_CON_USE_SSL3: + case ECORE_CON_USE_SSL3 | ECORE_CON_LOAD_CERT: + priority = "NONE:%VERIFY_ALLOW_X509_V1_CA_CRT:+RSA:+DHE-RSA:+DHE-DSS:+ANON-DH:+COMP-DEFLATE:+COMP-NULL:+CTYPE-X509:+SHA1:+SHA256:+SHA384:+SHA512:+AES-256-CBC:+AES-128-CBC:+3DES-CBC:!VERS-TLS1.0:!VERS-TLS1.1"; + break; + + case ECORE_CON_USE_TLS: + case ECORE_CON_USE_TLS | ECORE_CON_LOAD_CERT: + priority = "NONE:%VERIFY_ALLOW_X509_V1_CA_CRT:+RSA:+DHE-RSA:+DHE-DSS:+ANON-DH:+COMP-DEFLATE:+COMP-NULL:+CTYPE-X509:+SHA1:+SHA256:+SHA384:+SHA512:+AES-256-CBC:+AES-128-CBC:+3DES-CBC:!VERS-SSL3.0"; + break; + + case ECORE_CON_USE_MIXED: + case ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT: + break; + + default: + return ECORE_CON_SSL_ERROR_NONE; + } + + _client_connected++; + + SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_init(&cl->session, GNUTLS_SERVER)); + SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_session_ticket_key_generate(&cl->session_ticket)); + SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_session_ticket_enable_server(cl->session, &cl->session_ticket)); + INF("Applying priority string: %s", priority); + SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_priority_set_direct(cl->session, priority, NULL)); + SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(cl->session, GNUTLS_CRD_CERTIFICATE, cl->host_server->cert)); + // SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(cl->session, GNUTLS_CRD_PSK, cl->host_server->pskcred_s)); + if (!cl->host_server->use_cert) + SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(cl->session, GNUTLS_CRD_ANON, cl->host_server->anoncred_s)); + + gnutls_certificate_server_set_request(cl->session, GNUTLS_CERT_REQUEST); + + gnutls_dh_set_prime_bits(cl->session, 2048); + gnutls_transport_set_ptr(cl->session, (gnutls_transport_ptr_t)((intptr_t)cl->fd)); + cl->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING; + + case ECORE_CON_SSL_STATE_HANDSHAKING: + if (!cl->session) + { + DBG("Client was previously lost, going to error condition"); + goto error; + } + DBG("calling gnutls_handshake()"); + ret = gnutls_handshake(cl->session); + SSL_ERROR_CHECK_GOTO_ERROR(gnutls_error_is_fatal(ret)); + + if (!ret) + { + cl->handshaking = EINA_FALSE; + cl->ssl_state = ECORE_CON_SSL_STATE_DONE; + } + else + { + if (gnutls_record_get_direction(cl->session)) + ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_WRITE); + else + ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ); + return ECORE_CON_SSL_ERROR_NONE; + } + + default: + break; + } + + if (!cl->host_server->verify) + /* not verifying certificates, so we're done! */ + return ECORE_CON_SSL_ERROR_NONE; + /* use CRL/CA lists to verify */ + SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_certificate_verify_peers2(cl->session, &iter)); + if (iter & GNUTLS_CERT_INVALID) + ERR("The certificate is not trusted."); + else if (iter & GNUTLS_CERT_SIGNER_NOT_FOUND) + ERR("The certificate hasn't got a known issuer."); + else if (iter & GNUTLS_CERT_REVOKED) + ERR("The certificate has been revoked."); + else if (iter & GNUTLS_CERT_EXPIRED) + ERR("The certificate has expired"); + else if (iter & GNUTLS_CERT_NOT_ACTIVATED) + ERR("The certificate is not yet activated"); + + if (iter) + goto error; + if (gnutls_certificate_type_get(cl->session) != GNUTLS_CRT_X509) + { + ERR("Warning: PGP certificates are not yet supported!"); + goto error; + } + + SSL_ERROR_CHECK_GOTO_ERROR(!(cert_list = gnutls_certificate_get_peers(cl->session, &cert_list_size))); + SSL_ERROR_CHECK_GOTO_ERROR(!cert_list_size); + + _gnutls_print_session(cert_list, cert_list_size); +/* + gnutls_x509_crt_t cert = NULL; + SSL_ERROR_CHECK_GOTO_ERROR(gnutls_x509_crt_init(&cert)); + SSL_ERROR_CHECK_GOTO_ERROR(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER)); + + SSL_ERROR_CHECK_GOTO_ERROR(!gnutls_x509_crt_check_hostname(cert, cl->host_server->name)); + gnutls_x509_crt_deinit(cert); +*/ + DBG("SSL certificate verification succeeded!"); + return ECORE_CON_SSL_ERROR_NONE; + +error: + _gnutls_print_errors(cl, ECORE_CON_EVENT_CLIENT_ERROR, ret); + if ((ret == GNUTLS_E_WARNING_ALERT_RECEIVED) || (ret == GNUTLS_E_FATAL_ALERT_RECEIVED)) + ERR("Also received alert: %s", gnutls_alert_get_name(gnutls_alert_get(cl->session))); + if (cl->session && (cl->ssl_state != ECORE_CON_SSL_STATE_DONE)) + { + ERR("last out: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_out(cl->session))); + ERR("last in: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_in(cl->session))); + } +/* + if (cert) + gnutls_x509_crt_deinit(cert); +*/ + _ecore_con_ssl_client_shutdown_gnutls(cl); + return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED; +} + +static Ecore_Con_Ssl_Error +_ecore_con_ssl_client_shutdown_gnutls(Ecore_Con_Client *cl) +{ + if (cl->session) + { + gnutls_bye(cl->session, GNUTLS_SHUT_RDWR); + gnutls_deinit(cl->session); + gnutls_free(cl->session_ticket.data); + cl->session_ticket.data = NULL; + } + + cl->session = NULL; + + return ECORE_CON_SSL_ERROR_NONE; +} + +static int +_ecore_con_ssl_client_read_gnutls(Ecore_Con_Client *cl, + unsigned char *buf, + int size) +{ + int num; + + if (cl->ssl_state == ECORE_CON_SSL_STATE_HANDSHAKING) + { + if (!_ecore_con_ssl_client_init_gnutls(cl)) + return 0; + return -1; + } + + num = gnutls_record_recv(cl->session, buf, size); + if (num > 0) + return num; + + if (num == GNUTLS_E_REHANDSHAKE) + { + WRN("Rehandshake request ignored"); + return 0; + cl->handshaking = EINA_TRUE; + cl->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING; + if (!_ecore_con_ssl_client_init_gnutls(cl)) + return 0; + WRN("Rehandshake request ignored"); + return 0; + } + else if ((!gnutls_error_is_fatal(num)) && (num != GNUTLS_E_SUCCESS)) + return 0; + + return -1; +} + +static int +_ecore_con_ssl_client_write_gnutls(Ecore_Con_Client *cl, + const unsigned char *buf, + int size) +{ + int num; + + if (cl->ssl_state == ECORE_CON_SSL_STATE_HANDSHAKING) + { + if (!_ecore_con_ssl_client_init_gnutls(cl)) + return 0; + return -1; + } + + num = gnutls_record_send(cl->session, buf, size); + if (num > 0) + return num; + + if (num == GNUTLS_E_REHANDSHAKE) + { + WRN("Rehandshake request ignored"); + return 0; + cl->handshaking = EINA_TRUE; + cl->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING; + if (!_ecore_con_ssl_client_init_gnutls(cl)) + return 0; + } + else if (!gnutls_error_is_fatal(num)) + return 0; + + return -1; +} + +#elif USE_OPENSSL && !USE_GNUTLS + +/* + * OpenSSL + */ + +static Ecore_Con_Ssl_Error +_ecore_con_ssl_init_openssl(void) +{ + SSL_library_init(); + SSL_load_error_strings(); + OpenSSL_add_all_algorithms(); + + return ECORE_CON_SSL_ERROR_NONE; +} + +static Ecore_Con_Ssl_Error +_ecore_con_ssl_shutdown_openssl(void) +{ + ERR_free_strings(); + EVP_cleanup(); + return ECORE_CON_SSL_ERROR_NONE; +} + +static Ecore_Con_Ssl_Error +_ecore_con_ssl_server_prepare_openssl(Ecore_Con_Server *svr, + int ssl_type) +{ + long options; + int dh = 0; + + if (ssl_type & ECORE_CON_USE_SSL2) + return ECORE_CON_SSL_ERROR_SSL2_NOT_SUPPORTED; + + switch (ssl_type) + { + case ECORE_CON_USE_SSL3: + case ECORE_CON_USE_SSL3 | ECORE_CON_LOAD_CERT: + if (!svr->created) + SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl_ctx = SSL_CTX_new(SSLv3_client_method()))); + else + SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl_ctx = SSL_CTX_new(SSLv3_server_method()))); + break; + + case ECORE_CON_USE_TLS: + case ECORE_CON_USE_TLS | ECORE_CON_LOAD_CERT: + if (!svr->created) + SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl_ctx = SSL_CTX_new(TLSv1_client_method()))); + else + SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl_ctx = SSL_CTX_new(TLSv1_server_method()))); + break; + + case ECORE_CON_USE_MIXED: + case ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT: + if (!svr->created) + SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl_ctx = SSL_CTX_new(SSLv23_client_method()))); + else + SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))); + options = SSL_CTX_get_options(svr->ssl_ctx); + SSL_CTX_set_options(svr->ssl_ctx, options | SSL_OP_NO_SSLv2 | SSL_OP_SINGLE_DH_USE); + break; + + default: + return ECORE_CON_SSL_ERROR_NONE; + } + + if ((!svr->use_cert) && svr->created) + { + DH *dh_params; + INF("Generating DH params"); + SSL_ERROR_CHECK_GOTO_ERROR(!(dh_params = DH_new())); + SSL_ERROR_CHECK_GOTO_ERROR(!DH_generate_parameters_ex(dh_params, 1024, DH_GENERATOR_5, NULL)); + SSL_ERROR_CHECK_GOTO_ERROR(!DH_check(dh_params, &dh)); + SSL_ERROR_CHECK_GOTO_ERROR((dh & DH_CHECK_P_NOT_PRIME) || (dh & DH_CHECK_P_NOT_SAFE_PRIME)); + SSL_ERROR_CHECK_GOTO_ERROR(!DH_generate_key(dh_params)); + SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_set_tmp_dh(svr->ssl_ctx, dh_params)); + DH_free(dh_params); + INF("DH params successfully generated and applied!"); + SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_set_cipher_list(svr->ssl_ctx, "aNULL:!eNULL:!LOW:!EXPORT:@STRENGTH")); + } + else if (!svr->use_cert) + SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_set_cipher_list(svr->ssl_ctx, "aNULL:!eNULL:!LOW:!EXPORT:!ECDH:RSA:AES:!PSK:@STRENGTH")); + + return ECORE_CON_SSL_ERROR_NONE; + +error: + if (dh) + { + if (dh & DH_CHECK_P_NOT_PRIME) + ERR("openssl error: dh_params could not generate a prime!"); + else + ERR("openssl error: dh_params could not generate a safe prime!"); + } + else + _openssl_print_errors(svr, ECORE_CON_EVENT_SERVER_ERROR); + _ecore_con_ssl_server_shutdown_openssl(svr); + return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED; +} + +static Ecore_Con_Ssl_Error +_ecore_con_ssl_server_init_openssl(Ecore_Con_Server *svr) +{ + int ret = -1; + + switch (svr->ssl_state) + { + case ECORE_CON_SSL_STATE_DONE: + return ECORE_CON_SSL_ERROR_NONE; + + case ECORE_CON_SSL_STATE_INIT: + SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl = SSL_new(svr->ssl_ctx))); + + SSL_ERROR_CHECK_GOTO_ERROR(!SSL_set_fd(svr->ssl, svr->fd)); + SSL_set_connect_state(svr->ssl); + svr->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING; + + case ECORE_CON_SSL_STATE_HANDSHAKING: + if (!svr->ssl) + { + DBG("Server was previously lost, going to error condition"); + goto error; + } + ret = SSL_do_handshake(svr->ssl); + svr->ssl_err = SSL_get_error(svr->ssl, ret); + SSL_ERROR_CHECK_GOTO_ERROR((svr->ssl_err == SSL_ERROR_SYSCALL) || (svr->ssl_err == SSL_ERROR_SSL)); + + if (ret == 1) + { + svr->handshaking = EINA_FALSE; + svr->ssl_state = ECORE_CON_SSL_STATE_DONE; + } + else + { + if (svr->ssl_err == SSL_ERROR_WANT_READ) + ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ); + else if (svr->ssl_err == SSL_ERROR_WANT_WRITE) + ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE); + return ECORE_CON_SSL_ERROR_NONE; + } + + default: + break; + } + + _openssl_print_session(svr->ssl); + if ((!svr->verify) && (!svr->verify_basic)) + /* not verifying certificates, so we're done! */ + return ECORE_CON_SSL_ERROR_NONE; + + { + X509 *cert; + SSL_set_verify(svr->ssl, SSL_VERIFY_PEER, NULL); + /* use CRL/CA lists to verify */ + cert = SSL_get_peer_certificate(svr->ssl); + if (cert) + { + char *c; + int clen; + int name = 0; + + if (svr->verify) + { + int err; + + err = SSL_get_verify_result(svr->ssl); + _openssl_print_verify_error(err); + SSL_ERROR_CHECK_GOTO_ERROR(err); + } + clen = X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_subject_alt_name, NULL, 0); + if (clen > 0) + name = NID_subject_alt_name; + else + clen = X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName, NULL, 0); + SSL_ERROR_CHECK_GOTO_ERROR(clen < 1); + if (!name) name = NID_commonName; + c = alloca(++clen); + X509_NAME_get_text_by_NID(X509_get_subject_name(cert), name, c, clen); + INF("CERT NAME: %s\n", c); + SSL_ERROR_CHECK_GOTO_ERROR(!_openssl_name_verify(c, svr->verify_name ?: svr->name)); + } + } + + DBG("SSL certificate verification succeeded!"); + + return ECORE_CON_SSL_ERROR_NONE; + +error: + _openssl_print_errors(svr, ECORE_CON_EVENT_SERVER_ERROR); + _ecore_con_ssl_server_shutdown_openssl(svr); + return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED; +} + +static Eina_Bool +_ecore_con_ssl_server_cafile_add_openssl(Ecore_Con_Server *svr, + const char *ca_file) +{ + struct stat st; + + if (stat(ca_file, &st)) return EINA_FALSE; + if (S_ISDIR(st.st_mode)) + SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_load_verify_locations(svr->ssl_ctx, NULL, ca_file)); + else + SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_load_verify_locations(svr->ssl_ctx, ca_file, NULL)); + return EINA_TRUE; + +error: + _openssl_print_errors(svr, ECORE_CON_EVENT_SERVER_ERROR); + return EINA_FALSE; +} + +static Eina_Bool +_ecore_con_ssl_server_crl_add_openssl(Ecore_Con_Server *svr, + const char *crl_file) +{ + X509_STORE *st; + X509_LOOKUP *lu; + static Eina_Bool flag = EINA_FALSE; + + SSL_ERROR_CHECK_GOTO_ERROR(!(st = SSL_CTX_get_cert_store(svr->ssl_ctx))); + SSL_ERROR_CHECK_GOTO_ERROR(!(lu = X509_STORE_add_lookup(st, X509_LOOKUP_file()))); + SSL_ERROR_CHECK_GOTO_ERROR(X509_load_crl_file(lu, crl_file, X509_FILETYPE_PEM) < 1); + if (!flag) + { + X509_STORE_set_flags(st, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); + flag = EINA_TRUE; + } + + return EINA_TRUE; + +error: + _openssl_print_errors(svr, ECORE_CON_EVENT_SERVER_ERROR); + return EINA_FALSE; +} + +static Eina_Bool +_ecore_con_ssl_server_privkey_add_openssl(Ecore_Con_Server *svr, + const char *key_file) +{ + FILE *fp = NULL; + EVP_PKEY *privkey = NULL; + + if (!(fp = fopen(key_file, "r"))) + goto error; + + SSL_ERROR_CHECK_GOTO_ERROR(!(privkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL))); + + fclose(fp); + SSL_ERROR_CHECK_GOTO_ERROR(SSL_CTX_use_PrivateKey(svr->ssl_ctx, privkey) < 1); + SSL_ERROR_CHECK_GOTO_ERROR(SSL_CTX_check_private_key(svr->ssl_ctx) < 1); + + return EINA_TRUE; + +error: + if (fp) + fclose(fp); + _openssl_print_errors(svr, ECORE_CON_EVENT_SERVER_ERROR); + return EINA_FALSE; +} + +static Eina_Bool +_ecore_con_ssl_server_cert_add_openssl(Ecore_Con_Server *svr, + const char *cert_file) +{ + FILE *fp = NULL; + X509 *cert = NULL; + + if (!(fp = fopen(cert_file, "r"))) + goto error; + + SSL_ERROR_CHECK_GOTO_ERROR(!(cert = PEM_read_X509(fp, NULL, NULL, NULL))); + + fclose(fp); + + SSL_ERROR_CHECK_GOTO_ERROR(SSL_CTX_use_certificate(svr->ssl_ctx, cert) < 1); + + return EINA_TRUE; + +error: + if (fp) + fclose(fp); + _openssl_print_errors(svr, ECORE_CON_EVENT_SERVER_ERROR); + return EINA_FALSE; +} + +static Ecore_Con_Ssl_Error +_ecore_con_ssl_server_shutdown_openssl(Ecore_Con_Server *svr) +{ + if (svr->ssl) + { + if (!SSL_shutdown(svr->ssl)) + SSL_shutdown(svr->ssl); + + SSL_free(svr->ssl); + } + + if (svr->ssl_ctx) + SSL_CTX_free(svr->ssl_ctx); + + svr->ssl = NULL; + svr->ssl_ctx = NULL; + svr->ssl_err = SSL_ERROR_NONE; + + return ECORE_CON_SSL_ERROR_NONE; +} + +static int +_ecore_con_ssl_server_read_openssl(Ecore_Con_Server *svr, + unsigned char *buf, + int size) +{ + int num; + + if (!svr->ssl) return -1; + num = SSL_read(svr->ssl, buf, size); + svr->ssl_err = SSL_get_error(svr->ssl, num); + + if (svr->fd_handler) + { + if (svr->ssl && svr->ssl_err == SSL_ERROR_WANT_READ) + ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ); + else if (svr->ssl && svr->ssl_err == SSL_ERROR_WANT_WRITE) + ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE); + } + + if ((svr->ssl_err == SSL_ERROR_ZERO_RETURN) || + (svr->ssl_err == SSL_ERROR_SYSCALL) || + (svr->ssl_err == SSL_ERROR_SSL)) + return -1; + + if (num < 0) + return 0; + + return num; +} + +static int +_ecore_con_ssl_server_write_openssl(Ecore_Con_Server *svr, + const unsigned char *buf, + int size) +{ + int num; + + num = SSL_write(svr->ssl, buf, size); + svr->ssl_err = SSL_get_error(svr->ssl, num); + + if (svr->fd_handler) + { + if (svr->ssl && svr->ssl_err == SSL_ERROR_WANT_READ) + ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ); + else if (svr->ssl && svr->ssl_err == SSL_ERROR_WANT_WRITE) + ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE); + } + + if ((svr->ssl_err == SSL_ERROR_ZERO_RETURN) || + (svr->ssl_err == SSL_ERROR_SYSCALL) || + (svr->ssl_err == SSL_ERROR_SSL)) + return -1; + + if (num < 0) + return 0; + + return num; +} + +static Ecore_Con_Ssl_Error +_ecore_con_ssl_client_init_openssl(Ecore_Con_Client *cl) +{ + int ret = -1; + switch (cl->ssl_state) + { + case ECORE_CON_SSL_STATE_DONE: + return ECORE_CON_SSL_ERROR_NONE; + + case ECORE_CON_SSL_STATE_INIT: + SSL_ERROR_CHECK_GOTO_ERROR(!(cl->ssl = SSL_new(cl->host_server->ssl_ctx))); + + SSL_ERROR_CHECK_GOTO_ERROR(!SSL_set_fd(cl->ssl, cl->fd)); + SSL_set_accept_state(cl->ssl); + cl->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING; + + case ECORE_CON_SSL_STATE_HANDSHAKING: + if (!cl->ssl) + { + DBG("Client was previously lost, going to error condition"); + goto error; + } + ret = SSL_do_handshake(cl->ssl); + cl->ssl_err = SSL_get_error(cl->ssl, ret); + SSL_ERROR_CHECK_GOTO_ERROR((cl->ssl_err == SSL_ERROR_SYSCALL) || (cl->ssl_err == SSL_ERROR_SSL)); + if (ret == 1) + { + cl->handshaking = EINA_FALSE; + cl->ssl_state = ECORE_CON_SSL_STATE_DONE; + } + else + { + if (cl->ssl_err == SSL_ERROR_WANT_READ) + ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ); + else if (cl->ssl_err == SSL_ERROR_WANT_WRITE) + ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_WRITE); + return ECORE_CON_SSL_ERROR_NONE; + } + + default: + break; + } + + _openssl_print_session(cl->ssl); + if (!cl->host_server->verify) + /* not verifying certificates, so we're done! */ + return ECORE_CON_SSL_ERROR_NONE; + SSL_set_verify(cl->ssl, SSL_VERIFY_PEER, NULL); + /* use CRL/CA lists to verify */ + if (SSL_get_peer_certificate(cl->ssl)) + { + int err; + + err = SSL_get_verify_result(cl->ssl); + _openssl_print_verify_error(err); + SSL_ERROR_CHECK_GOTO_ERROR(err); + } + + return ECORE_CON_SSL_ERROR_NONE; + +error: + _openssl_print_errors(cl, ECORE_CON_EVENT_CLIENT_ERROR); + _ecore_con_ssl_client_shutdown_openssl(cl); + return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED; +} + +static Ecore_Con_Ssl_Error +_ecore_con_ssl_client_shutdown_openssl(Ecore_Con_Client *cl) +{ + if (cl->ssl) + { + if (!SSL_shutdown(cl->ssl)) + SSL_shutdown(cl->ssl); + + SSL_free(cl->ssl); + } + + cl->ssl = NULL; + cl->ssl_err = SSL_ERROR_NONE; + + return ECORE_CON_SSL_ERROR_NONE; +} + +static int +_ecore_con_ssl_client_read_openssl(Ecore_Con_Client *cl, + unsigned char *buf, + int size) +{ + int num; + + if (!cl->ssl) return -1; + num = SSL_read(cl->ssl, buf, size); + cl->ssl_err = SSL_get_error(cl->ssl, num); + + if (cl->fd_handler) + { + if (cl->ssl && cl->ssl_err == SSL_ERROR_WANT_READ) + ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ); + else if (cl->ssl && cl->ssl_err == SSL_ERROR_WANT_WRITE) + ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_WRITE); + } + + if ((cl->ssl_err == SSL_ERROR_ZERO_RETURN) || + (cl->ssl_err == SSL_ERROR_SYSCALL) || + (cl->ssl_err == SSL_ERROR_SSL)) + return -1; + + if (num < 0) + return 0; + + return num; +} + +static int +_ecore_con_ssl_client_write_openssl(Ecore_Con_Client *cl, + const unsigned char *buf, + int size) +{ + int num; + + num = SSL_write(cl->ssl, buf, size); + cl->ssl_err = SSL_get_error(cl->ssl, num); + + if (cl->fd_handler) + { + if (cl->ssl && cl->ssl_err == SSL_ERROR_WANT_READ) + ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ); + else if (cl->ssl && cl->ssl_err == SSL_ERROR_WANT_WRITE) + ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_WRITE); + } + + if ((cl->ssl_err == SSL_ERROR_ZERO_RETURN) || + (cl->ssl_err == SSL_ERROR_SYSCALL) || + (cl->ssl_err == SSL_ERROR_SSL)) + return -1; + + if (num < 0) + return 0; + + return num; +} + +#else + +/* + * No Ssl + */ + +static Ecore_Con_Ssl_Error +_ecore_con_ssl_init_none(void) +{ + return ECORE_CON_SSL_ERROR_NONE; +} + +static Ecore_Con_Ssl_Error +_ecore_con_ssl_shutdown_none(void) +{ + return ECORE_CON_SSL_ERROR_NONE; +} + +static Ecore_Con_Ssl_Error +_ecore_con_ssl_server_prepare_none(Ecore_Con_Server *svr __UNUSED__, + int ssl_type __UNUSED__) +{ + return ECORE_CON_SSL_ERROR_NONE; +} + +static Ecore_Con_Ssl_Error +_ecore_con_ssl_server_init_none(Ecore_Con_Server *svr __UNUSED__) +{ + return ECORE_CON_SSL_ERROR_NOT_SUPPORTED; +} + +static Eina_Bool +_ecore_con_ssl_server_cafile_add_none(Ecore_Con_Server *svr __UNUSED__, + const char *ca_file __UNUSED__) +{ + return EINA_FALSE; +} + +static Eina_Bool +_ecore_con_ssl_server_cert_add_none(Ecore_Con_Server *svr __UNUSED__, + const char *cert_file __UNUSED__) +{ + return EINA_FALSE; +} + +static Eina_Bool +_ecore_con_ssl_server_privkey_add_none(Ecore_Con_Server *svr __UNUSED__, + const char *key_file __UNUSED__) +{ + return EINA_FALSE; +} + +static Eina_Bool +_ecore_con_ssl_server_crl_add_none(Ecore_Con_Server *svr __UNUSED__, + const char *crl_file __UNUSED__) +{ + return EINA_FALSE; +} + +static Ecore_Con_Ssl_Error +_ecore_con_ssl_server_shutdown_none(Ecore_Con_Server *svr __UNUSED__) +{ + return ECORE_CON_SSL_ERROR_NOT_SUPPORTED; +} + +static int +_ecore_con_ssl_server_read_none(Ecore_Con_Server *svr __UNUSED__, + unsigned char *buf __UNUSED__, + int size __UNUSED__) +{ + return -1; +} + +static int +_ecore_con_ssl_server_write_none(Ecore_Con_Server *svr __UNUSED__, + const unsigned char *buf __UNUSED__, + int size __UNUSED__) +{ + return -1; +} + +static Ecore_Con_Ssl_Error +_ecore_con_ssl_client_init_none(Ecore_Con_Client *cl __UNUSED__) +{ + return ECORE_CON_SSL_ERROR_NOT_SUPPORTED; +} + +static Ecore_Con_Ssl_Error +_ecore_con_ssl_client_shutdown_none(Ecore_Con_Client *cl __UNUSED__) +{ + return ECORE_CON_SSL_ERROR_NOT_SUPPORTED; +} + +static int +_ecore_con_ssl_client_read_none(Ecore_Con_Client *cl __UNUSED__, + unsigned char *buf __UNUSED__, + int size __UNUSED__) +{ + return -1; +} + +static int +_ecore_con_ssl_client_write_none(Ecore_Con_Client *cl __UNUSED__, + const unsigned char *buf __UNUSED__, + int size __UNUSED__) +{ + return -1; +} + +#endif diff --git a/src/lib/ecore_con/ecore_con_url.c b/src/lib/ecore_con/ecore_con_url.c new file mode 100644 index 0000000..05f0678 --- /dev/null +++ b/src/lib/ecore_con/ecore_con_url.c @@ -0,0 +1,1635 @@ +/* + * For info on how to use libcurl, see: + * http://curl.haxx.se/libcurl/c/libcurl-tutorial.html + */ + +/* + * FIXME: Support more CURL features... + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#ifdef HAVE_WS2TCPIP_H +# include +#endif + +#ifdef HAVE_ESCAPE +# include +#endif + +#include "Ecore.h" +#include "ecore_private.h" +#include "Ecore_Con.h" +#include "ecore_con_private.h" + +#define CURL_MIN_TIMEOUT 100 + +int ECORE_CON_EVENT_URL_DATA = 0; +int ECORE_CON_EVENT_URL_COMPLETE = 0; +int ECORE_CON_EVENT_URL_PROGRESS = 0; + +#ifdef HAVE_CURL +static void _ecore_con_url_event_url_complete(Ecore_Con_Url *url_con, CURLMsg *curlmsg); +static void _ecore_con_url_multi_remove(Ecore_Con_Url *url_con); +static Eina_Bool _ecore_con_url_perform(Ecore_Con_Url *url_con); +static size_t _ecore_con_url_header_cb(void *ptr, size_t size, size_t nitems, void *stream); +static size_t _ecore_con_url_data_cb(void *buffer, size_t size, size_t nitems, void *userp); +static int _ecore_con_url_progress_cb(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow); +static size_t _ecore_con_url_read_cb(void *ptr, size_t size, size_t nitems, void *stream); +static void _ecore_con_event_url_free(Ecore_Con_Url *url_con, void *ev); +static Eina_Bool _ecore_con_url_timer(void *data); +static Eina_Bool _ecore_con_url_fd_handler(void *data, Ecore_Fd_Handler *fd_handler); +static Eina_Bool _ecore_con_url_timeout_cb(void *data); +static void _ecore_con_url_status_get(Ecore_Con_Url *url_con); + +static Eina_List *_url_con_list = NULL; +static Eina_List *_fd_hd_list = NULL; +static CURLM *_curlm = NULL; +static int _init_count = 0; +static Ecore_Timer *_curl_timer = NULL; +static Eina_Bool pipelining = EINA_FALSE; + +#endif + +/** + * @addtogroup Ecore_Con_Url_Group Ecore URL Connection Functions + * + * @{ + */ + +EAPI int +ecore_con_url_init(void) +{ +#ifdef HAVE_CURL + long ms; + if (++_init_count > 1) return _init_count; + + ECORE_CON_EVENT_URL_DATA = ecore_event_type_new(); + ECORE_CON_EVENT_URL_COMPLETE = ecore_event_type_new(); + ECORE_CON_EVENT_URL_PROGRESS = ecore_event_type_new(); + + // curl_global_init() is not thread safe! + if (curl_global_init(CURL_GLOBAL_ALL)) return --_init_count; + + _curlm = curl_multi_init(); + if (!_curlm) + { + curl_global_cleanup(); + return --_init_count; + } + + curl_multi_timeout(_curlm, &ms); + if (ms >= CURL_MIN_TIMEOUT || ms <= 0) ms = CURL_MIN_TIMEOUT; + + _curl_timer = ecore_timer_add((double)ms / 1000, _ecore_con_url_timer, NULL); + ecore_timer_freeze(_curl_timer); + + return _init_count; +#else + return 0; +#endif +} + +EAPI int +ecore_con_url_shutdown(void) +{ +#ifdef HAVE_CURL + Ecore_Con_Url *url_con; + Ecore_Fd_Handler *fd_handler; + if (_init_count == 0) return 0; + --_init_count; + if (_init_count) return _init_count; + + if (_curl_timer) + { + ecore_timer_del(_curl_timer); + _curl_timer = NULL; + } + + EINA_LIST_FREE(_url_con_list, url_con) + ecore_con_url_free(url_con); + EINA_LIST_FREE(_fd_hd_list, fd_handler) + ecore_main_fd_handler_del(fd_handler); + + if (_curlm) + { + curl_multi_cleanup(_curlm); + _curlm = NULL; + } + curl_global_cleanup(); + return 0; +#endif + return 1; +} + +EAPI void +ecore_con_url_pipeline_set(Eina_Bool enable) +{ +#ifdef HAVE_CURL + if (enable == pipelining) return; + curl_multi_setopt(_curlm, CURLMOPT_PIPELINING, !!enable); + pipelining = enable; +#else + return; + (void)enable; +#endif +} + +EAPI Eina_Bool +ecore_con_url_pipeline_get(void) +{ +#ifdef HAVE_CURL + return pipelining; +#endif + return EINA_FALSE; +} + +extern Ecore_Con_Socks *_ecore_con_proxy_global; + +EAPI Ecore_Con_Url * +ecore_con_url_new(const char *url) +{ +#ifdef HAVE_CURL + Ecore_Con_Url *url_con; + CURLcode ret; + + if (!_init_count) + return NULL; + + url_con = calloc(1, sizeof(Ecore_Con_Url)); + if (!url_con) + return NULL; + + url_con->write_fd = -1; + + url_con->curl_easy = curl_easy_init(); + if (!url_con->curl_easy) + { + free(url_con); + return NULL; + } + + ECORE_MAGIC_SET(url_con, ECORE_MAGIC_CON_URL); + + if (!ecore_con_url_url_set(url_con, url)) + { + ecore_con_url_free(url_con); + return NULL; + } + + // Read socks proxy + url_con->proxy_type = -1; + if (_ecore_con_proxy_global && _ecore_con_proxy_global->ip && + (_ecore_con_proxy_global->version == 4 || + _ecore_con_proxy_global->version == 5)) + { + char proxy[256]; + char host[256]; + + if (_ecore_con_proxy_global->version == 5) + { + if (_ecore_con_proxy_global->lookup) + snprintf(host, sizeof(host), "socks5h://%s", + _ecore_con_proxy_global->ip); + else snprintf(host, sizeof(host), "socks5://%s", + _ecore_con_proxy_global->ip); + } + else if (_ecore_con_proxy_global->version == 4) + { + if (_ecore_con_proxy_global->lookup) + snprintf(host, sizeof(host), "socks4a://%s", + _ecore_con_proxy_global->ip); + else snprintf(host, sizeof(host), "socks4://%s", + _ecore_con_proxy_global->ip); + } + + if (_ecore_con_proxy_global->port > 0 && + _ecore_con_proxy_global->port <= 65535) + snprintf(proxy, sizeof(proxy), "%s:%d", host, + _ecore_con_proxy_global->port); + else snprintf(proxy, sizeof(proxy), "%s", host); + + ecore_con_url_proxy_set(url_con, proxy); + ecore_con_url_proxy_username_set(url_con, + _ecore_con_proxy_global->username); + } + + ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_ENCODING, "gzip,deflate"); + if (ret != CURLE_OK) + { + ERR("Could not set CURLOPT_ENCODING to \"gzip,deflate\": %s", + curl_easy_strerror(ret)); + ecore_con_url_free(url_con); + return NULL; + } + + curl_easy_setopt(url_con->curl_easy, CURLOPT_WRITEFUNCTION, + _ecore_con_url_data_cb); + curl_easy_setopt(url_con->curl_easy, CURLOPT_WRITEDATA, url_con); + + curl_easy_setopt(url_con->curl_easy, CURLOPT_PROGRESSFUNCTION, + _ecore_con_url_progress_cb); + curl_easy_setopt(url_con->curl_easy, CURLOPT_PROGRESSDATA, url_con); + curl_easy_setopt(url_con->curl_easy, CURLOPT_NOPROGRESS, EINA_FALSE); + + curl_easy_setopt(url_con->curl_easy, CURLOPT_HEADERFUNCTION, + _ecore_con_url_header_cb); + curl_easy_setopt(url_con->curl_easy, CURLOPT_HEADERDATA, url_con); + + /* + * FIXME: Check that these timeouts are sensible defaults + * FIXME: Provide a means to change these timeouts + */ + curl_easy_setopt(url_con->curl_easy, CURLOPT_CONNECTTIMEOUT, 30); + curl_easy_setopt(url_con->curl_easy, CURLOPT_FOLLOWLOCATION, 1); + + return url_con; +#else + return NULL; + url = NULL; +#endif +} + +EAPI Ecore_Con_Url * +ecore_con_url_custom_new(const char *url, + const char *custom_request) +{ +#ifdef HAVE_CURL + Ecore_Con_Url *url_con; + CURLcode ret; + + if (!url) + return NULL; + + if (!custom_request) + return NULL; + + url_con = ecore_con_url_new(url); + + if (!url_con) + return NULL; + + ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_CUSTOMREQUEST, custom_request); + if (ret != CURLE_OK) + { + ERR("Could not set a custom request string: %s", + curl_easy_strerror(ret)); + ecore_con_url_free(url_con); + return NULL; + } + + return url_con; +#else + return NULL; + url = NULL; + custom_request = NULL; +#endif +} + +EAPI void +ecore_con_url_free(Ecore_Con_Url *url_con) +{ +#ifdef HAVE_CURL + char *s; + + if (!url_con) return; + + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_free"); + return; + } + + if (url_con->curl_easy) + { + // FIXME : How can we delete curl_easy's fds ?? (Curl do not give this info.) + // This cause "Failed to delete epoll fd xx!" error messages + curl_easy_setopt(url_con->curl_easy, CURLOPT_PROGRESSFUNCTION, NULL); + curl_easy_setopt(url_con->curl_easy, CURLOPT_NOPROGRESS, EINA_TRUE); + + if (url_con->multi) + { + _ecore_con_url_multi_remove(url_con); + _url_con_list = eina_list_remove(_url_con_list, url_con); + } + + curl_easy_cleanup(url_con->curl_easy); + } + if (url_con->timer) ecore_timer_del(url_con->timer); + + url_con->curl_easy = NULL; + url_con->timer = NULL; + url_con->dead = EINA_TRUE; + if (url_con->event_count) return; + ECORE_MAGIC_SET(url_con, ECORE_MAGIC_NONE); + + curl_slist_free_all(url_con->headers); + EINA_LIST_FREE(url_con->additional_headers, s) + free(s); + EINA_LIST_FREE(url_con->response_headers, s) + free(s); + eina_stringshare_del(url_con->url); + if (url_con->post_data) free(url_con->post_data); + free(url_con); +#else + return; + (void)url_con; +#endif +} + +EAPI const char * +ecore_con_url_url_get(Ecore_Con_Url *url_con) +{ +#ifdef HAVE_CURL + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, __func__); + return NULL; + } + return url_con->url; +#else + return NULL; + (void)url_con; +#endif +} + +EAPI int +ecore_con_url_status_code_get(Ecore_Con_Url *url_con) +{ +#ifdef HAVE_CURL + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, __func__); + return 0; + } + + if (url_con->status) return url_con->status; + _ecore_con_url_status_get(url_con); + return url_con->status; +#else + return -1; + (void)url_con; +#endif +} + +EAPI Eina_Bool +ecore_con_url_url_set(Ecore_Con_Url *url_con, const char *url) +{ +#ifdef HAVE_CURL + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_url_set"); + return EINA_FALSE; + } + + if (url_con->dead) return EINA_FALSE; + eina_stringshare_replace(&url_con->url, url); + + if (url_con->url) + curl_easy_setopt(url_con->curl_easy, CURLOPT_URL, + url_con->url); + else + curl_easy_setopt(url_con->curl_easy, CURLOPT_URL, ""); + + return EINA_TRUE; +#else + return EINA_FALSE; + (void)url; + (void)url_con; +#endif +} + +EAPI void +ecore_con_url_data_set(Ecore_Con_Url *url_con, void *data) +{ +#ifdef HAVE_CURL + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_data_set"); + return; + } + + url_con->data = data; +#else + return; + url_con = NULL; + data = NULL; +#endif +} + +EAPI void +ecore_con_url_additional_header_add(Ecore_Con_Url *url_con, const char *key, const char *value) +{ +#ifdef HAVE_CURL + char *tmp; + + if (url_con->dead) return; + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, + "ecore_con_url_additional_header_add"); + return; + } + + if (url_con->dead) return; + tmp = malloc(strlen(key) + strlen(value) + 3); + if (!tmp) + return; + + sprintf(tmp, "%s: %s", key, value); + url_con->additional_headers = eina_list_append(url_con->additional_headers, + tmp); +#else + return; + url_con = NULL; + key = NULL; + value = NULL; +#endif +} + +EAPI void +ecore_con_url_additional_headers_clear(Ecore_Con_Url *url_con) +{ +#ifdef HAVE_CURL + char *s; + + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, + "ecore_con_url_additional_headers_clear"); + return; + } + + EINA_LIST_FREE(url_con->additional_headers, s) + free(s); +#else + return; + url_con = NULL; +#endif +} + +EAPI void * +ecore_con_url_data_get(Ecore_Con_Url *url_con) +{ +#ifdef HAVE_CURL + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_data_get"); + return NULL; + } + + return url_con->data; +#else + return NULL; + url_con = NULL; +#endif +} + +EAPI void +ecore_con_url_time(Ecore_Con_Url *url_con, Ecore_Con_Url_Time condition, double timestamp) +{ +#ifdef HAVE_CURL + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_time"); + return; + } + + if (url_con->dead) return; + url_con->time_condition = condition; + url_con->timestamp = timestamp; +#else + return; + (void)url_con; + (void)condition; + (void)timestamp; +#endif +} + +EAPI void +ecore_con_url_fd_set(Ecore_Con_Url *url_con, int fd) +{ +#ifdef HAVE_CURL + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_set"); + return; + } + + if (url_con->dead) return; + url_con->write_fd = fd; +#else + return; + (void)url_con; + (void)fd; +#endif +} + +EAPI int +ecore_con_url_received_bytes_get(Ecore_Con_Url *url_con) +{ +#ifdef HAVE_CURL + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, + "ecore_con_url_received_bytes_get"); + return -1; + } + + return url_con->received; +#else + return 0; + (void)url_con; +#endif +} + +EAPI const Eina_List * +ecore_con_url_response_headers_get(Ecore_Con_Url *url_con) +{ +#ifdef HAVE_CURL + return url_con->response_headers; +#else + return NULL; + (void)url_con; +#endif +} + +EAPI Eina_Bool +ecore_con_url_httpauth_set(Ecore_Con_Url *url_con, const char *username, const char *password, Eina_Bool safe) +{ +#ifdef HAVE_CURL + CURLcode ret; + + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, + "ecore_con_url_httpauth_set"); + return EINA_FALSE; + } + + if (url_con->dead) return EINA_FALSE; +# if LIBCURL_VERSION_NUM >= 0x071301 + if ((username) && (password)) + { + if (safe) + curl_easy_setopt(url_con->curl_easy, CURLOPT_HTTPAUTH, + CURLAUTH_ANYSAFE); + else + curl_easy_setopt(url_con->curl_easy, CURLOPT_HTTPAUTH, CURLAUTH_ANY); + + ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_USERNAME, username); + if (ret != CURLE_OK) + { + ERR("Could not set username for HTTP authentication: %s", + curl_easy_strerror(ret)); + return EINA_FALSE; + } + + ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_PASSWORD, password); + if (ret != CURLE_OK) + { + ERR("Could not set password for HTTP authentication: %s", + curl_easy_strerror(ret)); + return EINA_FALSE; + } + + return EINA_TRUE; + } +# endif +#else + return EINA_FALSE; + (void)url_con; + (void)username; + (void)password; + (void)safe; +#endif + + return EINA_FALSE; +} + +#define MODE_AUTO 0 +#define MODE_GET 1 +#define MODE_POST 2 + +static Eina_Bool +_ecore_con_url_send(Ecore_Con_Url *url_con, int mode, const void *data, long length, const char *content_type) +{ +#ifdef HAVE_CURL + Eina_List *l; + const char *s; + char tmp[512]; + + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_send"); + return EINA_FALSE; + } + + if (!url_con->url) return EINA_FALSE; + if (url_con->dead) return EINA_FALSE; + + /* Free response headers from previous send() calls */ + EINA_LIST_FREE(url_con->response_headers, s) + free((char *)s); + url_con->response_headers = NULL; + url_con->status = 0; + + curl_slist_free_all(url_con->headers); + url_con->headers = NULL; + + if ((mode == MODE_POST) || (mode == MODE_AUTO)) + { + if (url_con->post_data) free(url_con->post_data); + url_con->post_data = NULL; + if ((data) && (length > 0)) + { + url_con->post_data = malloc(length); + if (url_con->post_data) + { + memcpy(url_con->post_data, data, length); + if ((content_type) && (strlen(content_type) < 450)) + { + snprintf(tmp, sizeof(tmp), "Content-Type: %s", content_type); + url_con->headers = curl_slist_append(url_con->headers, tmp); + } + curl_easy_setopt(url_con->curl_easy, CURLOPT_POSTFIELDS, url_con->post_data); + curl_easy_setopt(url_con->curl_easy, CURLOPT_POSTFIELDSIZE, length); + } + else + return EINA_FALSE; + } + else curl_easy_setopt(url_con->curl_easy, CURLOPT_POSTFIELDSIZE, 0); + if (mode == MODE_POST) + curl_easy_setopt(url_con->curl_easy, CURLOPT_POST, 1); + } + + switch (url_con->time_condition) + { + case ECORE_CON_URL_TIME_NONE: + curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMECONDITION, + CURL_TIMECOND_NONE); + break; + + case ECORE_CON_URL_TIME_IFMODSINCE: + curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMECONDITION, + CURL_TIMECOND_IFMODSINCE); + curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMEVALUE, + (long)url_con->timestamp); + break; + + case ECORE_CON_URL_TIME_IFUNMODSINCE: + curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMECONDITION, + CURL_TIMECOND_IFUNMODSINCE); + curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMEVALUE, + (long)url_con->timestamp); + break; + } + + /* Additional headers */ + EINA_LIST_FOREACH(url_con->additional_headers, l, s) + url_con->headers = curl_slist_append(url_con->headers, s); + + curl_easy_setopt(url_con->curl_easy, CURLOPT_HTTPHEADER, url_con->headers); + + url_con->received = 0; + + return _ecore_con_url_perform(url_con); +#else + return EINA_FALSE; + (void)url_con; + (void)mode; + (void)data; + (void)length; + (void)content_type; +#endif +} + +EAPI Eina_Bool +ecore_con_url_get(Ecore_Con_Url *url_con) +{ + return _ecore_con_url_send(url_con, MODE_GET, NULL, 0, NULL); +} + +EAPI Eina_Bool +ecore_con_url_post(Ecore_Con_Url *url_con, const void *data, long length, const char *content_type) +{ + return _ecore_con_url_send(url_con, MODE_POST, data, length, content_type); +} + +EAPI Eina_Bool +ecore_con_url_ftp_upload(Ecore_Con_Url *url_con, const char *filename, const char *user, const char *pass, const char *upload_dir) +{ +#ifdef HAVE_CURL + char url[4096]; + char userpwd[4096]; + FILE *fd; + struct stat file_info; + CURLcode ret; + + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, + ECORE_MAGIC_CON_URL, + "ecore_con_url_ftp_upload"); + return EINA_FALSE; + } + + if (url_con->dead) return EINA_FALSE; + if (!url_con->url) return EINA_FALSE; + if ((!filename) || (!filename[0])) return EINA_FALSE; + + if (stat(filename, &file_info)) + return EINA_FALSE; + + snprintf(userpwd, sizeof(userpwd), "%s:%s", user, pass); + ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_USERPWD, userpwd); + if (ret != CURLE_OK) + { + ERR("Could not set username and password for FTP upload: %s", + curl_easy_strerror(ret)); + return EINA_FALSE; + } + + char tmp[PATH_MAX]; + snprintf(tmp, PATH_MAX, "%s", filename); + + if (upload_dir) + snprintf(url, sizeof(url), "ftp://%s/%s/%s", url_con->url, + upload_dir, basename(tmp)); + else + snprintf(url, sizeof(url), "ftp://%s/%s", url_con->url, + basename(tmp)); + + if (!ecore_con_url_url_set(url_con, url)) + return EINA_FALSE; + + curl_easy_setopt(url_con->curl_easy, CURLOPT_INFILESIZE_LARGE, + (curl_off_t)file_info.st_size); + curl_easy_setopt(url_con->curl_easy, CURLOPT_UPLOAD, 1); + curl_easy_setopt(url_con->curl_easy, CURLOPT_READFUNCTION, + _ecore_con_url_read_cb); + + fd = fopen(filename, "rb"); + if (!fd) + { + ERR("Could not open \"%s\" for FTP upload", filename); + return EINA_FALSE; + } + curl_easy_setopt(url_con->curl_easy, CURLOPT_READDATA, fd); + + return _ecore_con_url_perform(url_con); +#else + return EINA_FALSE; + (void)url_con; + (void)filename; + (void)user; + (void)pass; + (void)upload_dir; +#endif +} + +EAPI void +ecore_con_url_cookies_init(Ecore_Con_Url *url_con) +{ +#ifdef HAVE_CURL + if (!url_con) + return; + + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, + "ecore_con_url_cookies_init"); + return; + } + + if (url_con->dead) return; + curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIEFILE, ""); +#else + return; + (void)url_con; +#endif +} + +EAPI void +ecore_con_url_cookies_ignore_old_session_set(Ecore_Con_Url *url_con, Eina_Bool ignore) +{ +#ifdef HAVE_CURL + if (!url_con) + return; + + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, + "ecore_con_url_cookies_ignore_old_session_set"); + return; + } + + if (url_con->dead) return; + curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIESESSION, ignore); +#else + return; + (void)url_con; + (void)ignore; +#endif +} + +EAPI void +ecore_con_url_cookies_clear(Ecore_Con_Url *url_con) +{ +#ifdef HAVE_CURL + if (!url_con) + return; + + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, + "ecore_con_url_cookies_clear"); + return; + } + + if (url_con->dead) return; + curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIELIST, "ALL"); +#else + return; + (void)url_con; +#endif +} + +EAPI void +ecore_con_url_cookies_session_clear(Ecore_Con_Url *url_con) +{ +#ifdef HAVE_CURL + if (!url_con) + return; + + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, + "ecore_con_url_cookies_session_clear"); + return; + } + + if (url_con->dead) return; + curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIELIST, "SESS"); +#else + return; + (void)url_con; +#endif +} + +EAPI void +ecore_con_url_cookies_file_add(Ecore_Con_Url *url_con, const char *const file_name) +{ +#ifdef HAVE_CURL + if (!url_con) + return; + + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, + "ecore_con_url_cookies_file_add"); + return; + } + + if (url_con->dead) return; + curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIEFILE, file_name); +#else + return; + (void)url_con; + (void)file_name; +#endif +} + +EAPI Eina_Bool +ecore_con_url_cookies_jar_file_set(Ecore_Con_Url *url_con, const char *const cookiejar_file) +{ +#ifdef HAVE_CURL + CURLcode ret; + + if (!url_con) + return EINA_FALSE; + + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, + "ecore_con_url_cookies_jar_file_set"); + return EINA_FALSE; + } + + if (url_con->dead) return EINA_FALSE; + ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIEJAR, + cookiejar_file); + if (ret != CURLE_OK) + { + ERR("Setting the cookie-jar name failed: %s", + curl_easy_strerror(ret)); + return EINA_FALSE; + } + + return EINA_TRUE; +#else + return EINA_FALSE; + (void)url_con; + (void)cookiejar_file; +#endif +} + +EAPI void +ecore_con_url_cookies_jar_write(Ecore_Con_Url *url_con) +{ +#ifdef HAVE_CURL + if (!url_con) + return; + + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, + "ecore_con_url_cookies_jar_write"); + return; + } + + if (url_con->dead) return; + curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIELIST, "FLUSH"); +#else + return; + (void)url_con; +#endif +} + +EAPI void +ecore_con_url_verbose_set(Ecore_Con_Url *url_con, Eina_Bool verbose) +{ +#ifdef HAVE_CURL + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, + "ecore_con_url_verbose_set"); + return; + } + + if (!url_con->url) + return; + + if (url_con->dead) return; + curl_easy_setopt(url_con->curl_easy, CURLOPT_VERBOSE, (int)verbose); +#else + return; + (void)url_con; + (void)verbose; +#endif +} + +EAPI void +ecore_con_url_ftp_use_epsv_set(Ecore_Con_Url *url_con, Eina_Bool use_epsv) +{ +#ifdef HAVE_CURL + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, + "ecore_con_url_ftp_use_epsv_set"); + return; + } + + if (!url_con->url) + return; + + if (url_con->dead) return; + curl_easy_setopt(url_con->curl_easy, CURLOPT_FTP_USE_EPSV, (int)use_epsv); +#else + return; + (void)url_con; + (void)use_epsv; +#endif +} + +/** + * Toggle libcurl's verify peer's certificate option. + * + * If @p verify is @c EINA_TRUE, libcurl will verify + * the authenticity of the peer's certificate, otherwise + * it will not. Default behavior of libcurl is to check + * peer's certificate. + * + * @param url_con Ecore_Con_Url instance which will be acted upon. + * @param verify Whether or not libcurl will check peer's certificate. + * @since 1.1.0 + */ +EAPI void +ecore_con_url_ssl_verify_peer_set(Ecore_Con_Url *url_con, Eina_Bool verify) +{ +#ifdef HAVE_CURL + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, + "ecore_con_url_ssl_verify_peer_set"); + return; + } + + if (!url_con->url) + return; + + if (url_con->dead) return; + curl_easy_setopt(url_con->curl_easy, CURLOPT_SSL_VERIFYPEER, (int)verify); +#else + return; + (void)url_con; + (void)verify; +#endif +} + +/** + * Set a custom CA to trust for SSL/TLS connections. + * + * Specify the path of a file (in PEM format) containing one or more + * CA certificate(s) to use for the validation of the server certificate. + * + * This function can also disable CA validation if @p ca_path is @c NULL. + * However, the server certificate still needs to be valid for the connection + * to succeed (i.e., the certificate must concern the server the + * connection is made to). + * + * @param url_con Connection object that will use the custom CA. + * @param ca_path Path to a CA certificate(s) file or @c NULL to disable + * CA validation. + * + * @return @c 0 on success. When cURL is used, non-zero return values + * are equal to cURL error codes. + */ +EAPI int +ecore_con_url_ssl_ca_set(Ecore_Con_Url *url_con, const char *ca_path) +{ + int res = -1; + +#ifdef HAVE_CURL + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_ssl_ca_set"); + return -1; + } + + if (!url_con->url) return -1; + if (url_con->dead) return -1; + if (ca_path == NULL) + res = curl_easy_setopt(url_con->curl_easy, CURLOPT_SSL_VERIFYPEER, 0); + else + { + res = curl_easy_setopt(url_con->curl_easy, CURLOPT_SSL_VERIFYPEER, 1); + if (!res) + res = curl_easy_setopt(url_con->curl_easy, CURLOPT_CAINFO, ca_path); + } +#else + return -1; + (void)url_con; + (void)ca_path; +#endif + + return res; +} + +EAPI Eina_Bool +ecore_con_url_http_version_set(Ecore_Con_Url *url_con, Ecore_Con_Url_Http_Version version) +{ +#ifdef HAVE_CURL + int res = -1; + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_http_version_set"); + return EINA_FALSE; + } + if (url_con->dead) return EINA_FALSE; + switch (version) + { + case ECORE_CON_URL_HTTP_VERSION_1_0: + res = curl_easy_setopt(url_con->curl_easy, + CURLOPT_HTTP_VERSION, + CURL_HTTP_VERSION_1_0); + break; + + case ECORE_CON_URL_HTTP_VERSION_1_1: + res = curl_easy_setopt(url_con->curl_easy, + CURLOPT_HTTP_VERSION, + CURL_HTTP_VERSION_1_1); + break; + + default: + break; + } + if (res != CURLE_OK) + { + ERR("curl http version setting failed: %s", curl_easy_strerror(res)); + return EINA_FALSE; + } + return EINA_TRUE; +#else + (void)url_con; + (void)version; + return EINA_FALSE; +#endif +} + +EAPI Eina_Bool +ecore_con_url_proxy_set(Ecore_Con_Url *url_con, const char *proxy) +{ +#ifdef HAVE_CURL + int res = -1; + curl_version_info_data *vers = NULL; + + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_proxy_set"); + return EINA_FALSE; + } + + if (!url_con->url) return EINA_FALSE; + if (url_con->dead) return EINA_FALSE; + + if (!proxy) res = curl_easy_setopt(url_con->curl_easy, CURLOPT_PROXY, ""); + else + { + // before curl version 7.21.7, socks protocol:// prefix is not supported + // (e.g. socks4://, socks4a://, socks5:// or socks5h://, etc.) + vers = curl_version_info(CURLVERSION_NOW); + if (vers->version_num < 0x71507) + { + url_con->proxy_type = CURLPROXY_HTTP; + if (strstr(proxy, "socks4a")) + url_con->proxy_type = CURLPROXY_SOCKS4A; + else if (strstr(proxy, "socks4")) + url_con->proxy_type = CURLPROXY_SOCKS4; + else if (strstr(proxy, "socks5h")) + url_con->proxy_type = CURLPROXY_SOCKS5_HOSTNAME; + else if (strstr(proxy, "socks5")) + url_con->proxy_type = CURLPROXY_SOCKS5; + res = curl_easy_setopt(url_con->curl_easy, CURLOPT_PROXYTYPE, + url_con->proxy_type); + if (res != CURLE_OK) + { + ERR("curl proxy type setting failed: %s", + curl_easy_strerror(res)); + url_con->proxy_type = -1; + return EINA_FALSE; + } + } + res = curl_easy_setopt(url_con->curl_easy, CURLOPT_PROXY, proxy); + } + if (res != CURLE_OK) + { + ERR("curl proxy setting failed: %s", curl_easy_strerror(res)); + url_con->proxy_type = -1; + return EINA_FALSE; + } + return EINA_TRUE; +#else + return EINA_FALSE; + (void)url_con; + (void)proxy; +#endif +} + +EAPI void +ecore_con_url_timeout_set(Ecore_Con_Url *url_con, double timeout) +{ +#ifdef HAVE_CURL + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_timeout_set"); + return; + } + + if (url_con->dead) return; + if (!url_con->url || timeout < 0) return; + if (url_con->timer) ecore_timer_del(url_con->timer); + url_con->timer = ecore_timer_add(timeout, _ecore_con_url_timeout_cb, url_con); +#else + return; + (void)url_con; + (void)timeout; +#endif +} + +EAPI Eina_Bool +ecore_con_url_proxy_username_set(Ecore_Con_Url *url_con, const char *username) +{ +#ifdef HAVE_CURL + int res = -1; + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_proxy_username_set"); + return EINA_FALSE; + } + + if (url_con->dead) return EINA_FALSE; + if (!url_con->url) return EINA_FALSE; + if ((!username) || (!username[0])) return EINA_FALSE; + if (url_con->proxy_type == CURLPROXY_SOCKS4 || url_con->proxy_type == CURLPROXY_SOCKS4A) + { + ERR("Proxy type should be socks5 and above"); + return EINA_FALSE; + } + + res = curl_easy_setopt(url_con->curl_easy, CURLOPT_USERNAME, username); + if (res != CURLE_OK) + { + ERR("curl_easy_setopt() failed: %s", curl_easy_strerror(res)); + return EINA_FALSE; + } + return EINA_TRUE; +#else + return EINA_FALSE; + (void)url_con; + (void)username; +#endif +} + +EAPI Eina_Bool +ecore_con_url_proxy_password_set(Ecore_Con_Url *url_con, const char *password) +{ +#ifdef HAVE_CURL + int res = -1; + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_proxy_password_set"); + return EINA_FALSE; + } + if (!url_con->url) return EINA_FALSE; + if (url_con->dead) return EINA_FALSE; + if (!password) return EINA_FALSE; + if (url_con->proxy_type == CURLPROXY_SOCKS4 || url_con->proxy_type == CURLPROXY_SOCKS4A) + { + ERR("Proxy type should be socks5 and above"); + return EINA_FALSE; + } + + res = curl_easy_setopt(url_con->curl_easy, CURLOPT_PASSWORD, password); + if (res != CURLE_OK) + { + ERR("curl_easy_setopt() failed: %s", curl_easy_strerror(res)); + return EINA_FALSE; + } + return EINA_TRUE; +#else + return EINA_FALSE; + (void)url_con; + (void)password; +#endif +} + +/** + * @} + */ + +#ifdef HAVE_CURL +static void +_ecore_con_url_status_get(Ecore_Con_Url *url_con) +{ + long status = 0; + + if (!url_con->curl_easy) return; + if (!curl_easy_getinfo(url_con->curl_easy, CURLINFO_RESPONSE_CODE, &status)) + url_con->status = status; + else + url_con->status = 0; +} + +static void +_ecore_con_url_event_url_complete(Ecore_Con_Url *url_con, CURLMsg *curlmsg) +{ + Ecore_Con_Event_Url_Complete *e; + + e = calloc(1, sizeof(Ecore_Con_Event_Url_Complete)); + if (!e) return; + + if (curlmsg && (curlmsg->data.result == CURLE_OK)) + { + if (!url_con->status) + _ecore_con_url_status_get(url_con); + } + else if (curlmsg) + ERR("Curl message have errors: %d", curlmsg->data.result); + else + CRIT("THIS IS BAD."); + + e->status = url_con->status; + e->url_con = url_con; + url_con->event_count++; + ecore_event_add(ECORE_CON_EVENT_URL_COMPLETE, e, (Ecore_End_Cb)_ecore_con_event_url_free, url_con); +} + +static void +_ecore_con_url_multi_remove(Ecore_Con_Url *url_con) +{ + CURLMcode ret; + + ret = curl_multi_remove_handle(_curlm, url_con->curl_easy); + url_con->multi = EINA_FALSE; + if (ret != CURLM_OK) ERR("curl_multi_remove_handle failed: %s", curl_multi_strerror(ret)); +} + +static Eina_Bool +_ecore_con_url_timeout_cb(void *data) +{ + Ecore_Con_Url *url_con = data; + + if (!url_con) return ECORE_CALLBACK_CANCEL; + if (!url_con->curl_easy) return ECORE_CALLBACK_CANCEL; + + _ecore_con_url_multi_remove(url_con); + _url_con_list = eina_list_remove(_url_con_list, url_con); + + curl_slist_free_all(url_con->headers); + url_con->headers = NULL; + + url_con->timer = NULL; + + _ecore_con_url_event_url_complete(url_con, NULL); + return ECORE_CALLBACK_CANCEL; +} + +static size_t +_ecore_con_url_data_cb(void *buffer, size_t size, size_t nitems, void *userp) +{ + Ecore_Con_Url *url_con; + Ecore_Con_Event_Url_Data *e; + size_t real_size = size * nitems; + + url_con = (Ecore_Con_Url *)userp; + + if (!url_con) + return -1; + + if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) + { + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_data_cb"); + return -1; + } + + url_con->received += real_size; + + INF("reading from %s", url_con->url); + if (url_con->write_fd < 0) + { + e = + malloc(sizeof(Ecore_Con_Event_Url_Data) + sizeof(unsigned char) * + (real_size - 1)); + if (e) + { + e->url_con = url_con; + e->size = real_size; + memcpy(e->data, buffer, real_size); + url_con->event_count++; + ecore_event_add(ECORE_CON_EVENT_URL_DATA, e, (Ecore_End_Cb)_ecore_con_event_url_free, url_con); + } + } + else + { + ssize_t count = 0; + size_t total_size = real_size; + size_t offset = 0; + + while (total_size > 0) + { + count = write(url_con->write_fd, + (char *)buffer + offset, + total_size); + if (count < 0) + { + if (errno != EAGAIN && errno != EINTR) + return -1; + } + else + { + total_size -= count; + offset += count; + } + } + } + + return real_size; +} + +static size_t +_ecore_con_url_header_cb(void *ptr, size_t size, size_t nitems, void *stream) +{ + size_t real_size = size * nitems; + Ecore_Con_Url *url_con = stream; + + char *header = malloc(sizeof(char) * (real_size + 1)); + if (!header) + return real_size; + + memcpy(header, ptr, real_size); + header[real_size] = '\0'; + + url_con->response_headers = eina_list_append(url_con->response_headers, + header); + + return real_size; +} + +static int +_ecore_con_url_progress_cb(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) +{ + Ecore_Con_Event_Url_Progress *e; + Ecore_Con_Url *url_con; + + url_con = clientp; + + e = malloc(sizeof(Ecore_Con_Event_Url_Progress)); + if (e) + { + e->url_con = url_con; + e->down.total = dltotal; + e->down.now = dlnow; + e->up.total = ultotal; + e->up.now = ulnow; + url_con->event_count++; + ecore_event_add(ECORE_CON_EVENT_URL_PROGRESS, e, (Ecore_End_Cb)_ecore_con_event_url_free, url_con); + } + + return 0; +} + +static size_t +_ecore_con_url_read_cb(void *ptr, size_t size, size_t nitems, void *stream) +{ + size_t retcode = fread(ptr, size, nitems, stream); + + if (ferror((FILE *)stream)) + { + fclose(stream); + return CURL_READFUNC_ABORT; + } + else if (retcode == 0) + { + fclose((FILE *)stream); + return 0; + } + +#ifdef _WIN32 + INF("*** We read %Iu bytes from file", retcode); +#else + INF("*** We read %zu bytes from file", retcode); +#endif + return retcode; +} + +static void +_ecore_con_url_info_read(void) +{ + CURLMsg *curlmsg; + int n_remaining; + + while ((curlmsg = curl_multi_info_read(_curlm, &n_remaining))) + { + Eina_List *l, *ll; + Ecore_Con_Url *url_con = NULL; + DBG("Curl message: %d", curlmsg->msg); + + if (curlmsg->msg == CURLMSG_DONE) + { + EINA_LIST_FOREACH_SAFE(_url_con_list, l, ll, url_con) + { + if (curlmsg->easy_handle == url_con->curl_easy) + _ecore_con_url_event_url_complete(url_con, curlmsg); + } + } + } +} + +static void +_ecore_con_url_curl_clear(void) +{ + Ecore_Fd_Handler *fdh; + Ecore_Con_Url *url_con; + + EINA_LIST_FREE(_fd_hd_list, fdh) ecore_main_fd_handler_del(fdh); + EINA_LIST_FREE(_url_con_list, url_con) _ecore_con_url_multi_remove(url_con); +} + +static Eina_Bool +_ecore_con_url_fd_handler(void *data __UNUSED__, Ecore_Fd_Handler *fd_handler __UNUSED__) +{ + Ecore_Fd_Handler *fdh; + EINA_LIST_FREE(_fd_hd_list, fdh) ecore_main_fd_handler_del(fdh); + ecore_timer_interval_set(_curl_timer, 0.1); + return ECORE_CALLBACK_CANCEL; +} + +static void +_ecore_con_url_fdset(void) +{ + CURLMcode ret; + fd_set read_set, write_set, exc_set; + int fd, fd_max; + + FD_ZERO(&read_set); + FD_ZERO(&write_set); + FD_ZERO(&exc_set); + + ret = curl_multi_fdset(_curlm, &read_set, &write_set, &exc_set, &fd_max); + if (ret != CURLM_OK) + { + ERR("curl_multi_fdset failed: %s", curl_multi_strerror(ret)); + return; + } + + for (fd = 0; fd <= fd_max; fd++) + { + int flags = 0; + if (FD_ISSET(fd, &read_set)) flags |= ECORE_FD_READ; + if (FD_ISSET(fd, &write_set)) flags |= ECORE_FD_WRITE; + if (FD_ISSET(fd, &exc_set)) flags |= ECORE_FD_ERROR; + if (flags) + { + // FIXME: Who is owner (easy_handle) of this fd?? (Curl do not give this info.) + // This cause "Failed to delete epoll fd xx!" error messages + Ecore_Fd_Handler *fd_handler; + fd_handler = ecore_main_fd_handler_add(fd, flags, + _ecore_con_url_fd_handler, + NULL, NULL, NULL); + if (fd_handler) + _fd_hd_list = eina_list_append(_fd_hd_list, fd_handler); + } + } +} + +static Eina_Bool +_ecore_con_url_timer(void *data __UNUSED__) +{ + Ecore_Fd_Handler *fdh; + int still_running; + CURLMcode ret; + + EINA_LIST_FREE(_fd_hd_list, fdh) ecore_main_fd_handler_del(fdh); + _ecore_con_url_info_read(); + + ret = curl_multi_perform(_curlm, &still_running); + if (ret == CURLM_CALL_MULTI_PERFORM) + { + DBG("curl_multi_perform() again immediately"); + return ECORE_CALLBACK_RENEW; + } + else if (ret != CURLM_OK) + { + ERR("curl_multi_perform() failed: %s", curl_multi_strerror(ret)); + _ecore_con_url_curl_clear(); + ecore_timer_freeze(_curl_timer); + } + + if (still_running) + { + long ms; + _ecore_con_url_fdset(); + curl_multi_timeout(_curlm, &ms); + DBG("multiperform is still running: %d, timeout: %ld", still_running, ms); + if (ms >= CURL_MIN_TIMEOUT || ms <= 0) ms = CURL_MIN_TIMEOUT; + ecore_timer_interval_set(_curl_timer, (double)ms / 1000); + } + else + { + DBG("multiperform ended"); + _ecore_con_url_info_read(); + _ecore_con_url_curl_clear(); + ecore_timer_freeze(_curl_timer); + } + + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +_ecore_con_url_perform(Ecore_Con_Url *url_con) +{ + CURLMcode ret; + + ret = curl_multi_add_handle(_curlm, url_con->curl_easy); + if (ret != CURLM_OK) + { + ERR("curl_multi_add_handle() failed: %s", curl_multi_strerror(ret)); + return EINA_FALSE; + } + + url_con->multi = EINA_TRUE; + _url_con_list = eina_list_append(_url_con_list, url_con); + ecore_timer_thaw(_curl_timer); + + return EINA_TRUE; +} + +static void +_ecore_con_event_url_free(Ecore_Con_Url *url_con, void *ev) +{ + free(ev); + url_con->event_count--; + if (url_con->dead && (!url_con->event_count)) + ecore_con_url_free(url_con); +} + +#endif diff --git a/src/lib/ecore_config/Ecore_Config.h b/src/lib/ecore_config/Ecore_Config.h new file mode 100644 index 0000000..6733d7b --- /dev/null +++ b/src/lib/ecore_config/Ecore_Config.h @@ -0,0 +1,312 @@ +#ifndef _ECORE_CONFIG_H +# define _ECORE_CONFIG_H + +#ifdef EAPI +#undef EAPI +#endif +#ifdef _MSC_VER +# ifdef BUILDING_DLL +# define EAPI __declspec(dllexport) +# else +# define EAPI __declspec(dllimport) +# endif +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif + +/** + * @file + * @brief Provides the Enlightened Property Library. + * + * This file provies all headers and structs for use with Ecore_Config. + * Using individual header files should not be necessary. + */ + +# define DIR_DELIMITER '/' +# define ECORE_CONFIG_FLOAT_PRECISION 1000 + +/* FIXME: this should only be included if evas is present */ +# include + +# define ECORE_CONFIG_GLOBAL_ID "_system" + +/* structures */ + +/** + * Valid configuration property types. + */ +typedef enum Ecore_Config_Type +{ + ECORE_CONFIG_NIL = 0, /**< Property with no value. */ + ECORE_CONFIG_INT = 1, /**< Integer property type. */ + ECORE_CONFIG_FLT = 2, /**< Float property type. */ + ECORE_CONFIG_STR = 3, /**< String property type. */ + ECORE_CONFIG_RGB = 4, /**< Colour property type. */ + ECORE_CONFIG_THM = 5, /**< Theme property type. */ + ECORE_CONFIG_BLN = 6, /**< Boolean property type. */ + ECORE_CONFIG_SCT = 7, /**< Structure property type */ +} Ecore_Config_Type; + +typedef enum Ecore_Config_Flag +{ + ECORE_CONFIG_FLAG_NONE = 0, + ECORE_CONFIG_FLAG_BOUNDS = 1, + ECORE_CONFIG_FLAG_MODIFIED = 2, + ECORE_CONFIG_FLAG_SYSTEM = 4, + ECORE_CONFIG_FLAG_CMDLN = 8 +} Ecore_Config_Flag; + +/** + * Property change callback function prototype. + */ +typedef int (*Ecore_Config_Listener) (const char *key, + const Ecore_Config_Type type, + const int tag, void *data); + +typedef struct Ecore_Config_Listener_List +{ + Ecore_Config_Listener listener; + const char *name; + void *data; + int tag; + struct Ecore_Config_Listener_List *next; +} Ecore_Config_Listener_List; + +/** + * The actual property for storing a key-value pair. + */ +typedef struct Ecore_Config_Prop +{ + char *key; /* Property key. */ + char *description; /* Description set by ecore_config_descibe. */ + char short_opt; /* short identifier on command line (-f) */ + char *long_opt; /* long identifier on command line (--foo) */ + char *ptr; /* Used as the value when the property is a string or theme. */ + Ecore_Config_Type type; /* Property type. */ + long val; /* Used as the value when the property is an integer, float or colour. */ + long lo; /* Lower bound for the value when the property is an integer or float. */ + long hi; /* Higher bound for the value when the property is an integer or float. */ + long step; /* Increment for the value when the property is an integer or float. */ + Ecore_Config_Flag flags; /// < Configuration flags. + Ecore_Config_Listener_List *listeners; /* List of change listeners. */ + void *data; /// < Stores extra data for the property. + struct Ecore_Config_Prop *parent; /* if we are in a struct we have a parent to notify of changes etc */ + struct Ecore_Config_Prop *next; /* Pointer to the next property in the list. */ +} Ecore_Config_Prop; + +/* + * A container for a list of properties. Provided so that an + * application can use different set of properties at any time. This + * is useful for multiple window support. + */ +typedef struct Ecore_Config_Bundle +{ + char *identifier; /* Identifier for this set of properties (window ID for example) */ + char *owner; /* This is used to store the application name related to the bundle */ + long serial; /* Unique identifier to identify bundle */ + Ecore_Config_Prop *data; /* Pointer to root of property list */ + void *user_data; /* App specific pointer to "other data" */ + struct Ecore_Config_Bundle *next; /* Pointer to next bundle in this application */ +} Ecore_Config_Bundle; + +typedef struct Ecore_Config_Server +{ + void *server; + char *name; + Ecore_Config_Bundle *bundles; /* data anchor */ + struct Ecore_Config_Server *next; +} Ecore_Config_Server; + +# ifdef __cplusplus +extern "C" +{ +# endif + +/* global ptrs to save passing them through the API */ + EAPI extern Ecore_Config_Server *__ecore_config_server_global; + EAPI extern Ecore_Config_Server *__ecore_config_server_local; + EAPI extern Ecore_Config_Bundle *__ecore_config_bundle_local; + EAPI extern char *__ecore_config_app_name; + + EAPI Ecore_Config_Prop *ecore_config_get(const char *key); + EAPI const char *ecore_config_type_get(const Ecore_Config_Prop *e); + EAPI int ecore_config_boolean_get(const char *key); + EAPI char *ecore_config_string_get(const char *key); + EAPI long ecore_config_int_get(const char *key); + EAPI int ecore_config_argb_get(const char *key, int *a, int *r, + int *g, int *b); + EAPI long ecore_config_argbint_get(const char *key); + EAPI char *ecore_config_argbstr_get(const char *key); + EAPI float ecore_config_float_get(const char *key); + EAPI char *ecore_config_theme_get(const char *key); + EAPI char *ecore_config_as_string_get(const char *key); + EAPI int ecore_config_bound(Ecore_Config_Prop *e); + EAPI int ecore_config_describe(const char *key, const char *desc); + EAPI int ecore_config_short_opt_set(const char *key, + char short_opt); + EAPI int ecore_config_long_opt_set(const char *key, + const char *long_opt); + EAPI int ecore_config_set(const char *key, const char *val); + EAPI int ecore_config_typed_set(const char *key, const void *val, + int type); + EAPI int ecore_config_boolean_set(const char *key, int val); + EAPI int ecore_config_string_set(const char *key, const char *val); + EAPI int ecore_config_int_set(const char *key, int val); + EAPI int ecore_config_argb_set(const char *key, int a, int r, int g, int b); + EAPI int ecore_config_argbint_set(const char *key, long argb); + EAPI int ecore_config_argbstr_set(const char *key, const char *val); + EAPI int ecore_config_float_set(const char *key, float val); + EAPI int ecore_config_theme_set(const char *key, const char *val); + EAPI int ecore_config_theme_preview_group_set(const char *key, + const char *group); + EAPI int ecore_config_as_string_set(const char *key, const char *val); + + EAPI int ecore_config_default(const char *key, const char *val, + float lo, float hi, float step); + EAPI int ecore_config_typed_default(const char *key, const void *val, + int type); + EAPI int ecore_config_boolean_default(const char *key, int val); + EAPI int ecore_config_int_default(const char *key, int val); + EAPI int ecore_config_int_default_bound(const char *key, int val, + int lo, int hi, int step); + EAPI int ecore_config_string_default(const char *key, const char *val); + EAPI int ecore_config_float_default(const char *key, float val); + EAPI int ecore_config_float_default_bound(const char *key, + float val, float lo, + float hi, float step); + EAPI int ecore_config_argb_default(const char *key, int a, int r, int g, int b); + EAPI int ecore_config_argbint_default(const char *key, long argb); + EAPI int ecore_config_argbstr_default(const char *key, const char *val); + EAPI int ecore_config_theme_default(const char *key, const char *val); + EAPI int ecore_config_struct_default(const char *key); + EAPI int ecore_config_struct_int_add(const char *key, const char *name, int val); + EAPI int ecore_config_struct_float_add(const char *key, const char *name, float val); + EAPI int ecore_config_struct_create(const char *key); + EAPI int ecore_config_struct_string_add(const char *key, const char *name, const char* val); + EAPI int ecore_config_struct_theme_add(const char *key, const char *name, const char* val); + EAPI int ecore_config_struct_argb_add(const char *key, const char *name, int a, int r, int g, int b); + EAPI int ecore_config_struct_boolean_add(const char *key, const char *name, int val); + EAPI int ecore_config_struct_get(const char *key, void *data); + + EAPI int ecore_config_listen(const char *name, const char *key, + Ecore_Config_Listener listener, + int tag, void *data); + EAPI int ecore_config_deaf(const char *name, const char *key, + Ecore_Config_Listener listener); + EAPI Ecore_Config_Prop *ecore_config_dst(Ecore_Config_Prop *e); + EAPI int ecore_config_type_guess(const char *key, const char *val); + + EAPI Ecore_Config_Bundle *ecore_config_bundle_new(Ecore_Config_Server *srv, + const char *id); + EAPI Ecore_Config_Bundle *ecore_config_bundle_1st_get(Ecore_Config_Server *srv); + EAPI Ecore_Config_Bundle *ecore_config_bundle_next_get(Ecore_Config_Bundle *ns); + EAPI Ecore_Config_Bundle *ecore_config_bundle_by_serial_get(Ecore_Config_Server *srv, + long serial); + EAPI Ecore_Config_Bundle *ecore_config_bundle_by_label_get(Ecore_Config_Server *srv, + const char *label); + EAPI long ecore_config_bundle_serial_get(Ecore_Config_Bundle *ns); + EAPI char *ecore_config_bundle_label_get(Ecore_Config_Bundle *ns); + + EAPI int ecore_config_init(const char *name); + EAPI int ecore_config_shutdown(void); + + EAPI int ecore_config_system_init(void); + EAPI int ecore_config_system_shutdown(void); + + EAPI int ecore_config_load(void); + EAPI int ecore_config_file_load(const char *file); + EAPI int ecore_config_save(void); + EAPI int ecore_config_file_save(const char *file); + +/* error codes */ +# define ECORE_CONFIG_ERR_NOTSUPP (-16) +# define ECORE_CONFIG_ERR_NOFILE (-15) +# define ECORE_CONFIG_ERR_META_DLFAIL (-14) +# define ECORE_CONFIG_ERR_META_FILE (-13) +# define ECORE_CONFIG_ERR_META_FORMAT (-12) +# define ECORE_CONFIG_ERR_MONMIS (-11) +# define ECORE_CONFIG_ERR_NOEXEC (-10) +# define ECORE_CONFIG_ERR_PARTIAL (-9) +# define ECORE_CONFIG_ERR_PATHEX (-8) +# define ECORE_CONFIG_ERR_TYPEMISMATCH (-7) +# define ECORE_CONFIG_ERR_MUTEX (-6) +# define ECORE_CONFIG_ERR_NOTFOUND (-5) /* Error indicating that the item searched for could not be found. */ +# define ECORE_CONFIG_ERR_OOM (-4) /* Error given when the program runs out of memory. */ +# define ECORE_CONFIG_ERR_IGNORED (-3) /* Error occurred, but was ignored. */ +# define ECORE_CONFIG_ERR_NODATA (-2) /* Error given when necessary data is not provided. */ +# define ECORE_CONFIG_ERR_FAIL (-1) /* Failure result. */ +# define ECORE_CONFIG_ERR_SUCC (0) /* Success result. */ + +# define ECORE_CONFIG_PARSE_HELP (-2) /* Help was displayed */ +# define ECORE_CONFIG_PARSE_EXIT (-1) /* An error occurred */ +# define ECORE_CONFIG_PARSE_CONTINUE (0) /* Arguments parsed successfully */ + +/* convenience mathods in convenience.c */ + /* FIXME: this should only be included if evas is present */ + EAPI int ecore_config_evas_font_path_apply(Evas *evas); + EAPI char *ecore_config_theme_search_path_get(void); + EAPI int ecore_config_theme_search_path_append(const char *append); + + EAPI char *ecore_config_theme_default_path_get(void); + EAPI char *ecore_config_theme_with_path_from_name_get(char *name); + EAPI char *ecore_config_theme_with_path_get(const char *key); + EAPI void ecore_config_args_display(void); + EAPI int ecore_config_args_parse(void); + EAPI void ecore_config_args_callback_str_add(char short_opt, + char *long_opt, char *desc, + void (*func)(char *val, void *data), + void *data); + EAPI void ecore_config_args_callback_noarg_add(char short_opt, + char *long_opt, char *desc, + void (*func)(char *val, void *data), + void *data); + EAPI void ecore_config_app_describe(char *description); + + EAPI int ecore_config_create(const char *key, void *val, + char short_opt, char *long_opt, + char *desc); + EAPI int ecore_config_typed_create(const char *key, void *val, + int type, char short_opt, + char *long_opt, char *desc); + EAPI int ecore_config_boolean_create(const char *key, int val, + char short_opt, char *long_opt, + char *desc); + EAPI int ecore_config_int_create(const char *key, int val, + char short_opt, char *long_opt, + char *desc); + EAPI int ecore_config_int_create_bound(const char *key, int val, + int low, int high, + int step, char short_opt, + char *long_opt, + char *desc); + EAPI int ecore_config_string_create(const char *key, char *val, + char short_opt, + char *long_opt, char *desc); + EAPI int ecore_config_float_create(const char *key, float val, + char short_opt, char *long_opt, + char *desc); + EAPI int ecore_config_float_create_bound(const char *key, + float val, float low, + float high, float step, + char short_opt, + char *long_opt, + char *desc); + EAPI int ecore_config_argb_create(const char *key, char *val, + char short_opt, char *long_opt, + char *desc); + EAPI int ecore_config_theme_create(const char *key, char *val, + char short_opt, char *long_opt, + char *desc); + +# ifdef __cplusplus +} +# endif +#endif diff --git a/src/lib/ecore_config/Makefile.am b/src/lib/ecore_config/Makefile.am new file mode 100644 index 0000000..c459351 --- /dev/null +++ b/src/lib/ecore_config/Makefile.am @@ -0,0 +1,62 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore_ipc \ +-I$(top_srcdir)/ \ +-I$(top_builddir)/src/lib/ecore \ +-I$(top_builddir)/src/lib/ecore_ipc \ +-I$(top_builddir)/ \ +-DPACKAGE_BIN_DIR=\"$(bindir)\" \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \ +@EVAS_CFLAGS@ \ +@EET_CFLAGS@ \ +@EINA_CFLAGS@ + +CLEANFILES = $(DB) + +#DB = system.db +#$(DB): Makefile +# edb_ed $(top_builddir)/src/lib/ecore_config/$(DB) add /e/theme/name str "winter" +# edb_ed $(top_builddir)/src/lib/ecore_config/$(DB) add /e/font/path str "$(pkgdatadir)/data/fonts" +# edb_ed $(top_builddir)/src/lib/ecore_config/$(DB) add /apps/web/browser str `which firefox 2>/dev/null || which phoenix 2>/dev/null || which mozilla 2>/dev/null || which opera 2>/dev/null || which konqueror 2>/dev/null || which epiphany 2>/dev/null` +# edb_ed $(top_builddir)/src/lib/ecore_config/$(DB) add /apps/web/email str `which thunderbird 2>/dev/null || which mozilla 2>/dev/null || which kmail 2>/dev/null || which sylpheed 2>/dev/null || which evolution 2>/dev/null` + +lib_LTLIBRARIES = libecore_config.la + +includes_HEADERS = Ecore_Config.h +includesdir = $(includedir)/ecore-@VMAJ@ + +libecore_config_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@ + +#config_DATA = $(DB) +#configdir = $(pkgdatadir) + +libecore_config_la_SOURCES = \ +ecore_config.c \ +ecore_config_util.c \ +ecore_config_storage.c \ +ecore_config_extra.c \ +ecore_config_db.c + +libecore_config_la_LIBADD = \ +$(top_builddir)/src/lib/ecore/libecore.la \ +@EET_LIBS@ \ +@EINA_LIBS@ \ +@EVAS_LIBS@ + +if BUILD_ECORE_IPC + +libecore_config_la_SOURCES += \ +ecore_config_ipc_main.c \ +ecore_config_ipc_ecore.c + +libecore_config_la_LIBADD += $(top_builddir)/src/lib/ecore_ipc/libecore_ipc.la + +endif + +EXTRA_DIST = \ +ecore_config_ipc.h \ +ecore_config_private.h \ +ecore_config_util.h diff --git a/src/lib/ecore_config/ecore_config.c b/src/lib/ecore_config/ecore_config.c new file mode 100644 index 0000000..e81538e --- /dev/null +++ b/src/lib/ecore_config/ecore_config.c @@ -0,0 +1,1870 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "Ecore_Config.h" +#include "ecore_config_private.h" +#include "ecore_config_ipc.h" + +#include "ecore_config_util.h" +int _ecore_config_log_dom = -1; +int DEBUG = 0; +EAPI Ecore_Config_Server *__ecore_config_server_global = NULL; +EAPI Ecore_Config_Server *__ecore_config_server_local = NULL; +EAPI Ecore_Config_Bundle *__ecore_config_bundle_local = NULL; +EAPI char *__ecore_config_app_name = NULL; +int __ecore_config_system_init = 0; + +static int _ecore_config_system_init_no_load(void); +static int _ecore_config_system_load(void); + +static inline void *__ecore_argb_to_long(int a, int r, int g, int b, long *v); +static inline void *__ecore_argbstr_to_long(const char *argb, long *v); + +static const char *_ecore_config_type[] = + { "undefined", "integer", "float", "string", "colour", "theme", "boolean", "structure" }; + +/** + * @defgroup Ecore_Config_Property_Group Ecore Config Property Functions + * + * Functions that retrieve or set the attributes relating to a property. + */ + +/** + * Removes the given property from the local configuration and destroys it. + * @param e Property to destroy. + * @return @c NULL + * @ingroup Ecore_Config_Property_Group + */ +EAPI Ecore_Config_Prop * +ecore_config_dst(Ecore_Config_Prop * e) +{ + Ecore_Config_Bundle *t; + Ecore_Config_Prop *p, *c; + Ecore_Config_Listener_List *l; + + p = NULL; + t = __ecore_config_bundle_local; + c = t->data; + + if (!e || !e->key) + return NULL; + if (t) + { + if (t->data == e) + t->data = e->next; + else + { + do + { + p = c; + c = c->next; + } + while (c && (c != e)); + if (c) /* remove from list if even in there */ + p->next = c->next; + } + } + + while (e->listeners) + { + l = e->listeners; + e->listeners = e->listeners->next; + free(l); + } + + if (e->key) + free(e->key); + if (e->ptr && ((e->type == ECORE_CONFIG_STR) || (e->type == ECORE_CONFIG_THM))) + free(e->ptr); + + memset(e, 0, sizeof(Ecore_Config_Prop)); + free(e); + + return NULL; +} + +/** + * @defgroup Ecore_Config_Get_Group Configuration Retrieve Functions + * + * Functions that retrieve configuration values, based on type. + */ + +/** + * Returns the property with the given key. + * @param key The unique name of the wanted property. + * @return The property that corresponds to the given key. @c NULL if the + * key could not be found. + * @ingroup Ecore_Config_Get_Group + */ +EAPI Ecore_Config_Prop * +ecore_config_get(const char *key) +{ + Ecore_Config_Bundle *t; + Ecore_Config_Prop *e; + + t = __ecore_config_bundle_local; + if (!t || !key) + return NULL; + e = t->data; + while (e) + { + if (!strcmp(key, e->key)) + return e; + e = e->next; + } + return NULL; +} + +/** + * Returns the type of the property. + * @param e Property to get the type of. + * @returns The type of the property. If the property is invalid, then the + * string "not found" is returned. + * @ingroup Ecore_Config_Property_Group + */ +EAPI const char * +ecore_config_type_get(const Ecore_Config_Prop * e) +{ + if (e) + { + return _ecore_config_type[e->type]; + } + return "not found"; +} + +/** + * Returns the specified property as a string. + * @param key The property key. + * @return The string value of the property. The function returns @c NULL if + * the property is not a string or is not set. + * @ingroup Ecore_Config_Get_Group + */ +EAPI char * +ecore_config_string_get(const char *key) +{ + return _ecore_config_string_get( ecore_config_get(key) ); +} + +char * +_ecore_config_string_get(Ecore_Config_Prop *e) +{ + return (e && (e->type == ECORE_CONFIG_STR) && e->ptr) ? strdup(e->ptr) : NULL; +} + +/** + * Returns the specified property as an integer. + * @param key The property key. + * @return The value of the property. The function returns -1 if the + * property is not an integer or is not set. + * @ingroup Ecore_Config_Get_Group + */ +EAPI int +ecore_config_boolean_get(const char *key) +{ + return _ecore_config_boolean_get( ecore_config_get(key) ); +} + +int +_ecore_config_boolean_get(Ecore_Config_Prop *e) +{ + return (e && ((e->type == ECORE_CONFIG_INT) || (e->type == ECORE_CONFIG_BLN))) ? (e->val != 0) : -1; +} + +/** + * Returns the specified property as a long integer. + * @param key The property key. + * @return The integer value of the property. The function returns 0 if the + * property is not an integer or is not set. + * @ingroup Ecore_Config_Get_Group + */ +EAPI long +ecore_config_int_get(const char *key) +{ + return _ecore_config_int_get( ecore_config_get(key) ); +} + +long +_ecore_config_int_get(Ecore_Config_Prop *e) +{ + return (e && ((e->type == ECORE_CONFIG_INT) || (e->type == ECORE_CONFIG_RGB))) ? e->val : 0L; +} + +/** + * Returns the specified property as a float. + * @param key The property key. + * @return The float value of the property. The function returns 0.0 if the + * property is not a float or is not set. + * @ingroup Ecore_Config_Get_Group + */ +EAPI float +ecore_config_float_get(const char *key) +{ + return _ecore_config_float_get( ecore_config_get(key) ); +} + +float +_ecore_config_float_get(Ecore_Config_Prop *e) +{ + return (e && (e->type == ECORE_CONFIG_FLT)) ? ((float)e->val / ECORE_CONFIG_FLOAT_PRECISION) : 0.0; +} + +/** + * Finds the alpha, red, green and blue values of a color property. + * @param key The property key. + * @param a A pointer to an integer to store the alpha value into. + * @param r A pointer to an integer to store the red value into. + * @param g A pointer to an integer to store the green value into. + * @param b A pointer to an integer to store the blue value into. + * @return @c ECORE_CONFIG_ERR_SUCC on success. @c ECORE_CONFIG_ERR_FAIL + * otherwise. + * @ingroup Ecore_Config_Get_Group + */ +EAPI int +ecore_config_argb_get(const char *key, int *a, int *r, int *g, int *b) +{ + return _ecore_config_argb_get( ecore_config_get(key), a, r, g, b); +} + +int +_ecore_config_argb_get(Ecore_Config_Prop *e, int *a, int *r, int *g, int *b) +{ + if (e && ((e->type == ECORE_CONFIG_RGB))) + { + if(a) *a = (e->val >> 24) & 0xff; + if(r) *r = (e->val >> 16) & 0xff; + if(g) *g = (e->val >> 8) & 0xff; + if(b) *b = e->val & 0xff; + return ECORE_CONFIG_ERR_SUCC; + } + return ECORE_CONFIG_ERR_FAIL; +} + +/** + * Returns a color property as a long + * @param key The property key. + * @return ARGB data as long + * @ingroup Ecore_Config_Get_Group + */ +EAPI long +ecore_config_argbint_get(const char *key) +{ + return _ecore_config_argbint_get( ecore_config_get(key) ); +} + +long +_ecore_config_argbint_get(Ecore_Config_Prop *e) +{ + if (e && ((e->type == ECORE_CONFIG_RGB))) + { + return e->val; + } + return 0L; +} + +/** + * Returns a color property as a string of hexadecimal characters. + * @param key The property key. + * @return A string of hexadecimal characters in the format #aarrggbb. + * @ingroup Ecore_Config_Get_Group + */ +EAPI char * +ecore_config_argbstr_get(const char *key) +{ + return _ecore_config_argbstr_get( ecore_config_get(key) ); +} + +char * +_ecore_config_argbstr_get(Ecore_Config_Prop *e) +{ + char *r; + + r = NULL; + esprintf(&r, "#%08x", _ecore_config_int_get(e)); + return r; +} + +/** + * Returns a theme property. + * @param key The property key. + * @return The name of the theme the property refers to. The function returns + * @c NULL if the property is not a theme or is not set. + * @ingroup Ecore_Config_Get_Group + */ +EAPI char * +ecore_config_theme_get(const char *key) +{ + return _ecore_config_theme_get( ecore_config_get(key) ); +} + +char * +_ecore_config_theme_get(Ecore_Config_Prop *e) +{ + return (e && (e->type == ECORE_CONFIG_THM)) ? strdup(e->ptr) : NULL; +} + +/** + * Retrieves the key as a string. + * @param key The property key. + * @return Returns a character array in the form of 'key:type=value'. @c NULL + * is returned if the property does not exist. + * @ingroup Ecore_Config_Get_Group + */ +EAPI char * +ecore_config_as_string_get(const char *key) +{ + Ecore_Config_Prop *e; + char *val; + char *r; + + val = NULL; + r = NULL; + if (!(e = ecore_config_get(key))) + ERR("no such property, \"%s\"...", key); + else + { + switch (e->type) + { + case ECORE_CONFIG_NIL: + val = strdup(""); + break; + case ECORE_CONFIG_INT: + esprintf(&val, "%ld", _ecore_config_int_get(e)); + break; + case ECORE_CONFIG_BLN: + esprintf(&val, "%ld", _ecore_config_boolean_get(e)); + break; + case ECORE_CONFIG_FLT: + esprintf(&val, "%lf", _ecore_config_float_get(e)); + break; + case ECORE_CONFIG_STR: + esprintf(&val, "\"%s\"", _ecore_config_string_get(e)); + break; + case ECORE_CONFIG_RGB: + esprintf(&val, "#%08x", _ecore_config_int_get(e)); + break; + case ECORE_CONFIG_THM: + esprintf(&val, "\"%s\"", _ecore_config_theme_get(e)); + break; + case ECORE_CONFIG_SCT: + break; + default: + esprintf(&r, "%s:unknown_type", key); + break; + } + if (val) + { + esprintf(&r, "%s:%s=%s", key, _ecore_config_type[e->type], val); + free(val); + } + } + return r; +} + +EAPI int +ecore_config_bound(Ecore_Config_Prop * e) +{ + int ret; + long v; + + ret = ECORE_CONFIG_ERR_SUCC; + + if (!e) + return ECORE_CONFIG_ERR_FAIL; + if (e->flags & ECORE_CONFIG_FLAG_BOUNDS) + { + if ((e->val < e->lo)) + { + WRN("ecore_config_bounds(\"%s\",%ld): value out of range; adjusted to %ld...", + e->key, e->val, e->lo); + e->val = e->lo; + } + else if ((e->val > e->hi)) + { + WRN("ecore_config_bounds(\"%s\",%ld): value out of range; adjusted to %ld...", + e->key, e->val, e->hi); + e->val = e->hi; + } + else + ret = ECORE_CONFIG_ERR_IGNORED; + } + else + ret = ECORE_CONFIG_ERR_IGNORED; + + if (e->step) + { + v = ((int)(e->val / e->step)) * e->step; + if (v != e->val) + { + if (e->type == ECORE_CONFIG_FLT) + WRN("ecore_config_bound(\"%s\"): float value %f not a multiple of %f, adjusted to %f...", + e->key, ((double)e->val) / ECORE_CONFIG_FLOAT_PRECISION, + ((double)e->step) / ECORE_CONFIG_FLOAT_PRECISION, + ((double)v) / ECORE_CONFIG_FLOAT_PRECISION); + else + WRN("ecore_config_bound(\"%s\"): integer value %ld not a multiple of %ld, adjusted to %ld...", + e->key, e->val, e->step, v); + ret = ECORE_CONFIG_ERR_SUCC; + e->val = v; + } + } + + return ret; +} + +/** + * Tries to guess the type of a property. + * + * This function first checks to see if the property exists. If it does, then + * the type of the stored property is returned. Otherwise, the function tries + * to guess the type of the property based on @p val. + * + * @param key The property key. + * @param val The value in string form. + * @return The type of the property determined by the function. Note that if + * val is @c NULL, @c ECORE_CONFIG_NIL will be returned. + */ +EAPI int +ecore_config_type_guess(const char *key, const char *val) +{ + Ecore_Config_Prop *p; + char *l; + + l = NULL; + + if (key && (p = ecore_config_get(key)) && p->type != ECORE_CONFIG_NIL) + return p->type; + + if (!val) + return ECORE_CONFIG_NIL; + if (val[0] == '#') + return ECORE_CONFIG_RGB; + strtol(val, &l, 10); + if (*l) + { + float f; + + if (sscanf(val, "%f%*s", &f) != 1) + return ECORE_CONFIG_STR; + return ECORE_CONFIG_FLT; + } + return ECORE_CONFIG_INT; +} + +static int +ecore_config_typed_val(Ecore_Config_Prop * e, const void *val, int type) +{ + + if (!e) + return ECORE_CONFIG_ERR_NODATA; + + if (!(val) && (type != ECORE_CONFIG_NIL && type != ECORE_CONFIG_SCT)) + e->ptr = NULL; + else + { + if (type == ECORE_CONFIG_INT || type == ECORE_CONFIG_BLN) + { + e->val = (long) *((int *)val); + e->type = type; + } + else if (type == ECORE_CONFIG_STR || type == ECORE_CONFIG_THM) + { + if (!(e->ptr = strdup(val))) + return ECORE_CONFIG_ERR_OOM; + if (e->type == ECORE_CONFIG_NIL) + e->type = type; + } + else if (type == ECORE_CONFIG_RGB) + { + __ecore_argbstr_to_long((char *)val, &e->val); + e->type = ECORE_CONFIG_RGB; + } + else if (type == ECORE_CONFIG_FLT) + { + e->val = (long) ((*((float *)val)) * ECORE_CONFIG_FLOAT_PRECISION); + e->type = ECORE_CONFIG_FLT; + } + else if (type == ECORE_CONFIG_SCT) + { + e->type = ECORE_CONFIG_SCT; + } + else + { + e->type = ECORE_CONFIG_NIL; + } + + ecore_config_bound(e); + e->flags |= ECORE_CONFIG_FLAG_MODIFIED; + e->flags &= ~ECORE_CONFIG_FLAG_CMDLN; + return ECORE_CONFIG_ERR_SUCC; + } + return ECORE_CONFIG_ERR_IGNORED; +} + +static int +ecore_config_typed_add(const char *key, const void *val, int type) +{ + int error = ECORE_CONFIG_ERR_SUCC; + Ecore_Config_Prop *e = NULL; + Ecore_Config_Bundle *t; + + t = __ecore_config_bundle_local; + if (!key) + return ECORE_CONFIG_ERR_NODATA; + + if (!(e = calloc(1, sizeof(Ecore_Config_Prop)))) + { + return ECORE_CONFIG_ERR_OOM; + } + else if (!(e->key = strdup(key))) + { + error = ECORE_CONFIG_ERR_OOM; + } + else if ((error = ecore_config_typed_val(e, val, type)) == ECORE_CONFIG_ERR_SUCC) + { + if (t) + { + e->next = t->data; + t->data = e; + } + return ECORE_CONFIG_ERR_SUCC; + } + + if(e->key) + free(e->key); + if(e) + free(e); + + if (error == ECORE_CONFIG_ERR_SUCC) + error = ECORE_CONFIG_ERR_FAIL; + + return error; +} + +static int +ecore_config_add(const char *key, const char *val) +{ + int type; + + type = ecore_config_type_guess(key, val); + return ecore_config_typed_add(key, val, type); +} + +/** + * Sets the description field of the indicated property. + * @param key The property key. + * @param desc Description string. + * @note The description string is copied for the property's use. You can + * free @p desc once this function is called. + * @ingroup Ecore_Config_Property_Group + */ +EAPI int +ecore_config_describe(const char *key, const char *desc) +{ + Ecore_Config_Prop *e; + + if (!(e = ecore_config_get(key))) + return ECORE_CONFIG_ERR_NODATA; + e->description = strdup(desc); + return ECORE_CONFIG_ERR_SUCC; +} + +/** + * Set the short option character of a property. + * @param key The property key. + * @param short_opt Character used to indicate the value of a property + * given on the command line. + * @return @c ECORE_CONFIG_ERR_SUCC on success. @c ECORE_CONFIG_ERR_NODATA + * is returned if the property does not exist. + * @ingroup Ecore_Config_Property_Group + */ +EAPI int +ecore_config_short_opt_set(const char *key, char short_opt) +{ + Ecore_Config_Prop *e; + + if (!(e = ecore_config_get(key))) + return ECORE_CONFIG_ERR_NODATA; + e->short_opt = short_opt; + return ECORE_CONFIG_ERR_SUCC; +} + +/** + * Set the long option string of the property. + * @param key The property key. + * @param long_opt String used to indicate the value of a property given + * on the command line. + * @return @c ECORE_CONFIG_ERR_SUCC on success. @c ECORE_CONFIG_ERR_NODATA + * is returned if the property does not exist. + * @ingroup Ecore_Config_Property_Group + */ +EAPI int +ecore_config_long_opt_set(const char *key, const char *long_opt) +{ + Ecore_Config_Prop *e; + + if (!(e = ecore_config_get(key))) + return ECORE_CONFIG_ERR_NODATA; + if (e->long_opt) + free(e->long_opt); + if (long_opt) + e->long_opt = strdup(long_opt); + return ECORE_CONFIG_ERR_SUCC; +} + +static void +_ecore_config_listener_fire(Ecore_Config_Prop *prop) +{ + Ecore_Config_Listener_List *l; + for (l = prop->listeners; l; l = l->next) + l->listener(prop->key, prop->type, l->tag, l->data); + + /* fire change listeners for the generic struct container etc */ + if (prop->parent) + _ecore_config_listener_fire(prop->parent); +} + +/** + * Sets the indicated property to the given value and type. + * @param key The property key. + * @param val A pointer to the value to set the property to. + * @param type The type of the property. + * @return @c ECORE_CONFIG_ERR_SUCC if the property is set successfully. + * @ingroup Ecore_Config_Property_Group + */ +EAPI int +ecore_config_typed_set(const char *key, const void *val, int type) +{ + Ecore_Config_Prop *e; + int ret; + + if (!key) + return ECORE_CONFIG_ERR_NODATA; +/* if (!t) { * global prop * + e=ecore_config_get(key); + if (e) + for(l=e->listeners;l;l=l->next) + l->listener(e->key,e->type,l->tag,l->data,t); + return ECORE_CONFIG_ERR_SUCC; + } +*/ + if (!(e = ecore_config_get(key))) + return ecore_config_typed_add(key, val, type); + + if ((ret = ecore_config_typed_val(e, val, type)) == ECORE_CONFIG_ERR_SUCC) + { + _ecore_config_listener_fire(e); + } + else + { + ERR("ecore_config_typed_set(\"%s\"): ecore_config_typed_val() failed: %d", + key, ret); + } + + return ret; +} + +/** + * @defgroup Ecore_Config_Set_Group Ecore Config Setters + * + * Functions that set the value of a property. + */ + +/** + * Sets the indicated property to the value indicated by @a val. + * @param key The property key. + * @param val String representation of value to set. + * @return @c ECORE_CONFIG_ERR_SUCC if the property is set successfully. + * @ingroup Ecore_Config_Set_Group + */ +EAPI int +ecore_config_set(const char *key, const char *val) +{ + int type; + int tmpi; + float tmpf; + long tmpl; + + type = ecore_config_type_guess(key, val); + if (type == ECORE_CONFIG_INT || type == ECORE_CONFIG_BLN) + { + tmpi = atoi(val); + return ecore_config_typed_set(key, &tmpi, type); + } + else if (type == ECORE_CONFIG_FLT) + { + tmpf = atof(val); + return ecore_config_typed_set(key, &tmpf, type); + } + else if (type == ECORE_CONFIG_RGB) + { + __ecore_argbstr_to_long(val, &tmpl); + return ecore_config_typed_set(key, &tmpl, type); + } + else + return ecore_config_typed_set(key, val, type); +} + +/** + * Sets the indicated property to the value given in the string. + * @param key The property key. + * @param val String representation of the value. + * @return @c ECORE_CONFIG_ERR_SUCC if the property is set successfully. + * @ingroup Ecore_Config_Set_Group + */ +EAPI int +ecore_config_as_string_set(const char *key, const char *val) +{ + return ecore_config_set(key, val); +} + +/** + * Sets the indicated property to the given boolean. + * @param key The property key. + * @param val Boolean integer to set the property to. + * @return @c ECORE_CONFIG_ERR_SUCC if the property is set successfully. + * @ingroup Ecore_Config_Set_Group + */ +EAPI int +ecore_config_boolean_set(const char *key, int val) +{ + val = val ? 1 : 0; + return ecore_config_typed_set(key, &val, ECORE_CONFIG_BLN); +} + +/** + * Sets the indicated property to the given integer. + * @param key The property key. + * @param val Integer to set the property to. + * @return @c ECORE_CONFIG_ERR_SUCC if the property is set successfully. + * @ingroup Ecore_Config_Set_Group + */ +EAPI int +ecore_config_int_set(const char *key, int val) +{ + return ecore_config_typed_set(key, &val, ECORE_CONFIG_INT); +} + +/** + * Sets the indicated property to the given string. + * @param key The property key. + * @param val String to set the property to. + * @return @c ECORE_CONFIG_ERR_SUCC if the property is set successfully. + * @ingroup Ecore_Config_Set_Group + */ +EAPI int +ecore_config_string_set(const char *key, const char *val) +{ + return ecore_config_typed_set(key, val, ECORE_CONFIG_STR); +} + +/** + * Sets the indicated property to the given float value. + * @param key The property key. + * @param val Float to set the property to. + * @return @c ECORE_CONFIG_ERR_SUCC if the property is set successfully. + * @ingroup Ecore_Config_Set_Group + */ +EAPI int +ecore_config_float_set(const char *key, float val) +{ + return ecore_config_typed_set(key, &val, ECORE_CONFIG_FLT); +} + +/** + * Sets the indicated property to a color value. + * @param key The property key + * @param a integer 0..255 + * @param r integer 0..255 + * @param g integer 0..255 + * @param b integer 0..255 + * @return @c ECORE_CONFIG_ERR_SUCC if the property is set successfully. + * @ingroup Ecore_Config_Set_Group + */ +EAPI int +ecore_config_argb_set(const char *key, int a, int r, int g, int b) +{ + long v = 0; + return ecore_config_typed_set(key, __ecore_argb_to_long(a,r,g,b, &v), ECORE_CONFIG_RGB); +} + +/** + * Sets the indicated property to a color value. + * @param key The property key + * @param argb ARGB data as long + * @return @c ECORE_CONFIG_ERR_SUCC if the property is set successfully. + * @ingroup Ecore_Config_Set_Group + */ +EAPI int +ecore_config_argbint_set(const char *key, long argb) +{ + return ecore_config_typed_set(key, &argb, ECORE_CONFIG_RGB); +} + +/** + * Sets the indicated property to a color value. + * @param key The property key + * @param val Color value in ARGB format. + * @return @c ECORE_CONFIG_ERR_SUCC if the property is set successfully. + * @ingroup Ecore_Config_Set_Group + */ +EAPI int +ecore_config_argbstr_set(const char *key, const char *val) +{ + long v = 0; + return ecore_config_typed_set(key, __ecore_argbstr_to_long(val, &v), ECORE_CONFIG_RGB); +} + +/** + * Sets the indicated property to a theme name. + * @param key The property key. + * @param val String giving the name of the theme. + * @return @c ECORE_CONFIG_ERR_SUCC if the property is set successfully. + * @ingroup Ecore_Config_Set_Group + */ +EAPI int +ecore_config_theme_set(const char *key, const char *val) +{ + return ecore_config_typed_set(key, val, ECORE_CONFIG_THM); +} + +/** + * Sets the theme preview group of an indicated property. + * @param key The property key. + * @param group The group name. + * @return @c ECORE_CONFIG_ERR_SUCC on success. + * @ingroup Ecore_Config_Set_Group + */ +EAPI int +ecore_config_theme_preview_group_set(const char *key, const char *group) +{ + int ret; + Ecore_Config_Prop *e; + + ret = ECORE_CONFIG_ERR_SUCC; + if (!(e = ecore_config_get(key))) + { /* prop doesn't exist yet */ + if ((ret = ecore_config_typed_add(key, "", ECORE_CONFIG_THM)) != ECORE_CONFIG_ERR_SUCC) /* try to add it */ + return ret; /* ...failed */ + if (!(e = ecore_config_get(key))) /* get handle */ + return ECORE_CONFIG_ERR_FAIL; + } + if (e->data) + free(e->data); + e->data = strdup(group); + + return ret; +} + +EAPI int +ecore_config_typed_default(const char *key, const void *val, int type) +{ + int ret; + Ecore_Config_Prop *e; + + ret = ECORE_CONFIG_ERR_SUCC; + + if (!(e = ecore_config_get(key))) + { /* prop doesn't exist yet */ + if ((ret = ecore_config_typed_add(key, val, type)) != ECORE_CONFIG_ERR_SUCC) /* try to add it */ + return ret; /* ...failed */ + if (!(e = ecore_config_get(key))) /* get handle */ + return ECORE_CONFIG_ERR_FAIL; + e->flags = e->flags & ~ECORE_CONFIG_FLAG_MODIFIED; + } + else if (!(e->flags & ECORE_CONFIG_FLAG_MODIFIED) && !(e->flags & ECORE_CONFIG_FLAG_SYSTEM)) + { + ecore_config_typed_set(key, val, type); + if (!(e = ecore_config_get(key))) /* get handle */ + return ECORE_CONFIG_ERR_FAIL; + e->flags = e->flags & ~ECORE_CONFIG_FLAG_MODIFIED; + } + return ret; +} + +/** + * @defgroup Ecore_Config_Default_Group Ecore Config Defaults + * + * Functions that are used to set the default values of properties. + */ + +/** + * Sets the indicated property if it has not already been set or loaded. + * @param key The property key. + * @param val Default value of the key. + * @param lo Lowest valid value for the key. + * @param hi Highest valid value for the key. + * @param step Used by integer and float values. + * @return @c ECORE_CONFIG_ERR_SUCC if there are no errors. + * @note The @p lo, @p hi and @p step parameters are only used when storing + * integer and float properties. + * @ingroup Ecore_Config_Default_Group + */ +EAPI int +ecore_config_default(const char *key, const char *val, float lo, float hi, float step) +{ + int ret, type; + Ecore_Config_Prop *e; + + type = ecore_config_type_guess(key, val); + ret = ecore_config_typed_default(key, val, type); + e = ecore_config_get(key); + if (e) + { + if (type == ECORE_CONFIG_INT) + { + e->step = step; + e->flags |= ECORE_CONFIG_FLAG_BOUNDS; + e->lo = lo; + e->hi = hi; + ecore_config_bound(e); + } + else if (type == ECORE_CONFIG_FLT) + { + e->step = (int)(step * ECORE_CONFIG_FLOAT_PRECISION); + e->flags |= ECORE_CONFIG_FLAG_BOUNDS; + e->lo = (int)(lo * ECORE_CONFIG_FLOAT_PRECISION); + e->hi = (int)(hi * ECORE_CONFIG_FLOAT_PRECISION); + ecore_config_bound(e); + } + } + + return ret; +} + +/** + * Sets the indicated property to the given boolean if the property has not yet + * been set. + * @param key The property key. + * @param val Boolean Integer to set the value to. + * @return @c ECORE_CONFIG_ERR_SUCC if there are no problems. + * @ingroup Ecore_Config_Default_Group + */ +EAPI int +ecore_config_boolean_default(const char *key, int val) +{ + val = val ? 1 : 0; + return ecore_config_typed_default(key, &val, ECORE_CONFIG_BLN); +} + +/** + * Sets the indicated property to the given integer if the property has not yet + * been set. + * @param key The property key. + * @param val Integer to set the value to. + * @return @c ECORE_CONFIG_ERR_SUCC if there are no problems. + * @ingroup Ecore_Config_Default_Group + */ +EAPI int +ecore_config_int_default(const char *key, int val) +{ + return ecore_config_typed_default(key, &val, ECORE_CONFIG_INT); +} + +/** + * Sets the indicated property to the given integer if the property has not yet + * been set. + * + * The bounds and step values are set regardless. + * + * @param key The property key. + * @param val Integer to set the property to. + * @param low Lowest valid integer value for the property. + * @param high Highest valid integer value for the property. + * @param step Increment value for the property. + * @return @c ECORE_CONFIG_ERR_SUCC if there were no problems. + * @ingroup Ecore_Config_Default_Group + */ +EAPI int +ecore_config_int_default_bound(const char *key, int val, int low, int high, + int step) +{ + Ecore_Config_Prop *e; + int ret; + + ret = ecore_config_typed_default(key, &val, ECORE_CONFIG_INT); + e = ecore_config_get(key); + if (e) + { + e->step = step; + e->flags |= ECORE_CONFIG_FLAG_BOUNDS; + e->lo = low; + e->hi = high; + ecore_config_bound(e); + } + + return ret; +} + +/** + * Sets the indicated property to the given string if the property has not yet + * been set. + * @param key The property key. + * @param val String to set the property to. + * @return @c ECORE_CONFIG_ERR_SUCC if there were no problems. + * @ingroup Ecore_Config_Default_Group + */ +EAPI int +ecore_config_string_default(const char *key, const char *val) +{ + return ecore_config_typed_default(key, val, ECORE_CONFIG_STR); +} + +/** + * Sets the indicated property to the given float if the property has not yet + * been set. + * @param key The property key. + * @param val Float to set the property to. + * @return @c ECORE_CONFIG_ERR_SUCC if there were no problems. + * @ingroup Ecore_Config_Default_Group + */ +EAPI int +ecore_config_float_default(const char *key, float val) +{ + return ecore_config_typed_default(key, &val, ECORE_CONFIG_FLT); +} + +/** + * Sets the indicated property to the given float if the property has not yet + * been set. + * + * The bounds and step values are set regardless. + * + * @param key The property key. + * @param val Float to set the property to. + * @param low Lowest valid integer value for the property. + * @param high Highest valid float value for the property. + * @param step Increment value for the property. + * @return @c ECORE_CONFIG_ERR_SUCC if there were no problems. + * @ingroup Ecore_Config_Default_Group + */ +EAPI int +ecore_config_float_default_bound(const char *key, float val, float low, + float high, float step) +{ + Ecore_Config_Prop *e; + int ret; + + ret = ecore_config_typed_default(key, &val, ECORE_CONFIG_FLT); + e = ecore_config_get(key); + if (e) + { + e->step = (int)(step * ECORE_CONFIG_FLOAT_PRECISION); + e->flags |= ECORE_CONFIG_FLAG_BOUNDS; + e->lo = (int)(low * ECORE_CONFIG_FLOAT_PRECISION); + e->hi = (int)(high * ECORE_CONFIG_FLOAT_PRECISION); + ecore_config_bound(e); + } + + return ret; +} + +/** + * Sets the indicated property to a color value if the property has not yet + * been set. + * @param key The property key. + * @param a integer 0..255 + * @param r integer 0..255 + * @param g integer 0..255 + * @param b integer 0..255 + * @return @c ECORE_CONFIG_ERR_SUCC if there are no problems. + * @ingroup Ecore_Config_Default_Group + */ +EAPI int +ecore_config_argb_default(const char *key, int a, int r, int g, int b) +{ + long v = 0; + return ecore_config_typed_default(key, __ecore_argb_to_long(a,r,g,b, &v), ECORE_CONFIG_RGB); +} + +/** + * Sets the indicated property to a color value if the property has not yet + * been set. + * @param key The property key. + * @param argb ARGB data as long + * @return @c ECORE_CONFIG_ERR_SUCC if there are no problems. + * @ingroup Ecore_Config_Default_Group + */ +EAPI int +ecore_config_argbint_default(const char *key, long argb) +{ + return ecore_config_typed_default(key, &argb, ECORE_CONFIG_RGB); +} + +/** + * Sets the indicated property to a color value if the property has not yet + * been set. + * @param key The property key. + * @param val Color value in ARGB format. + * @return @c ECORE_CONFIG_ERR_SUCC if there are no problems. + * @ingroup Ecore_Config_Default_Group + */ +EAPI int +ecore_config_argbstr_default(const char *key, const char *val) +{ + long v = 0; + return ecore_config_typed_default(key, __ecore_argbstr_to_long(val, &v), ECORE_CONFIG_RGB); +} + +/** + * Sets the indicated property to a theme name if the property has not yet + * been set. + * @param key The property key. + * @param val String giving the name of the theme. + * @return @c ECORE_CONFIG_ERR_SUCC if the property is set successfully. + * @ingroup Ecore_Config_Default_Group + */ +EAPI int +ecore_config_theme_default(const char *key, const char *val) +{ + return ecore_config_typed_default(key, val, ECORE_CONFIG_THM); +} + +/** + * @defgroup Ecore_Config_Struct_Group Ecore Config Structures + * + * Functions that are used to create structures of properties. + */ + +/** + * Sets the indicated property to a structure if the property has not yet + * been set. + * @param key The property key. + * @return @c ECORE_CONFIG_ERR_SUCC if the property is set successfully. + * @ingroup Ecore_Config_Struct_Group + */ +EAPI int +ecore_config_struct_create(const char *key) +{ + WRN("you are using ecore_config structures. These are very young"); + WRN(" and not complete - you have been warned"); + + return ecore_config_typed_default(key, NULL, ECORE_CONFIG_SCT); +} + +static int +_ecore_config_struct_append(Ecore_Config_Prop *sct, Ecore_Config_Prop *add) +{ + Eina_List *l; + + if (!sct || !add || sct->type != ECORE_CONFIG_SCT) + return ECORE_CONFIG_ERR_IGNORED; + + l = sct->data; + sct->data = eina_list_append(l, add); + add->parent = sct; + + return ECORE_CONFIG_ERR_SUCC; +} + +static int +_ecore_config_struct_typed_add(const char *key, const char *name, const void *val, + int type) +{ + char *subkey; + int ret; + + subkey = malloc((strlen(key) + strlen(name) + 2) * sizeof(char)); + strcpy(subkey, key); + strcat(subkey, "."); + strcat(subkey, name); + + ecore_config_typed_default(subkey, val, type); + ret = _ecore_config_struct_append(ecore_config_get(key), + ecore_config_get(subkey)); + free(subkey); + return ret; +} + +/** + * Add an int property to the named structure. The property is set if it has not + * yet been set. + * @param key The key of the structure to add to. + * @param name The name of the item to add - this will be appended to the key + * @param val the int to default to + * @return @c ECORE_CONFIG_ERR_SUCC if the property is set successfully. + * @ingroup Ecore_Config_Struct_Group + */ +EAPI int +ecore_config_struct_int_add(const char *key, const char *name, int val) +{ + return _ecore_config_struct_typed_add(key, name, &val, ECORE_CONFIG_INT); +} + +/** + * Add a float property to the named structure. The property is set if it has + * not yet been set. + * @param key The key of the structure to add to. + * @param name The name of the item to add - this will be appended to the key + * @param val The float to default to + * @return @c ECORE_CONFIG_ERR_SUCC if the property is set successfully. + * @ingroup Ecore_Config_Struct_Group + */ +EAPI int +ecore_config_struct_float_add(const char *key, const char *name, float val) +{ + return _ecore_config_struct_typed_add(key, name, &val, ECORE_CONFIG_FLT); +} + +/** + * Add a string property to the named structure. The property is set if it has + * not yet been set. + * @param key The key of the structure to add to. + * @param name The name of the item to add - this will be appended to the key + * @param val The string to default to + * @return @c ECORE_CONFIG_ERR_SUCC if the property is set successfully. + * @ingroup Ecore_Config_Struct_Group + */ +EAPI int +ecore_config_struct_string_add(const char *key, const char *name, const char* val) +{ + return _ecore_config_struct_typed_add(key, name, val, ECORE_CONFIG_STR); +} + +/** + * Add an argb property to the named structure. The property is set if it has + * not yet been set. + * @param key The key of the structure to add to. + * @param name The name of the item to add - this will be appended to the key + * @param a The alpha to default to + * @param r The red to default to + * @param g The green to default to + * @param b The blue to default to + * @return @c ECORE_CONFIG_ERR_SUCC if the property is set successfully. + * @ingroup Ecore_Config_Struct_Group + */ +EAPI int +ecore_config_struct_argb_add(const char *key, const char *name, int a, int r, + int g, int b) +{ + long argb; + + __ecore_argb_to_long(a, r, g, b, &argb); + return _ecore_config_struct_typed_add(key, name, &argb, ECORE_CONFIG_RGB); +} + +/** + * Add a theme property to the named structure. The property is set if it has + * not yet been set. + * @param key The key of the structure to add to. + * @param name The name of the item to add - this will be appended to the key + * @param val The theme name to default to + * @return @c ECORE_CONFIG_ERR_SUCC if the property is set successfully. + * @ingroup Ecore_Config_Struct_Group + */ +EAPI int +ecore_config_struct_theme_add(const char *key, const char *name, const char* val) +{ + return _ecore_config_struct_typed_add(key, name, val, ECORE_CONFIG_THM); +} + +/** + * Add a boolean property to the named structure. The property is set if it has + * not yet been set. + * @param key The key of the structure to add to. + * @param name The name of the item to add - this will be appended to the key + * @param val The boolean to default to + * @return @c ECORE_CONFIG_ERR_SUCC if the property is set successfully. + * @ingroup Ecore_Config_Struct_Group + */ +EAPI int +ecore_config_struct_boolean_add(const char *key, const char *name, int val) +{ + val = val ? 1 : 0; + return _ecore_config_struct_typed_add(key, name, &val, ECORE_CONFIG_BLN); +} + +/** + * Get the contents of a defined structure property and load it into the passed + * C struct + * @param key The name of the structure property to look up. + * @param data The struct to write into. + * @return @c ECORE_CONFIG_ERR_SUCC if the structure is written successfully. + * @ingroup Ecore_Config_Struct_Group + */ +EAPI int +ecore_config_struct_get(const char *key, void *data) +{ + Ecore_Config_Prop *e, *f; + Eina_List *l; + unsigned char *ptr; + long argb; + + e = ecore_config_get(key); + if (!e) + return ECORE_CONFIG_ERR_NODATA; + + l = e->data; + ptr = data; + while (l) + { + f = (Ecore_Config_Prop *) l->data; + switch (f->type) + { + case ECORE_CONFIG_INT: + *((int *) ptr) = _ecore_config_int_get(f); + ptr += sizeof(int); + break; + case ECORE_CONFIG_BLN: + *((int *) ptr) = _ecore_config_boolean_get(f); + ptr += sizeof(int); + break; + case ECORE_CONFIG_FLT: + *((float *) ptr) = _ecore_config_float_get(f); + ptr += sizeof(float); + break; + case ECORE_CONFIG_STR: + case ECORE_CONFIG_THM: + *((char **) ptr) = _ecore_config_string_get(f); + ptr += sizeof(char *); + break; + case ECORE_CONFIG_RGB: + argb = _ecore_config_argbint_get(f); + *((int *) ptr) = (argb >> 24) & 0xff; + ptr += sizeof(int); + *((int *) ptr) = (argb >> 16) & 0xff; + ptr += sizeof(int); + *((int *) ptr) = (argb >> 8) & 0xff; + ptr += sizeof(int); + *((int *) ptr) = argb & 0xff; + ptr += sizeof(int); + break; + default: + WRN("ARGH - STRUCT coding not implemented yet"); + } + l = eina_list_next(l); + } + return ECORE_CONFIG_ERR_SUCC; +} + +/** + * @defgroup Ecore_Config_Listeners_Group Ecore Config Listeners + * + * Functions that set and unset property listener callbacks. + */ + +/** + * Adds a callback function to the list of functions called when a property + * changes. + * @param name Name of the callback. + * @param key The key of the property to listen to. + * @param listener Listener callback function. + * @param tag Tag to pass to @p listener when it is called. + * @param data Data to pass to @p listener when it is called. + * @return @c ECORE_CONFIG_ERR_SUCC if successful in setting up the callback. + * @ingroup Ecore_Config_Listeners_Group + */ +EAPI int +ecore_config_listen(const char *name, const char *key, + Ecore_Config_Listener listener, int tag, void *data) +{ + Ecore_Config_Prop *e; + Ecore_Config_Listener_List *l; + + if (!key) + return ECORE_CONFIG_ERR_NODATA; + + if (!(e = ecore_config_get(key))) + { + int ret = ecore_config_add(key, ""); + + if (ret != ECORE_CONFIG_ERR_SUCC) + { + ERR("ecore_config_listen: ecore_config_add(\"%s\") failed: %d", + key, ret); + return ret; + } + if (!(e = ecore_config_get(key))) + { + ERR("ecore_config_listen: list of properties corrupted!?"); + return ECORE_CONFIG_ERR_FAIL; + } + } + + for (l = e->listeners; l; l = l->next) + if (!strcmp(l->name, name) || (l->listener == listener)) + { + ERR("ecore_config_listen: %s is already listening for changes of %s...", + name, key); + return ECORE_CONFIG_ERR_IGNORED; + } + + if (!(l = malloc(sizeof(Ecore_Config_Listener_List)))) + return ECORE_CONFIG_ERR_OOM; + + ERR("registering listener \"%s\" for \"%s\" (%d)...", name, key, e->type); + + memset(l, 0, sizeof(Ecore_Config_Listener_List)); + + l->listener = listener; + l->name = name; + l->data = data; + l->tag = tag; + l->next = e->listeners; + e->listeners = l; + + if (e->type != ECORE_CONFIG_NIL) /* call right on creation if prop exists and has val */ + listener(key, e->type, tag, data); + + return ECORE_CONFIG_ERR_SUCC; +} + +/** + * Removes a listener callback. + * @param name Name of the callback to remove. + * @param key The property key the callback is listening to. + * @param listener The callback function to remove. + * @return @c ECORE_CONFIG_ERR_SUCC if successful in removing the callback. + * If no callback matches the given parameters, then + * @c ECORE_CONFIG_ERR_NOTFOUND is returned. If @c NULL is passed + * for the key pointer, @c ECORE_CONFIG_ERR_NODATA is returned. + * @ingroup Ecore_Config_Listeners_Group + */ +EAPI int +ecore_config_deaf(const char *name, const char *key, + Ecore_Config_Listener listener) +{ + Ecore_Config_Prop *e; + Ecore_Config_Listener_List *l, *p; + int ret; + + ret = ECORE_CONFIG_ERR_NOTFOUND; + + if (!key) + return ECORE_CONFIG_ERR_NODATA; + + if (!(e = ecore_config_get(key))) + return ECORE_CONFIG_ERR_NOTFOUND; + + for (p = NULL, l = e->listeners; l; p = l) + { + Ecore_Config_Listener_List *nl; + + nl = l->next; + if ((name && !strcmp(l->name, name)) || (l->listener == listener)) + { + ret = ECORE_CONFIG_ERR_SUCC; + if (!p) + e->listeners = e->listeners->next; + else + p->next = l->next; + memset(l, 0, sizeof(Ecore_Config_Listener)); + free(l); + } + l = nl; + } + + return ret; +} + +/** + * Locates the first configuration bundle on the given server. + * @param srv The configuration server. + * @return Pointer to the first configuration bundle. + */ +EAPI Ecore_Config_Bundle * +ecore_config_bundle_1st_get(Ecore_Config_Server * srv) +{ /* anchor: global, but read-only */ + return srv->bundles; +} + +/** + * Locates the configuration bundle after the given one. + * @param ns The configuration bundle. + * @return The next configuration bundle. + */ +EAPI Ecore_Config_Bundle * +ecore_config_bundle_next_get(Ecore_Config_Bundle * ns) +{ + return ns ? ns->next : NULL; +} + +/** + * Locates a configuration bundle on a configuration server based on its serial + * number. + * @param srv The configuration server. + * @param serial Serial number. + * @return The configuration bundle with the given serial number. + */ +EAPI Ecore_Config_Bundle * +ecore_config_bundle_by_serial_get(Ecore_Config_Server * srv, long serial) +{ + Ecore_Config_Bundle *eb; + + eb = srv->bundles; + + if (serial < 0) + return NULL; + else if (serial == 0) + { + Ecore_Config_Bundle *r = eb; + + return r; + } + + while (eb) + { + if (eb->serial == serial) + return eb; + eb = eb->next; + } + return NULL; +} + +/** + * Gets the Ecore_Config_Bundle with the given identifier from the given + * server. + * @param srv The configuration server. + * @param label The bundle's identifier string. + * @return The bundle with the given identifier string, or @c NULL if it + * could not be found. + */ +EAPI Ecore_Config_Bundle * +ecore_config_bundle_by_label_get(Ecore_Config_Server * srv, const char *label) +{ + Ecore_Config_Bundle *ns; + + ns = srv->bundles; + + while (ns) + { + if (ns->identifier && !strcmp(ns->identifier, label)) + return ns; + ns = ns->next; + } + return NULL; +} + +/** + * Retrieves the bundle's serial number. + * @param ns The configuration bundle. + * @return The bundle's identifier string, or -1 if ns is @c NULL. + */ +EAPI long +ecore_config_bundle_serial_get(Ecore_Config_Bundle * ns) +{ + return ns ? ns->serial : -1; +} + +/** + * Retrieves the bundle's identifier. + * @param ns The configuration bundle. + * @return The bundle's identifer string. + */ +EAPI char * +ecore_config_bundle_label_get(Ecore_Config_Bundle * ns) +{ + return ns ? ns->identifier : NULL; +} + +/** + * Creates a new Ecore_Config_Bundle. + * @param srv Config server. + * @param identifier Identifier string for the new bundle. + * @return A pointer to a new Ecore_Config_Bundle. @c NULL is returned if the + * structure couldn't be allocated. + */ +EAPI Ecore_Config_Bundle * +ecore_config_bundle_new(Ecore_Config_Server * srv, const char *identifier) +{ + Ecore_Config_Bundle *t; + static long ss; + + ss = 0; /* bundle unique serial */ + + if ((t = malloc(sizeof(Ecore_Config_Bundle)))) + { + memset(t, 0, sizeof(Ecore_Config_Bundle)); + + t->identifier = (char *)identifier; + t->serial = ++ss; + t->owner = srv->name; + t->next = srv->bundles; + srv->bundles = t; + } + return t; +} + +static Ecore_Config_Server * +do_init(const char *name) +{ + return _ecore_config_ipc_init(name); +} + +static Ecore_Config_Server * +ecore_config_init_local(const char *name) +{ + char *p; + char *buf; + + if ((p = getenv("HOME"))) + { /* debug-only ### FIXME */ + if (!(buf = malloc(PATH_MAX * sizeof(char)))) + return NULL; + snprintf(buf, PATH_MAX, "%s/.ecore/%s/.global", p, name); + unlink(buf); + + free(buf); + } + + return do_init(name); +} + +static Ecore_Config_Server * +ecore_config_init_global(const char *name) +{ + char *p; + int global; + char *buf; + + if ((p = getenv("HOME"))) + { /* debug-only ### FIXME */ + if (!(buf = malloc(PATH_MAX * sizeof(char)))) + return NULL; + snprintf(buf, PATH_MAX, "%s/.ecore/%s/.global", p, name); + global = creat(buf, S_IRWXU); + + if (global >= 0) + close(global); + + free(buf); + } + + return do_init(name); +} + +/** + * @defgroup Ecore_Config_App_Lib_Group Ecore Config App Library Functions + * + * Functions that are used to start up and shutdown the Enlightened + * Property Library when used directly by an application. + */ + +/** + * Initializes the Enlightened Property Library. + * + * Either this function or @ref ecore_config_system_init must be run + * before any other function in the Enlightened Property Library, even + * if you have run @ref ecore_init . The name given is used to + * determine the default configuration to load. + * + * @param name Application name + * @return @c ECORE_CONFIG_ERR_SUCC if the library is successfully set up. + * @c ECORE_CONFIG_ERR_FAIL otherwise. + * @ingroup Ecore_Config_App_Lib_Group + */ +EAPI int +ecore_config_init(const char *name) +{ + char *path; + Ecore_Config_Prop *list; + _ecore_config_log_dom = eina_log_domain_register + ("ecore_config", ECORE_CONFIG_DEFAULT_LOG_COLOR); + if(_ecore_config_log_dom < 0) + { + EINA_LOG_ERR("Impossible to create a log domain for the Ecore config module."); + return -1; + } + _ecore_config_system_init_no_load(); + + __ecore_config_app_name = strdup(name); + __ecore_config_server_local = ecore_config_init_local(name); + if (!__ecore_config_server_local) + return ECORE_CONFIG_ERR_FAIL; + + list = __ecore_config_bundle_local->data; + free( __ecore_config_bundle_local ); + __ecore_config_bundle_local = + ecore_config_bundle_new(__ecore_config_server_local, "config"); + __ecore_config_bundle_local->data = list; + + path = ecore_config_theme_default_path_get(); + ecore_config_string_default("/e/themes/search_path", path); + if (path) + free(path); + + list = ecore_config_get("/e/themes/search_path"); + if (list) + { + list->flags |= ECORE_CONFIG_FLAG_SYSTEM; + list->flags &= ~ECORE_CONFIG_FLAG_MODIFIED; + } + + return _ecore_config_system_load(); +} + +/** + * Frees memory and shuts down the library for an application. + * @return @c ECORE_CONFIG_ERR_IGNORED . + * @ingroup Ecore_Config_App_Lib_Group + */ +EAPI int +ecore_config_shutdown(void) +{ + return ecore_config_system_shutdown(); +} + +/** + * @defgroup Ecore_Config_Lib_Lib_Group Ecore Config Library Functions + * + * Functions that are used to start up and shutdown the Enlightened + * Property Library when used directly by an application. + */ + +/** + * Initializes the Enlightened Property Library. + * + * This function is meant to be run from other programming libraries. + * It should not be called from applications. + * + * This function (or @ref ecore_config_init ) + * must be run before any other function in the + * Enlightened Property Library, even if you have run @ref ecore_init . + * + * @return @c ECORE_CONFIG_ERR_SUCC if the library is successfully set up. + * @c ECORE_CONFIG_ERR_FAIL otherwise. + * @ingroup Ecore_Config_Lib_Lib_Group + */ +EAPI int +ecore_config_system_init(void) +{ + _ecore_config_system_init_no_load(); + return _ecore_config_system_load(); +} + +static int +_ecore_config_system_init_no_load(void) +{ + char *p; + + __ecore_config_system_init++; + if (__ecore_config_system_init > 1) + return ECORE_CONFIG_ERR_IGNORED; + + DEBUG = -1; + if ((p = getenv("ECORE_CONFIG_DEBUG")) && p[0] != 0) + { + DEBUG = atoi(p); + } + + __ecore_config_server_global = + ecore_config_init_global(ECORE_CONFIG_GLOBAL_ID); + if (!__ecore_config_server_global) + return ECORE_CONFIG_ERR_FAIL; + + __ecore_config_bundle_local = + ecore_config_bundle_new(__ecore_config_server_global, "system"); + + /* set up a simple default path */ + ecore_config_string_default("/e/themes/search_path", PACKAGE_DATA_DIR "../ewl/themes"); + + return ECORE_CONFIG_ERR_SUCC; +} + + +static int +_ecore_config_system_load(void) +{ + char *buf, *p; + Ecore_Config_Prop *sys; + + if (__ecore_config_system_init != 1) + return ECORE_CONFIG_ERR_FAIL; + + if ((p = getenv("HOME"))) + { /* debug-only ### FIXME */ + if ((buf = malloc(PATH_MAX * sizeof(char)))) + { + snprintf(buf, PATH_MAX, "%s/.e/config.eet", p); + if (ecore_config_file_load(buf) != 0) { + /* even if this file (system.eet) doesn't exist we can + * continue without it as it isn't striclty necessary. + */ + ecore_config_file_load(PACKAGE_DATA_DIR "/system.eet"); + } + sys = __ecore_config_bundle_local->data; + while (sys) + { + /* unmark it modified - modification will mean it has been overridden */ + sys->flags &= ~ECORE_CONFIG_FLAG_MODIFIED; + /* mark as system so that examine can hide them */ + sys->flags |= ECORE_CONFIG_FLAG_SYSTEM; + sys = sys->next; + } + } + free(buf); + } + + return ECORE_CONFIG_ERR_SUCC; +} + + +/** + * Frees memory and shuts down the library for other programming libraries. + * @return @c ECORE_CONFIG_ERR_IGNORED + * @ingroup Ecore_Config_Lib_Lib_Group + */ +EAPI int +ecore_config_system_shutdown(void) +{ + int ret; + + __ecore_config_system_init--; + if (__ecore_config_system_init > 0) + return ECORE_CONFIG_ERR_IGNORED; + + ret = _ecore_config_ipc_exit(); + if (__ecore_config_app_name) + free(__ecore_config_app_name); + while(__ecore_config_bundle_local->data) + ecore_config_dst(__ecore_config_bundle_local->data); + free(__ecore_config_bundle_local); + free(__ecore_config_server_local); + free(__ecore_config_server_global); + eina_log_domain_unregister(_ecore_config_log_dom); + _ecore_config_log_dom = -1; + return ret; +} + +static inline void * +__ecore_argb_to_long(int a, int r, int g, int b, long *v) +{ + *v = ((a << 24) & 0xff000000 ) + | ((r << 16) & 0xff0000 ) + | ((g << 8) & 0xff00 ) + | ( b & 0xff ); + + return v; +} + +static inline void * +__ecore_argbstr_to_long(const char *argb, long *v) +{ + char *l = NULL; + + // convert hexadecimal string #..., #0x..., 0x..., ... to long + if(*argb == '#') + argb++; + *v = (long)strtoul( argb, &l, 16); + + if(*l) + { + ERR("ecore_config_val: value \"%s\" not a valid hexadecimal RGB value?", argb); + return NULL; + } + + return v; +} + diff --git a/src/lib/ecore_config/ecore_config_db.c b/src/lib/ecore_config/ecore_config_db.c new file mode 100644 index 0000000..6238958 --- /dev/null +++ b/src/lib/ecore_config/ecore_config_db.c @@ -0,0 +1,296 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "Ecore_Config.h" +#include "ecore_config_private.h" +#include "ecore_config_util.h" + +struct _Ecore_Config_DB_File +{ + Eet_File *ef; +}; + +Ecore_Config_DB_File * +_ecore_config_db_open_read(const char *file) +{ + Eet_File *ef; + Ecore_Config_DB_File *db; + + eet_init(); + db = malloc(sizeof(Ecore_Config_DB_File)); + if (!db) return NULL; + ef = eet_open((char*)file, EET_FILE_MODE_READ); + if (!ef) + { + free(db); + return NULL; + } + db->ef = ef; + return db; +} + +Ecore_Config_DB_File * +_ecore_config_db_open_write(const char *file) +{ + Eet_File *ef; + Ecore_Config_DB_File *db; + + eet_init(); + db = malloc(sizeof(Ecore_Config_DB_File)); + if (!db) return NULL; + ef = eet_open((char*)file, EET_FILE_MODE_WRITE); + if (!ef) + { + free(db); + return NULL; + } + db->ef = ef; + return db; +} + +void +_ecore_config_db_close(Ecore_Config_DB_File *db) +{ + eet_close(db->ef); + free(db); + eet_shutdown(); +} + +char ** +_ecore_config_db_keys_get(Ecore_Config_DB_File *db, int *num_ret) +{ + char **keys; + int key_count; + int i; + + keys = eet_list(db->ef, (char*)"*", &key_count); + if (!keys) + { + *num_ret = 0; + return NULL; + } + /* make keys freeable - this is safe to do */ + for (i = 0; i < key_count; i++) keys[i] = strdup(keys[i]); + *num_ret = key_count; + return keys; +} + +Ecore_Config_Type +_ecore_config_db_key_type_get(Ecore_Config_DB_File *db, const char *key) +{ + char *data; + int size; + + data = eet_read(db->ef, (char*)key, &size); + if (data) + { + if (size <= 2) + { + free(data); + return ECORE_CONFIG_NIL; + } + if (data[size - 1] != 0) + { + free(data); + return ECORE_CONFIG_NIL; + } + return (Ecore_Config_Type) data[0]; + } + return ECORE_CONFIG_NIL; +} + +int +_ecore_config_db_read(Ecore_Config_DB_File *db, const char *key) +{ + char *data, *value; + int size; + Ecore_Config_Type type; + + data = eet_read(db->ef, (char*)key, &size); + if (data) + { + int l; + char *prev_locale; + + if (size <= 2) + { + free(data); + return 0; + } + if (data[size - 1] != 0) + { + free(data); + return 0; + } + /* "type" NIL 1242 NIL */ + l = strlen(data); + if (l >= (size - 1)) + { + free(data); + return 0; + } + + type = data[0]; + value = data + l + 1; + + switch (type) + { + case ECORE_CONFIG_INT: + case ECORE_CONFIG_BLN: + { + int tmp; + prev_locale = setlocale(LC_NUMERIC, "C"); + tmp = atoi(value); + if (prev_locale) setlocale(LC_NUMERIC, prev_locale); + + ecore_config_typed_set(key, (void *)&tmp, type); + break; + } + case ECORE_CONFIG_FLT: + { + float tmp; + prev_locale = setlocale(LC_NUMERIC, "C"); + tmp = atof(value); + if (prev_locale) setlocale(LC_NUMERIC, prev_locale); + + ecore_config_typed_set(key, (void *)&tmp, type); + break; + } + case ECORE_CONFIG_RGB: + ecore_config_argbstr_set(key, value); + break; + case ECORE_CONFIG_STR: + case ECORE_CONFIG_THM: + ecore_config_typed_set(key, (void *)value, type); + break; + case ECORE_CONFIG_SCT: + INF("loading struct %s", key); + break; + default: + WRN("Type %d not handled", type); + } + free(data); + return 1; + } + return 0; +} + +/* +void * +_ecore_config_db_key_data_get(Ecore_Config_DB_File *db, const char *key, int *size_ret) +{ + char *data; + int size; + + data = eet_read(db->ef, (char*)key, &size); + if (data) + { + int l; + char *dat; + + if (size <= 2) + { + free(data); + return NULL; + } + if (data[size - 1] != 0) + { + free(data); + return NULL; + } + * "type" NIL data_goes_here NIL * + l = strlen(data); + if (l >= (size - 1)) + { + free(data); + return NULL; + } + dat = malloc(size - (l + 2)); + memcpy(dat, data + l + 1, size - (l + 2)); + free(data); + *size_ret = size - (l + 2); + return dat; + } + return NULL; +}*/ + +void +_ecore_config_db_write(Ecore_Config_DB_File *db, Ecore_Config_Prop *e) +{ + char *prev_locale= NULL; + char *val = NULL; + char *r = NULL; + int num; + + prev_locale = setlocale(LC_NUMERIC, "C"); + + switch (e->type) + { + case ECORE_CONFIG_INT: + esprintf(&val, "%i", _ecore_config_int_get(e)); + break; + case ECORE_CONFIG_BLN: + esprintf(&val, "%i", _ecore_config_boolean_get(e)); + break; + case ECORE_CONFIG_FLT: + esprintf(&val, "%16.16f", _ecore_config_float_get(e)); + break; + case ECORE_CONFIG_STR: + val = _ecore_config_string_get(e); + break; + case ECORE_CONFIG_THM: + val = _ecore_config_theme_get(e); + break; + case ECORE_CONFIG_RGB: + val = _ecore_config_argbstr_get(e); + break; + default: + WRN("Type %d not handled", e->type); + } + + if (prev_locale) + { + setlocale(LC_NUMERIC, prev_locale); + } + + if(val) + { + num = esprintf(&r, "%c%c%s%c", (char) e->type, 0, val, 0); + if(num) + eet_write(db->ef, e->key, r, num, 1); + free(r); + } + + free(val); +} +/* +void +_ecore_config_db_key_data_set(Ecore_Config_DB_File *db, const char *key, void *data, int data_size) +{ + char *buf; + int num; + + num = 1 + 1 + data_size + 1; + buf = malloc(num); + if (!buf) return; + buf[0] = (char) ECORE_CONFIG_BIN; + buf[1] = 0; + memcpy(buf + 2, data, data_size); + buf[num - 1] = 0; + eet_write(db->ef, (char*)key, buf, num, 1); + free(buf); +}*/ diff --git a/src/lib/ecore_config/ecore_config_extra.c b/src/lib/ecore_config/ecore_config_extra.c new file mode 100644 index 0000000..a134952 --- /dev/null +++ b/src/lib/ecore_config/ecore_config_extra.c @@ -0,0 +1,803 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include +#include + +#include "Ecore_Config.h" +#include "Ecore.h" +#include "ecore_config_private.h" +typedef struct __Ecore_Config_Arg_Callback _Ecore_Config_Arg_Callback; +struct __Ecore_Config_Arg_Callback +{ + char short_opt; + char *long_opt; + char *description; + void *data; + void (*func)(char *val, void *data); + Ecore_Config_Type type; + _Ecore_Config_Arg_Callback *next; +}; + +char *__ecore_config_app_description; +_Ecore_Config_Arg_Callback *_ecore_config_arg_callbacks; + +/* shorthand prop setup code to make client apps a little smaller ;) */ + +/** + * Creates a new property, if it does not already exist, and sets its + * attributes to those given. + * + * The type of the property is guessed from the key and the value + * given. + * + * @param key The property key. + * @param val Pointer to default value of key. + * @param short_opt Short option used to set the property from command + * line. + * @param long_opt Long option used to set the property from command line. + * @param desc String description of property. + * @return @c ECORE_CONFIG_ERR_SUCC on success. + * @ingroup Ecore_Config_Create_Group + */ +int +ecore_config_create(const char *key, void *val, char short_opt, char *long_opt, + char *desc) +{ + int type = ecore_config_type_guess(key, val); + + return ecore_config_typed_create(key, val, type, short_opt, long_opt, desc); +} + +/** + * Creates a new property, if it does not already exist, and sets its + * attributes to those given. + * @param key The property key. + * @param val Pointer to default value of key. + * @param type Type of the property. + * @param short_opt Short option used to set the property from + * command line. + * @param long_opt Long option used to set the property from command line. + * @param desc String description of property. + * @return @c ECORE_CONFIG_ERR_SUCC on success. + * @ingroup Ecore_Config_Create_Group + */ +int +ecore_config_typed_create(const char *key, void *val, int type, char short_opt, + char *long_opt, char *desc) +{ + int ret; + + if ((ret = + ecore_config_typed_default(key, val, type)) != ECORE_CONFIG_ERR_SUCC) + return ret; + if ((ret = + ecore_config_short_opt_set(key, short_opt)) != ECORE_CONFIG_ERR_SUCC) + return ret; + if ((ret = + ecore_config_long_opt_set(key, long_opt)) != ECORE_CONFIG_ERR_SUCC) + return ret; + ret = ecore_config_describe(key, desc); + return ret; +} + +/** + * Creates a new boolean property, if it does not already exist, and sets its + * attributes to those given. + * @param key The property key. + * @param val Default boolean value of key. + * @param short_opt Short option used to set the property from command + * line. + * @param long_opt Long option used to set the property from command line. + * @param desc String description of property. + * @return @c ECORE_CONFIG_ERR_SUCC on success. + * @ingroup Ecore_Config_Create_Group + */ +int +ecore_config_boolean_create(const char *key, int val, char short_opt, + char *long_opt, char *desc) +{ + return + ecore_config_typed_create(key, (void *)&val, ECORE_CONFIG_BLN, short_opt, long_opt, + desc); +} + +/** + * Creates a new integer property, if it does not already exist, and sets its + * attributes to those given. + * @param key The property key. + * @param val Default integer value of key. + * @param short_opt Short option used to set the property from command + * line. + * @param long_opt Long option used to set the property from command line. + * @param desc String description of property. + * @return @c ECORE_CONFIG_ERR_SUCC on success. + * @ingroup Ecore_Config_Create_Group + */ +int +ecore_config_int_create(const char *key, int val, char short_opt, + char *long_opt, char *desc) +{ + return + ecore_config_typed_create(key, (void *)&val, ECORE_CONFIG_INT, short_opt, long_opt, + desc); +} + +/** + * Creates a new integer property, if it does not already exist, and sets its + * attributes to those given. + * @param key The property key. + * @param val Default integer value of key. + * @param low Lowest valid integer value for the property. + * @param high Highest valid integer value for the property. + * @param step Increment value for the property. + * @param short_opt Short option used to set the property from command + * line. + * @param long_opt Long option used to set the property from command line. + * @param desc String description of property. + * @return @c ECORE_CONFIG_ERR_SUCC on success. + * @ingroup Ecore_Config_Create_Group + */ +int +ecore_config_int_create_bound(const char *key, int val, int low, int high, + int step, char short_opt, char *long_opt, + char *desc) +{ + Ecore_Config_Prop *e; + int ret; + + ret = + ecore_config_typed_create(key, (void *)&val, ECORE_CONFIG_INT, short_opt, long_opt, + desc); + if (ret != ECORE_CONFIG_ERR_SUCC) + return ret; + e = ecore_config_get(key); + if (e) + { + e->step = step; + e->flags |= ECORE_CONFIG_FLAG_BOUNDS; + e->lo = low; + e->hi = high; + ecore_config_bound(e); + } + return ret; +} + +/** + * Creates a new string property, if it does not already exist, and sets its + * attributes to those given. + * @param key The property key. + * @param val Default value of key. + * @param short_opt Short option used to set the property from command + * line. + * @param long_opt Long option used to set the property from command line. + * @param desc String description of property. + * @return @c ECORE_CONFIG_ERR_SUCC on success. + * @ingroup Ecore_Config_Create_Group + */ +int +ecore_config_string_create(const char *key, char *val, char short_opt, + char *long_opt, char *desc) +{ + return + ecore_config_typed_create(key, (void *)val, ECORE_CONFIG_STR, short_opt, long_opt, + desc); +} + +/** + * Creates a new float property, if it does not already exist, and sets its + * attributes to those given. + * @param key The property key. + * @param val Default float value of key. + * @param short_opt Short option used to set the property from command + * line. + * @param long_opt Long option used to set the property from command line. + * @param desc String description of property. + * @return @c ECORE_CONFIG_ERR_SUCC on success. + * @ingroup Ecore_Config_Create_Group + */ +int +ecore_config_float_create(const char *key, float val, char short_opt, + char *long_opt, char *desc) +{ + return + ecore_config_typed_create(key, (void *)&val, ECORE_CONFIG_FLT, short_opt, long_opt, + desc); +} + +/** + * Creates a new float property, if it does not already exist, and sets its + * attributes to those given. + * @param key The property key. + * @param val Default float value of key. + * @param low Lowest valid float value for the property. + * @param high Highest valid float value for the property. + * @param step Increment value for the property. + * @param short_opt Short option used to set the property from command + * line. + * @param long_opt Long option used to set the property from command line. + * @param desc String description of property. + * @return @c ECORE_CONFIG_ERR_SUCC on success. + * @ingroup Ecore_Config_Create_Group + */ +int +ecore_config_float_create_bound(const char *key, float val, float low, + float high, float step, char short_opt, + char *long_opt, char *desc) +{ + Ecore_Config_Prop *e; + int ret; + + ret = + ecore_config_typed_create(key, (void *)&val, ECORE_CONFIG_FLT, short_opt, long_opt, + desc); + e = ecore_config_get(key); + if (e) + { + e->step = (int)(step * ECORE_CONFIG_FLOAT_PRECISION); + e->flags |= ECORE_CONFIG_FLAG_BOUNDS; + e->lo = (int)(low * ECORE_CONFIG_FLOAT_PRECISION); + e->hi = (int)(high * ECORE_CONFIG_FLOAT_PRECISION); + ecore_config_bound(e); + } + return ret; +} + +/** + * Creates a new color property, if it does not already exist, and sets its + * attributes to those given. + * @param key The property key. + * @param val Default color value of key, as a hexadecimal string. + * @param short_opt Short option used to set the property from command + * line. + * @param long_opt Long option used to set the property from command line. + * @param desc String description of property. + * @return @c ECORE_CONFIG_ERR_SUCC on success. + * @ingroup Ecore_Config_Create_Group + */ +int +ecore_config_argb_create(const char *key, char *val, char short_opt, + char *long_opt, char *desc) +{ + return + ecore_config_typed_create(key, (void *)val, ECORE_CONFIG_RGB, short_opt, long_opt, + desc); +} + +/** + * Creates a new theme property, if it does not already exist, and sets its + * attributes to those given. + * @param key The property key. + * @param val Default theme name for the property. + * @param short_opt Short option used to set the property from command + * line. + * @param long_opt Long option used to set the property from command line. + * @param desc String description of property. + * @return @c ECORE_CONFIG_ERR_SUCC on success. + * @ingroup Ecore_Config_Create_Group + */ +int +ecore_config_theme_create(const char *key, char *val, char short_opt, + char *long_opt, char *desc) +{ + return + ecore_config_typed_create(key, (void *)val, ECORE_CONFIG_THM, short_opt, long_opt, + desc); +} + +/* this should only be built if evas is present */ + +/** + * Calls evas_font_path_append on @p evas for each of the font names stored + * in the property "/e/font/path". + * @param evas Evas object to append the font names to. + * @return @c ECORE_CONFIG_ERR_SUCC on success. @c ECORE_CONFIG_ERR_NODATA + * is returned if the property has not been set. + */ +int +ecore_config_evas_font_path_apply(Evas * evas) +{ + char *font_path, *font_path_tmp, *ptr, *end; + + font_path = ecore_config_string_get("/e/font/path"); + + if (!font_path) + return ECORE_CONFIG_ERR_NODATA; + ptr = font_path; + end = font_path + strlen(font_path); + font_path_tmp = font_path; + while (ptr && ptr < end) + { + while (*ptr != '|' && ptr < end) + ptr++; + if (ptr < end) + *ptr = '\0'; + + evas_font_path_append(evas, font_path_tmp); + ptr++; + font_path_tmp = ptr; + } + + free(font_path); + + return ECORE_CONFIG_ERR_SUCC; +} + +/** + * Retrieves the default theme search path. + * + * @return The default theme search path. + */ +char * +ecore_config_theme_default_path_get(void) +{ + char *path, *home; + int len; + + home = getenv("HOME"); + len = strlen(PACKAGE_DATA_DIR "/../") + strlen(__ecore_config_app_name) + + strlen("/themes/") + 1; + if (home) + len += strlen(home) + strlen("/.e/apps/") + + strlen(__ecore_config_app_name) + + strlen("/themes/|"); /* no \0, as that is above */ + + if (!(path = malloc(len))) + return NULL; + + *path = '\0'; + if (home) + { + strcat(path, home); + strcat(path, "/.e/apps/"); + strcat(path, __ecore_config_app_name); + strcat(path, "/themes/|"); + } + strcat(path, PACKAGE_DATA_DIR "/../"); + strcat(path, __ecore_config_app_name); + strcat(path, "/themes/"); + + return path; +} + +/** + * Retrieves the search path used to find themes. + * + * The search path is stored in the property "/e/themes/search_path". If + * the property has not been set, the default path used is + * "/usr/local/share//themes|~/.e/apps//themes". + * See @ref ecore_config_theme_default_path_get for more information about + * the default path. + * + * @return The search path. @c NULL is returned if there is no memory left. + */ +char * +ecore_config_theme_search_path_get(void) +{ + char *search_path; + search_path = ecore_config_string_get("/e/themes/search_path"); + + /* this should no longer be the case, as it is defaulted in init */ + if (!search_path) + { + search_path = ecore_config_theme_default_path_get(); + if (search_path) + { + ecore_config_string_default("/e/themes/search_path", search_path); + free(search_path); + } + } + return search_path; +} + +/** + * Adds the given path to the search path used to find themes. + * + * If the search path is successfully, the new search path will be saved + * into the property "/e/themes/search_path". Therefore, this function + * should be called @b after @ref ecore_config_load to allow a user to + * override the default search path. + * + * @param path The given + * @return @c ECORE_CONFIG_ERR_SUCC on success. @c ECORE_CONFIG_ERR_FAIL + * will be returned if @p path already exists in the search path. + * @c ECORE_CONFIG_ERR_FAIL is returned if @p path is @c NULL. + */ +int +ecore_config_theme_search_path_append(const char *path) +{ + char *search_path, *loc, *new_search_path; + int len, search_len; + Ecore_Config_Prop *prop; + + if (!path) + return ECORE_CONFIG_ERR_NODATA; + search_path = ecore_config_theme_search_path_get(); + + loc = strstr(search_path, path); + len = strlen(path); + search_len = strlen(search_path); + + if (!loc || (loc != search_path && *(loc - 1) != '|') || + (loc != (search_path + search_len - len) && *(loc + len - 1) != '|')) + { + new_search_path = malloc(search_len + len + 2); /* 2 = \0 + | */ + strcpy(new_search_path, search_path); + strncat(new_search_path, "|", 1); + strncat(new_search_path, path, len); + + ecore_config_string_set("/e/themes/search_path", new_search_path); + prop = ecore_config_get("/e/themes/search_path"); + if (prop) + prop->flags &= ~ECORE_CONFIG_FLAG_MODIFIED; + + free(new_search_path); + + return ECORE_CONFIG_ERR_SUCC; + } + return ECORE_CONFIG_ERR_FAIL; +} + +/** + * Retrieve a theme file's full path. + * + * The search path for theme files is given by @ref + * ecore_config_theme_search_path_get . + * + * @param name The name of the theme. + * @return A full path to the theme on success. @c NULL will be returned + * if @p name is @c NULL or no theme matching the given name could + * be found. + */ +char * +ecore_config_theme_with_path_from_name_get(char *name) +{ + char *search_path, *search_path_tmp, *ptr, *end, *file; + struct stat st; + + if (!name) + return NULL; /* no theme specified (nor a default) */ + + search_path = ecore_config_theme_search_path_get(); + ptr = search_path; + end = search_path + strlen(search_path); + search_path_tmp = search_path; + while (ptr && ptr < end) + { + while (*ptr != '|' && ptr < end) + ptr++; + if (ptr < end) + *ptr = '\0'; + + file = malloc(strlen(search_path_tmp) + strlen(name) + 6); + /* 6 = / + .edj + \0 */ + + snprintf(file, strlen(search_path_tmp) + strlen(name) + 6, + "%s/%s.edj", search_path_tmp, name); + + if (stat(file, &st) == 0) + { + free(search_path); + return file; + } + free(file); + ptr++; + search_path_tmp = ptr; + } + + free(search_path); + + return NULL; /* we could not find the theme with that name in search path */ +} + +/** + * Retrieves the full path to the theme file of the theme stored in the + * given property. + * + * The search path for themes is given by @ref + * ecore_config_theme_search_path_get . + * + * @param key The given property. + * @return A full path to the theme on success, or @c NULL on failure. + * This function will fail if no key is specified or not theme + * matching that given by the property @p key could be found. + */ +char * +ecore_config_theme_with_path_get(const char *key) +{ + return + ecore_config_theme_with_path_from_name_get(ecore_config_theme_get(key)); +} + +static const char *_ecore_config_short_types[] = + { " ", " ", " ", " ", " ", " ", "" }; + +/** + * Prints the property list of the local configuration bundle to output. + */ +void +ecore_config_args_display(void) +{ + Ecore_Config_Prop *props; + _Ecore_Config_Arg_Callback *callbacks; + + if (__ecore_config_app_description) + ERR("%s\n\n", __ecore_config_app_description); + ERR("Supported Options:"); + ERR(" -h, --help\t Print this text"); + if (!__ecore_config_bundle_local) + return; + props = __ecore_config_bundle_local->data; + while (props) + { + /* if it is a system prop, or cannot be set on command line hide it */ + if (props->flags & ECORE_CONFIG_FLAG_SYSTEM || (!props->short_opt && !props->long_opt)) + { + props = props->next; + continue; + } + INF(" %c%c%c --%s\t%s %s", props->short_opt ? '-' : ' ', + props->short_opt ? props->short_opt : ' ', + props->short_opt ? ',' : ' ', + props->long_opt ? props->long_opt : props->key, + _ecore_config_short_types[props->type], + props->description ? props->description : + "(no description available)"); + + props = props->next; + } + callbacks = _ecore_config_arg_callbacks; + while (callbacks) + { + INF(" %c%c%c --%s\t%s %s", callbacks->short_opt ? '-' : ' ', + callbacks->short_opt ? callbacks->short_opt : ' ', + callbacks->short_opt ? ',' : ' ', + callbacks->long_opt ? callbacks->long_opt : "", + _ecore_config_short_types[callbacks->type], + callbacks->description ? callbacks->description : + "(no description available)"); + + callbacks = callbacks->next; + } +} + +static int +ecore_config_parse_set(Ecore_Config_Prop * prop, char *arg, char *opt, + char opt2) +{ + if (!arg) + { + if (opt) + ERR("Missing expected argument for option --%s", opt); + else + ERR("Missing expected argument for option -%c", opt2); + return ECORE_CONFIG_PARSE_EXIT; + } + else + { + ecore_config_set(prop->key, arg); + prop->flags |= ECORE_CONFIG_FLAG_CMDLN; + } + return ECORE_CONFIG_PARSE_CONTINUE; +} + +static void +ecore_config_args_callback_add(char short_opt, char *long_opt, char *desc, + void (*func)(char *val, void *data), + void *data, Ecore_Config_Type type) { + _Ecore_Config_Arg_Callback *new_cb; + + new_cb = malloc(sizeof(_Ecore_Config_Arg_Callback)); + new_cb->short_opt = short_opt; + if (long_opt) + new_cb->long_opt = strdup(long_opt); + if (desc) + new_cb->description = strdup(desc); + new_cb->data = data; + new_cb->func = func; + new_cb->type = type; + + new_cb->next = _ecore_config_arg_callbacks; + _ecore_config_arg_callbacks = new_cb; +} + +void +ecore_config_args_callback_str_add(char short_opt, char *long_opt, char *desc, + void (*func)(char *val, void *data), + void *data) { + ecore_config_args_callback_add(short_opt, long_opt, desc, func, data, ECORE_CONFIG_STR); +} + +void +ecore_config_args_callback_noarg_add(char short_opt, char *long_opt, char *desc, + void (*func)(char *val, void *data), + void *data) { + ecore_config_args_callback_add(short_opt, long_opt, desc, func, data, ECORE_CONFIG_NIL); +} + +/** + * Parse the arguments set by @ref ecore_app_args_set and set properties + * accordingly. + * + * @return @c ECORE_CONFIG_PARSE_CONTINUE if successful. + * @c ECORE_CONFIG_PARSE_EXIT is returned if an unrecognised option + * is found. @c ECORE_CONFIG_PARSE_HELP is returned if help was + * displayed. + */ +int +ecore_config_args_parse(void) +{ + int argc; + char **argv; + int nextarg, next_short_opt, found, ret; + char *arg; + char *long_opt, short_opt; + Ecore_Config_Prop *prop; + _Ecore_Config_Arg_Callback *callback; + + ecore_app_args_get(&argc, &argv); + nextarg = 1; + while (nextarg < argc) + { + arg = argv[nextarg]; + + if (*arg != '-') + { + ERR("Unexpected attribute \"%s\"", arg); + nextarg++; + continue; + } + + next_short_opt = 1; + short_opt = *(arg + next_short_opt); + + if (short_opt == '-') + { + long_opt = arg + 2; + + if (!strcmp(long_opt, "help")) + { + ecore_config_args_display(); + return ECORE_CONFIG_PARSE_HELP; + } + + found = 0; + prop = __ecore_config_bundle_local->data; + while (prop) + { + if ((prop->long_opt && !strcmp(long_opt, prop->long_opt)) + || !strcmp(long_opt, prop->key)) + { + found = 1; + if ((ret = + ecore_config_parse_set(prop, argv[++nextarg], + long_opt, + '\0')) != + ECORE_CONFIG_PARSE_CONTINUE) + return ret; + break; + } + prop = prop->next; + } + if (!found) + { + callback = _ecore_config_arg_callbacks; + while (callback) + { + if ((callback->long_opt && + !strcmp(long_opt, callback->long_opt))) + { + found = 1; + if (callback->type == ECORE_CONFIG_NIL) + { + callback->func(NULL, callback->data); + } + else + { + if (!argv[++nextarg]) + { + ERR("Missing expected argument for option --%s", long_opt); + return ECORE_CONFIG_PARSE_EXIT; + } + callback->func(argv[nextarg], callback->data); + } + break; + } + callback = callback->next; + } + } + if (!found) + { + ERR("Unrecognised option \"%s\"", long_opt); + ERR("Try using -h or --help for more information.\n"); + return ECORE_CONFIG_PARSE_EXIT; + } + } + else + { + while (short_opt) + { + if (short_opt == 'h') + { + ecore_config_args_display(); + return ECORE_CONFIG_PARSE_HELP; + } + else + { + found = 0; + prop = __ecore_config_bundle_local->data; + while (prop) + { + if (short_opt == prop->short_opt) + { + found = 1; + if ((ret = + ecore_config_parse_set(prop, + argv[++nextarg], + NULL, + short_opt)) != + ECORE_CONFIG_PARSE_CONTINUE) + return ret; + break; + } + prop = prop->next; + } + + if (!found) + { + callback = _ecore_config_arg_callbacks; + while (callback) + { + if (short_opt == callback->short_opt) + { + found = 1; + if (callback->type == ECORE_CONFIG_NIL) + { + callback->func(NULL, callback->data); + } + else + { + if (!argv[++nextarg]) + { + ERR("Missing expected argument for option -%c", short_opt); + return ECORE_CONFIG_PARSE_EXIT; + } + callback->func(argv[nextarg], callback->data); + } + break; + } + callback = callback->next; + } + } + if (!found) + { + ERR("Unrecognised option '%c'", short_opt); + ERR("Try using -h or --help for more information.\n"); + return ECORE_CONFIG_PARSE_EXIT; + } + } + short_opt = *(arg + ++next_short_opt); + } + } + nextarg++; + } + + return ECORE_CONFIG_PARSE_CONTINUE; +} + +/** + * Sets the description string used by @ref ecore_config_args_display . + * @param description Description of application. + */ +void +ecore_config_app_describe(char *description) +{ + if (__ecore_config_app_description) + free(__ecore_config_app_description); + __ecore_config_app_description = strdup(description); +} diff --git a/src/lib/ecore_config/ecore_config_ipc.h b/src/lib/ecore_config/ecore_config_ipc.h new file mode 100644 index 0000000..7b3dea1 --- /dev/null +++ b/src/lib/ecore_config/ecore_config_ipc.h @@ -0,0 +1,50 @@ +#include +#include "Ecore_Config.h" + +typedef enum +{ + IPC_NONE, + IPC_PROP_LIST, + IPC_PROP_DESC, + IPC_PROP_GET, + IPC_PROP_SET, /* end of the codes shared by evidence and econf */ + + IPC_GLOBAL_PROP_LIST, + + IPC_BUNDLE_LIST, + IPC_BUNDLE_NEW, + IPC_BUNDLE_LABEL_GET, + IPC_BUNDLE_LABEL_SET, + IPC_BUNDLE_LABEL_FIND, + + IPC_LAST +} Ecore_Config_Ipc_Call; + +Ecore_Config_Server *_ecore_config_ipc_init(const char *pipe_name); +int _ecore_config_ipc_exit(void); + +Ecore_Config_Server *_ecore_config_server_convert(void *srv); + +char *_ecore_config_ipc_prop_list(Ecore_Config_Server * srv, + const long serial); +char *_ecore_config_ipc_prop_desc(Ecore_Config_Server * srv, + const long serial, + const char *key); +char *_ecore_config_ipc_prop_get(Ecore_Config_Server * srv, + const long serial, + const char *key); +int _ecore_config_ipc_prop_set(Ecore_Config_Server * srv, + const long serial, + const char *key, + const char *val); + +char *_ecore_config_ipc_bundle_list(Ecore_Config_Server * srv); +int _ecore_config_ipc_bundle_new(Ecore_Config_Server * srv, + const char *); +char *_ecore_config_ipc_bundle_label_get(Ecore_Config_Server * + srv, const long); +int _ecore_config_ipc_bundle_label_set(Ecore_Config_Server * + srv, const long, + const char *); +long _ecore_config_ipc_bundle_label_find(Ecore_Config_Server * + srv, const char *); diff --git a/src/lib/ecore_config/ecore_config_ipc_ecore.c b/src/lib/ecore_config/ecore_config_ipc_ecore.c new file mode 100644 index 0000000..b1622f3 --- /dev/null +++ b/src/lib/ecore_config/ecore_config_ipc_ecore.c @@ -0,0 +1,384 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +/* by Azundris, with thanks to Corey Donohoe */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "ecore_private.h" +#include + +#include "ecore_config_ipc.h" +#include "ecore_config_util.h" +#include "ecore_config_private.h" + +#include "Ecore_Config.h" + + +/*****************************************************************************/ + +static int +_ecore_config_ipc_ecore_string_get(char **m, char **r) +{ + char *q; + int l = 0; + + if (!m || !*m) + return ECORE_CONFIG_ERR_NODATA; + if (!r) + return ECORE_CONFIG_ERR_FAIL; + q = *m; + if (*q != 's') + return ECORE_CONFIG_ERR_TYPEMISMATCH; + q++; + l = (*(q++)) << 8; + l += *(q++); + *r = q; + q += l; + *m = q; + WRN("IPC/eCore: got string-%d \"%s\"", l, *r); + return ECORE_CONFIG_ERR_SUCC; +} + +static char * +_ecore_config_ipc_global_prop_list(Ecore_Config_Server * srv __UNUSED__, long serial __UNUSED__) +{ + Ecore_Config_DB_File *db; + char **keys; + int key_count, x; + estring *s; + int f; + char buf[PATH_MAX], *p; + // char *data; UNUSED + Ecore_Config_Type type; + + db = NULL; + s = estring_new(8192); + f = 0; + if ((p = getenv("HOME"))) + { + snprintf(buf, sizeof(buf), "%s/.e/config.eet", p); + if (!(db = _ecore_config_db_open_read(buf))) + { + strcpy(buf, PACKAGE_DATA_DIR"/system.eet"); + if (!(db = _ecore_config_db_open_read(buf))) + return NULL; + } + } + if (!db) return NULL; + key_count = 0; + keys = _ecore_config_db_keys_get(db, &key_count); + if (keys) + { + for (x = 0; x < key_count; x++) + { + type = _ecore_config_db_key_type_get(db, keys[x]); + switch (type) + { + case ECORE_CONFIG_INT: + estring_appendf(s, "%s%s: integer", f ? "\n" : "", keys[x]); + break; + case ECORE_CONFIG_BLN: + estring_appendf(s, "%s%s: boolean", f ? "\n" : "", keys[x]); + break; + case ECORE_CONFIG_FLT: + estring_appendf(s, "%s%s: float", f ? "\n" : "", keys[x]); + break; + case ECORE_CONFIG_STR: + estring_appendf(s, "%s%s: string", f ? "\n" : "", keys[x]); + break; + case ECORE_CONFIG_RGB: + estring_appendf(s, "%s%s: colour", f ? "\n" : "", keys[x]); + break; + case ECORE_CONFIG_THM: + estring_appendf(s, "%s%s: theme", f ? "\n" : "", keys[x]); + break; + case ECORE_CONFIG_SCT: + estring_appendf(s, "%s%s: structure", f ? "\n" : "", keys[x]); + break; + default: + estring_appendf(s, "%s%s: unknown", f ? "\n" : "", keys[x]); + continue; + } + f = 1; + } + } + _ecore_config_db_close(db); + if (keys) + { + for (x = 0; x < key_count; x++) + { + free(keys[x]); + } + free(keys); + } + + return estring_disown(s); +} + +/*****************************************************************************/ + +static int +_ecore_config_ipc_ecore_send(Ecore_Ipc_Event_Client_Data * e, int code, + char *reply) +{ + static int our_ref = 0; + int len = reply ? strlen(reply) + 1 : 0; + + our_ref++; + WRN("IPC/eCore: replying [0,0] %d IRT %d => %d {\"%s\":%d}", our_ref, + e->ref, code, reply ? reply : "", len); + return ecore_ipc_client_send(e->client, 0, 0, our_ref, e->ref, code, reply, + len); +} + +/*****************************************************************************/ + +static int +_ecore_config_ipc_ecore_handle_request(Ecore_Ipc_Server * server, + Ecore_Ipc_Event_Client_Data * e) +{ + Ecore_Config_Server *srv; + long serial; + int ret; + char *r, *k, *v, *m; + + srv = _ecore_config_server_convert(server); + serial = e->minor; + r = NULL; + m = (char *)e->data; + INF("IPC/eCore: client sent: [%d,%d] #%d (%d) @ %p", e->major, e->minor, + e->ref, e->size, server); + + switch (e->major) + { + case IPC_PROP_LIST: + if (srv == __ecore_config_server_global) + r = _ecore_config_ipc_global_prop_list(srv, serial); + else + r = _ecore_config_ipc_prop_list(srv, serial); + break; + case IPC_PROP_DESC: + if (_ecore_config_ipc_ecore_string_get(&m, &k) == ECORE_CONFIG_ERR_SUCC) + r = _ecore_config_ipc_prop_desc(srv, serial, k); + break; + case IPC_PROP_GET: + if (_ecore_config_ipc_ecore_string_get(&m, &k) == ECORE_CONFIG_ERR_SUCC) + r = _ecore_config_ipc_prop_get(srv, serial, k); + break; + case IPC_PROP_SET: + if (_ecore_config_ipc_ecore_string_get(&m, &k) == ECORE_CONFIG_ERR_SUCC) + { + if (_ecore_config_ipc_ecore_string_get(&m, &v) == + ECORE_CONFIG_ERR_SUCC) + return _ecore_config_ipc_ecore_send(e, + _ecore_config_ipc_prop_set + (srv, serial, k, v), NULL); + } + break; + + case IPC_BUNDLE_LIST: + r = _ecore_config_ipc_bundle_list(srv); + break; + case IPC_BUNDLE_NEW: + if (_ecore_config_ipc_ecore_string_get(&m, &k) == ECORE_CONFIG_ERR_SUCC) + return _ecore_config_ipc_ecore_send(e, + k ? + _ecore_config_ipc_bundle_new(srv, + k) : + ECORE_CONFIG_ERR_FAIL, NULL); + break; + case IPC_BUNDLE_LABEL_SET: + if (_ecore_config_ipc_ecore_string_get(&m, &k) == ECORE_CONFIG_ERR_SUCC) + return _ecore_config_ipc_ecore_send(e, + k ? + _ecore_config_ipc_bundle_label_set + (srv, serial, + k) : ECORE_CONFIG_ERR_FAIL, + NULL); + break; + case IPC_BUNDLE_LABEL_FIND: + if (_ecore_config_ipc_ecore_string_get(&m, &k) == ECORE_CONFIG_ERR_SUCC) + return _ecore_config_ipc_ecore_send(e, + _ecore_config_ipc_bundle_label_find + (srv, k), NULL); + break; + case IPC_BUNDLE_LABEL_GET: + r = _ecore_config_ipc_bundle_label_get(srv, serial); + break; + } + + ret = + _ecore_config_ipc_ecore_send(e, + r ? ECORE_CONFIG_ERR_SUCC : + ECORE_CONFIG_ERR_FAIL, r); + if (r) + { + free(r); + return ret; + } + return ECORE_CONFIG_ERR_NOTFOUND; +} + +/*****************************************************************************/ + +static Eina_Bool +_ecore_config_ipc_client_add(void *data, int type __UNUSED__, void *event) +{ + Ecore_Ipc_Server **server; + Ecore_Ipc_Event_Client_Data *e; + + server = (Ecore_Ipc_Server **) data; + e = (Ecore_Ipc_Event_Client_Data *) event; + + if (*server != ecore_ipc_client_server_get(e->client)) + return EINA_TRUE; + + INF("IPC/eCore: Client connected. @ %p", server); + return EINA_TRUE; +} + +static Eina_Bool +_ecore_config_ipc_client_del(void *data, int type __UNUSED__, void *event) +{ + Ecore_Ipc_Server **server; + Ecore_Ipc_Event_Client_Data *e; + + server = (Ecore_Ipc_Server **) data; + e = (Ecore_Ipc_Event_Client_Data *) event; + + if (*server != ecore_ipc_client_server_get(e->client)) + return EINA_TRUE; + + INF("IPC/eCore: Client disconnected. @ %p", server); + return EINA_TRUE; +} + +static Eina_Bool +_ecore_config_ipc_client_sent(void *data, int type __UNUSED__, void *event) +{ + Ecore_Ipc_Server **server; + Ecore_Ipc_Event_Client_Data *e; + + server = (Ecore_Ipc_Server **) data; + e = (Ecore_Ipc_Event_Client_Data *) event; + + if (*server != ecore_ipc_client_server_get(e->client)) + return EINA_TRUE; + + _ecore_config_ipc_ecore_handle_request(*server, e); + return EINA_TRUE; +} + +/*****************************************************************************/ + +int +_ecore_config_ipc_ecore_init(const char *pipe_name, void **data) +{ + Ecore_Ipc_Server **server; + struct stat st; + char *p; + int port; + char socket[PATH_MAX]; + + server = (Ecore_Ipc_Server **) data; + port = 0; + if (!server) + return ECORE_CONFIG_ERR_FAIL; + +/* if(*server) + return ECORE_CONFIG_ERR_IGNORED; */ + + ecore_init(); + if (ecore_ipc_init() < 1) + return ECORE_CONFIG_ERR_FAIL; + + if ((p = getenv("HOME"))) + { /* debug-only ### FIXME */ + int stale; + + stale = 1; + while (stale) + { + snprintf(socket, PATH_MAX, "%s/.ecore/%s/%d", p, pipe_name, port); + + if (!stat(socket, &st)) + { + INF("IPC/eCore: pipe \"%s\" already exists!?", socket); +/* if(unlink(buf)) + E(0,"IPC/eCore: could not remove pipe \"%s\": %d\n",buf,errno); }}*/ + port++; + } + else + { + stale = 0; + } + } + } + *server = ecore_ipc_server_add(ECORE_IPC_LOCAL_USER, pipe_name, port, NULL); + ecore_event_handler_add(ECORE_IPC_EVENT_CLIENT_ADD, + _ecore_config_ipc_client_add, server); + ecore_event_handler_add(ECORE_IPC_EVENT_CLIENT_DEL, + _ecore_config_ipc_client_del, server); + ecore_event_handler_add(ECORE_IPC_EVENT_CLIENT_DATA, + _ecore_config_ipc_client_sent, server); + + if (*server) + { + INF("IPC/eCore: Server is listening on %s.", pipe_name); + } + + return ECORE_CONFIG_ERR_SUCC; +} + +int +_ecore_config_ipc_ecore_exit(void **data) +{ + int ret; + Ecore_Ipc_Server **server; + + ret = ECORE_CONFIG_ERR_SUCC; + server = (Ecore_Ipc_Server **) data; + + if (!server) + return ECORE_CONFIG_ERR_FAIL; + + if (*server) + { + ecore_ipc_server_del(*server); + *server = NULL; + } + + ecore_ipc_shutdown(); + ecore_shutdown(); + + return ret; +} + +/*****************************************************************************/ + +int +_ecore_config_ipc_ecore_poll(void **data) +{ + Ecore_Ipc_Server **server; + + server = (Ecore_Ipc_Server **) data; + + if (!server) + return ECORE_CONFIG_ERR_FAIL; + + ecore_main_loop_iterate(); + + return ECORE_CONFIG_ERR_SUCC; +} + +/*****************************************************************************/ diff --git a/src/lib/ecore_config/ecore_config_ipc_main.c b/src/lib/ecore_config/ecore_config_ipc_main.c new file mode 100644 index 0000000..35bd783 --- /dev/null +++ b/src/lib/ecore_config/ecore_config_ipc_main.c @@ -0,0 +1,275 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +/* ############## bad */ +#define HAVE_EVAS2 + +#include +#include +#include +#include +#include +#include +#include +#include /* malloc(), free() */ + +#include "Ecore.h" +#include "Ecore_Config.h" +#include "ecore_config_util.h" +#include "ecore_config_ipc.h" + +#include "ecore_config_private.h" + +static Ecore_Config_Server *__ecore_config_servers; +Ecore_Timer *ipc_timer = NULL; + +Ecore_Config_Server * +_ecore_config_server_convert(void *srv) +{ + Ecore_Config_Server *srv_tmp; + + srv_tmp = __ecore_config_servers; + while (srv_tmp) + { + if (srv_tmp->server == srv) + return srv_tmp; + srv_tmp = srv_tmp->next; + } + + return __ecore_config_server_global; +} + +/*****************************************************************************/ +/* INTERFACE FOR IPC MODULES */ +/*****************************/ + +char * +_ecore_config_ipc_prop_list(Ecore_Config_Server * srv, const long serial) +{ + Ecore_Config_Bundle *theme; + Ecore_Config_Prop *e; + estring *s; + int f; + + theme = ecore_config_bundle_by_serial_get(srv, serial); + e = theme ? theme->data : NULL; + s = estring_new(8192); + f = 0; + while (e) + { + /* ignore system properties in listings, unless they have been overridden */ + if (e->flags & ECORE_CONFIG_FLAG_SYSTEM && !(e->flags & ECORE_CONFIG_FLAG_MODIFIED)) + { + e = e->next; + continue; + } + estring_appendf(s, "%s%s: %s", f ? "\n" : "", e->key, + ecore_config_type_get(e)); + if (e->flags & ECORE_CONFIG_FLAG_BOUNDS) + { + if (e->type == ECORE_CONFIG_FLT) + estring_appendf(s, ", range %le..%le", + (float)e->lo / ECORE_CONFIG_FLOAT_PRECISION, + (float)e->hi / ECORE_CONFIG_FLOAT_PRECISION); + else + estring_appendf(s, ", range %d..%d", e->lo, e->hi); + } + if (e->type == ECORE_CONFIG_THM) + estring_appendf(s, ", group %s", e->data ? e->data : "Main"); + f = 1; + e = e->next; + } + + return estring_disown(s); +} + +char * +_ecore_config_ipc_prop_desc(Ecore_Config_Server * srv, const long serial, + const char *key) +{ +#ifdef HAVE_EVAS2 + Ecore_Config_Prop *e; + + e = ecore_config_get(key); + if (e) + { + estring *s = estring_new(512); + + estring_appendf(s, "%s: %s", e->key, ecore_config_type_get(e)); + if (e->flags & ECORE_CONFIG_FLAG_BOUNDS) + estring_appendf(s, ", range %d..%d", e->lo, e->hi); + return estring_disown(s); + } +#endif + return strdup(""); +} + +char * +_ecore_config_ipc_prop_get(Ecore_Config_Server * srv, const long serial, + const char *key) +{ +#ifdef HAVE_EVAS2 + char *ret; + + if ((ret = ecore_config_as_string_get(key))) + return ret; +#endif + return strdup(""); +} + +int +_ecore_config_ipc_prop_set(Ecore_Config_Server * srv, const long serial, + const char *key, const char *val) +{ +#ifdef HAVE_EVAS2 + int ret; + Ecore_Config_Bundle *theme; + + theme = ecore_config_bundle_by_serial_get(srv, serial); + ret = ecore_config_set(key, (char *)val); + ERR("ipc.prop.set(%s->%s,\"%s\") => %d\n", theme ? theme->identifier : "", + key, val, ret); + return ret; +#else + return ECORE_CONFIG_ERR_NOTSUPP; +#endif +} + +/*****************************************************************************/ + +char * +_ecore_config_ipc_bundle_list(Ecore_Config_Server * srv) +{ + Ecore_Config_Bundle *ns; + estring *s; + int f; + + ns = ecore_config_bundle_1st_get(srv); + s = estring_new(8192); + f = 0; + if (!ns) + return strdup(""); + + while (ns) + { + estring_appendf(s, "%s%d: %s", f ? "\n" : "", + ecore_config_bundle_serial_get(ns), + ecore_config_bundle_label_get(ns)); + f = 1; + ns = ecore_config_bundle_next_get(ns); + } + + return estring_disown(s); +} + +int +_ecore_config_ipc_bundle_new(Ecore_Config_Server * srv, const char *label) +{ + if (ecore_config_bundle_new(srv, label)) + return ECORE_CONFIG_ERR_SUCC; + return ECORE_CONFIG_ERR_FAIL; +} + +char * +_ecore_config_ipc_bundle_label_get(Ecore_Config_Server * srv, const long serial) +{ + Ecore_Config_Bundle *ns; + char *label; + + ns = ecore_config_bundle_by_serial_get(srv, serial); + label = ecore_config_bundle_label_get(ns); + return strdup(label ? label : ""); +} + +int +_ecore_config_ipc_bundle_label_set(Ecore_Config_Server * srv, const long serial, + const char *label) +{ + Ecore_Config_Bundle *ns; + + ns = ecore_config_bundle_by_serial_get(srv, serial); + if (!(ns->identifier = malloc(sizeof(label)))) + return ECORE_CONFIG_ERR_OOM; + memcpy(ns->identifier, label, sizeof(label)); + return ECORE_CONFIG_ERR_SUCC; +} + +long +_ecore_config_ipc_bundle_label_find(Ecore_Config_Server * srv, + const char *label) +{ + Ecore_Config_Bundle *ns; + + ns = ecore_config_bundle_by_label_get(srv, label); + return ns ? ecore_config_bundle_serial_get(ns) : -1; +} + +static Eina_Bool +_ecore_config_ipc_poll(void *data __UNUSED__) +{ + Ecore_Config_Server *s; + + s = __ecore_config_servers; + while (s) + { + _ecore_config_ipc_ecore_poll(&s->server); + s = s->next; + } + + return EINA_TRUE; +} + +int +_ecore_config_ipc_exit(void) +{ + Ecore_Config_Server *l; + + if (ipc_timer) + ecore_timer_del(ipc_timer); + + l = __ecore_config_servers; + while (l) + { + _ecore_config_ipc_ecore_exit(&l->server); + if (l->name) + free(l->name); + l = l->next; + } + + return ECORE_CONFIG_ERR_SUCC; +} + +Ecore_Config_Server * +_ecore_config_ipc_init(const char *pipe_name) +{ + int ret; + Ecore_Config_Server *list; + Ecore_Config_Server *ret_srv; + + list = NULL; + ret_srv = NULL; + list = NULL; + + list = calloc(1, sizeof(Ecore_Config_Server)); + if ((ret = _ecore_config_ipc_ecore_init(pipe_name, &list->server)) != ECORE_CONFIG_ERR_SUCC) + { + ERR("_ecore_config_ipc_init: failed to register %s, code %d", + pipe_name, ret); + } + + ERR("_ecore_config_ipc_init: registered \"%s\"...", pipe_name); + + list->name = strdup(pipe_name); + list->next = __ecore_config_servers; + + __ecore_config_servers = list; + if (!ret_srv) + ret_srv = list; + + if (!ipc_timer) + ipc_timer = ecore_timer_add(100, _ecore_config_ipc_poll, NULL); + + return ret_srv; +} +/*****************************************************************************/ diff --git a/src/lib/ecore_config/ecore_config_private.h b/src/lib/ecore_config/ecore_config_private.h new file mode 100644 index 0000000..b97f695 --- /dev/null +++ b/src/lib/ecore_config/ecore_config_private.h @@ -0,0 +1,70 @@ +#ifndef _ECORE_CONFIG_PRIVATE_H +# define _ECORE_CONFIG_PRIVATE_H +#ifdef ECORE_CONFIG_DEFAULT_LOG_COLOR +# undef ECORE_CONFIG_DEFAULT_LOG_COLOR +#endif +#define ECORE_CONFIG_DEFAULT_LOG_COLOR EINA_COLOR_BLUE + /* eina_log related things */ + +extern int _ecore_config_log_dom; +#ifdef ERR +# undef ERR +#endif +#define ERR(...) EINA_LOG_DOM_ERR(_ecore_config_log_dom, __VA_ARGS__) + +#ifdef DBG +# undef DBG +#endif +#define DBG(...) EINA_LOG_DOM_DBG(_ecore_config_log_dom, __VA_ARGS__) + +#ifdef INF +# undef INF +#endif +#define INF(...) EINA_LOG_DOM_INFO(_ecore_config_log_dom, __VA_ARGS__) + +#ifdef WRN +# undef WRN +#endif +#define WRN(...) EINA_LOG_DOM_WARN(_ecore_config_log_dom, __VA_ARGS__) + +#ifdef CRIT +# undef CRIT +#endif +#define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_config_log_dom, __VA_ARGS__) + +/* debug */ +extern int DEBUG; + + +typedef struct _Ecore_Config_DB_File Ecore_Config_DB_File; + +int _ecore_config_mod_init(const char *pipe_name, void **data); +int _ecore_config_mod_exit(void **data); +int _ecore_config_mod_poll(void **data); + +Ecore_Config_DB_File *_ecore_config_db_open_read(const char *file); +Ecore_Config_DB_File *_ecore_config_db_open_write(const char *file); +void _ecore_config_db_close(Ecore_Config_DB_File *db); +char **_ecore_config_db_keys_get(Ecore_Config_DB_File *db, int *num_ret); +Ecore_Config_Type _ecore_config_db_key_type_get(Ecore_Config_DB_File *db, const char *key); +int _ecore_config_db_read(Ecore_Config_DB_File *db, const char *key); +void _ecore_config_db_write(Ecore_Config_DB_File *db, Ecore_Config_Prop *e); + +int _ecore_config_boolean_get(Ecore_Config_Prop *e); +char *_ecore_config_string_get(Ecore_Config_Prop *e); +long _ecore_config_int_get(Ecore_Config_Prop *e); +int _ecore_config_argb_get(Ecore_Config_Prop *e, int *a, int *r, + int *g, int *b); +char *_ecore_config_argbstr_get(Ecore_Config_Prop *e); +long _ecore_config_argbint_get(Ecore_Config_Prop *e); +float _ecore_config_float_get(Ecore_Config_Prop *e); +char *_ecore_config_theme_get(Ecore_Config_Prop *e); + +int _ecore_config_ipc_ecore_init(const char *pipe_name, void **data); +int _ecore_config_ipc_ecore_exit(void **data); +int _ecore_config_ipc_ecore_poll(void **data); + +#include "Ecore.h" +#include "ecore_private.h" + +#endif diff --git a/src/lib/ecore_config/ecore_config_storage.c b/src/lib/ecore_config/ecore_config_storage.c new file mode 100644 index 0000000..d059645 --- /dev/null +++ b/src/lib/ecore_config/ecore_config_storage.c @@ -0,0 +1,176 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "Ecore_Config.h" +#include "ecore_config_private.h" + +/** + * Loads the default configuration. + * @return @c ECORE_CONFIG_ERR_SUCC on success. @c ECORE_CONFIG_ERR_NODATA + * is returned if the file cannot be loaded. + * @ingroup Ecore_Config_File_Group + */ +EAPI int +ecore_config_load(void) +{ + char file[PATH_MAX]; + + if (!__ecore_config_app_name) + return ECORE_CONFIG_ERR_FAIL; + + snprintf(file, PATH_MAX, "%s/.e/apps/%s/config.eet", getenv("HOME"), + __ecore_config_app_name); + return ecore_config_file_load(file); +} + +/** + * Saves the current configuration to the default file. + * @return @c ECORE_CONFIG_ERR_SUCC is returned on success. + * @c ECORE_CONFIG_ERR_FAIL is returned if the data cannot be + * saved. + * @ingroup Ecore_Config_File_Group + */ +EAPI int +ecore_config_save(void) +{ + char file[PATH_MAX]; + + if (!__ecore_config_app_name) + return ECORE_CONFIG_ERR_FAIL; + + snprintf(file, PATH_MAX, "%s/.e/apps/%s/config.eet", getenv("HOME"), + __ecore_config_app_name); + return ecore_config_file_save(file); +} + +/** + * Load the given configuration file to the local configuration. + * @param file Name of the file to load. + * @return @c ECORE_CONFIG_ERR_SUCC on success. @c ECORE_CONFIG_ERR_NODATA + * is returned if the file cannot be loaded. + * @ingroup Ecore_Config_File_Group + */ +EAPI int +ecore_config_file_load(const char *file) +{ + Ecore_Config_DB_File *db; + char **keys; + int key_count; + int x; + // double ftmp; UNUSED + // int pt; UNUSED + // int itmp; UNUSED + // Ecore_Config_Type type; UNUSED + char *data; + + db = NULL; + data = NULL; + + db = _ecore_config_db_open_read(file); + if (!db) + { + ERR("Cannot open database from file %s!", file); + return ECORE_CONFIG_ERR_NODATA; + } + key_count = 0; + keys = _ecore_config_db_keys_get(db, &key_count); + if (keys) + { + for (x = 0; x < key_count; x++) + { + _ecore_config_db_read(db, keys[x]); + } + } + _ecore_config_db_close(db); + if (keys) + { + for (x = 0; x < key_count; x++) + { + free(keys[x]); + } + free(keys); + } + return ECORE_CONFIG_ERR_SUCC; +} + +static void +_ecore_config_recurse_mkdir(const char *file) +{ + char *file_ptr; + char *file_tmp; + struct stat status; + + file_tmp = strdup(file); + file_ptr = file_tmp + strlen(file_tmp); + while (*file_ptr != '/' && file_ptr > file_tmp) + file_ptr--; + *file_ptr = '\0'; + + if ((file_tmp[0] != 0) && stat(file_tmp, &status)) + { + _ecore_config_recurse_mkdir(file_tmp); + mkdir(file_tmp, S_IRUSR | S_IWUSR | S_IXUSR); + } + free(file_tmp); +} + +/** + * Saves the local configuration to the given file. + * @param file Name of the file to save to. + * @return @c ECORE_CONFIG_ERR_SUCC is returned on success. + * @c ECORE_CONFIG_ERR_FAIL is returned if the data cannot be + * saved. + * @ingroup Ecore_Config_File_Group + */ +EAPI int +ecore_config_file_save(const char *file) +{ + Ecore_Config_Prop *next; + Ecore_Config_DB_File *db; + struct stat status; + + next = __ecore_config_bundle_local->data; + db = NULL; + + /* if file does not exist check to see if the dirs exist, creating if not */ + if (stat(file, &status)) + _ecore_config_recurse_mkdir(file); + + db = _ecore_config_db_open_write(file); + if (!db) + { + ERR("Cannot open database from file %s!", file); + return ECORE_CONFIG_ERR_FAIL; + } + + while (next) + { + /* let the config_db deal with this + * handyande: hmm, not sure that it ever does - reinstating until + * further discussions satisfy me! + */ + if (!(next->flags & ECORE_CONFIG_FLAG_MODIFIED) || next->flags & ECORE_CONFIG_FLAG_CMDLN) + { + next = next->next; + continue; + } + + _ecore_config_db_write(db, next); + + next = next->next; + } + + _ecore_config_db_close(db); + return ECORE_CONFIG_ERR_SUCC; +} diff --git a/src/lib/ecore_config/ecore_config_util.c b/src/lib/ecore_config/ecore_config_util.c new file mode 100644 index 0000000..6156936 --- /dev/null +++ b/src/lib/ecore_config/ecore_config_util.c @@ -0,0 +1,129 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +/* azundris */ + +#include +#include /* malloc(), free() */ +#include +#include /* str...() */ + +#include /* varargs in sprintf/appendf */ + +#include "Ecore.h" +#include "ecore_private.h" + +#include "Ecore_Config.h" +#include "ecore_config_util.h" + +#include "ecore_config_private.h" + +#define CHUNKLEN 4096 + +/*****************************************************************************/ +/* STRINGS */ +/***********/ + +estring * +estring_new(int size) +{ + estring *e = malloc(sizeof(estring)); + + if (e) + { + memset(e, 0, sizeof(estring)); + if ((size > 0) && (e->str = malloc(size))) + e->alloc = size; + } + return e; +} + +char * +estring_disown(estring * e) +{ + if (e) + { + char *r = e->str; + + free(e); + return r; + } + return NULL; +} + +int +estring_appendf(estring * e, const char *fmt, ...) +{ + int need; + va_list ap; + char *p; + + if (!e) + return ECORE_CONFIG_ERR_FAIL; + + if (!e->str) + { + e->used = e->alloc = 0; + if (!(e->str = (char *)malloc(e->alloc = CHUNKLEN))) + return ECORE_CONFIG_ERR_OOM; + } + + va_start(ap, fmt); + need = vsnprintf(NULL, 0, fmt, ap); + va_end(ap); + + if (need >= (e->alloc - e->used)) + { + e->alloc = e->used + need + (CHUNKLEN - (need % CHUNKLEN)); + + if (!(p = (char *)realloc(e->str, e->alloc))) + { + free(e->str); + e->alloc = e->used = 0; + return ECORE_CONFIG_ERR_OOM; + } + e->str = p; + } + + va_start(ap, fmt); + need = vsnprintf(e->str + e->used, e->alloc - e->used, fmt, ap); + va_end(ap); + + return e->used += need; +} + +int +esprintf(char **result, const char *fmt, ...) +{ + va_list ap; + size_t need; + char *n; + + if (!result) + return ECORE_CONFIG_ERR_FAIL; + + va_start(ap, fmt); + need = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + n = malloc(need + 1); + + if (n) + { + va_start(ap, fmt); + need = vsnprintf(n, need, fmt, ap); + va_end(ap); + + n[need] = 0; + + if(*result) + free(result); + *result = n; + + return need; + } + + return ECORE_CONFIG_ERR_OOM; +} + +/*****************************************************************************/ diff --git a/src/lib/ecore_config/ecore_config_util.h b/src/lib/ecore_config/ecore_config_util.h new file mode 100644 index 0000000..5bee9d6 --- /dev/null +++ b/src/lib/ecore_config/ecore_config_util.h @@ -0,0 +1,14 @@ +#define TIMER_STOP 0 +#define TIMER_CONT 1 + +typedef struct _estring +{ + char *str; + int alloc, used; +} estring; + +estring *estring_new(int size); +char *estring_disown(estring * e); +int estring_appendf(estring * e, const char *fmt, ...); + +int esprintf(char **result, const char *fmt, ...); diff --git a/src/lib/ecore_directfb/Ecore_DirectFB.h b/src/lib/ecore_directfb/Ecore_DirectFB.h new file mode 100644 index 0000000..3b94816 --- /dev/null +++ b/src/lib/ecore_directfb/Ecore_DirectFB.h @@ -0,0 +1,181 @@ +#ifndef _ECORE_DIRECTFB_H +#define _ECORE_DIRECTFB_H + +#include + +#include + +#ifdef EAPI +# undef EAPI +#endif /* ifdef EAPI */ + +#ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else /* if __GNUC__ >= 4 */ +# define EAPI +# endif /* if __GNUC__ >= 4 */ +#else /* ifdef __GNUC__ */ +# define EAPI +#endif /* ifdef __GNUC__ */ + +#ifdef __cplusplus +extern "C" { +#endif /* ifdef __cplusplus */ + +EAPI extern int ECORE_DIRECTFB_EVENT_POSITION; +EAPI extern int ECORE_DIRECTFB_EVENT_SIZE; +EAPI extern int ECORE_DIRECTFB_EVENT_CLOSE; +EAPI extern int ECORE_DIRECTFB_EVENT_DESTROYED; +EAPI extern int ECORE_DIRECTFB_EVENT_GOT_FOCUS; +EAPI extern int ECORE_DIRECTFB_EVENT_LOST_FOCUS; +EAPI extern int ECORE_DIRECTFB_EVENT_KEY_DOWN; +EAPI extern int ECORE_DIRECTFB_EVENT_KEY_UP; +EAPI extern int ECORE_DIRECTFB_EVENT_BUTTON_DOWN; +EAPI extern int ECORE_DIRECTFB_EVENT_BUTTON_UP; +EAPI extern int ECORE_DIRECTFB_EVENT_MOTION; +EAPI extern int ECORE_DIRECTFB_EVENT_ENTER; +EAPI extern int ECORE_DIRECTFB_EVENT_LEAVE; +EAPI extern int ECORE_DIRECTFB_EVENT_WHEEL; + +#ifndef _ECORE_DIRECTFB_WINDOW_PREDEF +typedef struct _Ecore_DirectFB_Window Ecore_DirectFB_Window; +#endif /* ifndef _ECORE_DIRECTFB_WINDOW_PREDEF */ +typedef struct _Ecore_DirectFB_Cursor Ecore_DirectFB_Cursor; + +typedef struct _Ecore_DirectFB_Event_Key_Down Ecore_DirectFB_Event_Key_Down; +typedef struct _Ecore_DirectFB_Event_Key_Up Ecore_DirectFB_Event_Key_Up; +typedef struct _Ecore_DirectFB_Event_Button_Down Ecore_DirectFB_Event_Button_Down; +typedef struct _Ecore_DirectFB_Event_Button_Up Ecore_DirectFB_Event_Button_Up; +typedef struct _Ecore_DirectFB_Event_Motion Ecore_DirectFB_Event_Motion; +typedef struct _Ecore_DirectFB_Event_Enter Ecore_DirectFB_Event_Enter; +typedef struct _Ecore_DirectFB_Event_Leave Ecore_DirectFB_Event_Leave; +typedef struct _Ecore_DirectFB_Event_Wheel Ecore_DirectFB_Event_Wheel; +typedef struct _Ecore_DirectFB_Event_Got_Focus Ecore_DirectFB_Event_Got_Focus; +typedef struct _Ecore_DirectFB_Event_Lost_Focus Ecore_DirectFB_Event_Lost_Focus; + +/* this struct is to keep windows data (id, window itself and surface) in memory as every call + * to DirectFB for this values (e.g window->GetSurface(window,&surface)) will increment the + * reference count, then we will have to release N times the data, so better we just ask for + them once */ +struct _Ecore_DirectFB_Window +{ + DFBWindowID id; + IDirectFBWindow *window; + IDirectFBSurface *surface; + Ecore_DirectFB_Cursor *cursor; +}; + +struct _Ecore_DirectFB_Cursor +{ + IDirectFBSurface *surface; + int hot_x; + int hot_y; +}; + +struct _Ecore_DirectFB_Event_Key_Down /** DirectFB Key Down event */ +{ + char *name; /**< The name of the key that was released */ + char *string; /**< The logical symbol of the key that was pressed */ + char *key_compose; /**< The UTF-8 string conversion if any */ + unsigned int time; + DFBWindowID win; +}; + +struct _Ecore_DirectFB_Event_Key_Up /** DirectFB Key Up event */ +{ + char *name; /**< The name of the key that was released */ + char *string; /**< The logical symbol of the key that was pressed */ + char *key_compose; /**< The UTF-8 string conversion if any */ + unsigned int time; + DFBWindowID win; +}; + +struct _Ecore_DirectFB_Event_Button_Down +{ + int button; + int modifiers; + int x, y; + unsigned int time; + int double_click : 1; + int triple_click : 1; + DFBWindowID win; +}; +struct _Ecore_DirectFB_Event_Button_Up +{ + int button; + int modifiers; + int x, y; + unsigned int time; + DFBWindowID win; + int double_click : 1; + int triple_click : 1; +}; +struct _Ecore_DirectFB_Event_Motion +{ + int modifiers; + int x, y; + unsigned int time; + DFBWindowID win; +}; + +struct _Ecore_DirectFB_Event_Enter +{ + int modifiers; + int x, y; + unsigned int time; + DFBWindowID win; +}; + +struct _Ecore_DirectFB_Event_Leave +{ + int modifiers; + int x, y; + unsigned int time; + DFBWindowID win; +}; + +struct _Ecore_DirectFB_Event_Wheel +{ + int direction; + int z; + int modifiers; + unsigned int time; + DFBWindowID win; +}; + +struct _Ecore_DirectFB_Event_Got_Focus +{ + unsigned int time; + DFBWindowID win; +}; + +struct _Ecore_DirectFB_Event_Lost_Focus +{ + unsigned int time; + DFBWindowID win; +}; + +/* main functions */ +EAPI int ecore_directfb_init(const char *name); +EAPI int ecore_directfb_shutdown(void); +EAPI IDirectFB * ecore_directfb_interface_get(void); + +/* window operations */ +EAPI Ecore_DirectFB_Window *ecore_directfb_window_new(int x, int y, int w, int h); +EAPI void ecore_directfb_window_free(Ecore_DirectFB_Window *window); +EAPI void ecore_directfb_window_move(Ecore_DirectFB_Window *window, int x, int y); +EAPI void ecore_directfb_window_resize(Ecore_DirectFB_Window *window, int w, int h); +EAPI void ecore_directfb_window_focus(Ecore_DirectFB_Window *window); +EAPI void ecore_directfb_window_show(Ecore_DirectFB_Window *window); +EAPI void ecore_directfb_window_hide(Ecore_DirectFB_Window *window); +EAPI void ecore_directfb_window_shaped_set(Ecore_DirectFB_Window *window, Eina_Bool set); +EAPI void ecore_directfb_window_fullscreen_set(Ecore_DirectFB_Window *window, Eina_Bool set); +EAPI void ecore_directfb_window_size_get(Ecore_DirectFB_Window *window, int *w, int *h); +EAPI void ecore_directfb_window_cursor_show(Ecore_DirectFB_Window *window, Eina_Bool show); + +#ifdef __cplusplus +} +#endif /* ifdef __cplusplus */ + +#endif /* ifndef _ECORE_DIRECTFB_H */ diff --git a/src/lib/ecore_directfb/Makefile.am b/src/lib/ecore_directfb/Makefile.am new file mode 100644 index 0000000..8142d33 --- /dev/null +++ b/src/lib/ecore_directfb/Makefile.am @@ -0,0 +1,31 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_builddir)/src/lib/ecore \ +@DIRECTFB_CFLAGS@ @EINA_CFLAGS@ + +lib_LTLIBRARIES = libecore_directfb.la +includes_HEADERS = Ecore_DirectFB.h +includesdir = $(includedir)/ecore-@VMAJ@ + +libecore_directfb_la_SOURCES = \ +ecore_directfb.c \ +ecore_directfb_keys.h \ +ecore_directfb_private.h + +libecore_directfb_la_LIBADD = \ +$(top_builddir)/src/lib/ecore/libecore.la \ +@DIRECTFB_LIBS@ \ +@EINA_LIBS@ + +libecore_directfb_la_LDFLAGS = -version-info @version_info@ @release_info@ + +libecore_directfb_la_DEPENDENCIES = \ +$(top_builddir)/src/lib/ecore/libecore.la + +EXTRA_DIST = \ +Ecore_DirectFB.h \ +ecore_directfb.c \ +ecore_directfb_keys.h \ +ecore_directfb_private.h diff --git a/src/lib/ecore_directfb/ecore_directfb.c b/src/lib/ecore_directfb/ecore_directfb.c new file mode 100644 index 0000000..7c56b5d --- /dev/null +++ b/src/lib/ecore_directfb/ecore_directfb.c @@ -0,0 +1,757 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include +#include + +#include "Ecore_DirectFB.h" +#include "ecore_directfb_private.h" +#include "ecore_directfb_keys.h" +#include "Ecore.h" +#include "ecore_private.h" + +/* ecore_directfb */ +/******************/ +/* About */ +/* with this you can create windows of directfb and handle events through ecore + * TODO: + * - handle all event types + * - + * */ +int _ecore_directfb_log_dom = -1; + +static int _ecore_directfb_init_count = 0; + +static int _window_event_fd = 0; +static int _input_event_fd = 0; + +static int _ecore_directfb_fullscreen_window_id = 0; +static int _cursor_x = 0; +static int _cursor_y = 0; + +EAPI int ECORE_DIRECTFB_EVENT_POSITION = 0; +EAPI int ECORE_DIRECTFB_EVENT_SIZE = 0; +EAPI int ECORE_DIRECTFB_EVENT_CLOSE = 0; +EAPI int ECORE_DIRECTFB_EVENT_DESTROYED = 0; +EAPI int ECORE_DIRECTFB_EVENT_GOT_FOCUS = 0; +EAPI int ECORE_DIRECTFB_EVENT_LOST_FOCUS = 0; +EAPI int ECORE_DIRECTFB_EVENT_KEY_DOWN = 0; +EAPI int ECORE_DIRECTFB_EVENT_KEY_UP = 0; +EAPI int ECORE_DIRECTFB_EVENT_BUTTON_DOWN = 0; +EAPI int ECORE_DIRECTFB_EVENT_BUTTON_UP = 0; +EAPI int ECORE_DIRECTFB_EVENT_MOTION = 0; +EAPI int ECORE_DIRECTFB_EVENT_ENTER = 0; +EAPI int ECORE_DIRECTFB_EVENT_LEAVE = 0; +EAPI int ECORE_DIRECTFB_EVENT_WHEEL = 0; + +static Ecore_Fd_Handler *_window_event_fd_handler_handle = NULL; +static Ecore_Fd_Handler *_input_event_fd_handler_handle = NULL; + +/* this hash is to store all the possible key names for fast lookup */ +static Eina_Hash *_ecore_directfb_key_symbols_hash = NULL; + +static IDirectFB *_dfb = NULL; // the main interface +static IDirectFBEventBuffer *_window_event; // the main event buffer (all windows are attached to this) +static IDirectFBEventBuffer *_input_event; // the main event buffer (all windows are attached to this) +static IDirectFBDisplayLayer *_layer; // the main layer +static DFBResult _err; // useful for DFBCHECK + +/*******************/ +/* local functions */ +/*******************/ + +/* free ecore directfb events functions */ +/****************************************/ + +static void +_ecore_directfb_event_free_key_down(void *data __UNUSED__, void *ev) +{ + Ecore_DirectFB_Event_Key_Up *e; + + e = ev; + if(e->name) + free(e->name); + + if (e->string) + free(e->string); + + if (e->key_compose) + free(e->key_compose); + + free(e); +} + +static void +_ecore_directfb_event_free_key_up(void *data __UNUSED__, void *ev) +{ + Ecore_DirectFB_Event_Key_Up *e; + + e = ev; + if(e->name) + free(e->name); + + if (e->string) + free(e->string); + + if (e->key_compose) + free(e->key_compose); + + free(e); +} + +/* directfb window input events handler */ +/****************************************/ + +static void +_ecore_directfb_event_handle_motion(DFBEvent *evt) +{ + Ecore_DirectFB_Event_Motion *e; + e = calloc(1, sizeof(Ecore_DirectFB_Event_Motion)); + + switch(evt->clazz) + { + case DFEC_INPUT: + e->modifiers = 0; + switch(evt->input.axis) + { + case DIAI_X: + e->x = _cursor_x = evt->input.axisabs; + e->y = _cursor_y; + break; + + case DIAI_Y: + e->y = _cursor_y = evt->input.axisabs; + e->x = _cursor_x; + break; + + case DIAI_Z: + //_ecore_directfb_event_handle_wheel(evt); + return; + + default: + return; + } + e->win = _ecore_directfb_fullscreen_window_id; + e->time = 0; + break; + + case DFEC_WINDOW: + e->modifiers = 0; + e->x = evt->window.x; + e->y = evt->window.y; + e->win = evt->window.window_id; + e->time = 0; + break; + + default: + break; + } + ecore_event_add(ECORE_DIRECTFB_EVENT_MOTION, e, NULL, NULL); +} + +static void +_ecore_directfb_event_handle_key_down(DFBEvent *evt) +{ + Ecore_DirectFB_Event_Key_Down *e; + unsigned int key_symbol; + struct keymap *k; + + e = calloc(1, sizeof(Ecore_DirectFB_Event_Key_Down)); + + switch(evt->clazz) + { + case DFEC_INPUT: + key_symbol = evt->input.key_symbol; + k = eina_hash_find(_ecore_directfb_key_symbols_hash, &key_symbol); + + if(!k) + { + ERR("Symbol %0X of class DFEC_INPUT not found.", evt->input.key_symbol); + return; + } + + e->name = strdup(k->name); + e->string = strdup(k->string); + e->key_compose = NULL; + e->win = _ecore_directfb_fullscreen_window_id; + e->time = 0; + break; + + case DFEC_WINDOW: + key_symbol = evt->window.key_symbol; + k = eina_hash_find(_ecore_directfb_key_symbols_hash, &key_symbol); + + if(!k) + { + ERR("Symbol %0X of class DFEC_WINDOW not found.", evt->window.key_symbol); + return; + } + + e->name = strdup(k->name); + e->string = strdup(k->string); + e->key_compose = NULL; + e->win = evt->window.window_id; + e->time = 0; + break; + + default: + break; + } + + ecore_event_add(ECORE_DIRECTFB_EVENT_KEY_DOWN, e, _ecore_directfb_event_free_key_down, NULL); +} + +static void +_ecore_directfb_event_handle_key_up(DFBEvent *evt) +{ + Ecore_DirectFB_Event_Key_Up *e; + unsigned int key_symbol; + struct keymap *k; + + e = calloc(1, sizeof(Ecore_DirectFB_Event_Key_Up)); + + switch(evt->clazz) + { + case DFEC_INPUT: + key_symbol = evt->input.key_symbol; + k = eina_hash_find(_ecore_directfb_key_symbols_hash, &key_symbol); + + if(!k) + { + ERR("Symbol %0X of class DFEC_INPUT not found.", evt->input.key_symbol); + return; + } + + e->name = strdup(k->name); + e->string = strdup(k->string); + e->key_compose = NULL; + e->win = _ecore_directfb_fullscreen_window_id; + e->time = 0; + break; + + case DFEC_WINDOW: + key_symbol = evt->window.key_symbol; + k = eina_hash_find(_ecore_directfb_key_symbols_hash, &key_symbol); + + if(!k) + { + ERR("Symbol %0X of class DFEC_WINDOW not found.", evt->window.key_symbol); + return; + } + + e->name = strdup(k->name); + e->string = strdup(k->string); + e->key_compose = NULL; + e->win = evt->window.window_id; + e->time = 0; + break; + + default: + break; + } + ecore_event_add(ECORE_DIRECTFB_EVENT_KEY_UP, e, _ecore_directfb_event_free_key_up, NULL); +} + +static void +_ecore_directfb_event_handle_button_down(DFBEvent *evt) +{ + Ecore_DirectFB_Event_Button_Down *e; + e = calloc(1, sizeof(Ecore_DirectFB_Event_Button_Down)); + + switch(evt->clazz) + { + case DFEC_INPUT: + e->button = evt->input.button + 1; + e->modifiers = 0; + DFBCHECK(_layer->GetCursorPosition(_layer,&e->x,&e->y)); + e->x = _cursor_x; + e->y = _cursor_y; + e->win = _ecore_directfb_fullscreen_window_id; + e->time = 0; + + break; + + case DFEC_WINDOW: + e->button = evt->window.button + 1; + e->modifiers = 0; + e->x = evt->window.x; + e->y = evt->window.y; + e->win = evt->window.window_id; + e->time = 0; + break; + + default: + break; + } + + ecore_event_add(ECORE_DIRECTFB_EVENT_BUTTON_DOWN, e, NULL, NULL); +} + +static void +_ecore_directfb_event_handle_button_up(DFBEvent *evt) +{ + Ecore_DirectFB_Event_Button_Up *e; + e = calloc(1, sizeof(Ecore_DirectFB_Event_Button_Up)); + + switch(evt->clazz) + { + case DFEC_INPUT: + e->button = evt->input.button + 1; + e->modifiers = 0; + e->x = _cursor_x; + e->y = _cursor_y; + e->win = _ecore_directfb_fullscreen_window_id; + e->time = 0; + + break; + + case DFEC_WINDOW: + e->button = evt->window.button + 1; + e->modifiers = 0; + e->x = evt->window.x; + e->y = evt->window.y; + e->win = evt->window.window_id; + e->time = 0; + break; + + default: + break; + } + ecore_event_add(ECORE_DIRECTFB_EVENT_BUTTON_UP, e, NULL, NULL); +} + +static void +_ecore_directfb_event_handle_enter(DFBWindowEvent *evt) +{ + Ecore_DirectFB_Event_Enter *e; + e = calloc(1, sizeof(Ecore_DirectFB_Event_Enter)); + + e->modifiers = 0; + e->x = evt->x; + e->y = evt->y; + e->win = evt->window_id; + e->time = 0; + + ecore_event_add(ECORE_DIRECTFB_EVENT_ENTER, e, NULL, NULL); +} + +static void +_ecore_directfb_event_handle_leave(DFBWindowEvent *evt) +{ + Ecore_DirectFB_Event_Leave *e; + e = calloc(1, sizeof(Ecore_DirectFB_Event_Leave)); + + e->modifiers = 0; + e->x = evt->x; + e->y = evt->y; + e->win = evt->window_id; + e->time = 0; + + ecore_event_add(ECORE_DIRECTFB_EVENT_LEAVE, e, NULL, NULL); +} + +static void +_ecore_directfb_event_handle_wheel(DFBWindowEvent *evt) +{ + Ecore_DirectFB_Event_Wheel *e; + e = calloc(1, sizeof(Ecore_DirectFB_Event_Wheel)); + + // currently there's no direction (only up/down); + e->direction = 0; + e->z = evt->step; + e->modifiers = 0; + e->win = evt->window_id; + e->time = 0; + + ecore_event_add(ECORE_DIRECTFB_EVENT_WHEEL, e, NULL, NULL); +} + +static void +_ecore_directfb_event_handle_got_focus(DFBWindowEvent *evt) +{ + Ecore_DirectFB_Event_Got_Focus *e; + e = calloc(1, sizeof(Ecore_DirectFB_Event_Got_Focus)); + + e->win = evt->window_id; + e->time = 0; + + ecore_event_add(ECORE_DIRECTFB_EVENT_GOT_FOCUS, e, NULL, NULL); +} + +static void +_ecore_directfb_event_handle_lost_focus(DFBWindowEvent *evt) +{ + Ecore_DirectFB_Event_Lost_Focus *e; + e = calloc(1, sizeof(Ecore_DirectFB_Event_Lost_Focus)); + + e->win = evt->window_id; + e->time = 0; + + ecore_event_add(ECORE_DIRECTFB_EVENT_LOST_FOCUS, e, NULL, NULL); +} + +/* inputs and windows fds handlers */ +/***********************************/ +/* TODO fix this to handle windows and input events (fullscreen/window mode) + * in fullscreen theres no window_id so get the id from a global var (only one fullscreen + * window at a time */ + +static Eina_Bool +_ecore_directfb_input_event_fd_handler(void *data __UNUSED__,Ecore_Fd_Handler *fd_handler __UNUSED__) +{ + DFBEvent evt; + int v = 0; + + v = read(_input_event_fd, &evt, sizeof(DFBEvent)); + if (v < 0) + return EINA_TRUE; + + if (v < 1) + return EINA_TRUE; + + /* we are getting duplicate events, only parse if we are in fullscreen */ + //if(_ecore_directfb_fullscreen_window_id == 0) break; + if(evt.input.type == DIET_KEYPRESS) + _ecore_directfb_event_handle_key_down(&evt); + + if(evt.input.type == DIET_KEYRELEASE) + _ecore_directfb_event_handle_key_up(&evt); + + if(evt.input.type == DIET_BUTTONPRESS) + _ecore_directfb_event_handle_button_down(&evt); + + if(evt.input.type == DIET_BUTTONRELEASE) + _ecore_directfb_event_handle_button_up(&evt); + + if(evt.input.type == DIET_AXISMOTION) + _ecore_directfb_event_handle_motion(&evt); + + return EINA_TRUE; +} + +static Eina_Bool +_ecore_directfb_window_event_fd_handler(void *data __UNUSED__,Ecore_Fd_Handler *fd_handler __UNUSED__) +{ + DFBEvent evt; + int v = 0; + + v = read(_window_event_fd, &evt, sizeof(DFBEvent)); + if (v < 0) + return EINA_TRUE; + + if (v < 1) + return EINA_TRUE; + + if(evt.window.type & DWET_POSITION) + INF("position"); + + if(evt.window.type & DWET_SIZE) + INF("size"); + + if(evt.window.type & DWET_CLOSE) + INF("close"); + + if(evt.window.type & DWET_DESTROYED) + INF("destroyed"); + + if(evt.window.type & DWET_GOTFOCUS) + _ecore_directfb_event_handle_got_focus(&evt.window); + + if(evt.window.type & DWET_LOSTFOCUS) + _ecore_directfb_event_handle_lost_focus(&evt.window); + + if(evt.window.type & DWET_KEYDOWN) + _ecore_directfb_event_handle_key_down(&evt); + + if(evt.window.type & DWET_KEYUP) + _ecore_directfb_event_handle_key_up(&evt); + + if(evt.window.type & DWET_BUTTONDOWN) + _ecore_directfb_event_handle_button_down(&evt); + + if(evt.window.type & DWET_BUTTONUP) + _ecore_directfb_event_handle_button_up(&evt); + + if(evt.window.type & DWET_MOTION) + _ecore_directfb_event_handle_motion(&evt); + + if(evt.window.type & DWET_ENTER) + _ecore_directfb_event_handle_enter(&evt.window); + + if(evt.window.type & DWET_LEAVE) + _ecore_directfb_event_handle_leave(&evt.window); + + if(evt.window.type & DWET_WHEEL) + _ecore_directfb_event_handle_wheel(&evt.window); + + return EINA_TRUE; +} + +/* api functions */ +/*****************/ + +EAPI IDirectFB * +ecore_directfb_interface_get(void) +{ + return _dfb; +} + +EAPI Ecore_DirectFB_Window * +ecore_directfb_window_new(int x, int y, int w, int h) +{ + Ecore_DirectFB_Window *window; + IDirectFBWindow *dfb_window; + IDirectFBSurface *dfb_surface = NULL; + DFBWindowDescription desc; + DFBWindowID id; + + memset(&desc, 0, sizeof(DFBWindowDescription)); + desc.flags = (DWDESC_POSX | DWDESC_POSY | DWDESC_WIDTH | DWDESC_HEIGHT | DWDESC_CAPS); + desc.posx = x; + desc.posy = y; + desc.width = w; + desc.height = h; + desc.caps = DWCAPS_ALPHACHANNEL; + + DFBCHECK(_layer->CreateWindow(_layer, &desc, &dfb_window)); + + dfb_window->AttachEventBuffer(dfb_window, _window_event); + dfb_window->SetOptions(dfb_window,DWOP_NONE); + dfb_window->SetOpacity(dfb_window, 0xFF); + + DFBCHECK(dfb_window->GetID(dfb_window, &id)); + DFBCHECK(dfb_window->GetSurface(dfb_window,&dfb_surface)); + + window = malloc(sizeof(Ecore_DirectFB_Window)); + window->id = id; + window->window = dfb_window; + window->surface = dfb_surface; + window->cursor = NULL; + + return window; +} + +EAPI void +ecore_directfb_window_free(Ecore_DirectFB_Window *ecore_window) +{ + DFBCHECK(ecore_window->surface->Release(ecore_window->surface)); + DFBCHECK(ecore_window->window->Release(ecore_window->window)); + free(ecore_window); +} + +EAPI void +ecore_directfb_window_move(Ecore_DirectFB_Window *ecore_window, int x, int y) +{ + DFBCHECK(ecore_window->window->MoveTo(ecore_window->window, x, y)); +} + +EAPI void +ecore_directfb_window_resize(Ecore_DirectFB_Window *ecore_window, int w, int h) +{ + DFBCHECK(ecore_window->window->Resize(ecore_window->window, w, h)); +} + +EAPI void +ecore_directfb_window_focus(Ecore_DirectFB_Window *ecore_window) +{ + DFBCHECK(ecore_window->window->RequestFocus(ecore_window->window)); +} + +EAPI void +ecore_directfb_window_hide(Ecore_DirectFB_Window *ecore_window) +{ + DFBCHECK(ecore_window->window->SetOpacity(ecore_window->window, 0)); +} + +EAPI void +ecore_directfb_window_show(Ecore_DirectFB_Window *ecore_window) +{ + DFBCHECK(ecore_window->window->SetOpacity(ecore_window->window, 0xFF)); +} + +EAPI void +ecore_directfb_window_shaped_set(Ecore_DirectFB_Window *ecore_window, Eina_Bool set) +{ + DFBWindowOptions opts; + + DFBCHECK(ecore_window->window->GetOptions(ecore_window->window, &opts)); + if(set) + { + opts |= DWOP_SHAPED; + opts |= DWOP_ALPHACHANNEL; + DFBCHECK(ecore_window->window->SetOptions(ecore_window->window, opts)); + } + else + { + opts &= ~DWOP_SHAPED; + opts &= ~DWOP_ALPHACHANNEL; + DFBCHECK(ecore_window->window->SetOptions(ecore_window->window, opts)); + } +} + +EAPI void +ecore_directfb_window_cursor_show(Ecore_DirectFB_Window *ecore_window, Eina_Bool show) +{ + if(!show) + { + /* create an empty cursor and set it */ + IDirectFBSurface *cursor; + DFBSurfaceDescription desc; + + memset(&desc, 0, sizeof(DFBSurfaceDescription)); + desc.flags = (DSDESC_HEIGHT | DSDESC_WIDTH | DSDESC_PIXELFORMAT); + desc.width = 1; + desc.height = 1; + desc.pixelformat = DSPF_A1; + + DFBCHECK(_dfb->CreateSurface(_dfb,&desc,&cursor)); + DFBCHECK(cursor->Clear(cursor,0,0,0,0)); + DFBCHECK(ecore_window->window->SetCursorShape(ecore_window->window, cursor, 0, 0)); + } + else + { + /* we already have a cursor surface so set it*/ + if(ecore_window->cursor) + { + DFBCHECK(ecore_window->window->SetCursorShape(ecore_window->window, ecore_window->cursor->surface, ecore_window->cursor->hot_x, ecore_window->cursor->hot_y)); + } + /* or just set the default directfb cursor */ + else + { + DFBCHECK(ecore_window->window->SetCursorShape(ecore_window->window, NULL, 0, 0)); + } + } +} + +EAPI void +ecore_directfb_window_cursor_set(Ecore_DirectFB_Window *ecore_window, Ecore_DirectFB_Cursor *cursor) +{ + if((!cursor) && (ecore_window->cursor)) + { + ecore_window->cursor = NULL; + DFBCHECK(ecore_window->window->SetCursorShape(ecore_window->window, NULL, 0, 0)); + return; + } + + if(cursor) + { + ecore_window->cursor = cursor; + DFBCHECK(ecore_window->window->SetCursorShape(ecore_window->window, cursor->surface, cursor->hot_x, cursor->hot_y)); + } +} + +EAPI void +ecore_directfb_window_fullscreen_set(Ecore_DirectFB_Window *ecore_window, Eina_Bool on) +{ + // always release the surface (we are going to get a new one in both cases) + DFBCHECK(ecore_window->surface->Release(ecore_window->surface)); + if(on) + { + DFBCHECK(_layer->SetCooperativeLevel(_layer,DLSCL_EXCLUSIVE)); + DFBCHECK(_layer->GetSurface(_layer,&ecore_window->surface)); + DFBCHECK(_dfb->CreateInputEventBuffer(_dfb, DICAPS_ALL, DFB_FALSE, &_input_event)); + DFBCHECK(_input_event->CreateFileDescriptor(_input_event,&_input_event_fd)); + /* the event of axismove sends one axis at a time, so we must store both */ + DFBCHECK(_layer->GetCursorPosition(_layer,&_cursor_x,&_cursor_y)); + + _input_event_fd_handler_handle = ecore_main_fd_handler_add(_input_event_fd,ECORE_FD_READ,_ecore_directfb_input_event_fd_handler, NULL,NULL,NULL); + _ecore_directfb_fullscreen_window_id = ecore_window->id; + } + else + { + ecore_main_fd_handler_del(_input_event_fd_handler_handle); + DFBCHECK(_input_event->Release(_input_event)); + DFBCHECK(_layer->SetCooperativeLevel(_layer,DLSCL_SHARED)); + DFBCHECK(ecore_window->window->GetSurface(ecore_window->window, &ecore_window->surface)); + _ecore_directfb_fullscreen_window_id = 0; + } +} + +EAPI void +ecore_directfb_window_size_get(Ecore_DirectFB_Window *ecore_window, int *w, int *h) +{ + DFBCHECK(ecore_window->surface->GetSize(ecore_window->surface,w,h)); + return; +} + +EAPI int +ecore_directfb_init(const char *name __UNUSED__) +{ + int i = 0; + + if (++_ecore_directfb_init_count != 1) + return _ecore_directfb_init_count; + + _ecore_directfb_log_dom = eina_log_domain_register + ("ecore_directfb", ECORE_DIRECTFB_DEFAULT_LOG_COLOR); + if(_ecore_directfb_log_dom < 0) + { + EINA_LOG_ERR("Impossible to create a log domain for the Ecore directFB module."); + return _ecore_directfb_init_count--; + } + + DFBCHECK(DirectFBInit(NULL,NULL)); + DFBCHECK(DirectFBCreate(&_dfb)); + + DFBCHECK(_dfb->GetDisplayLayer(_dfb, DLID_PRIMARY, &_layer)); + DFBCHECK(_layer->SetCooperativeLevel(_layer, DLSCL_SHARED)); + + /* window events and fd */ + DFBCHECK(_dfb->CreateEventBuffer(_dfb, &_window_event)); + DFBCHECK(_window_event->CreateFileDescriptor(_window_event,&_window_event_fd)); + _window_event_fd_handler_handle = ecore_main_fd_handler_add(_window_event_fd,ECORE_FD_READ,_ecore_directfb_window_event_fd_handler, NULL,NULL,NULL); + + /* register ecore directfb events */ + ECORE_DIRECTFB_EVENT_POSITION = ecore_event_type_new(); + ECORE_DIRECTFB_EVENT_SIZE = ecore_event_type_new(); + ECORE_DIRECTFB_EVENT_CLOSE = ecore_event_type_new(); + ECORE_DIRECTFB_EVENT_DESTROYED = ecore_event_type_new(); + ECORE_DIRECTFB_EVENT_GOT_FOCUS = ecore_event_type_new(); + ECORE_DIRECTFB_EVENT_LOST_FOCUS = ecore_event_type_new(); + ECORE_DIRECTFB_EVENT_KEY_DOWN = ecore_event_type_new(); + ECORE_DIRECTFB_EVENT_KEY_UP = ecore_event_type_new(); + ECORE_DIRECTFB_EVENT_BUTTON_DOWN = ecore_event_type_new(); + ECORE_DIRECTFB_EVENT_BUTTON_UP = ecore_event_type_new(); + ECORE_DIRECTFB_EVENT_MOTION = ecore_event_type_new(); + ECORE_DIRECTFB_EVENT_ENTER = ecore_event_type_new(); + ECORE_DIRECTFB_EVENT_LEAVE = ecore_event_type_new(); + ECORE_DIRECTFB_EVENT_WHEEL = ecore_event_type_new(); + + /* create the hash table for the keynames */ + _ecore_directfb_key_symbols_hash = eina_hash_int32_new(free); + for(i = 0; i < _ecore_directfb_key_symbols_count; i++) + { + struct keymap *k; + k = malloc(sizeof(struct keymap)); + k->name = _ecore_directfb_key_symbols[i].name; + k->string = _ecore_directfb_key_symbols[i].string; + eina_hash_add(_ecore_directfb_key_symbols_hash, &_ecore_directfb_key_symbols[i].id, k); + } + /* create the hash for the windows(key = windowid, val = Ecore_DirectFB_Window struct) */ + return _ecore_directfb_init_count; +} + +EAPI int +ecore_directfb_shutdown(void) +{ + if (--_ecore_directfb_init_count != 0) + return _ecore_directfb_init_count; + + ecore_main_fd_handler_del(_window_event_fd_handler_handle); + eina_hash_free(_ecore_directfb_key_symbols_hash); + + if(_ecore_directfb_fullscreen_window_id) + { + DFBCHECK(_input_event->Release(_input_event)); + ecore_main_fd_handler_del(_input_event_fd_handler_handle); + } + + DFBCHECK(_window_event->Release(_window_event)); + DFBCHECK(_layer->Release(_layer)); + DFBCHECK(_dfb->Release(_dfb)); + eina_log_domain_unregister(_ecore_directfb_log_dom); + _ecore_directfb_log_dom = -1; + return _ecore_directfb_init_count; +} + diff --git a/src/lib/ecore_directfb/ecore_directfb_keys.h b/src/lib/ecore_directfb/ecore_directfb_keys.h new file mode 100644 index 0000000..19cca46 --- /dev/null +++ b/src/lib/ecore_directfb/ecore_directfb_keys.h @@ -0,0 +1,184 @@ +typedef struct _Ecore_DirectFB_Key_Symbols Ecore_DirectFB_Key_Symbols; +struct _Ecore_DirectFB_Key_Symbols +{ + char *string; + char *name; + unsigned int id; +}; + +static const Ecore_DirectFB_Key_Symbols _ecore_directfb_key_symbols[] = { + {"\010", "BackSpace",DIKS_BACKSPACE}, + {"\011", "Tab", DIKS_TAB}, + {"\015", "Return", DIKS_RETURN}, + {"", "Cancel", DIKS_CANCEL}, + {"", "Escape", DIKS_ESCAPE}, + {" ", "space", DIKS_SPACE}, + {"!", "exclam", DIKS_EXCLAMATION_MARK}, + {"\"", "quotedbl", DIKS_QUOTATION}, + {"#", "numbersign", DIKS_NUMBER_SIGN}, + {"$", "dollar", DIKS_DOLLAR_SIGN}, + {"%", "percent", DIKS_PERCENT_SIGN}, + {"&", "ampersand", DIKS_AMPERSAND}, + {"'", "apostrophe", DIKS_APOSTROPHE}, + {"(", "parenleft", DIKS_PARENTHESIS_LEFT}, + {")", "parenright", DIKS_PARENTHESIS_RIGHT}, + {"*", "asterisk", DIKS_ASTERISK}, + {"+", "plus", DIKS_PLUS_SIGN}, + {",", "comma", DIKS_COMMA}, + {"-", "minus", DIKS_MINUS_SIGN}, + {".", "period", DIKS_PERIOD}, + {"/", "slash", DIKS_SLASH}, + {"0", "0", DIKS_0}, + {"1", "1", DIKS_1}, + {"2", "2", DIKS_2}, + {"3", "3", DIKS_3}, + {"4", "4", DIKS_4}, + {"5", "5", DIKS_5}, + {"6", "6", DIKS_6}, + {"7", "7", DIKS_7}, + {"8", "8", DIKS_8}, + {"9", "9", DIKS_9}, + {":", "colon", DIKS_COLON}, + {";", "semicolon", DIKS_SEMICOLON}, + {"<", "less", DIKS_LESS_THAN_SIGN}, + {"=", "equal", DIKS_EQUALS_SIGN}, + {">", "greater", DIKS_GREATER_THAN_SIGN}, + {"?", "question", DIKS_QUESTION_MARK}, + {"@", "at", DIKS_AT}, + {"A", "A", DIKS_CAPITAL_A }, + {"B", "B", DIKS_CAPITAL_B }, + {"C", "C", DIKS_CAPITAL_C }, + {"D", "D", DIKS_CAPITAL_D }, + {"E", "E", DIKS_CAPITAL_E }, + {"F", "F", DIKS_CAPITAL_F }, + {"G", "G", DIKS_CAPITAL_G }, + {"H", "H", DIKS_CAPITAL_H }, + {"I", "I", DIKS_CAPITAL_I }, + {"J", "J", DIKS_CAPITAL_J }, + {"K", "K", DIKS_CAPITAL_K }, + {"L", "L", DIKS_CAPITAL_L }, + {"M", "M", DIKS_CAPITAL_M }, + {"N", "N", DIKS_CAPITAL_N }, + {"O", "O", DIKS_CAPITAL_O }, + {"P", "P", DIKS_CAPITAL_P }, + {"Q", "Q", DIKS_CAPITAL_Q }, + {"R", "R", DIKS_CAPITAL_R }, + {"S", "S", DIKS_CAPITAL_S }, + {"T", "T", DIKS_CAPITAL_T }, + {"U", "U", DIKS_CAPITAL_U }, + {"V", "V", DIKS_CAPITAL_V }, + {"W", "W", DIKS_CAPITAL_W }, + {"X", "X", DIKS_CAPITAL_X }, + {"Y", "Y", DIKS_CAPITAL_Y }, + {"Z", "Z", DIKS_CAPITAL_Z }, + {"[", "bracketleft", DIKS_SQUARE_BRACKET_LEFT }, + {"\\", "backslash", DIKS_BACKSLASH }, + {"]", "bracketright", DIKS_SQUARE_BRACKET_RIGHT }, + {"^", "asciicircum", DIKS_CIRCUMFLEX_ACCENT }, + {"_", "underscore", DIKS_UNDERSCORE }, + {"`", "grave", DIKS_GRAVE_ACCENT}, + {"a", "a", DIKS_SMALL_A }, + {"b","b", DIKS_SMALL_B }, + {"c","c", DIKS_SMALL_C }, + {"d","d", DIKS_SMALL_D }, + {"e","e", DIKS_SMALL_E }, + {"f","f", DIKS_SMALL_F }, + {"g","g", DIKS_SMALL_G }, + {"h","h", DIKS_SMALL_H }, + {"i","i", DIKS_SMALL_I }, + {"j","j", DIKS_SMALL_J }, + {"k","k", DIKS_SMALL_K }, + {"l","l", DIKS_SMALL_L }, + {"m","m", DIKS_SMALL_M }, + {"n","n", DIKS_SMALL_N }, + {"o", "o", DIKS_SMALL_O }, + {"p", "p", DIKS_SMALL_P }, + {"q", "q", DIKS_SMALL_Q }, + {"r", "r", DIKS_SMALL_R }, + {"s", "s", DIKS_SMALL_S }, + {"t", "t", DIKS_SMALL_T }, + {"u", "u", DIKS_SMALL_U }, + {"v", "v", DIKS_SMALL_V }, + {"w", "w", DIKS_SMALL_W }, + {"x", "x", DIKS_SMALL_X }, + {"y", "y", DIKS_SMALL_Y }, + {"z", "z", DIKS_SMALL_Z }, + {"{", "braceleft",DIKS_CURLY_BRACKET_LEFT }, + {"|", "bar", DIKS_VERTICAL_BAR }, + {"}", "braceright", DIKS_CURLY_BRACKET_RIGHT }, + {"~", "asciitilde", DIKS_TILDE }, + {"\177", "Delete", DIKS_DELETE }, + {"", "Left", DIKS_CURSOR_LEFT }, + {"", "Right", DIKS_CURSOR_RIGHT}, + {"", "Up", DIKS_CURSOR_UP}, + {"", "Down", DIKS_CURSOR_DOWN}, + {"", "Insert", DIKS_INSERT}, + {"", "Home", DIKS_HOME}, + {"", "End", DIKS_END}, + {"", "Page_Up", DIKS_PAGE_UP}, + {"", "Page_Down", DIKS_PAGE_DOWN}, + {"", "Print", DIKS_PRINT}, + {"", "Pause", DIKS_PAUSE}, + /* ok */ + {"", "Select",DIKS_SELECT}, + /* goto */ + {"", "Clear", DIKS_CLEAR}, + /* power */ + /* power 2 */ + /* option */ + {"", "Menu",DIKS_MENU}, + {"", "Help",DIKS_HELP}, + /* info */ + /* time */ + /* vendor */ + /* archive */ + /* program */ + /* channel */ + /* favorites */ + /* hasta next */ + {"", "Next",DIKS_NEXT}, + {"", "Begin",DIKS_BEGIN}, + /* digits */ + /* teen */ + /* twen */ + {"", "Break", DIKS_BREAK}, + /* exit */ + /* setup */ + {"", "upleftcorner", DIKS_CURSOR_LEFT_UP }, + {"", "lowleftcorner", DIKS_CURSOR_LEFT_DOWN }, + {"", "uprightcorner", DIKS_CURSOR_UP_RIGHT }, + {"", "lowrightcorner",DIKS_CURSOR_DOWN_RIGHT }, + {"", "F1",DIKS_F1}, + {"", "F2",DIKS_F2}, + {"", "F3",DIKS_F3}, + {"", "F4",DIKS_F4}, + {"", "F5",DIKS_F5}, + {"", "F6",DIKS_F6}, + {"", "F7",DIKS_F7}, + {"", "F8",DIKS_F8}, + {"", "F9",DIKS_F9}, + {"", "F10",DIKS_F10}, + {"", "F11",DIKS_F11}, + {"", "F12",DIKS_F12}, + /* this are only mapped to one, not left right */ + {"", "Shift_L", DIKS_SHIFT}, + /*{"Shift_R",0xFFE2},*/ + {"", "Control_L", DIKS_CONTROL}, + /*{"Control_R",0xFFE4},*/ + {"", "Meta_L", DIKS_META}, + /* {"Meta_R",0xFFE8},*/ + {"", "Alt_L", DIKS_ALT}, + {"", "Alt_R", DIKS_ALTGR}, + {"", "Super_L", DIKS_SUPER}, + /*{"Super_R",0xFFEC},*/ + {"", "Hyper_L", DIKS_HYPER}, + /*{"Hyper_R",0xFFEE},*/ + + {"", "Caps_Lock", DIKS_CAPS_LOCK}, + {"", "Num_Lock", DIKS_NUM_LOCK}, + {"", "Scroll_Lock", DIKS_SCROLL_LOCK}, + /* not included the dead keys */ + /* not included the custom keys */ + {"", "VoidSymbol", DIKS_NULL} +}; +static int _ecore_directfb_key_symbols_count = sizeof(_ecore_directfb_key_symbols) / sizeof(Ecore_DirectFB_Key_Symbols); diff --git a/src/lib/ecore_directfb/ecore_directfb_private.h b/src/lib/ecore_directfb/ecore_directfb_private.h new file mode 100644 index 0000000..ed34587 --- /dev/null +++ b/src/lib/ecore_directfb/ecore_directfb_private.h @@ -0,0 +1,52 @@ +#ifndef _ECORE_DIRECTFB_PRIVATE_H +#define _ECORE_DIRECTFB_PRIVATE_H +/* eina_log related things */ + +extern int _ecore_directfb_log_dom; + +#ifdef ECORE_DIRECTFB_DEFAULT_LOG_COLOR +#undef ECORE_DIRECTFB_DEFAULT_LOG_COLOR +#endif /* ifdef ECORE_DIRECTFB_DEFAULT_LOG_COLOR */ +#define ECORE_DIRECTFB_DEFAULT_LOG_COLOR EINA_COLOR_BLUE + +#ifdef ERR +# undef ERR +#endif /* ifdef ERR */ +#define ERR(...) EINA_LOG_DOM_ERR(_ecore_directfb_log_dom, __VA_ARGS__) + +#ifdef DBG +# undef DBG +#endif /* ifdef DBG */ +#define DBG(...) EINA_LOG_DOM_DBG(_ecore_directfb_log_dom, __VA_ARGS__) + +#ifdef INF +# undef INF +#endif /* ifdef INF */ +#define INF(...) EINA_LOG_DOM_INFO(_ecore_directfb_log_dom, __VA_ARGS__) + +#ifdef WRN +# undef WRN +#endif /* ifdef WRN */ +#define WRN(...) EINA_LOG_DOM_WARN(_ecore_directfb_log_dom, __VA_ARGS__) + +#ifdef CRIT +# undef CRIT +#endif /* ifdef CRIT */ +#define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_directfb_log_dom, __VA_ARGS__) + +/* macro for a safe call to DirectFB functions */ +#define DFBCHECK(x ...)\ + {\ + _err = x;\ + if (_err != DFB_OK) {\ + CRIT("%s <%d>:\n\t", __FILE__, __LINE__ );\ + DirectFBErrorFatal( # x, _err );\ + }\ + } + +struct keymap +{ + char *name; + char *string; +}; +#endif /* ifndef _ECORE_DIRECTFB_PRIVATE_H */ diff --git a/src/lib/ecore_evas/Ecore_Evas.h b/src/lib/ecore_evas/Ecore_Evas.h new file mode 100644 index 0000000..db42d1d --- /dev/null +++ b/src/lib/ecore_evas/Ecore_Evas.h @@ -0,0 +1,2270 @@ +#ifndef _ECORE_EVAS_H +#define _ECORE_EVAS_H + +#include +#include +#include + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_ECORE_EVAS_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_ECORE_EVAS_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +/** + * @file Ecore_Evas.h + * @brief Evas wrapper functions + * + * The following is a list of example that partially exemplify Ecore_Evas's API: + * @li @ref ecore_evas_callbacks_example_c + * @li @ref ecore_evas_object_example_c + * @li @ref ecore_evas_basics_example_c + * @li @ref Ecore_Evas_Window_Sizes_Example_c + * @li @ref Ecore_Evas_Buffer_Example_01_c + * @li @ref Ecore_Evas_Buffer_Example_02_c + */ + +/* FIXME: + * to do soon: + * - iconfication api needs to work + * - maximization api needs to work + * - document all calls + * + * later: + * - buffer back-end that renders to an evas_image_object ??? + * - qt back-end ??? + * - dfb back-end ??? (dfb's threads make this REALLY HARD) + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup Ecore_Evas_Group Ecore_Evas wrapper/helper set of functions + * + * Ecore evas is a set of functions that makes it easy to tie together ecore's + * main loop and input handling to evas. As such it's a natural base for EFL + * applications. While this combination makes it easy to create the basic + * aspects all applications need, for normal applications(ones with buttons, + * checkboxes and layouts) one should consider using Elementary. + * + * Ecore evas is extremely well suited for applications that are not based on + * widgets. It has a main loop that delivers events, does basic window handling + * and leaves all of the drawing up to the user. This works very well if used + * in conjunction with Edje or if doing custom drawing as, for example, is done + * in games. + * + * This is a list of examples of these functions: + * @li @ref ecore_evas_basics_example_c + * @li @ref ecore_evas_object_example_c + * @li @ref ecore_evas_callbacks_example_c + * @li @ref Ecore_Evas_Window_Sizes_Example_c + * @li @ref Ecore_Evas_Buffer_Example_01_c + * @li @ref Ecore_Evas_Buffer_Example_02_c + * + * @{ + */ + +/* these are dummy and just tell u what API levels ecore_evas supports - not if + * the actual support is compiled in. you need to query for that separately. + */ +#define HAVE_ECORE_EVAS_X 1 +#define HAVE_ECORE_EVAS_FB 1 +#define HAVE_ECORE_EVAS_X11_GL 1 +#define HAVE_ECORE_EVAS_X11_16 1 +#define HAVE_ECORE_EVAS_DIRECTFB 1 +#define HAVE_ECORE_EVAS_WIN32 1 +#define HAVE_ECORE_EVAS_COCOA 1 +#define HAVE_ECORE_EVAS_SDL 1 +#define HAVE_ECORE_EVAS_WINCE 1 +#define HAVE_ECORE_EVAS_EWS 1 +#define HAVE_ECORE_EVAS_PSL1GHT 1 +#define HAVE_ECORE_EVAS_WAYLAND_SHM 1 +#define HAVE_ECORE_EVAS_WAYLAND_EGL 1 + +typedef enum _Ecore_Evas_Engine_Type +{ + ECORE_EVAS_ENGINE_SOFTWARE_BUFFER, + ECORE_EVAS_ENGINE_SOFTWARE_XLIB, + ECORE_EVAS_ENGINE_XRENDER_X11, + ECORE_EVAS_ENGINE_OPENGL_X11, + ECORE_EVAS_ENGINE_SOFTWARE_XCB, + ECORE_EVAS_ENGINE_XRENDER_XCB, + ECORE_EVAS_ENGINE_SOFTWARE_GDI, + ECORE_EVAS_ENGINE_SOFTWARE_DDRAW, + ECORE_EVAS_ENGINE_DIRECT3D, + ECORE_EVAS_ENGINE_OPENGL_GLEW, + ECORE_EVAS_ENGINE_OPENGL_COCOA, + ECORE_EVAS_ENGINE_SOFTWARE_SDL, + ECORE_EVAS_ENGINE_DIRECTFB, + ECORE_EVAS_ENGINE_SOFTWARE_FB, + ECORE_EVAS_ENGINE_SOFTWARE_8_X11, + ECORE_EVAS_ENGINE_SOFTWARE_16_X11, + ECORE_EVAS_ENGINE_SOFTWARE_16_DDRAW, + ECORE_EVAS_ENGINE_SOFTWARE_16_WINCE, + ECORE_EVAS_ENGINE_OPENGL_SDL, + ECORE_EVAS_ENGINE_EWS, + ECORE_EVAS_ENGINE_PSL1GHT, + ECORE_EVAS_ENGINE_WAYLAND_SHM, + ECORE_EVAS_ENGINE_WAYLAND_EGL +} Ecore_Evas_Engine_Type; + +typedef enum _Ecore_Evas_Avoid_Damage_Type +{ + ECORE_EVAS_AVOID_DAMAGE_NONE = 0, + ECORE_EVAS_AVOID_DAMAGE_EXPOSE = 1, + ECORE_EVAS_AVOID_DAMAGE_BUILT_IN = 2 +} Ecore_Evas_Avoid_Damage_Type; + +typedef enum _Ecore_Evas_Object_Associate_Flags +{ + ECORE_EVAS_OBJECT_ASSOCIATE_BASE = 0, + ECORE_EVAS_OBJECT_ASSOCIATE_STACK = 1 << 0, + ECORE_EVAS_OBJECT_ASSOCIATE_LAYER = 1 << 1, + ECORE_EVAS_OBJECT_ASSOCIATE_DEL = 1 << 2 +} Ecore_Evas_Object_Associate_Flags; + +#ifndef _ECORE_X_H +#define _ECORE_X_WINDOW_PREDEF +typedef unsigned int Ecore_X_Window; +#endif + +#ifndef _ECORE_DIRECTFB_H +#define _ECORE_DIRECTFB_WINDOW_PREDEF +typedef struct _Ecore_DirectFB_Window Ecore_DirectFB_Window; +#endif + +#ifndef __ECORE_WIN32_H__ +typedef struct _Ecore_Win32_Window Ecore_Win32_Window; +#endif + +#ifndef __ECORE_WINCE_H__ +typedef struct _Ecore_WinCE_Window Ecore_WinCE_Window; +#endif + +#ifndef __ECORE_COCOA_H__ +typedef struct _Ecore_Cocoa_Window Ecore_Cocoa_Window; +#endif + +#ifndef _ECORE_EVAS_PRIVATE_H +/* basic data types */ +typedef struct _Ecore_Evas Ecore_Evas; +typedef void (*Ecore_Evas_Event_Cb) (Ecore_Evas *ee); /**< Callback used for several ecore evas events @since 1.2 */ +#endif + +#ifndef _ECORE_WAYLAND_H_ +#define _ECORE_WAYLAND_WINDOW_PREDEF +typedef struct _Ecore_Wl_Window Ecore_Wl_Window; +#endif + +/* module setup/shutdown calls */ + +EAPI int ecore_evas_engine_type_supported_get(Ecore_Evas_Engine_Type engine); + +/** + * @brief Init the Ecore_Evas system. + * + * @return How many times the lib has been initialized, 0 indicates failure. + * + * Set up the Evas wrapper system. Init Evas and Ecore libraries. + * + * @see ecore_evas_shutdown() + */ +EAPI int ecore_evas_init(void); +/** + * @brief Shut down the Ecore_Evas system. + * + * @return 0 if ecore evas is fully shut down, or > 0 if it still being used. + * + * This closes the Evas wrapper system down. Shut down Evas and Ecore libraries. + * + * @see ecore_evas_init() + */ +EAPI int ecore_evas_shutdown(void); + +EAPI void ecore_evas_app_comp_sync_set(Eina_Bool do_sync); +EAPI Eina_Bool ecore_evas_app_comp_sync_get(void); + +/** + * @brief Returns a list of supported engines names. + * + * @return Newly allocated list with engines names. Engines names + * strings are internal and should be considered constants, do not + * free or modify them, to free the list use ecore_evas_engines_free(). + */ +EAPI Eina_List *ecore_evas_engines_get(void); +/** + * @brief Free list returned by ecore_evas_engines_get() + * + * @param engines list with engines names + */ +EAPI void ecore_evas_engines_free(Eina_List *engines); +/** + * @brief Creates a new Ecore_Evas based on engine name and common parameters. + * + * @param engine_name engine name as returned by + * ecore_evas_engines_get() or @c NULL to use environment variable + * ECORE_EVAS_ENGINE, that can be undefined and in this case + * this call will try to find the first working engine. + * @param x horizontal position of window (not supported in all engines) + * @param y vertical position of window (not supported in all engines) + * @param w width of window + * @param h height of window + * @param extra_options string with extra parameter, dependent on engines + * or @ NULL. String is usually in the form: 'key1=value1;key2=value2'. + * Pay attention that when getting that from shell commands, most + * consider ';' as the command terminator, so you need to escape + * it or use quotes. + * + * @return Ecore_Evas instance or @c NULL if creation failed. + */ +EAPI Ecore_Evas *ecore_evas_new(const char *engine_name, int x, int y, int w, int h, const char *extra_options); +/** + * @brief Set whether an Ecore_Evas has an alpha channel or not. + * + * @param ee The Ecore_Evas to shape + * @param alpha @c EINA_TRUE to enable the alpha channel, @c EINA_FALSE to + * disable it + * + * This function allows you to make an Ecore_Evas translucent using an + * alpha channel. See ecore_evas_shaped_set() for details. The difference + * between a shaped window and a window with an alpha channel is that an + * alpha channel supports multiple levels of transparency, as opposed to + * the 1 bit transparency of a shaped window (a pixel is either opaque, or + * it's transparent). + * + * @warning Support for this depends on the underlying windowing system. + */ +EAPI void ecore_evas_alpha_set(Ecore_Evas *ee, Eina_Bool alpha); +/** + * @brief Query whether an Ecore_Evas has an alpha channel. + * @param ee The Ecore_Evas to query. + * @return @c EINA_TRUE if ee has an alpha channel, @c EINA_FALSE if it does + * not. + * + * This function returns @c EINA_TRUE if @p ee has an alpha channel, and + * @c EINA_FALSE if it does not. + * + * @see ecore_evas_alpha_set() + */ +EAPI Eina_Bool ecore_evas_alpha_get(const Ecore_Evas *ee); +/** + * @brief Set whether an Ecore_Evas has an transparent window or not. + * + * @param ee The Ecore_Evas to shape + * @param transparent @c EINA_TRUE to enable the transparent window, + * @c EINA_FALSE to disable it + * + * This function sets some translucency options, for more complete support see + * ecore_evas_alpha_set(). + * + * @warning Support for this depends on the underlying windowing system. + * + * @see ecore_evas_alpha_set() + */ +EAPI void ecore_evas_transparent_set(Ecore_Evas *ee, Eina_Bool transparent); +/** + * @brief Query whether an Ecore_Evas is transparent. + * + * @param ee The Ecore_Evas to query. + * @return @c EINA_TRUE if ee is transparent, @c EINA_FALSE if it isn't. + * + * @see ecore_evas_transparent_set() + */ +EAPI Eina_Bool ecore_evas_transparent_get(const Ecore_Evas *ee); +/** + * @brief Get the geometry of an Ecore_Evas. + * + * @param ee The Ecore_Evas whose geometry y + * @param x A pointer to an int to place the x coordinate in + * @param y A pointer to an int to place the y coordinate in + * @param w A pointer to an int to place the w size in + * @param h A pointer to an int to place the h size in + * + * This function takes four pointers to (already allocated) ints, and places + * the geometry of @p ee in them. If any of the parameters is not desired you + * may pass @c NULL on them. + * + * @code + * int x, y, w, h; + * ecore_evas_geometry_get(ee, &x, &y, &w, &h); + * @endcode + * + * @see ecore_evas_new() + * @see ecore_evas_resize() + * @see ecore_evas_move() + * @see ecore_evas_move_resize() + */ +EAPI void ecore_evas_geometry_get(const Ecore_Evas *ee, int *x, int *y, int *w, int *h); +/** + * @brief Get the geometry which an Ecore_Evas was latest recently requested. + * + * @param ee The Ecore_Evas whose geometry y + * @param x A pointer to an int to place the x coordinate in + * @param y A pointer to an int to place the y coordinate in + * @param w A pointer to an int to place the w size in + * @param h A pointer to an int to place the h size in + * + * This function takes four pointers to (already allocated) ints, and places + * the geometry which @p ee was latest recently requested . If any of the + * parameters is not desired you may pass @c NULL on them. + * This function can represent recently requested geometry. + * ecore_evas_geometry_get function returns the value is updated after engine + * finished request. By comparison, ecore_evas_request_geometry_get returns + * recently requested value. + * + * @code + * int x, y, w, h; + * ecore_evas_request_geometry_get(ee, &x, &y, &w, &h); + * @endcode + * + * @since 1.1 + */ +EAPI void ecore_evas_request_geometry_get(const Ecore_Evas *ee, int *x, int *y, int *w, int *h); +/** + * @brief Set the focus of an Ecore_Evas' window. + * + * @param ee The Ecore_Evas + * @param on @c EINA_TRUE for focus, @c EINA_FALSE to defocus. + * + * This function focuses @p ee if @p on is @c EINA_TRUE, or unfocuses @p ee if + * @p on is @c EINA_FALSE. + * + * @warning Support for this depends on the underlying windowing system. + */ +EAPI void ecore_evas_focus_set(Ecore_Evas *ee, Eina_Bool on); +/** + * @brief Query whether an Ecore_Evas' window is focused or not. + * + * @param ee The Ecore_Evas to set + * @return @c EINA_TRUE if @p ee if focused, @c EINA_FALSE if not. + * + * @see ecore_evas_focus_set() + */ +EAPI Eina_Bool ecore_evas_focus_get(const Ecore_Evas *ee); +/** + * @brief Iconify or uniconify an Ecore_Evas' window. + * + * @param ee The Ecore_Evas + * @param on @c EINA_TRUE to iconify, @c EINA_FALSE to uniconify. + * + * This function iconifies @p ee if @p on is @c EINA_TRUE, or uniconifies @p ee + * if @p on is @c EINA_FALSE. + * + * @note Iconify and minimize are synonyms. + * + * @warning Support for this depends on the underlying windowing system. + */ +EAPI void ecore_evas_iconified_set(Ecore_Evas *ee, Eina_Bool on); +/** + * @brief Query whether an Ecore_Evas' window is iconified or not. + * + * @param ee The Ecore_Evas to set + * @return @c EINA_TRUE if @p ee is iconified, @c EINA_FALSE if not. + * + * @note Iconify and minimize are synonyms. + * + * @see ecore_evas_iconified_set() + */ +EAPI Eina_Bool ecore_evas_iconified_get(const Ecore_Evas *ee); +/** + * @brief Set whether an Ecore_Evas' window is borderless or not. + * + * @param ee The Ecore_Evas + * @param on @c EINA_TRUE for borderless, @c EINA_FALSE for bordered. + * + * This function makes @p ee borderless if @p on is @c EINA_TRUE, or bordered + * if @p on is @c EINA_FALSE. + * + * @warning Support for this depends on the underlying windowing system. + */ +EAPI void ecore_evas_borderless_set(Ecore_Evas *ee, Eina_Bool on); +/** + * @brief Query whether an Ecore_Evas' window is borderless or not. + * + * @param ee The Ecore_Evas to set + * @return @c EINA_TRUE if @p ee is borderless, @c EINA_FALSE if not. + * + * @see ecore_evas_borderless_set() + */ +EAPI Eina_Bool ecore_evas_borderless_get(const Ecore_Evas *ee); +/** + * @brief Set whether or not an Ecore_Evas' window is fullscreen. + * + * @param ee The Ecore_Evas + * @param on @c EINA_TRUE fullscreen, @c EINA_FALSE not. + * + * This function causes @p ee to be fullscreen if @p on is @c EINA_TRUE, or + * not if @p on is @c EINA_FALSE. + * + * @warning Support for this depends on the underlying windowing system. + */ +EAPI void ecore_evas_fullscreen_set(Ecore_Evas *ee, Eina_Bool on); +/** + * @brief Query whether an Ecore_Evas' window is fullscreen or not. + * + * @param ee The Ecore_Evas to set + * @return @c EINA_TRUE if @p ee is fullscreen, @c EINA_FALSE if not. + * + * @see ecore_evas_fullscreen_set() + */ +EAPI Eina_Bool ecore_evas_fullscreen_get(const Ecore_Evas *ee); +/** + * @brief Set another window that this window is a group member of + * + * @param ee The Ecore_Evas + * @param ee_group The other group member + * + * If @p ee_group is @c NULL, @p ee is removed from the group, otherwise it is + * added. Note that if you free the @p ee_group canvas before @p ee, then + * getting the group canvas with ecore_evas_window_group_get() will return + * an invalid handle. + * + * @warning Support for this depends on the underlying windowing system. + * @since 1.2 + */ +EAPI void ecore_evas_window_group_set(Ecore_Evas *ee, const Ecore_Evas *ee_group); +/** + * @brief Get the canvas group set. + * + * This returns the handle set by ecore_evas_window_group_set(). + * + * @param ee The Ecore_Evas to set + * @return The Canvas group handle + * + * @see ecore_evas_window_group_set() + * @since 1.2 + */ +EAPI const Ecore_Evas *ecore_evas_window_group_get(const Ecore_Evas *ee); +/** + * @brief Set the aspect ratio of a canvas window + * + * @param ee The Ecore_Evas + * @param aspect The aspect ratio (width divided by height), or 0 to disable + * + * This sets the desired aspect ratio of a canvas window + * + * @warning Support for this depends on the underlying windowing system. + * @since 1.2 + */ +EAPI void ecore_evas_aspect_set(Ecore_Evas *ee, double aspect); +/** + * @brief Get the aspect ratio of a canvas window + * + * This returns the value set by ecore_evas_aspect_set(). + * + * @param ee The Ecore_Evas to set + * @return The aspect ratio + * + * @see ecore_evas_aspect_set() + * @since 1.2 + */ +EAPI double ecore_evas_aspect_get(const Ecore_Evas *ee); +/** + * @brief Set The urgent hint flag + * + * @param ee The Ecore_Evas + * @param urgent The urgent state flag + * + * This sets the "urgent" state hint on a window so the desktop environment + * can highlight it somehow. + * + * @warning Support for this depends on the underlying windowing system. + * @since 1.2 + */ +EAPI void ecore_evas_urgent_set(Ecore_Evas *ee, Eina_Bool urgent); +/** + * @brief Get the urgent state on the cavas window + * + * This returns the value set by ecore_evas_urgent_set() + * + * @param ee The Ecore_Evas to set + * @return The urgent state set + * + * @see ecore_evas_urgent_set() + * @since 1.2 + */ +EAPI Eina_Bool ecore_evas_urgent_get(const Ecore_Evas *ee); +/** + * @brief Set the modal state flag on the canvas window + * + * @param ee The Ecore_Evas + * @param modal The modal hint flag + * + * This hints if the window should be modal (eg if it is also transient + * for another window, the other window will maybe be denied focus by + * the desktop window manager). + * + * @warning Support for this depends on the underlying windowing system. + * @since 1.2 + */ +EAPI void ecore_evas_modal_set(Ecore_Evas *ee, Eina_Bool modal); +/** + * @brief Get The modal flag + * + * This returns the value set by ecore_evas_modal_set(). + * + * @param ee The Ecore_Evas to set + * @return The modal flag + * + * @see ecore_evas_modal_set() + * @since 1.2 + */ +EAPI Eina_Bool ecore_evas_modal_get(const Ecore_Evas *ee); +/** + * @brief Set the "i demand attention" flag on a canvas window + * + * @param ee The Ecore_Evas + * @param demand The flag state to set + * + * A window may demand attention now (eg you must enter a password before + * continuing), and so it may flag a window with this. + * + * @warning Support for this depends on the underlying windowing system. + * @since 1.2 + */ +EAPI void ecore_evas_demand_attention_set(Ecore_Evas *ee, Eina_Bool demand); +/** + * @brief Get the "i demand attention" flag + * + * This returns the value set by ecore_evas_demand_attention_set(). + * + * @param ee The Ecore_Evas to set + * @return The "i demand attention" flag. + * + * @see ecore_evas_demand_attention_set() + * @since 1.2 + */ +EAPI Eina_Bool ecore_evas_demand_attention_get(const Ecore_Evas *ee); +/** + * @brief Set the "focus skip" flag + * + * @param ee The Ecore_Evas + * @param skip The "focus skip" state to set. + * + * A window may not want to accept focus, be in the taskbar, pager etc. + * sometimes (example for a small notification window that hovers around + * a taskbar or panel, or hovers around a window until some activity + * dismisses it). + * + * @warning Support for this depends on the underlying windowing system. + * @since 1.2 + */ +EAPI void ecore_evas_focus_skip_set(Ecore_Evas *ee, Eina_Bool skip); +/** + * @brief Get the "focus skip" flag + * + * This returns the value set by ecore_evas_focus_skip_set(). + * + * @param ee The Ecore_Evas to set + * @return The "focus skip" flag. + * + * @see ecore_evas_focus_skip_set() + * @since 1.2 + */ +EAPI Eina_Bool ecore_evas_focus_skip_get(const Ecore_Evas *ee); + +/** + * @brief Set if this evas should ignore @b all events. + * + * @param ee The Ecore_Evas whose window's to ignore events. + * @param ignore The Ecore_Evas new ignore state. + * + * @warning Support for this depends on the underlying windowing system. + */ +EAPI void ecore_evas_ignore_events_set(Ecore_Evas *ee, Eina_Bool ignore); +/** + * @brief Returns the ignore state of an Ecore_Evas' window. + * + * @param ee The Ecore_Evas whose window's ignore events state is returned. + * @return The Ecore_Evas window's ignore state. + * + * @see ecore_evas_ignore_events_set() + */ +EAPI Eina_Bool ecore_evas_ignore_events_get(const Ecore_Evas *ee); +/** + * @brief Query whether an Ecore_Evas' window is visible or not. + * + * @param ee The Ecore_Evas to query. + * @return 1 if visible, 0 if not. + * + * This function queries @p ee and returns 1 if it is visible, and 0 if not. + * + * @see ecore_evas_show() + * @see ecore_evas_hide() + */ +EAPI int ecore_evas_visibility_get(const Ecore_Evas *ee); +/** + * @brief Set the layer of an Ecore_Evas' window. + * + * @param ee The Ecore_Evas + * @param layer The layer to put @p ee on. + * + * This function moves @p ee to the layer @p layer. + * + * @warning Support for this depends on the underlying windowing system. + * + * @see ecore_evas_lower() + * @see ecore_evas_raise() + */ +EAPI void ecore_evas_layer_set(Ecore_Evas *ee, int layer); +/** + * @brief Get the layer of an Ecore_Evas' window. + * + * @param ee The Ecore_Evas to set + * @return the layer @p ee's window is on. + * + * @see ecore_evas_layer_set() + * @see ecore_evas_lower() + * @see ecore_evas_raise() + */ +EAPI int ecore_evas_layer_get(const Ecore_Evas *ee); +/** + * @brief Maximize (or unmaximize) an Ecore_Evas' window. + * + * @param ee The Ecore_Evas + * @param on @c EINA_TRUE to maximize, @c EINA_FALSE to unmaximize. + * + * This function maximizes @p ee if @p on is @c EINA_TRUE, or unmaximizes @p ee + * if @p on is @c EINA_FALSE. + * + * @warning Support for this depends on the underlying windowing system. + */ +EAPI void ecore_evas_maximized_set(Ecore_Evas *ee, Eina_Bool on); +/** + * @brief Query whether an Ecore_Evas' window is maximized or not. + * + * @param ee The Ecore_Evas to set + * @return @c EINA_TRUE if @p ee is maximized, @c EINA_FALSE if not. + * + * @see ecore_evas_maximized_set() + */ +EAPI Eina_Bool ecore_evas_maximized_get(const Ecore_Evas *ee); +/** + * @brief Set Ecore_Evas's window profile list. + * + * @param ee The Ecore_Evas + * @param profiles The profile name list + * @param num_profiles The number of profile names + * + * @warning Support for this depends on the underlying windowing system. + * @since 1.7.0 + */ +EAPI void ecore_evas_profiles_set(Ecore_Evas *ee, const char **profiles, unsigned int num_profiles); +/** + * @brief Get Ecore_Evas's window profile name. + * + * @param ee The Ecore_Evas + * @return The profile name + * + * @since 1.7.0 + */ +EAPI const char *ecore_evas_profile_get(const Ecore_Evas *ee); +/** + * @brief Move an Ecore_Evas. + * + * @param ee The Ecore_Evas to move + * @param x The x coordinate to move to + * @param y The y coordinate to move to + * + * This moves @p ee to the screen coordinates (@p x, @p y) + * + * @warning Support for this depends on the underlying windowing system. + * + * @see ecore_evas_new() + * @see ecore_evas_resize() + * @see ecore_evas_move_resize() + */ +EAPI void ecore_evas_move(Ecore_Evas *ee, int x, int y); +/** + * @brief Resize an Ecore_Evas. + * + * @param ee The Ecore_Evas to move + * @param w The w coordinate to resize to + * @param h The h coordinate to resize to + * + * This resizes @p ee to @p w x @p h. + * + * @warning Support for this depends on the underlying windowing system. + * + * @see ecore_evas_new() + * @see ecore_evas_move() + * @see ecore_evas_move_resize() + */ +EAPI void ecore_evas_resize(Ecore_Evas *ee, int w, int h); +/** + * @brief Move and resize an Ecore_Evas + * + * @param ee The Ecore_Evas to move and resize + * @param x The x coordinate to move to + * @param y The y coordinate to move to + * @param w The w coordinate to resize to + * @param h The h coordinate to resize to + * + * This moves @p ee to the screen coordinates (@p x, @p y) and resizes + * it to @p w x @p h. + * + * @warning Support for this depends on the underlying windowing system. + * + * @see ecore_evas_new() + * @see ecore_evas_move() + * @see ecore_evas_resize() + */ +EAPI void ecore_evas_move_resize(Ecore_Evas *ee, int x, int y, int w, int h); +/** + * @brief Set the rotation of an Ecore_Evas' window. + * + * @param ee The Ecore_Evas + * @param rot the angle (in degrees) of rotation. + * + * The allowed values of @p rot depend on the engine being used. Most only + * allow multiples of 90. + * + * @warning Support for this depends on the underlying windowing system. + * + * @see ecore_evas_rotation_with_resize_set() + */ +EAPI void ecore_evas_rotation_set(Ecore_Evas *ee, int rot); +/** + * @brief Set the rotation of an Ecore_Evas' window + * + * @param ee The Ecore_Evas + * @param rot the angle (in degrees) of rotation. + * + * Like ecore_evas_rotation_set(), but it also resizes the window's contents so + * that they fit inside the current window geometry. + * + * @warning Support for this depends on the underlying windowing system. + * + * @see ecore_evas_rotation_set() + */ +EAPI void ecore_evas_rotation_with_resize_set(Ecore_Evas *ee, int rot); +/** + * @brief Get the rotation of an Ecore_Evas' window + * + * @param ee The Ecore_Evas + * @return the angle (in degrees) of rotation. + * + * @see ecore_evas_rotation_set() + * @see ecore_evas_rotation_with_resize_set() + */ +EAPI int ecore_evas_rotation_get(const Ecore_Evas *ee); +/** + * @brief Raise an Ecore_Evas' window. + * + * @param ee The Ecore_Evas to raise. + * + * This functions raises the Ecore_Evas to the front. + * + * @warning Support for this depends on the underlying windowing system. + * + * @see ecore_evas_lower() + * @see ecore_evas_layer_set() + */ +EAPI void ecore_evas_raise(Ecore_Evas *ee); +/** + * @brief Lower an Ecore_Evas' window. + * + * @param ee The Ecore_Evas to raise. + * + * This functions lowers the Ecore_Evas to the back. + * + * @warning Support for this depends on the underlying windowing system. + * + * @see ecore_evas_raise() + * @see ecore_evas_layer_set() + */ +EAPI void ecore_evas_lower(Ecore_Evas *ee); +/** + * @brief Set the title of an Ecore_Evas' window. + * + * @param ee The Ecore_Evas whose title you wish to set. + * @param t The title + * + * This function sets the title of @p ee to @p t. + * + * @warning Support for this depends on the underlying windowing system. + */ +EAPI void ecore_evas_title_set(Ecore_Evas *ee, const char *t); +/** + * @brief Get the title of an Ecore_Evas' window. + * + * @param ee The Ecore_Evas whose title you wish to get. + * @return The title of @p ee. + * + * This function returns the title of @p ee. + * + * @see ecore_evas_title_set() + */ +EAPI const char *ecore_evas_title_get(const Ecore_Evas *ee); +/** + * @brief Set the name and class of an Ecore_Evas' window. + * + * @param ee the Ecore_Evas + * @param n the name + * @param c the class + * + * This function sets the name of @p ee to @p n, and its class to @p c. The + * meaning of @p name and @p class depends on the underlying windowing system. + * + * @warning Support for this depends on the underlying windowing system. + */ +EAPI void ecore_evas_name_class_set(Ecore_Evas *ee, const char *n, const char *c); +/** + * @brief Get the name and class of an Ecore_Evas' window + * + * This function gets the name of @p ee into @p n, and its class into + * @p c. + * + * @param ee The Ecore_Evas to query. + * @param n A pointer to a string to place the name in. + * @param c A pointer to a string to place the class in. + * @see ecore_evas_name_class_set() + */ +EAPI void ecore_evas_name_class_get(const Ecore_Evas *ee, const char **n, const char **c); +/** + * @brief Returns a pointer to the underlying window. + * + * @param ee The Ecore_Evas whose window is desired. + * @return A pointer to the underlying window. + * + * @warning Support for this depends on the underlying windowing system. + */ +EAPI Ecore_Window ecore_evas_window_get(const Ecore_Evas *ee); + + +/* engine/target specific init calls */ +EAPI Ecore_Evas *ecore_evas_software_x11_new(const char *disp_name, Ecore_X_Window parent, int x, int y, int w, int h); +EAPI Ecore_X_Window ecore_evas_software_x11_window_get(const Ecore_Evas *ee); +EAPI void ecore_evas_software_x11_direct_resize_set(Ecore_Evas *ee, Eina_Bool on); +EAPI Eina_Bool ecore_evas_software_x11_direct_resize_get(const Ecore_Evas *ee); +EAPI void ecore_evas_software_x11_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win); + +#define ECORE_EVAS_GL_X11_OPT_NONE 0 +#define ECORE_EVAS_GL_X11_OPT_INDIRECT 1 +#define ECORE_EVAS_GL_X11_OPT_VSYNC 2 +#define ECORE_EVAS_GL_X11_OPT_LAST 3 + +EAPI Ecore_Evas *ecore_evas_gl_x11_new(const char *disp_name, Ecore_X_Window parent, int x, int y, int w, int h); +EAPI Ecore_Evas *ecore_evas_gl_x11_options_new(const char *disp_name, Ecore_X_Window parent, int x, int y, int w, int h, const int *opt); +EAPI Ecore_X_Window ecore_evas_gl_x11_window_get(const Ecore_Evas *ee); +EAPI void ecore_evas_gl_x11_direct_resize_set(Ecore_Evas *ee, Eina_Bool on); +EAPI Eina_Bool ecore_evas_gl_x11_direct_resize_get(const Ecore_Evas *ee); +EAPI void ecore_evas_gl_x11_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win); +EAPI void ecore_evas_gl_x11_pre_post_swap_callback_set(const Ecore_Evas *ee, void *data, void (*pre_cb) (void *data, Evas *e), void (*post_cb) (void *data, Evas *e)); + +EAPI Ecore_Evas *ecore_evas_xrender_x11_new(const char *disp_name, Ecore_X_Window parent, int x, int y, int w, int h); +EAPI Ecore_X_Window ecore_evas_xrender_x11_window_get(const Ecore_Evas *ee); +EAPI void ecore_evas_xrender_x11_direct_resize_set(Ecore_Evas *ee, Eina_Bool on); +EAPI Eina_Bool ecore_evas_xrender_x11_direct_resize_get(const Ecore_Evas *ee); +EAPI void ecore_evas_xrender_x11_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win); + +EAPI Ecore_Evas *ecore_evas_software_x11_8_new(const char *disp_name, Ecore_X_Window parent, int x, int y, int w, int h); +EAPI Ecore_X_Window ecore_evas_software_x11_8_window_get(const Ecore_Evas *ee); +EAPI Ecore_X_Window ecore_evas_software_x11_8_subwindow_get(const Ecore_Evas *ee); +EAPI void ecore_evas_software_x11_8_direct_resize_set(Ecore_Evas *ee, Eina_Bool on); +EAPI Eina_Bool ecore_evas_software_x11_8_direct_resize_get(const Ecore_Evas *ee); +EAPI void ecore_evas_software_x11_8_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win); + +EAPI Ecore_Evas *ecore_evas_software_x11_16_new(const char *disp_name, Ecore_X_Window parent, int x, int y, int w, int h); +EAPI Ecore_X_Window ecore_evas_software_x11_16_window_get(const Ecore_Evas *ee); +EAPI void ecore_evas_software_x11_16_direct_resize_set(Ecore_Evas *ee, Eina_Bool on); +EAPI Eina_Bool ecore_evas_software_x11_16_direct_resize_get(const Ecore_Evas *ee); +EAPI void ecore_evas_software_x11_16_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win); + +EAPI Ecore_Evas *ecore_evas_fb_new(const char *disp_name, int rotation, int w, int h); + +EAPI Ecore_Evas *ecore_evas_directfb_new(const char *disp_name, int windowed, int x, int y, int w, int h); +EAPI Ecore_DirectFB_Window *ecore_evas_directfb_window_get(const Ecore_Evas *ee); + + +EAPI Ecore_Evas *ecore_evas_wayland_shm_new(const char *disp_name, unsigned int parent, int x, int y, int w, int h, Eina_Bool frame); +EAPI Ecore_Evas *ecore_evas_wayland_egl_new(const char *disp_name, unsigned int parent, int x, int y, int w, int h, Eina_Bool frame); +EAPI void ecore_evas_wayland_resize(Ecore_Evas *ee, int location); +EAPI void ecore_evas_wayland_move(Ecore_Evas *ee, int x, int y); + +/* EAPI void ecore_evas_wayland_drag_start(Ecore_Evas *ee, Ecore_Evas *drag_ee, void *source); */ +EAPI void ecore_evas_wayland_pointer_set(Ecore_Evas *ee, int hot_x, int hot_y); +EAPI void ecore_evas_wayland_type_set(Ecore_Evas *ee, int type); +EAPI Ecore_Wl_Window *ecore_evas_wayland_window_get(const Ecore_Evas *ee); + +/** + * @brief Create a new @c Ecore_Evas canvas bound to the Evas + * @b buffer engine + * + * @param w The width of the canvas, in pixels + * @param h The height of the canvas, in pixels + * @return A new @c Ecore_Evas instance or @c NULL, on failure + * + * This creates a new buffer canvas wrapper, with image data array + * @b bound to the ARGB format, 8 bits per pixel. + * + * This function will allocate the needed pixels array with canonical + * @c malloc(). If you wish a custom function to allocate it, consider + * using ecore_evas_buffer_allocfunc_new(), instead. + * + * @note This function actually is a wrapper on + * ecore_evas_buffer_allocfunc_new(), using the same @a w and @a h + * arguments and canonical @c malloc() and @c free() to the memory + * allocation and freeing functions. See that function's documentation + * for more details. + */ +EAPI Ecore_Evas *ecore_evas_buffer_new(int w, int h); + +/** + * @brief Create a new @c Ecore_Evas canvas bound to the Evas + * @b buffer engine, giving custom allocation and freeing functions for + * the canvas memory region + * + * @param w The width of the canvas, in canvas units + * @param h The height of the canvas, in canvas units + * @param alloc_func Function to be called to allocate the memory + * needed for the new buffer canvas. @a data will be passed the same + * value as the @p data of this function, while @a size will be passed + * @p w times @p h times @c sizeof(int). + * @param free_func Function to be called to free the memory used by + * the new buffer canvas. @a data will be passed the same value as the + * @p data of this function, while @a pix will be passed the canvas + * memory pointer. + * @param data Custom data to be passed to the allocation and freeing + * functions + * @return A new @c Ecore_Evas instance or @c NULL, on failure + * + * This creates a new buffer canvas wrapper, with image data array + * @b bound to the ARGB format, 8 bits per pixel. + * + * This function is useful when one wants an @c Ecore_Evas buffer + * canvas with a custom allocation function, like one getting memory + * chunks from a memory pool, for example. + * + * On any resizing of this @c Ecore_Evas buffer canvas, its image data + * will be @b freed, to be allocated again with the new size. + * + * @note @p w and @p h sizes have to greater or equal to 1. Otherwise, + * they'll be interpreted as 1, exactly. + * + * @see ecore_evas_buffer_new() + */ +EAPI Ecore_Evas *ecore_evas_buffer_allocfunc_new(int w, int h, void *(*alloc_func) (void *data, int size), void (*free_func) (void *data, void *pix), const void *data); + +/** + * @brief Grab a pointer to the actual pixels array of a given + * @c Ecore_Evas @b buffer canvas/window. + * + * @param ee An @c Ecore_Evas handle + * @return A pointer to the internal pixels array of @p ee + * + * Besides returning a pointer to the actual pixel array of the given + * canvas, this call will force a rendering update on @p ee, + * first. + * + * A common use case for this call is to create an image object, from + * @b another canvas, to have as data @p ee's contents, thus + * snapshoting the canvas. For that case, one can also use the + * ecore_evas_object_image_new() helper function. + */ +EAPI const void *ecore_evas_buffer_pixels_get(Ecore_Evas *ee); + +/** + * @brief Create a new @c Ecore_Evas canvas bound to the Evas + * @b ews (Ecore + Evas Single Process Windowing System) engine + * + * EWS is a simple single process windowing system. The backing store + * is also an @c Ecore_Evas that can be setup with + * ecore_evas_ews_setup() and retrieved with + * ecore_evas_ews_ecore_evas_get(). It will allow window management + * using events prefixed with @c ECORE_EVAS_EVENT_EWS_. + * + * The EWS windows (returned by this function or + * ecore_evas_new("ews"...)) will all be software buffer windows + * automatic rendered to the backing store. + * + * @param x horizontal position of window, in pixels + * @param y vertical position of window, in pixels + * @param w The width of the canvas, in pixels + * @param h The height of the canvas, in pixels + * @return A new @c Ecore_Evas instance or @c NULL, on failure + * + * @see ecore_evas_ews_setup() + * @see ecore_evas_ews_ecore_evas_get() + * + * @since 1.1 + */ +EAPI Ecore_Evas *ecore_evas_ews_new(int x, int y, int w, int h); + + +/** + * Returns the backing store image object that represents the given + * window in EWS. + * @return The evas object of EWS backing store. + * + * @note This should not be modified anyhow, but may be helpful to + * determine stacking and geometry of it for window managers + * that decorate windows. + * + * @param ee The Ecore_Evas from which to get the backing store. + * @see ecore_evas_ews_manager_set() + * @see ecore_evas_ews_evas_get() + * @since 1.1 + */ +EAPI Evas_Object *ecore_evas_ews_backing_store_get(const Ecore_Evas *ee); + +/** + * Calls the window to be deleted (freed), but can let user decide to + * forbid it by using ecore_evas_callback_delete_request_set() + * + * @param ee The Ecore_Evas for which window will be deleted. + * @since 1.1 + */ +EAPI void ecore_evas_ews_delete_request(Ecore_Evas *ee); + +/** + * @brief Create an Evas image object with image data bound to an + * own, internal @c Ecore_Evas canvas wrapper + * + * @param ee_target @c Ecore_Evas to have the canvas receiving the new + * image object + * @return A handle to the new image object + * + * This will create a @b special Evas image object. The image's pixel + * array will get bound to the same image data array of an @b internal + * @b buffer @c Ecore_Evas canvas. The user of this function is, then, + * supposed to grab that @c Ecore_Evas handle, with + * ecore_evas_object_ecore_evas_get(), and use its canvas to render + * whichever contents he/she wants, @b independently of the contents + * of the canvas owned by @p ee_target. Those contents will reflect on + * the canvas of @p ee, though, being exactly the image data of the + * object returned by this function. + * + * This is a helper function for the scenario of one wanting to grab a + * buffer canvas' contents (with ecore_evas_buffer_pixels_get()) to be + * used on another canvas, for whichever reason. The most common goal + * of this setup is to @b save an image file with a whole canvas as + * contents, which could not be achieved by using an image file within + * the target canvas. + * + * @warning Always resize the returned image and its underlying + * @c Ecore_Evas handle accordingly. They must be kept with same sizes + * for things to work as expected. Also, you @b must issue + * @c evas_object_image_size_set() on the image with that same size. If + * the image is to be shown in a canvas bound to an engine different + * than the buffer one, then you must also set this image's @b fill + * properties accordingly. + * + * @note The image returned will always be bound to the + * @c EVAS_COLORSPACE_ARGB8888 colorspace, always. + * + * @note Use ecore_evas_object_evas_get() to grab the image's internal + * own canvas directly. + * + * @note If snapshoting this image's internal canvas, remember to + * flush its internal @c Ecore_Evas firstly, with + * ecore_evas_manual_render(). + */ +EAPI Evas_Object *ecore_evas_object_image_new(Ecore_Evas *ee_target); + +/** + * @brief Retrieve the internal @c Ecore_Evas handle of an image + * object created via ecore_evas_object_image_new() + * + * @param obj A handle to an image object created via + * ecore_evas_object_image_new() + * @return The underlying @c Ecore_Evas handle in @p obj + */ +EAPI Ecore_Evas *ecore_evas_object_ecore_evas_get(Evas_Object *obj); + +/** + * @brief Retrieve the canvas bound to the internal @c Ecore_Evas + * handle of an image object created via ecore_evas_object_image_new() + * + * @param obj A handle to an image object created via + * ecore_evas_object_image_new() + * @return A handle to @p obj's underlying @c Ecore_Evas's canvas + */ +EAPI Evas *ecore_evas_object_evas_get(Evas_Object *obj); + +EAPI Ecore_Evas *ecore_evas_software_gdi_new(Ecore_Win32_Window *parent, + int x, + int y, + int width, + int height); + +EAPI Ecore_Evas *ecore_evas_software_ddraw_new(Ecore_Win32_Window *parent, + int x, + int y, + int width, + int height); + +EAPI Ecore_Evas *ecore_evas_software_16_ddraw_new(Ecore_Win32_Window *parent, + int x, + int y, + int width, + int height); + +EAPI Ecore_Evas *ecore_evas_direct3d_new(Ecore_Win32_Window *parent, + int x, + int y, + int width, + int height); + +EAPI Ecore_Evas *ecore_evas_gl_glew_new(Ecore_Win32_Window *parent, + int x, + int y, + int width, + int height); + +EAPI Ecore_Win32_Window *ecore_evas_win32_window_get(const Ecore_Evas *ee); + +EAPI Ecore_Evas *ecore_evas_sdl_new(const char* name, int w, int h, int fullscreen, int hwsurface, int noframe, int alpha); +EAPI Ecore_Evas *ecore_evas_sdl16_new(const char* name, int w, int h, int fullscreen, int hwsurface, int noframe, int alpha); +EAPI Ecore_Evas *ecore_evas_gl_sdl_new(const char* name, int w, int h, int fullscreen, int noframe); + +EAPI Ecore_Evas *ecore_evas_software_wince_new(Ecore_WinCE_Window *parent, + int x, + int y, + int width, + int height); + +EAPI Ecore_Evas *ecore_evas_software_wince_fb_new(Ecore_WinCE_Window *parent, + int x, + int y, + int width, + int height); + +EAPI Ecore_Evas *ecore_evas_software_wince_gapi_new(Ecore_WinCE_Window *parent, + int x, + int y, + int width, + int height); + +EAPI Ecore_Evas *ecore_evas_software_wince_ddraw_new(Ecore_WinCE_Window *parent, + int x, + int y, + int width, + int height); + +EAPI Ecore_Evas *ecore_evas_software_wince_gdi_new(Ecore_WinCE_Window *parent, + int x, + int y, + int width, + int height); + +EAPI Ecore_WinCE_Window *ecore_evas_software_wince_window_get(const Ecore_Evas *ee); + +EAPI Ecore_Evas *ecore_evas_cocoa_new(Ecore_Cocoa_Window *parent, + int x, + int y, + int w, + int h); + +EAPI Ecore_Evas *ecore_evas_psl1ght_new(const char* name, int w, int h); + + +/* generic manipulation calls */ +/** + * @brief Get the engine name used by this Ecore_Evas(window). + * + * @param ee Ecore_Evas whose engine's name is desired. + * @return A string that can(usually) be used in ecore_evas_new() + * + * @see ecore_evas_free() + */ +EAPI const char *ecore_evas_engine_name_get(const Ecore_Evas *ee); +/** + * @brief Return the Ecore_Evas for this Evas + * + * @param e The Evas to get the Ecore_Evas from + * @return The Ecore_Evas that holds this Evas, or @c NULL if not held by one. + * + * @warning Only use on Evas' created with ecore evas! + */ +EAPI Ecore_Evas *ecore_evas_ecore_evas_get(const Evas *e); +/** + * @brief Free an Ecore_Evas + * + * @param ee The Ecore_Evas to free + * + * This frees up any memory used by the Ecore_Evas. + */ +EAPI void ecore_evas_free(Ecore_Evas *ee); +/** + * @brief Retrieve user data associated with an Ecore_Evas. + * + * @param ee The Ecore_Evas to retrieve the user data from. + * @param key The key which the user data to be retrieved is associated with. + * + * This function retrieves user specific data that has been stored within an + * Ecore_Evas structure with ecore_evas_data_set(). + * + * @returns @c NULL on error or no data found, A pointer to the user data on + * success. + * + * @see ecore_evas_data_set() + */ +EAPI void *ecore_evas_data_get(const Ecore_Evas *ee, const char *key); +/** + * @brief Store user data in an Ecore_Evas structure. + * + * @param ee The Ecore_Evas to store the user data in. + * @param key A unique string to associate the user data against. Cannot + * be NULL. + * @param data A pointer to the user data to store. + * + * This function associates the @p data with a @p key which is stored by + * the Ecore_Evas @p ee. Be aware that a call to ecore_evas_free() will + * not free any memory for the associated user data, this is the responsibility + * of the caller. + * + * @see ecore_evas_callback_pre_free_set() + * @see ecore_evas_free() + * @see ecore_evas_data_get() + */ +EAPI void ecore_evas_data_set(Ecore_Evas *ee, const char *key, const void *data); +/** + * Set a callback for Ecore_Evas resize events. + * @param ee The Ecore_Evas to set callbacks on + * @param func The function to call + + * A call to this function will set a callback on an Ecore_Evas, causing + * @p func to be called whenever @p ee is resized. + * + * @warning If and when this function is called depends on the underlying + * windowing system. + */ +EAPI void ecore_evas_callback_resize_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func); +/** + * Set a callback for Ecore_Evas move events. + * @param ee The Ecore_Evas to set callbacks on + * @param func The function to call + + * A call to this function will set a callback on an Ecore_Evas, causing + * @p func to be called whenever @p ee is moved. + * + * @warning If and when this function is called depends on the underlying + * windowing system. + */ +EAPI void ecore_evas_callback_move_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func); +/** + * Set a callback for Ecore_Evas show events. + * @param ee The Ecore_Evas to set callbacks on + * @param func The function to call + + * A call to this function will set a callback on an Ecore_Evas, causing + * @p func to be called whenever @p ee is shown. + * + * @warning If and when this function is called depends on the underlying + * windowing system. + */ +EAPI void ecore_evas_callback_show_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func); +/** + * Set a callback for Ecore_Evas hide events. + * @param ee The Ecore_Evas to set callbacks on + * @param func The function to call + + * A call to this function will set a callback on an Ecore_Evas, causing + * @p func to be called whenever @p ee is hidden. + * + * @warning If and when this function is called depends on the underlying + * windowing system. + */ +EAPI void ecore_evas_callback_hide_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func); +/** + * Set a callback for Ecore_Evas delete request events. + * @param ee The Ecore_Evas to set callbacks on + * @param func The function to call + + * A call to this function will set a callback on an Ecore_Evas, causing + * @p func to be called whenever @p ee gets a delete request. + * + * @warning If and when this function is called depends on the underlying + * windowing system. + */ +EAPI void ecore_evas_callback_delete_request_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func); +/** + * Set a callback for Ecore_Evas destroy events. + * @param ee The Ecore_Evas to set callbacks on + * @param func The function to call + + * A call to this function will set a callback on an Ecore_Evas, causing + * @p func to be called whenever @p ee is destroyed. + * + * @warning If and when this function is called depends on the underlying + * windowing system. + */ +EAPI void ecore_evas_callback_destroy_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func); +/** + * Set a callback for Ecore_Evas focus in events. + * @param ee The Ecore_Evas to set callbacks on + * @param func The function to call + + * A call to this function will set a callback on an Ecore_Evas, causing + * @p func to be called whenever @p ee gets focus. + * + * @warning If and when this function is called depends on the underlying + * windowing system. + */ +EAPI void ecore_evas_callback_focus_in_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func); +/** + * Set a callback for Ecore_Evas focus out events. + * @param ee The Ecore_Evas to set callbacks on + * @param func The function to call + + * A call to this function will set a callback on an Ecore_Evas, causing + * @p func to be called whenever @p ee loses focus. + * + * @warning If and when this function is called depends on the underlying + * windowing system. + */ +EAPI void ecore_evas_callback_focus_out_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func); +/** + * Set a callback for Ecore_Evas sticky events. + * @param ee The Ecore_Evas to set callbacks on + * @param func The function to call + + * A call to this function will set a callback on an Ecore_Evas, causing + * @p func to be called whenever @p ee becomes sticky. + * + * @warning If and when this function is called depends on the underlying + * windowing system. + */ +EAPI void ecore_evas_callback_sticky_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func); +/** + * Set a callback for Ecore_Evas un-sticky events. + * @param ee The Ecore_Evas to set callbacks on + * @param func The function to call + + * A call to this function will set a callback on an Ecore_Evas, causing + * @p func to be called whenever @p ee becomes un-sticky. + * + * @warning If and when this function is called depends on the underlying + * windowing system. + */ +EAPI void ecore_evas_callback_unsticky_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func); +/** + * Set a callback for Ecore_Evas mouse in events. + * @param ee The Ecore_Evas to set callbacks on + * @param func The function to call + + * A call to this function will set a callback on an Ecore_Evas, causing + * @p func to be called whenever the mouse enters @p ee. + * + * @warning If and when this function is called depends on the underlying + * windowing system. + */ +EAPI void ecore_evas_callback_mouse_in_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func); +/** + * Set a callback for Ecore_Evas mouse out events. + * @param ee The Ecore_Evas to set callbacks on + * @param func The function to call + + * A call to this function will set a callback on an Ecore_Evas, causing + * @p func to be called whenever the mouse leaves @p ee. + * + * @warning If and when this function is called depends on the underlying + * windowing system. + */ +EAPI void ecore_evas_callback_mouse_out_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func); +/** + * Set a callback for Ecore_Evas pre render events. + * @param ee The Ecore_Evas to set callbacks on + * @param func The function to call + + * A call to this function will set a callback on an Ecore_Evas, causing + * @p func to be called just before the evas in @p ee is rendered. + * + * @warning If and when this function is called depends on the underlying + * windowing system. + */ +EAPI void ecore_evas_callback_pre_render_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func); +/** + * Set a callback for Ecore_Evas mouse post render events. + * @param ee The Ecore_Evas to set callbacks on + * @param func The function to call + + * A call to this function will set a callback on an Ecore_Evas, causing + * @p func to be called just after the evas in @p ee is rendered. + * + * @warning If and when this function is called depends on the underlying + * windowing system. + */ +EAPI void ecore_evas_callback_post_render_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func); +/** + * Set a callback for Ecore_Evas pre-free event. + * @param ee The Ecore_Evas to set callbacks on + * @param func The function to call + * + * A call to this function will set a callback on an Ecore_Evas, causing + * @p func to be called just before the instance @p ee is freed. + * + * @warning If and when this function is called depends on the underlying + * windowing system. + */ +EAPI void ecore_evas_callback_pre_free_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func); +/** + * Set a callback for Ecore_Evas state changes. + * @param ee The Ecore_Evas to set callbacks on + * @param func The function to call + + * A call to this function will set a callback on an Ecore_Evas, causing + * @p func to be called whenever @p ee changes state. + * + * @since 1.2 + * @warning If and when this function is called depends on the underlying + * windowing system. + */ +EAPI void ecore_evas_callback_state_change_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func); + +/** + * Get an Ecore_Evas's Evas + * @param ee The Ecore_Evas whose Evas you wish to get + * @return The Evas wrapped by @p ee + * + * This function returns the Evas contained within @p ee. + */ +EAPI Evas *ecore_evas_get(const Ecore_Evas *ee); + +/** + * Provide Managed move co-ordinates for an Ecore_Evas + * @param ee The Ecore_Evas to move + * @param x The x coordinate to set as the managed location + * @param y The y coordinate to set as the managed location + * + * This sets the managed geometry position of the @p ee to (@p x, @p y) + */ +EAPI void ecore_evas_managed_move(Ecore_Evas *ee, int x, int y); + +/** + * Set whether an Ecore_Evas is shaped or not. + * + * @param ee The Ecore_Evas to shape. + * @param shaped @c EINA_TRUE to shape, @c EINA_FALSE to not. + * + * This function allows one to make an Ecore_Evas shaped to the contents of the + * evas. If @p shaped is @c EINA_TRUE, @p ee will be transparent in parts of + * the evas that contain no objects. If @p shaped is @c EINA_FALSE, then @p ee + * will be rectangular, and parts with no data will show random framebuffer + * artifacting. For non-shaped Ecore_Evases, it is recommended to cover the + * entire evas with a background object. + */ +EAPI void ecore_evas_shaped_set(Ecore_Evas *ee, Eina_Bool shaped); + +/** + * Query whether an Ecore_Evas is shaped or not. + * + * @param ee The Ecore_Evas to query. + * @return @c EINA_TRUE if shaped, @c EINA_FALSE if not. + * + * This function returns @c EINA_TRUE if @p ee is shaped, and @c EINA_FALSE if not. + */ +EAPI Eina_Bool ecore_evas_shaped_get(const Ecore_Evas *ee); +/** + * @brief Show an Ecore_Evas' window + * + * @param ee The Ecore_Evas to show. + * + * This function makes @p ee visible. + */ +EAPI void ecore_evas_show(Ecore_Evas *ee); +/** + * @brief Hide an Ecore_Evas' window + * + * @param ee The Ecore_Evas to hide. + * + * This function makes @p ee hidden(not visible). + */ +EAPI void ecore_evas_hide(Ecore_Evas *ee); + +/** + * Activate (set focus to, via the window manager) an Ecore_Evas' window. + * @param ee The Ecore_Evas to activate. + * + * This functions activates the Ecore_Evas. + */ +EAPI void ecore_evas_activate(Ecore_Evas *ee); + + +/** + * Set the minimum size of a given @c Ecore_Evas window + * + * @param ee An @c Ecore_Evas window's handle + * @param w The minimum width + * @param h The minimum height + * + * This function sets the minimum size of @p ee to be @p w x @p h. + * One won't be able to resize that window to dimensions smaller than + * the ones set. + * + * @note When base sizes are set, via ecore_evas_size_base_set(), + * they'll be used to calculate a window's minimum size, instead of + * those set by this function. + * + * @see ecore_evas_size_min_get() + */ +EAPI void ecore_evas_size_min_set(Ecore_Evas *ee, int w, int h); + +/** + * Get the minimum size set for a given @c Ecore_Evas window + * + * @param ee An @c Ecore_Evas window's handle + * @param w A pointer to an int to place the minimum width in. + * @param h A pointer to an int to place the minimum height in. + * + * @note Use @c NULL pointers on the size components you're not + * interested in: they'll be ignored by the function. + * + * @see ecore_evas_size_min_set() for more details + */ +EAPI void ecore_evas_size_min_get(const Ecore_Evas *ee, int *w, int *h); + +/** + * Set the maximum size of a given @c Ecore_Evas window + * + * @param ee An @c Ecore_Evas window's handle + * @param w The maximum width + * @param h The maximum height + * + * This function sets the maximum size of @p ee to be @p w x @p h. + * One won't be able to resize that window to dimensions bigger than + * the ones set. + * + * @see ecore_evas_size_max_get() + */ +EAPI void ecore_evas_size_max_set(Ecore_Evas *ee, int w, int h); + +/** + * Get the maximum size set for a given @c Ecore_Evas window + * + * @param ee An @c Ecore_Evas window's handle + * @param w A pointer to an int to place the maximum width in. + * @param h A pointer to an int to place the maximum height in. + * + * @note Use @c NULL pointers on the size components you're not + * interested in: they'll be ignored by the function. + * + * @see ecore_evas_size_max_set() for more details + */ +EAPI void ecore_evas_size_max_get(const Ecore_Evas *ee, int *w, int *h); + +/** + * Set the base size for a given @c Ecore_Evas window + * + * @param ee An @c Ecore_Evas window's handle + * @param w The base width + * @param h The base height + * + * This function sets the @b base size of @p ee to be @p w x @p h. + * When base sizes are set, they'll be used to calculate a window's + * @b minimum size, instead of those set by ecore_evas_size_min_get(). + * + * @see ecore_evas_size_base_get() + */ +EAPI void ecore_evas_size_base_set(Ecore_Evas *ee, int w, int h); + +/** + * Get the base size set for a given @c Ecore_Evas window + * + * @param ee An @c Ecore_Evas window's handle + * @param w A pointer to an int to place the base width in. + * @param h A pointer to an int to place the base height in. + * + * @note Use @c NULL pointers on the size components you're not + * interested in: they'll be ignored by the function. + * + * @see ecore_evas_size_base_set() for more details + */ +EAPI void ecore_evas_size_base_get(const Ecore_Evas *ee, int *w, int *h); + +/** + * Set the "size step" for a given @c Ecore_Evas window + * + * @param ee An @c Ecore_Evas window's handle + * @param w The step width + * @param h The step height + * + * This function sets the size steps of @p ee to be @p w x @p h. This + * limits the size of this @c Ecore_Evas window to be @b always an + * integer multiple of the step size, for each axis. + */ +EAPI void ecore_evas_size_step_set(Ecore_Evas *ee, int w, int h); + +/** + * Get the "size step" set for a given @c Ecore_Evas window + * + * @param ee An @c Ecore_Evas window's handle + * @param w A pointer to an int to place the step width in. + * @param h A pointer to an int to place the step height in. + * + * @note Use @c NULL pointers on the size components you're not + * interested in: they'll be ignored by the function. + * + * @see ecore_evas_size_base_set() for more details + */ +EAPI void ecore_evas_size_step_get(const Ecore_Evas *ee, int *w, int *h); + +/** + * @brief Set the cursor of an Ecore_Evas. + * + * @param ee The Ecore_Evas + * @param file The path to an image file for the cursor. + * @param layer The layer in which the cursor will appear. + * @param hot_x The x coordinate of the cursor's hot spot. + * @param hot_y The y coordinate of the cursor's hot spot. + * + * This function makes the mouse cursor over @p ee be the image specified by + * @p file. The actual point within the image that the mouse is at is specified + * by @p hot_x and @p hot_y, which are coordinates with respect to the top left + * corner of the cursor image. + * + * @note This function creates an object from the image and uses + * ecore_evas_object_cursor_set(). + * + * @see ecore_evas_object_cursor_set() + */ +EAPI void ecore_evas_cursor_set(Ecore_Evas *ee, const char *file, int layer, int hot_x, int hot_y); +/** + * @brief Get information about an Ecore_Evas' cursor + * + * @param ee The Ecore_Evas to set + * @param obj A pointer to an Evas_Object to place the cursor Evas_Object. + * @param layer A pointer to an int to place the cursor's layer in. + * @param hot_x A pointer to an int to place the cursor's hot_x coordinate in. + * @param hot_y A pointer to an int to place the cursor's hot_y coordinate in. + * + * This function queries information about an Ecore_Evas' cursor. + * + * @see ecore_evas_cursor_set() + * @see ecore_evas_object_cursor_set() + */ +EAPI void ecore_evas_cursor_get(const Ecore_Evas *ee, Evas_Object **obj, int *layer, int *hot_x, int *hot_y); +/** + * @brief Set the cursor of an Ecore_Evas + * + * @param ee The Ecore_Evas + * + * @param obj The Evas_Object which will be the cursor. + * @param layer The layer in which the cursor will appear. + * @param hot_x The x coordinate of the cursor's hot spot. + * @param hot_y The y coordinate of the cursor's hot spot. + * + * This function makes the mouse cursor over @p ee be the object specified by + * @p obj. The actual point within the object that the mouse is at is specified + * by @p hot_x and @p hot_y, which are coordinates with respect to the top left + * corner of the cursor object. + * + * @see ecore_evas_cursor_set() + */ +EAPI void ecore_evas_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y); + +/** + * Tell the WM whether or not to ignore an Ecore_Evas' window + * + * @param ee The Ecore_Evas. + * @param on @c EINA_TRUE to ignore, @c EINA_FALSE to not. + * + * This function causes the window manager to ignore @p ee if @p on is + * @c EINA_TRUE, or not ignore @p ee if @p on is @c EINA_FALSE. + */ +EAPI void ecore_evas_override_set(Ecore_Evas *ee, Eina_Bool on); + +/** + * Query whether an Ecore_Evas' window is overridden or not + * + * @param ee The Ecore_Evas to set. + * @return @c EINA_TRUE if @p ee is overridden, @c EINA_FALSE if not. + */ +EAPI Eina_Bool ecore_evas_override_get(const Ecore_Evas *ee); + +/** + * Set whether or not an Ecore_Evas' window should avoid damage + * + * @param ee The Ecore_Evas + * @param on The type of the damage management + * + * This option causes updates of the Ecore_Evas to be done on a pixmap, and + * then copied to the window, or the pixmap used directly on the window, + * depending on the setting. Possible options are: + * + * @li @ref ECORE_EVAS_AVOID_DAMAGE_NONE - every expose event triggers a new + * damage and consequently render of the affected area. The rendering of things + * happens directly on the window; + * + * @li @ref ECORE_EVAS_AVOID_DAMAGE_EXPOSE - there's a pixmap where everything + * is rendered into, and then copied to the window. On expose events, there's + * no need to render things again, just to copy the exposed region to the + * window; + * + * @li @ref ECORE_EVAS_AVOID_DAMAGE_BUILT_IN - there's the same pixmap as the + * previous one, but it is set as a "background pixmap" of the window. The + * rendered things appear directly on the window, with no need to copy + * anything, but would stay stored on the pixmap, so there's no need to render + * things again on expose events. This option can be faster than the previous + * one, but may lead to artifacts during resize of the window. + */ +EAPI void ecore_evas_avoid_damage_set(Ecore_Evas *ee, Ecore_Evas_Avoid_Damage_Type on); + +/** + * Query whether an Ecore_Evas' window avoids damage or not + * @param ee The Ecore_Evas to set + * @return The type of the damage management + * + */ +EAPI Ecore_Evas_Avoid_Damage_Type ecore_evas_avoid_damage_get(const Ecore_Evas *ee); + +/** + * Set the withdrawn state of an Ecore_Evas' window. + * @param ee The Ecore_Evas whose window's withdrawn state is set. + * @param withdrawn The Ecore_Evas window's new withdrawn state. + * + */ +EAPI void ecore_evas_withdrawn_set(Ecore_Evas *ee, Eina_Bool withdrawn); + +/** + * Returns the withdrawn state of an Ecore_Evas' window. + * @param ee The Ecore_Evas whose window's withdrawn state is returned. + * @return The Ecore_Evas window's withdrawn state. + * + */ +EAPI Eina_Bool ecore_evas_withdrawn_get(const Ecore_Evas *ee); + +/** + * Set the sticky state of an Ecore_Evas window. + * + * @param ee The Ecore_Evas whose window's sticky state is set. + * @param sticky The Ecore_Evas window's new sticky state. + * + */ +EAPI void ecore_evas_sticky_set(Ecore_Evas *ee, Eina_Bool sticky); + +/** + * Returns the sticky state of an Ecore_Evas' window. + * + * @param ee The Ecore_Evas whose window's sticky state is returned. + * @return The Ecore_Evas window's sticky state. + * + */ +EAPI Eina_Bool ecore_evas_sticky_get(const Ecore_Evas *ee); +EAPI void ecore_evas_manual_render_set(Ecore_Evas *ee, Eina_Bool manual_render); +EAPI Eina_Bool ecore_evas_manual_render_get(const Ecore_Evas *ee); + +/** + * @brief Registers an @c Ecore_Evas to receive events through ecore_input_evas. + * + * @param ee The @c Ecore_Evas handle. + * + * This function calls ecore_event_window_register() with the @p ee as its @c + * id argument, @c window argument, and uses its @c Evas too. It is useful when + * no @c window information is available on a given @c Ecore_Evas backend. + * + * @see ecore_evas_input_event_unregister() + * @since 1.1 + */ +EAPI void ecore_evas_input_event_register(Ecore_Evas *ee); +/** + * @brief Unregisters an @c Ecore_Evas receiving events through ecore_input_evas. + * + * @param ee The @c Ecore_Evas handle. + * + * @see ecore_evas_input_event_register() + * @since 1.1 + */ +EAPI void ecore_evas_input_event_unregister(Ecore_Evas *ee); + +/** + * @brief Force immediate rendering on a given @c Ecore_Evas window + * + * @param ee An @c Ecore_Evas handle + * + * Use this call to forcefully flush the @p ee's canvas rendering + * pipeline, thus bring its window to an up to date state. + */ +EAPI void ecore_evas_manual_render(Ecore_Evas *ee); +EAPI void ecore_evas_comp_sync_set(Ecore_Evas *ee, Eina_Bool do_sync); +EAPI Eina_Bool ecore_evas_comp_sync_get(const Ecore_Evas *ee); + +/** + * @brief Get geometry of screen associated with this Ecore_Evas. + * + * @param ee The Ecore_Evas whose window's to query container screen geometry. + * @param x where to return the horizontal offset value. May be @c NULL. + * @param y where to return the vertical offset value. May be @c NULL. + * @param w where to return the width value. May be @c NULL. + * @param h where to return the height value. May be @c NULL. + * + * @since 1.1 + */ +EAPI void ecore_evas_screen_geometry_get(const Ecore_Evas *ee, int *x, int *y, int *w, int *h); + +/** + * @brief Get the dpi of the screen the Ecore_Evas is primarily on. + * + * @param ee The Ecore_Evas whose window's to query. + * @param xdpi Pointer to integer to store horizontal DPI. May be @c NULL. + * @param ydpi Pointer to integer to store vertical DPI. May be @c NULL. + * + * @since 1.7 + */ +EAPI void ecore_evas_screen_dpi_get(const Ecore_Evas *ee, int *xdpi, int *ydpi); + +EAPI void ecore_evas_draw_frame_set(Ecore_Evas *ee, Eina_Bool draw_frame); +EAPI Eina_Bool ecore_evas_draw_frame_get(const Ecore_Evas *ee); + +/** + * @brief Associate the given object to this ecore evas. + * + * @param ee The Ecore_Evas to associate to @a obj + * @param obj The object to associate to @a ee + * @param flags The association flags. + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * Association means that operations on one will affect the other, for + * example moving the object will move the window, resize the object will + * also affect the ecore evas window, hide and show applies as well. + * + * This is meant to simplify development, since you often need to associate + * these events with your "base" objects, background or bottom-most object. + * + * Be aware that some methods might not be what you would like, deleting + * either the window or the object will delete the other. If you want to + * change that behavior, let's say to hide window when it's closed, you + * must use ecore_evas_callback_delete_request_set() and set your own code, + * like ecore_evas_hide(). Just remember that if you override delete_request + * and still want to delete the window/object, you must do that yourself. + * + * Since we now define delete_request, deleting windows will not quit + * main loop, if you wish to do so, you should listen for EVAS_CALLBACK_FREE + * on the object, that way you get notified and you can call + * ecore_main_loop_quit(). + * + * Flags can be OR'ed of: + * @li ECORE_EVAS_OBJECT_ASSOCIATE_BASE (or 0): to listen to basic events + * like delete, resize and move, but no stacking or layer are used. + * @li ECORE_EVAS_OBJECT_ASSOCIATE_STACK: stacking operations will act + * on the Ecore_Evas, not the object. So evas_object_raise() will + * call ecore_evas_raise(). Relative operations (stack_above, stack_below) + * are still not implemented. + * @li ECORE_EVAS_OBJECT_ASSOCIATE_LAYER: stacking operations will act + * on the Ecore_Evas, not the object. So evas_object_layer_set() will + * call ecore_evas_layer_set(). + * @li ECORE_EVAS_OBJECT_ASSOCIATE_DEL: the object delete will delete the + * ecore_evas as well as delete_requests on the ecore_evas will delete + * etc. + */ +EAPI Eina_Bool ecore_evas_object_associate(Ecore_Evas *ee, Evas_Object *obj, Ecore_Evas_Object_Associate_Flags flags); +/** + * @brief Cancel the association set with ecore_evas_object_associate(). + * + * @param ee The Ecore_Evas to dissociate from @a obj + * @param obj The object to dissociate from @a ee + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool ecore_evas_object_dissociate(Ecore_Evas *ee, Evas_Object *obj); +/** + * @brief Get the object associated with @p ee + * + * @param ee The Ecore_Evas to get the object from. + * @return The associated object, or @c NULL if there is no associated object. + */ +EAPI Evas_Object *ecore_evas_object_associate_get(const Ecore_Evas *ee); + +/* helper function to be used with ECORE_GETOPT_CALLBACK_*() */ +EAPI unsigned char ecore_getopt_callback_ecore_evas_list_engines(const Ecore_Getopt *parser, const Ecore_Getopt_Desc *desc, const char *str, void *data, Ecore_Getopt_Value *storage); + +/** + * @brief Get a list of all the ecore_evases. + * + * @return A list of ecore_evases. + * + * The returned list of ecore evases is only valid until the canvases are + * destroyed (and should not be cached for instance). The list can be freed by + * just deleting the list. + */ +EAPI Eina_List *ecore_evas_ecore_evas_list_get(void); + +/* specific calls to an x11 environment ecore_evas */ +EAPI void ecore_evas_x11_leader_set(Ecore_Evas *ee, Ecore_X_Window win); +EAPI Ecore_X_Window ecore_evas_x11_leader_get(Ecore_Evas *ee); +EAPI void ecore_evas_x11_leader_default_set(Ecore_Evas *ee); +EAPI void ecore_evas_x11_shape_input_rectangle_set(Ecore_Evas *ee, int x, int y, int w, int h); +EAPI void ecore_evas_x11_shape_input_rectangle_add(Ecore_Evas *ee, int x, int y, int w, int h); +EAPI void ecore_evas_x11_shape_input_rectangle_subtract(Ecore_Evas *ee, int x, int y, int w, int h); +EAPI void ecore_evas_x11_shape_input_empty(Ecore_Evas *ee); +EAPI void ecore_evas_x11_shape_input_reset(Ecore_Evas *ee); +EAPI void ecore_evas_x11_shape_input_apply(Ecore_Evas *ee); + +/** + * @defgroup Ecore_Evas_Ews Ecore_Evas Single Process Windowing System. + * + * These are global scope functions to manage the EWS to be used by + * ecore_evas_ews_new(). + * + * @since 1.1 + * @{ + */ + +/** + * Sets the engine to be used by the backing store engine. + * + * @param engine The engine to be set. + * @param options The options of the engine to be set. + * @return @c EINA_TRUE on success, @c EINA_FALSE if ews is already in use. + * @since 1.1 + */ +EAPI Eina_Bool ecore_evas_ews_engine_set(const char *engine, const char *options); + +/** + * Reconfigure the backing store used. + * + * @param x The X coordinate to be used. + * @param y The Y coordinate to be used. + * @param w The width of the Ecore_Evas to setup. + * @param h The height of the Ecore_Evas to setup. + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * @since 1.1 + */ +EAPI Eina_Bool ecore_evas_ews_setup(int x, int y, int w, int h); + +/** + * Return the internal backing store in use. + * + * @return The internal backing store in use. + * @note this will forced it to be created, making future calls to + * ecore_evas_ews_engine_set() void. + * + * @see ecore_evas_ews_evas_get() + * @since 1.1 + */ +EAPI Ecore_Evas *ecore_evas_ews_ecore_evas_get(void); + +/** + * Return the internal backing store in use. + * + * @return The internal backing store in use. + * @note this will forced it to be created, making future calls to + * ecore_evas_ews_engine_set() void. + * + * @see ecore_evas_ews_ecore_evas_get() + * @since 1.1 + */ +EAPI Evas *ecore_evas_ews_evas_get(void); + +/** + * Get the current background. + */ +EAPI Evas_Object *ecore_evas_ews_background_get(void); + +/** + * Set the current background, must be created at evas ecore_evas_ews_evas_get() + * + * It will be kept at lowest layer (EVAS_LAYER_MIN) and below + * everything else. You can set any object, default is a black + * rectangle. + * + * @note previous object will be deleted! + * @param o The Evas_Object for which to set the background. + */ +EAPI void ecore_evas_ews_background_set(Evas_Object *o); + +/** + * Return all Ecore_Evas* created by EWS. + * + * @return An eina list of Ecore_evases. + e @note Do not change the returned list or its contents. + * @since 1.1 + */ +EAPI const Eina_List *ecore_evas_ews_children_get(void); + +/** + * Set the identifier of the manager taking care of internal windows. + * + * The ECORE_EVAS_EWS_EVENT_MANAGER_CHANGE event is issued. Consider + * handling it to know if you should stop handling events yourself + * (ie: another manager took over) + * + * @param manager any unique identifier address. + * + * @see ecore_evas_ews_manager_get() + * @since 1.1 + */ +EAPI void ecore_evas_ews_manager_set(const void *manager); + +/** + * Get the identifier of the manager taking care of internal windows. + * + * @return the value set by ecore_evas_ews_manager_set() + * @since 1.1 + */ +EAPI const void *ecore_evas_ews_manager_get(void); + +EAPI extern int ECORE_EVAS_EWS_EVENT_MANAGER_CHANGE; /**< manager was changed @since 1.1 */ +EAPI extern int ECORE_EVAS_EWS_EVENT_ADD; /**< window was created @since 1.1 */ +EAPI extern int ECORE_EVAS_EWS_EVENT_DEL; /**< window was deleted, pointer is already invalid but may be used as reference for further cleanup work. @since 1.1 */ +EAPI extern int ECORE_EVAS_EWS_EVENT_RESIZE; /**< window was resized @since 1.1 */ +EAPI extern int ECORE_EVAS_EWS_EVENT_MOVE; /**< window was moved @since 1.1 */ +EAPI extern int ECORE_EVAS_EWS_EVENT_SHOW; /**< window become visible @since 1.1 */ +EAPI extern int ECORE_EVAS_EWS_EVENT_HIDE; /**< window become hidden @since 1.1 */ +EAPI extern int ECORE_EVAS_EWS_EVENT_FOCUS; /**< window was focused @since 1.1 */ +EAPI extern int ECORE_EVAS_EWS_EVENT_UNFOCUS; /**< window lost focus @since 1.1 */ +EAPI extern int ECORE_EVAS_EWS_EVENT_RAISE; /**< window was raised @since 1.1 */ +EAPI extern int ECORE_EVAS_EWS_EVENT_LOWER; /**< window was lowered @since 1.1 */ +EAPI extern int ECORE_EVAS_EWS_EVENT_ACTIVATE; /**< window was activated @since 1.1 */ + +EAPI extern int ECORE_EVAS_EWS_EVENT_ICONIFIED_CHANGE; /**< window minimized/iconified changed @since 1.1 */ +EAPI extern int ECORE_EVAS_EWS_EVENT_MAXIMIZED_CHANGE; /**< window maximized changed @since 1.1 */ +EAPI extern int ECORE_EVAS_EWS_EVENT_LAYER_CHANGE; /**< window layer changed @since 1.1 */ +EAPI extern int ECORE_EVAS_EWS_EVENT_FULLSCREEN_CHANGE; /**< window fullscreen changed @since 1.1 */ +EAPI extern int ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE; /**< some other window property changed (title, name, class, alpha, transparent, shaped...) @since 1.1 */ + +/** + * @} + */ + +/** + * @defgroup Ecore_Evas_Extn External plug/socket infrastructure to remote canvases + * + * These functions allow 1 process to create a "socket" was pluged into which another + * process can create a "plug" remotely to plug into. + * Socket can provides content for several plugs. + * This is best for small sized objects (about the size range + * of a small icon up to a few large icons). Sine the plug is actually an + * image object, you can fetch the pixel data + * + * @since 1.2 + * @{ + */ + +EAPI extern int ECORE_EVAS_EXTN_CLIENT_ADD; /**< this event is received when a plug has connected to an extn socket @since 1.2 */ +EAPI extern int ECORE_EVAS_EXTN_CLIENT_DEL; /**< this event is received when a plug has disconnected from an extn socket @since 1.2 */ + +/** + * @brief Create a new Ecore_Evas canvas for the new external ecore evas socket + * + * @param w The width of the canvas, in pixels + * @param h The height of the canvas, in pixels + * @return A new @c Ecore_Evas instance or @c NULL, on failure + * + * This creates a new extn_socket canvas wrapper, with image data array + * @b bound to the ARGB format, 8 bits per pixel. + * + * If creation is successful, an Ecore_Evas handle is returned or @c NULL if + * creation fails. Also focus, show, hide etc. callbacks will also be called + * if the plug object is shown, or already visible on connect, or if it is + * hidden later, focused or unfocused. + * + * This function has to be flowed by ecore_evas_extn_socket_listen(), + * for starting ecore ipc service. + * + * @code + * Eina_Bool res = EINA_FALSE; + * Ecore_Evas *ee = ecore_evas_extn_socket_new(1, 1); + * + * res = ecore_evas_extn_socket_listen("svcname", 1, EINA_FALSE); + * if (!res) return; + * ecore_evas_resize(ee, 240, 400); + * @endcode + * + * or + * + * @code + * Eina_Bool res = EINA_FALSE; + * Ecore_Evas *ee = ecore_evas_extn_socket_new(240, 400); + * + * res = ecore_evas_extn_socket_listen("svcname", 1, EINA_FALSE); + * if (!res) return; + * @endcode + * + * When a client(plug) connects, you will get the ECORE_EVAS_EXTN_CLIENT_ADD event + * in the ecore event queue, with event_info being the image object pointer + * passed as a void pointer. When a client disconnects you will get the + * ECORE_EVAS_EXTN_CLIENT_DEL event. + * + * You can set up event handles for these events as follows: + * + * @code + * static void client_add_cb(void *data, int event, void *event_info) + * { + * Evas_Object *obj = event_info; + * printf("client added to image object %p\n", obj); + * evas_object_show(obj); + * } + * + * static void client_del_cb(void *data, int event, void *event_info) + * { + * Evas_Object *obj = event_info; + * printf("client deleted from image object %p\n", obj); + * evas_object_hide(obj); + * } + * + * void setup(void) + * { + * ecore_event_handler_add(ECORE_EVAS_EXTN_CLIENT_ADD, + * client_add_cb, NULL); + * ecore_event_handler_add(ECORE_EVAS_EXTN_CLIENT_DEL, + * client_del_cb, NULL); + * } + * @endcode + * + * Note that events come in later after the event happened. You may want to be + * careful as data structures you had associated with the image object + * may have been freed after deleting, but the object may still be around + * awating cleanup and thus still be valid.You can change the size with something like: + * + * @see ecore_evas_extn_socket_listen() + * @see ecore_evas_extn_plug_new() + * @see ecore_evas_extn_plug_object_data_lock() + * @see ecore_evas_extn_plug_object_data_unlock() + * + * @since 1.2 + */ +EAPI Ecore_Evas *ecore_evas_extn_socket_new(int w, int h); + +/** + * @brief Create a socket to provide the service for external ecore evas + * socket. + * + * @param ee The Ecore_Evas. + * @param svcname The name of the service to be advertised. ensure that it is + * unique (when combined with @p svcnum) otherwise creation may fail. + * @param svcnum A number (any value, @c 0 being the common default) to + * differentiate multiple instances of services with the same name. + * @param svcsys A boolean that if true, specifies to create a system-wide + * service all users can connect to, otherwise the service is private to the + * user ide that created the service. + * @return @c EINA_TRUE if creation is successful, @c EINA_FALSE if it does + * not. + * + * This creates socket specified by @p svcname, @p svcnum and @p svcsys. If + * creation is successful, @c EINA_TRUE is returned or @c EINA_FALSE if + * creation fails. + * + * @see ecore_evas_extn_socket_new() + * @see ecore_evas_extn_plug_new() + * @see ecore_evas_extn_plug_object_data_lock() + * @see ecore_evas_extn_plug_object_data_unlock() + * + * @since 1.2 + */ +EAPI Eina_Bool ecore_evas_extn_socket_listen(Ecore_Evas *ee, const char *svcname, int svcnum, Eina_Bool svcsys); + +/** + * @brief Lock the pixel data so the socket cannot change it + * + * @param obj The image object returned by ecore_evas_extn_plug_new() to lock + * + * You may need to get the image pixel data with evas_object_image_data_get() + * from the image object, but need to ensure that it does not change while + * you are using the data. This function lets you set an advisory lock on the + * image data so the external plug process will not render to it or alter it. + * + * You should only hold the lock for just as long as you need to read out the + * image data or otherwise deal with it, and then unlock it with + * ecore_evas_extn_plug_object_data_unlock(). Keeping a lock over more than + * 1 iteration of the main ecore loop will be problematic, so avoid it. Also + * forgetting to unlock may cause the socket process to freeze and thus create + * odd behavior. + * + * @see ecore_evas_extn_plug_new() + * @see ecore_evas_extn_plug_object_data_unlock() + * + * @since 1.2 + */ +EAPI void ecore_evas_extn_plug_object_data_lock(Evas_Object *obj); + +/** + * @brief Unlock the pixel data so the socket can change it again. + * + * @param obj The image object returned by ecore_evas_extn_plug_new() to unlock + * + * This unlocks after an advisor lock has been taken by + * ecore_evas_extn_plug_object_data_lock(). + * + * @see ecore_evas_extn_plug_new() + * @see ecore_evas_extn_plug_object_data_lock() + * + * @since 1.2 + */ +EAPI void ecore_evas_extn_plug_object_data_unlock(Evas_Object *obj); + +/** + * @brief Create a new external ecore evas plug + * + * @param ee_target The Ecore_Evas containing the canvas in which the new image object will live. + * @return An evas image object that will contain the image output of a socket. + * + * This creates an image object that will contain the output of another + * processes socket canvas when it connects. All input will be sent back to + * this process as well, effectively swallowing or placing the socket process + * in the canvas of the plug process in place of the image object. The image + * object by default is created to be filled (equivalent of + * evas_object_image_filled_add() on creation) so image content will scale + * to fill the image unless otherwise reconfigured. The Ecore_Evas size + * of the plug is the master size and determines size in pixels of the + * plug canvas. You can change the size with something like: + * + * @code + * Eina_Bool res = EINA_FALSE; + * Evas_Object *obj = ecore_evas_extn_plug_new(ee); + * + * res = ecore_evas_extn_plug_connect("svcname", 1, EINA_FALSE); + * if (!res) return; + * ecore_evas_resize(ee, 240, 400); + * @endcode + * + * @see ecore_evas_extn_socket_new() + * @see ecore_evas_extn_plug_connect() + * @since 1.2 + */ +EAPI Evas_Object *ecore_evas_extn_plug_new(Ecore_Evas *ee_target); + +/** + * @brief Connect an external ecore evas plug to service provided by external + * ecore evas socket. + * + * @param obj The Ecore_Evas containing the canvas in which the new image + * object will live. + * @param svcname The service name to connect to set up by the socket. + * @param svcnum The service number to connect to (set up by socket). + * @param svcsys Boolean to set if the service is a system one or not (set up + * by socket). + * @return @c EINA_TRUE if creation is successful, @c EINA_FALSE if it does + * not. + * + * @see ecore_evas_extn_plug_new() + * + * @since 1.2 + */ +EAPI Eina_Bool ecore_evas_extn_plug_connect(Evas_Object *obj, const char *svcname, int svcnum, Eina_Bool svcsys); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/ecore_evas/Makefile.am b/src/lib/ecore_evas/Makefile.am new file mode 100644 index 0000000..cd7f37b --- /dev/null +++ b/src/lib/ecore_evas/Makefile.am @@ -0,0 +1,160 @@ +MAINTAINERCLEANFILES = Makefile.in + +if BUILD_ECORE_X +ECORE_X_INC = -I$(top_srcdir)/src/lib/ecore_x @x_cflags@ +ECORE_X_LIB = $(top_builddir)/src/lib/ecore_x/libecore_x.la @x_libs@ +else +ECORE_X_INC = +ECORE_X_LIB = +endif + +if BUILD_ECORE_FB +ECORE_FB_INC = -I$(top_srcdir)/src/lib/ecore_fb +ECORE_FB_LIB = $(top_builddir)/src/lib/ecore_fb/libecore_fb.la +else +ECORE_FB_INC = +ECORE_FB_LIB = +endif + +if BUILD_ECORE_DIRECTFB +ECORE_DIRECTFB_INC = -I$(top_srcdir)/src/lib/ecore_directfb -I@DIRECTFB_CFLAGS@ +ECORE_DIRECTFB_LIB = $(top_builddir)/src/lib/ecore_directfb/libecore_directfb.la +else +ECORE_DIRECTFB_INC = +ECORE_DIRECTFB_LIB = +endif + +if BUILD_ECORE_WIN32 +ECORE_WIN32_INC = -I$(top_srcdir)/src/lib/ecore_win32 +ECORE_WIN32_LIB = $(top_builddir)/src/lib/ecore_win32/libecore_win32.la +else +ECORE_WIN32_INC = +ECORE_WIN32_LIB = +endif + +if BUILD_ECORE_SDL +ECORE_SDL_INC = -I$(top_srcdir)/src/lib/ecore_sdl @SDL_CFLAGS@ +ECORE_SDL_LIB = $(top_builddir)/src/lib/ecore_sdl/libecore_sdl.la +ECORE_SDL_LIBADD = @SDL_LIBS@ $(ECORE_SDL_LIB) +else +ECORE_SDL_INC = +ECORE_SDL_LIB = +ECORE_SDL_LIBADD = +endif + +if BUILD_ECORE_COCOA +ECORE_COCOA_INC = -I$(top_srcdir)/src/lib/ecore_cocoa +ECORE_COCOA_LIB = $(top_builddir)/src/lib/ecore_cocoa/libecore_cocoa.la +else +ECORE_COCOA_INC = +ECORE_COCOA_LIB = +endif + +if BUILD_ECORE_WINCE +ECORE_WINCE_INC = -I$(top_srcdir)/src/lib/ecore_wince +ECORE_WINCE_LIB = $(top_builddir)/src/lib/ecore_wince/libecore_wince.la +else +ECORE_WINCE_INC = +ECORE_WINCE_LIB = +endif + +if BUILD_ECORE_PSL1GHT +ECORE_PSL1GHT_INC = -I$(top_srcdir)/src/lib/ecore_psl1ght +ECORE_PSL1GHT_LIB = $(top_builddir)/src/lib/ecore_psl1ght/libecore_psl1ght.la +else +ECORE_PSL1GHT_INC = +ECORE_PSL1GHT_LIB = +endif + +if BUILD_ECORE_WAYLAND +ECORE_WAYLAND_INC = -I$(top_srcdir)/src/lib/ecore_wayland @WAYLAND_CFLAGS@ +ECORE_WAYLAND_LIB = $(top_builddir)/src/lib/ecore_wayland/libecore_wayland.la +ECORE_WAYLAND_LIBADD = @WAYLAND_LIBS@ $(ECORE_WAYLAND_LIB) +else +ECORE_WAYLAND_INC = +ECORE_WAYLAND_LIB = +ECORE_WAYLAND_LIBADD = +endif + +if BUILD_ECORE_IPC +ECORE_IPC_INC= \ +-I$(top_srcdir)/src/lib/ecore_ipc \ +-I$(top_builddir)/src/lib/ecore_ipc + +ECORE_IPC_LIB=$(top_builddir)/src/lib/ecore_ipc/libecore_ipc.la +endif + +AM_CPPFLAGS = \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore_evas \ +-I$(top_srcdir)/src/lib/ecore_input \ +-I$(top_srcdir)/src/lib/ecore_input_evas \ +-I$(top_builddir)/src/lib/ecore \ +-I$(top_builddir)/src/lib/ecore_evas \ +-I$(top_builddir)/src/lib/ecore_input \ +-I$(top_builddir)/src/lib/ecore_input_evas \ +@EFL_ECORE_EVAS_BUILD@ \ +$(ECORE_X_INC) \ +$(ECORE_FB_INC) \ +$(ECORE_DIRECTFB_INC) \ +$(ECORE_WIN32_INC) \ +$(ECORE_SDL_INC) \ +$(ECORE_COCOA_INC) \ +$(ECORE_WINCE_INC) \ +$(ECORE_PSL1GHT_INC) \ +$(ECORE_WAYLAND_INC) \ +$(ECORE_IPC_INC) \ +@EVAS_CFLAGS@ \ +@EINA_CFLAGS@ \ +@EVIL_CFLAGS@ \ +@WAYLAND_EGL_CFLAGS@ + +AM_CFLAGS = @WIN32_CFLAGS@ + +lib_LTLIBRARIES = libecore_evas.la +includes_HEADERS = Ecore_Evas.h +includesdir = $(includedir)/ecore-@VMAJ@ + +libecore_evas_la_SOURCES = \ +ecore_evas.c \ +ecore_evas_util.c \ +ecore_evas_x.c \ +ecore_evas_fb.c \ +ecore_evas_buffer.c \ +ecore_evas_directfb.c \ +ecore_evas_win32.c \ +ecore_evas_sdl.c \ +ecore_evas_cocoa.c \ +ecore_evas_wince.c \ +ecore_evas_ews.c \ +ecore_evas_psl1ght.c \ +ecore_evas_wayland_shm.c \ +ecore_evas_wayland_egl.c \ +ecore_evas_extn.c + +libecore_evas_la_LIBADD = \ +$(ECORE_X_LIB) \ +$(ECORE_FB_LIB) \ +$(ECORE_DIRECTFB_LIB) \ +$(ECORE_WIN32_LIB) \ +$(ECORE_SDL_LIB) \ +$(ECORE_SDL_LIBADD) \ +$(ECORE_COCOA_LIB) \ +$(ECORE_WINCE_LIB) \ +$(ECORE_IPC_LIB) \ +$(ECORE_PSL1GHT_LIB) \ +$(ECORE_WAYLAND_LIB) \ +$(ECORE_WAYLAND_LIBADD) \ +$(top_builddir)/src/lib/ecore_input/libecore_input.la \ +$(top_builddir)/src/lib/ecore_input_evas/libecore_input_evas.la \ +$(top_builddir)/src/lib/ecore/libecore.la \ +@EVAS_LIBS@ \ +@EINA_LIBS@ \ +@EVIL_LIBS@ \ +@EFL_SHM_OPEN_LIBS@ \ +@WAYLAND_EGL_LIBS@ + +libecore_evas_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ + +EXTRA_DIST = \ +ecore_evas_private.h diff --git a/src/lib/ecore_evas/ecore_evas.c b/src/lib/ecore_evas/ecore_evas.c new file mode 100644 index 0000000..7a2ac9a --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas.c @@ -0,0 +1,2861 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include + +#ifndef _MSC_VER +# include +#endif + +#ifdef HAVE_SYS_MMAN_H +# include +#endif + +#ifdef HAVE_EVIL +# include +#endif + +#include "Ecore.h" +#include "ecore_private.h" +#include "Ecore_Input.h" + +#include "ecore_evas_private.h" +#include "Ecore_Evas.h" + +Eina_Bool _ecore_evas_app_comp_sync = 1; +int _ecore_evas_log_dom = -1; +static int _ecore_evas_init_count = 0; +static Ecore_Fd_Handler *_ecore_evas_async_events_fd = NULL; +static Eina_Bool _ecore_evas_async_events_fd_handler(void *data, Ecore_Fd_Handler *fd_handler); + +static Ecore_Idle_Enterer *ecore_evas_idle_enterer = NULL; +static Ecore_Evas *ecore_evases = NULL; +static int _ecore_evas_fps_debug = 0; + +static Eina_Bool +_ecore_evas_idle_enter(void *data __UNUSED__) +{ + Ecore_Evas *ee; + double t1 = 0.0; + double t2 = 0.0; + int rend = 0; + + if (!ecore_evases) return ECORE_CALLBACK_RENEW; + if (_ecore_evas_fps_debug) + { + t1 = ecore_time_get(); + } + EINA_INLIST_FOREACH(ecore_evases, ee) + { + if (!ee->manual_render) + { + if (ee->engine.func->fn_render) + rend |= ee->engine.func->fn_render(ee); + } + } + if (_ecore_evas_fps_debug) + { + t2 = ecore_time_get(); + if (rend) + _ecore_evas_fps_debug_rendertime_add(t2 - t1); + } + return ECORE_CALLBACK_RENEW; +} + +/** + * Query if a particular rendering engine target has support + * @param engine The engine to check support for + * @return 1 if the particular engine is supported, 0 if it is not + * + * Query if engine @param engine is supported by ecore_evas. 1 is returned if + * it is, and 0 is returned if it is not supported. + */ +EAPI int +ecore_evas_engine_type_supported_get(Ecore_Evas_Engine_Type engine) +{ + switch (engine) + { + case ECORE_EVAS_ENGINE_SOFTWARE_BUFFER: +#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER + return EINA_TRUE; +#else + return EINA_FALSE; +#endif + case ECORE_EVAS_ENGINE_SOFTWARE_XLIB: +#ifdef BUILD_ECORE_EVAS_SOFTWARE_XLIB + return EINA_TRUE; +#else + return EINA_FALSE; +#endif + case ECORE_EVAS_ENGINE_XRENDER_X11: + return EINA_FALSE; + case ECORE_EVAS_ENGINE_OPENGL_X11: +#ifdef BUILD_ECORE_EVAS_OPENGL_X11 + return EINA_TRUE; +#else + return EINA_FALSE; +#endif + case ECORE_EVAS_ENGINE_SOFTWARE_XCB: +#ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB + return EINA_TRUE; +#else + return EINA_FALSE; +#endif + case ECORE_EVAS_ENGINE_XRENDER_XCB: + return EINA_FALSE; + case ECORE_EVAS_ENGINE_SOFTWARE_GDI: +#ifdef BUILD_ECORE_EVAS_SOFTWARE_GDI + return EINA_TRUE; +#else + return EINA_FALSE; +#endif + case ECORE_EVAS_ENGINE_SOFTWARE_DDRAW: +#ifdef BUILD_ECORE_EVAS_SOFTWARE_DDRAW + return EINA_TRUE; +#else + return EINA_FALSE; +#endif + case ECORE_EVAS_ENGINE_DIRECT3D: +#ifdef BUILD_ECORE_EVAS_DIRECT3D + return EINA_TRUE; +#else + return EINA_FALSE; +#endif + case ECORE_EVAS_ENGINE_OPENGL_GLEW: +#ifdef BUILD_ECORE_EVAS_OPENGL_GLEW + return EINA_TRUE; +#else + return EINA_FALSE; +#endif + case ECORE_EVAS_ENGINE_SOFTWARE_SDL: +#ifdef BUILD_ECORE_EVAS_SOFTWARE_SDL + return EINA_TRUE; +#else + return EINA_FALSE; +#endif + case ECORE_EVAS_ENGINE_OPENGL_SDL: +#ifdef BUILD_ECORE_EVAS_OPENGL_SDL + return EINA_TRUE; +#else + return EINA_FALSE; +#endif + case ECORE_EVAS_ENGINE_DIRECTFB: +#ifdef BUILD_ECORE_EVAS_DIRECTFB + return EINA_TRUE; +#else + return EINA_FALSE; +#endif + case ECORE_EVAS_ENGINE_SOFTWARE_FB: +#ifdef BUILD_ECORE_EVAS_FB + return EINA_TRUE; +#else + return EINA_FALSE; +#endif + + case ECORE_EVAS_ENGINE_SOFTWARE_8_X11: +#ifdef BUILD_ECORE_EVAS_SOFTWARE_8_X11 + return EINA_TRUE; +#else + return EINA_FALSE; +#endif + + case ECORE_EVAS_ENGINE_SOFTWARE_16_X11: +#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_X11 + return EINA_TRUE; +#else + return EINA_FALSE; +#endif + case ECORE_EVAS_ENGINE_SOFTWARE_16_DDRAW: +#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_DDRAW + return EINA_TRUE; +#else + return EINA_FALSE; +#endif + case ECORE_EVAS_ENGINE_SOFTWARE_16_WINCE: +#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_WINCE + return EINA_TRUE; +#else + return EINA_FALSE; +#endif + case ECORE_EVAS_ENGINE_OPENGL_COCOA: +#ifdef BUILD_ECORE_EVAS_OPENGL_COCOA + return EINA_TRUE; +#else + return EINA_FALSE; +#endif + case ECORE_EVAS_ENGINE_EWS: +#ifdef BUILD_ECORE_EVAS_EWS + return EINA_TRUE; +#else + return EINA_FALSE; +#endif + case ECORE_EVAS_ENGINE_PSL1GHT: +#ifdef BUILD_ECORE_EVAS_PSL1GHT + return EINA_TRUE; +#else + return EINA_FALSE; +#endif + case ECORE_EVAS_ENGINE_WAYLAND_SHM: +#ifdef BUILD_ECORE_EVAS_WAYLAND_SHM + return EINA_TRUE; +#else + return EINA_FALSE; +#endif + case ECORE_EVAS_ENGINE_WAYLAND_EGL: +#ifdef BUILD_ECORE_EVAS_WAYLAND_EGL + return EINA_TRUE; +#else + return EINA_FALSE; +#endif + default: + return EINA_FALSE; + }; +} + +static void +_ecore_evas_fork_cb(void *data __UNUSED__) +{ + int fd; + + if (_ecore_evas_async_events_fd) + ecore_main_fd_handler_del(_ecore_evas_async_events_fd); + fd = evas_async_events_fd_get(); + if (fd >= 0) + _ecore_evas_async_events_fd = + ecore_main_fd_handler_add(fd, ECORE_FD_READ, + _ecore_evas_async_events_fd_handler, NULL, + NULL, NULL); +} + +EAPI int +ecore_evas_init(void) +{ + int fd; + + if (++_ecore_evas_init_count != 1) + return _ecore_evas_init_count; + + if (!evas_init()) + return --_ecore_evas_init_count; + + if (!ecore_init()) + goto shutdown_evas; + + _ecore_evas_log_dom = eina_log_domain_register + ("ecore_evas", ECORE_EVAS_DEFAULT_LOG_COLOR); + if(_ecore_evas_log_dom < 0) + { + EINA_LOG_ERR("Impossible to create a log domain for Ecore_Evas."); + goto shutdown_ecore; + } + + ecore_fork_reset_callback_add(_ecore_evas_fork_cb, NULL); + fd = evas_async_events_fd_get(); + if (fd >= 0) + _ecore_evas_async_events_fd = + ecore_main_fd_handler_add(fd, ECORE_FD_READ, + _ecore_evas_async_events_fd_handler, NULL, + NULL, NULL); + + ecore_evas_idle_enterer = + ecore_idle_enterer_add(_ecore_evas_idle_enter, NULL); + if (getenv("ECORE_EVAS_FPS_DEBUG")) _ecore_evas_fps_debug = 1; + if (_ecore_evas_fps_debug) _ecore_evas_fps_debug_init(); + +#ifdef BUILD_ECORE_EVAS_EWS + _ecore_evas_ews_events_init(); +#endif + + _ecore_evas_extn_init(); + + if (getenv("ECORE_EVAS_COMP_NOSYNC")) + _ecore_evas_app_comp_sync = 0; + return _ecore_evas_init_count; + + shutdown_ecore: + ecore_shutdown(); + shutdown_evas: + evas_shutdown(); + + return --_ecore_evas_init_count; +} + +EAPI int +ecore_evas_shutdown(void) +{ + if (--_ecore_evas_init_count != 0) + return _ecore_evas_init_count; + + while (ecore_evases) _ecore_evas_free(ecore_evases); + + _ecore_evas_extn_shutdown(); + + if (_ecore_evas_fps_debug) _ecore_evas_fps_debug_shutdown(); + ecore_idle_enterer_del(ecore_evas_idle_enterer); + ecore_evas_idle_enterer = NULL; + +#ifdef BUILD_ECORE_EVAS_X11 + while (_ecore_evas_x_shutdown()); +#endif +#ifdef BUILD_ECORE_EVAS_WIN32 + while (_ecore_evas_win32_shutdown()); +#endif +#ifdef BUILD_ECORE_EVAS_FB + while (_ecore_evas_fb_shutdown()); +#endif +#ifdef BUILD_ECORE_EVAS_EWS + while (_ecore_evas_ews_shutdown()); +#endif +#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER + while (_ecore_evas_buffer_shutdown()); +#endif +#ifdef BUILD_ECORE_EVAS_DIRECTFB + while (_ecore_evas_directfb_shutdown()); +#endif +#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_WINCE + while (_ecore_evas_wince_shutdown()); +#endif + + if (_ecore_evas_async_events_fd) + ecore_main_fd_handler_del(_ecore_evas_async_events_fd); + + ecore_fork_reset_callback_del(_ecore_evas_fork_cb, NULL); + + eina_log_domain_unregister(_ecore_evas_log_dom); + _ecore_evas_log_dom = -1; + ecore_shutdown(); + evas_shutdown(); + + return _ecore_evas_init_count; +} + +EAPI void +ecore_evas_app_comp_sync_set(Eina_Bool do_sync) +{ + _ecore_evas_app_comp_sync = do_sync; +} + +EAPI Eina_Bool +ecore_evas_app_comp_sync_get(void) +{ + return _ecore_evas_app_comp_sync; +} + +struct ecore_evas_engine { + const char *name; + Ecore_Evas *(*constructor)(int x, int y, int w, int h, const char *extra_options); +}; + +/* inline is just to avoid need to ifdef around it */ +static inline const char * +_ecore_evas_parse_extra_options_str(const char *extra_options, const char *key, char **value) +{ + int len = strlen(key); + + while (extra_options) + { + const char *p; + + if (strncmp(extra_options, key, len) != 0) + { + extra_options = strchr(extra_options, ';'); + if (extra_options) + extra_options++; + continue; + } + + extra_options += len; + p = strchr(extra_options, ';'); + if (p) + { + len = p - extra_options; + *value = malloc(len + 1); + memcpy(*value, extra_options, len); + (*value)[len] = '\0'; + extra_options = p + 1; + } + else + { + *value = strdup(extra_options); + extra_options = NULL; + } + } + return extra_options; +} + +/* inline is just to avoid need to ifdef around it */ +static inline const char * +_ecore_evas_parse_extra_options_uint(const char *extra_options, const char *key, unsigned int *value) +{ + int len = strlen(key); + + while (extra_options) + { + const char *p; + + if (strncmp(extra_options, key, len) != 0) + { + extra_options = strchr(extra_options, ';'); + if (extra_options) + extra_options++; + continue; + } + + extra_options += len; + *value = strtol(extra_options, NULL, 0); + + p = strchr(extra_options, ';'); + if (p) + extra_options = p + 1; + else + extra_options = NULL; + } + return extra_options; +} + +/* inline is just to avoid need to ifdef around it */ +static inline const char * +_ecore_evas_parse_extra_options_x(const char *extra_options, char **disp_name, unsigned int *parent) +{ + _ecore_evas_parse_extra_options_str(extra_options, "display=", disp_name); + _ecore_evas_parse_extra_options_uint(extra_options, "parent=", parent); + return extra_options; +} + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 +static Ecore_Evas * +_ecore_evas_constructor_software_x11(int x, int y, int w, int h, const char *extra_options) +{ + unsigned int parent = 0; + char *disp_name = NULL; + Ecore_Evas *ee; + + _ecore_evas_parse_extra_options_x(extra_options, &disp_name, &parent); + ee = ecore_evas_software_x11_new(disp_name, parent, x, y, w, h); + free(disp_name); + + return ee; +} +#endif + +#ifdef BUILD_ECORE_EVAS_OPENGL_COCOA +static Ecore_Evas * +_ecore_evas_constructor_cocoa(int x, int y, int w, int h, const char *extra_options) +{ + char *name = NULL; + Ecore_Evas *ee; + + _ecore_evas_parse_extra_options_str(extra_options, "name=", &name); + ee = ecore_evas_cocoa_new(NULL, x, y, w, h); + free(name); + + if (ee) ecore_evas_move(ee, x, y); + return ee; +} +#endif + +#ifdef BUILD_ECORE_EVAS_OPENGL_X11 +static Ecore_Evas * +_ecore_evas_constructor_opengl_x11(int x, int y, int w, int h, const char *extra_options) +{ + Ecore_X_Window parent = 0; + char *disp_name = NULL; + Ecore_Evas *ee; + + _ecore_evas_parse_extra_options_x(extra_options, &disp_name, &parent); + ee = ecore_evas_gl_x11_new(disp_name, parent, x, y, w, h); + free(disp_name); + + return ee; +} +#endif + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_8_X11 +static Ecore_Evas * +_ecore_evas_constructor_software_8_x11(int x, int y, int w, int h, const char *extra_options) +{ + Ecore_X_Window parent = 0; + char *disp_name = NULL; + Ecore_Evas *ee; + + _ecore_evas_parse_extra_options_x(extra_options, &disp_name, &parent); + ee = ecore_evas_software_x11_8_new(disp_name, parent, x, y, w, h); + free(disp_name); + + return ee; +} +#endif + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_X11 +static Ecore_Evas * +_ecore_evas_constructor_software_16_x11(int x, int y, int w, int h, const char *extra_options) +{ + Ecore_X_Window parent = 0; + char *disp_name = NULL; + Ecore_Evas *ee; + + _ecore_evas_parse_extra_options_x(extra_options, &disp_name, &parent); + ee = ecore_evas_software_x11_16_new(disp_name, parent, x, y, w, h); + free(disp_name); + + return ee; +} +#endif + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_SDL +static Ecore_Evas * +_ecore_evas_constructor_sdl(int x __UNUSED__, int y __UNUSED__, int w, int h, const char *extra_options) +{ + Ecore_Evas *ee; + unsigned int fullscreen = 0, hwsurface = 0, noframe = 0, alpha = 0; + char *name = NULL; + + _ecore_evas_parse_extra_options_str(extra_options, "name=", &name); + _ecore_evas_parse_extra_options_uint(extra_options, "fullscreen=", &fullscreen); + _ecore_evas_parse_extra_options_uint(extra_options, "hwsurface=", &hwsurface); + _ecore_evas_parse_extra_options_uint(extra_options, "noframe=", &noframe); + _ecore_evas_parse_extra_options_uint(extra_options, "alpha=", &alpha); + + ee = ecore_evas_sdl_new(name, w, h, fullscreen, hwsurface, noframe, alpha); + free(name); + + return ee; +} +#endif + +#ifdef BUILD_ECORE_EVAS_OPENGL_SDL +static Ecore_Evas * +_ecore_evas_constructor_opengl_sdl(int x __UNUSED__, int y __UNUSED__, int w, int h, const char *extra_options) +{ + Ecore_Evas *ee; + unsigned int fullscreen = 0, noframe = 0; + char *name = NULL; + + _ecore_evas_parse_extra_options_str(extra_options, "name=", &name); + _ecore_evas_parse_extra_options_uint(extra_options, "fullscreen=", &fullscreen); + _ecore_evas_parse_extra_options_uint(extra_options, "noframe=", &noframe); + + ee = ecore_evas_gl_sdl_new(name, w, h, fullscreen, noframe); + free(name); + + return ee; +} +#endif + +#ifdef BUILD_ECORE_EVAS_DIRECTFB +static Ecore_Evas * +_ecore_evas_constructor_directfb(int x, int y, int w, int h, const char *extra_options) +{ + Ecore_Evas *ee; + char *disp_name = NULL; + unsigned int windowed = 1; + + _ecore_evas_parse_extra_options_str(extra_options, "display=", &disp_name); + _ecore_evas_parse_extra_options_uint(extra_options, "windowed=", &windowed); + + ee = ecore_evas_directfb_new(disp_name, windowed, x, y, w, h); + free(disp_name); + + return ee; +} +#endif + +#ifdef BUILD_ECORE_EVAS_FB +static Ecore_Evas * +_ecore_evas_constructor_fb(int x __UNUSED__, int y __UNUSED__, int w, int h, const char *extra_options) +{ + Ecore_Evas *ee; + char *disp_name = NULL; + unsigned int rotation = 0; + + _ecore_evas_parse_extra_options_str(extra_options, "display=", &disp_name); + _ecore_evas_parse_extra_options_uint(extra_options, "rotation=", &rotation); + + ee = ecore_evas_fb_new(disp_name, rotation, w, h); + free(disp_name); + + return ee; +} +#endif + + +#ifdef BUILD_ECORE_EVAS_PSL1GHT +static Ecore_Evas * +_ecore_evas_constructor_psl1ght(int x __UNUSED__, int y __UNUSED__, int w, int h, const char *extra_options) +{ + Ecore_Evas *ee; + char *name = NULL; + + _ecore_evas_parse_extra_options_str(extra_options, "name=", &name); + ee = ecore_evas_psl1ght_new(name, w, h); + free(name); + + if (ee) ecore_evas_move(ee, x, y); + return ee; +} +#endif + +#ifdef BUILD_ECORE_EVAS_WAYLAND_SHM +static Ecore_Evas * +_ecore_evas_constructor_wayland_shm(int x, int y, int w, int h, const char *extra_options) +{ + char *disp_name = NULL; + unsigned int frame = 1, parent = 0; + Ecore_Evas *ee; + + _ecore_evas_parse_extra_options_str(extra_options, "display=", &disp_name); + _ecore_evas_parse_extra_options_uint(extra_options, "frame=", &frame); + _ecore_evas_parse_extra_options_uint(extra_options, "parent=", &parent); + ee = ecore_evas_wayland_shm_new(disp_name, parent, x, y, w, h, frame); + free(disp_name); + + return ee; +} +#endif + +#ifdef BUILD_ECORE_EVAS_WAYLAND_EGL +static Ecore_Evas * +_ecore_evas_constructor_wayland_egl(int x, int y, int w, int h, const char *extra_options) +{ + char *disp_name = NULL; + unsigned int frame = 1, parent = 0; + Ecore_Evas *ee; + + _ecore_evas_parse_extra_options_str(extra_options, "display=", &disp_name); + _ecore_evas_parse_extra_options_uint(extra_options, "frame=", &frame); + _ecore_evas_parse_extra_options_uint(extra_options, "parent=", &parent); + ee = ecore_evas_wayland_egl_new(disp_name, parent, x, y, w, h, frame); + free(disp_name); + + return ee; +} +#endif + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_GDI +static Ecore_Evas * +_ecore_evas_constructor_software_gdi(int x, int y, int w, int h, const char *extra_options) +{ + return ecore_evas_software_gdi_new(NULL, x, y, w, h); +} +#endif + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_DDRAW +static Ecore_Evas * +_ecore_evas_constructor_software_ddraw(int x, int y, int w, int h, const char *extra_options) +{ + return ecore_evas_software_ddraw_new(NULL, x, y, w, h); +} +#endif + +#ifdef BUILD_ECORE_EVAS_DIRECT3D +static Ecore_Evas * +_ecore_evas_constructor_direct3d(int x, int y, int w, int h, const char *extra_options) +{ + return ecore_evas_direct3d_new(NULL, x, y, w, h); +} +#endif + +#ifdef BUILD_ECORE_EVAS_OPENGL_GLEW +static Ecore_Evas * +_ecore_evas_constructor_opengl_glew(int x, int y, int w, int h, const char *extra_options) +{ + return ecore_evas_gl_glew_new(NULL, x, y, w, h); +} +#endif + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_DDRAW +static Ecore_Evas * +_ecore_evas_constructor_software_16_ddraw(int x, int y, int w, int h, const char *extra_options) +{ + return ecore_evas_software_16_ddraw_new(NULL, x, y, w, h); +} +#endif + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_WINCE +static Ecore_Evas * +_ecore_evas_constructor_software_16_wince(int x, int y, int w, int h, const char *extra_options __UNUSED__) +{ + return ecore_evas_software_wince_new(NULL, x, y, w, h); +} + +static Ecore_Evas * +_ecore_evas_constructor_software_16_wince_fb(int x, int y, int w, int h, const char *extra_options __UNUSED__) +{ + return ecore_evas_software_wince_fb_new(NULL, x, y, w, h); +} + +static Ecore_Evas * +_ecore_evas_constructor_software_16_wince_gapi(int x, int y, int w, int h, const char *extra_options __UNUSED__) +{ + return ecore_evas_software_wince_gapi_new(NULL, x, y, w, h); +} + +static Ecore_Evas * +_ecore_evas_constructor_software_16_wince_gdi(int x, int y, int w, int h, const char *extra_options __UNUSED__) +{ + return ecore_evas_software_wince_gdi_new(NULL, x, y, w, h); +} +#endif + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER +static Ecore_Evas * +_ecore_evas_constructor_buffer(int x __UNUSED__, int y __UNUSED__, int w, int h, const char *extra_options __UNUSED__) +{ + return ecore_evas_buffer_new(w, h); +} +#endif + +#ifdef BUILD_ECORE_EVAS_EWS +static Ecore_Evas * +_ecore_evas_constructor_ews(int x, int y, int w, int h, const char *extra_options __UNUSED__) +{ + return ecore_evas_ews_new(x, y, w, h); +} +#endif + +/* note: keep sorted by priority, highest first */ +static const struct ecore_evas_engine _engines[] = { + /* unix */ +#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 + {"software_x11", _ecore_evas_constructor_software_x11}, +#endif +#ifdef BUILD_ECORE_EVAS_OPENGL_X11 + {"opengl_x11", _ecore_evas_constructor_opengl_x11}, +#endif +#ifdef BUILD_ECORE_EVAS_SOFTWARE_8_X11 + {"software_8_x11", _ecore_evas_constructor_software_8_x11}, +#endif +#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_X11 + {"software_16_x11", _ecore_evas_constructor_software_16_x11}, +#endif +#ifdef BUILD_ECORE_EVAS_DIRECTFB + {"directfb", _ecore_evas_constructor_directfb}, +#endif +#ifdef BUILD_ECORE_EVAS_FB + {"fb", _ecore_evas_constructor_fb}, +#endif + + /* windows */ +#ifdef BUILD_ECORE_EVAS_SOFTWARE_GDI + {"software_gdi", _ecore_evas_constructor_software_gdi}, +#endif +#ifdef BUILD_ECORE_EVAS_SOFTWARE_DDRAW + {"software_ddraw", _ecore_evas_constructor_software_ddraw}, +#endif +#ifdef BUILD_ECORE_EVAS_DIRECT3D + {"direct3d", _ecore_evas_constructor_direct3d}, +#endif +#ifdef BUILD_ECORE_EVAS_OPENGL_GLEW + {"opengl_glew", _ecore_evas_constructor_opengl_glew}, +#endif +#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_DDRAW + {"software_16_ddraw", _ecore_evas_constructor_software_16_ddraw}, +#endif +#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_WINCE + {"software_16_wince", _ecore_evas_constructor_software_16_wince}, + {"software_16_wince_fb", _ecore_evas_constructor_software_16_wince_fb}, + {"software_16_wince_gapi", _ecore_evas_constructor_software_16_wince_gapi}, + {"software_16_wince_gdi", _ecore_evas_constructor_software_16_wince_gdi}, +#endif + + /* Apple */ +#ifdef BUILD_ECORE_EVAS_OPENGL_COCOA + {"opengl_cocoa", _ecore_evas_constructor_cocoa}, +#endif + + /* PS3 support */ +#ifdef BUILD_ECORE_EVAS_PSL1GHT + {"psl1ght", _ecore_evas_constructor_psl1ght}, +#endif + + /* Wayland */ +#ifdef BUILD_ECORE_EVAS_WAYLAND_SHM + {"wayland_shm", _ecore_evas_constructor_wayland_shm}, +#endif + +#ifdef BUILD_ECORE_EVAS_WAYLAND_EGL + {"wayland_egl", _ecore_evas_constructor_wayland_egl}, +#endif + + /* Last chance to have a window */ +#ifdef BUILD_ECORE_EVAS_OPENGL_SDL + {"opengl_sdl", _ecore_evas_constructor_opengl_sdl}, +#endif + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_SDL + {"sdl", _ecore_evas_constructor_sdl}, +#endif + + /* independent */ +#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER + {"buffer", _ecore_evas_constructor_buffer}, +#endif + +#ifdef BUILD_ECORE_EVAS_EWS + {"ews", _ecore_evas_constructor_ews}, +#endif + {NULL, NULL} +}; + +EAPI Eina_List * +ecore_evas_engines_get(void) +{ + const struct ecore_evas_engine *itr; + Eina_List *lst = NULL; + + for (itr = _engines; itr->name; itr++) + lst = eina_list_append(lst, itr->name); + + return lst; +} + +EAPI void +ecore_evas_engines_free(Eina_List *engines) +{ + eina_list_free(engines); +} + +static Ecore_Evas * +_ecore_evas_new_auto_discover(int x, int y, int w, int h, const char *extra_options) +{ + const struct ecore_evas_engine *itr; + + DBG("auto discover engine"); + + for (itr = _engines; itr->constructor; itr++) + { + Ecore_Evas *ee = itr->constructor(x, y, w, h, extra_options); + if (ee) + { + INF("auto discovered '%s'", itr->name); + return ee; + } + } + + WRN("could not auto discover."); + return NULL; +} + +EAPI Ecore_Evas * +ecore_evas_new(const char *engine_name, int x, int y, int w, int h, const char *extra_options) +{ + const struct ecore_evas_engine *itr; + + if (!engine_name) + { + engine_name = getenv("ECORE_EVAS_ENGINE"); + if (engine_name) + DBG("no engine_name provided, using ECORE_EVAS_ENGINE='%s'", + engine_name); + } + if (!engine_name) + return _ecore_evas_new_auto_discover(x, y, w, h, extra_options); + + for (itr = _engines; itr->name; itr++) + if (strcmp(itr->name, engine_name) == 0) + { + INF("using engine '%s', extra_options=%s", + engine_name, extra_options ? extra_options : "(null)"); + return itr->constructor(x, y, w, h, extra_options); + } + + WRN("unknown engine '%s'", engine_name); + return NULL; +} + +EAPI const char * +ecore_evas_engine_name_get(const Ecore_Evas *ee) +{ + if (!ee) + return NULL; + return ee->driver; +} + +EAPI Ecore_Evas * +ecore_evas_ecore_evas_get(const Evas *e) +{ + Ecore_Evas *ee = evas_data_attach_get(e); + if (!ee) return NULL; + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, "ecore_evas_ecore_evas_get"); + return NULL; + } + return ee; +} + +EAPI void +ecore_evas_free(Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_free"); + return; + } + _ecore_evas_free(ee); + return; +} + +EAPI void * +ecore_evas_data_get(const Ecore_Evas *ee, const char *key) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_data_get"); + return NULL; + } + + if (!key) return NULL; + if (!ee->data) return NULL; + + return eina_hash_find(ee->data, key); +} + +EAPI void +ecore_evas_data_set(Ecore_Evas *ee, const char *key, const void *data) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_data_set"); + return; + } + + if (!key) return; + + if (ee->data) + eina_hash_del(ee->data, key, NULL); + if (data) + { + if (!ee->data) + ee->data = eina_hash_string_superfast_new(NULL); + eina_hash_add(ee->data, key, data); + } +} + +#define IFC(_ee, _fn) if (_ee->engine.func->_fn) {_ee->engine.func->_fn +#define IFE return;} + +EAPI void +ecore_evas_callback_resize_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_callback_resize_set"); + return; + } + IFC(ee, fn_callback_resize_set) (ee, func); + IFE; + ee->func.fn_resize = func; +} + +EAPI void +ecore_evas_callback_move_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_callback_move_set"); + return; + } + IFC(ee, fn_callback_move_set) (ee, func); + IFE; + ee->func.fn_move = func; +} + +EAPI void +ecore_evas_callback_show_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_callback_show_set"); + return; + } + IFC(ee, fn_callback_show_set) (ee, func); + IFE; + ee->func.fn_show = func; +} + +EAPI void +ecore_evas_callback_hide_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_callback_hide_set"); + return; + } + IFC(ee, fn_callback_hide_set) (ee, func); + IFE; + ee->func.fn_hide = func; +} + +EAPI void +ecore_evas_callback_delete_request_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_callback_delete_request_set"); + return; + } + IFC(ee, fn_callback_delete_request_set) (ee, func); + IFE; + ee->func.fn_delete_request = func; +} + +EAPI void +ecore_evas_callback_destroy_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_callback_destroy_set"); + return; + } + IFC(ee, fn_callback_destroy_set) (ee, func); + IFE; + ee->func.fn_destroy = func; +} + +EAPI void +ecore_evas_callback_focus_in_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_callback_focus_in_set"); + return; + } + IFC(ee, fn_callback_focus_in_set) (ee, func); + IFE; + ee->func.fn_focus_in = func; +} + +EAPI void +ecore_evas_callback_focus_out_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_callback_focus_out_set"); + return; + } + IFC(ee, fn_callback_focus_out_set) (ee, func); + IFE; + ee->func.fn_focus_out = func; +} + +EAPI void +ecore_evas_callback_sticky_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_callback_sticky_set"); + return; + } + IFC(ee, fn_callback_sticky_set) (ee, func); + IFE; + ee->func.fn_sticky = func; +} + +EAPI void +ecore_evas_callback_unsticky_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_callback_unsticky_set"); + return; + } + IFC(ee, fn_callback_unsticky_set) (ee, func); + IFE; + ee->func.fn_unsticky = func; +} + +EAPI void +ecore_evas_callback_mouse_in_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_callback_mouse_in_set"); + return; + } + IFC(ee, fn_callback_mouse_in_set) (ee, func); + IFE; + ee->func.fn_mouse_in = func; +} + +EAPI void +ecore_evas_callback_mouse_out_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_callback_mouse_out_set"); + return; + } + IFC(ee, fn_callback_mouse_out_set) (ee, func); + IFE; + ee->func.fn_mouse_out = func; +} + +EAPI void +ecore_evas_callback_pre_render_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_callback_pre_render_set"); + return; + } + IFC(ee, fn_callback_pre_render_set) (ee, func); + IFE; + ee->func.fn_pre_render = func; +} + +EAPI void +ecore_evas_callback_post_render_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_callback_post_render_set"); + return; + } + IFC(ee, fn_callback_post_render_set) (ee, func); + IFE; + ee->func.fn_post_render = func; +} + +EAPI void +ecore_evas_callback_pre_free_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_callback_pre_free_set"); + return; + } + ee->func.fn_pre_free = func; +} + +EAPI void +ecore_evas_callback_state_change_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_callback_state_change_set"); + return; + } + ee->func.fn_state_change = func; +} + +EAPI Evas * +ecore_evas_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_get"); + return NULL; + } + return ee->evas; +} + +EAPI void +ecore_evas_move(Ecore_Evas *ee, int x, int y) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_move"); + return; + } + if (ee->prop.fullscreen) return; + IFC(ee, fn_move) (ee, x, y); + IFE; +} + +EAPI void +ecore_evas_managed_move(Ecore_Evas *ee, int x, int y) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_move"); + return; + } + IFC(ee, fn_managed_move) (ee, x, y); + IFE; +} + +EAPI void +ecore_evas_resize(Ecore_Evas *ee, int w, int h) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_resize"); + return; + } + if (ee->prop.fullscreen) return; + if (w < 1) w = 1; + if (h < 1) h = 1; + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + IFC(ee, fn_resize) (ee, h, w); + IFE; + } + else + { + IFC(ee, fn_resize) (ee, w, h); + IFE; + } +} + +EAPI void +ecore_evas_move_resize(Ecore_Evas *ee, int x, int y, int w, int h) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_move_resize"); + return; + } + if (ee->prop.fullscreen) return; + if (w < 1) w = 1; + if (h < 1) h = 1; + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + IFC(ee, fn_move_resize) (ee, x, y, h, w); + IFE; + } + else + { + IFC(ee, fn_move_resize) (ee, x, y, w, h); + IFE; + } +} + +EAPI void +ecore_evas_geometry_get(const Ecore_Evas *ee, int *x, int *y, int *w, int *h) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_geometry_get"); + return; + } + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + if (x) *x = ee->x; + if (y) *y = ee->y; + if (w) *w = ee->h; + if (h) *h = ee->w; + } + else + { + if (x) *x = ee->x; + if (y) *y = ee->y; + if (w) *w = ee->w; + if (h) *h = ee->h; + } +} + +EAPI void +ecore_evas_request_geometry_get(const Ecore_Evas *ee, int *x, int *y, int *w, int *h) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_request_geometry_get"); + return; + } + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + if (x) *x = ee->req.x; + if (y) *y = ee->req.y; + if (w) *w = ee->req.h; + if (h) *h = ee->req.w; + } + else + { + if (x) *x = ee->req.x; + if (y) *y = ee->req.y; + if (w) *w = ee->req.w; + if (h) *h = ee->req.h; + } +} + +EAPI void +ecore_evas_rotation_set(Ecore_Evas *ee, int rot) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_rotation_set"); + return; + } + rot = rot % 360; + while (rot < 0) rot += 360; + while (rot >= 360) rot -= 360; + IFC(ee, fn_rotation_set) (ee, rot, 0); + /* make sure everything gets redrawn */ + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w); + IFE; +} + +EAPI void +ecore_evas_rotation_with_resize_set(Ecore_Evas *ee, int rot) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_rotation_set"); + return; + } + rot = rot % 360; + while (rot < 0) rot += 360; + while (rot >= 360) rot -= 360; + IFC(ee, fn_rotation_set) (ee, rot, 1); + /* make sure everything gets redrawn */ + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w); + IFE; +} + +EAPI int +ecore_evas_rotation_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_rotation_get"); + return 0; + } + return ee->rotation; +} + +EAPI void +ecore_evas_shaped_set(Ecore_Evas *ee, Eina_Bool shaped) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_shaped_set"); + return; + } + IFC(ee, fn_shaped_set) (ee, shaped); + IFE; +} + +EAPI Eina_Bool +ecore_evas_shaped_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_shaped_get"); + return EINA_FALSE; + } + return ee->shaped ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_evas_alpha_set(Ecore_Evas *ee, Eina_Bool alpha) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_alpha_set"); + return; + } + IFC(ee, fn_alpha_set) (ee, alpha); + IFE; +} + +EAPI Eina_Bool +ecore_evas_alpha_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_alpha_get"); + return EINA_FALSE; + } + return ee->alpha ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_evas_transparent_set(Ecore_Evas *ee, Eina_Bool transparent) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_transparent_set"); + return; + } + IFC(ee, fn_transparent_set) (ee, transparent); + IFE; +} + +EAPI Eina_Bool +ecore_evas_transparent_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_transparent_get"); + return EINA_FALSE; + } + return ee->transparent ? EINA_TRUE : 0; +} + +EAPI void +ecore_evas_show(Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_show"); + return; + } + IFC(ee, fn_show) (ee); + IFE; +} + +EAPI void +ecore_evas_hide(Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_hide"); + return; + } + IFC(ee, fn_hide) (ee); + IFE; +} + + EAPI int +ecore_evas_visibility_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_visibility_get"); + return 0; + } + return ee->visible ? 1:0; +} + +EAPI void +ecore_evas_raise(Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_raise"); + return; + } + IFC(ee, fn_raise) (ee); + IFE; +} + +EAPI void +ecore_evas_lower(Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_lower"); + return; + } + IFC(ee, fn_lower) (ee); + IFE; +} + +EAPI void +ecore_evas_activate(Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_activate"); + return; + } + IFC(ee, fn_activate) (ee); + IFE; +} + +EAPI void +ecore_evas_title_set(Ecore_Evas *ee, const char *t) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_title_set"); + return; + } + IFC(ee, fn_title_set) (ee, t); + IFE; +} + +EAPI const char * +ecore_evas_title_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_title_get"); + return NULL; + } + return ee->prop.title; +} + +EAPI void +ecore_evas_name_class_set(Ecore_Evas *ee, const char *n, const char *c) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_name_class_set"); + return; + } + IFC(ee, fn_name_class_set) (ee, n, c); + IFE; +} + +EAPI void +ecore_evas_name_class_get(const Ecore_Evas *ee, const char **n, const char **c) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_name_class_get"); + return; + } + if (n) *n = ee->prop.name; + if (c) *c = ee->prop.clas; +} + +EAPI void +ecore_evas_size_min_set(Ecore_Evas *ee, int w, int h) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_size_min_set"); + return; + } + if (w < 0) w = 0; + if (h < 0) h = 0; + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + IFC(ee, fn_size_min_set) (ee, h, w); + IFE; + } + else + { + IFC(ee, fn_size_min_set) (ee, w, h); + IFE; + } +} + +EAPI void +ecore_evas_size_min_get(const Ecore_Evas *ee, int *w, int *h) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_size_min_get"); + return; + } + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + if (w) *w = ee->prop.min.h; + if (h) *h = ee->prop.min.w; + } + else + { + if (w) *w = ee->prop.min.w; + if (h) *h = ee->prop.min.h; + } +} + +EAPI void +ecore_evas_size_max_set(Ecore_Evas *ee, int w, int h) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_size_max_set"); + return; + } + if (w < 0) w = 0; + if (h < 0) h = 0; + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + IFC(ee, fn_size_max_set) (ee, h, w); + IFE; + } + else + { + IFC(ee, fn_size_max_set) (ee, w, h); + IFE; + } +} + +EAPI void +ecore_evas_size_max_get(const Ecore_Evas *ee, int *w, int *h) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_size_max_get"); + return; + } + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + if (w) *w = ee->prop.max.h; + if (h) *h = ee->prop.max.w; + } + else + { + if (w) *w = ee->prop.max.w; + if (h) *h = ee->prop.max.h; + } +} + +EAPI void +ecore_evas_size_base_set(Ecore_Evas *ee, int w, int h) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_size_base_set"); + return; + } + if (w < 0) w = 0; + if (h < 0) h = 0; + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + IFC(ee, fn_size_base_set) (ee, h, w); + IFE; + } + else + { + IFC(ee, fn_size_base_set) (ee, w, h); + IFE; + } +} + +EAPI void +ecore_evas_size_base_get(const Ecore_Evas *ee, int *w, int *h) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_size_base_get"); + return; + } + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + if (w) *w = ee->prop.base.h; + if (h) *h = ee->prop.base.w; + } + else + { + if (w) *w = ee->prop.base.w; + if (h) *h = ee->prop.base.h; + } +} + +EAPI void +ecore_evas_size_step_set(Ecore_Evas *ee, int w, int h) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_size_step_set"); + return; + } + if (w < 0) w = 0; + if (h < 0) h = 0; + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + IFC(ee, fn_size_step_set) (ee, h, w); + IFE; + } + else + { + IFC(ee, fn_size_step_set) (ee, w, h); + IFE; + } +} + +EAPI void +ecore_evas_size_step_get(const Ecore_Evas *ee, int *w, int *h) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_size_step_get"); + return; + } + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + if (w) *w = ee->prop.step.h; + if (h) *h = ee->prop.step.w; + } + else + { + if (w) *w = ee->prop.step.w; + if (h) *h = ee->prop.step.h; + } +} + +EAPI void +ecore_evas_cursor_set(Ecore_Evas *ee, const char *file, int layer, int hot_x, int hot_y) +{ + Evas_Object *obj = NULL; + + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_cursor_set"); + return; + } + + if (file) + { + int x, y; + + obj = evas_object_image_add(ee->evas); + evas_object_image_file_set(obj, file, NULL); + evas_object_image_size_get(obj, &x, &y); + evas_object_resize(obj, x, y); + evas_object_image_fill_set(obj, 0, 0, x, y); + } + + IFC(ee, fn_object_cursor_set) (ee, obj, layer, hot_x, hot_y); + IFE; +} + +EAPI void +ecore_evas_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_cursor_set"); + return; + } + IFC(ee, fn_object_cursor_set) (ee, obj, layer, hot_x, hot_y); + IFE; +} + +EAPI void +ecore_evas_cursor_get(const Ecore_Evas *ee, Evas_Object **obj, int *layer, int *hot_x, int *hot_y) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_cursor_get"); + return; + } + if (obj) *obj = ee->prop.cursor.object; + if (layer) *layer = ee->prop.cursor.layer; + if (hot_x) *hot_x = ee->prop.cursor.hot.x; + if (hot_y) *hot_y = ee->prop.cursor.hot.y; +} + +EAPI void +ecore_evas_layer_set(Ecore_Evas *ee, int layer) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_layer_set"); + return; + } + IFC(ee, fn_layer_set) (ee, layer); + IFE; +} + +EAPI int +ecore_evas_layer_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_layer_get"); + return 0; + } + return ee->prop.layer; +} + +EAPI void +ecore_evas_focus_set(Ecore_Evas *ee, Eina_Bool on) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_focus_set"); + return; + } + IFC(ee, fn_focus_set) (ee, on); + IFE; +} + +EAPI Eina_Bool +ecore_evas_focus_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_focus_get"); + return EINA_FALSE; + } + return ee->prop.focused ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_evas_iconified_set(Ecore_Evas *ee, Eina_Bool on) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_iconified_set"); + return; + } + IFC(ee, fn_iconified_set) (ee, on); + IFE; +} + +EAPI Eina_Bool +ecore_evas_iconified_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_iconified_get"); + return EINA_FALSE; + } + return ee->prop.iconified ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_evas_borderless_set(Ecore_Evas *ee, Eina_Bool on) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_borderless_set"); + return; + } + IFC(ee, fn_borderless_set) (ee, on); + IFE; +} + +EAPI Eina_Bool +ecore_evas_borderless_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_borderless_get"); + return EINA_FALSE; + } + return ee->prop.borderless ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_evas_override_set(Ecore_Evas *ee, Eina_Bool on) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_override_set"); + return; + } + IFC(ee, fn_override_set) (ee, on); + IFE; +} + +EAPI Eina_Bool +ecore_evas_override_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_override_get"); + return EINA_FALSE; + } + return ee->prop.override ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_evas_maximized_set(Ecore_Evas *ee, Eina_Bool on) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_maximized_set"); + return; + } + IFC(ee, fn_maximized_set) (ee, on); + IFE; +} + +EAPI Eina_Bool +ecore_evas_maximized_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_maximized_get"); + return EINA_FALSE; + } + return ee->prop.maximized ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_evas_fullscreen_set(Ecore_Evas *ee, Eina_Bool on) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_fullscreen_set"); + return; + } + IFC(ee, fn_fullscreen_set) (ee, on); + IFE; +} + +EAPI Eina_Bool +ecore_evas_fullscreen_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_fullscreen_get"); + return EINA_FALSE; + } + return ee->prop.fullscreen ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_evas_avoid_damage_set(Ecore_Evas *ee, Ecore_Evas_Avoid_Damage_Type on) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_avoid_damage_set"); + return; + } + IFC(ee, fn_avoid_damage_set) (ee, on); + IFE; +} + +EAPI Ecore_Evas_Avoid_Damage_Type +ecore_evas_avoid_damage_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_avoid_damage_get"); + return ECORE_EVAS_AVOID_DAMAGE_NONE; + } + return ee->prop.avoid_damage; +} + +EAPI void +ecore_evas_withdrawn_set(Ecore_Evas *ee, Eina_Bool withdrawn) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_withdrawn_set"); + return; + } + + IFC(ee, fn_withdrawn_set) (ee, withdrawn); + IFE; +} + +EAPI Eina_Bool +ecore_evas_withdrawn_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_withdrawn_get"); + return EINA_FALSE; + } + return ee->prop.withdrawn ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_evas_sticky_set(Ecore_Evas *ee, Eina_Bool sticky) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_sticky_set"); + return; + } + + IFC(ee, fn_sticky_set) (ee, sticky); + IFE; +} + +EAPI Eina_Bool +ecore_evas_sticky_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_sticky_get"); + return EINA_FALSE; + } + return ee->prop.sticky ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_evas_window_group_set(Ecore_Evas *ee, const Ecore_Evas *ee_group) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "XXX"); + return; + } + + IFC(ee, fn_window_group_set) (ee, ee_group); + IFE; +} + +EAPI const Ecore_Evas * +ecore_evas_window_group_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "XXX"); + return EINA_FALSE; + } + return ee->prop.group_ee; +} + +EAPI void +ecore_evas_aspect_set(Ecore_Evas *ee, double aspect) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "XXX"); + return; + } + + IFC(ee, fn_aspect_set) (ee, aspect); + IFE; +} + +EAPI double +ecore_evas_aspect_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "XXX"); + return EINA_FALSE; + } + return ee->prop.aspect; +} + +EAPI void +ecore_evas_urgent_set(Ecore_Evas *ee, Eina_Bool urgent) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "XXX"); + return; + } + + IFC(ee, fn_urgent_set) (ee, urgent); + IFE; +} + +EAPI Eina_Bool +ecore_evas_urgent_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "XXX"); + return EINA_FALSE; + } + return ee->prop.urgent ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_evas_modal_set(Ecore_Evas *ee, Eina_Bool modal) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "XXX"); + return; + } + + IFC(ee, fn_modal_set) (ee, modal); + IFE; +} + +EAPI Eina_Bool +ecore_evas_modal_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "XXX"); + return EINA_FALSE; + } + return ee->prop.modal ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_evas_demand_attention_set(Ecore_Evas *ee, Eina_Bool demand) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "XXX"); + return; + } + + IFC(ee, fn_demands_attention_set) (ee, demand); + IFE; +} + +EAPI Eina_Bool +ecore_evas_demand_attention_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "XXX"); + return EINA_FALSE; + } + return ee->prop.demand_attention ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_evas_focus_skip_set(Ecore_Evas *ee, Eina_Bool skip) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "XXX"); + return; + } + + IFC(ee, fn_focus_skip_set) (ee, skip); + IFE; +} + +EAPI Eina_Bool +ecore_evas_focus_skip_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "XXX"); + return EINA_FALSE; + } + return ee->prop.focus_skip ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_evas_ignore_events_set(Ecore_Evas *ee, Eina_Bool ignore) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_ignore_events_set"); + return; + } + + IFC(ee, fn_ignore_events_set) (ee, ignore); + IFE; +} + +EAPI Eina_Bool +ecore_evas_ignore_events_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_ignore_events_get"); + return EINA_FALSE; + } + return ee->ignore_events ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_evas_manual_render_set(Ecore_Evas *ee, Eina_Bool manual_render) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_manual_render_set"); + return; + } + ee->manual_render = manual_render; +} + +EAPI Eina_Bool +ecore_evas_manual_render_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_manual_render_get"); + return EINA_FALSE; + } + return ee->manual_render ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_evas_manual_render(Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_manual_render"); + return; + } + if (ee->engine.func->fn_render) + ee->engine.func->fn_render(ee); +} + +EAPI void +ecore_evas_comp_sync_set(Ecore_Evas *ee, Eina_Bool do_sync) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_comp_sync_set"); + return; + } + ee->no_comp_sync = !do_sync; +} + +EAPI Eina_Bool +ecore_evas_comp_sync_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_comp_sync_get"); + return EINA_FALSE; + } + return !ee->no_comp_sync; +} + +EAPI Ecore_Window +ecore_evas_window_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_window_get"); + return 0; + } + + return ee->prop.window; +} + +EAPI void +ecore_evas_screen_geometry_get(const Ecore_Evas *ee, int *x, int *y, int *w, int *h) +{ + if (x) *x = 0; + if (y) *y = 0; + if (w) *w = 0; + if (h) *h = 0; + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_screen_geometry_get"); + return; + } + + IFC(ee, fn_screen_geometry_get) (ee, x, y, w, h); + IFE; +} + +EAPI void +ecore_evas_screen_dpi_get(const Ecore_Evas *ee, int *xdpi, int *ydpi) +{ + if (xdpi) *xdpi = 0; + if (ydpi) *ydpi = 0; + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_screen_geometry_get"); + return; + } + + IFC(ee, fn_screen_dpi_get) (ee, xdpi, ydpi); + IFE; +} + +EAPI void +ecore_evas_draw_frame_set(Ecore_Evas *ee, Eina_Bool draw_frame) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, "ecore_evas_draw_frame_set"); + return; + } + ee->prop.draw_frame = draw_frame; +} + +EAPI Eina_Bool +ecore_evas_draw_frame_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, "ecore_evas_draw_frame_get"); + return EINA_FALSE; + } + return ee->prop.draw_frame; +} + +/* fps debug calls - for debugging how much time your app actually spends */ +/* rendering graphics... :) */ + +static int _ecore_evas_fps_debug_init_count = 0; +static int _ecore_evas_fps_debug_fd = -1; +unsigned int *_ecore_evas_fps_rendertime_mmap = NULL; + +void +_ecore_evas_fps_debug_init(void) +{ + char buf[4096]; + const char *tmp; + + _ecore_evas_fps_debug_init_count++; + if (_ecore_evas_fps_debug_init_count > 1) return; + +#ifndef HAVE_EVIL + tmp = "/tmp"; +#else + tmp = evil_tmpdir_get (); +#endif /* HAVE_EVIL */ + snprintf(buf, sizeof(buf), "%s/.ecore_evas_fps_debug-%i", tmp, (int)getpid()); + _ecore_evas_fps_debug_fd = open(buf, O_CREAT | O_TRUNC | O_RDWR, 0644); + if (_ecore_evas_fps_debug_fd < 0) + { + unlink(buf); + _ecore_evas_fps_debug_fd = open(buf, O_CREAT | O_TRUNC | O_RDWR, 0644); + } + if (_ecore_evas_fps_debug_fd >= 0) + { + unsigned int zero = 0; + char *buf2 = (char *)&zero; + ssize_t todo = sizeof(unsigned int); + + while (todo > 0) + { + ssize_t r = write(_ecore_evas_fps_debug_fd, buf2, todo); + if (r > 0) + { + todo -= r; + buf2 += r; + } + else if ((r < 0) && (errno == EINTR)) + continue; + else + { + ERR("could not write to file '%s' fd %d: %s", + buf, _ecore_evas_fps_debug_fd, strerror(errno)); + close(_ecore_evas_fps_debug_fd); + _ecore_evas_fps_debug_fd = -1; + return; + } + } + _ecore_evas_fps_rendertime_mmap = mmap(NULL, sizeof(unsigned int), + PROT_READ | PROT_WRITE, + MAP_SHARED, + _ecore_evas_fps_debug_fd, 0); + if (_ecore_evas_fps_rendertime_mmap == MAP_FAILED) + _ecore_evas_fps_rendertime_mmap = NULL; + } +} + +void +_ecore_evas_fps_debug_shutdown(void) +{ + _ecore_evas_fps_debug_init_count--; + if (_ecore_evas_fps_debug_init_count > 0) return; + if (_ecore_evas_fps_debug_fd >= 0) + { + char buf[4096]; + + snprintf(buf, sizeof(buf), "/tmp/.ecore_evas_fps_debug-%i", (int)getpid()); + unlink(buf); + if (_ecore_evas_fps_rendertime_mmap) + { + munmap(_ecore_evas_fps_rendertime_mmap, sizeof(int)); + _ecore_evas_fps_rendertime_mmap = NULL; + } + close(_ecore_evas_fps_debug_fd); + _ecore_evas_fps_debug_fd = -1; + } +} + +void +_ecore_evas_fps_debug_rendertime_add(double t) +{ + static double rtime = 0.0; + static double rlapse = 0.0; + static int frames = 0; + static int flapse = 0; + double tim; + + tim = ecore_time_get(); + rtime += t; + frames++; + if (rlapse == 0.0) + { + rlapse = tim; + flapse = frames; + } + else if ((tim - rlapse) >= 0.5) + { + printf("FRAME: %i, FPS: %3.1f, RTIME %3.0f%%\n", + frames, + (frames - flapse) / (tim - rlapse), + (100.0 * rtime) / (tim - rlapse) + ); + rlapse = tim; + flapse = frames; + rtime = 0.0; + } +} + +void +_ecore_evas_register(Ecore_Evas *ee) +{ + ee->registered = 1; + ecore_evases = (Ecore_Evas *)eina_inlist_prepend + (EINA_INLIST_GET(ecore_evases), EINA_INLIST_GET(ee)); +} + +void +_ecore_evas_ref(Ecore_Evas *ee) +{ + ee->refcount++; +} + +void +_ecore_evas_unref(Ecore_Evas *ee) +{ + ee->refcount--; + if (ee->refcount == 0) + { + if (ee->deleted) _ecore_evas_free(ee); + } + else if (ee->refcount < -1) + ERR("Ecore_Evas %p->refcount=%d < 0", ee, ee->refcount); +} + +void +_ecore_evas_free(Ecore_Evas *ee) +{ + ee->deleted = EINA_TRUE; + if (ee->refcount > 0) return; + + if (ee->func.fn_pre_free) ee->func.fn_pre_free(ee); + while (ee->sub_ecore_evas) + { + _ecore_evas_free(ee->sub_ecore_evas->data); + } + if (ee->data) eina_hash_free(ee->data); + ee->data = NULL; + if (ee->name) free(ee->name); + ee->name = NULL; + if (ee->prop.title) free(ee->prop.title); + ee->prop.title = NULL; + if (ee->prop.name) free(ee->prop.name); + ee->prop.name = NULL; + if (ee->prop.clas) free(ee->prop.clas); + ee->prop.clas = NULL; + if (ee->prop.cursor.object) evas_object_del(ee->prop.cursor.object); + ee->prop.cursor.object = NULL; + if (ee->evas) evas_free(ee->evas); + ee->evas = NULL; + ECORE_MAGIC_SET(ee, ECORE_MAGIC_NONE); + ee->driver = NULL; + if (ee->engine.idle_flush_timer) + ecore_timer_del(ee->engine.idle_flush_timer); + if (ee->engine.func->fn_free) ee->engine.func->fn_free(ee); + if (ee->registered) + { + ecore_evases = (Ecore_Evas *)eina_inlist_remove + (EINA_INLIST_GET(ecore_evases), EINA_INLIST_GET(ee)); + } + free(ee); +} + +static Eina_Bool +_ecore_evas_cb_idle_flush(void *data) +{ + Ecore_Evas *ee; + + ee = (Ecore_Evas *)data; + evas_render_idle_flush(ee->evas); + ee->engine.idle_flush_timer = NULL; + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool +_ecore_evas_async_events_fd_handler(void *data __UNUSED__, Ecore_Fd_Handler *fd_handler __UNUSED__) +{ + evas_async_events_process(); + + return ECORE_CALLBACK_RENEW; +} + +void +_ecore_evas_idle_timeout_update(Ecore_Evas *ee) +{ + if (ee->engine.idle_flush_timer) + ecore_timer_del(ee->engine.idle_flush_timer); + ee->engine.idle_flush_timer = ecore_timer_add(IDLE_FLUSH_TIME, + _ecore_evas_cb_idle_flush, + ee); +} + +void +_ecore_evas_mouse_move_process(Ecore_Evas *ee, int x, int y, unsigned int timestamp) +{ + ee->mouse.x = x; + ee->mouse.y = y; + if (ee->prop.cursor.object) + { + evas_object_show(ee->prop.cursor.object); + if (ee->rotation == 0) + evas_object_move(ee->prop.cursor.object, + x - ee->prop.cursor.hot.x, + y - ee->prop.cursor.hot.y); + else if (ee->rotation == 90) + evas_object_move(ee->prop.cursor.object, + ee->h - y - 1 - ee->prop.cursor.hot.x, + x - ee->prop.cursor.hot.y); + else if (ee->rotation == 180) + evas_object_move(ee->prop.cursor.object, + ee->w - x - 1 - ee->prop.cursor.hot.x, + ee->h - y - 1 - ee->prop.cursor.hot.y); + else if (ee->rotation == 270) + evas_object_move(ee->prop.cursor.object, + y - ee->prop.cursor.hot.x, + ee->w - x - 1 - ee->prop.cursor.hot.y); + } + if (ee->rotation == 0) + evas_event_feed_mouse_move(ee->evas, x, y, timestamp, NULL); + else if (ee->rotation == 90) + evas_event_feed_mouse_move(ee->evas, ee->h - y - 1, x, timestamp, NULL); + else if (ee->rotation == 180) + evas_event_feed_mouse_move(ee->evas, ee->w - x - 1, ee->h - y - 1, timestamp, NULL); + else if (ee->rotation == 270) + evas_event_feed_mouse_move(ee->evas, y, ee->w - x - 1, timestamp, NULL); +} + +void +_ecore_evas_mouse_multi_move_process(Ecore_Evas *ee, int device, + int x, int y, + double radius, + double radius_x, double radius_y, + double pressure, + double angle, + double mx, double my, + unsigned int timestamp) +{ + if (ee->rotation == 0) + evas_event_feed_multi_move(ee->evas, device, + x, y, + radius, + radius_x, radius_y, + pressure, + angle - ee->rotation, + mx, my, + timestamp, NULL); + else if (ee->rotation == 90) + evas_event_feed_multi_move(ee->evas, device, + ee->h - y - 1, x, + radius, + radius_y, radius_x, + pressure, + angle - ee->rotation, + ee->h - my - 1, mx, + timestamp, NULL); + else if (ee->rotation == 180) + evas_event_feed_multi_move(ee->evas, device, + ee->w - x - 1, ee->h - y - 1, + radius, + radius_x, radius_y, + pressure, + angle - ee->rotation, + ee->w - mx - 1, ee->h - my - 1, + timestamp, NULL); + else if (ee->rotation == 270) + evas_event_feed_multi_move(ee->evas, device, + y, ee->w - x - 1, + radius, + radius_y, radius_x, + pressure, + angle - ee->rotation, + my, ee->w - mx - 1, + timestamp, NULL); +} + +void +_ecore_evas_mouse_multi_down_process(Ecore_Evas *ee, int device, + int x, int y, + double radius, + double radius_x, double radius_y, + double pressure, + double angle, + double mx, double my, + Evas_Button_Flags flags, + unsigned int timestamp) +{ + if (ee->rotation == 0) + evas_event_feed_multi_down(ee->evas, device, + x, y, + radius, + radius_x, radius_y, + pressure, + angle - ee->rotation, + mx, my, + flags, timestamp, NULL); + else if (ee->rotation == 90) + evas_event_feed_multi_down(ee->evas, device, + ee->h - y - 1, x, + radius, + radius_y, radius_x, + pressure, + angle - ee->rotation, + ee->h - my - 1, mx, + flags, timestamp, NULL); + else if (ee->rotation == 180) + evas_event_feed_multi_down(ee->evas, device, + ee->w - x - 1, ee->h - y - 1, + radius, + radius_x, radius_y, + pressure, + angle - ee->rotation, + ee->w - mx - 1, ee->h - my - 1, + flags, timestamp, NULL); + else if (ee->rotation == 270) + evas_event_feed_multi_down(ee->evas, device, + y, ee->w - x - 1, + radius, + radius_y, radius_x, + pressure, + angle - ee->rotation, + my, ee->w - mx - 1, + flags, timestamp, NULL); +} + +void +_ecore_evas_mouse_multi_up_process(Ecore_Evas *ee, int device, + int x, int y, + double radius, + double radius_x, double radius_y, + double pressure, + double angle, + double mx, double my, + Evas_Button_Flags flags, + unsigned int timestamp) +{ + if (ee->rotation == 0) + evas_event_feed_multi_up(ee->evas, device, + x, y, + radius, + radius_x, radius_y, + pressure, + angle - ee->rotation, + mx, my, + flags, timestamp, NULL); + else if (ee->rotation == 90) + evas_event_feed_multi_up(ee->evas, device, + ee->h - y - 1, x, + radius, + radius_y, radius_x, + pressure, + angle - ee->rotation, + ee->h - my - 1, mx, + flags, timestamp, NULL); + else if (ee->rotation == 180) + evas_event_feed_multi_up(ee->evas, device, + ee->w - x - 1, ee->h - y - 1, + radius, + radius_x, radius_y, + pressure, + angle - ee->rotation, + ee->w - mx - 1, ee->h - my - 1, + flags, timestamp, NULL); + else if (ee->rotation == 270) + evas_event_feed_multi_up(ee->evas, device, + y, ee->w - x - 1, + radius, + radius_y, radius_x, + pressure, + angle - ee->rotation, + my, ee->w - mx - 1, + flags, timestamp, NULL); +} + +EAPI Eina_List * +ecore_evas_ecore_evas_list_get(void) +{ + Ecore_Evas *ee; + Eina_List *l = NULL; + + EINA_INLIST_FOREACH(ecore_evases, ee) + { + l = eina_list_append(l, ee); + } + + return l; +} + +EAPI void +ecore_evas_input_event_register(Ecore_Evas *ee) +{ + ecore_event_window_register((Ecore_Window)ee, ee, ee->evas, + (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, + (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, + (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, + (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); +} + +EAPI void +ecore_evas_input_event_unregister(Ecore_Evas *ee) +{ + ecore_event_window_unregister((Ecore_Window)ee); +} + +#if defined(BUILD_ECORE_EVAS_WAYLAND_SHM) || defined (BUILD_ECORE_EVAS_WAYLAND_EGL) +EAPI void +ecore_evas_wayland_resize(Ecore_Evas *ee, int location) +{ + if (!ee) return; + if (!strcmp(ee->driver, "wayland_shm")) + { +#ifdef BUILD_ECORE_EVAS_WAYLAND_SHM + _ecore_evas_wayland_shm_resize(ee, location); +#endif + } + else if (!strcmp(ee->driver, "wayland_egl")) + { +#ifdef BUILD_ECORE_EVAS_WAYLAND_EGL + _ecore_evas_wayland_egl_resize(ee, location); +#endif + } +} + +EAPI void +ecore_evas_wayland_move(Ecore_Evas *ee, int x, int y) +{ + if (!ee) return; + if (!strcmp(ee->driver, "wayland_shm")) + { +#ifdef BUILD_ECORE_EVAS_WAYLAND_SHM + _ecore_evas_wayland_shm_move(ee, x, y); +#endif + } + else if (!strcmp(ee->driver, "wayland_egl")) + { +#ifdef BUILD_ECORE_EVAS_WAYLAND_EGL + _ecore_evas_wayland_egl_move(ee, x, y); +#endif + } +} + +EAPI void +ecore_evas_wayland_type_set(Ecore_Evas *ee, int type) +{ + if (!ee) return; + ecore_wl_window_type_set(ee->engine.wl.win, type); +} + +EAPI Ecore_Wl_Window * +ecore_evas_wayland_window_get(const Ecore_Evas *ee) +{ + if (!(!strncmp(ee->driver, "wayland", 7))) + return NULL; + + return ee->engine.wl.win; +} + +EAPI void +ecore_evas_wayland_pointer_set(Ecore_Evas *ee, int hot_x, int hot_y) +{ + Ecore_Wl_Window *win; + + win = ecore_evas_wayland_window_get(ee); + /* ecore_wl_window_pointer_set(win, ee->engine.wl.buffer, hot_x, hot_y); */ +} + +#else +EAPI void +ecore_evas_wayland_resize(Ecore_Evas *ee __UNUSED__, int location __UNUSED__) +{ + +} + +EAPI void +ecore_evas_wayland_move(Ecore_Evas *ee __UNUSED__, int x __UNUSED__, int y __UNUSED__) +{ + +} + +EAPI void +ecore_evas_wayland_type_set(Ecore_Evas *ee __UNUSED__, int type __UNUSED__) +{ + +} + +EAPI Ecore_Wl_Window * +ecore_evas_wayland_window_get(const Ecore_Evas *ee __UNUSED__) +{ + return NULL; +} + +EAPI void +ecore_evas_wayland_pointer_set(Ecore_Evas *ee __UNUSED__, int hot_x __UNUSED__, int hot_y __UNUSED__) +{ + +} +#endif diff --git a/src/lib/ecore_evas/ecore_evas_buffer.c b/src/lib/ecore_evas/ecore_evas_buffer.c new file mode 100644 index 0000000..f15436c --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas_buffer.c @@ -0,0 +1,829 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +// NOTE: if you fix this, consider fixing ecore_evas_ews.c as it is similar! +#include + +#include +#include "ecore_private.h" +#include + +#include "ecore_evas_private.h" +#include "Ecore_Evas.h" + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER +static int _ecore_evas_init_count = 0; + +static int +_ecore_evas_buffer_init(void) +{ + _ecore_evas_init_count++; + return _ecore_evas_init_count; +} + +static void +_ecore_evas_buffer_free(Ecore_Evas *ee) +{ + if (ee->engine.buffer.image) + { + Ecore_Evas *ee2; + + ee2 = evas_object_data_get(ee->engine.buffer.image, "Ecore_Evas_Parent"); + evas_object_del(ee->engine.buffer.image); + ee2->sub_ecore_evas = eina_list_remove(ee2->sub_ecore_evas, ee); + } + else + { + ee->engine.buffer.free_func(ee->engine.buffer.data, + ee->engine.buffer.pixels); + } + _ecore_evas_buffer_shutdown(); +} + +static void +_ecore_evas_resize(Ecore_Evas *ee, int w, int h) +{ + Evas_Engine_Info_Buffer *einfo; + int stride = 0; + + if (w < 1) w = 1; + if (h < 1) h = 1; + ee->req.w = w; + ee->req.h = h; + if ((w == ee->w) && (h == ee->h)) return; + ee->w = w; + ee->h = h; + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + + if (ee->engine.buffer.image) + { + ee->engine.buffer.pixels = evas_object_image_data_get(ee->engine.buffer.image, 1); + stride = evas_object_image_stride_get(ee->engine.buffer.image); + } + else + { + if (ee->engine.buffer.pixels) + ee->engine.buffer.free_func(ee->engine.buffer.data, + ee->engine.buffer.pixels); + ee->engine.buffer.pixels = + ee->engine.buffer.alloc_func(ee->engine.buffer.data, + ee->w * ee->h * sizeof(int)); + stride = ee->w * sizeof(int); + } + + einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ee->evas); + if (einfo) + { + if (ee->alpha) + einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32; + else + einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_RGB32; + einfo->info.dest_buffer = ee->engine.buffer.pixels; + einfo->info.dest_buffer_row_bytes = stride; + einfo->info.use_color_key = 0; + einfo->info.alpha_threshold = 0; + einfo->info.func.new_update_region = NULL; + einfo->info.func.free_update_region = NULL; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + } + if (ee->engine.buffer.image) + evas_object_image_data_set(ee->engine.buffer.image, ee->engine.buffer.pixels); + if (ee->func.fn_resize) ee->func.fn_resize(ee); +} + +static void +_ecore_evas_move_resize(Ecore_Evas *ee, int x __UNUSED__, int y __UNUSED__, int w, int h) +{ + _ecore_evas_resize(ee, w, h); +} + +int +_ecore_evas_buffer_shutdown(void) +{ + _ecore_evas_init_count--; + if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0; + return _ecore_evas_init_count; +} + +static void +_ecore_evas_show(Ecore_Evas *ee) +{ + if (ee->engine.buffer.image) return; + if (ee->prop.focused) return; + ee->prop.focused = 1; + evas_focus_in(ee->evas); + if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee); +} + +int +_ecore_evas_buffer_render(Ecore_Evas *ee) +{ + Eina_List *updates = NULL, *l, *ll; + Ecore_Evas *ee2; + int rend = 0; + + EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2) + { + if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2); + if (ee2->engine.func->fn_render) + rend |= ee2->engine.func->fn_render(ee2); + if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2); + } + if (ee->engine.buffer.image) + { + int w, h; + + evas_object_image_size_get(ee->engine.buffer.image, &w, &h); + if ((w != ee->w) || (h != ee->h)) + _ecore_evas_resize(ee, w, h); + ee->engine.buffer.pixels = evas_object_image_data_get(ee->engine.buffer.image, 1); + } + if (ee->engine.buffer.pixels) + { + updates = evas_render_updates(ee->evas); + } + if (ee->engine.buffer.image) + { + Eina_Rectangle *r; + + evas_object_image_data_set(ee->engine.buffer.image, ee->engine.buffer.pixels); + EINA_LIST_FOREACH(updates, l, r) + evas_object_image_data_update_add(ee->engine.buffer.image, + r->x, r->y, r->w, r->h); + } + if (updates) + { + evas_render_updates_free(updates); + _ecore_evas_idle_timeout_update(ee); + } + + return updates ? 1 : rend; +} + +// NOTE: if you fix this, consider fixing ecore_evas_ews.c as it is similar! +static void +_ecore_evas_buffer_coord_translate(Ecore_Evas *ee, Evas_Coord *x, Evas_Coord *y) +{ + Evas_Coord xx, yy, ww, hh, fx, fy, fw, fh; + + evas_object_geometry_get(ee->engine.buffer.image, &xx, &yy, &ww, &hh); + evas_object_image_fill_get(ee->engine.buffer.image, &fx, &fy, &fw, &fh); + + if (fw < 1) fw = 1; + if (fh < 1) fh = 1; + + if (evas_object_map_get(ee->engine.buffer.image) && + evas_object_map_enable_get(ee->engine.buffer.image)) + { + fx = 0; fy = 0; + fw = ee->w; fh = ee->h; + ww = ee->w; hh = ee->h; + } + + if ((fx == 0) && (fy == 0) && (fw == ww) && (fh == hh)) + { + *x = (ee->w * (*x - xx)) / fw; + *y = (ee->h * (*y - yy)) / fh; + } + else + { + xx = (*x - xx) - fx; + while (xx < 0) xx += fw; + while (xx > fw) xx -= fw; + *x = (ee->w * xx) / fw; + + yy = (*y - yy) - fy; + while (yy < 0) yy += fh; + while (yy > fh) yy -= fh; + *y = (ee->h * yy) / fh; + } +} + +static void +_ecore_evas_buffer_transfer_modifiers_locks(Evas *e, Evas *e2) +{ + const char *mods[] = + { "Shift", "Control", "Alt", "Meta", "Hyper", "Super", NULL }; + const char *locks[] = + { "Scroll_Lock", "Num_Lock", "Caps_Lock", NULL }; + int i; + + for (i = 0; mods[i]; i++) + { + if (evas_key_modifier_is_set(evas_key_modifier_get(e), mods[i])) + evas_key_modifier_on(e2, mods[i]); + else + evas_key_modifier_off(e2, mods[i]); + } + for (i = 0; locks[i]; i++) + { + if (evas_key_lock_is_set(evas_key_lock_get(e), locks[i])) + evas_key_lock_on(e2, locks[i]); + else + evas_key_lock_off(e2, locks[i]); + } +} + +static void +_ecore_evas_buffer_cb_mouse_in(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee; + Evas_Event_Mouse_In *ev; + + ee = data; + ev = event_info; + _ecore_evas_buffer_transfer_modifiers_locks(e, ee->evas); + evas_event_feed_mouse_in(ee->evas, ev->timestamp, NULL); +} + +static void +_ecore_evas_buffer_cb_mouse_out(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee; + Evas_Event_Mouse_Out *ev; + + ee = data; + ev = event_info; + _ecore_evas_buffer_transfer_modifiers_locks(e, ee->evas); + evas_event_feed_mouse_out(ee->evas, ev->timestamp, NULL); +} + +static void +_ecore_evas_buffer_cb_mouse_down(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee; + Evas_Event_Mouse_Down *ev; + + ee = data; + ev = event_info; + _ecore_evas_buffer_transfer_modifiers_locks(e, ee->evas); + evas_event_feed_mouse_down(ee->evas, ev->button, ev->flags, ev->timestamp, NULL); +} + +static void +_ecore_evas_buffer_cb_mouse_up(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee; + Evas_Event_Mouse_Up *ev; + + ee = data; + ev = event_info; + _ecore_evas_buffer_transfer_modifiers_locks(e, ee->evas); + evas_event_feed_mouse_up(ee->evas, ev->button, ev->flags, ev->timestamp, NULL); +} + +static void +_ecore_evas_buffer_cb_mouse_move(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee; + Evas_Event_Mouse_Move *ev; + Evas_Coord x, y; + + ee = data; + ev = event_info; + x = ev->cur.canvas.x; + y = ev->cur.canvas.y; + _ecore_evas_buffer_coord_translate(ee, &x, &y); + _ecore_evas_buffer_transfer_modifiers_locks(e, ee->evas); + _ecore_evas_mouse_move_process(ee, x, y, ev->timestamp); +} + +static void +_ecore_evas_buffer_cb_mouse_wheel(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee; + Evas_Event_Mouse_Wheel *ev; + + ee = data; + ev = event_info; + _ecore_evas_buffer_transfer_modifiers_locks(e, ee->evas); + evas_event_feed_mouse_wheel(ee->evas, ev->direction, ev->z, ev->timestamp, NULL); +} + +static void +_ecore_evas_buffer_cb_multi_down(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee; + Evas_Event_Multi_Down *ev; + Evas_Coord x, y, xx, yy; + double xf, yf; + + ee = data; + ev = event_info; + x = ev->canvas.x; + y = ev->canvas.y; + xx = x; + yy = y; + _ecore_evas_buffer_coord_translate(ee, &x, &y); + xf = (ev->canvas.xsub - (double)xx) + (double)x; + yf = (ev->canvas.ysub - (double)yy) + (double)y; + _ecore_evas_buffer_transfer_modifiers_locks(e, ee->evas); + evas_event_feed_multi_down(ee->evas, ev->device, x, y, ev->radius, ev->radius_x, ev->radius_y, ev->pressure, ev->angle, xf, yf, ev->flags, ev->timestamp, NULL); +} + +static void +_ecore_evas_buffer_cb_multi_up(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee; + Evas_Event_Multi_Up *ev; + Evas_Coord x, y, xx, yy; + double xf, yf; + + ee = data; + ev = event_info; + x = ev->canvas.x; + y = ev->canvas.y; + xx = x; + yy = y; + _ecore_evas_buffer_coord_translate(ee, &x, &y); + xf = (ev->canvas.xsub - (double)xx) + (double)x; + yf = (ev->canvas.ysub - (double)yy) + (double)y; + _ecore_evas_buffer_transfer_modifiers_locks(e, ee->evas); + evas_event_feed_multi_up(ee->evas, ev->device, x, y, ev->radius, ev->radius_x, ev->radius_y, ev->pressure, ev->angle, xf, yf, ev->flags, ev->timestamp, NULL); +} + +static void +_ecore_evas_buffer_cb_multi_move(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee; + Evas_Event_Multi_Move *ev; + Evas_Coord x, y, xx, yy; + double xf, yf; + + ee = data; + ev = event_info; + x = ev->cur.canvas.x; + y = ev->cur.canvas.y; + xx = x; + yy = y; + _ecore_evas_buffer_coord_translate(ee, &x, &y); + xf = (ev->cur.canvas.xsub - (double)xx) + (double)x; + yf = (ev->cur.canvas.ysub - (double)yy) + (double)y; + _ecore_evas_buffer_transfer_modifiers_locks(e, ee->evas); + evas_event_feed_multi_move(ee->evas, ev->device, x, y, ev->radius, ev->radius_x, ev->radius_y, ev->pressure, ev->angle, xf, yf, ev->timestamp, NULL); +} + +static void +_ecore_evas_buffer_cb_free(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee; + + ee = data; + if (ee->driver) _ecore_evas_free(ee); +} + +static void +_ecore_evas_buffer_cb_key_down(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee; + Evas_Event_Key_Down *ev; + + ee = data; + ev = event_info; + _ecore_evas_buffer_transfer_modifiers_locks(e, ee->evas); + evas_event_feed_key_down(ee->evas, ev->keyname, ev->key, ev->string, ev->compose, ev->timestamp, NULL); +} + +static void +_ecore_evas_buffer_cb_key_up(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee; + Evas_Event_Key_Up *ev; + + ee = data; + ev = event_info; + _ecore_evas_buffer_transfer_modifiers_locks(e, ee->evas); + evas_event_feed_key_up(ee->evas, ev->keyname, ev->key, ev->string, ev->compose, ev->timestamp, NULL); +} + +static void +_ecore_evas_buffer_cb_focus_in(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee; + + ee = data; + ee->prop.focused = 1; + evas_focus_in(ee->evas); + if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee); +} + +static void +_ecore_evas_buffer_cb_focus_out(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee; + + ee = data; + ee->prop.focused = 0; + evas_focus_out(ee->evas); + if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee); +} + +static void +_ecore_evas_buffer_cb_show(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee; + + ee = data; + ee->visible = 1; + if (ee->func.fn_show) ee->func.fn_show(ee); +} + +static void +_ecore_evas_buffer_cb_hide(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee; + + ee = data; + ee->visible = 0; + if (ee->func.fn_hide) ee->func.fn_hide(ee); +} + +static void +_ecore_evas_buffer_alpha_set(Ecore_Evas *ee, int alpha) +{ + if (((ee->alpha) && (alpha)) || ((!ee->alpha) && (!alpha))) return; + ee->alpha = alpha; + if (ee->engine.buffer.image) + evas_object_image_alpha_set(ee->engine.buffer.image, ee->alpha); + else + { + Evas_Engine_Info_Buffer *einfo; + + einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ee->evas); + if (einfo) + { + if (ee->alpha) + einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32; + else + einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_RGB32; + evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); + } + } +} + +static Ecore_Evas_Engine_Func _ecore_buffer_engine_func = +{ + _ecore_evas_buffer_free, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_resize, + _ecore_evas_move_resize, + NULL, + NULL, + _ecore_evas_show, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_buffer_alpha_set, + NULL, //transparent + NULL, // profiles_set + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + + _ecore_evas_buffer_render, + NULL, // screen_geometry_get + NULL // screen_dpi_get +}; +#endif + +static void * +_ecore_evas_buffer_pix_alloc(void *data __UNUSED__, int size) +{ + return malloc(size); +} + +static void +_ecore_evas_buffer_pix_free(void *data __UNUSED__, void *pix) +{ + free(pix); +} + +EAPI Ecore_Evas * +ecore_evas_buffer_new(int w, int h) +{ + return ecore_evas_buffer_allocfunc_new + (w, h, _ecore_evas_buffer_pix_alloc, _ecore_evas_buffer_pix_free, NULL); +} + +EAPI Ecore_Evas * +ecore_evas_buffer_allocfunc_new(int w, int h, void *(*alloc_func) (void *data, int size), void (*free_func) (void *data, void *pix), const void *data) +{ +// NOTE: if you fix this, consider fixing ecore_evas_ews.c as it is similar! +#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER + Evas_Engine_Info_Buffer *einfo; + Ecore_Evas *ee; + int rmethod; + + if ((!alloc_func) || (!free_func)) return NULL; + rmethod = evas_render_method_lookup("buffer"); + if (!rmethod) return NULL; + ee = calloc(1, sizeof(Ecore_Evas)); + if (!ee) return NULL; + + ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); + + _ecore_evas_buffer_init(); + + ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_buffer_engine_func; + ee->engine.buffer.alloc_func = alloc_func; + ee->engine.buffer.free_func = free_func; + ee->engine.buffer.data = (void *)data; + + ee->driver = "buffer"; + + if (w < 1) w = 1; + if (h < 1) h = 1; + ee->rotation = 0; + ee->visible = 1; + ee->w = w; + ee->h = h; + ee->req.w = ee->w; + ee->req.h = ee->h; + + ee->prop.max.w = 0; + ee->prop.max.h = 0; + ee->prop.layer = 0; + ee->prop.focused = 1; + ee->prop.borderless = 1; + ee->prop.override = 1; + ee->prop.maximized = 1; + ee->prop.fullscreen = 0; + ee->prop.withdrawn = 0; + ee->prop.sticky = 0; + + /* init evas here */ + ee->evas = evas_new(); + evas_data_attach_set(ee->evas, ee); + evas_output_method_set(ee->evas, rmethod); + evas_output_size_set(ee->evas, w, h); + evas_output_viewport_set(ee->evas, 0, 0, w, h); + + ee->engine.buffer.pixels = + ee->engine.buffer.alloc_func + (ee->engine.buffer.data, w * h * sizeof(int)); + + einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ee->evas); + if (einfo) + { + einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_RGB32; + einfo->info.dest_buffer = ee->engine.buffer.pixels; + einfo->info.dest_buffer_row_bytes = ee->w * sizeof(int); + einfo->info.use_color_key = 0; + einfo->info.alpha_threshold = 0; + einfo->info.func.new_update_region = NULL; + einfo->info.func.free_update_region = NULL; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + } + else + { + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + evas_key_modifier_add(ee->evas, "Shift"); + evas_key_modifier_add(ee->evas, "Control"); + evas_key_modifier_add(ee->evas, "Alt"); + evas_key_modifier_add(ee->evas, "Meta"); + evas_key_modifier_add(ee->evas, "Hyper"); + evas_key_modifier_add(ee->evas, "Super"); + evas_key_lock_add(ee->evas, "Caps_Lock"); + evas_key_lock_add(ee->evas, "Num_Lock"); + evas_key_lock_add(ee->evas, "Scroll_Lock"); + + evas_event_feed_mouse_in(ee->evas, 0, NULL); + + _ecore_evas_register(ee); + + evas_event_feed_mouse_in(ee->evas, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff), NULL); + + return ee; +#else + return NULL; +#endif +} + +EAPI const void * +ecore_evas_buffer_pixels_get(Ecore_Evas *ee) +{ +#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER + _ecore_evas_buffer_render(ee); + return ee->engine.buffer.pixels; +#else + return NULL; +#endif +} + +EAPI Evas * +ecore_evas_object_evas_get(Evas_Object *obj) +{ + Ecore_Evas *ee; + + ee = evas_object_data_get(obj, "Ecore_Evas"); + if (!ee) return NULL; + + return ecore_evas_get(ee); +} + +EAPI Ecore_Evas * +ecore_evas_object_ecore_evas_get(Evas_Object *obj) +{ + return evas_object_data_get(obj, "Ecore_Evas"); +} + +EAPI Evas_Object * +ecore_evas_object_image_new(Ecore_Evas *ee_target) +{ +// NOTE: if you fix this, consider fixing ecore_evas_ews.c as it is similar! +#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER + Evas_Object *o; + Evas_Engine_Info_Buffer *einfo; + Ecore_Evas *ee; + int rmethod; + int w = 1, h = 1; + + rmethod = evas_render_method_lookup("buffer"); + if (!rmethod) return NULL; + ee = calloc(1, sizeof(Ecore_Evas)); + if (!ee) return NULL; + + o = evas_object_image_add(ee_target->evas); + evas_object_image_content_hint_set(o, EVAS_IMAGE_CONTENT_HINT_DYNAMIC); + evas_object_image_colorspace_set(o, EVAS_COLORSPACE_ARGB8888); + evas_object_image_alpha_set(o, 0); + evas_object_image_size_set(o, w, h); + + ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); + + _ecore_evas_buffer_init(); + + ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_buffer_engine_func; + + ee->driver = "buffer"; + + ee->rotation = 0; + ee->visible = 0; + ee->w = w; + ee->h = h; + ee->req.w = ee->w; + ee->req.h = ee->h; + + ee->prop.max.w = 0; + ee->prop.max.h = 0; + ee->prop.layer = 0; + ee->prop.focused = 0; + ee->prop.borderless = 1; + ee->prop.override = 1; + ee->prop.maximized = 0; + ee->prop.fullscreen = 0; + ee->prop.withdrawn = 0; + ee->prop.sticky = 0; + + /* init evas here */ + ee->evas = evas_new(); + evas_data_attach_set(ee->evas, ee); + evas_output_method_set(ee->evas, rmethod); + evas_output_size_set(ee->evas, w, h); + evas_output_viewport_set(ee->evas, 0, 0, w, h); + + ee->engine.buffer.image = o; + evas_object_data_set(ee->engine.buffer.image, "Ecore_Evas", ee); + evas_object_data_set(ee->engine.buffer.image, "Ecore_Evas_Parent", ee_target); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_MOUSE_IN, + _ecore_evas_buffer_cb_mouse_in, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_MOUSE_OUT, + _ecore_evas_buffer_cb_mouse_out, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_MOUSE_DOWN, + _ecore_evas_buffer_cb_mouse_down, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_MOUSE_UP, + _ecore_evas_buffer_cb_mouse_up, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_MOUSE_MOVE, + _ecore_evas_buffer_cb_mouse_move, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_MOUSE_WHEEL, + _ecore_evas_buffer_cb_mouse_wheel, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_MULTI_DOWN, + _ecore_evas_buffer_cb_multi_down, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_MULTI_UP, + _ecore_evas_buffer_cb_multi_up, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_MULTI_MOVE, + _ecore_evas_buffer_cb_multi_move, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_FREE, + _ecore_evas_buffer_cb_free, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_KEY_DOWN, + _ecore_evas_buffer_cb_key_down, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_KEY_UP, + _ecore_evas_buffer_cb_key_up, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_FOCUS_IN, + _ecore_evas_buffer_cb_focus_in, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_FOCUS_OUT, + _ecore_evas_buffer_cb_focus_out, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_SHOW, + _ecore_evas_buffer_cb_show, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_HIDE, + _ecore_evas_buffer_cb_hide, ee); + einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ee->evas); + if (einfo) + { + ee->engine.buffer.pixels = evas_object_image_data_get(o, 1); + einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32; + einfo->info.dest_buffer = ee->engine.buffer.pixels; + einfo->info.dest_buffer_row_bytes = evas_object_image_stride_get(o); + einfo->info.use_color_key = 0; + einfo->info.alpha_threshold = 0; + einfo->info.func.new_update_region = NULL; + einfo->info.func.free_update_region = NULL; + evas_object_image_data_set(o, ee->engine.buffer.pixels); + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + } + else + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + evas_key_modifier_add(ee->evas, "Shift"); + evas_key_modifier_add(ee->evas, "Control"); + evas_key_modifier_add(ee->evas, "Alt"); + evas_key_modifier_add(ee->evas, "Meta"); + evas_key_modifier_add(ee->evas, "Hyper"); + evas_key_modifier_add(ee->evas, "Super"); + evas_key_lock_add(ee->evas, "Caps_Lock"); + evas_key_lock_add(ee->evas, "Num_Lock"); + evas_key_lock_add(ee->evas, "Scroll_Lock"); + + ee_target->sub_ecore_evas = eina_list_append(ee_target->sub_ecore_evas, ee); + + return o; +#else + return NULL; +#endif +} diff --git a/src/lib/ecore_evas/ecore_evas_cocoa.c b/src/lib/ecore_evas/ecore_evas_cocoa.c new file mode 100644 index 0000000..96ea1d4 --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas_cocoa.c @@ -0,0 +1,584 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "Ecore.h" +#include "ecore_private.h" +#include "Ecore_Input.h" +#include "Ecore_Input_Evas.h" + +#ifdef BUILD_ECORE_EVAS_OPENGL_COCOA +#include +#include +#endif + +#include "ecore_evas_private.h" +#include "Ecore_Evas.h" + + +#ifdef BUILD_ECORE_EVAS_OPENGL_COCOA + +// FIXME: this engine has lots of problems. only 1 window at a time, drawRect looks wrong, doesnt handle resizes and more + +static int _ecore_evas_init_count = 0; +static Ecore_Evas *ecore_evases = NULL; +static Ecore_Event_Handler *ecore_evas_event_handlers[4] = { + NULL, NULL, NULL, NULL +}; +static Ecore_Idle_Enterer *ecore_evas_idle_enterer = NULL; +static Ecore_Poller *ecore_evas_event = NULL; + +static const char *ecore_evas_cocoa_default = "EFL Cocoa"; + + +static int +_ecore_evas_cocoa_render(Ecore_Evas *ee) +{ + int rend = 0; + Eina_List *updates = NULL; + Eina_List *ll; + Ecore_Evas *ee2; + + DBG("Render"); + + EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2) + { + if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2); + if (ee2->engine.func->fn_render) + rend |= ee2->engine.func->fn_render(ee2); + if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2); + } + + if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee); + updates = evas_render_updates(ee->evas); + if (ee->prop.avoid_damage) + { + updates = evas_render_updates(ee->evas); + if (updates) evas_render_updates_free(updates); + } + else if ((ee->visible) || + ((ee->should_be_visible) && (ee->prop.fullscreen)) || + ((ee->should_be_visible) && (ee->prop.override))) + { + if (ee->shaped) + { + updates = evas_render_updates(ee->evas); + if (updates) evas_render_updates_free(updates); + } + else + { + updates = evas_render_updates(ee->evas); + if (updates) evas_render_updates_free(updates); + } + } + else + evas_norender(ee->evas); + if (updates) rend = 1; + if (ee->func.fn_post_render) ee->func.fn_post_render(ee); + + if (rend) + { + static int frames = 0; + static double t0 = 0.0; + double t, td; + + t = ecore_time_get(); + frames++; + if ((t - t0) > 1.0) + { + td = t - t0; + printf("FPS: %3.3f\n", (double)frames / td); + frames = 0; + t0 = t; + } + } + + return rend; +} + + +static Ecore_Evas * +_ecore_evas_cocoa_match(void) +{ + DBG("Match"); + return ecore_evases; +} + +static int +_ecore_evas_cocoa_event_got_focus(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + + DBG("Got Focus"); + + ee = _ecore_evas_cocoa_match(); + + if (!ee) return ECORE_CALLBACK_PASS_ON; + ee->prop.focused = 1; + evas_focus_in(ee->evas); + if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee); + + return ECORE_CALLBACK_PASS_ON; +} + +static int +_ecore_evas_cocoa_event_lost_focus(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + + DBG("Lost Focus"); + + ee = _ecore_evas_cocoa_match(); + + if (!ee) return ECORE_CALLBACK_PASS_ON; + evas_focus_out(ee->evas); + ee->prop.focused = 0; + if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee); + + return ECORE_CALLBACK_PASS_ON; +} + +static int +_ecore_evas_cocoa_event_video_resize(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + /*Ecore_Cocoa_Event_Video_Resize *e; + Ecore_Evas *ee; + + e = event; + ee = _ecore_evas_cocoa_match(); + + if (!ee) return 1; // pass on event + evas_output_size_set(ee->evas, e->w, e->h); + + return 0;*/ + + DBG("Video Resize"); + return ECORE_CALLBACK_PASS_ON; +} + +static int +_ecore_evas_cocoa_event_video_expose(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__) +{ + Ecore_Evas *ee; + int w; + int h; + + DBG("Video Expose"); + + ee = _ecore_evas_cocoa_match(); + + if (!ee) return ECORE_CALLBACK_PASS_ON; + evas_output_size_get(ee->evas, &w, &h); + evas_damage_rectangle_add(ee->evas, 0, 0, w, h); + + return ECORE_CALLBACK_PASS_ON; +} + +static int +_ecore_evas_idle_enter(void *data __UNUSED__) +{ + Ecore_Evas *ee; + double t1 = 0.; + double t2 = 0.; + + DBG("Idle enter"); + + EINA_INLIST_FOREACH(ecore_evases, ee) + { + if (ee->visible) + evas_render(ee->evas); + else + evas_norender(ee->evas); + } + + return EINA_TRUE; +} + +static int +_ecore_evas_cocoa_event(void *data) +{ + // ecore_cocoa_feed_events(); + + DBG("Cocoa Event"); + + return 1; +} + +static int +_ecore_evas_cocoa_init(void) +{ + DBG("Cocoa Init"); + _ecore_evas_init_count++; + if (_ecore_evas_init_count > 1) + return _ecore_evas_init_count; + + ecore_evas_event_handlers[0] = ecore_event_handler_add(ECORE_COCOA_EVENT_GOT_FOCUS, _ecore_evas_cocoa_event_got_focus, NULL); + ecore_evas_event_handlers[1] = ecore_event_handler_add(ECORE_COCOA_EVENT_LOST_FOCUS, _ecore_evas_cocoa_event_lost_focus, NULL); + ecore_evas_event_handlers[2] = ecore_event_handler_add(ECORE_COCOA_EVENT_RESIZE, _ecore_evas_cocoa_event_video_resize, NULL); + ecore_evas_event_handlers[3] = ecore_event_handler_add(ECORE_COCOA_EVENT_EXPOSE, _ecore_evas_cocoa_event_video_expose, NULL); + + ecore_event_evas_init(); + return _ecore_evas_init_count; +} + +static int +_ecore_evas_cocoa_shutdown(void) +{ + DBG("Cocoa SHutodwn"); + _ecore_evas_init_count--; + if (_ecore_evas_init_count == 0) + { + int i; + + while (ecore_evases) _ecore_evas_free(ecore_evases); + + for (i = 0; i < sizeof (ecore_evas_event_handlers) / sizeof (Ecore_Event_Handler*); i++) + ecore_event_handler_del(ecore_evas_event_handlers[i]); + ecore_event_evas_shutdown(); + ecore_idle_enterer_del(ecore_evas_idle_enterer); + ecore_evas_idle_enterer = NULL; + ecore_poller_del(ecore_evas_event); + ecore_evas_event = NULL; + + ecore_event_evas_shutdown(); + } + if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0; + return _ecore_evas_init_count; +} + +static void +_ecore_evas_cocoa_free(Ecore_Evas *ee) +{ + DBG("Cocoa Free"); + ecore_evases = (Ecore_Evas *) eina_inlist_remove(EINA_INLIST_GET(ecore_evases), EINA_INLIST_GET(ee)); + ecore_event_window_unregister(0); + _ecore_evas_cocoa_shutdown(); + ecore_cocoa_shutdown(); +} + +static void +_ecore_evas_resize(Ecore_Evas *ee, int w, int h) +{ + DBG("Resize"); + if ((w == ee->w) && (h == ee->h)) return; + ee->w = w; + ee->h = h; + + printf("Ecore_Evas Resize %d %d\n", w, h); + + ecore_cocoa_window_resize(ee->prop.window, w, h); + + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + + if (ee->func.fn_resize) ee->func.fn_resize(ee); +} + +static void +_ecore_evas_move_resize(Ecore_Evas *ee, int x, int y, int w, int h) +{ + DBG("Move Resize"); + if ((w == ee->w) && (h == ee->h)) return; + ee->w = w; + ee->h = h; + + ecore_cocoa_window_move_resize(ee->prop.window, x, y, w, h); + + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + + if (ee->func.fn_resize) ee->func.fn_resize(ee); +} + + +static void +_ecore_evas_show(Ecore_Evas *ee, int x, int y, int w, int h) +{ + DBG("Show"); + ee->should_be_visible = 1; + if (ee->prop.avoid_damage) + _ecore_evas_cocoa_render(ee); + + ecore_cocoa_window_show(ee->prop.window); + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); +} + + +static void +_ecore_evas_hide(Ecore_Evas *ee, int x, int y, int w, int h) +{ + DBG("Hide"); + + ecore_cocoa_window_hide(ee->prop.window); + ee->should_be_visible = 0; +} + +static void +_ecore_evas_title_set(Ecore_Evas *ee, const char *title) +{ + INF("ecore evas title set"); + + if (ee->prop.title) free(ee->prop.title); + ee->prop.title = NULL; + if (title) ee->prop.title = strdup(title); + ecore_cocoa_window_title_set(ee->prop.window, + ee->prop.title); +} + +static void +_ecore_evas_object_cursor_del(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + Ecore_Evas *ee; + + DBG("Cursor DEL"); + + ee = data; + if (ee) + ee->prop.cursor.object = NULL; +} + +static void +_ecore_evas_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y) +{ + int x, y; + DBG("Cursor Set"); + if (ee->prop.cursor.object) evas_object_del(ee->prop.cursor.object); + + if (obj == NULL) + { + ee->prop.cursor.object = NULL; + ee->prop.cursor.layer = 0; + ee->prop.cursor.hot.x = 0; + ee->prop.cursor.hot.y = 0; + return; + } + + ee->prop.cursor.object = obj; + ee->prop.cursor.layer = layer; + ee->prop.cursor.hot.x = hot_x; + ee->prop.cursor.hot.y = hot_y; + + evas_pointer_output_xy_get(ee->evas, &x, &y); + evas_object_layer_set(ee->prop.cursor.object, ee->prop.cursor.layer); + evas_object_move(ee->prop.cursor.object, + x - ee->prop.cursor.hot.x, + y - ee->prop.cursor.hot.y); + + evas_object_pass_events_set(ee->prop.cursor.object, 1); + + if (evas_pointer_inside_get(ee->evas)) + evas_object_show(ee->prop.cursor.object); + + evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _ecore_evas_object_cursor_del, ee); +} + +static int +_ecore_evas_engine_cocoa_init(Ecore_Evas *ee) +{ + Evas_Engine_Info_GL_Cocoa *einfo; + const char *driver; + int rmethod; + + DBG("Cocoa Init"); + + driver = "gl_cocoa"; + + rmethod = evas_render_method_lookup(driver); + if (!rmethod) + return 0; + + ee->driver = driver; + evas_output_method_set(ee->evas, rmethod); + + einfo = (Evas_Engine_Info_GL_Cocoa *)evas_engine_info_get(ee->evas); + if (einfo) + { + /* FIXME: REDRAW_DEBUG missing for now */ + einfo->window = ee->prop.window; + //einfo->info.depth = ecore_win32_screen_depth_get(); + //einfo->info.rotation = 0; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + return 0; + } + ecore_cocoa_window_view_set(einfo->window, einfo->view); + } + else + { + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); + return 0; + } + + return 1; +} + +static Ecore_Evas_Engine_Func _ecore_cocoa_engine_func = + { + _ecore_evas_cocoa_free, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, //move + NULL, + _ecore_evas_resize, + _ecore_evas_move_resize, + NULL, //rotation + NULL, //shaped + _ecore_evas_show, + _ecore_evas_hide, + NULL, //raise + NULL, //lower + NULL, //activate + _ecore_evas_title_set, + NULL, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_object_cursor_set, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, //transparent + NULL, // profiles_set + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + + NULL, // render + NULL, + NULL // screen_dpi_get + }; +#endif + +EAPI Ecore_Evas * +ecore_evas_cocoa_new(Ecore_Cocoa_Window *parent, int x, int y, int w, int h) +{ +#ifdef BUILD_ECORE_EVAS_OPENGL_COCOA + Evas_Engine_Info_GL_Cocoa *einfo; + Ecore_Evas *ee; + int rmethod; + + DBG("Cocoa new"); + + if (!ecore_cocoa_init()) + return NULL; + + ee = calloc(1, sizeof(Ecore_Evas)); + if (!ee) + goto shutdown_ecore_cocoa; + + ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); + + _ecore_evas_cocoa_init(); + + ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_cocoa_engine_func; + + if (w < 1) w = 1; + if (h < 1) h = 1; + ee->visible = 1; + ee->x = x; + ee->y = y; + ee->w = w; + ee->h = h; + ee->req.x = ee->x; + ee->req.y = ee->y; + ee->req.w = ee->w; + ee->req.h = ee->h; + + ee->semi_sync = 1; + + + ee->prop.max.w = 32767; + ee->prop.max.h = 32767; + ee->prop.layer = 4; + ee->prop.request_pos = 0; + ee->prop.sticky = 0; + ee->prop.window = 0; + + printf("Create New Evas\n"); + + ee->evas = evas_new(); + + if (!ee->evas) + goto free_name; + + evas_data_attach_set(ee->evas, ee); + evas_output_method_set(ee->evas, rmethod); + evas_output_size_set(ee->evas, w, h); + evas_output_viewport_set(ee->evas, 0, 0, w, h); + + printf("Create New Cocoa Window\n"); + ee->prop.window = (Ecore_Cocoa_Window*)ecore_cocoa_window_new(x, y, w, h); + printf("Window Created %p\n", ee->prop.window); + if (!ee->prop.window) + { + _ecore_evas_cocoa_shutdown(); + free(ee); + return NULL; + } + + printf("Init Evas engine cocoa\n"); + if (!_ecore_evas_engine_cocoa_init(ee)) + { + _ecore_evas_cocoa_shutdown(); + free(ee); + return NULL; + } + + + ee->engine.func->fn_render = _ecore_evas_cocoa_render; + _ecore_evas_register(ee); + ecore_event_window_register(0, ee, ee->evas, NULL, NULL, NULL, NULL); + + evas_event_feed_mouse_in(ee->evas, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff), NULL); + printf("Ecore Evas returned : %p\n", ee); + return ee; + + free_window: + /* FIXME: free window here */ + free_evas: + free(ee->evas); + free_name: + free(ee->name); + free_ee: + _ecore_evas_cocoa_shutdown(); + free(ee); + shutdown_ecore_cocoa: + ecore_cocoa_shutdown(); + + return NULL; +#else + ERR("Cocoa support in ecore-evas not enabled"); + return NULL; + (void) parent; + (void) x; (void) y; (void) w; (void) h; +#endif +} diff --git a/src/lib/ecore_evas/ecore_evas_directfb.c b/src/lib/ecore_evas/ecore_evas_directfb.c new file mode 100644 index 0000000..d9fb237 --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas_directfb.c @@ -0,0 +1,606 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include +#include "ecore_private.h" +#ifdef BUILD_ECORE_EVAS_DIRECTFB +#include +#endif + +#include "ecore_evas_private.h" +#include "Ecore_Evas.h" + +#ifdef BUILD_ECORE_EVAS_DIRECTFB +static int _ecore_evas_init_count = 0; +static Ecore_Event_Handler *ecore_evas_event_handlers[13]; + +static Eina_Hash *ecore_evases_hash = NULL; + +static int +_ecore_evas_directfb_render(Ecore_Evas *ee) +{ + Eina_List *updates, *ll; + Ecore_Evas *ee2; + int rend = 0; + + EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2) + { + if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2); + if (ee2->engine.func->fn_render) + rend |= ee2->engine.func->fn_render(ee2); + if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2); + } + + if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee); + updates = evas_render_updates(ee->evas); + if (updates) + { + evas_render_updates_free(updates); + _ecore_evas_idle_timeout_update(ee); + } + if (ee->func.fn_post_render) ee->func.fn_post_render(ee); + + return updates ? 1 : rend; +} + +static char * +_ecore_evas_directfb_winid_str_get(Ecore_X_Window win) +{ + const char *vals = "qWeRtYuIoP5$&<~"; + static char id[9]; + unsigned int val; + val = (unsigned int)win; + id[0] = vals[(val >> 28) & 0xf]; + id[1] = vals[(val >> 24) & 0xf]; + id[2] = vals[(val >> 20) & 0xf]; + id[3] = vals[(val >> 16) & 0xf]; + id[4] = vals[(val >> 12) & 0xf]; + id[5] = vals[(val >> 8) & 0xf]; + id[6] = vals[(val >> 4) & 0xf]; + id[7] = vals[(val ) & 0xf]; + id[8] = 0; + return id; +} + +static Ecore_Evas * +_ecore_evas_directfb_match(DFBWindowID win) +{ + Ecore_Evas *ee; + + ee = eina_hash_find(ecore_evases_hash, _ecore_evas_directfb_winid_str_get(win)); + return ee; +} + +static Eina_Bool +_ecore_evas_directfb_event_key_down(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_DirectFB_Event_Key_Down *e; + + e = event; + ee = _ecore_evas_directfb_match(e->win); + + if (!ee) return EINA_TRUE; /* pass on event */ + evas_event_feed_key_down(ee->evas, e->name, e->name, e->string, + e->key_compose, e->time, NULL); + return EINA_TRUE; +} + +static Eina_Bool +_ecore_evas_directfb_event_key_up(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_DirectFB_Event_Key_Up *e; + + e = event; + ee = _ecore_evas_directfb_match(e->win); + + if (!ee) return EINA_TRUE; /* pass on event */ + evas_event_feed_key_up(ee->evas, e->name, e->name, e->string, + e->key_compose, e->time, NULL); + return EINA_TRUE; +} + +static Eina_Bool +_ecore_evas_directfb_event_motion(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_DirectFB_Event_Motion *e; + + e = event; + ee = _ecore_evas_directfb_match(e->win); + + if (!ee) return EINA_TRUE; /* pass on event */ + _ecore_evas_mouse_move_process(ee, e->x, e->y, e->time); + return EINA_TRUE; +} + +static Eina_Bool +_ecore_evas_directfb_event_button_down(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_DirectFB_Event_Button_Down *e; + + e = event; + ee = _ecore_evas_directfb_match(e->win); + + if (!ee) return EINA_TRUE; /* pass on event */ + // _ecore_evas_mouse_move_process(ee, e->x, e->y, e->time); + evas_event_feed_mouse_down(ee->evas, e->button, EVAS_BUTTON_NONE, e->time, NULL); + return EINA_TRUE; +} + +static Eina_Bool +_ecore_evas_directfb_event_button_up(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_DirectFB_Event_Button_Up *e; + Evas_Button_Flags flags = EVAS_BUTTON_NONE; + + e = event; + ee = _ecore_evas_directfb_match(e->win); + + if (!ee) return EINA_TRUE; /* pass on event */ + //_ecore_evas_mouse_move_process(ee, e->x, e->y, e->time); + evas_event_feed_mouse_up(ee->evas, e->button, flags, e->time, NULL); + return EINA_TRUE; +} + +static Eina_Bool +_ecore_evas_directfb_event_enter(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_DirectFB_Event_Enter *e; + + e = event; + ee = _ecore_evas_directfb_match(e->win); + + if (!ee) return EINA_TRUE; /* pass on event */ + evas_event_feed_mouse_in(ee->evas, e->time, NULL); + //_ecore_evas_mouse_move_process(ee, e->x, e->y, e->time); + return EINA_TRUE; +} + +static Eina_Bool +_ecore_evas_directfb_event_leave(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_DirectFB_Event_Leave *e; + + e = event; + ee = _ecore_evas_directfb_match(e->win); + + if (!ee) return EINA_TRUE; /* pass on event */ + evas_event_feed_mouse_out(ee->evas, e->time, NULL); + //_ecore_evas_mouse_move_process(ee, e->x, e->y, e->time); + if (ee->func.fn_mouse_out) ee->func.fn_mouse_out(ee); + if (ee->prop.cursor.object) evas_object_hide(ee->prop.cursor.object); + return EINA_TRUE; +} + +static Eina_Bool +_ecore_evas_directfb_event_wheel(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_DirectFB_Event_Wheel *e; + + e = event; + ee = _ecore_evas_directfb_match(e->win); + + if (!ee) return EINA_TRUE; /* pass on event */ + evas_event_feed_mouse_wheel(ee->evas, e->direction, e->z, e->time, NULL); + return EINA_TRUE; +} + +static Eina_Bool +_ecore_evas_directfb_event_got_focus(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_DirectFB_Event_Got_Focus *e; + + e = event; + ee = _ecore_evas_directfb_match(e->win); + + if (!ee) return EINA_TRUE; /* pass on event */ + ee->prop.focused = 1; + return EINA_TRUE; +} + +static Eina_Bool +_ecore_evas_directfb_event_lost_focus(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_DirectFB_Event_Lost_Focus *e; + + e = event; + ee = _ecore_evas_directfb_match(e->win); + + if (!ee) return EINA_TRUE; /* pass on event */ + ee->prop.focused = 0; + return EINA_TRUE; +} + +int +_ecore_evas_directfb_shutdown(void) +{ + _ecore_evas_init_count--; + if (_ecore_evas_init_count == 0) + { + int i; + + for (i = 0; i < 8; i++) + ecore_event_handler_del(ecore_evas_event_handlers[i]); + } + if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0; + return _ecore_evas_init_count; +} + + + + + +int +_ecore_evas_directfb_init(void) +{ + _ecore_evas_init_count++; + if (_ecore_evas_init_count > 1) return _ecore_evas_init_count; + + ecore_evas_event_handlers[0] = ecore_event_handler_add(ECORE_DIRECTFB_EVENT_KEY_DOWN, _ecore_evas_directfb_event_key_down, NULL); + ecore_evas_event_handlers[1] = ecore_event_handler_add(ECORE_DIRECTFB_EVENT_KEY_UP, _ecore_evas_directfb_event_key_up, NULL); + ecore_evas_event_handlers[2] = ecore_event_handler_add(ECORE_DIRECTFB_EVENT_BUTTON_DOWN, _ecore_evas_directfb_event_button_down, NULL); + ecore_evas_event_handlers[3] = ecore_event_handler_add(ECORE_DIRECTFB_EVENT_BUTTON_UP, _ecore_evas_directfb_event_button_up, NULL); + ecore_evas_event_handlers[4] = ecore_event_handler_add(ECORE_DIRECTFB_EVENT_MOTION, _ecore_evas_directfb_event_motion, NULL); + ecore_evas_event_handlers[5] = ecore_event_handler_add(ECORE_DIRECTFB_EVENT_ENTER, _ecore_evas_directfb_event_enter, NULL); + ecore_evas_event_handlers[6] = ecore_event_handler_add(ECORE_DIRECTFB_EVENT_LEAVE, _ecore_evas_directfb_event_leave, NULL); + ecore_evas_event_handlers[7] = ecore_event_handler_add(ECORE_DIRECTFB_EVENT_WHEEL, _ecore_evas_directfb_event_wheel, NULL); + ecore_evas_event_handlers[8] = ecore_event_handler_add(ECORE_DIRECTFB_EVENT_GOT_FOCUS, _ecore_evas_directfb_event_got_focus, NULL); + ecore_evas_event_handlers[9] = ecore_event_handler_add(ECORE_DIRECTFB_EVENT_LOST_FOCUS, _ecore_evas_directfb_event_lost_focus, NULL); + ecore_evas_event_handlers[10] = NULL; + ecore_evas_event_handlers[11] = NULL; + ecore_evas_event_handlers[12] = NULL; + + return _ecore_evas_init_count; +} + +/* engine functions */ +/********************/ + +static void +_ecore_evas_directfb_free(Ecore_Evas *ee) +{ + eina_hash_del(ecore_evases_hash, _ecore_evas_directfb_winid_str_get(ee->engine.directfb.window->id), ee); + ecore_directfb_window_free(ee->engine.directfb.window); + _ecore_evas_directfb_shutdown(); + ecore_directfb_shutdown(); +} + +static void +_ecore_evas_directfb_move(Ecore_Evas *ee, int x, int y) +{ + ecore_directfb_window_move(ee->engine.directfb.window, x, y); +} + +static void +_ecore_evas_directfb_resize(Ecore_Evas *ee, int w, int h) +{ + ee->req.w = w; + ee->req.h = h; + if ((w == ee->w) && (h == ee->h)) return; + ecore_directfb_window_resize(ee->engine.directfb.window, w, h); + ee->w = w; + ee->h = h; + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + evas_output_size_set(ee->evas, ee->h, ee->w); + evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w); + } + else + { + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + } +} + +static void +_ecore_evas_directfb_focus_set(Ecore_Evas *ee, int on __UNUSED__) +{ + ecore_directfb_window_focus(ee->engine.directfb.window); +} + +static void +_ecore_evas_directfb_hide(Ecore_Evas *ee) +{ + ecore_directfb_window_hide(ee->engine.directfb.window); + ee->should_be_visible = 0; +} + +static void +_ecore_evas_directfb_show(Ecore_Evas *ee) +{ + ecore_directfb_window_show(ee->engine.directfb.window); + ee->should_be_visible = 1; +} + +static void +_ecore_evas_directfb_shaped_set(Ecore_Evas *ee, int shaped) +{ + if (((ee->shaped) && (shaped)) || ((!ee->shaped) && (!shaped))) + return; + ee->shaped = shaped; + if(ee->shaped) + ecore_directfb_window_shaped_set(ee->engine.directfb.window, 1); + else + ecore_directfb_window_shaped_set(ee->engine.directfb.window, 0); + +} + +static void +_ecore_evas_object_cursor_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee; + + ee = data; + if (ee) + ee->prop.cursor.object = NULL; +} + +static void +_ecore_evas_directfb_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y) +{ + int x, y; + + if (ee->prop.cursor.object) evas_object_del(ee->prop.cursor.object); + + if (!obj) + { + ee->prop.cursor.object = NULL; + ee->prop.cursor.layer = 0; + ee->prop.cursor.hot.x = 0; + ee->prop.cursor.hot.y = 0; + ecore_directfb_window_cursor_show(ee->engine.directfb.window, 1); + return; + + } + + ee->prop.cursor.object = obj; + ee->prop.cursor.layer = layer; + ee->prop.cursor.hot.x = hot_x; + ee->prop.cursor.hot.y = hot_y; + + ecore_directfb_window_cursor_show(ee->engine.directfb.window, 0); + + evas_pointer_output_xy_get(ee->evas, &x, &y); + evas_object_layer_set(ee->prop.cursor.object, ee->prop.cursor.layer); + evas_object_move(ee->prop.cursor.object,x - ee->prop.cursor.hot.x,y - ee->prop.cursor.hot.y); + evas_object_pass_events_set(ee->prop.cursor.object, 1); + if (evas_pointer_inside_get(ee->evas)) + evas_object_show(ee->prop.cursor.object); + + evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _ecore_evas_object_cursor_del, ee); +} + +static void +_ecore_evas_directfb_fullscreen_set(Ecore_Evas *ee, int on) +{ + Evas_Engine_Info_DirectFB *einfo; + int w; + int h; + int resized = 0; + + if (((ee->prop.fullscreen) && (on)) || ((!ee->prop.fullscreen) && (!on))) + return; + + if (on) + ecore_directfb_window_fullscreen_set(ee->engine.directfb.window, 1); + else + ecore_directfb_window_fullscreen_set(ee->engine.directfb.window, 0); + /* set the new size of the evas */ + ecore_directfb_window_size_get(ee->engine.directfb.window, &w, &h); + if( (ee->w != w) || (ee->h != h)) + { + resized = 1; + ee->w = w; + ee->h = h; + ee->req.w = ee->w; + ee->req.h = ee->h; + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + evas_output_size_set(ee->evas, ee->h, ee->w); + evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w); + } + else + { + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + } + } + einfo = (Evas_Engine_Info_DirectFB *)evas_engine_info_get(ee->evas); + if (einfo) + { + einfo->info.surface = ee->engine.directfb.window->surface; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + } + ee->prop.fullscreen = on; + if (resized) + { + if(ee->func.fn_resize) ee->func.fn_resize(ee); + } +} + +static void * +_ecore_evas_directfb_window_get(const Ecore_Evas *ee) +{ + return ee->engine.directfb.window; +} +#endif + +#ifdef BUILD_ECORE_EVAS_DIRECTFB +static Ecore_Evas_Engine_Func _ecore_directfb_engine_func = +{ + _ecore_evas_directfb_free, /* free an ecore_evas */ + NULL, /* cb resize */ + NULL, /* cb move */ + NULL, /* cb show */ + NULL, /* cb hide */ + NULL, /* cb delete request */ + NULL, /* cb destroy */ + NULL, /* cb focus in */ + NULL, /* cb focus out */ + NULL, /* cb sticky */ + NULL, /* cb unsticky */ + NULL, /* cb mouse in */ + NULL, /* cb mouse out */ + NULL, /* cb pre render */ + NULL, /* cb post render */ + _ecore_evas_directfb_move, /* move */ + NULL, /* managed move */ + _ecore_evas_directfb_resize, /* resize */ + NULL, /* move resize */ + NULL,//_ecore_evas_directfb_rotation_set,/* rotation */ + _ecore_evas_directfb_shaped_set, /* shaped */ + _ecore_evas_directfb_show, /* show */ + _ecore_evas_directfb_hide, /* hide */ + NULL, /* raise */ + NULL, /* lower */ + NULL, /* activate */ + NULL, /* title set */ + NULL, /* name class set */ + NULL, /* size min */ + NULL, /* size max */ + NULL, /* size base */ + NULL, /* size step */ + _ecore_evas_directfb_object_cursor_set, /* set cursor to an evas object */ + NULL, /* layer set */ + _ecore_evas_directfb_focus_set, /* focus */ + NULL, /* iconified */ + NULL, /* borderless */ + NULL, /* override */ + NULL, /* maximized */ + _ecore_evas_directfb_fullscreen_set,/* fullscreen */ + NULL, /* avoid damage */ + NULL, /* withdrawn */ + NULL, /* sticky */ + NULL, /* ignore events */ + NULL, /* alpha */ + NULL, //transparent + NULL, // profiles_set + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + + NULL, // render + NULL, // screen_geometry_get + NULL // screen_dpi_get +}; +#endif + +/* api */ +/*******/ + +#ifdef BUILD_ECORE_EVAS_DIRECTFB +EAPI Ecore_Evas * +ecore_evas_directfb_new(const char *disp_name, int windowed, int x, int y, int w, int h) +{ + Evas_Engine_Info_DirectFB *einfo; + Ecore_Evas *ee; + Ecore_DirectFB_Window *window; + int rmethod; + + rmethod = evas_render_method_lookup("directfb"); + if (!rmethod) return NULL; + if (!ecore_directfb_init(disp_name)) return NULL; + ee = calloc(1, sizeof(Ecore_Evas)); + if (!ee) return NULL; + + ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); + _ecore_evas_directfb_init(); + ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_directfb_engine_func; + + ee->driver = "directfb"; + if (disp_name) ee->name = strdup(disp_name); + + if (w < 1) w = 1; + if (h < 1) h = 1; + + ee->rotation = 0; + ee->visible = 1; + ee->x = x; + ee->y = y; + ee->w = w; + ee->h = h; + ee->req.x = ee->x; + ee->req.y = ee->y; + ee->req.w = ee->w; + ee->req.h = ee->h; + ee->prop.layer = 1; + ee->prop.fullscreen = 0; + + /* init evas here */ + ee->evas = evas_new(); + evas_data_attach_set(ee->evas, ee); + evas_output_method_set(ee->evas, rmethod); + evas_output_size_set(ee->evas, w, h); + evas_output_viewport_set(ee->evas, 0, 0, w, h); + einfo = (Evas_Engine_Info_DirectFB *)evas_engine_info_get(ee->evas); + + window = ecore_directfb_window_new(x,y,w,h); + ee->engine.directfb.window = window; + if (einfo) + { + einfo->info.dfb = ecore_directfb_interface_get(); + einfo->info.surface = window->surface; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + } + else + { + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + + ee->engine.func->fn_render = _ecore_evas_directfb_render; + _ecore_evas_register(ee); + + if (!ecore_evases_hash) + ecore_evases_hash = eina_hash_string_superfast_new(NULL); + eina_hash_add(ecore_evases_hash, _ecore_evas_directfb_winid_str_get(ee->engine.directfb.window->id), ee); + + return ee; +} +#else +EAPI Ecore_Evas * +ecore_evas_directfb_new(const char *disp_name __UNUSED__, int windowed __UNUSED__, int x __UNUSED__, int y __UNUSED__, int w __UNUSED__, int h __UNUSED__) +{ + return NULL; +} +#endif + +#ifdef BUILD_ECORE_EVAS_DIRECTFB +EAPI Ecore_DirectFB_Window * +ecore_evas_directfb_window_get(const Ecore_Evas *ee) +{ + if (!(!strcmp(ee->driver, "directfb"))) return 0; + return (Ecore_DirectFB_Window *) _ecore_evas_directfb_window_get(ee); +} +#else +EAPI Ecore_DirectFB_Window * +ecore_evas_directfb_window_get(const Ecore_Evas *ee __UNUSED__) +{ + return NULL; +} +#endif diff --git a/src/lib/ecore_evas/ecore_evas_ews.c b/src/lib/ecore_evas/ecore_evas_ews.c new file mode 100644 index 0000000..d6969cf --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas_ews.c @@ -0,0 +1,1469 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include +#include +#include "ecore_private.h" +#include + +#include "ecore_evas_private.h" +#include "Ecore_Evas.h" + +EAPI int ECORE_EVAS_EWS_EVENT_MANAGER_CHANGE = 0; +EAPI int ECORE_EVAS_EWS_EVENT_ADD = 0; +EAPI int ECORE_EVAS_EWS_EVENT_DEL = 0; +EAPI int ECORE_EVAS_EWS_EVENT_RESIZE = 0; +EAPI int ECORE_EVAS_EWS_EVENT_MOVE = 0; +EAPI int ECORE_EVAS_EWS_EVENT_SHOW = 0; +EAPI int ECORE_EVAS_EWS_EVENT_HIDE = 0; +EAPI int ECORE_EVAS_EWS_EVENT_FOCUS = 0; +EAPI int ECORE_EVAS_EWS_EVENT_UNFOCUS = 0; +EAPI int ECORE_EVAS_EWS_EVENT_RAISE = 0; +EAPI int ECORE_EVAS_EWS_EVENT_LOWER = 0; +EAPI int ECORE_EVAS_EWS_EVENT_ACTIVATE = 0; + +EAPI int ECORE_EVAS_EWS_EVENT_ICONIFIED_CHANGE = 0; +EAPI int ECORE_EVAS_EWS_EVENT_MAXIMIZED_CHANGE = 0; +EAPI int ECORE_EVAS_EWS_EVENT_LAYER_CHANGE = 0; +EAPI int ECORE_EVAS_EWS_EVENT_FULLSCREEN_CHANGE = 0; +EAPI int ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE = 0; + +#ifdef BUILD_ECORE_EVAS_EWS +static int _ecore_evas_init_count = 0; + +static Ecore_Evas *_ews_ee = NULL; +static Evas_Object *_ews_bg = NULL; +static Eina_List *_ews_children = NULL; +static const void *_ews_manager = NULL; +static char *_ews_engine = NULL; +static char *_ews_options = NULL; +static int _ews_x = 0; +static int _ews_y = 0; +static int _ews_w = 1024; +static int _ews_h = 768; +static Eina_Bool _ews_defaults_engine = EINA_TRUE; +static Eina_Bool _ews_defaults_geo = EINA_TRUE; + +static const char EWS_ENGINE_NAME[] = "ews"; + +static void +_ecore_evas_ews_pre_free(Ecore_Evas *ee __UNUSED__) +{ + DBG("EWS backing store free'd"); + _ews_children = eina_list_free(_ews_children); + _ews_ee = NULL; + _ews_bg = NULL; +} + +static void +_ecore_evas_ews_del_request(Ecore_Evas *ee __UNUSED__) +{ + INF("EWS backing store deletion is forbidden!"); +} + +static Ecore_Evas * +_ecore_evas_ews_ee_new(void) +{ + Ecore_Evas *ee = ecore_evas_new(_ews_engine, _ews_x, _ews_y, _ews_w, _ews_h, + _ews_options); + if (!ee) + ERR("Failed: ecore_evas_new(%s, %d, %d, %d, %d, %s)", + _ews_engine, _ews_x, _ews_y, _ews_w, _ews_h, _ews_options); + else + { + ecore_evas_size_min_set(ee, _ews_w, _ews_h); + ecore_evas_size_max_set(ee, _ews_w, _ews_h); + ecore_evas_callback_pre_free_set(ee, _ecore_evas_ews_pre_free); + ecore_evas_callback_delete_request_set(ee, _ecore_evas_ews_del_request); + ecore_evas_name_class_set(ee, "ecore_evas_ews", "ews"); + ecore_evas_title_set + (ee, "EWS: Ecore + Evas Single Process Windowing System"); + ecore_evas_show(ee); + } + + return ee; +} + +static void +_ecore_evas_ews_env_setup(void) +{ + const char *env = getenv("ECORE_EVAS_EWS"); + char *p, *n, *tmp; + + if (_ews_defaults_engine) + { + free(_ews_engine); + _ews_engine = NULL; + free(_ews_options); + _ews_options = NULL; + } + if (_ews_defaults_geo) + { + _ews_x = 0; + _ews_y = 0; + _ews_w = 1024; + _ews_h = 768; + } + + if ((!env) || (!*env)) return; + + p = tmp = strdup(env); + if (!tmp) return; + + n = strchr(p, ':'); + if (n) *n = '\0'; + if (_ews_defaults_engine) _ews_engine = strdup(p); + if (!n) goto end; + + p = n + 1; + n = strchr(p, ':'); + if (!n) goto end; + *n = '\0'; + if (_ews_defaults_geo) _ews_x = atoi(p); + + p = n + 1; + n = strchr(p, ':'); + if (!n) goto end; + *n = '\0'; + if (_ews_defaults_geo) _ews_y = atoi(p); + + p = n + 1; + n = strchr(p, ':'); + if (!n) goto end; + *n = '\0'; + if (_ews_defaults_geo) _ews_w = atoi(p); + + p = n + 1; + n = strchr(p, ':'); + if (n) *n = '\0'; + if (_ews_defaults_geo) _ews_h = atoi(p); + if (!n) goto end; + + p = n + 1; + if (_ews_defaults_engine) _ews_options = strdup(p); + + end: + free(tmp); +} + +static void +_ecore_evas_ews_event_free(void *data __UNUSED__, void *ev) +{ + Ecore_Evas *ee = ev; + _ecore_evas_unref(ee); +} + +static void +_ecore_evas_ews_event(Ecore_Evas *ee, int event) +{ + _ecore_evas_ref(ee); + ecore_event_add(event, ee, _ecore_evas_ews_event_free, NULL); +} + +static void +_ecore_evas_ews_event_free_del(void *data __UNUSED__, void *ev __UNUSED__) +{ + _ecore_evas_ews_shutdown(); +} + +static void +_ecore_evas_ews_free(Ecore_Evas *ee) +{ + evas_object_del(ee->engine.ews.image); + _ews_ee->sub_ecore_evas = eina_list_remove(_ews_ee->sub_ecore_evas, ee); + + ecore_event_add(ECORE_EVAS_EWS_EVENT_DEL, ee, _ecore_evas_ews_event_free_del, NULL); +} + +static void +_ecore_evas_ews_move(Ecore_Evas *ee, int x, int y) +{ + ee->req.x = x; + ee->req.y = y; + + if ((x == ee->x) && (y == ee->y)) return; + ee->x = x; + ee->y = y; + evas_object_move(ee->engine.ews.image, x, y); + if (ee->func.fn_move) ee->func.fn_move(ee); + + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_MOVE); +} + +static void +_ecore_evas_ews_managed_move(Ecore_Evas *ee, int x, int y) +{ + ee->req.x = x; + ee->req.y = y; + + if ((x == ee->x) && (y == ee->y)) return; + ee->x = x; + ee->y = y; + if (ee->func.fn_move) ee->func.fn_move(ee); + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_MOVE); +} + +static void +_ecore_evas_ews_resize_internal(Ecore_Evas *ee, int w, int h) +{ + Evas_Engine_Info_Buffer *einfo; + void *pixels; + int stride; + + evas_output_size_set(ee->evas, w, h); + evas_output_viewport_set(ee->evas, 0, 0, w, h); + evas_damage_rectangle_add(ee->evas, 0, 0, w, h); + + evas_object_image_size_set(ee->engine.ews.image, w, h); + evas_object_image_fill_set(ee->engine.ews.image, 0, 0, w, h); + evas_object_resize(ee->engine.ews.image, w, h); + + pixels = evas_object_image_data_get(ee->engine.ews.image, 1); + evas_object_image_data_set(ee->engine.ews.image, pixels); // refcount + stride = evas_object_image_stride_get(ee->engine.ews.image); + + einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ee->evas); + EINA_SAFETY_ON_NULL_RETURN(einfo); + + einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32; + einfo->info.dest_buffer = pixels; + einfo->info.dest_buffer_row_bytes = stride; + einfo->info.use_color_key = 0; + einfo->info.alpha_threshold = 0; + einfo->info.func.new_update_region = NULL; + einfo->info.func.free_update_region = NULL; + evas_object_image_data_set(ee->engine.ews.image, pixels); + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } +} + +static void +_ecore_evas_ews_resize(Ecore_Evas *ee, int w, int h) +{ + if (w < 1) w = 1; + if (h < 1) h = 1; + + ee->req.w = w; + ee->req.h = h; + + if ((w == ee->w) && (h == ee->h)) return; + ee->w = w; + ee->h = h; + _ecore_evas_ews_resize_internal(ee, w, h); + if (ee->func.fn_resize) ee->func.fn_resize(ee); + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_RESIZE); +} + +static void +_ecore_evas_ews_move_resize(Ecore_Evas *ee, int x, int y, int w, int h) +{ + _ecore_evas_ews_move(ee, x, y); + _ecore_evas_ews_resize(ee, w, h); +} + +static void +_ecore_evas_ews_rotation_set(Ecore_Evas *ee, int rot, int resize __UNUSED__) +{ + if (ee->rotation == rot) return; + ee->rotation = rot; + + ERR("TODO: rot=%d, resize=%d", rot, resize); + + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE); +} + +static void +_ecore_evas_ews_shaped_set(Ecore_Evas *ee, int val) +{ + if (ee->shaped == val) return; + ee->shaped = val; + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE); +} + +static void +_ecore_evas_ews_show(Ecore_Evas *ee) +{ + ee->should_be_visible = EINA_TRUE; + evas_object_show(ee->engine.ews.image); + if (ee->prop.fullscreen) + evas_object_focus_set(ee->engine.ews.image, EINA_TRUE); + + if (ee->func.fn_show) ee->func.fn_show(ee); + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_SHOW); +} + +static void +_ecore_evas_ews_hide(Ecore_Evas *ee) +{ + ee->should_be_visible = EINA_FALSE; + evas_object_hide(ee->engine.ews.image); + + if (ee->func.fn_hide) ee->func.fn_hide(ee); + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_HIDE); +} + +static void +_ecore_evas_ews_raise(Ecore_Evas *ee) +{ + evas_object_raise(ee->engine.ews.image); + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_RAISE); +} + +static void +_ecore_evas_ews_lower(Ecore_Evas *ee) +{ + evas_object_lower(ee->engine.ews.image); + evas_object_lower(_ews_bg); + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_LOWER); +} + +static void +_ecore_evas_ews_activate(Ecore_Evas *ee) +{ + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_ACTIVATE); +} + +static void +_ecore_evas_ews_title_set(Ecore_Evas *ee, const char *t) +{ + if (ee->prop.title) free(ee->prop.title); + ee->prop.title = NULL; + if (t) ee->prop.title = strdup(t); + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE); +} + +static void +_ecore_evas_ews_name_class_set(Ecore_Evas *ee, const char *n, const char *c) +{ + if (ee->prop.name) free(ee->prop.name); + if (ee->prop.clas) free(ee->prop.clas); + ee->prop.name = NULL; + ee->prop.clas = NULL; + if (n) ee->prop.name = strdup(n); + if (c) ee->prop.clas = strdup(c); + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE); +} + +static void +_ecore_evas_ews_size_min_set(Ecore_Evas *ee, int w, int h) +{ + if (w < 0) w = 0; + if (h < 0) h = 0; + if ((ee->prop.min.w == w) && (ee->prop.min.h == h)) return; + ee->prop.min.w = w; + ee->prop.min.h = h; + evas_object_size_hint_min_set(ee->engine.ews.image, w, h); + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE); +} + +static void +_ecore_evas_ews_size_max_set(Ecore_Evas *ee, int w, int h) +{ + if (w < 0) w = 0; + if (h < 0) h = 0; + if ((ee->prop.max.w == w) && (ee->prop.max.h == h)) return; + ee->prop.max.w = w; + ee->prop.max.h = h; + evas_object_size_hint_max_set(ee->engine.ews.image, w, h); + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE); +} + +static void +_ecore_evas_ews_size_base_set(Ecore_Evas *ee, int w, int h) +{ + if (w < 0) w = 0; + if (h < 0) h = 0; + if ((ee->prop.base.w == w) && (ee->prop.base.h == h)) return; + ee->prop.base.w = w; + ee->prop.base.h = h; + evas_object_size_hint_request_set(ee->engine.ews.image, w, h); + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE); +} + +static void +_ecore_evas_ews_size_step_set(Ecore_Evas *ee, int w, int h) +{ + if (w < 1) w = 1; + if (h < 1) h = 1; + if ((ee->prop.step.w == w) && (ee->prop.step.h == h)) return; + ee->prop.step.w = w; + ee->prop.step.h = h; + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE); +} + +static void +_ecore_evas_ews_object_cursor_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee = data; + ee->prop.cursor.object = NULL; +} + +static void +_ecore_evas_ews_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y) +{ + int x, y; + + if (ee->prop.cursor.object) evas_object_del(ee->prop.cursor.object); + + if (!obj) + { + ee->prop.cursor.object = NULL; + ee->prop.cursor.layer = 0; + ee->prop.cursor.hot.x = 0; + ee->prop.cursor.hot.y = 0; + return; + } + + ee->prop.cursor.object = obj; + ee->prop.cursor.layer = layer; + ee->prop.cursor.hot.x = hot_x; + ee->prop.cursor.hot.y = hot_y; + evas_pointer_output_xy_get(ee->evas, &x, &y); + evas_object_layer_set(ee->prop.cursor.object, ee->prop.cursor.layer); + evas_object_move(ee->prop.cursor.object, + x - ee->prop.cursor.hot.x, + y - ee->prop.cursor.hot.y); + evas_object_pass_events_set(ee->prop.cursor.object, 1); + if (evas_pointer_inside_get(ee->evas)) + evas_object_show(ee->prop.cursor.object); + + evas_object_event_callback_add + (obj, EVAS_CALLBACK_DEL, _ecore_evas_ews_object_cursor_del, ee); + + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE); +} + +static void +_ecore_evas_ews_layer_set(Ecore_Evas *ee, int layer) +{ + if (layer < EVAS_LAYER_MIN + 1) + layer = EVAS_LAYER_MIN + 1; + else if (layer > EVAS_LAYER_MAX) + layer = EVAS_LAYER_MAX; + + if (ee->prop.layer == layer) return; + ee->prop.layer = layer; + evas_object_layer_set(ee->engine.ews.image, layer); + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_LAYER_CHANGE); +} + +static void +_ecore_evas_ews_focus_set(Ecore_Evas *ee, int val) +{ + evas_object_focus_set(ee->engine.ews.image, val); + ee->prop.focused = val; + if (val) + { + evas_focus_in(ee->evas); + if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee); + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_FOCUS); + } + else + { + evas_focus_out(ee->evas); + if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee); + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_UNFOCUS); + } +} + +static void +_ecore_evas_ews_iconified_set(Ecore_Evas *ee, int val) +{ + if (ee->prop.iconified == val) return; + ee->prop.iconified = val; + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_ICONIFIED_CHANGE); +} + +static void +_ecore_evas_ews_borderless_set(Ecore_Evas *ee, int val) +{ + if (ee->prop.borderless == val) return; + ee->prop.borderless = val; + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE); +} + +static void +_ecore_evas_ews_override_set(Ecore_Evas *ee, int val) +{ + if (ee->prop.override == val) return; + if (ee->visible) evas_object_show(ee->engine.ews.image); + if (ee->prop.focused) evas_object_focus_set(ee->engine.ews.image, EINA_TRUE); + ee->prop.override = val; + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE); +} + +static void +_ecore_evas_ews_maximized_set(Ecore_Evas *ee, int val) +{ + if (ee->prop.maximized == val) return; + ee->prop.maximized = val; + if (val) evas_object_show(ee->engine.ews.image); + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_MAXIMIZED_CHANGE); +} + +static void +_ecore_evas_ews_fullscreen_set(Ecore_Evas *ee, int val) +{ + if (ee->prop.fullscreen == val) return; + ee->prop.fullscreen = val; + + if (!val) + { + evas_object_move(ee->engine.ews.image, ee->x, ee->y); + evas_object_resize(ee->engine.ews.image, ee->w, ee->h); + } + else + { + Evas_Coord w, h; + ecore_evas_geometry_get(_ews_ee, NULL, NULL, &w, &h); + evas_object_move(ee->engine.ews.image, 0, 0); + evas_object_resize(ee->engine.ews.image, w, h); + evas_object_focus_set(ee->engine.ews.image, EINA_TRUE); + } + + if (ee->should_be_visible) + evas_object_show(ee->engine.ews.image); + else + evas_object_hide(ee->engine.ews.image); + + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_FULLSCREEN_CHANGE); +} + +static void +_ecore_evas_ews_avoid_damage_set(Ecore_Evas *ee, int val) +{ + if (ee->prop.avoid_damage == val) return; + ee->prop.avoid_damage = val; + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE); +} + +static void +_ecore_evas_ews_withdrawn_set(Ecore_Evas *ee, int val) +{ + if (ee->prop.withdrawn == val) return; + ee->prop.withdrawn = val; + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE); +} + +static void +_ecore_evas_ews_sticky_set(Ecore_Evas *ee, int val) +{ + if (ee->prop.sticky == val) return; + ee->prop.sticky = val; + if ((val) && (ee->func.fn_sticky)) ee->func.fn_sticky(ee); + else if ((!val) && (ee->func.fn_unsticky)) ee->func.fn_unsticky(ee); + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE); +} + +static void +_ecore_evas_ews_ignore_events_set(Ecore_Evas *ee, int val) +{ + if (ee->ignore_events == val) return; + ee->ignore_events = val; + evas_object_pass_events_set(ee->engine.ews.image, val); + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE); +} + +static void +_ecore_evas_ews_alpha_set(Ecore_Evas *ee, int val) +{ + if (ee->alpha == val) return; + ee->alpha = val; + evas_object_image_alpha_set(ee->engine.ews.image, val); + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE); +} + +static void +_ecore_evas_ews_transparent_set(Ecore_Evas *ee, int val) +{ + if (ee->transparent == val) return; + ee->transparent = val; + evas_object_image_alpha_set(ee->engine.ews.image, val); + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE); +} + +static int +_ecore_evas_ews_render(Ecore_Evas *ee) +{ + Eina_List *updates = NULL, *l, *ll; + Ecore_Evas *ee2; + Eina_Rectangle *r; + int w, h, rend = 0; + void *pixels; + + EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2) + { + if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2); + rend |= _ecore_evas_ews_render(ee2); + if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2); + } + + evas_object_image_size_get(ee->engine.ews.image, &w, &h); + if ((w != ee->w) || (h != ee->h)) + ecore_evas_resize(ee, w, h); + + pixels = evas_object_image_data_get(ee->engine.ews.image, 1); + if (pixels) + { + updates = evas_render_updates(ee->evas); + } + evas_object_image_data_set(ee->engine.ews.image, pixels); + + EINA_LIST_FOREACH(updates, l, r) + evas_object_image_data_update_add(ee->engine.ews.image, + r->x, r->y, r->w, r->h); + + if (updates) + { + evas_render_updates_free(updates); + _ecore_evas_idle_timeout_update(ee); + } + + return updates ? 1 : rend; +} + +static void +_ecore_evas_ews_screen_geometry_get(const Ecore_Evas *ee __UNUSED__, int *x, int *y, int *w, int *h) +{ + ecore_evas_geometry_get(_ews_ee, x, y, w, h); +} + +static const Ecore_Evas_Engine_Func _ecore_ews_engine_func = +{ + _ecore_evas_ews_free, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_ews_move, + _ecore_evas_ews_managed_move, + _ecore_evas_ews_resize, + _ecore_evas_ews_move_resize, + _ecore_evas_ews_rotation_set, + _ecore_evas_ews_shaped_set, + _ecore_evas_ews_show, + _ecore_evas_ews_hide, + _ecore_evas_ews_raise, + _ecore_evas_ews_lower, + _ecore_evas_ews_activate, + _ecore_evas_ews_title_set, + _ecore_evas_ews_name_class_set, + _ecore_evas_ews_size_min_set, + _ecore_evas_ews_size_max_set, + _ecore_evas_ews_size_base_set, + _ecore_evas_ews_size_step_set, + _ecore_evas_ews_object_cursor_set, + _ecore_evas_ews_layer_set, + _ecore_evas_ews_focus_set, + _ecore_evas_ews_iconified_set, + _ecore_evas_ews_borderless_set, + _ecore_evas_ews_override_set, + _ecore_evas_ews_maximized_set, + _ecore_evas_ews_fullscreen_set, + _ecore_evas_ews_avoid_damage_set, + _ecore_evas_ews_withdrawn_set, + _ecore_evas_ews_sticky_set, + _ecore_evas_ews_ignore_events_set, + _ecore_evas_ews_alpha_set, + _ecore_evas_ews_transparent_set, + NULL, // profiles_set + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + + _ecore_evas_ews_render, + _ecore_evas_ews_screen_geometry_get, + NULL // screen_dpi_get +}; + +void +_ecore_evas_ews_events_init(void) +{ + if (ECORE_EVAS_EWS_EVENT_MANAGER_CHANGE != 0) return; + ECORE_EVAS_EWS_EVENT_MANAGER_CHANGE = ecore_event_type_new(); + ECORE_EVAS_EWS_EVENT_ADD = ecore_event_type_new(); + ECORE_EVAS_EWS_EVENT_DEL = ecore_event_type_new(); + ECORE_EVAS_EWS_EVENT_RESIZE = ecore_event_type_new(); + ECORE_EVAS_EWS_EVENT_MOVE = ecore_event_type_new(); + ECORE_EVAS_EWS_EVENT_SHOW = ecore_event_type_new(); + ECORE_EVAS_EWS_EVENT_HIDE = ecore_event_type_new(); + ECORE_EVAS_EWS_EVENT_FOCUS = ecore_event_type_new(); + ECORE_EVAS_EWS_EVENT_UNFOCUS = ecore_event_type_new(); + ECORE_EVAS_EWS_EVENT_RAISE = ecore_event_type_new(); + ECORE_EVAS_EWS_EVENT_LOWER = ecore_event_type_new(); + ECORE_EVAS_EWS_EVENT_ACTIVATE = ecore_event_type_new(); + ECORE_EVAS_EWS_EVENT_ICONIFIED_CHANGE = ecore_event_type_new(); + ECORE_EVAS_EWS_EVENT_MAXIMIZED_CHANGE = ecore_event_type_new(); + ECORE_EVAS_EWS_EVENT_LAYER_CHANGE = ecore_event_type_new(); + ECORE_EVAS_EWS_EVENT_FULLSCREEN_CHANGE = ecore_event_type_new(); + ECORE_EVAS_EWS_EVENT_CONFIG_CHANGE = ecore_event_type_new(); +} + +static int +_ecore_evas_ews_init(void) +{ + _ecore_evas_init_count++; + if (_ecore_evas_init_count > 1) return _ecore_evas_init_count; + + _ecore_evas_ews_env_setup(); + + return _ecore_evas_init_count; +} + +int +_ecore_evas_ews_shutdown(void) +{ + _ecore_evas_init_count--; + if (_ecore_evas_init_count == 0) + { + if (_ews_ee) + { + ecore_evas_free(_ews_ee); + _ews_ee = NULL; + } + if (_ews_children) + { + eina_list_free(_ews_children); + _ews_children = NULL; + } + + free(_ews_engine); + _ews_engine = NULL; + free(_ews_options); + _ews_options = NULL; + _ews_defaults_engine = EINA_TRUE; + _ews_defaults_geo = EINA_TRUE; + + } + if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0; + return _ecore_evas_init_count; +} + +static void +_ecore_evas_ews_coord_translate(Ecore_Evas *ee, Evas_Coord *x, Evas_Coord *y) +{ + Evas_Coord xx, yy, ww, hh, fx, fy, fw, fh; + + evas_object_geometry_get(ee->engine.ews.image, &xx, &yy, &ww, &hh); + evas_object_image_fill_get(ee->engine.ews.image, &fx, &fy, &fw, &fh); + + if (fw < 1) fw = 1; + if (fh < 1) fh = 1; + + if ((fx == 0) && (fy == 0) && (fw == ww) && (fh == hh)) + { + *x = (ee->w * (*x - xx)) / fw; + *y = (ee->h * (*y - yy)) / fh; + } + else + { + xx = (*x - xx) - fx; + while (xx < 0) xx += fw; + while (xx > fw) xx -= fw; + *x = (ee->w * xx) / fw; + + yy = (*y - yy) - fy; + while (yy < 0) yy += fh; + while (yy > fh) yy -= fh; + *y = (ee->h * yy) / fh; + } +} + +static void +_ecore_evas_ews_modifiers_apply(Ecore_Evas *ee, const Evas_Modifier *modifier) +{ + Evas *e = ee->evas; + + if (evas_key_modifier_is_set(modifier, "Shift")) + evas_key_modifier_on(e, "Shift"); + else evas_key_modifier_off(e, "Shift"); + + if (evas_key_modifier_is_set(modifier, "Control")) + evas_key_modifier_on(e, "Control"); + else evas_key_modifier_off(e, "Control"); + + if (evas_key_modifier_is_set(modifier, "Alt")) + evas_key_modifier_on(e, "Alt"); + else evas_key_modifier_off(e, "Alt"); + + if (evas_key_modifier_is_set(modifier, "Super")) + evas_key_modifier_on(e, "Super"); + else evas_key_modifier_off(e, "Super"); + + if (evas_key_modifier_is_set(modifier, "Hyper")) + evas_key_modifier_on(e, "Hyper"); + else evas_key_modifier_off(e, "Hyper"); + + if (evas_key_modifier_is_set(modifier, "Scroll_Lock")) + evas_key_lock_on(e, "Scroll_Lock"); + else evas_key_lock_off(e, "Scroll_Lock"); + + if (evas_key_modifier_is_set(modifier, "Num_Lock")) + evas_key_lock_on(e, "Num_Lock"); + else evas_key_lock_off(e, "Num_Lock"); + + if (evas_key_modifier_is_set(modifier, "Caps_Lock")) + evas_key_lock_on(e, "Caps_Lock"); + else evas_key_lock_off(e, "Caps_Lock"); + + if (evas_key_modifier_is_set(modifier, "Shift_Lock")) + evas_key_lock_on(e, "Shift_Lock"); + else evas_key_lock_off(e, "Shift_Lock"); +} + +static void +_ecore_evas_ews_cb_mouse_in(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee = data; + Evas_Event_Mouse_In *ev = event_info; + Evas_Coord x = ev->canvas.x; + Evas_Coord y = ev->canvas.y; + _ecore_evas_ews_coord_translate(ee, &x, &y); + if (ee->func.fn_mouse_in) ee->func.fn_mouse_in(ee); + _ecore_evas_ews_modifiers_apply(ee, ev->modifiers); + evas_event_feed_mouse_in(ee->evas, ev->timestamp, NULL); + _ecore_evas_mouse_move_process(ee, x, y, ev->timestamp); +} + +static void +_ecore_evas_ews_cb_mouse_out(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee = data; + Evas_Event_Mouse_Out *ev = event_info; + Evas_Coord x = ev->canvas.x; + Evas_Coord y = ev->canvas.y; + // TODO: consider grab mode in EWS + _ecore_evas_ews_coord_translate(ee, &x, &y); + if (ee->func.fn_mouse_out) ee->func.fn_mouse_out(ee); + _ecore_evas_ews_modifiers_apply(ee, ev->modifiers); + evas_event_feed_mouse_out(ee->evas, ev->timestamp, NULL); + if (ee->prop.cursor.object) evas_object_hide(ee->prop.cursor.object); + _ecore_evas_mouse_move_process(ee, x, y, ev->timestamp); +} + +static void +_ecore_evas_ews_cb_mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee = data; + Evas_Event_Mouse_Down *ev = event_info; + _ecore_evas_ews_modifiers_apply(ee, ev->modifiers); + evas_event_feed_mouse_down(ee->evas, ev->button, ev->flags, ev->timestamp, NULL); +} + +static void +_ecore_evas_ews_cb_mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee = data; + Evas_Event_Mouse_Up *ev = event_info; + _ecore_evas_ews_modifiers_apply(ee, ev->modifiers); + evas_event_feed_mouse_up(ee->evas, ev->button, ev->flags, ev->timestamp, NULL); +} + +static void +_ecore_evas_ews_cb_mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee = data; + Evas_Event_Mouse_Move *ev = event_info; + Evas_Coord x = ev->cur.canvas.x; + Evas_Coord y = ev->cur.canvas.y; + _ecore_evas_ews_coord_translate(ee, &x, &y); + _ecore_evas_ews_modifiers_apply(ee, ev->modifiers); + _ecore_evas_mouse_move_process(ee, x, y, ev->timestamp); +} + +static void +_ecore_evas_ews_cb_mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee = data; + Evas_Event_Mouse_Wheel *ev = event_info; + _ecore_evas_ews_modifiers_apply(ee, ev->modifiers); + evas_event_feed_mouse_wheel(ee->evas, ev->direction, ev->z, ev->timestamp, NULL); +} + +static void +_ecore_evas_ews_cb_multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee = data; + Evas_Event_Multi_Down *ev = event_info; + Evas_Coord x, y, xx, yy; + double xf, yf; + + x = ev->canvas.x; + y = ev->canvas.y; + xx = x; + yy = y; + _ecore_evas_ews_coord_translate(ee, &x, &y); + xf = (ev->canvas.xsub - (double)xx) + (double)x; + yf = (ev->canvas.ysub - (double)yy) + (double)y; + _ecore_evas_ews_modifiers_apply(ee, ev->modifiers); + evas_event_feed_multi_down(ee->evas, ev->device, x, y, ev->radius, ev->radius_x, ev->radius_y, ev->pressure, ev->angle, xf, yf, ev->flags, ev->timestamp, NULL); +} + +static void +_ecore_evas_ews_cb_multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee = data; + Evas_Event_Multi_Up *ev = event_info; + Evas_Coord x, y, xx, yy; + double xf, yf; + + x = ev->canvas.x; + y = ev->canvas.y; + xx = x; + yy = y; + _ecore_evas_ews_coord_translate(ee, &x, &y); + xf = (ev->canvas.xsub - (double)xx) + (double)x; + yf = (ev->canvas.ysub - (double)yy) + (double)y; + _ecore_evas_ews_modifiers_apply(ee, ev->modifiers); + evas_event_feed_multi_up(ee->evas, ev->device, x, y, ev->radius, ev->radius_x, ev->radius_y, ev->pressure, ev->angle, xf, yf, ev->flags, ev->timestamp, NULL); +} + +static void +_ecore_evas_ews_cb_multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee = data; + Evas_Event_Multi_Move *ev = event_info; + Evas_Coord x, y, xx, yy; + double xf, yf; + + x = ev->cur.canvas.x; + y = ev->cur.canvas.y; + xx = x; + yy = y; + _ecore_evas_ews_coord_translate(ee, &x, &y); + xf = (ev->cur.canvas.xsub - (double)xx) + (double)x; + yf = (ev->cur.canvas.ysub - (double)yy) + (double)y; + _ecore_evas_ews_modifiers_apply(ee, ev->modifiers); + evas_event_feed_multi_move(ee->evas, ev->device, x, y, ev->radius, ev->radius_x, ev->radius_y, ev->pressure, ev->angle, xf, yf, ev->timestamp, NULL); +} + +static void +_ecore_evas_ews_cb_free(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee = data; + if (ee->driver) _ecore_evas_free(ee); +} + +static void +_ecore_evas_ews_cb_key_down(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee = data; + Evas_Event_Key_Down *ev = event_info; + + if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Shift")) + evas_key_modifier_on(ee->evas, "Shift"); + else + evas_key_modifier_off(ee->evas, "Shift"); + if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Control")) + evas_key_modifier_on(ee->evas, "Control"); + else + evas_key_modifier_off(ee->evas, "Control"); + if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Alt")) + evas_key_modifier_on(ee->evas, "Alt"); + else + evas_key_modifier_off(ee->evas, "Alt"); + if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Meta")) + evas_key_modifier_on(ee->evas, "Meta"); + else + evas_key_modifier_off(ee->evas, "Meta"); + if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Hyper")) + evas_key_modifier_on(ee->evas, "Hyper"); + else + evas_key_modifier_off(ee->evas, "Hyper"); + if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Super")) + evas_key_modifier_on(ee->evas, "Super"); + else + evas_key_modifier_off(ee->evas, "Super"); + if (evas_key_lock_is_set(evas_key_lock_get(e), "Scroll_Lock")) + evas_key_lock_on(ee->evas, "Scroll_Lock"); + else + evas_key_lock_off(ee->evas, "Scroll_Lock"); + if (evas_key_lock_is_set(evas_key_lock_get(e), "Num_Lock")) + evas_key_lock_on(ee->evas, "Num_Lock"); + else + evas_key_lock_off(ee->evas, "Num_Lock"); + if (evas_key_lock_is_set(evas_key_lock_get(e), "Caps_Lock")) + evas_key_lock_on(ee->evas, "Caps_Lock"); + else + evas_key_lock_off(ee->evas, "Caps_Lock"); + evas_event_feed_key_down(ee->evas, ev->keyname, ev->key, ev->string, ev->compose, ev->timestamp, NULL); +} + +static void +_ecore_evas_ews_cb_key_up(void *data, Evas *e, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee = data; + Evas_Event_Key_Up *ev = event_info; + + if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Shift")) + evas_key_modifier_on(ee->evas, "Shift"); + else + evas_key_modifier_off(ee->evas, "Shift"); + if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Control")) + evas_key_modifier_on(ee->evas, "Control"); + else + evas_key_modifier_off(ee->evas, "Control"); + if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Alt")) + evas_key_modifier_on(ee->evas, "Alt"); + else + evas_key_modifier_off(ee->evas, "Alt"); + if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Meta")) + evas_key_modifier_on(ee->evas, "Meta"); + else + evas_key_modifier_off(ee->evas, "Meta"); + if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Hyper")) + evas_key_modifier_on(ee->evas, "Hyper"); + else + evas_key_modifier_off(ee->evas, "Hyper"); + if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Super")) + evas_key_modifier_on(ee->evas, "Super"); + else + evas_key_modifier_off(ee->evas, "Super"); + if (evas_key_lock_is_set(evas_key_lock_get(e), "Scroll_Lock")) + evas_key_lock_on(ee->evas, "Scroll_Lock"); + else + evas_key_lock_off(ee->evas, "Scroll_Lock"); + if (evas_key_lock_is_set(evas_key_lock_get(e), "Num_Lock")) + evas_key_lock_on(ee->evas, "Num_Lock"); + else + evas_key_lock_off(ee->evas, "Num_Lock"); + if (evas_key_lock_is_set(evas_key_lock_get(e), "Caps_Lock")) + evas_key_lock_on(ee->evas, "Caps_Lock"); + else + evas_key_lock_off(ee->evas, "Caps_Lock"); + evas_event_feed_key_up(ee->evas, ev->keyname, ev->key, ev->string, ev->compose, ev->timestamp, NULL); +} + +static void +_ecore_evas_ews_cb_focus_in(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee = data; + ecore_evas_focus_set(ee, EINA_TRUE); +} + +static void +_ecore_evas_ews_cb_focus_out(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee = data; + if (ee->deleted) return; + ecore_evas_focus_set(ee, EINA_FALSE); +} + +static void +_ecore_evas_ews_cb_show(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee = data; + ecore_evas_show(ee); +} + +static void +_ecore_evas_ews_cb_hide(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee = data; + if (ee->deleted) return; + ecore_evas_hide(ee); +} +#endif + +EAPI Ecore_Evas * +ecore_evas_ews_new(int x, int y, int w, int h) +{ +// basically a copy of ecore_evas_buffer_new() keep in sync... +#ifdef BUILD_ECORE_EVAS_EWS + Evas_Object *o; + Evas_Engine_Info_Buffer *einfo; + Ecore_Evas *ee; + int rmethod; + + if (_ecore_evas_ews_init() < 1) return NULL; + + if (!_ews_ee) _ews_ee = _ecore_evas_ews_ee_new(); + if (!_ews_ee) + { + ERR("Could not create EWS backing store"); + _ecore_evas_ews_shutdown(); + return NULL; + } + + rmethod = evas_render_method_lookup("buffer"); + if (!rmethod) return NULL; + ee = calloc(1, sizeof(Ecore_Evas)); + if (!ee) return NULL; + + if (w < 1) w = 1; + if (h < 1) h = 1; + + o = evas_object_image_add(_ews_ee->evas); + evas_object_image_content_hint_set(o, EVAS_IMAGE_CONTENT_HINT_DYNAMIC); + evas_object_image_colorspace_set(o, EVAS_COLORSPACE_ARGB8888); + evas_object_image_size_set(o, w, h); + evas_object_image_alpha_set(o, 1); + + ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); + + ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_ews_engine_func; + + ee->driver = EWS_ENGINE_NAME; + + ee->x = 0; + ee->y = 0; + ee->w = w; + ee->h = h; + ee->req.x = ee->x; + ee->req.y = ee->y; + ee->req.w = ee->w; + ee->req.h = ee->h; + + /* init evas here */ + ee->evas = evas_new(); + evas_data_attach_set(ee->evas, ee); + evas_output_method_set(ee->evas, rmethod); + evas_output_size_set(ee->evas, w, h); + evas_output_viewport_set(ee->evas, 0, 0, w, h); + + evas_object_move(o, x, y); + evas_object_resize(o, w, h); + evas_object_image_fill_set(o, 0, 0, w, h); + + ee->engine.ews.image = o; + evas_object_data_set(ee->engine.ews.image, "Ecore_Evas", ee); + evas_object_event_callback_add(ee->engine.ews.image, + EVAS_CALLBACK_MOUSE_IN, + _ecore_evas_ews_cb_mouse_in, ee); + evas_object_event_callback_add(ee->engine.ews.image, + EVAS_CALLBACK_MOUSE_OUT, + _ecore_evas_ews_cb_mouse_out, ee); + evas_object_event_callback_add(ee->engine.ews.image, + EVAS_CALLBACK_MOUSE_DOWN, + _ecore_evas_ews_cb_mouse_down, ee); + evas_object_event_callback_add(ee->engine.ews.image, + EVAS_CALLBACK_MOUSE_UP, + _ecore_evas_ews_cb_mouse_up, ee); + evas_object_event_callback_add(ee->engine.ews.image, + EVAS_CALLBACK_MOUSE_MOVE, + _ecore_evas_ews_cb_mouse_move, ee); + evas_object_event_callback_add(ee->engine.ews.image, + EVAS_CALLBACK_MOUSE_WHEEL, + _ecore_evas_ews_cb_mouse_wheel, ee); + evas_object_event_callback_add(ee->engine.ews.image, + EVAS_CALLBACK_MULTI_DOWN, + _ecore_evas_ews_cb_multi_down, ee); + evas_object_event_callback_add(ee->engine.ews.image, + EVAS_CALLBACK_MULTI_UP, + _ecore_evas_ews_cb_multi_up, ee); + evas_object_event_callback_add(ee->engine.ews.image, + EVAS_CALLBACK_MULTI_MOVE, + _ecore_evas_ews_cb_multi_move, ee); + evas_object_event_callback_add(ee->engine.ews.image, + EVAS_CALLBACK_FREE, + _ecore_evas_ews_cb_free, ee); + evas_object_event_callback_add(ee->engine.ews.image, + EVAS_CALLBACK_KEY_DOWN, + _ecore_evas_ews_cb_key_down, ee); + evas_object_event_callback_add(ee->engine.ews.image, + EVAS_CALLBACK_KEY_UP, + _ecore_evas_ews_cb_key_up, ee); + evas_object_event_callback_add(ee->engine.ews.image, + EVAS_CALLBACK_FOCUS_IN, + _ecore_evas_ews_cb_focus_in, ee); + evas_object_event_callback_add(ee->engine.ews.image, + EVAS_CALLBACK_FOCUS_OUT, + _ecore_evas_ews_cb_focus_out, ee); + evas_object_event_callback_add(ee->engine.ews.image, + EVAS_CALLBACK_SHOW, + _ecore_evas_ews_cb_show, ee); + evas_object_event_callback_add(ee->engine.ews.image, + EVAS_CALLBACK_HIDE, + _ecore_evas_ews_cb_hide, ee); + einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ee->evas); + if (einfo) + { + void *pixels = evas_object_image_data_get(o, 1); + evas_object_image_data_set(o, pixels); // refcount + einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32; + einfo->info.dest_buffer = pixels; + einfo->info.dest_buffer_row_bytes = evas_object_image_stride_get(o); + einfo->info.use_color_key = 0; + einfo->info.alpha_threshold = 0; + einfo->info.func.new_update_region = NULL; + einfo->info.func.free_update_region = NULL; + evas_object_image_data_set(o, pixels); + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + } + else + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + evas_key_modifier_add(ee->evas, "Shift"); + evas_key_modifier_add(ee->evas, "Control"); + evas_key_modifier_add(ee->evas, "Alt"); + evas_key_modifier_add(ee->evas, "Meta"); + evas_key_modifier_add(ee->evas, "Hyper"); + evas_key_modifier_add(ee->evas, "Super"); + evas_key_lock_add(ee->evas, "Caps_Lock"); + evas_key_lock_add(ee->evas, "Num_Lock"); + evas_key_lock_add(ee->evas, "Scroll_Lock"); + + _ews_ee->sub_ecore_evas = eina_list_append(_ews_ee->sub_ecore_evas, ee); + _ews_children = eina_list_append(_ews_children, ee); + + _ecore_evas_ews_event(ee, ECORE_EVAS_EWS_EVENT_ADD); + + return ee; +#else + return NULL; + (void)x; + (void)y; + (void)w; + (void)h; +#endif +} + +EAPI Evas_Object * +ecore_evas_ews_backing_store_get(const Ecore_Evas *ee) +{ +#ifdef BUILD_ECORE_EVAS_EWS + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_ews_backing_store_get"); + return NULL; + } + return ee->engine.ews.image; +#else + return NULL; + (void)ee; +#endif +} + +EAPI void +ecore_evas_ews_delete_request(Ecore_Evas *ee) +{ +#ifdef BUILD_ECORE_EVAS_EWS + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_ews_delete_request"); + return; + } + if (ee->func.fn_delete_request) ee->func.fn_delete_request(ee); + else ecore_evas_free(ee); +#else + (void)ee; +#endif +} + + +EAPI Eina_Bool +ecore_evas_ews_engine_set(const char *engine, const char *options) +{ +#ifdef BUILD_ECORE_EVAS_EWS + if (_ews_ee) return EINA_FALSE; + + free(_ews_engine); + free(_ews_options); + + _ews_engine = engine ? strdup(engine) : NULL; + _ews_options = options ? strdup(options) : NULL; + + if ((engine) && (!_ews_engine)) return EINA_FALSE; + if ((options) && (!_ews_options)) return EINA_FALSE; + + _ews_defaults_engine = EINA_FALSE; + return EINA_TRUE; +#else + return EINA_FALSE; + (void)engine; + (void)options; +#endif +} + +EAPI Eina_Bool +ecore_evas_ews_setup(int x, int y, int w, int h) +{ +#ifdef BUILD_ECORE_EVAS_EWS + Eina_Bool ret = EINA_TRUE; + + _ews_defaults_geo = EINA_FALSE; + _ews_x = x; + _ews_y = y; + _ews_w = w; + _ews_h = h; + + if (!_ews_ee) return EINA_TRUE; + + /* move-resize is not as implemented as move + resize */ + ecore_evas_move(_ews_ee, x, y); + ecore_evas_size_min_set(_ews_ee, w, h); + ecore_evas_size_max_set(_ews_ee, w, h); + ecore_evas_resize(_ews_ee, w, h); + + ecore_evas_geometry_get(_ews_ee, &x, &y, &w, &h); + +#define TST(n) if ((n != _ews_##n)) \ + { \ + WRN("Asked %d, got %d for "#n, _ews_##n, n); \ + ret = EINA_FALSE; \ + } + TST(x); + TST(y); + TST(w); + TST(h); +#undef TST + return ret; +#else + return EINA_FALSE; + (void)x; + (void)y; + (void)w; + (void)h; +#endif +} + +EAPI Ecore_Evas * +ecore_evas_ews_ecore_evas_get(void) +{ +#ifdef BUILD_ECORE_EVAS_EWS + if (!_ews_ee) _ews_ee = _ecore_evas_ews_ee_new(); + return _ews_ee; +#else + return NULL; +#endif +} + +EAPI Evas * +ecore_evas_ews_evas_get(void) +{ +#ifdef BUILD_ECORE_EVAS_EWS + return ecore_evas_get(ecore_evas_ews_ecore_evas_get()); +#else + return NULL; +#endif +} + +EAPI Evas_Object * +ecore_evas_ews_background_get(void) +{ +#ifdef BUILD_ECORE_EVAS_EWS + return _ews_bg; +#else + return NULL; +#endif +} + +#ifdef BUILD_ECORE_EVAS_EWS +static void +_ecore_evas_ews_background_free(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__) +{ + _ews_bg = NULL; + ecore_evas_ews_background_set(NULL); +} +#endif + +EAPI void +ecore_evas_ews_background_set(Evas_Object *o) +{ +#ifdef BUILD_ECORE_EVAS_EWS + if ((o) && (o == _ews_bg)) return; + + if (_ews_bg) + { + evas_object_del(_ews_bg); + _ews_bg = NULL; + } + + if ((!o) && (_ews_ee)) + { + o = evas_object_rectangle_add(ecore_evas_get(_ews_ee)); + evas_object_color_set(o, 0, 0, 0, 255); + } + + if (_ews_ee) + { + Evas_Coord w, h; + Evas *e = ecore_evas_get(_ews_ee); + + if (e != evas_object_evas_get(o)) + { + ERR("background not in ecore_evas_ews_evas_get() canvas!"); + return; + } + + evas_output_viewport_get(e, NULL, NULL, &w, &h); + evas_object_move(o, 0, 0); + evas_object_resize(o, w, h); + evas_object_layer_set(o, EVAS_LAYER_MIN); + evas_object_lower(o); + evas_object_show(o); + + evas_object_event_callback_add + (o, EVAS_CALLBACK_FREE, _ecore_evas_ews_background_free, NULL); + } + + _ews_bg = o; +#else + return; + (void)o; +#endif +} + + +EAPI const Eina_List * +ecore_evas_ews_children_get(void) +{ +#ifdef BUILD_ECORE_EVAS_EWS + return _ews_children; +#else + return NULL; +#endif +} + +EAPI void +ecore_evas_ews_manager_set(const void *manager) +{ +#ifdef BUILD_ECORE_EVAS_EWS + if (_ews_manager == manager) return; + _ews_manager = manager; + ecore_event_add(ECORE_EVAS_EWS_EVENT_MANAGER_CHANGE, NULL, NULL, NULL); +#else + (void)manager; +#endif +} + +EAPI const void * +ecore_evas_ews_manager_get(void) +{ +#ifdef BUILD_ECORE_EVAS_EWS + return _ews_manager; +#else + return NULL; +#endif +} diff --git a/src/lib/ecore_evas/ecore_evas_extn.c b/src/lib/ecore_evas/ecore_evas_extn.c new file mode 100644 index 0000000..d629ff3 --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas_extn.c @@ -0,0 +1,2221 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_MMAN_H +# include +#endif +#include +#include +#include +#include +#include + +#include +#include "ecore_private.h" +#include + +#ifdef BUILD_ECORE_EVAS_EXTN + +#include + +#endif + +#include "ecore_evas_private.h" +#include "Ecore_Evas.h" + + +#ifdef BUILD_ECORE_EVAS_EXTN + + +typedef struct _Shmfile Shmfile; + +struct _Shmfile +{ + int fd; + int size; + void *addr; + const char *file; +}; + +static int blank = 0x00000000; + +static Shmfile * +shmfile_new(const char *base, int id, int size, Eina_Bool sys) +{ + Shmfile *sf; + char file[PATH_MAX]; + + sf = calloc(1, sizeof(Shmfile)); + do + { + mode_t mode; + + snprintf(file, sizeof(file), "/%s-%i-%i.%i.%i", + base, id, (int)time(NULL), (int)getpid(), (int)rand()); + mode = S_IRUSR | S_IWUSR; + if (sys) mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + sf->fd = shm_open(file, O_RDWR | O_CREAT | O_EXCL, mode); + } + while (sf->fd < 0); + + sf->file = eina_stringshare_add(file); + if (!sf->file) + { + close(sf->fd); + shm_unlink(sf->file); + eina_stringshare_del(sf->file); + free(sf); + return NULL; + } + sf->size = size; + if (ftruncate(sf->fd, size) < 0) + { + close(sf->fd); + shm_unlink(sf->file); + eina_stringshare_del(sf->file); + free(sf); + return NULL; + } + sf->addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, sf->fd, 0); + if (sf->addr == MAP_FAILED) + { + close(sf->fd); + shm_unlink(sf->file); + eina_stringshare_del(sf->file); + free(sf); + return NULL; + } + return sf; +} + +void +shmfile_free(Shmfile *sf) +{ + munmap(sf->addr, sf->size); + close(sf->fd); + shm_unlink(sf->file); + eina_stringshare_del(sf->file); + free(sf); +} + +static Shmfile * +shmfile_open(const char *ref, int size, Eina_Bool sys) +{ + Shmfile *sf; + mode_t mode; + + sf = calloc(1, sizeof(Shmfile)); + mode = S_IRUSR | S_IWUSR; + if (sys) mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + sf->fd = shm_open(ref, O_RDWR, mode); + if (sf->fd < 0) + { + free(sf); + return NULL; + } + sf->file = eina_stringshare_add(ref); + if (!sf->file) + { + close(sf->fd); + eina_stringshare_del(sf->file); + free(sf); + return NULL; + } + sf->size = size; + sf->addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, sf->fd, 0); + if (sf->addr == MAP_FAILED) + { + close(sf->fd); + eina_stringshare_del(sf->file); + free(sf); + return NULL; + } + return sf; +} + +void +shmfile_close(Shmfile *sf) +{ + munmap(sf->addr, sf->size); + close(sf->fd); + eina_stringshare_del(sf->file); + free(sf); +} + +// procotol version - change this as needed +#define MAJOR 0x1011 + +enum // opcodes +{ + OP_RESIZE, + OP_SHOW, + OP_HIDE, + OP_FOCUS, + OP_UNFOCUS, + OP_UPDATE, + OP_UPDATE_DONE, + OP_LOCK_FILE, + OP_SHM_REF, + OP_EV_MOUSE_IN, + OP_EV_MOUSE_OUT, + OP_EV_MOUSE_UP, + OP_EV_MOUSE_DOWN, + OP_EV_MOUSE_MOVE, + OP_EV_MOUSE_WHEEL, + OP_EV_MULTI_UP, + OP_EV_MULTI_DOWN, + OP_EV_MULTI_MOVE, + OP_EV_KEY_UP, + OP_EV_KEY_DOWN, + OP_EV_HOLD +}; + +enum +{ + MOD_SHIFT = (1 << 0), + MOD_CTRL = (1 << 1), + MOD_ALT = (1 << 2), + MOD_META = (1 << 3), + MOD_HYPER = (1 << 4), + MOD_SUPER = (1 << 5), + MOD_CAPS = (1 << 6), + MOD_NUM = (1 << 7), + MOD_SCROLL = (1 << 8), +}; + +typedef struct _Ipc_Data_Resize Ipc_Data_Resize; +typedef struct _Ipc_Data_Update Ipc_Data_Update; +typedef struct _Ipc_Data_Ev_Mouse_In Ipc_Data_Ev_Mouse_In; +typedef struct _Ipc_Data_Ev_Mouse_Out Ipc_Data_Ev_Mouse_Out; +typedef struct _Ipc_Data_Ev_Mouse_Up Ipc_Data_Ev_Mouse_Up; +typedef struct _Ipc_Data_Ev_Mouse_Down Ipc_Data_Ev_Mouse_Down; +typedef struct _Ipc_Data_Ev_Mouse_Move Ipc_Data_Ev_Mouse_Move; +typedef struct _Ipc_Data_Ev_Mouse_Wheel Ipc_Data_Ev_Mouse_Wheel; +typedef struct _Ipc_Data_Ev_Hold Ipc_Data_Ev_Hold; +typedef struct _Ipc_Data_Ev_Multi_Up Ipc_Data_Ev_Multi_Up; +typedef struct _Ipc_Data_Ev_Multi_Down Ipc_Data_Ev_Multi_Down; +typedef struct _Ipc_Data_Ev_Multi_Move Ipc_Data_Ev_Multi_Move; +typedef struct _Ipc_Data_Ev_Key_Up Ipc_Data_Ev_Key_Up; +typedef struct _Ipc_Data_Ev_Key_Down Ipc_Data_Ev_Key_Down; + +struct _Ipc_Data_Resize +{ + int w, h; +}; + +struct _Ipc_Data_Update +{ + int x, w, y, h; +}; + +struct _Ipc_Data_Ev_Mouse_In +{ + unsigned int timestamp; + int mask; + Evas_Event_Flags event_flags; +}; + +struct _Ipc_Data_Ev_Mouse_Out +{ + unsigned int timestamp; + int mask; + Evas_Event_Flags event_flags; +}; + +struct _Ipc_Data_Ev_Mouse_Up +{ + int b; + Evas_Button_Flags flags; + int mask; + unsigned int timestamp; + Evas_Event_Flags event_flags; +}; + +struct _Ipc_Data_Ev_Mouse_Down +{ + int b; + Evas_Button_Flags flags; + int mask; + unsigned int timestamp; + Evas_Event_Flags event_flags; +}; + +struct _Ipc_Data_Ev_Mouse_Move +{ + int x, y; + Evas_Button_Flags flags; + int mask; + unsigned int timestamp; + Evas_Event_Flags event_flags; +}; + +struct _Ipc_Data_Ev_Mouse_Wheel +{ + int direction, z; + Evas_Button_Flags flags; + int mask; + unsigned int timestamp; + Evas_Event_Flags event_flags; +}; + +struct _Ipc_Data_Ev_Hold +{ + int hold; + unsigned int timestamp; + Evas_Event_Flags event_flags; +}; + +struct _Ipc_Data_Ev_Multi_Up +{ + Evas_Button_Flags flags; + int d, x, y; + double rad, radx, rady, pres, ang, fx, fy; + int mask; + unsigned int timestamp; + Evas_Event_Flags event_flags; +}; + +struct _Ipc_Data_Ev_Multi_Down +{ + Evas_Button_Flags flags; + int d, x, y; + double rad, radx, rady, pres, ang, fx, fy; + int mask; + unsigned int timestamp; + Evas_Event_Flags event_flags; +}; + +struct _Ipc_Data_Ev_Multi_Move +{ + int d, x, y; + double rad, radx, rady, pres, ang, fx, fy; + int mask; + unsigned int timestamp; + Evas_Event_Flags event_flags; +}; + +struct _Ipc_Data_Ev_Key_Up +{ + const char *keyname, *key, *string, *compose; + int mask; + unsigned int timestamp; + Evas_Event_Flags event_flags; +}; + +struct _Ipc_Data_Ev_Key_Down +{ + const char *keyname, *key, *string, *compose; + int mask; + unsigned int timestamp; + Evas_Event_Flags event_flags; +}; + +typedef struct _Extn Extn; + +struct _Extn +{ + struct { + Ecore_Ipc_Server *server; + Eina_List *clients; + Eina_List *handlers; + Eina_Bool am_server : 1; + } ipc; + struct { + const char *name; + int num; + Eina_Bool sys : 1; + } svc; + struct { + const char *lock; + int lockfd; + const char *shm; + int w, h; + Shmfile *shmfile; + Eina_List *updates; + Eina_Bool have_lock : 1; + Eina_Bool have_real_lock : 1; + } file; +}; + +static Eina_List *extn_ee_list = NULL; + +EAPI int ECORE_EVAS_EXTN_CLIENT_ADD = 0; +EAPI int ECORE_EVAS_EXTN_CLIENT_DEL = 0; + +void +_ecore_evas_extn_init(void) +{ + if (ECORE_EVAS_EXTN_CLIENT_ADD) return; + ECORE_EVAS_EXTN_CLIENT_ADD = ecore_event_type_new(); + ECORE_EVAS_EXTN_CLIENT_DEL = ecore_event_type_new(); +} + +void +_ecore_evas_extn_shutdown(void) +{ +} + +static void +_ecore_evas_extn_event_free(void *data, void *ev __UNUSED__) +{ + Ecore_Evas *ee = data; + if (ee->engine.buffer.image) + evas_object_unref(ee->engine.buffer.image); + _ecore_evas_unref(ee); +} + +static void +_ecore_evas_extn_event(Ecore_Evas *ee, int event) +{ + _ecore_evas_ref(ee); + if (ee->engine.buffer.image) + evas_object_ref(ee->engine.buffer.image); + ecore_event_add(event, ee->engine.buffer.image, + _ecore_evas_extn_event_free, ee); +} + +static Eina_Bool +_ecore_evas_lock_other_have(Ecore_Evas *ee) +{ + Eina_List *l; + Ecore_Evas *ee2; + Extn *extn, *extn2; + + extn = ee->engine.buffer.data; + if (!extn) return EINA_FALSE; + // brute force - i know. i expect extn_ee_list to be fairly short. could + // be improved with a hash of lockfiles + EINA_LIST_FOREACH(extn_ee_list, l, ee2) + { + if (ee == ee2) continue; + extn2 = ee2->engine.buffer.data; + if (!extn2) continue; + if ((extn->file.lock) && (extn2->file.lock) && + (!strcmp(extn->file.lock, extn2->file.lock)) && + (extn2->file.have_real_lock)) + return EINA_TRUE; + } + return EINA_FALSE; +} + +static void +_ecore_evas_socket_lock(Ecore_Evas *ee) +{ + Extn *extn; + + extn = ee->engine.buffer.data; + if (!extn) return; + if (extn->file.lockfd < 0) return; + if (extn->file.have_lock) return; + extn->file.have_lock = EINA_TRUE; + if (_ecore_evas_lock_other_have(ee)) return; + flock(extn->file.lockfd, LOCK_EX); + extn->file.have_real_lock = EINA_TRUE; +} + +static void +_ecore_evas_socket_unlock(Ecore_Evas *ee) +{ + Extn *extn; + + extn = ee->engine.buffer.data; + if (!extn) return; + if (extn->file.lockfd < 0) return; + if (!extn->file.have_lock) return; + extn->file.have_lock = EINA_FALSE; + if (!extn->file.have_real_lock) return; + flock(extn->file.lockfd, LOCK_UN); +} + +static void +_ecore_evas_extn_plug_targer_render_pre(void *data, Evas *e __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee = data; + if (ee) _ecore_evas_socket_lock(ee); +} + +static void +_ecore_evas_extn_plug_targer_render_post(void *data, Evas *e __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee = data; + if (ee) _ecore_evas_socket_unlock(ee); +} + +static void +_ecore_evas_extn_plug_image_obj_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee = data; + if (ee) ecore_evas_free(ee); +} + +static void +_ecore_evas_extn_coord_translate(Ecore_Evas *ee, Evas_Coord *x, Evas_Coord *y) +{ + Evas_Coord xx, yy, ww, hh, fx, fy, fw, fh; + + evas_object_geometry_get(ee->engine.buffer.image, &xx, &yy, &ww, &hh); + evas_object_image_fill_get(ee->engine.buffer.image, &fx, &fy, &fw, &fh); + + if (fw < 1) fw = 1; + if (fh < 1) fh = 1; + + if (evas_object_map_get(ee->engine.buffer.image) && + evas_object_map_enable_get(ee->engine.buffer.image)) + { + fx = 0; fy = 0; + fw = ee->w; fh = ee->h; + ww = ee->w; hh = ee->h; + } + + if ((fx == 0) && (fy == 0) && (fw == ww) && (fh == hh)) + { + *x = (ee->w * (*x - xx)) / fw; + *y = (ee->h * (*y - yy)) / fh; + } + else + { + xx = (*x - xx) - fx; + while (xx < 0) xx += fw; + while (xx > fw) xx -= fw; + *x = (ee->w * xx) / fw; + + yy = (*y - yy) - fy; + while (yy < 0) yy += fh; + while (yy > fh) yy -= fh; + *y = (ee->h * yy) / fh; + } +} + +static void +_ecore_evas_extn_free(Ecore_Evas *ee) +{ + Extn *extn; + Ecore_Ipc_Client *client; + + extn = ee->engine.buffer.data; + if (extn) + { + Ecore_Event_Handler *hdl; + + if (extn->file.have_lock) + _ecore_evas_socket_unlock(ee); + if (extn->file.lockfd) + { + close(extn->file.lockfd); + if (extn->ipc.am_server) + { + if (extn->file.lock) unlink(extn->file.lock); + } + } + if (extn->svc.name) eina_stringshare_del(extn->svc.name); + if (extn->ipc.clients) + { + EINA_LIST_FREE(extn->ipc.clients, client) + ecore_ipc_client_del(client); + } + if (extn->ipc.server) ecore_ipc_server_del(extn->ipc.server); + if (extn->file.lock) eina_stringshare_del(extn->file.lock); + if (extn->file.shm) eina_stringshare_del(extn->file.shm); + if (extn->file.shmfile) + { + if (extn->ipc.am_server) + shmfile_free(extn->file.shmfile); + else + shmfile_close(extn->file.shmfile); + } + + EINA_LIST_FREE(extn->ipc.handlers, hdl) + ecore_event_handler_del(hdl); + free(extn); + ecore_ipc_shutdown(); + ee->engine.buffer.data = NULL; + } + if (ee->engine.buffer.image) + { + Ecore_Evas *ee2; + + evas_object_event_callback_del_full(ee->engine.buffer.image, + EVAS_CALLBACK_DEL, + _ecore_evas_extn_plug_image_obj_del, + ee); + evas_event_callback_del_full(evas_object_evas_get(ee->engine.buffer.image), + EVAS_CALLBACK_RENDER_PRE, + _ecore_evas_extn_plug_targer_render_pre, + ee); + evas_event_callback_del_full(evas_object_evas_get(ee->engine.buffer.image), + EVAS_CALLBACK_RENDER_POST, + _ecore_evas_extn_plug_targer_render_post, + ee); + evas_object_del(ee->engine.buffer.image); + ee2 = evas_object_data_get(ee->engine.buffer.image, "Ecore_Evas_Parent"); + if (ee2) + { + ee2->sub_ecore_evas = eina_list_remove(ee2->sub_ecore_evas, ee); + } + } + extn_ee_list = eina_list_remove(extn_ee_list, ee); +} + +static void +_ecore_evas_resize(Ecore_Evas *ee, int w, int h) +{ + if (w < 1) w = 1; + if (h < 1) h = 1; + ee->req.w = w; + ee->req.h = h; + if ((w == ee->w) && (h == ee->h)) return; + ee->w = w; + ee->h = h; + + /* + * No need for it if not used later. + Extn *extn; + + extn = ee->engine.buffer.data; + */ + if (ee->engine.buffer.image) + evas_object_image_size_set(ee->engine.buffer.image, ee->w, ee->h); + /* Server can have many plugs, so I block resize comand from client to server * + if ((extn) && (extn->ipc.server)) + { + Ipc_Data_Resize ipc; + + ipc.w = ee->w; + ipc.h = ee->h; + ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_RESIZE, 0, 0, 0, &ipc, sizeof(ipc)); + }*/ + if (ee->func.fn_resize) ee->func.fn_resize(ee); +} + +static void +_ecore_evas_move_resize(Ecore_Evas *ee, int x __UNUSED__, int y __UNUSED__, int w, int h) +{ + _ecore_evas_resize(ee, w, h); +} + +static int +_ecore_evas_modifiers_locks_mask_get(Evas *e) +{ + int mask = 0; + + if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Shift")) + mask |= MOD_SHIFT; + if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Control")) + mask |= MOD_CTRL; + if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Alt")) + mask |= MOD_ALT; + if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Meta")) + mask |= MOD_META; + if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Hyper")) + mask |= MOD_HYPER; + if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Super")) + mask |= MOD_SUPER; + if (evas_key_lock_is_set(evas_key_lock_get(e), "Scroll_Lock")) + mask |= MOD_SCROLL; + if (evas_key_lock_is_set(evas_key_lock_get(e), "Num_Lock")) + mask |= MOD_NUM; + if (evas_key_lock_is_set(evas_key_lock_get(e), "Caps_Lock")) + mask |= MOD_CAPS; + return mask; +} + +static void +_ecore_evas_modifiers_locks_mask_set(Evas *e, int mask) +{ + if (mask & MOD_SHIFT) evas_key_modifier_on (e, "Shift"); + else evas_key_modifier_off(e, "Shift"); + if (mask & MOD_CTRL) evas_key_modifier_on (e, "Control"); + else evas_key_modifier_off(e, "Control"); + if (mask & MOD_ALT) evas_key_modifier_on (e, "Alt"); + else evas_key_modifier_off(e, "Alt"); + if (mask & MOD_META) evas_key_modifier_on (e, "Meta"); + else evas_key_modifier_off(e, "Meta"); + if (mask & MOD_HYPER) evas_key_modifier_on (e, "Hyper"); + else evas_key_modifier_off(e, "Hyper"); + if (mask & MOD_SUPER) evas_key_modifier_on (e, "Super"); + else evas_key_modifier_off(e, "Super"); + if (mask & MOD_SCROLL) evas_key_lock_on (e, "Scroll_Lock"); + else evas_key_lock_off(e, "Scroll_Lock"); + if (mask & MOD_NUM) evas_key_lock_on (e, "Num_Lock"); + else evas_key_lock_off(e, "Num_Lock"); + if (mask & MOD_CAPS) evas_key_lock_on (e, "Caps_Lock"); + else evas_key_lock_off(e, "Caps_Lock"); +} + +static void +_ecore_evas_extn_cb_mouse_in(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee = data; + Evas_Event_Mouse_In *ev = event_info; + Extn *extn; + + extn = ee->engine.buffer.data; + if (!extn) return; + if (extn->ipc.server) + { + Ipc_Data_Ev_Mouse_In ipc; + + ipc.timestamp = ev->timestamp; + ipc.mask = _ecore_evas_modifiers_locks_mask_get(ee->evas); + ipc.event_flags = ev->event_flags; + ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_MOUSE_IN, 0, 0, 0, &ipc, sizeof(ipc)); + } +} + +static void +_ecore_evas_extn_cb_mouse_out(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee = data; + Evas_Event_Mouse_Out *ev = event_info; + Extn *extn; + + extn = ee->engine.buffer.data; + if (!extn) return; + if (extn->ipc.server) + { + Ipc_Data_Ev_Mouse_Out ipc; + + ipc.timestamp = ev->timestamp; + ipc.mask = _ecore_evas_modifiers_locks_mask_get(ee->evas); + ipc.event_flags = ev->event_flags; + ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_MOUSE_OUT, 0, 0, 0, &ipc, sizeof(ipc)); + } +} + +static void +_ecore_evas_extn_cb_mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee = data; + Evas_Event_Mouse_Down *ev = event_info; + Extn *extn; + + extn = ee->engine.buffer.data; + if (!extn) return; + if (extn->ipc.server) + { + /* We have send mouse move event before mouse down event */ + { + Ipc_Data_Ev_Mouse_Move ipc_move; + Evas_Coord x, y; + + x = ev->canvas.x; + y = ev->canvas.y; + _ecore_evas_extn_coord_translate(ee, &x, &y); + ipc_move.x = x; + ipc_move.y = y; + ipc_move.timestamp = ev->timestamp; + ipc_move.mask = _ecore_evas_modifiers_locks_mask_get(ee->evas); + ipc_move.event_flags = ev->event_flags; + ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_MOUSE_MOVE, 0, 0, 0, &ipc_move, sizeof(ipc_move)); + } + { + Ipc_Data_Ev_Mouse_Down ipc; + ipc.b = ev->button; + ipc.flags = ev->flags; + ipc.timestamp = ev->timestamp; + ipc.mask = _ecore_evas_modifiers_locks_mask_get(ee->evas); + ipc.event_flags = ev->event_flags; + ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_MOUSE_DOWN, 0, 0, 0, &ipc, sizeof(ipc)); + } + } +} + +static void +_ecore_evas_extn_cb_mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee = data; + Evas_Event_Mouse_Up *ev = event_info; + Extn *extn; + + extn = ee->engine.buffer.data; + if (!extn) return; + if (extn->ipc.server) + { + Ipc_Data_Ev_Mouse_Up ipc; + + ipc.b = ev->button; + ipc.flags = ev->flags; + ipc.timestamp = ev->timestamp; + ipc.mask = _ecore_evas_modifiers_locks_mask_get(ee->evas); + ipc.event_flags = ev->event_flags; + ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_MOUSE_UP, 0, 0, 0, &ipc, sizeof(ipc)); + } +} + +static void +_ecore_evas_extn_cb_mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee = data; + Evas_Event_Mouse_Move *ev = event_info; + Extn *extn; + + extn = ee->engine.buffer.data; + if (!extn) return; + if (extn->ipc.server) + { + Ipc_Data_Ev_Mouse_Move ipc; + Evas_Coord x, y; + + x = ev->cur.canvas.x; + y = ev->cur.canvas.y; + _ecore_evas_extn_coord_translate(ee, &x, &y); + ipc.x = x; + ipc.y = y; + ipc.timestamp = ev->timestamp; + ipc.mask = _ecore_evas_modifiers_locks_mask_get(ee->evas); + ipc.event_flags = ev->event_flags; + ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_MOUSE_MOVE, 0, 0, 0, &ipc, sizeof(ipc)); + } +} + +static void +_ecore_evas_extn_cb_mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee = data; + Evas_Event_Mouse_Wheel *ev = event_info; + Extn *extn; + + extn = ee->engine.buffer.data; + if (!extn) return; + if (extn->ipc.server) + { + Ipc_Data_Ev_Mouse_Wheel ipc; + + ipc.direction = ev->direction; + ipc.z = ev->z; + ipc.timestamp = ev->timestamp; + ipc.mask = _ecore_evas_modifiers_locks_mask_get(ee->evas); + ipc.event_flags = ev->event_flags; + ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_MOUSE_WHEEL, 0, 0, 0, &ipc, sizeof(ipc)); + } +} + +static void +_ecore_evas_extn_cb_multi_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee = data; + Evas_Event_Multi_Down *ev = event_info; + Extn *extn; + + extn = ee->engine.buffer.data; + if (!extn) return; + if (extn->ipc.server) + { + Ipc_Data_Ev_Multi_Down ipc; + Evas_Coord x, y; + + ipc.d = ev->device; + x = ev->canvas.x; + y = ev->canvas.y; + _ecore_evas_extn_coord_translate(ee, &x, &y); + ipc.x = x; + ipc.y = y; + ipc.rad = ev->radius; + ipc.radx = ev->radius_x; + ipc.rady = ev->radius_y; + ipc.pres = ev->pressure; + ipc.ang = ev->angle; + ipc.fx = ev->canvas.xsub; + ipc.fy = ev->canvas.ysub; + ipc.flags = ev->flags; + ipc.timestamp = ev->timestamp; + ipc.mask = _ecore_evas_modifiers_locks_mask_get(ee->evas); + ipc.event_flags = ev->event_flags; + ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_MULTI_DOWN, 0, 0, 0, &ipc, sizeof(ipc)); + } +} + + +static void +_ecore_evas_extn_cb_multi_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee = data; + Evas_Event_Multi_Up *ev = event_info; + Extn *extn; + + extn = ee->engine.buffer.data; + if (!extn) return; + if (extn->ipc.server) + { + Ipc_Data_Ev_Multi_Up ipc; + Evas_Coord x, y; + + ipc.d = ev->device; + x = ev->canvas.x; + y = ev->canvas.y; + _ecore_evas_extn_coord_translate(ee, &x, &y); + ipc.x = x; + ipc.y = y; + ipc.rad = ev->radius; + ipc.radx = ev->radius_x; + ipc.rady = ev->radius_y; + ipc.pres = ev->pressure; + ipc.ang = ev->angle; + ipc.fx = ev->canvas.xsub; + ipc.fy = ev->canvas.ysub; + ipc.flags = ev->flags; + ipc.timestamp = ev->timestamp; + ipc.mask = _ecore_evas_modifiers_locks_mask_get(ee->evas); + ipc.event_flags = ev->event_flags; + ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_MULTI_UP, 0, 0, 0, &ipc, sizeof(ipc)); + } +} + +static void +_ecore_evas_extn_cb_multi_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee = data; + Evas_Event_Multi_Move *ev = event_info; + Extn *extn; + + extn = ee->engine.buffer.data; + if (!extn) return; + if (extn->ipc.server) + { + Ipc_Data_Ev_Multi_Move ipc; + Evas_Coord x, y; + + ipc.d = ev->device; + x = ev->cur.canvas.x; + y = ev->cur.canvas.y; + _ecore_evas_extn_coord_translate(ee, &x, &y); + ipc.x = x; + ipc.y = y; + ipc.rad = ev->radius; + ipc.radx = ev->radius_x; + ipc.rady = ev->radius_y; + ipc.pres = ev->pressure; + ipc.ang = ev->angle; + ipc.fx = ev->cur.canvas.xsub; + ipc.fy = ev->cur.canvas.ysub; + ipc.timestamp = ev->timestamp; + ipc.mask = _ecore_evas_modifiers_locks_mask_get(ee->evas); + ipc.event_flags = ev->event_flags; + ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_MULTI_MOVE, 0, 0, 0, &ipc, sizeof(ipc)); + } +} + +static void +_ecore_evas_extn_cb_free(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee; + + ee = data; + if (ee->driver) _ecore_evas_free(ee); +} + +static void +_ecore_evas_extn_cb_key_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee = data; + Evas_Event_Key_Down *ev = event_info; + Extn *extn; + + extn = ee->engine.buffer.data; + if (!extn) return; + if (extn->ipc.server) + { + Ipc_Data_Ev_Key_Down *ipc; + char *st, *p; + int len = 0; + + len = sizeof(Ipc_Data_Ev_Key_Down); + if (ev->key) len += strlen(ev->key) + 1; + if (ev->keyname) len += strlen(ev->keyname) + 1; + if (ev->string) len += strlen(ev->string) + 1; + if (ev->compose) len += strlen(ev->compose) + 1; + len += 1; + st = alloca(len); + ipc = (Ipc_Data_Ev_Key_Down *)st; + memset(st, 0, len); + p = st + sizeof(Ipc_Data_Ev_Key_Down); + if (ev->key) + { + strcpy(p, ev->key); + ipc->key = p - (long)st; + p += strlen(p) + 1; + } + if (ev->keyname) + { + strcpy(p, ev->keyname); + ipc->keyname = p - (long)st; + p += strlen(p) + 1; + } + if (ev->string) + { + strcpy(p, ev->string); + ipc->string = p - (long)st; + p += strlen(p) + 1; + } + if (ev->compose) + { + strcpy(p, ev->compose); + ipc->compose = p - (long)st; + p += strlen(p) + 1; + } + ipc->timestamp = ev->timestamp; + ipc->mask = _ecore_evas_modifiers_locks_mask_get(ee->evas); + ipc->event_flags = ev->event_flags; + ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_KEY_DOWN, 0, 0, 0, ipc, len); + } +} + +static void +_ecore_evas_extn_cb_key_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee = data; + Evas_Event_Key_Up *ev = event_info; + Extn *extn; + + extn = ee->engine.buffer.data; + if (!extn) return; + if (extn->ipc.server) + { + Ipc_Data_Ev_Key_Up *ipc; + char *st, *p; + int len = 0; + + len = sizeof(Ipc_Data_Ev_Key_Up); + if (ev->key) len += strlen(ev->key) + 1; + if (ev->keyname) len += strlen(ev->keyname) + 1; + if (ev->string) len += strlen(ev->string) + 1; + if (ev->compose) len += strlen(ev->compose) + 1; + len += 1; + st = alloca(len); + ipc = (Ipc_Data_Ev_Key_Up *)st; + memset(st, 0, len); + p = st + sizeof(Ipc_Data_Ev_Key_Down); + if (ev->key) + { + strcpy(p, ev->key); + ipc->key = p - (long)st; + p += strlen(p) + 1; + } + if (ev->keyname) + { + strcpy(p, ev->keyname); + ipc->keyname = p - (long)st; + p += strlen(p) + 1; + } + if (ev->string) + { + strcpy(p, ev->string); + ipc->string = p - (long)st; + p += strlen(p) + 1; + } + if (ev->compose) + { + strcpy(p, ev->compose); + ipc->compose = p - (long)st; + p += strlen(p) + 1; + } + ipc->timestamp = ev->timestamp; + ipc->mask = _ecore_evas_modifiers_locks_mask_get(ee->evas); + ipc->event_flags = ev->event_flags; + ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_KEY_UP, 0, 0, 0, ipc, len); + } +} + +static void +_ecore_evas_extn_cb_hold(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +{ + Ecore_Evas *ee = data; + Evas_Event_Hold *ev = event_info; + Extn *extn; + + extn = ee->engine.buffer.data; + if (!extn) return; + if (extn->ipc.server) + { + Ipc_Data_Ev_Hold ipc; + + ipc.hold = ev->hold; + ipc.timestamp = ev->timestamp; + ipc.event_flags = ev->event_flags; + ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_EV_HOLD, 0, 0, 0, &ipc, sizeof(ipc)); + } +} + +static void +_ecore_evas_extn_cb_focus_in(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee; + Extn *extn; + + ee = data; + ee->prop.focused = 1; + extn = ee->engine.buffer.data; + if (!extn) return; + if (!extn->ipc.server) return; + ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_FOCUS, 0, 0, 0, NULL, 0); +} + +static void +_ecore_evas_extn_cb_focus_out(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee; + Extn *extn; + + ee = data; + ee->prop.focused = 0; + extn = ee->engine.buffer.data; + if (!extn) return; + if (!extn->ipc.server) return; + ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_UNFOCUS, 0, 0, 0, NULL, 0); +} + +static void +_ecore_evas_extn_cb_show(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee; + Extn *extn; + + ee = data; + ee->visible = 1; + extn = ee->engine.buffer.data; + if (!extn) return; + if (!extn->ipc.server) return; + ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_SHOW, 0, 0, 0, NULL, 0); +} + +static void +_ecore_evas_extn_cb_hide(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee; + Extn *extn; + + ee = data; + ee->visible = 0; + extn = ee->engine.buffer.data; + if (!extn) return; + if (!extn->ipc.server) return; + ecore_ipc_server_send(extn->ipc.server, MAJOR, OP_HIDE, 0, 0, 0, NULL, 0); +} + +static const Ecore_Evas_Engine_Func _ecore_extn_plug_engine_func = +{ + _ecore_evas_extn_free, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_resize, + _ecore_evas_move_resize, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, //transparent + NULL, // profiles_set + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + + NULL, // render + NULL, // screen_geometry_get + NULL // screen_dpi_get +}; + +static Eina_Bool +_ipc_server_add(void *data, int type __UNUSED__, void *event) +{ + Ecore_Ipc_Event_Server_Add *e = event; + Ecore_Evas *ee = data; + Extn *extn; + + if (ee != ecore_ipc_server_data_get(e->server)) + return ECORE_CALLBACK_PASS_ON; + if (!eina_list_data_find(extn_ee_list, ee)) + return ECORE_CALLBACK_PASS_ON; + extn = ee->engine.buffer.data; + if (!extn) return ECORE_CALLBACK_PASS_ON; + //FIXME: find a way to let app know server there + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ipc_server_del(void *data, int type __UNUSED__, void *event) +{ + Ecore_Ipc_Event_Server_Del *e = event; + Ecore_Evas *ee = data; + Extn *extn; + + extn = ee->engine.buffer.data; + if (!extn) return ECORE_CALLBACK_PASS_ON; + if (extn->ipc.server != e->server) return ECORE_CALLBACK_PASS_ON; + evas_object_image_data_set(ee->engine.buffer.image, NULL); + ee->engine.buffer.pixels = NULL; + if (extn->file.shmfile) + { + shmfile_close(extn->file.shmfile); + extn->file.shmfile = NULL; + } + if (extn->file.shm) + { + eina_stringshare_del(extn->file.shm); + extn->file.shm = NULL; + } + extn->ipc.server = NULL; + if (ee->func.fn_delete_request) ee->func.fn_delete_request(ee); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ipc_server_data(void *data, int type __UNUSED__, void *event) +{ + Ecore_Ipc_Event_Server_Data *e = event; + Ecore_Evas *ee = data; + Extn *extn; + + if (ee != ecore_ipc_server_data_get(e->server)) + return ECORE_CALLBACK_PASS_ON; + if (!eina_list_data_find(extn_ee_list, ee)) + return ECORE_CALLBACK_PASS_ON; + extn = ee->engine.buffer.data; + if (!extn) return ECORE_CALLBACK_PASS_ON; + if (e->major != MAJOR) + return ECORE_CALLBACK_PASS_ON; + switch (e->minor) + { + case OP_UPDATE: + // add rect to update list + if (e->size >= (int)sizeof(Ipc_Data_Update)) + { + Ipc_Data_Update *ipc = malloc(sizeof(Ipc_Data_Update)); + if (ipc) + { + memcpy(ipc, e->data, sizeof(Ipc_Data_Update)); + extn->file.updates = eina_list_append(extn->file.updates, ipc); + } + } + break; + case OP_UPDATE_DONE: + // updates finished being sent - done now. frame ready + { + Ipc_Data_Update *ipc; + + EINA_LIST_FREE(extn->file.updates, ipc) + { + if (ee->engine.buffer.image) + evas_object_image_data_update_add(ee->engine.buffer.image, + ipc->x, ipc->y, + ipc->w, ipc->h); + } + } + break; + case OP_LOCK_FILE: + if ((e->data) && (e->size > 0) && + (((unsigned char *)e->data)[e->size - 1] == 0)) + { + if (extn->file.have_lock) _ecore_evas_socket_unlock(ee); + if (extn->file.lockfd) close(extn->file.lockfd); + if (extn->file.lock) eina_stringshare_del(extn->file.lock); + extn->file.lock = eina_stringshare_add(e->data); + extn->file.lockfd = open(extn->file.lock, O_RDONLY); + } + break; + case OP_SHM_REF: + // e->ref == w + // e->ref_to == h + // e->response == alpha + // e->data = shm ref string + nul byte + if ((e->data) && ((unsigned char *)e->data)[e->size - 1] == 0) + { + ee->engine.buffer.pixels = NULL; + if (extn->file.shmfile) + { + shmfile_close(extn->file.shmfile); + extn->file.shmfile = NULL; + } + if (extn->file.shm) + { + eina_stringshare_del(extn->file.shm); + extn->file.shm = NULL; + } + if ((e->ref > 0) && (e->ref_to > 0)) + { + extn->file.w = e->ref; + extn->file.h = e->ref_to; + extn->file.shm = eina_stringshare_add(e->data); + extn->file.shmfile = shmfile_open(extn->file.shm, + extn->file.w * + extn->file.h * 4, + EINA_TRUE); + if (extn->file.shmfile) + { + ee->engine.buffer.pixels = extn->file.shmfile->addr; + if (ee->engine.buffer.image) + { + if (e->response) + evas_object_image_alpha_set(ee->engine.buffer.image, + EINA_TRUE); + else + evas_object_image_alpha_set(ee->engine.buffer.image, + EINA_FALSE); + evas_object_image_size_set(ee->engine.buffer.image, + extn->file.w, + extn->file.h); + evas_object_image_data_set(ee->engine.buffer.image, + ee->engine.buffer.pixels); + evas_object_image_data_update_add(ee->engine.buffer.image, + 0, 0, + extn->file.w, + extn->file.h); + _ecore_evas_resize(ee, + extn->file.w, + extn->file.h); + } + else + evas_object_image_data_set(ee->engine.buffer.image, NULL); + } + else + evas_object_image_data_set(ee->engine.buffer.image, NULL); + } + else + evas_object_image_data_set(ee->engine.buffer.image, NULL); + } + break; + case OP_RESIZE: + if ((e->data) && (e->size >= (int)sizeof(Ipc_Data_Resize))) + { + Ipc_Data_Resize *ipc = e->data; + _ecore_evas_resize(ee, ipc->w, ipc->h); + } + break; + default: + break; + } + return ECORE_CALLBACK_PASS_ON; +} +#else +void +_ecore_evas_extn_init(void) +{ +} + +void +_ecore_evas_extn_shutdown(void) +{ +} + +#endif /* BUILD_ECORE_EVAS_EXTN */ + +EAPI Evas_Object * +ecore_evas_extn_plug_new(Ecore_Evas *ee_target) +{ +#ifdef BUILD_ECORE_EVAS_EXTN + Evas_Object *o; + Ecore_Evas *ee; + int w = 1, h = 1; + + if (!ee_target) return NULL; + + ee = calloc(1, sizeof(Ecore_Evas)); + if (!ee) return NULL; + + o = evas_object_image_filled_add(ee_target->evas); + /* this make problem in gl engine, so I'll block this until solve problem + evas_object_image_content_hint_set(o, EVAS_IMAGE_CONTENT_HINT_DYNAMIC);*/ + evas_object_image_colorspace_set(o, EVAS_COLORSPACE_ARGB8888); + evas_object_image_alpha_set(o, 1); + evas_object_image_size_set(o, 1, 1); + evas_object_image_data_set(o, &blank); + + ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); + + ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_extn_plug_engine_func; + + ee->driver = "extn_plug"; + + ee->rotation = 0; + ee->visible = 0; + ee->w = w; + ee->h = h; + ee->req.w = ee->w; + ee->req.h = ee->h; + + ee->prop.max.w = 0; + ee->prop.max.h = 0; + ee->prop.layer = 0; + ee->prop.focused = 0; + ee->prop.borderless = 1; + ee->prop.override = 1; + ee->prop.maximized = 0; + ee->prop.fullscreen = 0; + ee->prop.withdrawn = 0; + ee->prop.sticky = 0; + + ee->engine.buffer.image = o; + evas_object_data_set(ee->engine.buffer.image, "Ecore_Evas", ee); + evas_object_data_set(ee->engine.buffer.image, "Ecore_Evas_Parent", ee_target); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_MOUSE_IN, + _ecore_evas_extn_cb_mouse_in, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_MOUSE_OUT, + _ecore_evas_extn_cb_mouse_out, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_MOUSE_DOWN, + _ecore_evas_extn_cb_mouse_down, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_MOUSE_UP, + _ecore_evas_extn_cb_mouse_up, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_MOUSE_MOVE, + _ecore_evas_extn_cb_mouse_move, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_MOUSE_WHEEL, + _ecore_evas_extn_cb_mouse_wheel, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_MULTI_DOWN, + _ecore_evas_extn_cb_multi_down, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_MULTI_UP, + _ecore_evas_extn_cb_multi_up, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_MULTI_MOVE, + _ecore_evas_extn_cb_multi_move, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_FREE, + _ecore_evas_extn_cb_free, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_KEY_DOWN, + _ecore_evas_extn_cb_key_down, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_KEY_UP, + _ecore_evas_extn_cb_key_up, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_HOLD, + _ecore_evas_extn_cb_hold, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_FOCUS_IN, + _ecore_evas_extn_cb_focus_in, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_FOCUS_OUT, + _ecore_evas_extn_cb_focus_out, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_SHOW, + _ecore_evas_extn_cb_show, ee); + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_HIDE, + _ecore_evas_extn_cb_hide, ee); + + evas_object_event_callback_add(ee->engine.buffer.image, + EVAS_CALLBACK_DEL, + _ecore_evas_extn_plug_image_obj_del, ee); + + + extn_ee_list = eina_list_append(extn_ee_list, ee); + ee_target->sub_ecore_evas = eina_list_append(ee_target->sub_ecore_evas, ee); + + evas_event_callback_add(ee_target->evas, EVAS_CALLBACK_RENDER_PRE, + _ecore_evas_extn_plug_targer_render_pre, ee); + evas_event_callback_add(ee_target->evas, EVAS_CALLBACK_RENDER_POST, + _ecore_evas_extn_plug_targer_render_post, ee); + return o; +#else + return NULL; +#endif +} + +EAPI Eina_Bool +ecore_evas_extn_plug_connect(Evas_Object *obj, const char *svcname, int svcnum, Eina_Bool svcsys) +{ +#ifdef BUILD_ECORE_EVAS_EXTN + Extn *extn; + Ecore_Evas *ee = NULL; + + if (!obj) return EINA_FALSE; + + ee = evas_object_data_get(obj, "Ecore_Evas"); + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) return EINA_FALSE; + + extn = calloc(1, sizeof(Extn)); + if (!extn) return EINA_FALSE; + + Ecore_Ipc_Type ipctype = ECORE_IPC_LOCAL_USER; + + ecore_ipc_init(); + extn->svc.name = eina_stringshare_add(svcname); + extn->svc.num = svcnum; + extn->svc.sys = svcsys; + + if (extn->svc.sys) ipctype = ECORE_IPC_LOCAL_SYSTEM; + extn->ipc.server = ecore_ipc_server_connect(ipctype, (char *)extn->svc.name, + extn->svc.num, ee); + if (!extn->ipc.server) + { + eina_stringshare_del(extn->svc.name); + free(extn); + ecore_ipc_shutdown(); + return EINA_FALSE; + } + ee->engine.buffer.data = extn; + extn->ipc.handlers = eina_list_append + (extn->ipc.handlers, + ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_ADD, + _ipc_server_add, ee)); + extn->ipc.handlers = eina_list_append + (extn->ipc.handlers, + ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DEL, + _ipc_server_del, ee)); + extn->ipc.handlers = eina_list_append + (extn->ipc.handlers, + ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DATA, + _ipc_server_data, ee)); + return EINA_TRUE; +#else + return EINA_FALSE; +#endif +} + +EAPI void +ecore_evas_extn_plug_object_data_lock(Evas_Object *obj) +{ +#ifdef BUILD_ECORE_EVAS_EXTN + Ecore_Evas *ee; + + ee = ecore_evas_object_ecore_evas_get(obj); + if (!ee) return; + _ecore_evas_socket_lock(ee); +#endif +} + +EAPI void +ecore_evas_extn_plug_object_data_unlock(Evas_Object *obj) +{ +#ifdef BUILD_ECORE_EVAS_EXTN + Ecore_Evas *ee; + + ee = ecore_evas_object_ecore_evas_get(obj); + if (!ee) return; + _ecore_evas_socket_unlock(ee); +#endif +} + +#ifdef BUILD_ECORE_EVAS_EXTN +static void +_ecore_evas_socket_resize(Ecore_Evas *ee, int w, int h) +{ + Extn *extn; + Evas_Engine_Info_Buffer *einfo; + int stride = 0; + + if (w < 1) w = 1; + if (h < 1) h = 1; + ee->req.w = w; + ee->req.h = h; + if ((w == ee->w) && (h == ee->h)) return; + ee->w = w; + ee->h = h; + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + extn = ee->engine.buffer.data; + if (extn) + { + if (extn->file.shmfile) + shmfile_free(extn->file.shmfile); + ee->engine.buffer.pixels = NULL; + extn->file.shmfile = shmfile_new(extn->svc.name, extn->svc.num, + ee->w * ee->h * 4, extn->svc.sys); + if (extn->file.shmfile) + ee->engine.buffer.pixels = extn->file.shmfile->addr; + + stride = ee->w * 4; + einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ee->evas); + if (einfo) + { + if (ee->alpha) + einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32; + else + einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_RGB32; + einfo->info.dest_buffer = ee->engine.buffer.pixels; + einfo->info.dest_buffer_row_bytes = stride; + einfo->info.use_color_key = 0; + einfo->info.alpha_threshold = 0; + einfo->info.func.new_update_region = NULL; + einfo->info.func.free_update_region = NULL; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + } + + if (extn->ipc.clients && extn->file.shmfile) + { + Ipc_Data_Resize ipc; + Eina_List *l; + Ecore_Ipc_Client *client; + + EINA_LIST_FOREACH(extn->ipc.clients, l, client) + ecore_ipc_client_send(client, MAJOR, OP_SHM_REF, + ee->w, ee->h, ee->alpha, + extn->file.shmfile->file, + strlen(extn->file.shmfile->file) + 1); + ipc.w = ee->w; + ipc.h = ee->h; + EINA_LIST_FOREACH(extn->ipc.clients, l, client) + ecore_ipc_client_send(client, MAJOR, OP_RESIZE, + 0, 0, 0, &ipc, sizeof(ipc)); + } + } + if (ee->func.fn_resize) ee->func.fn_resize(ee); +} + +static void +_ecore_evas_socket_move_resize(Ecore_Evas *ee, int x __UNUSED__, int y __UNUSED__, int w, int h) +{ + _ecore_evas_socket_resize(ee, w, h); +} + +int +_ecore_evas_extn_socket_render(Ecore_Evas *ee) +{ + Eina_List *updates = NULL, *l, *ll; + Ecore_Evas *ee2; + int rend = 0; + Eina_Rectangle *r; + Extn *extn; + Ecore_Ipc_Client *client; + + extn = ee->engine.buffer.data; + EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2) + { + if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2); + if (ee2->engine.func->fn_render) + rend |= ee2->engine.func->fn_render(ee2); + if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2); + } + if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee); + + if (ee->engine.buffer.pixels) + { + _ecore_evas_socket_lock(ee); + updates = evas_render_updates(ee->evas); + _ecore_evas_socket_unlock(ee); + } + EINA_LIST_FOREACH(updates, l, r) + { + Ipc_Data_Update ipc; + + + ipc.x = r->x; + ipc.y = r->y; + ipc.w = r->w; + ipc.h = r->h; + EINA_LIST_FOREACH(extn->ipc.clients, ll, client) + ecore_ipc_client_send(client, MAJOR, OP_UPDATE, 0, 0, 0, &ipc, sizeof(ipc)); + } + if (updates) + { + evas_render_updates_free(updates); + _ecore_evas_idle_timeout_update(ee); + EINA_LIST_FOREACH(extn->ipc.clients, ll, client) + ecore_ipc_client_send(client, MAJOR, OP_UPDATE_DONE, 0, 0, 0, NULL, 0); + } + + if (ee->func.fn_post_render) ee->func.fn_post_render(ee); + return updates ? 1 : rend; +} + +static Eina_Bool +_ipc_client_add(void *data, int type __UNUSED__, void *event) +{ + Ecore_Ipc_Event_Client_Add *e = event; + Ecore_Evas *ee = data; + Extn *extn; + + if (ee != ecore_ipc_server_data_get(ecore_ipc_client_server_get(e->client))) + return ECORE_CALLBACK_PASS_ON; + if (!eina_list_data_find(extn_ee_list, ee)) + return ECORE_CALLBACK_PASS_ON; + extn = ee->engine.buffer.data; + if (!extn) return ECORE_CALLBACK_PASS_ON; + + extn->ipc.clients = eina_list_append(extn->ipc.clients, e->client); + ecore_ipc_client_send(e->client, MAJOR, OP_LOCK_FILE, 0, 0, 0, extn->file.lock, strlen(extn->file.lock) + 1); + + if (extn->file.shmfile) + { + Ipc_Data_Resize ipc; + + ecore_ipc_client_send(e->client, MAJOR, OP_SHM_REF, + ee->w, ee->h, ee->alpha, + extn->file.shmfile->file, + strlen(extn->file.shmfile->file) + 1); + ipc.w = ee->w; + ipc.h = ee->h; + + ecore_ipc_client_send(e->client, MAJOR, OP_RESIZE, + 0, 0, 0, &ipc, sizeof(ipc)); + } + _ecore_evas_extn_event(ee, ECORE_EVAS_EXTN_CLIENT_ADD); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ipc_client_del(void *data, int type __UNUSED__, void *event) +{ + Ecore_Ipc_Event_Client_Del *e = event; + Ecore_Evas *ee = data; + Extn *extn; + extn = ee->engine.buffer.data; + if (!extn) return ECORE_CALLBACK_PASS_ON; + if (!eina_list_data_find(extn->ipc.clients, e->client)) return ECORE_CALLBACK_PASS_ON; + + extn->ipc.clients = eina_list_remove(extn->ipc.clients, e->client); + + _ecore_evas_extn_event(ee, ECORE_EVAS_EXTN_CLIENT_DEL); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ipc_client_data(void *data, int type __UNUSED__, void *event) +{ + Ecore_Ipc_Event_Client_Data *e = event; + Ecore_Evas *ee = data; + Extn *extn; + + if (ee != ecore_ipc_server_data_get(ecore_ipc_client_server_get(e->client))) + return ECORE_CALLBACK_PASS_ON; + if (!eina_list_data_find(extn_ee_list, ee)) + return ECORE_CALLBACK_PASS_ON; + extn = ee->engine.buffer.data; + if (!extn) return ECORE_CALLBACK_PASS_ON; + if (e->major != MAJOR) + return ECORE_CALLBACK_PASS_ON; + switch (e->minor) + { + case OP_RESIZE: + if ((e->data) && (e->size >= (int)sizeof(Ipc_Data_Resize))) + { + + Ipc_Data_Resize *ipc = e->data; + /* create callbacke data size changed */ + _ecore_evas_socket_resize(ee, ipc->w, ipc->h); + } + break; + case OP_SHOW: + if (!ee->visible) + { + ee->visible = 1; + if (ee->func.fn_show) ee->func.fn_show(ee); + } + break; + case OP_HIDE: + if (ee->visible) + { + ee->visible = 0; + if (ee->func.fn_hide) ee->func.fn_hide(ee); + } + break; + case OP_FOCUS: + if (!ee->prop.focused) + { + ee->prop.focused = 1; + evas_focus_in(ee->evas); + if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee); + } + break; + case OP_UNFOCUS: + if (ee->prop.focused) + { + ee->prop.focused = 0; + evas_focus_out(ee->evas); + if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee); + } + break; + case OP_EV_MOUSE_IN: + if (e->size >= (int)sizeof(Ipc_Data_Ev_Mouse_In)) + { + Ipc_Data_Ev_Mouse_In *ipc = e->data; + Evas_Event_Flags flags; + + flags = evas_event_default_flags_get(ee->evas); + evas_event_default_flags_set(ee->evas, ipc->event_flags); + _ecore_evas_modifiers_locks_mask_set(ee->evas, ipc->mask); + evas_event_feed_mouse_in(ee->evas, ipc->timestamp, NULL); + evas_event_default_flags_set(ee->evas, flags); + } + break; + case OP_EV_MOUSE_OUT: + if (e->size >= (int)sizeof(Ipc_Data_Ev_Mouse_Out)) + { + Ipc_Data_Ev_Mouse_Out *ipc = e->data; + Evas_Event_Flags flags; + + flags = evas_event_default_flags_get(ee->evas); + evas_event_default_flags_set(ee->evas, ipc->event_flags); + _ecore_evas_modifiers_locks_mask_set(ee->evas, ipc->mask); + evas_event_feed_mouse_out(ee->evas, ipc->timestamp, NULL); + evas_event_default_flags_set(ee->evas, flags); + } + break; + case OP_EV_MOUSE_UP: + if (e->size >= (int)sizeof(Ipc_Data_Ev_Mouse_Up)) + { + Ipc_Data_Ev_Mouse_Up *ipc = e->data; + Evas_Event_Flags flags; + + flags = evas_event_default_flags_get(ee->evas); + evas_event_default_flags_set(ee->evas, ipc->event_flags); + _ecore_evas_modifiers_locks_mask_set(ee->evas, ipc->mask); + evas_event_feed_mouse_up(ee->evas, ipc->b, ipc->flags, ipc->timestamp, NULL); + evas_event_default_flags_set(ee->evas, flags); + } + break; + case OP_EV_MOUSE_DOWN: + if (e->size >= (int)sizeof(Ipc_Data_Ev_Mouse_Down)) + { + Ipc_Data_Ev_Mouse_Up *ipc = e->data; + Evas_Event_Flags flags; + + flags = evas_event_default_flags_get(ee->evas); + evas_event_default_flags_set(ee->evas, ipc->event_flags); + _ecore_evas_modifiers_locks_mask_set(ee->evas, ipc->mask); + evas_event_feed_mouse_down(ee->evas, ipc->b, ipc->flags, ipc->timestamp, NULL); + evas_event_default_flags_set(ee->evas, flags); + } + break; + case OP_EV_MOUSE_MOVE: + if (e->size >= (int)sizeof(Ipc_Data_Ev_Mouse_Move)) + { + Ipc_Data_Ev_Mouse_Move *ipc = e->data; + Evas_Event_Flags flags; + + flags = evas_event_default_flags_get(ee->evas); + evas_event_default_flags_set(ee->evas, ipc->event_flags); + _ecore_evas_modifiers_locks_mask_set(ee->evas, ipc->mask); + evas_event_feed_mouse_move(ee->evas, ipc->x, ipc->y, ipc->timestamp, NULL); + evas_event_default_flags_set(ee->evas, flags); + } + break; + case OP_EV_MOUSE_WHEEL: + if (e->size >= (int)sizeof(Ipc_Data_Ev_Mouse_Wheel)) + { + Ipc_Data_Ev_Mouse_Wheel *ipc = e->data; + Evas_Event_Flags flags; + + flags = evas_event_default_flags_get(ee->evas); + evas_event_default_flags_set(ee->evas, ipc->event_flags); + _ecore_evas_modifiers_locks_mask_set(ee->evas, ipc->mask); + evas_event_feed_mouse_wheel(ee->evas, ipc->direction, ipc->z, ipc->timestamp, NULL); + evas_event_default_flags_set(ee->evas, flags); + } + break; + case OP_EV_MULTI_UP: + if (e->size >= (int)sizeof(Ipc_Data_Ev_Multi_Up)) + { + Ipc_Data_Ev_Multi_Up *ipc = e->data; + Evas_Event_Flags flags; + + flags = evas_event_default_flags_get(ee->evas); + evas_event_default_flags_set(ee->evas, ipc->event_flags); + _ecore_evas_modifiers_locks_mask_set(ee->evas, ipc->mask); + evas_event_feed_multi_up(ee->evas, ipc->d, ipc->x, ipc->y, ipc->rad, ipc->radx, ipc->rady, ipc->pres, ipc->ang, ipc->fx, ipc->fy, ipc->flags, ipc->timestamp, NULL); + evas_event_default_flags_set(ee->evas, flags); + } + break; + case OP_EV_MULTI_DOWN: + if (e->size >= (int)sizeof(Ipc_Data_Ev_Multi_Down)) + { + Ipc_Data_Ev_Multi_Down *ipc = e->data; + Evas_Event_Flags flags; + + flags = evas_event_default_flags_get(ee->evas); + evas_event_default_flags_set(ee->evas, ipc->event_flags); + _ecore_evas_modifiers_locks_mask_set(ee->evas, ipc->mask); + evas_event_feed_multi_down(ee->evas, ipc->d, ipc->x, ipc->y, ipc->rad, ipc->radx, ipc->rady, ipc->pres, ipc->ang, ipc->fx, ipc->fy, ipc->flags, ipc->timestamp, NULL); + evas_event_default_flags_set(ee->evas, flags); + } + break; + case OP_EV_MULTI_MOVE: + if (e->size >= (int)sizeof(Ipc_Data_Ev_Multi_Move)) + { + Ipc_Data_Ev_Multi_Move *ipc = e->data; + Evas_Event_Flags flags; + + flags = evas_event_default_flags_get(ee->evas); + evas_event_default_flags_set(ee->evas, ipc->event_flags); + _ecore_evas_modifiers_locks_mask_set(ee->evas, ipc->mask); + evas_event_feed_multi_move(ee->evas, ipc->d, ipc->x, ipc->y, ipc->rad, ipc->radx, ipc->rady, ipc->pres, ipc->ang, ipc->fx, ipc->fy, ipc->timestamp, NULL); + evas_event_default_flags_set(ee->evas, flags); + } + break; + +#define STRGET(val) \ + do { \ + if ((ipc->val) && (ipc->val < (char *)(long)(e->size - 1))) \ + ipc->val = ((char *)ipc) + (long)ipc->val; \ + else \ + ipc->val = NULL; \ + } while (0) + + case OP_EV_KEY_UP: + if (e->size >= (int)sizeof(Ipc_Data_Ev_Key_Up)) + { + if ((e->data) && (e->size > 0) && + (((unsigned char *)e->data)[e->size - 1] == 0)) + { + Ipc_Data_Ev_Key_Up *ipc = e->data; + Evas_Event_Flags flags; + + STRGET(keyname); + STRGET(key); + STRGET(string); + STRGET(compose); + flags = evas_event_default_flags_get(ee->evas); + evas_event_default_flags_set(ee->evas, ipc->event_flags); + _ecore_evas_modifiers_locks_mask_set(ee->evas, ipc->mask); + evas_event_feed_key_up(ee->evas, ipc->keyname, ipc->key, ipc->string, ipc->compose, ipc->timestamp, NULL); + evas_event_default_flags_set(ee->evas, flags); + } + } + break; + case OP_EV_KEY_DOWN: + if (e->size >= (int)sizeof(Ipc_Data_Ev_Key_Down)) + { + if ((e->data) && (e->size > 0) && + (((unsigned char *)e->data)[e->size - 1] == 0)) + { + Ipc_Data_Ev_Key_Down *ipc = e->data; + Evas_Event_Flags flags; + + STRGET(keyname); + STRGET(key); + STRGET(string); + STRGET(compose); + flags = evas_event_default_flags_get(ee->evas); + evas_event_default_flags_set(ee->evas, ipc->event_flags); + _ecore_evas_modifiers_locks_mask_set(ee->evas, ipc->mask); + evas_event_feed_key_down(ee->evas, ipc->keyname, ipc->key, ipc->string, ipc->compose, ipc->timestamp, NULL); + evas_event_default_flags_set(ee->evas, flags); + } + } + break; + case OP_EV_HOLD: + if (e->size >= (int)sizeof(Ipc_Data_Ev_Hold)) + { + Ipc_Data_Ev_Hold *ipc = e->data; + Evas_Event_Flags flags; + + flags = evas_event_default_flags_get(ee->evas); + evas_event_default_flags_set(ee->evas, ipc->event_flags); + evas_event_feed_hold(ee->evas, ipc->hold, ipc->timestamp, NULL); + evas_event_default_flags_set(ee->evas, flags); + } + break; + default: + break; + } + return ECORE_CALLBACK_PASS_ON; +} + +static void +_ecore_evas_extn_socket_alpha_set(Ecore_Evas *ee, int alpha) +{ + Extn *extn; + Eina_List *l; + Ecore_Ipc_Client *client; + + if (((ee->alpha) && (alpha)) || ((!ee->alpha) && (!alpha))) return; + ee->alpha = alpha; + + extn = ee->engine.buffer.data; + if (extn) + { + Evas_Engine_Info_Buffer *einfo; + + einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ee->evas); + if (einfo) + { + if (ee->alpha) + einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32; + else + einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_RGB32; + evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + } + EINA_LIST_FOREACH(extn->ipc.clients, l, client) + ecore_ipc_client_send(client, MAJOR, OP_SHM_REF, + ee->w, ee->h, ee->alpha, + extn->file.shmfile->file, + strlen(extn->file.shmfile->file) + 1); + } +} + +static const Ecore_Evas_Engine_Func _ecore_extn_socket_engine_func = +{ + _ecore_evas_extn_free, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_socket_resize, + _ecore_evas_socket_move_resize, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_extn_socket_alpha_set, + NULL, //transparent + NULL, // profiles_set + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + + _ecore_evas_extn_socket_render, // render + NULL, // screen_geometry_get + NULL, // screen_dpi_get +}; + +#endif + +EAPI Ecore_Evas * +ecore_evas_extn_socket_new(int w, int h) +{ +#ifdef BUILD_ECORE_EVAS_EXTN + Evas_Engine_Info_Buffer *einfo; + Ecore_Evas *ee; + int rmethod; + + rmethod = evas_render_method_lookup("buffer"); + if (!rmethod) return NULL; + ee = calloc(1, sizeof(Ecore_Evas)); + if (!ee) return NULL; + + ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); + + ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_extn_socket_engine_func; + + ee->driver = "extn_socket"; + + ee->rotation = 0; + ee->visible = 0; + ee->w = w; + ee->h = h; + ee->req.w = ee->w; + ee->req.h = ee->h; + + ee->prop.max.w = 0; + ee->prop.max.h = 0; + ee->prop.layer = 0; + ee->prop.focused = 0; + ee->prop.borderless = 1; + ee->prop.override = 1; + ee->prop.maximized = 0; + ee->prop.fullscreen = 0; + ee->prop.withdrawn = 0; + ee->prop.sticky = 0; + + /* init evas here */ + ee->evas = evas_new(); + evas_data_attach_set(ee->evas, ee); + evas_output_method_set(ee->evas, rmethod); + evas_output_size_set(ee->evas, w, h); + evas_output_viewport_set(ee->evas, 0, 0, w, h); + + einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ee->evas); + if (einfo) + { + if (ee->alpha) + einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32; + else + einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_RGB32; + einfo->info.dest_buffer = NULL; + einfo->info.dest_buffer_row_bytes = 0; + einfo->info.use_color_key = 0; + einfo->info.alpha_threshold = 0; + einfo->info.func.new_update_region = NULL; + einfo->info.func.free_update_region = NULL; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + } + else + { + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + evas_key_modifier_add(ee->evas, "Shift"); + evas_key_modifier_add(ee->evas, "Control"); + evas_key_modifier_add(ee->evas, "Alt"); + evas_key_modifier_add(ee->evas, "Meta"); + evas_key_modifier_add(ee->evas, "Hyper"); + evas_key_modifier_add(ee->evas, "Super"); + evas_key_lock_add(ee->evas, "Caps_Lock"); + evas_key_lock_add(ee->evas, "Num_Lock"); + evas_key_lock_add(ee->evas, "Scroll_Lock"); + + extn_ee_list = eina_list_append(extn_ee_list, ee); + + _ecore_evas_register(ee); + + return ee; +#else + return NULL; +#endif +} + +EAPI Eina_Bool +ecore_evas_extn_socket_listen(Ecore_Evas *ee, const char *svcname, int svcnum, Eina_Bool svcsys) +{ +#ifdef BUILD_ECORE_EVAS_EXTN + Extn *extn; + + extn = calloc(1, sizeof(Extn)); + if (!extn) + { + return EINA_FALSE; + } + else + { + Ecore_Ipc_Type ipctype = ECORE_IPC_LOCAL_USER; + char buf[PATH_MAX]; + + ecore_ipc_init(); + extn->svc.name = eina_stringshare_add(svcname); + extn->svc.num = svcnum; + extn->svc.sys = svcsys; + + snprintf(buf, sizeof(buf), "/tmp/ee-lock-XXXXXX"); + extn->file.lockfd = mkstemp(buf); + if (extn->file.lockfd >= 0) + extn->file.lock = eina_stringshare_add(buf); + if ((extn->file.lockfd < 0) || (!extn->file.lock)) + { + if (extn->file.lockfd) + { + close(extn->file.lockfd); + unlink(buf); + } + eina_stringshare_del(extn->svc.name); + if (extn->file.lock) eina_stringshare_del(extn->file.lock); + free(extn); + ecore_ipc_shutdown(); + return EINA_FALSE; + } + + if (extn->svc.sys) ipctype = ECORE_IPC_LOCAL_SYSTEM; + extn->ipc.am_server = EINA_TRUE; + extn->ipc.server = ecore_ipc_server_add(ipctype, + (char *)extn->svc.name, + extn->svc.num, ee); + if (!extn->ipc.server) + { + if (extn->file.lockfd) + { + close(extn->file.lockfd); + if (extn->file.lock) unlink(extn->file.lock); + } + eina_stringshare_del(extn->svc.name); + eina_stringshare_del(extn->file.lock); + free(extn); + ecore_ipc_shutdown(); + return EINA_FALSE; + } + ee->engine.buffer.data = extn; + extn->ipc.handlers = eina_list_append + (extn->ipc.handlers, + ecore_event_handler_add(ECORE_IPC_EVENT_CLIENT_ADD, + _ipc_client_add, ee)); + extn->ipc.handlers = eina_list_append + (extn->ipc.handlers, + ecore_event_handler_add(ECORE_IPC_EVENT_CLIENT_DEL, + _ipc_client_del, ee)); + extn->ipc.handlers = eina_list_append + (extn->ipc.handlers, + ecore_event_handler_add(ECORE_IPC_EVENT_CLIENT_DATA, + _ipc_client_data, ee)); + } + return EINA_TRUE; +#else + return EINA_FALSE; +#endif +} diff --git a/src/lib/ecore_evas/ecore_evas_fb.c b/src/lib/ecore_evas/ecore_evas_fb.c new file mode 100644 index 0000000..a8200a9 --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas_fb.c @@ -0,0 +1,678 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include +#include "ecore_private.h" +#ifdef BUILD_ECORE_EVAS_FB +#include +#include +#endif + +#include "ecore_evas_private.h" +#include "Ecore_Evas.h" + +#ifdef BUILD_ECORE_EVAS_FB +static int _ecore_evas_init_count = 0; + +static char *ecore_evas_default_display = "0"; +static Eina_List *ecore_evas_input_devices = NULL; +static Ecore_Event_Handler *ecore_evas_event_handlers[4] = {NULL, NULL, NULL, NULL}; + +static void +_ecore_evas_mouse_move_process_fb(Ecore_Evas *ee, int x, int y) +{ + int fbw, fbh; + + ee->mouse.x = x; + ee->mouse.y = y; + ecore_fb_size_get(&fbw, &fbh); + if (ee->prop.cursor.object) + { + evas_object_show(ee->prop.cursor.object); + if (ee->rotation == 0) + evas_object_move(ee->prop.cursor.object, + x - ee->prop.cursor.hot.x, + y - ee->prop.cursor.hot.y); + else if (ee->rotation == 90) + evas_object_move(ee->prop.cursor.object, + (fbh - ee->h) + ee->h - y - 1 - ee->prop.cursor.hot.x, + x - ee->prop.cursor.hot.y); + else if (ee->rotation == 180) + evas_object_move(ee->prop.cursor.object, + (fbw - ee->w) + ee->w - x - 1 - ee->prop.cursor.hot.x, + (fbh - ee->h) + ee->h - y - 1 - ee->prop.cursor.hot.y); + else if (ee->rotation == 270) + evas_object_move(ee->prop.cursor.object, + y - ee->prop.cursor.hot.x, + (fbw - ee->w) + ee->w - x - 1 - ee->prop.cursor.hot.y); + } +} + +static Ecore_Evas *fb_ee = NULL; + +static Ecore_Evas * +_ecore_evas_fb_match(void) +{ + return fb_ee; +} + +static void +_ecore_evas_fb_lose(void *data __UNUSED__) +{ + Eina_List *ll; + Ecore_Fb_Input_Device *dev; + + if (fb_ee) fb_ee->visible = 0; + + EINA_LIST_FOREACH(ecore_evas_input_devices, ll, dev) + ecore_fb_input_device_listen(dev, 0); +} + +static void +_ecore_evas_fb_gain(void *data __UNUSED__) +{ + Ecore_Evas *ee; + Eina_List *ll; + Ecore_Fb_Input_Device *dev; + + if (fb_ee) + { + ee = fb_ee; + + ee->visible = 1; + if ((ee->rotation == 90) || (ee->rotation == 270)) + evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w); + else + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + } + + EINA_LIST_FOREACH(ecore_evas_input_devices, ll, dev) + ecore_fb_input_device_listen(dev, 1); +} + +static Eina_Bool +_ecore_evas_event_mouse_button_down(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Event_Mouse_Button *e; + + e = event; + ee = _ecore_evas_fb_match(); + if (!ee) return ECORE_CALLBACK_PASS_ON; + _ecore_evas_mouse_move_process_fb(ee, e->x, e->y); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_event_mouse_button_up(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Event_Mouse_Button *e; + + e = event; + ee = _ecore_evas_fb_match(); + if (!ee) return ECORE_CALLBACK_PASS_ON; + _ecore_evas_mouse_move_process_fb(ee, e->x, e->y); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_event_mouse_move(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Event_Mouse_Move *e; + + e = event; + ee = _ecore_evas_fb_match(); + if (!ee) return ECORE_CALLBACK_PASS_ON; + _ecore_evas_mouse_move_process_fb(ee, e->x, e->y); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_event_mouse_wheel(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Event_Mouse_Wheel *e; + + e = event; + ee = _ecore_evas_fb_match(); + if (!ee) return ECORE_CALLBACK_PASS_ON; + _ecore_evas_mouse_move_process_fb(ee, e->x, e->y); + return ECORE_CALLBACK_PASS_ON; +} + +static int +_ecore_evas_fb_render(Ecore_Evas *ee) +{ + int rend = 0; + + if (ee->visible) + { + Eina_List *updates; + Eina_List *ll; + Ecore_Evas *ee2; + + if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee); + + EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2) + { + if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2); + if (ee2->engine.func->fn_render) + rend |= ee2->engine.func->fn_render(ee2); + if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2); + } + + updates = evas_render_updates(ee->evas); + if (updates) + { + evas_render_updates_free(updates); + _ecore_evas_idle_timeout_update(ee); + rend = 1; + } + if (ee->func.fn_post_render) ee->func.fn_post_render(ee); + } + else + evas_norender(ee->evas); + return rend; +} + +static int +_ecore_evas_fb_init(Ecore_Evas *ee, int w, int h) +{ + Eina_File_Direct_Info *info; + Eina_Iterator *ls; + Ecore_Fb_Input_Device *device; + Ecore_Fb_Input_Device_Cap caps; + int mouse_handled = 0; + + _ecore_evas_init_count++; + if (_ecore_evas_init_count > 1) return _ecore_evas_init_count; + + ecore_event_evas_init(); + + /* register all input devices */ + ls = eina_file_direct_ls("/dev/input/"); + + EINA_ITERATOR_FOREACH(ls, info) + { + if (strncmp(info->path + info->name_start, "event", 5) != 0) + continue; + + if (!(device = ecore_fb_input_device_open(info->path))) + continue; + ecore_fb_input_device_window_set(device, ee); + + caps = ecore_fb_input_device_cap_get(device); + + /* Mouse */ +#ifdef HAVE_TSLIB + if (caps & ECORE_FB_INPUT_DEVICE_CAP_RELATIVE) +#else + if ((caps & ECORE_FB_INPUT_DEVICE_CAP_RELATIVE) || (caps & ECORE_FB_INPUT_DEVICE_CAP_ABSOLUTE)) +#endif + { + ecore_fb_input_device_axis_size_set(device, w, h); + ecore_fb_input_device_listen(device,1); + ecore_evas_input_devices = eina_list_append(ecore_evas_input_devices, device); + if (!mouse_handled) + { + ecore_evas_event_handlers[0] = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, _ecore_evas_event_mouse_button_down, NULL); + ecore_evas_event_handlers[1] = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, _ecore_evas_event_mouse_button_up, NULL); + ecore_evas_event_handlers[2] = ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE, _ecore_evas_event_mouse_move, NULL); + ecore_evas_event_handlers[3] = ecore_event_handler_add(ECORE_EVENT_MOUSE_WHEEL, _ecore_evas_event_mouse_wheel, NULL); + mouse_handled = 1; + } + } + /* Keyboard */ + else if ((caps & ECORE_FB_INPUT_DEVICE_CAP_KEYS_OR_BUTTONS) && !(caps & ECORE_FB_INPUT_DEVICE_CAP_ABSOLUTE)) + { + ecore_fb_input_device_listen(device,1); + ecore_evas_input_devices = eina_list_append(ecore_evas_input_devices, device); + } + } + eina_iterator_free(ls); + + if (!mouse_handled) + { + if (ecore_fb_ts_init()) + { + ecore_fb_ts_event_window_set(ee); + ecore_evas_event_handlers[0] = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, _ecore_evas_event_mouse_button_down, NULL); + ecore_evas_event_handlers[1] = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, _ecore_evas_event_mouse_button_up, NULL); + ecore_evas_event_handlers[2] = ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE, _ecore_evas_event_mouse_move, NULL); + mouse_handled = 1; + } + } + return _ecore_evas_init_count; +} + +static void +_ecore_evas_fb_free(Ecore_Evas *ee) +{ + ecore_evas_input_event_unregister(ee); + if (fb_ee == ee) fb_ee = NULL; + _ecore_evas_fb_shutdown(); + ecore_fb_shutdown(); +} + +static void +_ecore_evas_resize(Ecore_Evas *ee, int w, int h) +{ + ee->req.w = w; + ee->req.h = h; + if ((w == ee->w) && (h == ee->h)) return; + ee->w = w; + ee->h = h; + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + evas_output_size_set(ee->evas, ee->h, ee->w); + evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w); + evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w); + } + else + { + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + } + if (ee->func.fn_resize) ee->func.fn_resize(ee); +} + +static void +_ecore_evas_move_resize(Ecore_Evas *ee, int x __UNUSED__, int y __UNUSED__, int w, int h) +{ + ee->req.w = w; + ee->req.h = h; + if ((w == ee->w) && (h == ee->h)) return; + ee->w = w; + ee->h = h; + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + evas_output_size_set(ee->evas, ee->h, ee->w); + evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w); + evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w); + } + else + { + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + } + if (ee->func.fn_resize) ee->func.fn_resize(ee); +} + +static void +_ecore_evas_rotation_set(Ecore_Evas *ee, int rotation, int resize __UNUSED__) +{ + Evas_Engine_Info_FB *einfo; + int rot_dif; + + if (ee->rotation == rotation) return; + einfo = (Evas_Engine_Info_FB *)evas_engine_info_get(ee->evas); + if (!einfo) return; + rot_dif = ee->rotation - rotation; + if (rot_dif < 0) rot_dif = -rot_dif; + if (rot_dif != 180) + { + + einfo->info.rotation = rotation; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + if (!ee->prop.fullscreen) + { + int tmp; + + tmp = ee->w; + ee->w = ee->h; + ee->h = tmp; + ee->req.w = ee->w; + ee->req.h = ee->h; + } + else + { + if ((rotation == 0) || (rotation == 180)) + { + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + } + else + { + evas_output_size_set(ee->evas, ee->h, ee->w); + evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w); + } + } + ee->rotation = rotation; + } + else + { + einfo->info.rotation = rotation; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + ee->rotation = rotation; + } + if ((ee->rotation == 90) || (ee->rotation == 270)) + evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w); + else + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + _ecore_evas_mouse_move_process_fb(ee, ee->mouse.x, ee->mouse.y); + if (ee->func.fn_resize) ee->func.fn_resize(ee); +} + +static void +_ecore_evas_show(Ecore_Evas *ee) +{ + if (ee->prop.focused) return; + ee->prop.focused = 1; + evas_focus_in(ee->evas); + if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee); +} + +static void +_ecore_evas_hide(Ecore_Evas *ee) +{ + if (ee->prop.focused) + { + ee->prop.focused = 0; + evas_focus_out(ee->evas); + if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee); + } +} + +static void +_ecore_evas_object_cursor_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee; + + ee = data; + if (ee) + ee->prop.cursor.object = NULL; +} + +static void +_ecore_evas_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y) +{ + int x, y; + + if (ee->prop.cursor.object) evas_object_del(ee->prop.cursor.object); + + if (!obj) + { + ee->prop.cursor.object = NULL; + ee->prop.cursor.layer = 0; + ee->prop.cursor.hot.x = 0; + ee->prop.cursor.hot.y = 0; + return; + } + + ee->prop.cursor.object = obj; + ee->prop.cursor.layer = layer; + ee->prop.cursor.hot.x = hot_x; + ee->prop.cursor.hot.y = hot_y; + evas_pointer_output_xy_get(ee->evas, &x, &y); + evas_object_layer_set(ee->prop.cursor.object, ee->prop.cursor.layer); + evas_object_move(ee->prop.cursor.object, + x - ee->prop.cursor.hot.x, + y - ee->prop.cursor.hot.y); + evas_object_pass_events_set(ee->prop.cursor.object, 1); + if (evas_pointer_inside_get(ee->evas)) + evas_object_show(ee->prop.cursor.object); + + evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _ecore_evas_object_cursor_del, ee); +} + +static void +_ecore_evas_fullscreen_set(Ecore_Evas *ee, int on) +{ + Eina_List *l; + Ecore_Fb_Input_Device *dev; + int resized = 0; + + if (((ee->prop.fullscreen) && (on)) || + ((!ee->prop.fullscreen) && (!on))) return; + if (on) + { + int w, h; + + ee->engine.fb.real_w = ee->w; + ee->engine.fb.real_h = ee->h; + w = ee->w; + h = ee->h; + ecore_fb_size_get(&w, &h); + if ((w == 0) && (h == 0)) + { + w = ee->w; + h = ee->h; + } + if ((w != ee->w) || (h != ee->h)) resized = 1; + ee->w = w; + ee->h = h; + ee->req.w = ee->w; + ee->req.h = ee->h; + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + } + else + { + if ((ee->engine.fb.real_w != ee->w) || (ee->engine.fb.real_h != ee->h)) resized = 1; + ee->w = ee->engine.fb.real_w; + ee->h = ee->engine.fb.real_h; + ee->req.w = ee->w; + ee->req.h = ee->h; + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + } + ee->prop.fullscreen = on; + EINA_LIST_FOREACH(ecore_evas_input_devices, l, dev) + ecore_fb_input_device_axis_size_set(dev, ee->w, ee->h); + /* rescale the input device area */ + if (resized) + { + if (ee->func.fn_resize) ee->func.fn_resize(ee); + } +} + +int +_ecore_evas_fb_shutdown(void) +{ + _ecore_evas_init_count--; + if (_ecore_evas_init_count == 0) + { + int i; + + for (i = 0; i < 4; i++) + { + if (ecore_evas_event_handlers[i]) + ecore_event_handler_del(ecore_evas_event_handlers[i]); + } + ecore_fb_ts_shutdown(); + ecore_event_evas_shutdown(); + } + if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0; + return _ecore_evas_init_count; +} + +static Ecore_Evas_Engine_Func _ecore_fb_engine_func = +{ + _ecore_evas_fb_free, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_resize, + _ecore_evas_move_resize, + _ecore_evas_rotation_set, + NULL, + _ecore_evas_show, + _ecore_evas_hide, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_object_cursor_set, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_fullscreen_set, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, //transparent + NULL, // profiles_set + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + + NULL, // render + NULL, // screen_geometry_get + NULL // screen_dpi_get +}; +#endif + +/** + * @brief Create Ecore_Evas using fb backend. + * @param disp_name The name of the display to be used. + * @param rotation The rotation to be used. + * @param w The width of the Ecore_Evas to be created. + * @param h The height of the Ecore_Evas to be created. + * @return The new Ecore_Evas. + */ +#ifdef BUILD_ECORE_EVAS_FB +EAPI Ecore_Evas * +ecore_evas_fb_new(const char *disp_name, int rotation, int w, int h) +{ + Evas_Engine_Info_FB *einfo; + Ecore_Evas *ee; + + int rmethod; + + if (!disp_name) + disp_name = ecore_evas_default_display; + + rmethod = evas_render_method_lookup("fb"); + if (!rmethod) return NULL; + + if (!ecore_fb_init(disp_name)) return NULL; + ecore_fb_callback_gain_set(_ecore_evas_fb_gain, NULL); + ecore_fb_callback_lose_set(_ecore_evas_fb_lose, NULL); + ee = calloc(1, sizeof(Ecore_Evas)); + if (!ee) return NULL; + + ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); + + _ecore_evas_fb_init(ee, w, h); + + ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_fb_engine_func; + + ee->driver = "fb"; + if (disp_name) ee->name = strdup(disp_name); + + if (w < 1) w = 1; + if (h < 1) h = 1; + ee->rotation = rotation; + ee->visible = 1; + ee->w = w; + ee->h = h; + ee->req.w = ee->w; + ee->req.h = ee->h; + + ee->prop.max.w = 0; + ee->prop.max.h = 0; + ee->prop.layer = 0; + ee->prop.focused = 0; + ee->prop.borderless = 1; + ee->prop.override = 1; + ee->prop.maximized = 1; + ee->prop.fullscreen = 0; + ee->prop.withdrawn = 0; + ee->prop.sticky = 0; + + /* init evas here */ + ee->evas = evas_new(); + evas_data_attach_set(ee->evas, ee); + evas_output_method_set(ee->evas, rmethod); + + if ((rotation == 90) || (rotation == 270)) + { + evas_output_size_set(ee->evas, h, w); + evas_output_viewport_set(ee->evas, 0, 0, h, w); + } + else + { + evas_output_size_set(ee->evas, w, h); + evas_output_viewport_set(ee->evas, 0, 0, w, h); + } + + einfo = (Evas_Engine_Info_FB *)evas_engine_info_get(ee->evas); + if (einfo && disp_name) + { + einfo->info.virtual_terminal = 0; + einfo->info.device_number = strtol(disp_name, NULL, 10); + einfo->info.refresh = 0; + einfo->info.rotation = ee->rotation; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + } + else + { + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + + ecore_evas_input_event_register(ee); + + ee->engine.func->fn_render = _ecore_evas_fb_render; + _ecore_evas_register(ee); + fb_ee = ee; + evas_event_feed_mouse_in(ee->evas, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff), NULL); + return ee; +} +#else +EAPI Ecore_Evas * +ecore_evas_fb_new(const char *disp_name __UNUSED__, int rotation __UNUSED__, int w __UNUSED__, int h __UNUSED__) +{ + return NULL; +} +#endif diff --git a/src/lib/ecore_evas/ecore_evas_private.h b/src/lib/ecore_evas/ecore_evas_private.h new file mode 100644 index 0000000..6d45999 --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas_private.h @@ -0,0 +1,487 @@ +#ifndef _ECORE_EVAS_PRIVATE_H +#define _ECORE_EVAS_PRIVATE_H + +#include +#include +#include +#include +#include + +#define ECORE_MAGIC_EVAS 0x76543211 + +#ifdef BUILD_ECORE_EVAS_X11 +# include +# include +# ifdef HAVE_ECORE_X_XCB +# include +# endif +# ifdef HAVE_ECORE_X_XLIB +# include +# include +# endif +#endif + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 +# include +#endif + +#ifdef BUILD_ECORE_EVAS_OPENGL_X11 +# include +#endif + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_8_X11 +# include +#endif + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_X11 +# include +#endif + +#ifdef BUILD_ECORE_EVAS_FB +# include +#endif + +#ifdef BUILD_ECORE_EVAS_DIRECTFB +# include +# include "Ecore_DirectFB.h" +#endif + +#if defined(BUILD_ECORE_EVAS_SOFTWARE_BUFFER) || defined(BUILD_ECORE_EVAS_EWS) +# include +#endif + +#ifdef BUILD_ECORE_EVAS_WIN32 +# include "Ecore_Win32.h" +# ifdef BUILD_ECORE_EVAS_SOFTWARE_GDI +# include +# endif +# ifdef BUILD_ECORE_EVAS_SOFTWARE_DDRAW +# include +# endif +# ifdef BUILD_ECORE_EVAS_DIRECT3D +# include +# endif +# ifdef BUILD_ECORE_EVAS_OPENGL_GLEW +# include +# endif +# ifdef BUILD_ECORE_EVAS_SOFTWARE_16_DDRAW +# include +# endif +#endif + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_WINCE +# include "Ecore_WinCE.h" +# include +#endif + +#ifdef BUILD_ECORE_EVAS_GL_COCOA +# include "Ecore_Cocoa.h" +# include +#endif + +#ifdef BUILD_ECORE_EVAS_WAYLAND_SHM +# include "Ecore_Wayland.h" +# include +#endif + +#ifdef BUILD_ECORE_EVAS_WAYLAND_EGL +# include "Ecore_Wayland.h" +# include +#endif + +/** Log domain macros and variables **/ + +extern int _ecore_evas_log_dom; + +#ifdef ECORE_EVAS_DEFAULT_LOG_COLOR +# undef ECORE_EVAS_DEFAULT_LOG_COLOR +#endif +#define ECORE_EVAS_DEFAULT_LOG_COLOR EINA_COLOR_BLUE + +#ifdef ERR +# undef ERR +#endif +#define ERR(...) EINA_LOG_DOM_ERR(_ecore_evas_log_dom, __VA_ARGS__) +#ifdef DBG +# undef DBG +#endif +#define DBG(...) EINA_LOG_DOM_DBG(_ecore_evas_log_dom, __VA_ARGS__) +#ifdef INF +# undef INF +#endif +#define INF(...) EINA_LOG_DOM_INFO(_ecore_evas_log_dom, __VA_ARGS__) +#ifdef WRN +# undef WRN +#endif +#define WRN(...) EINA_LOG_DOM_WARN(_ecore_evas_log_dom, __VA_ARGS__) +#ifdef CRIT +# undef CRIT +#endif +#define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_evas_log_dom, __VA_ARGS__) + + +#define IDLE_FLUSH_TIME 0.5 +#ifndef _ECORE_EVAS_H +typedef struct _Ecore_Evas Ecore_Evas; +typedef void (*Ecore_Evas_Event_Cb) (Ecore_Evas *ee); +#endif + +typedef struct _Ecore_Evas_Engine Ecore_Evas_Engine; +typedef struct _Ecore_Evas_Engine_Func Ecore_Evas_Engine_Func; + +struct _Ecore_Evas_Engine_Func +{ + void (*fn_free) (Ecore_Evas *ee); + void (*fn_callback_resize_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func); + void (*fn_callback_move_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func); + void (*fn_callback_show_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func); + void (*fn_callback_hide_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func); + void (*fn_callback_delete_request_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func); + void (*fn_callback_destroy_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func); + void (*fn_callback_focus_in_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func); + void (*fn_callback_focus_out_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func); + void (*fn_callback_mouse_in_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func); + void (*fn_callback_mouse_out_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func); + void (*fn_callback_sticky_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func); + void (*fn_callback_unsticky_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func); + void (*fn_callback_pre_render_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func); + void (*fn_callback_post_render_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func); + void (*fn_move) (Ecore_Evas *ee, int x, int y); + void (*fn_managed_move) (Ecore_Evas *ee, int x, int y); + void (*fn_resize) (Ecore_Evas *ee, int w, int h); + void (*fn_move_resize) (Ecore_Evas *ee, int x, int y, int w, int h); + void (*fn_rotation_set) (Ecore_Evas *ee, int rot, int resize); + void (*fn_shaped_set) (Ecore_Evas *ee, int shaped); + void (*fn_show) (Ecore_Evas *ee); + void (*fn_hide) (Ecore_Evas *ee); + void (*fn_raise) (Ecore_Evas *ee); + void (*fn_lower) (Ecore_Evas *ee); + void (*fn_activate) (Ecore_Evas *ee); + void (*fn_title_set) (Ecore_Evas *ee, const char *t); + void (*fn_name_class_set) (Ecore_Evas *ee, const char *n, const char *c); + void (*fn_size_min_set) (Ecore_Evas *ee, int w, int h); + void (*fn_size_max_set) (Ecore_Evas *ee, int w, int h); + void (*fn_size_base_set) (Ecore_Evas *ee, int w, int h); + void (*fn_size_step_set) (Ecore_Evas *ee, int w, int h); + void (*fn_object_cursor_set) (Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y); + void (*fn_layer_set) (Ecore_Evas *ee, int layer); + void (*fn_focus_set) (Ecore_Evas *ee, int on); + void (*fn_iconified_set) (Ecore_Evas *ee, int on); + void (*fn_borderless_set) (Ecore_Evas *ee, int on); + void (*fn_override_set) (Ecore_Evas *ee, int on); + void (*fn_maximized_set) (Ecore_Evas *ee, int on); + void (*fn_fullscreen_set) (Ecore_Evas *ee, int on); + void (*fn_avoid_damage_set) (Ecore_Evas *ee, int on); + void (*fn_withdrawn_set) (Ecore_Evas *ee, int withdrawn); + void (*fn_sticky_set) (Ecore_Evas *ee, int sticky); + void (*fn_ignore_events_set) (Ecore_Evas *ee, int ignore); + void (*fn_alpha_set) (Ecore_Evas *ee, int alpha); + void (*fn_transparent_set) (Ecore_Evas *ee, int transparent); + void (*fn_profiles_set) (Ecore_Evas *ee, const char **profiles, int num_profiles); + + void (*fn_window_group_set) (Ecore_Evas *ee, const Ecore_Evas *ee_group); + void (*fn_aspect_set) (Ecore_Evas *ee, double aspect); + void (*fn_urgent_set) (Ecore_Evas *ee, int urgent); + void (*fn_modal_set) (Ecore_Evas *ee, int modal); + void (*fn_demands_attention_set) (Ecore_Evas *ee, int demand); + void (*fn_focus_skip_set) (Ecore_Evas *ee, int skip); + + int (*fn_render) (Ecore_Evas *ee); + void (*fn_screen_geometry_get) (const Ecore_Evas *ee, int *x, int *y, int *w, int *h); + void (*fn_screen_dpi_get) (const Ecore_Evas *ee, int *xdpi, int *ydpi); +}; + +struct _Ecore_Evas_Engine +{ + Ecore_Evas_Engine_Func *func; + +/* TODO: UGLY! This should be an union or inheritance! */ +#ifdef BUILD_ECORE_EVAS_X11 + struct + { + Ecore_X_Window win_root; + Eina_List *win_extra; + Ecore_X_Pixmap pmap; + Ecore_X_Pixmap mask; + Ecore_X_GC gc; + Ecore_X_XRegion *damages; + Ecore_X_Sync_Counter sync_counter; + Ecore_X_Window leader; + Ecore_X_Sync_Counter netwm_sync_counter; + int netwm_sync_val_hi; + unsigned int netwm_sync_val_lo; + int sync_val; // bigger! this will screw up at 2 billion frames (414 days of continual rendering @ 60fps) + int screen_num; + int px, py, pw, ph; + unsigned char direct_resize : 1; + unsigned char using_bg_pixmap : 1; + unsigned char managed : 1; + unsigned char sync_began : 1; + unsigned char sync_cancel : 1; + unsigned char netwm_sync_set : 1; + unsigned char configure_coming : 1; + struct { + unsigned char modal : 1; + unsigned char sticky : 1; + unsigned char maximized_v : 1; + unsigned char maximized_h : 1; + unsigned char shaded : 1; + unsigned char skip_taskbar : 1; + unsigned char skip_pager : 1; + unsigned char fullscreen : 1; + unsigned char above : 1; + unsigned char below : 1; + } state; + Ecore_X_Window win_shaped_input; + } x; +#endif +#ifdef BUILD_ECORE_EVAS_FB + struct { + int real_w; + int real_h; + } fb; +#endif +#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER + struct { + void *pixels; + Evas_Object *image; + void (*free_func) (void *data, void *pix); + void *(*alloc_func) (void *data, int size); + void *data; + } buffer; +#endif +#ifdef BUILD_ECORE_EVAS_DIRECTFB + struct { + Ecore_DirectFB_Window *window; + } directfb; +#endif +#ifdef BUILD_ECORE_EVAS_WIN32 + struct { + Ecore_Win32_Window *parent; + struct { + unsigned char region : 1; + unsigned char fullscreen : 1; + } state; + } win32; +#endif +#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_WINCE + struct { + Ecore_WinCE_Window *window; + struct { + unsigned char fullscreen : 1; + } state; + } wince; +#endif +#ifdef BUILD_ECORE_EVAS_EWS + struct { + Evas_Object *image; + } ews; +#endif + +#if defined(BUILD_ECORE_EVAS_WAYLAND_SHM) || defined(BUILD_ECORE_EVAS_WAYLAND_EGL) + struct + { + Ecore_Wl_Window *parent, *win; + Evas_Object *frame; + +# if defined(BUILD_ECORE_EVAS_WAYLAND_SHM) + struct wl_shm_pool *pool; + size_t pool_size; + void *pool_data; + struct wl_buffer *buffer; +# endif + + } wl; +#endif + + Ecore_Timer *idle_flush_timer; +}; + +struct _Ecore_Evas +{ + EINA_INLIST; + ECORE_MAGIC; + Evas *evas; + const char *driver; + char *name; + int x, y, w, h; + short rotation; + Eina_Bool shaped : 1; + Eina_Bool visible : 1; + Eina_Bool draw_ok : 1; + Eina_Bool should_be_visible : 1; + Eina_Bool alpha : 1; + Eina_Bool transparent : 1; + Eina_Bool in : 1; + + Eina_Hash *data; + + struct { + int x, y, w, h; + } req; + + struct { + int x, y; + } mouse; + + struct { + int w, h; + } expecting_resize; + + struct { + char *title; + char *name; + char *clas; + char *profile; + struct { + int w, h; + } min, + max, + base, + step; + struct { + Evas_Object *object; + int layer; + struct { + int x, y; + } hot; + } cursor; + int layer; + Ecore_Window window; + unsigned char avoid_damage; + Ecore_Evas *group_ee; + Ecore_Window group_ee_win; + double aspect; + char focused : 1; + char iconified : 1; + char borderless : 1; + char override : 1; + char maximized : 1; + char fullscreen : 1; + char withdrawn : 1; + char sticky : 1; + char request_pos : 1; + char draw_frame : 1; + char hwsurface : 1; + char urgent : 1; + char modal : 1; + char demand_attention : 1; + char focus_skip : 1; + } prop; + + struct { + void (*fn_resize) (Ecore_Evas *ee); + void (*fn_move) (Ecore_Evas *ee); + void (*fn_show) (Ecore_Evas *ee); + void (*fn_hide) (Ecore_Evas *ee); + void (*fn_delete_request) (Ecore_Evas *ee); + void (*fn_destroy) (Ecore_Evas *ee); + void (*fn_focus_in) (Ecore_Evas *ee); + void (*fn_focus_out) (Ecore_Evas *ee); + void (*fn_sticky) (Ecore_Evas *ee); + void (*fn_unsticky) (Ecore_Evas *ee); + void (*fn_mouse_in) (Ecore_Evas *ee); + void (*fn_mouse_out) (Ecore_Evas *ee); + void (*fn_pre_render) (Ecore_Evas *ee); + void (*fn_post_render) (Ecore_Evas *ee); + void (*fn_pre_free) (Ecore_Evas *ee); + void (*fn_state_change) (Ecore_Evas *ee); + } func; + + Ecore_Evas_Engine engine; + Eina_List *sub_ecore_evas; + + int refcount; + + unsigned char ignore_events : 1; + unsigned char manual_render : 1; + unsigned char registered : 1; + unsigned char no_comp_sync : 1; + unsigned char semi_sync : 1; + unsigned char deleted : 1; + int gl_sync_draw_done; // added by gl77.lee +}; + +void _ecore_evas_ref(Ecore_Evas *ee); +void _ecore_evas_unref(Ecore_Evas *ee); + +#ifdef BUILD_ECORE_EVAS_X11 +int _ecore_evas_x_shutdown(void); +#endif +#ifdef BUILD_ECORE_EVAS_FB +int _ecore_evas_fb_shutdown(void); +#endif +#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER +int _ecore_evas_buffer_shutdown(void); +int _ecore_evas_buffer_render(Ecore_Evas *ee); +#endif +#ifdef BUILD_ECORE_EVAS_DIRECTFB +int _ecore_evas_directfb_shutdown(void); +#endif +#ifdef BUILD_ECORE_EVAS_WIN32 +int _ecore_evas_win32_shutdown(void); +#endif +#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_WINCE +int _ecore_evas_wince_shutdown(void); +#endif +#ifdef BUILD_ECORE_EVAS_EWS +void _ecore_evas_ews_events_init(void); +int _ecore_evas_ews_shutdown(void); +#endif + +#ifdef BUILD_ECORE_EVAS_WAYLAND_SHM +void _ecore_evas_wayland_shm_resize(Ecore_Evas *ee, int location); +void _ecore_evas_wayland_shm_move(Ecore_Evas *ee, int x, int y); +void _ecore_evas_wayland_shm_drag_start(Ecore_Evas *ee, Ecore_Evas *drag_ee, void *source); +void _ecore_evas_wayland_shm_pointer_set(Ecore_Evas *ee, int hot_x, int hot_y); +void _ecore_evas_wayland_shm_type_set(Ecore_Evas *ee, int type); +#endif + +#ifdef BUILD_ECORE_EVAS_WAYLAND_EGL +void _ecore_evas_wayland_egl_resize(Ecore_Evas *ee, int location); +void _ecore_evas_wayland_egl_move(Ecore_Evas *ee, int x, int y); +void _ecore_evas_wayland_egl_drag_start(Ecore_Evas *ee, Ecore_Evas *drag_ee, void *source); +void _ecore_evas_wayland_egl_pointer_set(Ecore_Evas *ee, int hot_x, int hot_y); +void _ecore_evas_wayland_egl_type_set(Ecore_Evas *ee, int type); +#endif + +void _ecore_evas_fps_debug_init(void); +void _ecore_evas_fps_debug_shutdown(void); +void _ecore_evas_fps_debug_rendertime_add(double t); +void _ecore_evas_register(Ecore_Evas *ee); +void _ecore_evas_free(Ecore_Evas *ee); +void _ecore_evas_idle_timeout_update(Ecore_Evas *ee); +void _ecore_evas_mouse_move_process(Ecore_Evas *ee, int x, int y, unsigned int timestamp); +void _ecore_evas_mouse_multi_move_process(Ecore_Evas *ee, int device, + int x, int y, + double radius, + double radius_x, double radius_y, + double pressure, + double angle, + double mx, double my, + unsigned int timestamp); +void _ecore_evas_mouse_multi_down_process(Ecore_Evas *ee, int device, + int x, int y, + double radius, + double radius_x, double radius_y, + double pressure, + double angle, + double mx, double my, + Evas_Button_Flags flags, + unsigned int timestamp); +void _ecore_evas_mouse_multi_up_process(Ecore_Evas *ee, int device, + int x, int y, + double radius, + double radius_x, double radius_y, + double pressure, + double angle, + double mx, double my, + Evas_Button_Flags flags, + unsigned int timestamp); + +extern Eina_Bool _ecore_evas_app_comp_sync; + +void _ecore_evas_extn_init(void); +void _ecore_evas_extn_shutdown(void); + +#endif diff --git a/src/lib/ecore_evas/ecore_evas_psl1ght.c b/src/lib/ecore_evas/ecore_evas_psl1ght.c new file mode 100644 index 0000000..98d570e --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas_psl1ght.c @@ -0,0 +1,515 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "ecore_evas_private.h" +#include "Ecore_Evas.h" + +#ifdef BUILD_ECORE_EVAS_PSL1GHT +#include +#include + +static int _ecore_evas_init_count = 0; + +static Ecore_Evas *psl1ght_ee = NULL; +static Ecore_Event_Handler *ecore_evas_event_handlers[5] = { + NULL, NULL, NULL, NULL +}; + +static const char *ecore_evas_psl1ght_default = "EFL PSL1GHT"; +static int _ecore_evas_fps_debug = 0; +static Ecore_Poller *ecore_evas_event; + +static unsigned int +_ecore_evas_time_get() +{ + return (unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff; +} + +static Ecore_Evas * +_ecore_evas_psl1ght_match(void) +{ + return psl1ght_ee; +} + +static Eina_Bool +_ecore_evas_psl1ght_event_got_focus(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__) +{ + Ecore_Evas *ee; + + ee = _ecore_evas_psl1ght_match(); + + if (!ee) return ECORE_CALLBACK_PASS_ON; + /* pass on event */ + ee->prop.focused = 1; + evas_focus_in(ee->evas); + if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee); + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_psl1ght_event_lost_focus(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__) +{ + Ecore_Evas *ee; + + ee = _ecore_evas_psl1ght_match(); + + if (!ee) return ECORE_CALLBACK_PASS_ON; + /* pass on event */ + evas_focus_out(ee->evas); + ee->prop.focused = 0; + if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee); + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_psl1ght_event_video_expose(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__) +{ + Ecore_Evas *ee; + int w; + int h; + + ee = _ecore_evas_psl1ght_match(); + + if (!ee) return ECORE_CALLBACK_PASS_ON; + evas_output_size_get(ee->evas, &w, &h); + evas_damage_rectangle_add(ee->evas, 0, 0, w, h); + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_psl1ght_event_key_modifiers(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Psl1ght_Event_Key_Modifiers *e = event; + + ee = _ecore_evas_psl1ght_match(); + + if (!ee) return ECORE_CALLBACK_PASS_ON; + ecore_event_evas_modifier_lock_update(ee->evas, e->modifiers); + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_psl1ght_event_quit (void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__) +{ + Ecore_Evas *ee; + + ee = _ecore_evas_psl1ght_match(); + + if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */ + if (ee->func.fn_delete_request) + ee->func.fn_delete_request(ee); + return ECORE_CALLBACK_PASS_ON; +} + +static int +_ecore_evas_render(Ecore_Evas *ee) +{ + Eina_List *updates; + + updates = evas_render_updates(ee->evas); + if (updates) + { + evas_render_updates_free(updates); + _ecore_evas_idle_timeout_update(ee); + } + return updates ? 1 : 0; +} + +static int +_ecore_evas_psl1ght_render(Ecore_Evas *ee) +{ + int rend = 0; + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER + Eina_List *ll; + Ecore_Evas *ee2; + + EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2) + { + if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2); + rend |= _ecore_evas_buffer_render(ee2); + if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2); + } +#endif + + if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee); + + if (ee->prop.avoid_damage) rend = _ecore_evas_render(ee); + else if ((ee->visible) || + ((ee->should_be_visible) && (ee->prop.fullscreen)) || + ((ee->should_be_visible) && (ee->prop.override))) + rend |= _ecore_evas_render(ee); + else + evas_norender(ee->evas); + + if (ee->func.fn_post_render) ee->func.fn_post_render(ee); + return rend; +} + +static Eina_Bool +_ecore_evas_psl1ght_event(void *data __UNUSED__) +{ + ecore_psl1ght_poll_events(); + return ECORE_CALLBACK_RENEW; +} + +static int +_ecore_evas_psl1ght_init(int w __UNUSED__, int h __UNUSED__) +{ + _ecore_evas_init_count++; + if (_ecore_evas_init_count > 1) return _ecore_evas_init_count; + + _ecore_evas_fps_debug = 1; + + // this is pretty bad: poller? and set poll time? pol time is meant to be + // adjustable for things like polling battery state, or amoutn of spare + // memory etc. + // + ecore_evas_event = ecore_poller_add(ECORE_POLLER_CORE, 1, _ecore_evas_psl1ght_event, NULL); + ecore_poller_poll_interval_set(ECORE_POLLER_CORE, 0.006); + + if (_ecore_evas_fps_debug) + _ecore_evas_fps_debug_init(); + + ecore_event_evas_init(); + + ecore_evas_event_handlers[0] = + ecore_event_handler_add(ECORE_PSL1GHT_EVENT_GOT_FOCUS, + _ecore_evas_psl1ght_event_got_focus, NULL); + ecore_evas_event_handlers[1] = + ecore_event_handler_add(ECORE_PSL1GHT_EVENT_LOST_FOCUS, + _ecore_evas_psl1ght_event_lost_focus, NULL); + ecore_evas_event_handlers[2] = + ecore_event_handler_add(ECORE_PSL1GHT_EVENT_EXPOSE, + _ecore_evas_psl1ght_event_video_expose, NULL); + ecore_evas_event_handlers[3] = + ecore_event_handler_add(ECORE_PSL1GHT_EVENT_KEY_MODIFIERS, + _ecore_evas_psl1ght_event_key_modifiers, NULL); + ecore_evas_event_handlers[4] = + ecore_event_handler_add(ECORE_PSL1GHT_EVENT_QUIT, + _ecore_evas_psl1ght_event_quit, NULL); + + return _ecore_evas_init_count; +} + +static int +_ecore_evas_psl1ght_shutdown(void) +{ + _ecore_evas_init_count--; + if (_ecore_evas_init_count == 0) + { + unsigned int i; + + for (i = 0; i < sizeof (ecore_evas_event_handlers) / sizeof (Ecore_Event_Handler *); i++) + ecore_event_handler_del(ecore_evas_event_handlers[i]); + ecore_event_evas_shutdown(); + ecore_poller_del(ecore_evas_event); + ecore_evas_event = NULL; + if (_ecore_evas_fps_debug) + _ecore_evas_fps_debug_shutdown(); + } + if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0; + return _ecore_evas_init_count; +} + +static void +_ecore_evas_psl1ght_free(Ecore_Evas *ee) +{ + if (psl1ght_ee == ee) psl1ght_ee = NULL; + + ecore_event_window_unregister(0); + _ecore_evas_psl1ght_shutdown(); + ecore_psl1ght_shutdown(); +} + +static void +_ecore_evas_psl1ght_callback_delete_request_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +{ + ee->func.fn_delete_request = func; +} + +static void +_ecore_evas_screen_resized(Ecore_Evas *ee) +{ + int w, h; + + /* Do not resize if the window is not fullscreen */ + if (ee->prop.fullscreen == 0) return; + + ecore_psl1ght_screen_resolution_get (&w, &h); + + if (w != ee->w || h != ee->h) + { + ee->req.w = ee->w = w; + ee->req.h = ee->h = h; + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + ecore_psl1ght_resolution_set (w, h); + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + + _ecore_evas_mouse_move_process(ee, ee->mouse.x, ee->mouse.y, + _ecore_evas_time_get()); + if (ee->func.fn_resize) ee->func.fn_resize(ee); + } +} + +static void +_ecore_evas_resize(Ecore_Evas *ee, int w, int h) +{ + if ((w == ee->w) && (h == ee->h)) return; + ee->w = w; + ee->h = h; + + evas_output_size_set(ee->evas, ee->w, ee->h); + + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + + ecore_psl1ght_resolution_set (w, h); + + if (ee->func.fn_resize) ee->func.fn_resize(ee); + + _ecore_evas_screen_resized (ee); +} + +static void +_ecore_evas_move_resize(Ecore_Evas *ee, int x __UNUSED__, int y __UNUSED__, int w, int h) +{ + _ecore_evas_resize (ee, w, h); +} + +static void +_ecore_evas_show(Ecore_Evas *ee) +{ + if (ee->prop.focused) return; + ee->prop.focused = 1; + evas_focus_in(ee->evas); + if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee); +} + +static void +_ecore_evas_screen_geometry_get(const Ecore_Evas *ee __UNUSED__, int *x, int *y, int *w, int *h) +{ + if (x) *x = 0; + if (y) *y = 0; + ecore_psl1ght_screen_resolution_get (w, h); +} + +static void +_ecore_evas_object_cursor_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee; + + ee = data; + if (ee) + ee->prop.cursor.object = NULL; +} + +static void +_ecore_evas_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y) +{ + int x, y; + + if (ee->prop.cursor.object) evas_object_del(ee->prop.cursor.object); + + if (!obj) + { + ee->prop.cursor.object = NULL; + ee->prop.cursor.layer = 0; + ee->prop.cursor.hot.x = 0; + ee->prop.cursor.hot.y = 0; + return; + } + + ee->prop.cursor.object = obj; + ee->prop.cursor.layer = layer; + ee->prop.cursor.hot.x = hot_x; + ee->prop.cursor.hot.y = hot_y; + evas_pointer_output_xy_get(ee->evas, &x, &y); + evas_object_layer_set(ee->prop.cursor.object, ee->prop.cursor.layer); + evas_object_move(ee->prop.cursor.object, + x - ee->prop.cursor.hot.x, + y - ee->prop.cursor.hot.y); + evas_object_pass_events_set(ee->prop.cursor.object, 1); + if (evas_pointer_inside_get(ee->evas)) + evas_object_show(ee->prop.cursor.object); + + evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _ecore_evas_object_cursor_del, ee); +} + +static Ecore_Evas_Engine_Func _ecore_psl1ght_engine_func = +{ + _ecore_evas_psl1ght_free, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_psl1ght_callback_delete_request_set, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_resize, + _ecore_evas_move_resize, + NULL, + NULL, + _ecore_evas_show, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_object_cursor_set, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, //transparent + NULL, // profiles_set + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + + NULL, // render + _ecore_evas_screen_geometry_get, // screen_geometry_get + NULL // screen_dpi_get +}; + +EAPI Ecore_Evas * +ecore_evas_psl1ght_new(const char *name, int w, int h) +{ + void *einfo; + Ecore_Evas *ee; + + if (!name) + name = ecore_evas_psl1ght_default; + + ee = calloc(1, sizeof(Ecore_Evas)); + if (!ee) return NULL; + + ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); + + ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_psl1ght_engine_func; + + ee->driver = "psl1ght"; + if (name) ee->name = strdup(name); + + if (w < 1) w = 1; + if (h < 1) h = 1; + ee->visible = 1; + ee->w = w; + ee->h = h; + + ee->prop.max.w = 0; + ee->prop.max.h = 0; + ee->prop.layer = 0; + ee->prop.focused = 1; + ee->prop.borderless = 1; + ee->prop.override = 1; + ee->prop.maximized = 1; + ee->prop.fullscreen = 0; + ee->prop.withdrawn = 0; + ee->prop.sticky = 0; + ee->prop.window = 0; + + /* init evas here */ + ee->evas = evas_new(); + evas_data_attach_set(ee->evas, ee); + evas_output_method_set(ee->evas, evas_render_method_lookup("psl1ght")); + + evas_output_size_set(ee->evas, w, h); + evas_output_viewport_set(ee->evas, 0, 0, w, h); + + einfo = evas_engine_info_get(ee->evas); + if (einfo) + { + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + } + else + { + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + + if (!ecore_psl1ght_init(name)) + { + evas_free(ee->evas); + if (ee->name) free(ee->name); + free(ee); + return NULL; + } + ecore_psl1ght_resolution_set (w, h); + + _ecore_evas_psl1ght_init(w, h); + + ecore_event_window_register(0, ee, ee->evas, + (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, + (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, + (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, + (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); + + ee->engine.func->fn_render = _ecore_evas_psl1ght_render; + _ecore_evas_register(ee); + + psl1ght_ee = ee; + + _ecore_evas_screen_resized (ee); + + if (getenv("ECORE_EVAS_PSL1GHT_CURSOR_PATH")) + ecore_evas_cursor_set(ee, getenv("ECORE_EVAS_PSL1GHT_CURSOR_PATH"), EVAS_LAYER_MAX, 0, 0); + + evas_event_feed_mouse_in(ee->evas, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff), NULL); + + return ee; +} + +#else /* BUILD_ECORE_EVAS_PSL1GHT */ + +EAPI Ecore_Evas * +ecore_evas_psl1ght_new(const char *name __UNUSED__, int w __UNUSED__, int h __UNUSED__) +{ + ERR("OUTCH !"); + return NULL; +} + +#endif /* BUILD_ECORE_EVAS_PSL1GHT */ diff --git a/src/lib/ecore_evas/ecore_evas_sdl.c b/src/lib/ecore_evas/ecore_evas_sdl.c new file mode 100644 index 0000000..da1ddbd --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas_sdl.c @@ -0,0 +1,657 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#if defined(BUILD_ECORE_EVAS_SOFTWARE_SDL) || defined(BUILD_ECORE_EVAS_OPENGL_SDL) +# include +# ifdef BUILD_ECORE_EVAS_OPENGL_SDL +# include +# endif +#endif + +#include +#include + +#if defined(BUILD_ECORE_EVAS_SOFTWARE_SDL) || defined(BUILD_ECORE_EVAS_OPENGL_SDL) +#include +#endif + +#include "ecore_evas_private.h" +#include "Ecore_Evas.h" + +/* + * SDL only handle one window at a time. That's by definition, there is nothing wrong here. + * + */ +#if defined(BUILD_ECORE_EVAS_SOFTWARE_SDL) || defined(BUILD_ECORE_EVAS_OPENGL_SDL) + +/* static char *ecore_evas_default_display = "0"; */ +/* static Ecore_List *ecore_evas_input_devices = NULL; */ + +static int _ecore_evas_init_count = 0; + +static Ecore_Evas *sdl_ee = NULL; +static Ecore_Event_Handler *ecore_evas_event_handlers[4] = { + NULL, NULL, NULL, NULL +}; + +static const char *ecore_evas_sdl_default = "EFL SDL"; +static int _ecore_evas_fps_debug = 0; +static Ecore_Poller *ecore_evas_event; + +static Ecore_Evas * +_ecore_evas_sdl_match(void) +{ + return sdl_ee; +} + +static void * +_ecore_evas_sdl_switch_buffer(void *data, void *dest __UNUSED__) +{ + SDL_Flip(data); + return ((SDL_Surface*)data)->pixels; +} + +static Eina_Bool +_ecore_evas_sdl_event_got_focus(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__) +{ + Ecore_Evas *ee; + + ee = _ecore_evas_sdl_match(); + + if (!ee) return ECORE_CALLBACK_PASS_ON; + /* pass on event */ + ee->prop.focused = 1; + evas_focus_in(ee->evas); + if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_sdl_event_lost_focus(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__) +{ + Ecore_Evas *ee; + + ee = _ecore_evas_sdl_match(); + + if (!ee) return ECORE_CALLBACK_PASS_ON; + /* pass on event */ + ee->prop.focused = 0; + evas_focus_out(ee->evas); + if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_sdl_event_video_resize(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Sdl_Event_Video_Resize *e; + Ecore_Evas *ee; + int rmethod; + + e = event; + ee = _ecore_evas_sdl_match(); + + if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */ + + rmethod = evas_output_method_get(ee->evas); + if (rmethod == evas_render_method_lookup("buffer")) + { + Evas_Engine_Info_Buffer *einfo; + + einfo = (Evas_Engine_Info_Buffer *) evas_engine_info_get(ee->evas); + if (einfo) + { + einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_RGB32; + einfo->info.switch_data = SDL_SetVideoMode(e->w, e->h, 32, + (ee->prop.hwsurface ? SDL_HWSURFACE : SDL_SWSURFACE) + | (ee->prop.fullscreen ? SDL_FULLSCREEN : 0) + | (ee->alpha ? SDL_SRCALPHA : 0) + | SDL_DOUBLEBUF); + if (!einfo->info.switch_data) + { + return EINA_FALSE; + } + + SDL_SetAlpha(einfo->info.switch_data, SDL_SRCALPHA, 0); + SDL_FillRect(einfo->info.switch_data, NULL, 0); + + einfo->info.dest_buffer = ((SDL_Surface*)einfo->info.switch_data)->pixels; + einfo->info.dest_buffer_row_bytes = e->w * sizeof (int); + einfo->info.use_color_key = 0; + einfo->info.alpha_threshold = 0; + einfo->info.func.new_update_region = NULL; + einfo->info.func.free_update_region = NULL; + einfo->info.func.switch_buffer = _ecore_evas_sdl_switch_buffer; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *) einfo)) + { + return EINA_FALSE; + } + } + } + + ee->w = e->w; + ee->h = e->h; + + evas_output_size_set(ee->evas, e->w, e->h); + evas_output_viewport_set(ee->evas, 0, 0, e->w, e->h); + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_sdl_event_video_expose(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__) +{ + Ecore_Evas *ee; + int w; + int h; + + ee = _ecore_evas_sdl_match(); + + if (!ee) return ECORE_CALLBACK_PASS_ON; + evas_output_size_get(ee->evas, &w, &h); + evas_damage_rectangle_add(ee->evas, 0, 0, w, h); + + return ECORE_CALLBACK_PASS_ON; +} + +static int +_ecore_evas_render(Ecore_Evas *ee) +{ + Eina_List *updates; + + updates = evas_render_updates(ee->evas); + if (updates) + { + evas_render_updates_free(updates); + _ecore_evas_idle_timeout_update(ee); + } + return updates ? 1 : 0; +} + +static int +_ecore_evas_sdl_render(Ecore_Evas *ee) +{ + int rend = 0; + Eina_List *ll; + Ecore_Evas *ee2; + + EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2) + { + if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2); + if (ee2->engine.func->fn_render) + rend |= ee2->engine.func->fn_render(ee2); + if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2); + } + + if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee); + + if (ee->prop.avoid_damage) rend = _ecore_evas_render(ee); + else if ((ee->visible) || + ((ee->should_be_visible) && (ee->prop.fullscreen)) || + ((ee->should_be_visible) && (ee->prop.override))) + rend |= _ecore_evas_render(ee); + else + evas_norender(ee->evas); + + if (ee->func.fn_post_render) ee->func.fn_post_render(ee); + return rend; +} + +static Eina_Bool +_ecore_evas_sdl_event(void *data __UNUSED__) +{ + ecore_sdl_feed_events(); + return ECORE_CALLBACK_RENEW; +} + +static int +_ecore_evas_sdl_init(int w __UNUSED__, int h __UNUSED__) +{ + _ecore_evas_init_count++; + if (_ecore_evas_init_count > 1) return _ecore_evas_init_count; + +#ifndef _WIN32 + if (getenv("ECORE_EVAS_FPS_DEBUG")) _ecore_evas_fps_debug = 1; +#endif /* _WIN32 */ + // this is pretty bad: poller? and set poll time? pol time is meant to be + // adjustable for things like polling battery state, or amoutn of spare + // memory etc. + // + ecore_evas_event = ecore_poller_add(ECORE_POLLER_CORE, 1, _ecore_evas_sdl_event, NULL); + ecore_poller_poll_interval_set(ECORE_POLLER_CORE, 0.006); +#ifndef _WIN32 + if (_ecore_evas_fps_debug) _ecore_evas_fps_debug_init(); +#endif /* _WIN32 */ + + ecore_event_evas_init(); + + ecore_evas_event_handlers[0] = ecore_event_handler_add(ECORE_SDL_EVENT_GOT_FOCUS, _ecore_evas_sdl_event_got_focus, NULL); + ecore_evas_event_handlers[1] = ecore_event_handler_add(ECORE_SDL_EVENT_LOST_FOCUS, _ecore_evas_sdl_event_lost_focus, NULL); + ecore_evas_event_handlers[2] = ecore_event_handler_add(ECORE_SDL_EVENT_RESIZE, _ecore_evas_sdl_event_video_resize, NULL); + ecore_evas_event_handlers[3] = ecore_event_handler_add(ECORE_SDL_EVENT_EXPOSE, _ecore_evas_sdl_event_video_expose, NULL); + + return _ecore_evas_init_count; +} + +static int +_ecore_evas_sdl_shutdown(void) +{ + _ecore_evas_init_count--; + if (_ecore_evas_init_count == 0) + { + unsigned int i; + + for (i = 0; i < sizeof (ecore_evas_event_handlers) / sizeof (Ecore_Event_Handler*); i++) + ecore_event_handler_del(ecore_evas_event_handlers[i]); + ecore_event_evas_shutdown(); + ecore_poller_del(ecore_evas_event); + ecore_evas_event = NULL; +#ifndef _WIN32 + if (_ecore_evas_fps_debug) _ecore_evas_fps_debug_shutdown(); +#endif /* _WIN32 */ + } + if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0; + return _ecore_evas_init_count; +} + +static void +_ecore_evas_sdl_free(Ecore_Evas *ee) +{ + if (sdl_ee == ee) sdl_ee = NULL; + + ecore_event_window_unregister(0); + _ecore_evas_sdl_shutdown(); + ecore_sdl_shutdown(); +} + +static void +_ecore_evas_resize(Ecore_Evas *ee, int w, int h) +{ + int rmethod; + + if ((w == ee->w) && (h == ee->h)) return; + ee->w = w; + ee->h = h; + + rmethod = evas_output_method_get(ee->evas); + if (rmethod == evas_render_method_lookup("buffer")) + { + Evas_Engine_Info_Buffer *einfo; + + einfo = (Evas_Engine_Info_Buffer *) evas_engine_info_get(ee->evas); + if (einfo) + { + einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_RGB32; + einfo->info.switch_data = SDL_SetVideoMode(w, h, 32, + (ee->prop.hwsurface ? SDL_HWSURFACE : SDL_SWSURFACE) + | (ee->prop.fullscreen ? SDL_FULLSCREEN : 0) + | (ee->alpha ? SDL_SRCALPHA : 0) + | SDL_DOUBLEBUF); + if (!einfo->info.switch_data) + { + return ; + } + + SDL_SetAlpha(einfo->info.switch_data, SDL_SRCALPHA, 0); + SDL_FillRect(einfo->info.switch_data, NULL, 0); + + einfo->info.dest_buffer = ((SDL_Surface*)einfo->info.switch_data)->pixels; + einfo->info.dest_buffer_row_bytes = w * sizeof (int); + einfo->info.use_color_key = 0; + einfo->info.alpha_threshold = 0; + einfo->info.func.new_update_region = NULL; + einfo->info.func.free_update_region = NULL; + einfo->info.func.switch_buffer = _ecore_evas_sdl_switch_buffer; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *) einfo)) + { + return ; + } + } + } + + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + + if (ee->func.fn_resize) ee->func.fn_resize(ee); +} + +static void +_ecore_evas_move_resize(Ecore_Evas *ee, int x __UNUSED__, int y __UNUSED__, int w, int h) +{ + if ((w == ee->w) && (h == ee->h)) return; + ee->w = w; + ee->h = h; + + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + + if (ee->func.fn_resize) ee->func.fn_resize(ee); +} + +static void +_ecore_evas_show(Ecore_Evas *ee) +{ + if (ee->prop.focused) return; + ee->prop.focused = 1; + evas_event_feed_mouse_in(ee->evas, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff), NULL); +} + +static void +_ecore_evas_object_cursor_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee; + + ee = data; + if (ee) ee->prop.cursor.object = NULL; +} + +static void +_ecore_evas_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y) +{ + int x, y; + + if (ee->prop.cursor.object) evas_object_del(ee->prop.cursor.object); + + if (!obj) + { + ee->prop.cursor.object = NULL; + ee->prop.cursor.layer = 0; + ee->prop.cursor.hot.x = 0; + ee->prop.cursor.hot.y = 0; + return; + } + + ee->prop.cursor.object = obj; + ee->prop.cursor.layer = layer; + ee->prop.cursor.hot.x = hot_x; + ee->prop.cursor.hot.y = hot_y; + evas_pointer_output_xy_get(ee->evas, &x, &y); + evas_object_layer_set(ee->prop.cursor.object, ee->prop.cursor.layer); + evas_object_move(ee->prop.cursor.object, + x - ee->prop.cursor.hot.x, + y - ee->prop.cursor.hot.y); + evas_object_pass_events_set(ee->prop.cursor.object, 1); + if (evas_pointer_inside_get(ee->evas)) + evas_object_show(ee->prop.cursor.object); + + evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _ecore_evas_object_cursor_del, ee); +} + +static Ecore_Evas_Engine_Func _ecore_sdl_engine_func = +{ + _ecore_evas_sdl_free, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_resize, + _ecore_evas_move_resize, + NULL, + NULL, + _ecore_evas_show, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_object_cursor_set, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, //transparent + NULL, // profiles_set + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + + NULL, // render + NULL, // screen_geometry_get + NULL // screen_dpi_get +}; + +static Ecore_Evas* +_ecore_evas_internal_sdl_new(int rmethod, const char* name, int w, int h, int fullscreen, int hwsurface, int noframe, int alpha) +{ + Ecore_Evas *ee; + + if (!name) + name = ecore_evas_sdl_default; + + ee = calloc(1, sizeof(Ecore_Evas)); + if (!ee) return NULL; + + ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); + + ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_sdl_engine_func; + + ee->driver = "sdl"; + if (name) ee->name = strdup(name); + + if (w < 1) w = 1; + if (h < 1) h = 1; + ee->visible = 1; + ee->w = w; + ee->h = h; + + ee->prop.max.w = 0; + ee->prop.max.h = 0; + ee->prop.layer = 0; + ee->prop.focused = 1; + ee->prop.borderless = 1; + ee->prop.override = 1; + ee->prop.maximized = 1; + ee->prop.fullscreen = fullscreen; + ee->prop.withdrawn = 0; + ee->prop.sticky = 0; + ee->prop.window = 0; + ee->alpha = alpha; + ee->prop.hwsurface = hwsurface; + + /* init evas here */ + ee->evas = evas_new(); + evas_data_attach_set(ee->evas, ee); + evas_output_method_set(ee->evas, rmethod); + + evas_output_size_set(ee->evas, w, h); + evas_output_viewport_set(ee->evas, 0, 0, w, h); + + if (rmethod == evas_render_method_lookup("buffer")) + { + Evas_Engine_Info_Buffer *einfo; + + einfo = (Evas_Engine_Info_Buffer *) evas_engine_info_get(ee->evas); + if (einfo) + { + SDL_Init(SDL_INIT_NOPARACHUTE); + + if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) + { + ERR("SDL_Init failed with %s", SDL_GetError()); + SDL_Quit(); + return NULL; + } + + einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_RGB32; + einfo->info.switch_data = SDL_SetVideoMode(w, h, 32, + (hwsurface ? SDL_HWSURFACE : SDL_SWSURFACE) + | (fullscreen ? SDL_FULLSCREEN : 0) + | (noframe ? SDL_NOFRAME : 0) + | (alpha ? SDL_SRCALPHA : 0) + | SDL_DOUBLEBUF); + if (!einfo->info.switch_data) + { + ERR("SDL_SetVideoMode failed !"); + ecore_evas_free(ee); + return NULL; + } + + SDL_SetAlpha(einfo->info.switch_data, SDL_SRCALPHA, 0); + SDL_FillRect(einfo->info.switch_data, NULL, 0); + + einfo->info.dest_buffer = ((SDL_Surface*)einfo->info.switch_data)->pixels; + einfo->info.dest_buffer_row_bytes = w * sizeof (int); + einfo->info.use_color_key = 0; + einfo->info.alpha_threshold = 0; + einfo->info.func.new_update_region = NULL; + einfo->info.func.free_update_region = NULL; + einfo->info.func.switch_buffer = _ecore_evas_sdl_switch_buffer; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *) einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + } + else + { + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + } + else if (rmethod == evas_render_method_lookup("gl_sdl")) + { +#ifdef BUILD_ECORE_EVAS_OPENGL_SDL + Evas_Engine_Info_GL_SDL *einfo; + + einfo = (Evas_Engine_Info_GL_SDL *) evas_engine_info_get(ee->evas); + if (einfo) + { + einfo->flags.fullscreen = fullscreen; + einfo->flags.noframe = noframe; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + } + else + { + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } +#endif + } + else + { + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + + if (!ecore_sdl_init(name)) + { + evas_free(ee->evas); + if (ee->name) free(ee->name); + free(ee); + return NULL; + } + + _ecore_evas_sdl_init(w, h); + + ecore_event_window_register(0, ee, ee->evas, + (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, + (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, + (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, + (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); + + SDL_ShowCursor(SDL_ENABLE); + + ee->engine.func->fn_render = _ecore_evas_sdl_render; + _ecore_evas_register(ee); + + sdl_ee = ee; + return ee; +} +#endif + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_SDL +EAPI Ecore_Evas* +ecore_evas_sdl_new(const char* name, int w, int h, int fullscreen, int hwsurface, int noframe, int alpha) +{ + Ecore_Evas *ee; + int rmethod; + + rmethod = evas_render_method_lookup("buffer"); + if (!rmethod) return NULL; + + ee = _ecore_evas_internal_sdl_new(rmethod, name, w, h, fullscreen, hwsurface, noframe, alpha); + return ee; +} +#else +EAPI Ecore_Evas* +ecore_evas_sdl_new(const char* name __UNUSED__, int w __UNUSED__, int h __UNUSED__, int fullscreen __UNUSED__, int hwsurface __UNUSED__, int noframe __UNUSED__, int alpha __UNUSED__) +{ + ERR("OUTCH !"); + return NULL; +} +#endif + +EAPI Ecore_Evas* +ecore_evas_sdl16_new(const char* name __UNUSED__, int w __UNUSED__, int h __UNUSED__, int fullscreen __UNUSED__, int hwsurface __UNUSED__, int noframe __UNUSED__, int alpha __UNUSED__) +{ + ERR("OUTCH !"); + return NULL; +} + +#ifdef BUILD_ECORE_EVAS_OPENGL_SDL +EAPI Ecore_Evas* +ecore_evas_gl_sdl_new(const char* name, int w, int h, int fullscreen, int noframe) +{ + Ecore_Evas *ee; + int rmethod; + + rmethod = evas_render_method_lookup("gl_sdl"); + if (!rmethod) return NULL; + + ee = _ecore_evas_internal_sdl_new(rmethod, name, w, h, fullscreen, 0, noframe, 0); + if (ee) ee->driver = "gl_sdl"; + return ee; +} +#else +EAPI Ecore_Evas* +ecore_evas_gl_sdl_new(const char* name __UNUSED__, int w __UNUSED__, int h __UNUSED__, int fullscreen __UNUSED__, int noframe __UNUSED__) +{ + ERR("OUTCH !"); + return NULL; +} +#endif + diff --git a/src/lib/ecore_evas/ecore_evas_util.c b/src/lib/ecore_evas/ecore_evas_util.c new file mode 100644 index 0000000..5aca86c --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas_util.c @@ -0,0 +1,445 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include +#include "ecore_private.h" + +#include "ecore_evas_private.h" +#include "Ecore_Evas.h" + +static const char ASSOCIATE_KEY[] = "__Ecore_Evas_Associate"; + +static void _ecore_evas_object_associate(Ecore_Evas *ee, Evas_Object *obj, Ecore_Evas_Object_Associate_Flags flags); +static void _ecore_evas_object_dissociate(Ecore_Evas *ee, Evas_Object *obj); + + +static Evas_Object * +_ecore_evas_associate_get(const Ecore_Evas *ee) +{ + return ecore_evas_data_get(ee, ASSOCIATE_KEY); +} + +static void +_ecore_evas_associate_set(Ecore_Evas *ee, Evas_Object *obj) +{ + ecore_evas_data_set(ee, ASSOCIATE_KEY, obj); +} + +static void +_ecore_evas_associate_del(Ecore_Evas *ee) +{ + ecore_evas_data_set(ee, ASSOCIATE_KEY, NULL); +} + +static Ecore_Evas * +_evas_object_associate_get(const Evas_Object *obj) +{ + return evas_object_data_get(obj, ASSOCIATE_KEY); +} + +static void +_evas_object_associate_set(Evas_Object *obj, Ecore_Evas *ee) +{ + evas_object_data_set(obj, ASSOCIATE_KEY, ee); +} + +static void +_evas_object_associate_del(Evas_Object *obj) +{ + evas_object_data_del(obj, ASSOCIATE_KEY); +} + +/** Associated Events: ******************************************************/ + +/* Interceptors Callbacks */ + +static void +_ecore_evas_obj_intercept_move(void *data, Evas_Object *obj, Evas_Coord x, Evas_Coord y) +{ + Ecore_Evas *ee = data; + // FIXME: account for frame + ecore_evas_move(ee, x, y); + if (ecore_evas_override_get(ee)) evas_object_move(obj, x, y); +} + +static void +_ecore_evas_obj_intercept_raise(void *data, Evas_Object *obj __UNUSED__) +{ + Ecore_Evas *ee = data; + ecore_evas_raise(ee); +} + +static void +_ecore_evas_obj_intercept_lower(void *data, Evas_Object *obj __UNUSED__) +{ + Ecore_Evas *ee = data; + ecore_evas_lower(ee); +} + +static void +_ecore_evas_obj_intercept_stack_above(void *data __UNUSED__, Evas_Object *obj __UNUSED__, Evas_Object *above __UNUSED__) +{ + INF("TODO: %s", __FUNCTION__); +} + +static void +_ecore_evas_obj_intercept_stack_below(void *data __UNUSED__, Evas_Object *obj __UNUSED__, Evas_Object *below __UNUSED__) +{ + INF("TODO: %s", __FUNCTION__); +} + +static void +_ecore_evas_obj_intercept_layer_set(void *data, Evas_Object *obj __UNUSED__, int l) +{ + Ecore_Evas *ee = data; + ecore_evas_layer_set(ee, l); +} + +/* Event Callbacks */ + +static void +_ecore_evas_obj_callback_show(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee = data; + ecore_evas_show(ee); +} + +static void +_ecore_evas_obj_callback_hide(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee = data; + ecore_evas_hide(ee); +} + +static void +_ecore_evas_obj_callback_resize(void *data, Evas *e, Evas_Object *obj, void *event_info __UNUSED__) +{ + Ecore_Evas *ee = data; + Evas_Coord ow, oh, fw, fh; + + evas_object_geometry_get(obj, NULL, NULL, &ow, &oh); + evas_output_framespace_get(e, NULL, NULL, &fw, &fh); + ow += fw; + oh += fh; + ecore_evas_resize(ee, ow, oh); +} + +static void +_ecore_evas_obj_callback_changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__) +{ + Ecore_Evas *ee = data; + Evas_Coord w, h; + + evas_object_size_hint_min_get(obj, &w, &h); + ecore_evas_size_min_set(ee, w, h); + + evas_object_size_hint_max_get(obj, &w, &h); + if (w < 1) w = -1; + if (h < 1) h = -1; + ecore_evas_size_max_set(ee, w, h); +} + +static void +_ecore_evas_obj_callback_del(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__) +{ + Ecore_Evas *ee = data; + _ecore_evas_object_dissociate(ee, obj); + ecore_evas_free(ee); +} + +static void +_ecore_evas_obj_callback_del_dissociate(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__) +{ + Ecore_Evas *ee = data; + _ecore_evas_object_dissociate(ee, obj); +} + +static void +_ecore_evas_delete_request(Ecore_Evas *ee) +{ + Evas_Object *obj = _ecore_evas_associate_get(ee); + _ecore_evas_object_dissociate(ee, obj); + evas_object_del(obj); + ecore_evas_free(ee); +} + +static void +_ecore_evas_destroy(Ecore_Evas *ee) +{ + Evas_Object *obj = _ecore_evas_associate_get(ee); + if (!obj) + return; + _ecore_evas_object_dissociate(ee, obj); + evas_object_del(obj); +} + +static void +_ecore_evas_resize(Ecore_Evas *ee) +{ + Evas_Object *obj = _ecore_evas_associate_get(ee); + Evas_Coord w, h; + ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); + evas_object_resize(obj, w, h); +} + +static void +_ecore_evas_pre_free(Ecore_Evas *ee) +{ + Evas_Object *obj = _ecore_evas_associate_get(ee); + if (!obj) + return; + _ecore_evas_object_dissociate(ee, obj); + evas_object_del(obj); +} + +static int +_ecore_evas_object_evas_check(const char *function __UNUSED__, const Ecore_Evas *ee, const Evas_Object *obj) +{ + const char *name, *type; + Evas *e; + + e = evas_object_evas_get(obj); + if (e == ee->evas) + return 1; + + name = evas_object_name_get(obj); + type = evas_object_type_get(obj); + + ERR("ERROR: %s(): object %p (name=\"%s\", type=\"%s\") evas " + "is not the same as this Ecore_Evas evas: %p != %p", + function, obj, + name ? name : "", type ? type : "", e, ee->evas); + fflush(stderr); + if (getenv("ECORE_ERROR_ABORT")) abort(); + + return 0; +} + +EAPI Eina_Bool +ecore_evas_object_associate(Ecore_Evas *ee, Evas_Object *obj, Ecore_Evas_Object_Associate_Flags flags) +{ + Ecore_Evas *old_ee; + Evas_Object *old_obj; + + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, __FUNCTION__); + return EINA_FALSE; + } + + CHECK_PARAM_POINTER_RETURN("obj", obj, EINA_FALSE); + if (!_ecore_evas_object_evas_check(__FUNCTION__, ee, obj)) + return EINA_FALSE; + + old_ee = _evas_object_associate_get(obj);; + if (old_ee) + ecore_evas_object_dissociate(old_ee, obj); + + old_obj = _ecore_evas_associate_get(ee); + if (old_obj) + ecore_evas_object_dissociate(ee, old_obj); + + _ecore_evas_object_associate(ee, obj, flags); + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_evas_object_dissociate(Ecore_Evas *ee, Evas_Object *obj) +{ + Ecore_Evas *old_ee; + Evas_Object *old_obj; + + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, __FUNCTION__); + return EINA_FALSE; + } + + CHECK_PARAM_POINTER_RETURN("obj", obj, EINA_FALSE); + old_ee = _evas_object_associate_get(obj); + if (ee != old_ee) { + ERR("ERROR: trying to dissociate object that is not using " + "this Ecore_Evas: %p != %p", ee, old_ee); + return EINA_FALSE; + } + + old_obj = _ecore_evas_associate_get(ee); + if (old_obj != obj) { + ERR("ERROR: trying to dissociate object that is not being " + "used by this Ecore_Evas: %p != %p", old_obj, obj); + return EINA_FALSE; + } + + _ecore_evas_object_dissociate(ee, obj); + + return EINA_TRUE; +} + +EAPI Evas_Object * +ecore_evas_object_associate_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, __FUNCTION__); + return NULL; + } + return _ecore_evas_associate_get(ee); +} + +static void +_ecore_evas_object_associate(Ecore_Evas *ee, Evas_Object *obj, Ecore_Evas_Object_Associate_Flags flags) +{ + evas_object_event_callback_add + (obj, EVAS_CALLBACK_SHOW, + _ecore_evas_obj_callback_show, ee); + evas_object_event_callback_add + (obj, EVAS_CALLBACK_HIDE, + _ecore_evas_obj_callback_hide, ee); + evas_object_event_callback_add + (obj, EVAS_CALLBACK_RESIZE, + _ecore_evas_obj_callback_resize, ee); + evas_object_event_callback_add + (obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, + _ecore_evas_obj_callback_changed_size_hints, ee); + if (flags & ECORE_EVAS_OBJECT_ASSOCIATE_DEL) + evas_object_event_callback_add + (obj, EVAS_CALLBACK_DEL, _ecore_evas_obj_callback_del, ee); + else + evas_object_event_callback_add + (obj, EVAS_CALLBACK_DEL, _ecore_evas_obj_callback_del_dissociate, ee); + + evas_object_intercept_move_callback_add + (obj, _ecore_evas_obj_intercept_move, ee); + + if (flags & ECORE_EVAS_OBJECT_ASSOCIATE_STACK) + { + evas_object_intercept_raise_callback_add + (obj, _ecore_evas_obj_intercept_raise, ee); + evas_object_intercept_lower_callback_add + (obj, _ecore_evas_obj_intercept_lower, ee); + evas_object_intercept_stack_above_callback_add + (obj, _ecore_evas_obj_intercept_stack_above, ee); + evas_object_intercept_stack_below_callback_add + (obj, _ecore_evas_obj_intercept_stack_below, ee); + } + + if (flags & ECORE_EVAS_OBJECT_ASSOCIATE_LAYER) + evas_object_intercept_layer_set_callback_add + (obj, _ecore_evas_obj_intercept_layer_set, ee); + + if (flags & ECORE_EVAS_OBJECT_ASSOCIATE_DEL) + { + ecore_evas_callback_delete_request_set(ee, _ecore_evas_delete_request); + ecore_evas_callback_destroy_set(ee, _ecore_evas_destroy); + } + ecore_evas_callback_pre_free_set(ee, _ecore_evas_pre_free); + ecore_evas_callback_resize_set(ee, _ecore_evas_resize); + + _evas_object_associate_set(obj, ee); + _ecore_evas_associate_set(ee, obj); +} + +static void +_ecore_evas_object_dissociate(Ecore_Evas *ee, Evas_Object *obj) +{ + evas_object_event_callback_del_full + (obj, EVAS_CALLBACK_SHOW, + _ecore_evas_obj_callback_show, ee); + evas_object_event_callback_del_full + (obj, EVAS_CALLBACK_HIDE, + _ecore_evas_obj_callback_hide, ee); + evas_object_event_callback_del_full + (obj, EVAS_CALLBACK_RESIZE, + _ecore_evas_obj_callback_resize, ee); + evas_object_event_callback_del_full + (obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, + _ecore_evas_obj_callback_changed_size_hints, ee); + evas_object_event_callback_del_full + (obj, EVAS_CALLBACK_DEL, _ecore_evas_obj_callback_del, ee); + evas_object_event_callback_del_full + (obj, EVAS_CALLBACK_DEL, _ecore_evas_obj_callback_del_dissociate, ee); + + evas_object_intercept_move_callback_del + (obj, _ecore_evas_obj_intercept_move); + + evas_object_intercept_raise_callback_del + (obj, _ecore_evas_obj_intercept_raise); + evas_object_intercept_lower_callback_del + (obj, _ecore_evas_obj_intercept_lower); + evas_object_intercept_stack_above_callback_del + (obj, _ecore_evas_obj_intercept_stack_above); + evas_object_intercept_stack_below_callback_del + (obj, _ecore_evas_obj_intercept_stack_below); + + evas_object_intercept_layer_set_callback_del + (obj, _ecore_evas_obj_intercept_layer_set); + + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, __FUNCTION__); + } + else + { + if (ee->func.fn_delete_request == _ecore_evas_delete_request) + ecore_evas_callback_delete_request_set(ee, NULL); + if (ee->func.fn_destroy == _ecore_evas_destroy) + ecore_evas_callback_destroy_set(ee, NULL); + if (ee->func.fn_resize == _ecore_evas_resize) + ecore_evas_callback_resize_set(ee, NULL); + if (ee->func.fn_pre_free == _ecore_evas_pre_free) + ecore_evas_callback_pre_free_set(ee, NULL); + + _ecore_evas_associate_del(ee); + } + + _evas_object_associate_del(obj); +} + +/** + * Helper ecore_getopt callback to list available Ecore_Evas engines. + * + * This will list all available engines except buffer, this is useful + * for applications to let user choose how they should create windows + * with ecore_evas_new(). + * + * @c callback_data value is used as @c FILE* and says where to output + * messages, by default it is @c stdout. You can specify this value + * with ECORE_GETOPT_CALLBACK_FULL() or ECORE_GETOPT_CALLBACK_ARGS(). + * + * If there is a boolean storage provided, then it is marked with 1 + * when this option is executed. + * @param parser This parameter isn't in use. + * @param desc This parameter isn't in use. + * @param str This parameter isn't in use. + * @param data The data to be used. + * @param storage The storage to be used. + * @return The function always return 1. + */ +unsigned char +ecore_getopt_callback_ecore_evas_list_engines(const Ecore_Getopt *parser __UNUSED__, const Ecore_Getopt_Desc *desc __UNUSED__, const char *str __UNUSED__, void *data, Ecore_Getopt_Value *storage) +{ + Eina_List *lst, *n; + const char *engine; + FILE *fp = data; + + if (!fp) + fp = stdout; + + lst = ecore_evas_engines_get(); + + fputs("supported engines:\n", fp); + EINA_LIST_FOREACH(lst, n, engine) + if (strcmp(engine, "buffer") != 0) + fprintf(fp, "\t%s\n", engine); + + ecore_evas_engines_free(lst); + + if (storage->boolp) + *storage->boolp = 1; + + return 1; +} diff --git a/src/lib/ecore_evas/ecore_evas_wayland_egl.c b/src/lib/ecore_evas/ecore_evas_wayland_egl.c new file mode 100644 index 0000000..f881a46 --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas_wayland_egl.c @@ -0,0 +1,1141 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +//#define LOGFNS 1 + +#ifdef LOGFNS +# include +# define LOGFN(fl, ln, fn) \ + printf("-ECORE_EVAS-WL: %25s: %5i - %s\n", fl, ln, fn); +#else +# define LOGFN(fl, ln, fn) +#endif + +#ifdef BUILD_ECORE_EVAS_WAYLAND_EGL +# include +# include +# include +# include +# include +#endif + +#include +#include +#include + +#include "ecore_evas_private.h" +#include "Ecore_Evas.h" + +#ifdef BUILD_ECORE_EVAS_WAYLAND_EGL +# include +# include + +/* local structures */ +typedef struct _EE_Wl_Smart_Data EE_Wl_Smart_Data; +struct _EE_Wl_Smart_Data +{ + Evas_Object *frame; + Evas_Object *text; + Evas_Coord x, y, w, h; +}; + +/* local function prototypes */ +static int _ecore_evas_wl_init(void); +static int _ecore_evas_wl_shutdown(void); +static void _ecore_evas_wl_pre_free(Ecore_Evas *ee); +static void _ecore_evas_wl_free(Ecore_Evas *ee); +static void _ecore_evas_wl_callback_resize_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)); +static void _ecore_evas_wl_callback_move_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)); +static void _ecore_evas_wl_callback_delete_request_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)); +static void _ecore_evas_wl_callback_focus_in_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)); +static void _ecore_evas_wl_callback_focus_out_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)); +static void _ecore_evas_wl_callback_mouse_in_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)); +static void _ecore_evas_wl_callback_mouse_out_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)); +static void _ecore_evas_wl_move(Ecore_Evas *ee, int x, int y); +static void _ecore_evas_wl_resize(Ecore_Evas *ee, int w, int h); +static void _ecore_evas_wl_show(Ecore_Evas *ee); +static void _ecore_evas_wl_hide(Ecore_Evas *ee); +static void _ecore_evas_wl_raise(Ecore_Evas *ee); +static void _ecore_evas_wl_title_set(Ecore_Evas *ee, const char *title); +static void _ecore_evas_wl_name_class_set(Ecore_Evas *ee, const char *n, const char *c); +static void _ecore_evas_wl_size_min_set(Ecore_Evas *ee, int w, int h); +static void _ecore_evas_wl_size_max_set(Ecore_Evas *ee, int w, int h); +static void _ecore_evas_wl_size_base_set(Ecore_Evas *ee, int w, int h); +static void _ecore_evas_wl_size_step_set(Ecore_Evas *ee, int w, int h); +static void _ecore_evas_wl_layer_set(Ecore_Evas *ee, int layer); +static void _ecore_evas_wl_iconified_set(Ecore_Evas *ee, int iconify); +static void _ecore_evas_wl_maximized_set(Ecore_Evas *ee, int max); +static void _ecore_evas_wl_fullscreen_set(Ecore_Evas *ee, int full); +static void _ecore_evas_wl_ignore_events_set(Ecore_Evas *ee, int ignore); +static void _ecore_evas_wl_alpha_set(Ecore_Evas *ee, int alpha); +static void _ecore_evas_wl_transparent_set(Ecore_Evas *ee, int transparent); +static int _ecore_evas_wl_render(Ecore_Evas *ee); +static void _ecore_evas_wl_screen_geometry_get(const Ecore_Evas *ee __UNUSED__, int *x, int *y, int *w, int *h); +static void _ecore_evas_wl_screen_dpi_get(const Ecore_Evas *ee __UNUSED__, int *xdpi, int *ydpi); +static Eina_Bool _ecore_evas_wl_cb_mouse_in(void *data __UNUSED__, int type __UNUSED__, void *event); +static Eina_Bool _ecore_evas_wl_cb_mouse_out(void *data __UNUSED__, int type __UNUSED__, void *event); +static Eina_Bool _ecore_evas_wl_cb_focus_in(void *data __UNUSED__, int type __UNUSED__, void *event); +static Eina_Bool _ecore_evas_wl_cb_focus_out(void *data __UNUSED__, int type __UNUSED__, void *event); +static Eina_Bool _ecore_evas_wl_cb_window_configure(void *data __UNUSED__, int type __UNUSED__, void *event); + +/* SMART stuff for frame */ +static Evas_Smart *_ecore_evas_wl_smart = NULL; + +static void _ecore_evas_wl_smart_init(void); +static void _ecore_evas_wl_smart_add(Evas_Object *obj); +static void _ecore_evas_wl_smart_del(Evas_Object *obj); +static void _ecore_evas_wl_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h); +static void _ecore_evas_wl_smart_show(Evas_Object *obj); +static void _ecore_evas_wl_smart_hide(Evas_Object *obj); + +static Evas_Object *_ecore_evas_wl_frame_add(Evas *evas); + +/* local variables */ +static int _ecore_evas_wl_init_count = 0; +static Ecore_Event_Handler *_ecore_evas_wl_event_hdls[5]; + +static Ecore_Evas_Engine_Func _ecore_wl_engine_func = +{ + _ecore_evas_wl_free, + _ecore_evas_wl_callback_resize_set, + _ecore_evas_wl_callback_move_set, + NULL, + NULL, + _ecore_evas_wl_callback_delete_request_set, + NULL, + _ecore_evas_wl_callback_focus_in_set, + _ecore_evas_wl_callback_focus_out_set, + _ecore_evas_wl_callback_mouse_in_set, + _ecore_evas_wl_callback_mouse_out_set, + NULL, // sticky_set + NULL, // unsticky_set + NULL, // pre_render_set + NULL, // post_render_set + _ecore_evas_wl_move, + NULL, // managed_move + _ecore_evas_wl_resize, + NULL, // move_resize + NULL, // rotation_set + NULL, // shaped_set + _ecore_evas_wl_show, + _ecore_evas_wl_hide, + _ecore_evas_wl_raise, + NULL, // lower + NULL, // activate + _ecore_evas_wl_title_set, + _ecore_evas_wl_name_class_set, + _ecore_evas_wl_size_min_set, + _ecore_evas_wl_size_max_set, + _ecore_evas_wl_size_base_set, + _ecore_evas_wl_size_step_set, + NULL, // object_cursor_set + _ecore_evas_wl_layer_set, + NULL, // focus set + _ecore_evas_wl_iconified_set, + NULL, // borderless set + NULL, // override set + _ecore_evas_wl_maximized_set, + _ecore_evas_wl_fullscreen_set, + NULL, // func avoid_damage set + NULL, // func withdrawn set + NULL, // func sticky set + _ecore_evas_wl_ignore_events_set, + _ecore_evas_wl_alpha_set, + _ecore_evas_wl_transparent_set, + NULL, // func profiles set + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_wl_render, + _ecore_evas_wl_screen_geometry_get, + _ecore_evas_wl_screen_dpi_get +}; + +/* external variables */ + +/* external functions */ +EAPI Ecore_Evas * +ecore_evas_wayland_egl_new(const char *disp_name, unsigned int parent, int x, int y, int w, int h, Eina_Bool frame) +{ + Ecore_Wl_Window *p = NULL; + Evas_Engine_Info_Wayland_Egl *einfo; + Ecore_Evas *ee; + int method = 0, count = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(method = evas_render_method_lookup("wayland_egl"))) + { + ERR("Render method lookup failed for Wayland_Egl"); + return NULL; + } + + count = ecore_wl_init(disp_name); + if (!count) + { + ERR("Failed to initialize Ecore_Wayland"); + return NULL; + } + else if (count == 1) + ecore_wl_display_iterate(); + + if (!(ee = calloc(1, sizeof(Ecore_Evas)))) + { + ERR("Failed to allocate Ecore_Evas"); + ecore_wl_shutdown(); + return NULL; + } + + ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); + + _ecore_evas_wl_init(); + + ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_wl_engine_func; + + ee->driver = "wayland_egl"; + if (disp_name) ee->name = strdup(disp_name); + + if (w < 1) w = 1; + if (h < 1) h = 1; + + ee->x = x; + ee->y = y; + ee->w = w; + ee->h = h; + ee->req.x = ee->x; + ee->req.y = ee->y; + ee->req.w = ee->w; + ee->req.h = ee->h; + ee->rotation = 0; + ee->prop.max.w = 32767; + ee->prop.max.h = 32767; + ee->prop.layer = 4; + ee->prop.request_pos = 0; + ee->prop.sticky = 0; + ee->prop.draw_frame = frame; + ee->alpha = EINA_FALSE; + + ee->evas = evas_new(); + evas_data_attach_set(ee->evas, ee); + evas_output_method_set(ee->evas, method); + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + + /* FIXME: This needs to be set based on theme & scale */ + if (ee->prop.draw_frame) + evas_output_framespace_set(ee->evas, 4, 18, 8, 22); + + if (parent) + p = ecore_wl_window_find(parent); + + /* FIXME: Get if parent is alpha, and set */ + + ee->engine.wl.parent = p; + ee->engine.wl.win = + ecore_wl_window_new(p, x, y, w, h, ECORE_WL_WINDOW_BUFFER_TYPE_EGL_WINDOW); + ee->prop.window = ee->engine.wl.win->id; + + if ((einfo = (Evas_Engine_Info_Wayland_Egl *)evas_engine_info_get(ee->evas))) + { + einfo->info.display = ecore_wl_display_get(); + einfo->info.destination_alpha = ee->alpha; + einfo->info.rotation = ee->rotation; + einfo->info.depth = 32; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("Failed to set Evas Engine Info for '%s'", ee->driver); + ecore_evas_free(ee); + _ecore_evas_wl_shutdown(); + ecore_wl_shutdown(); + return NULL; + } + } + else + { + ERR("Failed to get Evas Engine Info for '%s'", ee->driver); + ecore_evas_free(ee); + _ecore_evas_wl_shutdown(); + ecore_wl_shutdown(); + return NULL; + } + + ecore_evas_callback_pre_free_set(ee, _ecore_evas_wl_pre_free); + + if (ee->prop.draw_frame) + { + ee->engine.wl.frame = _ecore_evas_wl_frame_add(ee->evas); + evas_object_is_frame_object_set(ee->engine.wl.frame, EINA_TRUE); + evas_object_move(ee->engine.wl.frame, 0, 0); + } + + _ecore_evas_register(ee); + ecore_evas_input_event_register(ee); + + ecore_event_window_register(ee->prop.window, ee, ee->evas, + (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, + (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, + (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, + (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); + + /* evas_event_feed_mouse_in(ee->evas, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff), NULL); */ + + return ee; +} + +/* local functions */ +static int +_ecore_evas_wl_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (++_ecore_evas_wl_init_count != 1) + return _ecore_evas_wl_init_count; + + _ecore_evas_wl_event_hdls[0] = + ecore_event_handler_add(ECORE_WL_EVENT_MOUSE_IN, + _ecore_evas_wl_cb_mouse_in, NULL); + _ecore_evas_wl_event_hdls[1] = + ecore_event_handler_add(ECORE_WL_EVENT_MOUSE_OUT, + _ecore_evas_wl_cb_mouse_out, NULL); + _ecore_evas_wl_event_hdls[2] = + ecore_event_handler_add(ECORE_WL_EVENT_FOCUS_IN, + _ecore_evas_wl_cb_focus_in, NULL); + _ecore_evas_wl_event_hdls[3] = + ecore_event_handler_add(ECORE_WL_EVENT_FOCUS_OUT, + _ecore_evas_wl_cb_focus_out, NULL); + _ecore_evas_wl_event_hdls[4] = + ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_CONFIGURE, + _ecore_evas_wl_cb_window_configure, NULL); + + ecore_event_evas_init(); + + return _ecore_evas_wl_init_count; +} + +static int +_ecore_evas_wl_shutdown(void) +{ + unsigned int i = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (--_ecore_evas_wl_init_count != 0) + return _ecore_evas_wl_init_count; + + for (i = 0; i < sizeof(_ecore_evas_wl_event_hdls) / sizeof(Ecore_Event_Handler *); i++) + { + if (_ecore_evas_wl_event_hdls[i]) + ecore_event_handler_del(_ecore_evas_wl_event_hdls[i]); + } + + ecore_event_evas_shutdown(); + + return _ecore_evas_wl_init_count; +} + +static void +_ecore_evas_wl_pre_free(Ecore_Evas *ee) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (ee->engine.wl.frame) evas_object_del(ee->engine.wl.frame); +} + +static void +_ecore_evas_wl_free(Ecore_Evas *ee) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (ee->engine.wl.win) ecore_wl_window_free(ee->engine.wl.win); + ee->engine.wl.win = NULL; + + ecore_event_window_unregister(ee->prop.window); + ecore_evas_input_event_unregister(ee); + + _ecore_evas_wl_shutdown(); + ecore_wl_shutdown(); +} + +static void +_ecore_evas_wl_callback_resize_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + ee->func.fn_resize = func; +} + +static void +_ecore_evas_wl_callback_move_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + ee->func.fn_move = func; +} + +static void +_ecore_evas_wl_callback_delete_request_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + ee->func.fn_delete_request = func; +} + +static void +_ecore_evas_wl_callback_focus_in_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + ee->func.fn_focus_in = func; +} + +static void +_ecore_evas_wl_callback_focus_out_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + ee->func.fn_focus_out = func; +} + +static void +_ecore_evas_wl_callback_mouse_in_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + ee->func.fn_mouse_in = func; +} + +static void +_ecore_evas_wl_callback_mouse_out_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + ee->func.fn_mouse_out = func; +} + +static void +_ecore_evas_wl_move(Ecore_Evas *ee, int x, int y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + ee->req.x = x; + ee->req.y = y; + if ((ee->x != x) || (ee->y != y)) + { + ee->x = x; + ee->y = y; + if (ee->engine.wl.win) + ecore_wl_window_update_location(ee->engine.wl.win, x, y); + if (ee->func.fn_move) ee->func.fn_move(ee); + } +} + +static void +_ecore_evas_wl_resize(Ecore_Evas *ee, int w, int h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + int fw = 0, fh = 0; + + if (!ee) return; + if (w < 1) w = 1; + if (h < 1) h = 1; + + ee->req.w = w; + ee->req.h = h; + + if (!ee->prop.fullscreen) + { + if (ee->prop.min.w > w) w = ee->prop.min.w; + else if (w > ee->prop.max.w) w = ee->prop.max.w; + if (ee->prop.min.h > h) h = ee->prop.min.h; + else if (h > ee->prop.max.h) h = ee->prop.max.h; + + evas_output_framespace_get(ee->evas, NULL, NULL, &fw, &fh); + w += fw; + h += fh; + } + +// ecore_wl_window_damage(ee->engine.wl.win, 0, 0, ee->w, ee->h); + + if ((ee->w != w) || (ee->h != h)) + { + ee->w = w; + ee->h = h; + + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + evas_output_size_set(ee->evas, h, w); + evas_output_viewport_set(ee->evas, 0, 0, h, w); + } + else + { + evas_output_size_set(ee->evas, w, h); + evas_output_viewport_set(ee->evas, 0, 0, w, h); + } + + if (ee->prop.avoid_damage) + { + int pdam = 0; + + pdam = ecore_evas_avoid_damage_get(ee); + ecore_evas_avoid_damage_set(ee, 0); + ecore_evas_avoid_damage_set(ee, pdam); + } + + if (ee->engine.wl.frame) + evas_object_resize(ee->engine.wl.frame, w, h); + + /* set new engine destination */ + /* evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); */ + + /* ecore_wl_window_damage(ee->engine.wl.win, 0, 0, ee->w, ee->h); */ + + // WAS ACTIVE + /* ecore_wl_flush(); */ + + if (ee->engine.wl.win) + { + ecore_wl_window_update_size(ee->engine.wl.win, w, h); + ecore_wl_window_buffer_attach(ee->engine.wl.win, NULL, 0, 0); + } + + if (ee->func.fn_resize) ee->func.fn_resize(ee); + } +} + +static void +_ecore_evas_wl_show(Ecore_Evas *ee) +{ + Evas_Engine_Info_Wayland_Egl *einfo; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if ((!ee) || (ee->visible)) return; + + if (ee->engine.wl.win) + { + ecore_wl_window_show(ee->engine.wl.win); + ecore_wl_window_update_size(ee->engine.wl.win, ee->w, ee->h); + ecore_wl_window_buffer_attach(ee->engine.wl.win, NULL, 0, 0); + + if ((ee->prop.clas) && (ee->engine.wl.win->shell_surface)) + wl_shell_surface_set_class(ee->engine.wl.win->shell_surface, + ee->prop.clas); + if ((ee->prop.title) && (ee->engine.wl.win->shell_surface)) + wl_shell_surface_set_title(ee->engine.wl.win->shell_surface, + ee->prop.title); + } + + if (ee->engine.wl.frame) + { + evas_object_show(ee->engine.wl.frame); + evas_object_resize(ee->engine.wl.frame, ee->w, ee->h); + } + + if (ee->engine.wl.win) + { + einfo = (Evas_Engine_Info_Wayland_Egl *)evas_engine_info_get(ee->evas); + if (!einfo) + { + ERR("Failed to get Evas Engine Info for '%s'", ee->driver); + return; + } + + einfo->info.surface = ecore_wl_window_surface_get(ee->engine.wl.win); + /* if (einfo->info.surface) */ + evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); + /* else */ + /* printf("Failed to get a Surface from Ecore_Wl\n"); */ + } + + ee->visible = 1; + if (ee->func.fn_show) ee->func.fn_show(ee); +} + +static void +_ecore_evas_wl_hide(Ecore_Evas *ee) +{ + Evas_Engine_Info_Wayland_Egl *einfo; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if ((!ee) || (!ee->visible)) return; + + einfo = (Evas_Engine_Info_Wayland_Egl *)evas_engine_info_get(ee->evas); + if (einfo) + { + einfo->info.surface = NULL; + evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); + } + + if (ee->engine.wl.win) + ecore_wl_window_hide(ee->engine.wl.win); + + ee->visible = 0; + ee->should_be_visible = 0; + + if (ee->func.fn_hide) ee->func.fn_hide(ee); +} + +static void +_ecore_evas_wl_raise(Ecore_Evas *ee) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if ((!ee) || (!ee->visible)) return; + ecore_wl_window_raise(ee->engine.wl.win); +} + +static void +_ecore_evas_wl_title_set(Ecore_Evas *ee, const char *title) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (ee->prop.title) free(ee->prop.title); + ee->prop.title = NULL; + if (title) ee->prop.title = strdup(title); + if ((ee->prop.draw_frame) && (ee->engine.wl.frame)) + { + EE_Wl_Smart_Data *sd; + + if (!(sd = evas_object_smart_data_get(ee->engine.wl.frame))) return; + evas_object_text_text_set(sd->text, ee->prop.title); + } + + if ((ee->prop.title) && (ee->engine.wl.win->shell_surface)) + wl_shell_surface_set_title(ee->engine.wl.win->shell_surface, + ee->prop.title); +} + +static void +_ecore_evas_wl_name_class_set(Ecore_Evas *ee, const char *n, const char *c) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (ee->prop.name) free(ee->prop.name); + if (ee->prop.clas) free(ee->prop.clas); + ee->prop.name = NULL; + ee->prop.clas = NULL; + if (n) ee->prop.name = strdup(n); + if (c) ee->prop.clas = strdup(c); + + if ((ee->prop.clas) && (ee->engine.wl.win->shell_surface)) + wl_shell_surface_set_class(ee->engine.wl.win->shell_surface, + ee->prop.clas); +} + +static void +_ecore_evas_wl_size_min_set(Ecore_Evas *ee, int w, int h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (w < 0) w = 0; + if (h < 0) h = 0; + if ((ee->prop.min.w == w) && (ee->prop.min.h == h)) return; + ee->prop.min.w = w; + ee->prop.min.h = h; +} + +static void +_ecore_evas_wl_size_max_set(Ecore_Evas *ee, int w, int h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (w < 0) w = 0; + if (h < 0) h = 0; + if ((ee->prop.max.w == w) && (ee->prop.max.h == h)) return; + ee->prop.max.w = w; + ee->prop.max.h = h; +} + +static void +_ecore_evas_wl_size_base_set(Ecore_Evas *ee, int w, int h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (w < 0) w = 0; + if (h < 0) h = 0; + if ((ee->prop.base.w == w) && (ee->prop.base.h == h)) return; + ee->prop.base.w = w; + ee->prop.base.h = h; +} + +static void +_ecore_evas_wl_size_step_set(Ecore_Evas *ee, int w, int h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (w < 0) w = 0; + if (h < 0) h = 0; + if ((ee->prop.step.w == w) && (ee->prop.step.h == h)) return; + ee->prop.step.w = w; + ee->prop.step.h = h; +} + +static void +_ecore_evas_wl_layer_set(Ecore_Evas *ee, int layer) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (ee->prop.layer == layer) return; + if (layer < 1) layer = 1; + else if (layer > 255) layer = 255; + ee->prop.layer = layer; +} + +static void +_ecore_evas_wl_iconified_set(Ecore_Evas *ee, int iconify) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (ee->prop.iconified == iconify) return; + ee->prop.iconified = iconify; + /* FIXME: Implement this in Wayland someshow */ +} + +static void +_ecore_evas_wl_maximized_set(Ecore_Evas *ee, int max) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (ee->prop.maximized == max) return; + ee->prop.maximized = max; + ecore_wl_window_maximized_set(ee->engine.wl.win, max); +} + +static void +_ecore_evas_wl_fullscreen_set(Ecore_Evas *ee, int full) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (ee->prop.fullscreen == full) return; + ee->prop.fullscreen = full; + ecore_wl_window_fullscreen_set(ee->engine.wl.win, full); +} + +static void +_ecore_evas_wl_ignore_events_set(Ecore_Evas *ee, int ignore) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + ee->ignore_events = ignore; + /* NB: Hmmm, may need to pass this to ecore_wl_window in the future */ +} + +static void +_ecore_evas_wl_alpha_set(Ecore_Evas *ee, int alpha) +{ + Evas_Engine_Info_Wayland_Egl *einfo; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if ((ee->alpha == alpha)) return; + ee->alpha = alpha; + if ((einfo = (Evas_Engine_Info_Wayland_Egl *)evas_engine_info_get(ee->evas))) + { + einfo->info.destination_alpha = alpha; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + } +} + +static void +_ecore_evas_wl_transparent_set(Ecore_Evas *ee, int transparent) +{ + Evas_Engine_Info_Wayland_Egl *einfo; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if ((ee->transparent == transparent)) return; + ee->transparent = transparent; + if (!ee->visible) return; + if ((einfo = (Evas_Engine_Info_Wayland_Egl *)evas_engine_info_get(ee->evas))) + { + einfo->info.destination_alpha = transparent; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + } +} + +static int +_ecore_evas_wl_render(Ecore_Evas *ee) +{ + int rend = 0; + + if (!ee) return 0; + if (!ee->visible) + evas_norender(ee->evas); + else + { + Eina_List *ll = NULL, *updates = NULL; + Ecore_Evas *ee2 = NULL; + + if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee); + + EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2) + { + if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2); + if (ee2->engine.func->fn_render) + rend |= ee2->engine.func->fn_render(ee2); + if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2); + } + + if ((updates = evas_render_updates(ee->evas))) + { + Eina_List *l = NULL; + Eina_Rectangle *r; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + EINA_LIST_FOREACH(updates, l, r) + ecore_wl_window_damage(ee->engine.wl.win, + r->x, r->y, r->w, r->h); + + ecore_wl_flush(); + + evas_render_updates_free(updates); + _ecore_evas_idle_timeout_update(ee); + rend = 1; + } + + if (ee->func.fn_post_render) ee->func.fn_post_render(ee); + } + return rend; +} + +static void +_ecore_evas_wl_screen_geometry_get(const Ecore_Evas *ee __UNUSED__, int *x, int *y, int *w, int *h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (x) *x = 0; + if (y) *y = 0; + ecore_wl_screen_size_get(w, h); +} + +static void +_ecore_evas_wl_screen_dpi_get(const Ecore_Evas *ee __UNUSED__, int *xdpi, int *ydpi) +{ + int dpi = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (xdpi) *xdpi = 0; + if (ydpi) *ydpi = 0; + /* FIXME: Ideally this needs to get the DPI from a specific screen */ + dpi = ecore_wl_dpi_get(); + if (xdpi) *xdpi = dpi; + if (ydpi) *ydpi = dpi; +} + +void +_ecore_evas_wayland_egl_resize(Ecore_Evas *ee, int location) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (ee->engine.wl.win) + { + Evas_Engine_Info_Wayland_Egl *einfo; + + if ((einfo = (Evas_Engine_Info_Wayland_Egl *)evas_engine_info_get(ee->evas))) + { + einfo->info.edges = location; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + + ee->engine.wl.win->resizing = EINA_TRUE; + ecore_wl_window_resize(ee->engine.wl.win, ee->w, ee->h, location); + } +} + +void +_ecore_evas_wayland_egl_move(Ecore_Evas *ee, int x, int y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (ee->engine.wl.win) + { + ee->engine.wl.win->moving = EINA_TRUE; + ecore_wl_window_move(ee->engine.wl.win, x, y); + } +} + +static Eina_Bool +_ecore_evas_wl_cb_mouse_in(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Wl_Event_Mouse_In *ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ev = event; + ee = ecore_event_window_match(ev->window); + if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; + if (ev->window != ee->prop.window) return ECORE_CALLBACK_PASS_ON; + if (ee->func.fn_mouse_in) ee->func.fn_mouse_in(ee); + ecore_event_evas_modifier_lock_update(ee->evas, ev->modifiers); + evas_event_feed_mouse_in(ee->evas, ev->timestamp, NULL); + _ecore_evas_mouse_move_process(ee, ev->x, ev->y, ev->timestamp); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_wl_cb_mouse_out(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Wl_Event_Mouse_Out *ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ev = event; + ee = ecore_event_window_match(ev->window); + if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; + if (ev->window != ee->prop.window) return ECORE_CALLBACK_PASS_ON; + ecore_event_evas_modifier_lock_update(ee->evas, ev->modifiers); + _ecore_evas_mouse_move_process(ee, ev->x, ev->y, ev->timestamp); + evas_event_feed_mouse_out(ee->evas, ev->timestamp, NULL); + if (ee->func.fn_mouse_out) ee->func.fn_mouse_out(ee); + if (ee->prop.cursor.object) evas_object_hide(ee->prop.cursor.object); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_wl_cb_focus_in(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Wl_Event_Focus_In *ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ev = event; + ee = ecore_event_window_match(ev->win); + if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; + if (ev->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; + ee->prop.focused = 1; + evas_focus_in(ee->evas); + if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_wl_cb_focus_out(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Wl_Event_Focus_In *ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ev = event; + ee = ecore_event_window_match(ev->win); + if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; + if (ev->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; + evas_focus_out(ee->evas); + ee->prop.focused = 0; + if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_wl_cb_window_configure(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Wl_Event_Window_Configure *ev; + int nw = 0, nh = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ev = event; + ee = ecore_event_window_match(ev->win); + if (!ee) return ECORE_CALLBACK_PASS_ON; + if (ev->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; + + if (ee->prop.fullscreen) + { + _ecore_evas_wl_move(ee, ev->x, ev->y); + _ecore_evas_wl_resize(ee, ev->w, ev->h); + + return ECORE_CALLBACK_PASS_ON; + } + + if ((ee->x != ev->x) || (ee->y != ev->y)) + { + ee->req.x = ee->x; + ee->req.y = ee->y; + if (ee->func.fn_move) ee->func.fn_move(ee); + } + + nw = ev->w; + nh = ev->h; + + if ((ee->prop.maximized) || (!ee->prop.fullscreen)) + { + int fw = 0, fh = 0; + + evas_output_framespace_get(ee->evas, NULL, NULL, &fw, &fh); + nw = ev->w - fw; + nh = ev->h - fh; + } + + if (ee->prop.min.w > nw) nw = ee->prop.min.w; + else if (nw > ee->prop.max.w) nw = ee->prop.max.w; + if (ee->prop.min.h > nh) nh = ee->prop.min.h; + else if (nh > ee->prop.max.h) nh = ee->prop.max.h; + + if ((ee->w != nw) || (ee->h != nh)) + { + ee->req.w = nw; + ee->req.h = nh; + if (ee->func.fn_resize) ee->func.fn_resize(ee); + } + + return ECORE_CALLBACK_PASS_ON; +} + +static void +_ecore_evas_wl_smart_init(void) +{ + if (_ecore_evas_wl_smart) return; + { + static const Evas_Smart_Class sc = + { + "ecore_evas_wl_frame", EVAS_SMART_CLASS_VERSION, + _ecore_evas_wl_smart_add, + _ecore_evas_wl_smart_del, + NULL, + _ecore_evas_wl_smart_resize, + _ecore_evas_wl_smart_show, + _ecore_evas_wl_smart_hide, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + }; + _ecore_evas_wl_smart = evas_smart_class_new(&sc); + } +} + +static void +_ecore_evas_wl_smart_add(Evas_Object *obj) +{ + EE_Wl_Smart_Data *sd; + Evas *evas; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(sd = calloc(1, sizeof(EE_Wl_Smart_Data)))) return; + + evas = evas_object_evas_get(obj); + + sd->x = 0; + sd->y = 0; + sd->w = 1; + sd->h = 1; + + sd->frame = evas_object_rectangle_add(evas); + evas_object_is_frame_object_set(sd->frame, EINA_TRUE); + evas_object_color_set(sd->frame, 249, 249, 249, 255); + evas_object_smart_member_add(sd->frame, obj); + + sd->text = evas_object_text_add(evas); + evas_object_color_set(sd->text, 0, 0, 0, 255); + evas_object_text_style_set(sd->text, EVAS_TEXT_STYLE_PLAIN); + evas_object_text_font_set(sd->text, "Sans", 10); + evas_object_text_text_set(sd->text, "Smart Test"); + + evas_object_smart_data_set(obj, sd); +} + +static void +_ecore_evas_wl_smart_del(Evas_Object *obj) +{ + EE_Wl_Smart_Data *sd; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(sd = evas_object_smart_data_get(obj))) return; + evas_object_del(sd->text); + evas_object_del(sd->frame); + free(sd); +} + +static void +_ecore_evas_wl_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h) +{ + EE_Wl_Smart_Data *sd; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(sd = evas_object_smart_data_get(obj))) return; + if ((sd->w == w) && (sd->h == h)) return; + sd->w = w; + sd->h = h; + evas_object_resize(sd->frame, w, h); +} + +static void +_ecore_evas_wl_smart_show(Evas_Object *obj) +{ + EE_Wl_Smart_Data *sd; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(sd = evas_object_smart_data_get(obj))) return; + evas_object_show(sd->frame); + evas_object_show(sd->text); +} + +static void +_ecore_evas_wl_smart_hide(Evas_Object *obj) +{ + EE_Wl_Smart_Data *sd; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(sd = evas_object_smart_data_get(obj))) return; + evas_object_hide(sd->text); + evas_object_hide(sd->frame); +} + +static Evas_Object * +_ecore_evas_wl_frame_add(Evas *evas) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_evas_wl_smart_init(); + return evas_object_smart_add(evas, _ecore_evas_wl_smart); +} + +#else +EAPI Ecore_Evas * +ecore_evas_wayland_egl_new(const char *disp_name __UNUSED__, unsigned int parent __UNUSED__, int x __UNUSED__, int y __UNUSED__, int w __UNUSED__, int h __UNUSED__, Eina_Bool frame __UNUSED__) +{ + return NULL; +} +#endif diff --git a/src/lib/ecore_evas/ecore_evas_wayland_shm.c b/src/lib/ecore_evas/ecore_evas_wayland_shm.c new file mode 100644 index 0000000..8ef3335 --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas_wayland_shm.c @@ -0,0 +1,1320 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +//#define LOGFNS 1 + +#ifdef LOGFNS +# include +# define LOGFN(fl, ln, fn) \ + printf("-ECORE_EVAS-WL: %25s: %5i - %s\n", fl, ln, fn); +#else +# define LOGFN(fl, ln, fn) +#endif + +#ifdef BUILD_ECORE_EVAS_WAYLAND_SHM +# include +# include +# include +# include +# include +#endif + +#include +#include +#include + +#include "ecore_evas_private.h" +#include "Ecore_Evas.h" + +#ifdef BUILD_ECORE_EVAS_WAYLAND_SHM +# include +# include + +/* local structures */ +typedef struct _EE_Wl_Smart_Data EE_Wl_Smart_Data; +struct _EE_Wl_Smart_Data +{ + Evas_Object *frame; + Evas_Object *text; + Evas_Coord x, y, w, h; +}; + +/* local function prototypes */ +static int _ecore_evas_wl_init(void); +static int _ecore_evas_wl_shutdown(void); +static void _ecore_evas_wl_pre_free(Ecore_Evas *ee); +static void _ecore_evas_wl_free(Ecore_Evas *ee); +static void _ecore_evas_wl_callback_resize_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)); +static void _ecore_evas_wl_callback_move_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)); +static void _ecore_evas_wl_callback_delete_request_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)); +static void _ecore_evas_wl_callback_focus_in_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)); +static void _ecore_evas_wl_callback_focus_out_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)); +static void _ecore_evas_wl_callback_mouse_in_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)); +static void _ecore_evas_wl_callback_mouse_out_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)); +static void _ecore_evas_wl_move(Ecore_Evas *ee, int x, int y); +static void _ecore_evas_wl_resize(Ecore_Evas *ee, int w, int h); +static void _ecore_evas_wl_move_resize(Ecore_Evas *ee, int x, int y, int w, int h); +static void _ecore_evas_wl_show(Ecore_Evas *ee); +static void _ecore_evas_wl_hide(Ecore_Evas *ee); +static void _ecore_evas_wl_raise(Ecore_Evas *ee); +static void _ecore_evas_wl_title_set(Ecore_Evas *ee, const char *title); +static void _ecore_evas_wl_name_class_set(Ecore_Evas *ee, const char *n, const char *c); +static void _ecore_evas_wl_size_min_set(Ecore_Evas *ee, int w, int h); +static void _ecore_evas_wl_size_max_set(Ecore_Evas *ee, int w, int h); +static void _ecore_evas_wl_size_base_set(Ecore_Evas *ee, int w, int h); +static void _ecore_evas_wl_size_step_set(Ecore_Evas *ee, int w, int h); +static void _ecore_evas_wl_layer_set(Ecore_Evas *ee, int layer); +static void _ecore_evas_wl_iconified_set(Ecore_Evas *ee, int iconify); +static void _ecore_evas_wl_maximized_set(Ecore_Evas *ee, int max); +static void _ecore_evas_wl_fullscreen_set(Ecore_Evas *ee, int full); +static void _ecore_evas_wl_ignore_events_set(Ecore_Evas *ee, int ignore); +static void _ecore_evas_wl_alpha_set(Ecore_Evas *ee, int alpha); +static void _ecore_evas_wl_transparent_set(Ecore_Evas *ee, int transparent); +static int _ecore_evas_wl_render(Ecore_Evas *ee); +static void _ecore_evas_wl_screen_geometry_get(const Ecore_Evas *ee __UNUSED__, int *x, int *y, int *w, int *h); +static void _ecore_evas_wl_screen_dpi_get(const Ecore_Evas *ee __UNUSED__, int *xdpi, int *ydpi); +static void _ecore_evas_wl_ensure_pool_size(Ecore_Evas *ee, int w, int h); +static struct wl_shm_pool *_ecore_evas_wl_shm_pool_create(int size, void **data); + +static void _ecore_evas_wl_buffer_new(Ecore_Evas *ee, struct wl_shm_pool *pool); + +static Eina_Bool _ecore_evas_wl_cb_mouse_in(void *data __UNUSED__, int type __UNUSED__, void *event); +static Eina_Bool _ecore_evas_wl_cb_mouse_out(void *data __UNUSED__, int type __UNUSED__, void *event); +static Eina_Bool _ecore_evas_wl_cb_focus_in(void *data __UNUSED__, int type __UNUSED__, void *event); +static Eina_Bool _ecore_evas_wl_cb_focus_out(void *data __UNUSED__, int type __UNUSED__, void *event); +static Eina_Bool _ecore_evas_wl_cb_window_configure(void *data __UNUSED__, int type __UNUSED__, void *event); + +/* SMART stuff for frame */ +static Evas_Smart *_ecore_evas_wl_smart = NULL; + +static void _ecore_evas_wl_smart_init(void); +static void _ecore_evas_wl_smart_add(Evas_Object *obj); +static void _ecore_evas_wl_smart_del(Evas_Object *obj); +static void _ecore_evas_wl_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h); +static void _ecore_evas_wl_smart_show(Evas_Object *obj); +static void _ecore_evas_wl_smart_hide(Evas_Object *obj); + +static Evas_Object *_ecore_evas_wl_frame_add(Evas *evas); + +/* local variables */ +static int _ecore_evas_wl_init_count = 0; +static Ecore_Event_Handler *_ecore_evas_wl_event_hdls[5]; + +static Ecore_Evas_Engine_Func _ecore_wl_engine_func = +{ + _ecore_evas_wl_free, + _ecore_evas_wl_callback_resize_set, + _ecore_evas_wl_callback_move_set, + NULL, + NULL, + _ecore_evas_wl_callback_delete_request_set, + NULL, + _ecore_evas_wl_callback_focus_in_set, + _ecore_evas_wl_callback_focus_out_set, + _ecore_evas_wl_callback_mouse_in_set, + _ecore_evas_wl_callback_mouse_out_set, + NULL, // sticky_set + NULL, // unsticky_set + NULL, // pre_render_set + NULL, // post_render_set + _ecore_evas_wl_move, + NULL, // managed_move + _ecore_evas_wl_resize, + _ecore_evas_wl_move_resize, + NULL, // rotation_set + NULL, // shaped_set + _ecore_evas_wl_show, + _ecore_evas_wl_hide, + _ecore_evas_wl_raise, + NULL, // lower + NULL, // activate + _ecore_evas_wl_title_set, + _ecore_evas_wl_name_class_set, + _ecore_evas_wl_size_min_set, + _ecore_evas_wl_size_max_set, + _ecore_evas_wl_size_base_set, + _ecore_evas_wl_size_step_set, + NULL, // object_cursor_set + _ecore_evas_wl_layer_set, + NULL, // focus set + _ecore_evas_wl_iconified_set, + NULL, // borderless set + NULL, // override set + _ecore_evas_wl_maximized_set, + _ecore_evas_wl_fullscreen_set, + NULL, // func avoid_damage set + NULL, // func withdrawn set + NULL, // func sticky set + _ecore_evas_wl_ignore_events_set, + _ecore_evas_wl_alpha_set, + _ecore_evas_wl_transparent_set, + NULL, // func profiles set + NULL, // window group set + NULL, // aspect set + NULL, // urgent set + NULL, // modal set + NULL, // demand attention set + NULL, // focus skip set + _ecore_evas_wl_render, + _ecore_evas_wl_screen_geometry_get, + _ecore_evas_wl_screen_dpi_get +}; + +/* external variables */ + +/* external functions */ +EAPI Ecore_Evas * +ecore_evas_wayland_shm_new(const char *disp_name, unsigned int parent, int x, int y, int w, int h, Eina_Bool frame) +{ + Ecore_Wl_Window *p = NULL; + Evas_Engine_Info_Wayland_Shm *einfo; + Ecore_Evas *ee; + int method = 0, count = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(method = evas_render_method_lookup("wayland_shm"))) + { + ERR("Render method lookup failed for Wayland_Shm"); + return NULL; + } + + count = ecore_wl_init(disp_name); + if (!count) + { + ERR("Failed to initialize Ecore_Wayland"); + return NULL; + } + else if (count == 1) + ecore_wl_display_iterate(); + + if (!(ee = calloc(1, sizeof(Ecore_Evas)))) + { + ERR("Failed to allocate Ecore_Evas"); + ecore_wl_shutdown(); + return NULL; + } + + ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); + + _ecore_evas_wl_init(); + + ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_wl_engine_func; + + ee->driver = "wayland_shm"; + if (disp_name) ee->name = strdup(disp_name); + + if (w < 1) w = 1; + if (h < 1) h = 1; + + ee->x = x; + ee->y = y; + ee->w = w; + ee->h = h; + ee->req.x = ee->x; + ee->req.y = ee->y; + ee->req.w = ee->w; + ee->req.h = ee->h; + ee->rotation = 0; + ee->prop.max.w = 32767; + ee->prop.max.h = 32767; + ee->prop.layer = 4; + ee->prop.request_pos = 0; + ee->prop.sticky = 0; + ee->prop.draw_frame = frame; + ee->alpha = EINA_FALSE; + + ee->evas = evas_new(); + evas_data_attach_set(ee->evas, ee); + evas_output_method_set(ee->evas, method); + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + + /* FIXME: This needs to be set based on theme & scale */ + if (ee->prop.draw_frame) + evas_output_framespace_set(ee->evas, 4, 18, 8, 22); + + if (parent) p = ecore_wl_window_find(parent); + + /* FIXME: Get if parent is alpha, and set */ + + ee->engine.wl.parent = p; + ee->engine.wl.win = + ecore_wl_window_new(p, x, y, w, h, ECORE_WL_WINDOW_BUFFER_TYPE_SHM); + ee->prop.window = ee->engine.wl.win->id; + + if ((einfo = (Evas_Engine_Info_Wayland_Shm *)evas_engine_info_get(ee->evas))) + { + einfo->info.rotation = ee->rotation; + einfo->info.destination_alpha = ee->alpha; + einfo->info.rotation = ee->rotation; + einfo->info.debug = EINA_FALSE; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("Failed to set Evas Engine Info for '%s'", ee->driver); + ecore_evas_free(ee); + _ecore_evas_wl_shutdown(); + ecore_wl_shutdown(); + return NULL; + } + } + else + { + ERR("Failed to get Evas Engine Info for '%s'", ee->driver); + ecore_evas_free(ee); + _ecore_evas_wl_shutdown(); + ecore_wl_shutdown(); + return NULL; + } + + ecore_evas_callback_pre_free_set(ee, _ecore_evas_wl_pre_free); + + if (ee->prop.draw_frame) + { + ee->engine.wl.frame = _ecore_evas_wl_frame_add(ee->evas); + evas_object_is_frame_object_set(ee->engine.wl.frame, EINA_TRUE); + evas_object_move(ee->engine.wl.frame, 0, 0); + } + + _ecore_evas_register(ee); + ecore_evas_input_event_register(ee); + + ecore_event_window_register(ee->prop.window, ee, ee->evas, + (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, + (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, + (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, + (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); + +// evas_event_feed_mouse_in(ee->evas, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff), NULL); + + return ee; +} + +/* local functions */ +static int +_ecore_evas_wl_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (++_ecore_evas_wl_init_count != 1) + return _ecore_evas_wl_init_count; + + _ecore_evas_wl_event_hdls[0] = + ecore_event_handler_add(ECORE_WL_EVENT_MOUSE_IN, + _ecore_evas_wl_cb_mouse_in, NULL); + _ecore_evas_wl_event_hdls[1] = + ecore_event_handler_add(ECORE_WL_EVENT_MOUSE_OUT, + _ecore_evas_wl_cb_mouse_out, NULL); + _ecore_evas_wl_event_hdls[2] = + ecore_event_handler_add(ECORE_WL_EVENT_FOCUS_IN, + _ecore_evas_wl_cb_focus_in, NULL); + _ecore_evas_wl_event_hdls[3] = + ecore_event_handler_add(ECORE_WL_EVENT_FOCUS_OUT, + _ecore_evas_wl_cb_focus_out, NULL); + _ecore_evas_wl_event_hdls[4] = + ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_CONFIGURE, + _ecore_evas_wl_cb_window_configure, NULL); + + ecore_event_evas_init(); + + return _ecore_evas_wl_init_count; +} + +static int +_ecore_evas_wl_shutdown(void) +{ + unsigned int i = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (--_ecore_evas_wl_init_count != 0) + return _ecore_evas_wl_init_count; + + for (i = 0; i < sizeof(_ecore_evas_wl_event_hdls) / sizeof(Ecore_Event_Handler *); i++) + { + if (_ecore_evas_wl_event_hdls[i]) + ecore_event_handler_del(_ecore_evas_wl_event_hdls[i]); + } + + ecore_event_evas_shutdown(); + + return _ecore_evas_wl_init_count; +} + +static void +_ecore_evas_wl_pre_free(Ecore_Evas *ee) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (ee->engine.wl.frame) evas_object_del(ee->engine.wl.frame); +} + +static void +_ecore_evas_wl_free(Ecore_Evas *ee) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (ee->engine.wl.buffer) wl_buffer_destroy(ee->engine.wl.buffer); + ee->engine.wl.buffer = NULL; + + if (ee->engine.wl.win) ecore_wl_window_free(ee->engine.wl.win); + ee->engine.wl.win = NULL; + + ecore_event_window_unregister(ee->prop.window); + ecore_evas_input_event_unregister(ee); + + _ecore_evas_wl_shutdown(); + ecore_wl_shutdown(); +} + +static void +_ecore_evas_wl_callback_resize_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + ee->func.fn_resize = func; +} + +static void +_ecore_evas_wl_callback_move_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + ee->func.fn_move = func; +} + +static void +_ecore_evas_wl_callback_delete_request_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + ee->func.fn_delete_request = func; +} + +static void +_ecore_evas_wl_callback_focus_in_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + ee->func.fn_focus_in = func; +} + +static void +_ecore_evas_wl_callback_focus_out_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + ee->func.fn_focus_out = func; +} + +static void +_ecore_evas_wl_callback_mouse_in_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + ee->func.fn_mouse_in = func; +} + +static void +_ecore_evas_wl_callback_mouse_out_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + ee->func.fn_mouse_out = func; +} + +static void +_ecore_evas_wl_move(Ecore_Evas *ee, int x, int y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + + ee->req.x = x; + ee->req.y = y; + + if ((ee->x != x) || (ee->y != y)) + { + ee->x = x; + ee->y = y; + if (ee->engine.wl.win) + ecore_wl_window_update_location(ee->engine.wl.win, x, y); + if (ee->func.fn_move) ee->func.fn_move(ee); + } +} + +static void +_ecore_evas_wl_resize(Ecore_Evas *ee, int w, int h) +{ + Evas_Engine_Info_Wayland_Shm *einfo; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (w < 1) w = 1; + if (h < 1) h = 1; + + ee->req.w = w; + ee->req.h = h; + + if (!ee->prop.fullscreen) + { + int fw = 0, fh = 0; + + if (ee->prop.min.w > w) w = ee->prop.min.w; + else if (w > ee->prop.max.w) w = ee->prop.max.w; + if (ee->prop.min.h > h) h = ee->prop.min.h; + else if (h > ee->prop.max.h) h = ee->prop.max.h; + + evas_output_framespace_get(ee->evas, NULL, NULL, &fw, &fh); + w += fw; + h += fh; + } + + if ((ee->w != w) || (ee->h != h)) + { + ee->w = w; + ee->h = h; + + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + evas_output_size_set(ee->evas, h, w); + evas_output_viewport_set(ee->evas, 0, 0, h, w); + } + else + { + evas_output_size_set(ee->evas, w, h); + evas_output_viewport_set(ee->evas, 0, 0, w, h); + } + + if (ee->prop.avoid_damage) + { + int pdam = 0; + + pdam = ecore_evas_avoid_damage_get(ee); + ecore_evas_avoid_damage_set(ee, 0); + ecore_evas_avoid_damage_set(ee, pdam); + } + + if (ee->engine.wl.frame) + evas_object_resize(ee->engine.wl.frame, w, h); + + if (ee->engine.wl.buffer) wl_buffer_destroy(ee->engine.wl.buffer); + ee->engine.wl.buffer = NULL; + + _ecore_evas_wl_ensure_pool_size(ee, w, h); + + if (ee->engine.wl.pool) + _ecore_evas_wl_buffer_new(ee, ee->engine.wl.pool); + + einfo = (Evas_Engine_Info_Wayland_Shm *)evas_engine_info_get(ee->evas); + if (!einfo) + { + ERR("Failed to get Evas Engine Info for '%s'", ee->driver); + return; + } + + einfo->info.dest = ee->engine.wl.pool_data; + evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); + + if (ee->engine.wl.win) + { +// if (!ee->prop.fullscreen) + ecore_wl_window_update_size(ee->engine.wl.win, w, h); + ecore_wl_window_buffer_attach(ee->engine.wl.win, + ee->engine.wl.buffer, 0, 0); + } + + if (ee->func.fn_resize) ee->func.fn_resize(ee); + } +} + +static void +_ecore_evas_wl_move_resize(Ecore_Evas *ee, int x, int y, int w, int h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if ((ee->x != x) || (ee->y != y)) + _ecore_evas_wl_move(ee, x, y); + if ((ee->w != w) || (ee->h != h)) + _ecore_evas_wl_resize(ee, w, h); +} + +static void +_ecore_evas_wl_ensure_pool_size(Ecore_Evas *ee, int w, int h) +{ + int stride = 0; + size_t len = 0; + + stride = w * sizeof(int); + len = stride * h; + + if ((ee->engine.wl.pool) && (len < ee->engine.wl.pool_size)) + return; + else + { + struct wl_shm_pool *pool = NULL; + void *data; + int size; + + if (ee->engine.wl.pool) + wl_shm_pool_destroy(ee->engine.wl.pool); + + /* + * Make the pool 1.5 times the current requirement to allow growth + * without requiring a new pool allocation + */ + size = 1.5 * len; + pool = _ecore_evas_wl_shm_pool_create(size, &data); + + ee->engine.wl.pool = pool; + ee->engine.wl.pool_size = size; + ee->engine.wl.pool_data = data; + } +} + +static void +_ecore_evas_wl_show(Ecore_Evas *ee) +{ + Evas_Engine_Info_Wayland_Shm *einfo; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if ((!ee) || (ee->visible)) return; + + _ecore_evas_wl_ensure_pool_size(ee, ee->w, ee->h); + + if (ee->engine.wl.pool) + _ecore_evas_wl_buffer_new(ee, ee->engine.wl.pool); + + einfo = (Evas_Engine_Info_Wayland_Shm *)evas_engine_info_get(ee->evas); + if (!einfo) + { + ERR("Failed to get Evas Engine Info for '%s'", ee->driver); + return; + } + + einfo->info.dest = ee->engine.wl.pool_data; + evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); + + /* ecore_wl_flush(); */ + + if (ee->engine.wl.win) + { + ecore_wl_window_show(ee->engine.wl.win); + ecore_wl_window_update_size(ee->engine.wl.win, ee->w, ee->h); + ecore_wl_window_buffer_attach(ee->engine.wl.win, + ee->engine.wl.buffer, 0, 0); + + if ((ee->prop.clas) && (ee->engine.wl.win->shell_surface)) + wl_shell_surface_set_class(ee->engine.wl.win->shell_surface, + ee->prop.clas); + if ((ee->prop.title) && (ee->engine.wl.win->shell_surface)) + wl_shell_surface_set_title(ee->engine.wl.win->shell_surface, + ee->prop.title); + } + + if (ee->engine.wl.frame) + { + evas_object_show(ee->engine.wl.frame); + evas_object_resize(ee->engine.wl.frame, ee->w, ee->h); + } + + ee->visible = 1; + if (ee->func.fn_show) ee->func.fn_show(ee); +} + +static void +_ecore_evas_wl_hide(Ecore_Evas *ee) +{ + Evas_Engine_Info_Wayland_Shm *einfo; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if ((!ee) || (!ee->visible)) return; + + if (ee->engine.wl.buffer) wl_buffer_destroy(ee->engine.wl.buffer); + ee->engine.wl.buffer = NULL; + + munmap(ee->engine.wl.pool_data, ee->engine.wl.pool_size); + + einfo = (Evas_Engine_Info_Wayland_Shm *)evas_engine_info_get(ee->evas); + if ((einfo) && (einfo->info.dest)) + { + einfo->info.dest = NULL; + evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); + } + + ecore_wl_window_hide(ee->engine.wl.win); + + ee->visible = 0; + ee->should_be_visible = 0; + + if (ee->func.fn_hide) ee->func.fn_hide(ee); +} + +static void +_ecore_evas_wl_raise(Ecore_Evas *ee) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if ((!ee) || (!ee->visible)) return; + ecore_wl_window_raise(ee->engine.wl.win); +} + +static void +_ecore_evas_wl_title_set(Ecore_Evas *ee, const char *title) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (ee->prop.title) free(ee->prop.title); + ee->prop.title = NULL; + if (title) ee->prop.title = strdup(title); + if ((ee->prop.draw_frame) && (ee->engine.wl.frame)) + { + EE_Wl_Smart_Data *sd; + + if (!(sd = evas_object_smart_data_get(ee->engine.wl.frame))) return; + evas_object_text_text_set(sd->text, ee->prop.title); + } + + if ((ee->prop.title) && (ee->engine.wl.win->shell_surface)) + wl_shell_surface_set_title(ee->engine.wl.win->shell_surface, + ee->prop.title); +} + +static void +_ecore_evas_wl_name_class_set(Ecore_Evas *ee, const char *n, const char *c) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (ee->prop.name) free(ee->prop.name); + if (ee->prop.clas) free(ee->prop.clas); + ee->prop.name = NULL; + ee->prop.clas = NULL; + if (n) ee->prop.name = strdup(n); + if (c) ee->prop.clas = strdup(c); + + if ((ee->prop.clas) && (ee->engine.wl.win->shell_surface)) + wl_shell_surface_set_class(ee->engine.wl.win->shell_surface, + ee->prop.clas); +} + +static void +_ecore_evas_wl_size_min_set(Ecore_Evas *ee, int w, int h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (w < 0) w = 0; + if (h < 0) h = 0; + if ((ee->prop.min.w == w) && (ee->prop.min.h == h)) return; + ee->prop.min.w = w; + ee->prop.min.h = h; +} + +static void +_ecore_evas_wl_size_max_set(Ecore_Evas *ee, int w, int h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (w < 0) w = 0; + if (h < 0) h = 0; + if ((ee->prop.max.w == w) && (ee->prop.max.h == h)) return; + ee->prop.max.w = w; + ee->prop.max.h = h; +} + +static void +_ecore_evas_wl_size_base_set(Ecore_Evas *ee, int w, int h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (w < 0) w = 0; + if (h < 0) h = 0; + if ((ee->prop.base.w == w) && (ee->prop.base.h == h)) return; + ee->prop.base.w = w; + ee->prop.base.h = h; +} + +static void +_ecore_evas_wl_size_step_set(Ecore_Evas *ee, int w, int h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (w < 0) w = 0; + if (h < 0) h = 0; + if ((ee->prop.step.w == w) && (ee->prop.step.h == h)) return; + ee->prop.step.w = w; + ee->prop.step.h = h; +} + +static void +_ecore_evas_wl_layer_set(Ecore_Evas *ee, int layer) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (ee->prop.layer == layer) return; + if (layer < 1) layer = 1; + else if (layer > 255) layer = 255; + ee->prop.layer = layer; +} + +static void +_ecore_evas_wl_iconified_set(Ecore_Evas *ee, int iconify) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (ee->prop.iconified == iconify) return; + ee->prop.iconified = iconify; + /* FIXME: Implement this in Wayland someshow */ +} + +static void +_ecore_evas_wl_maximized_set(Ecore_Evas *ee, int max) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (ee->prop.maximized == max) return; + ee->prop.maximized = max; + ecore_wl_window_maximized_set(ee->engine.wl.win, max); +} + +static void +_ecore_evas_wl_fullscreen_set(Ecore_Evas *ee, int full) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (ee->prop.fullscreen == full) return; + ee->prop.fullscreen = full; + ecore_wl_window_fullscreen_set(ee->engine.wl.win, full); +} + +static void +_ecore_evas_wl_ignore_events_set(Ecore_Evas *ee, int ignore) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + ee->ignore_events = ignore; + /* NB: Hmmm, may need to pass this to ecore_wl_window in the future */ +} + +static void +_ecore_evas_wl_alpha_set(Ecore_Evas *ee, int alpha) +{ + Evas_Engine_Info_Wayland_Shm *einfo; + Ecore_Wl_Window *win; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if ((ee->alpha == alpha)) return; + ee->alpha = alpha; + + /* FIXME: NB: We should really add a ecore_wl_window_alpha_set function + * but we are in API freeze, so just hack it in for now and fix when + * freeze is over */ + if ((win = ee->engine.wl.win)) + win->alpha = alpha; + + /* if (ee->engine.wl.win) */ + /* ecore_wl_window_transparent_set(ee->engine.wl.win, alpha); */ + + if (ee->engine.wl.buffer) wl_buffer_destroy(ee->engine.wl.buffer); + ee->engine.wl.buffer = NULL; + + _ecore_evas_wl_ensure_pool_size(ee, ee->w, ee->h); + + if (ee->engine.wl.pool) + _ecore_evas_wl_buffer_new(ee, ee->engine.wl.pool); + + if ((einfo = (Evas_Engine_Info_Wayland_Shm *)evas_engine_info_get(ee->evas))) + { + einfo->info.destination_alpha = alpha; + einfo->info.dest = ee->engine.wl.pool_data; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + } + + if (ee->engine.wl.win) + { + ecore_wl_window_update_size(ee->engine.wl.win, ee->w, ee->h); + ecore_wl_window_buffer_attach(ee->engine.wl.win, + ee->engine.wl.buffer, 0, 0); + } +} + +static void +_ecore_evas_wl_transparent_set(Ecore_Evas *ee, int transparent) +{ + Evas_Engine_Info_Wayland_Shm *einfo; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if ((ee->transparent == transparent)) return; + ee->transparent = transparent; + + if (ee->engine.wl.win) + ecore_wl_window_transparent_set(ee->engine.wl.win, transparent); + + if (ee->engine.wl.buffer) wl_buffer_destroy(ee->engine.wl.buffer); + ee->engine.wl.buffer = NULL; + + _ecore_evas_wl_ensure_pool_size(ee, ee->w, ee->h); + + if (ee->engine.wl.pool) + _ecore_evas_wl_buffer_new(ee, ee->engine.wl.pool); + + if ((einfo = (Evas_Engine_Info_Wayland_Shm *)evas_engine_info_get(ee->evas))) + { + einfo->info.destination_alpha = transparent; + einfo->info.dest = ee->engine.wl.pool_data; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + } + + if (ee->engine.wl.win) + { + ecore_wl_window_update_size(ee->engine.wl.win, ee->w, ee->h); + ecore_wl_window_buffer_attach(ee->engine.wl.win, + ee->engine.wl.buffer, 0, 0); + } +} + +static int +_ecore_evas_wl_render(Ecore_Evas *ee) +{ + int rend = 0; + + if (!ee) return 0; + if (!ee->visible) + evas_norender(ee->evas); + else + { + Eina_List *ll = NULL, *updates = NULL; + Ecore_Evas *ee2 = NULL; + + if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee); + + EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2) + { + if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2); + if (ee2->engine.func->fn_render) + rend |= ee2->engine.func->fn_render(ee2); + if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2); + } + + if ((updates = evas_render_updates(ee->evas))) + { + Eina_List *l = NULL; + Eina_Rectangle *r; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + EINA_LIST_FOREACH(updates, l, r) + ecore_wl_window_damage(ee->engine.wl.win, + r->x, r->y, r->w, r->h); + + ecore_wl_flush(); + + evas_render_updates_free(updates); + _ecore_evas_idle_timeout_update(ee); + rend = 1; + } + + if (ee->func.fn_post_render) ee->func.fn_post_render(ee); + } + return rend; +} + +static void +_ecore_evas_wl_screen_geometry_get(const Ecore_Evas *ee __UNUSED__, int *x, int *y, int *w, int *h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (x) *x = 0; + if (y) *y = 0; + ecore_wl_screen_size_get(w, h); +} + +static void +_ecore_evas_wl_screen_dpi_get(const Ecore_Evas *ee __UNUSED__, int *xdpi, int *ydpi) +{ + int dpi = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (xdpi) *xdpi = 0; + if (ydpi) *ydpi = 0; + /* FIXME: Ideally this needs to get the DPI from a specific screen */ + dpi = ecore_wl_dpi_get(); + if (xdpi) *xdpi = dpi; + if (ydpi) *ydpi = dpi; +} + +static struct wl_shm_pool * +_ecore_evas_wl_shm_pool_create(int size, void **data) +{ + struct wl_shm *shm; + struct wl_shm_pool *pool; + char tmp[PATH_MAX]; + int fd; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(shm = ecore_wl_shm_get())) return NULL; + + strcpy(tmp, "/tmp/ecore-evas-wayland_shm-XXXXXX"); + if ((fd = mkstemp(tmp)) < 0) + { + ERR("Could not create temporary file."); + return NULL; + } + + if (ftruncate(fd, size) < 0) + { + ERR("Could not truncate temporary file."); + close(fd); + return NULL; + } + + *data = mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0); + unlink(tmp); + + if (*data == MAP_FAILED) + { + ERR("mmap of temporary file failed."); + close(fd); + return NULL; + } + + pool = wl_shm_create_pool(shm, fd, size); + + close(fd); + + return pool; +} + +static void +_ecore_evas_wl_buffer_new(Ecore_Evas *ee, struct wl_shm_pool *pool) +{ + unsigned int format; + int stride = 0; + + if ((ee->alpha) || (ee->transparent)) + format = WL_SHM_FORMAT_ARGB8888; + else + format = WL_SHM_FORMAT_XRGB8888; + + stride = (ee->w * sizeof(int)); + + ee->engine.wl.buffer = + wl_shm_pool_create_buffer(pool, 0, ee->w, ee->h, stride, format); +} + +void +_ecore_evas_wayland_shm_resize(Ecore_Evas *ee, int location) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (ee->engine.wl.win) + { + ee->engine.wl.win->resizing = EINA_TRUE; + ecore_wl_window_resize(ee->engine.wl.win, ee->w, ee->h, location); + } +} + +void +_ecore_evas_wayland_shm_move(Ecore_Evas *ee, int x, int y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ee) return; + if (ee->engine.wl.win) + { + ee->engine.wl.win->moving = EINA_TRUE; + ecore_wl_window_move(ee->engine.wl.win, x, y); + } +} + +static Eina_Bool +_ecore_evas_wl_cb_mouse_in(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Wl_Event_Mouse_In *ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ev = event; + ee = ecore_event_window_match(ev->window); + if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; + if (ev->window != ee->prop.window) return ECORE_CALLBACK_PASS_ON; + if (!ee->in) + { + if (ee->func.fn_mouse_in) ee->func.fn_mouse_in(ee); + ecore_event_evas_modifier_lock_update(ee->evas, ev->modifiers); + evas_event_feed_mouse_in(ee->evas, ev->timestamp, NULL); +// _ecore_evas_mouse_move_process(ee, ev->x, ev->y, ev->timestamp); + ee->in = EINA_TRUE; + } + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_wl_cb_mouse_out(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Wl_Event_Mouse_Out *ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ev = event; + ee = ecore_event_window_match(ev->window); + if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; + if (ev->window != ee->prop.window) return ECORE_CALLBACK_PASS_ON; + if (ee->in) + { + ecore_event_evas_modifier_lock_update(ee->evas, ev->modifiers); +// _ecore_evas_mouse_move_process(ee, ev->x, ev->y, ev->timestamp); + evas_event_feed_mouse_out(ee->evas, ev->timestamp, NULL); + if (ee->func.fn_mouse_out) ee->func.fn_mouse_out(ee); + if (ee->prop.cursor.object) evas_object_hide(ee->prop.cursor.object); + ee->in = EINA_FALSE; + } + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_wl_cb_focus_in(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Wl_Event_Focus_In *ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ev = event; + ee = ecore_event_window_match(ev->win); + if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; + if (ev->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; + ee->prop.focused = 1; + evas_focus_in(ee->evas); + if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_wl_cb_focus_out(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Wl_Event_Focus_In *ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ev = event; + ee = ecore_event_window_match(ev->win); + if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; + if (ev->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; + evas_focus_out(ee->evas); + ee->prop.focused = 0; + if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_wl_cb_window_configure(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Wl_Event_Window_Configure *ev; + int nw = 0, nh = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ev = event; + ee = ecore_event_window_match(ev->win); + if (!ee) return ECORE_CALLBACK_PASS_ON; + if (ev->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; + + if (ee->prop.fullscreen) + { + _ecore_evas_wl_move(ee, ev->x, ev->y); + _ecore_evas_wl_resize(ee, ev->w, ev->h); + + return ECORE_CALLBACK_PASS_ON; + } + + if ((ee->x != ev->x) || (ee->y != ev->y)) + { + ee->req.x = ee->x; + ee->req.y = ee->y; + if (ee->func.fn_move) ee->func.fn_move(ee); + } + + nw = ev->w; + nh = ev->h; + + if ((ee->prop.maximized) || (!ee->prop.fullscreen)) + { + int fw = 0, fh = 0; + + evas_output_framespace_get(ee->evas, NULL, NULL, &fw, &fh); + nw = ev->w - fw; + nh = ev->h - fh; + } + + if (ee->prop.min.w > nw) nw = ee->prop.min.w; + else if (nw > ee->prop.max.w) nw = ee->prop.max.w; + if (ee->prop.min.h > nh) nh = ee->prop.min.h; + else if (nh > ee->prop.max.h) nh = ee->prop.max.h; + + if ((ee->w != nw) || (ee->h != nh)) + { + ee->req.w = nw; + ee->req.h = nh; + if (ee->func.fn_resize) ee->func.fn_resize(ee); + } + + return ECORE_CALLBACK_PASS_ON; +} + +static void +_ecore_evas_wl_smart_init(void) +{ + if (_ecore_evas_wl_smart) return; + { + static const Evas_Smart_Class sc = + { + "ecore_evas_wl_frame", EVAS_SMART_CLASS_VERSION, + _ecore_evas_wl_smart_add, + _ecore_evas_wl_smart_del, + NULL, + _ecore_evas_wl_smart_resize, + _ecore_evas_wl_smart_show, + _ecore_evas_wl_smart_hide, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + }; + _ecore_evas_wl_smart = evas_smart_class_new(&sc); + } +} + +static void +_ecore_evas_wl_smart_add(Evas_Object *obj) +{ + EE_Wl_Smart_Data *sd; + Evas *evas; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(sd = calloc(1, sizeof(EE_Wl_Smart_Data)))) return; + + evas = evas_object_evas_get(obj); + + sd->x = 0; + sd->y = 0; + sd->w = 1; + sd->h = 1; + + sd->frame = evas_object_rectangle_add(evas); + evas_object_is_frame_object_set(sd->frame, EINA_TRUE); + evas_object_color_set(sd->frame, 249, 249, 249, 255); + evas_object_smart_member_add(sd->frame, obj); + + sd->text = evas_object_text_add(evas); + evas_object_color_set(sd->text, 0, 0, 0, 255); + evas_object_text_style_set(sd->text, EVAS_TEXT_STYLE_PLAIN); + evas_object_text_font_set(sd->text, "Sans", 10); + evas_object_text_text_set(sd->text, "Smart Test"); + + evas_object_smart_data_set(obj, sd); +} + +static void +_ecore_evas_wl_smart_del(Evas_Object *obj) +{ + EE_Wl_Smart_Data *sd; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(sd = evas_object_smart_data_get(obj))) return; + evas_object_del(sd->text); + evas_object_del(sd->frame); + free(sd); +} + +static void +_ecore_evas_wl_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h) +{ + EE_Wl_Smart_Data *sd; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(sd = evas_object_smart_data_get(obj))) return; + if ((sd->w == w) && (sd->h == h)) return; + sd->w = w; + sd->h = h; + evas_object_resize(sd->frame, w, h); +} + +static void +_ecore_evas_wl_smart_show(Evas_Object *obj) +{ + EE_Wl_Smart_Data *sd; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(sd = evas_object_smart_data_get(obj))) return; + evas_object_show(sd->frame); + evas_object_show(sd->text); +} + +static void +_ecore_evas_wl_smart_hide(Evas_Object *obj) +{ + EE_Wl_Smart_Data *sd; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(sd = evas_object_smart_data_get(obj))) return; + evas_object_hide(sd->text); + evas_object_hide(sd->frame); +} + +static Evas_Object * +_ecore_evas_wl_frame_add(Evas *evas) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_evas_wl_smart_init(); + return evas_object_smart_add(evas, _ecore_evas_wl_smart); +} + +#else +EAPI Ecore_Evas * +ecore_evas_wayland_shm_new(const char *disp_name __UNUSED__, unsigned int parent __UNUSED__, int x __UNUSED__, int y __UNUSED__, int w __UNUSED__, int h __UNUSED__, Eina_Bool frame __UNUSED__) +{ + return NULL; +} +#endif diff --git a/src/lib/ecore_evas/ecore_evas_win32.c b/src/lib/ecore_evas/ecore_evas_win32.c new file mode 100644 index 0000000..59d6ed8 --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas_win32.c @@ -0,0 +1,1589 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include /* for NULL */ + +#include +#include "ecore_private.h" +#ifdef BUILD_ECORE_EVAS_WIN32 +# define WIN32_LEAN_AND_MEAN +# include +# undef WIN32_LEAN_AND_MEAN +# include +# include +#endif /* BUILD_ECORE_EVAS_WIN32 */ + +#include "ecore_evas_private.h" +#include "Ecore_Evas.h" + +#ifdef BUILD_ECORE_EVAS_WIN32 + +#define ECORE_EVAS_EVENT_COUNT 10 + +static int _ecore_evas_init_count = 0; + +static Ecore_Event_Handler *ecore_evas_event_handlers[ECORE_EVAS_EVENT_COUNT]; + +static Eina_Bool _ecore_evas_win32_event_mouse_in(void *data __UNUSED__, int type __UNUSED__, void *event); + +static Eina_Bool _ecore_evas_win32_event_mouse_out(void *data __UNUSED__, int type __UNUSED__, void *event); + +static Eina_Bool _ecore_evas_win32_event_window_focus_in(void *data __UNUSED__, int type __UNUSED__, void *event); + +static Eina_Bool _ecore_evas_win32_event_window_focus_out(void *data __UNUSED__, int type __UNUSED__, void *event); + +static Eina_Bool _ecore_evas_win32_event_window_damage(void *data __UNUSED__, int type __UNUSED__, void *event); + +static Eina_Bool _ecore_evas_win32_event_window_destroy(void *data __UNUSED__, int type __UNUSED__, void *event); + +static Eina_Bool _ecore_evas_win32_event_window_show(void *data __UNUSED__, int type __UNUSED__, void *event); + +static Eina_Bool _ecore_evas_win32_event_window_hide(void *data __UNUSED__, int type __UNUSED__, void *event); + +static Eina_Bool _ecore_evas_win32_event_window_configure(void *data __UNUSED__, int type __UNUSED__, void *event); + +static Eina_Bool _ecore_evas_win32_event_window_delete_request(void *data __UNUSED__, int type __UNUSED__, void *event); + +/* Private functions */ + +static int +_ecore_evas_win32_render(Ecore_Evas *ee) +{ + int rend = 0; + Eina_List *updates = NULL; + Eina_List *ll; + Ecore_Evas *ee2; + + EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2) + { + if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2); + if (ee2->engine.func->fn_render) + rend |= ee2->engine.func->fn_render(ee2); + if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2); + } + + if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee); + if (ee->prop.avoid_damage) + { + updates = evas_render_updates(ee->evas); + if (updates) evas_render_updates_free(updates); + } + else if ((ee->visible) || + ((ee->should_be_visible) && (ee->prop.fullscreen)) || + ((ee->should_be_visible) && (ee->prop.override))) + { + if (ee->shaped) + { + updates = evas_render_updates(ee->evas); + if (updates) evas_render_updates_free(updates); + } + else + { + updates = evas_render_updates(ee->evas); + if (updates) evas_render_updates_free(updates); + } + } + else + evas_norender(ee->evas); + if (updates) rend = 1; + if (ee->func.fn_post_render) ee->func.fn_post_render(ee); + return rend; +} + +static int +_ecore_evas_win32_init(void) +{ + _ecore_evas_init_count++; + if (_ecore_evas_init_count > 1) + return _ecore_evas_init_count; + + ecore_evas_event_handlers[0] = ecore_event_handler_add(ECORE_WIN32_EVENT_MOUSE_IN, _ecore_evas_win32_event_mouse_in, NULL); + ecore_evas_event_handlers[1] = ecore_event_handler_add(ECORE_WIN32_EVENT_MOUSE_OUT, _ecore_evas_win32_event_mouse_out, NULL); + ecore_evas_event_handlers[2] = ecore_event_handler_add(ECORE_WIN32_EVENT_WINDOW_FOCUS_IN, _ecore_evas_win32_event_window_focus_in, NULL); + ecore_evas_event_handlers[3] = ecore_event_handler_add(ECORE_WIN32_EVENT_WINDOW_FOCUS_OUT, _ecore_evas_win32_event_window_focus_out, NULL); + ecore_evas_event_handlers[4] = ecore_event_handler_add(ECORE_WIN32_EVENT_WINDOW_DAMAGE, _ecore_evas_win32_event_window_damage, NULL); + ecore_evas_event_handlers[5] = ecore_event_handler_add(ECORE_WIN32_EVENT_WINDOW_DESTROY, _ecore_evas_win32_event_window_destroy, NULL); + ecore_evas_event_handlers[6] = ecore_event_handler_add(ECORE_WIN32_EVENT_WINDOW_SHOW, _ecore_evas_win32_event_window_show, NULL); + ecore_evas_event_handlers[7] = ecore_event_handler_add(ECORE_WIN32_EVENT_WINDOW_HIDE, _ecore_evas_win32_event_window_hide, NULL); + ecore_evas_event_handlers[8] = ecore_event_handler_add(ECORE_WIN32_EVENT_WINDOW_CONFIGURE, _ecore_evas_win32_event_window_configure, NULL); + ecore_evas_event_handlers[9] = ecore_event_handler_add(ECORE_WIN32_EVENT_WINDOW_DELETE_REQUEST, _ecore_evas_win32_event_window_delete_request, NULL); + + ecore_event_evas_init(); + return _ecore_evas_init_count; +} + +int +_ecore_evas_win32_shutdown(void) +{ + _ecore_evas_init_count--; + if (_ecore_evas_init_count == 0) + { + int i; + + for (i = 0; i < ECORE_EVAS_EVENT_COUNT; i++) + ecore_event_handler_del(ecore_evas_event_handlers[i]); + ecore_event_evas_shutdown(); + } + + if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0; + + return _ecore_evas_init_count; +} + +static Eina_Bool +_ecore_evas_win32_event_mouse_in(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Win32_Event_Mouse_In *e; + + INF("mouse in"); + + e = event; + ee = ecore_event_window_match((Ecore_Window)e->window); + if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ + if ((Ecore_Window)e->window != ee->prop.window) return 1; + + if (ee->func.fn_mouse_in) ee->func.fn_mouse_in(ee); + /* FIXME to do */ +/* _ecore_evas_x_modifier_locks_update(ee, e->modifiers); */ + evas_event_feed_mouse_in(ee->evas, e->timestamp, NULL); + evas_focus_in(ee->evas); + _ecore_evas_mouse_move_process(ee, e->x, e->y, e->timestamp); + + return 1; +} + +static Eina_Bool +_ecore_evas_win32_event_mouse_out(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Win32_Event_Mouse_Out *e; + + INF("mouse out"); + + e = event; + ee = ecore_event_window_match((Ecore_Window)e->window); + if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ + if ((Ecore_Window)e->window != ee->prop.window) return 1; + + /* FIXME to do */ +/* _ecore_evas_x_modifier_locks_update(ee, e->modifiers); */ + _ecore_evas_mouse_move_process(ee, e->x, e->y, e->timestamp); + + evas_event_feed_mouse_out(ee->evas, e->timestamp, NULL); + if (ee->func.fn_mouse_out) ee->func.fn_mouse_out(ee); + if (ee->prop.cursor.object) evas_object_hide(ee->prop.cursor.object); + + return 1; +} + +static Eina_Bool +_ecore_evas_win32_event_window_focus_in(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Win32_Event_Window_Focus_In *e; + + e = event; + ee = ecore_event_window_match((Ecore_Window)e->window); + if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; + if ((Ecore_Window)e->window != ee->prop.window) return ECORE_CALLBACK_PASS_ON; + + ee->prop.focused = 1; + evas_focus_in(ee->evas); + if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_win32_event_window_focus_out(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Win32_Event_Window_Focus_Out *e; + + e = event; + ee = ecore_event_window_match((Ecore_Window)e->window); + if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; + if ((Ecore_Window)e->window != ee->prop.window) return ECORE_CALLBACK_PASS_ON; + + evas_focus_out(ee->evas); + ee->prop.focused = 0; + if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_win32_event_window_damage(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Win32_Event_Window_Damage *e; + + INF("window damage"); + + e = event; + ee = ecore_event_window_match((Ecore_Window)e->window); + if (!ee) return 1; /* pass on event */ + if ((Ecore_Window)e->window != ee->prop.window) return 1; + + if (ee->prop.avoid_damage) + { +#ifdef _MSC_VER +# pragma message ("[ECORE] [WIN32] No Region code") +#else +# warning [ECORE] [WIN32] No Region code +#endif /* ! _MSC_VER */ + } + else + { + if (ee->rotation == 0) + evas_damage_rectangle_add(ee->evas, + e->x, + e->y, + e->width, + e->height); + else if (ee->rotation == 90) + evas_damage_rectangle_add(ee->evas, + ee->h - e->y - e->height, + e->x, + e->height, + e->width); + else if (ee->rotation == 180) + evas_damage_rectangle_add(ee->evas, + ee->w - e->x - e->width, + ee->h - e->y - e->height, + e->width, + e->height); + else if (ee->rotation == 270) + evas_damage_rectangle_add(ee->evas, + e->y, + ee->w - e->x - e->width, + e->height, + e->width); + } + + return 1; +} + +static Eina_Bool +_ecore_evas_win32_event_window_destroy(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Win32_Event_Window_Destroy *e; + + INF("window destroy"); + + e = event; + ee = ecore_event_window_match((Ecore_Window)e->window); + if (!ee) return 1; /* pass on event */ + if ((Ecore_Window)e->window != ee->prop.window) return 1; + if (ee->func.fn_destroy) ee->func.fn_destroy(ee); + ecore_evas_free(ee); + + return 1; +} + +static Eina_Bool +_ecore_evas_win32_event_window_show(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Win32_Event_Window_Show *e; + + INF("window show"); + + e = event; + ee = ecore_event_window_match((Ecore_Window)e->window); + if (!ee) return 1; /* pass on event */ + if ((Ecore_Window)e->window != ee->prop.window) return 1; + if (ee->visible) return 0; /* dont pass it on */ + ee->visible = 1; + if (ee->func.fn_show) ee->func.fn_show(ee); + + return 1; +} + +static Eina_Bool +_ecore_evas_win32_event_window_hide(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Win32_Event_Window_Hide *e; + + INF("window hide"); + + e = event; + ee = ecore_event_window_match((Ecore_Window)e->window); + if (!ee) return 1; /* pass on event */ + if ((Ecore_Window)e->window != ee->prop.window) return 1; + if (!ee->visible) return 0; /* dont pass it on */ + ee->visible = 0; + if (ee->func.fn_hide) ee->func.fn_hide(ee); + + return 1; +} + +static Eina_Bool +_ecore_evas_win32_event_window_configure(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Win32_Event_Window_Configure *e; + + INF("window configure"); + + e = event; + ee = ecore_event_window_match((Ecore_Window)e->window); + if (!ee) return 1; /* pass on event */ + if ((Ecore_Window)e->window != ee->prop.window) return 1; + + if (ee->prop.override) + { + if ((ee->x != e->x) || (ee->y != e->y)) + { + ee->x = e->x; + ee->y = e->y; + ee->req.x = ee->x; + ee->req.y = ee->y; + + if (ee->func.fn_move) ee->func.fn_move(ee); + } + } + + if ((ee->w != e->width) || (ee->h != e->height)) + { + ee->w = e->width; + ee->h = e->height; + ee->req.w = ee->w; + ee->req.h = ee->h; + + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + evas_output_size_set(ee->evas, ee->h, ee->w); + evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w); + } + else + { + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + } + if (ee->prop.avoid_damage) + { + int pdam; + + pdam = ecore_evas_avoid_damage_get(ee); + ecore_evas_avoid_damage_set(ee, 0); + ecore_evas_avoid_damage_set(ee, pdam); + } +/* if (ee->shaped) */ +/* _ecore_evas_win32_region_border_resize(ee); */ + if ((ee->expecting_resize.w > 0) && + (ee->expecting_resize.h > 0)) + { + if ((ee->expecting_resize.w == ee->w) && + (ee->expecting_resize.h == ee->h)) + _ecore_evas_mouse_move_process(ee, ee->mouse.x, ee->mouse.y, + ecore_win32_current_time_get()); + ee->expecting_resize.w = 0; + ee->expecting_resize.h = 0; + } + if (ee->func.fn_resize) ee->func.fn_resize(ee); + } + + return 1; +} + +static Eina_Bool +_ecore_evas_win32_event_window_delete_request(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Win32_Event_Window_Delete_Request *e; + + INF("window delete request"); + + e = event; + ee = ecore_event_window_match((Ecore_Window)e->window); + if (!ee) return 1; /* pass on event */ + if ((Ecore_Window)e->window != ee->prop.window) return 1; + if (ee->func.fn_delete_request) ee->func.fn_delete_request(ee); + + INF(" * ee event delete\n"); + return 1; +} + + +/* Ecore_Evas interface */ + +static void +_ecore_evas_win32_free(Ecore_Evas *ee) +{ + INF("ecore evas free"); + + ecore_win32_window_free((struct _Ecore_Win32_Window *)ee->prop.window); + ecore_event_window_unregister(ee->prop.window); + _ecore_evas_win32_shutdown(); + ecore_win32_shutdown(); +} + +static void +_ecore_evas_win32_callback_delete_request_set(Ecore_Evas *ee, + Ecore_Evas_Event_Cb func) +{ + ee->func.fn_delete_request = func; +} + +static void +_ecore_evas_win32_move(Ecore_Evas *ee, int x, int y) +{ + INF("ecore evas move (%dx%d)", x, y); + ee->req.x = x; + ee->req.y = y; + + if ((x != ee->x) || (y != ee->y)) + { + ee->x = x; + ee->y = y; + ecore_win32_window_move((struct _Ecore_Win32_Window *)ee->prop.window, + x, y); + if (ee->func.fn_move) ee->func.fn_move(ee); + } +} + +static void +_ecore_evas_win32_resize(Ecore_Evas *ee, int width, int height) +{ + INF("ecore evas resize (%dx%d)", width, height); + ee->req.w = width; + ee->req.h = height; + + if ((ee->w != width) || (ee->h != height)) + { + ee->w = width; + ee->h = height; + ecore_win32_window_resize((struct _Ecore_Win32_Window *)ee->prop.window, + width, height); + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + evas_output_size_set(ee->evas, ee->h, ee->w); + evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w); + } + else + { + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + } + if (ee->prop.avoid_damage) + { + int pdam; + + pdam = ecore_evas_avoid_damage_get(ee); + ecore_evas_avoid_damage_set(ee, 0); + ecore_evas_avoid_damage_set(ee, pdam); + } +/* if ((ee->shaped) || (ee->alpha)) */ +/* _ecore_evas_win32_region_border_resize(ee); */ + if (ee->func.fn_resize) ee->func.fn_resize(ee); + } +} + +static void +_ecore_evas_win32_move_resize(Ecore_Evas *ee, int x, int y, int width, int height) +{ + INF("ecore evas resize (%dx%d %dx%d)", x, y, width, height); + ee->req.x = x; + ee->req.y = y; + ee->req.w = width; + ee->req.h = height; + + if ((ee->w != width) || (ee->h != height) || (x != ee->x) || (y != ee->y)) + { + int change_size = 0; + int change_pos = 0; + + if ((ee->w != width) || (ee->h != height)) change_size = 1; + if ((x != ee->x) || (y != ee->y)) change_pos = 1; + + ee->x = x; + ee->y = y; + ee->w = width; + ee->h = height; + ecore_win32_window_move_resize((struct _Ecore_Win32_Window *)ee->prop.window, + x, y, width, height); + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + evas_output_size_set(ee->evas, ee->h, ee->w); + evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w); + } + else + { + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + } + if (ee->prop.avoid_damage) + { + int pdam; + + pdam = ecore_evas_avoid_damage_get(ee); + ecore_evas_avoid_damage_set(ee, 0); + ecore_evas_avoid_damage_set(ee, pdam); + } +/* if ((ee->shaped) || (ee->alpha)) */ +/* _ecore_evas_win32_region_border_resize(ee); */ + if (change_pos) + { + if (ee->func.fn_move) ee->func.fn_move(ee); + } + if (change_size) + { + if (ee->func.fn_resize) ee->func.fn_resize(ee); + } + } +} + +static void +_ecore_evas_win32_rotation_set_internal(Ecore_Evas *ee, int rotation) +{ + int rot_dif; + + rot_dif = ee->rotation - rotation; + if (rot_dif < 0) rot_dif = -rot_dif; + + if (rot_dif != 180) + { + int minw, minh, maxw, maxh, basew, baseh, stepw, steph; + + if (!ee->prop.fullscreen) + { + ecore_win32_window_resize((struct _Ecore_Win32_Window *)ee->prop.window, + ee->h, ee->w); + ee->expecting_resize.w = ee->h; + ee->expecting_resize.h = ee->w; + } + else + { + int w, h; + + ecore_win32_window_size_get((struct _Ecore_Win32_Window *)ee->prop.window, + &w, &h); + ecore_win32_window_resize((struct _Ecore_Win32_Window *)ee->prop.window, + h, w); + if ((rotation == 0) || (rotation == 180)) + { + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + } + else + { + evas_output_size_set(ee->evas, ee->h, ee->w); + evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w); + } + if (ee->func.fn_resize) ee->func.fn_resize(ee); + } + ecore_evas_size_min_get(ee, &minw, &minh); + ecore_evas_size_max_get(ee, &maxw, &maxh); + ecore_evas_size_base_get(ee, &basew, &baseh); + ecore_evas_size_step_get(ee, &stepw, &steph); + ee->rotation = rotation; + ecore_evas_size_min_set(ee, minh, minw); + ecore_evas_size_max_set(ee, maxh, maxw); + ecore_evas_size_base_set(ee, baseh, basew); + ecore_evas_size_step_set(ee, steph, stepw); + _ecore_evas_mouse_move_process(ee, ee->mouse.x, ee->mouse.y, + ecore_win32_current_time_get()); + } + else + { + ee->rotation = rotation; + _ecore_evas_mouse_move_process(ee, ee->mouse.x, ee->mouse.y, + ecore_win32_current_time_get()); + if (ee->func.fn_resize) ee->func.fn_resize(ee); + } + + if ((ee->rotation == 90) || (ee->rotation == 270)) + evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w); + else + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); +} + +static void +_ecore_evas_win32_rotation_set(Ecore_Evas *ee, int rotation, int resize) +{ + INF("ecore evas rotation: %s", rotation ? "yes" : "no"); + + if (ee->rotation == rotation) return; + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_GDI + if (!strcmp(ee->driver, "software_gdi")) + { + Evas_Engine_Info_Software_Gdi *einfo; + + einfo = (Evas_Engine_Info_Software_Gdi *)evas_engine_info_get(ee->evas); + if (!einfo) return; + einfo->info.rotation = rotation; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + _ecore_evas_win32_rotation_set_internal(ee, rotation); + } +#endif /* BUILD_ECORE_EVAS_SOFTWARE_GDI */ + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_DDRAW + if (!strcmp(ee->driver, "software_ddraw")) + { + Evas_Engine_Info_Software_DDraw *einfo; + + einfo = (Evas_Engine_Info_Software_DDraw *)evas_engine_info_get(ee->evas); + if (!einfo) return; + einfo->info.rotation = rotation; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + _ecore_evas_win32_rotation_set_internal(ee, rotation); + } +#endif /* BUILD_ECORE_EVAS_SOFTWARE_DDRAW */ +} + +static void +_ecore_evas_win32_shaped_set(Ecore_Evas *ee, int shaped) +{ + if (((ee->shaped) && (shaped)) || ((!ee->shaped) && (!shaped))) + return; + + if (!strcmp(ee->driver, "software_ddraw")) return; + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_GDI + if (!strcmp(ee->driver, "software_gdi")) + { + Evas_Engine_Info_Software_Gdi *einfo; + + einfo = (Evas_Engine_Info_Software_Gdi *)evas_engine_info_get(ee->evas); + ee->shaped = shaped; + if (einfo) + { + ee->engine.win32.state.region = ee->shaped; + einfo->info.region = ee->engine.win32.state.region; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + if (ee->shaped) + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + } +#endif /* BUILD_ECORE_EVAS_SOFTWARE_GDI */ + } +} + +static void +_ecore_evas_win32_show(Ecore_Evas *ee) +{ + INF("ecore evas show"); + + ee->should_be_visible = 1; + if (ee->prop.avoid_damage) + _ecore_evas_win32_render(ee); + ecore_win32_window_show((struct _Ecore_Win32_Window *)ee->prop.window); +/* if (ee->prop.fullscreen) */ +/* ecore_win32_window_focus(ee->prop.window); */ +} + +static void +_ecore_evas_win32_hide(Ecore_Evas *ee) +{ + INF("ecore evas hide"); + + ecore_win32_window_hide((struct _Ecore_Win32_Window *)ee->prop.window); + ee->should_be_visible = 0; +} + +static void +_ecore_evas_win32_raise(Ecore_Evas *ee) +{ + INF("ecore evas raise"); + + if (!ee->prop.fullscreen) + ecore_win32_window_raise((struct _Ecore_Win32_Window *)ee->prop.window); + else + ecore_win32_window_raise((struct _Ecore_Win32_Window *)ee->prop.window); +} + +static void +_ecore_evas_win32_lower(Ecore_Evas *ee) +{ + INF("ecore evas lower"); + + if (!ee->prop.fullscreen) + ecore_win32_window_lower((struct _Ecore_Win32_Window *)ee->prop.window); + else + ecore_win32_window_lower((struct _Ecore_Win32_Window *)ee->prop.window); +} + +static void +_ecore_evas_win32_activate(Ecore_Evas *ee) +{ + INF("ecore evas activate"); + + ecore_win32_window_focus((struct _Ecore_Win32_Window *)ee->prop.window); +} + +static void +_ecore_evas_win32_title_set(Ecore_Evas *ee, const char *title) +{ + INF("ecore evas title set"); + + if (ee->prop.title) free(ee->prop.title); + ee->prop.title = NULL; + if (title) ee->prop.title = strdup(title); + ecore_win32_window_title_set((struct _Ecore_Win32_Window *)ee->prop.window, + ee->prop.title); +} + +static void +_ecore_evas_win32_size_min_set(Ecore_Evas *ee, int width, int height) +{ + if (width < 0) width = 0; + if (height < 0) height = 0; + if ((ee->prop.min.w == width) && (ee->prop.min.h == height)) return; + ee->prop.min.w = width; + ee->prop.min.h = height; + ecore_win32_window_size_min_set((struct _Ecore_Win32_Window *)ee->prop.window, + width, height); +} + +static void +_ecore_evas_win32_size_max_set(Ecore_Evas *ee, int width, int height) +{ + if (width < 0) width = 0; + if (height < 0) height = 0; + if ((ee->prop.max.w == width) && (ee->prop.max.h == height)) return; + ee->prop.max.w = width; + ee->prop.max.h = height; + ecore_win32_window_size_max_set((struct _Ecore_Win32_Window *)ee->prop.window, + width, height); +} + +static void +_ecore_evas_win32_size_base_set(Ecore_Evas *ee, int width, int height) +{ + if (width < 0) width = 0; + if (height < 0) height = 0; + if ((ee->prop.base.w == width) && (ee->prop.base.h == height)) return; + ee->prop.base.w = width; + ee->prop.base.h = height; + ecore_win32_window_size_base_set((struct _Ecore_Win32_Window *)ee->prop.window, + width, height); +} + +static void +_ecore_evas_win32_size_step_set(Ecore_Evas *ee, int width, int height) +{ + if (width < 1) width = 1; + if (height < 1) height = 1; + if ((ee->prop.step.w == width) && (ee->prop.step.h == height)) return; + ee->prop.step.w = width; + ee->prop.step.h = height; + ecore_win32_window_size_step_set((struct _Ecore_Win32_Window *)ee->prop.window, + width, height); +} + +static void +_ecore_evas_win32_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y) +{ +#if 0 + int x, y; + + if (ee->prop.cursor.object) evas_object_del(ee->prop.cursor.object); + + if (obj == NULL) + { + ee->prop.cursor.object = NULL; + ee->prop.cursor.layer = 0; + ee->prop.cursor.hot.x = 0; + ee->prop.cursor.hot.y = 0; + ecore_win32_window_cursor_show(ee->prop.window, 1); + return; + } + + ee->prop.cursor.object = obj; + ee->prop.cursor.layer = layer; + ee->prop.cursor.hot.x = hot_x; + ee->prop.cursor.hot.y = hot_y; + + ecore_win32_window_cursor_show(ee->prop.window, 0); + + evas_pointer_output_xy_get(ee->evas, &x, &y); + evas_object_layer_set(ee->prop.cursor.object, ee->prop.cursor.layer); + evas_object_move(ee->prop.cursor.object, + x - ee->prop.cursor.hot.x, + y - ee->prop.cursor.hot.y); + evas_object_pass_events_set(ee->prop.cursor.object, 1); + if (evas_pointer_inside_get(ee->evas)) + evas_object_show(ee->prop.cursor.object); +#endif +} + +static void +_ecore_evas_win32_focus_set(Ecore_Evas *ee, int on __UNUSED__) +{ + ecore_win32_window_focus((struct _Ecore_Win32_Window *)ee->prop.window); +} + +static void +_ecore_evas_win32_iconified_set(Ecore_Evas *ee, int on) +{ +/* if (((ee->prop.borderless) && (on)) || */ +/* ((!ee->prop.borderless) && (!on))) return; */ + ee->prop.iconified = on; + ecore_win32_window_iconified_set((struct _Ecore_Win32_Window *)ee->prop.window, + ee->prop.iconified); +} + +static void +_ecore_evas_win32_borderless_set(Ecore_Evas *ee, int on) +{ + if (((ee->prop.borderless) && (on)) || + ((!ee->prop.borderless) && (!on))) return; + ee->prop.borderless = on; + ecore_win32_window_borderless_set((struct _Ecore_Win32_Window *)ee->prop.window, + ee->prop.borderless); + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_GDI + if (!strcmp(ee->driver, "software_gdi")) + { + Evas_Engine_Info_Software_Gdi *einfo; + + einfo = (Evas_Engine_Info_Software_Gdi *)evas_engine_info_get(ee->evas); + if (einfo) + { + einfo->info.borderless = ee->prop.borderless; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + if (ee->prop.borderless) + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + } + } +#endif /* BUILD_ECORE_EVAS_SOFTWARE_GDI */ +} + +static void +_ecore_evas_win32_override_set(Ecore_Evas *ee, int on) +{ + struct _Ecore_Win32_Window *window; + + INF("ecore evas override set"); + + window = (struct _Ecore_Win32_Window *)ee->prop.window; + + if (ee->prop.override == on) return; + if (ee->should_be_visible) ecore_win32_window_hide(window); + /* FIXME: use borderless_set for now */ + ecore_win32_window_borderless_set(window, on); + if (ee->should_be_visible) ecore_win32_window_show(window); + if (ee->prop.focused) ecore_win32_window_focus(window); + ee->prop.override = on; +} + +static void +_ecore_evas_win32_fullscreen_set(Ecore_Evas *ee, int on) +{ + struct _Ecore_Win32_Window *window; + + INF("ecore evas fullscreen set"); + + if ((ee->engine.win32.state.fullscreen && on) || + (!ee->engine.win32.state.fullscreen && !on)) + return; + + ee->engine.win32.state.fullscreen = on; + ee->prop.fullscreen = on; + + window = (struct _Ecore_Win32_Window *)ee->prop.window; + + if (on != 0) + { + ecore_win32_window_fullscreen_set(window, on); + } + else + { + ecore_win32_window_fullscreen_set(window, on); + } + + /* Nothing to be done for the GDI backend at the evas level */ + +#ifdef BUILD_ECORE_EVAS_SOFTWRE_DDRAW + if (strcmp(ee->driver, "software_ddraw") == 0) + { + Evas_Engine_Info_Software_DDraw *einfo; + + einfo = (Evas_Engine_Info_Software_DDraw *)evas_engine_info_get(ecore_evas_get(ee)); + if (einfo) + { + einfo->info.fullscreen = !!on; +/* einfo->info.layered = window->shape.layered; */ + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + } + } +#endif /* BUILD_ECORE_EVAS_SOFTWARE_DDRAW */ + +#ifdef BUILD_ECORE_EVAS_DIRECT3D + if (strcmp(ee->driver, "direct3d") == 0) + { + Evas_Engine_Info_Direct3D *einfo; + + einfo = (Evas_Engine_Info_Direct3D *)evas_engine_info_get(ecore_evas_get(ee)); + if (einfo) + { + einfo->info.fullscreen = !!on; + einfo->info.layered = window->shape.layered; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + } + } +#endif /* BUILD_ECORE_EVAS_DIRECT3D */ +} +static void +_ecore_evas_win32_alpha_set(Ecore_Evas *ee, int alpha) +{ + alpha = !!alpha; + if ((ee->alpha == alpha)) return; + + if (!strcmp(ee->driver, "software_gdi")) + { +#ifdef BUILD_ECORE_EVAS_SOFTWARE_GDI + Evas_Engine_Info_Software_Gdi *einfo; + + einfo = (Evas_Engine_Info_Software_Gdi *)evas_engine_info_get(ee->evas); + if (!einfo) return; + + ee->shaped = 0; + ee->alpha = alpha; + /* ecore_win32_window_free(ee->prop.window); */ + /* ecore_event_window_unregister(ee->prop.window); */ + /* if (ee->alpha) */ + /* { */ + /* if (ee->prop.override) */ + /* ee->prop.window = ecore_x_window_override_argb_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); */ + /* else */ + /* ee->prop.window = ecore_x_window_argb_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); */ + /* if (!ee->engine.x.mask) */ + /* ee->engine.x.mask = ecore_x_pixmap_new(ee->prop.window, ee->req.w, ee->req.h, 1); */ + /* } */ + /* else */ + /* { */ + /* if (ee->prop.override) */ + /* ee->prop.window = ecore_win32_window_override_new(ee->engine.win32.win_root, */ + /* ee->req.x, */ + /* ee->req.y, */ + /* ee->req.w, */ + /* ee->req.h); */ + /* else */ + /* ee->prop.window = ecore_win32_window_new(ee->engine.win32.win_root, */ + /* ee->req.x, */ + /* ee->req.y, */ + /* ee->req.w, */ + /* ee->req.h); */ + /* if (ee->engine.win32.mask) ecore_x_pixmap_free(ee->engine.x.mask); */ + /* ee->engine.win32.mask = 0; */ + /* ecore_win32_window_shape_input_mask_set(ee->prop.window, 0); */ + /* } */ + + /* einfo->info.destination_alpha = alpha; */ + einfo->info.region = alpha; + +// if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask); +// ee->engine.x.mask = 0; + /* einfo->info.mask = ee->engine.win32.mask; */ + /* einfo->info.drawable = ee->prop.window; */ + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + evas_damage_rectangle_add(ee->evas, 0, 0, ee->req.w, ee->req.h); + /* ecore_win32_window_shape_mask_set(ee->prop.window, 0); */ + /* ecore_event_window_register(ee->prop.window, ee, ee->evas, */ + /* (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, */ + /* (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, */ + /* (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, */ + /* (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); */ + if (ee->prop.borderless) + ecore_win32_window_borderless_set((struct _Ecore_Win32_Window *)ee->prop.window, ee->prop.borderless); + if (ee->visible) ecore_win32_window_show((struct _Ecore_Win32_Window *)ee->prop.window); + if (ee->prop.focused) ecore_win32_window_focus((struct _Ecore_Win32_Window *)ee->prop.window); + if (ee->prop.title) + { + ecore_win32_window_title_set((struct _Ecore_Win32_Window *)ee->prop.window, ee->prop.title); + /* ecore_win32_name_set(ee->prop.window, ee->prop.title); */ + } + ecore_win32_window_type_set((struct _Ecore_Win32_Window *)ee->prop.window, ECORE_WIN32_WINDOW_TYPE_NORMAL); +#endif /* BUILD_ECORE_EVAS_SOFTWARE_GDI */ + } +} + +static void +_ecore_evas_win32_screen_dpi_get(const Ecore_Evas *ee, int *xdpi, int *ydpi) +{ + HDC dc; + + dc = GetDC(NULL); + if (!dc) + { + if (xdpi) *xdpi = 0; + if (ydpi) *ydpi = 0; + return; + } + + if (xdpi) *xdpi = GetDeviceCaps(dc, LOGPIXELSX); + if (ydpi) *ydpi = GetDeviceCaps(dc, LOGPIXELSY); + + /* + * Alternative (to test) + int width_mm; + int height_mm; + int width_px; + int height_px; + + width_mm = GetDeviceCaps(dc, HORZSIZE); + height_mm = GetDeviceCaps(dc, VERTSIZE); + width_px = GetDeviceCaps(dc, HORZRES); + height_px = GetDeviceCaps(dc, VERTRES); + + *xdpi = (width_px * 254) / (width_mm * 10); + *ydpi = (height_px * 254) / (height_mm * 10); + + code with LOGPIXELS gives 96x96 + code with the computation gives 101x77 + + */ + + ReleaseDC(NULL, dc); +} + +static Ecore_Evas_Engine_Func _ecore_win32_engine_func = +{ + _ecore_evas_win32_free, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_win32_callback_delete_request_set, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_win32_move, + NULL, + _ecore_evas_win32_resize, + _ecore_evas_win32_move_resize, + _ecore_evas_win32_rotation_set, + _ecore_evas_win32_shaped_set, + _ecore_evas_win32_show, + _ecore_evas_win32_hide, + _ecore_evas_win32_raise, + _ecore_evas_win32_lower, + _ecore_evas_win32_activate, + _ecore_evas_win32_title_set, + NULL, /* _ecore_evas_x_name_class_set */ + _ecore_evas_win32_size_min_set, + _ecore_evas_win32_size_max_set, + _ecore_evas_win32_size_base_set, + _ecore_evas_win32_size_step_set, + _ecore_evas_win32_cursor_set, + NULL, /* _ecore_evas_x_layer_set */ + _ecore_evas_win32_focus_set, + _ecore_evas_win32_iconified_set, + _ecore_evas_win32_borderless_set, + _ecore_evas_win32_override_set, + NULL, + _ecore_evas_win32_fullscreen_set, + NULL, /* _ecore_evas_x_avoid_damage_set */ + NULL, /* _ecore_evas_x_withdrawn_set */ + NULL, /* _ecore_evas_x_sticky_set */ + NULL, /* _ecore_evas_x_ignore_events_set */ + _ecore_evas_win32_alpha_set, + NULL, //transparent + NULL, // profiles_set + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + + NULL, // render + NULL, // screen_geometry_get + _ecore_evas_win32_screen_dpi_get +}; + +#endif /* BUILD_ECORE_EVAS_WIN32 */ + +/* API */ + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_GDI +static int +_ecore_evas_engine_software_gdi_init(Ecore_Evas *ee) +{ + Evas_Engine_Info_Software_Gdi *einfo; + const char *driver; + int rmethod; + + driver = "software_gdi"; + + rmethod = evas_render_method_lookup(driver); + if (!rmethod) + return 0; + + ee->driver = driver; + evas_output_method_set(ee->evas, rmethod); + + einfo = (Evas_Engine_Info_Software_Gdi *)evas_engine_info_get(ee->evas); + if (einfo) + { + /* FIXME: REDRAW_DEBUG missing for now */ + einfo->info.window = ((struct _Ecore_Win32_Window *)ee->prop.window)->window; + einfo->info.depth = ecore_win32_screen_depth_get(); + einfo->info.rotation = 0; + einfo->info.borderless = 0; + einfo->info.fullscreen = 0; + einfo->info.region = 0; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + return 0; + } + } + else + { + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); + return 0; + } + + return 1; +} +#endif /* BUILD_ECORE_EVAS_SOFTWARE_GDI */ + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_DDRAW +static int +_ecore_evas_engine_software_ddraw_init(Ecore_Evas *ee) +{ + Evas_Engine_Info_Software_DDraw *einfo; + const char *driver; + int rmethod; + + driver = "software_ddraw"; + + rmethod = evas_render_method_lookup(driver); + if (!rmethod) + return 0; + + ee->driver = driver; + evas_output_method_set(ee->evas, rmethod); + + einfo = (Evas_Engine_Info_Software_DDraw *)evas_engine_info_get(ee->evas); + if (einfo) + { + /* FIXME: REDRAW_DEBUG missing for now */ + einfo->info.window = ((struct _Ecore_Win32_Window *)ee->prop.window)->window; + einfo->info.depth = ecore_win32_screen_depth_get(); + einfo->info.rotation = 0; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + return 0; + } + } + else + { + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); + return 0; + } + + return 1; +} +#endif /* BUILD_ECORE_EVAS_SOFTWARE_DDRAW */ + +#ifdef BUILD_ECORE_EVAS_DIRECT3D +static int +_ecore_evas_engine_direct3d_init(Ecore_Evas *ee) +{ + Evas_Engine_Info_Direct3D *einfo; + const char *driver; + int rmethod; + + driver = "direct3d"; + + rmethod = evas_render_method_lookup(driver); + if (!rmethod) + return 0; + + ee->driver = driver; + evas_output_method_set(ee->evas, rmethod); + + einfo = (Evas_Engine_Info_Direct3D *)evas_engine_info_get(ee->evas); + if (einfo) + { + /* FIXME: REDRAW_DEBUG missing for now */ + einfo->info.window = ((struct _Ecore_Win32_Window *)ee->prop.window)->window; + einfo->info.depth = ecore_win32_screen_depth_get(); + einfo->info.rotation = 0; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + return 0; + } + } + else + { + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); + return 0; + } + + return 1; +} +#endif /* BUILD_ECORE_EVAS_DIRECT3D */ + +#ifdef BUILD_ECORE_EVAS_OPENGL_GLEW +static int +_ecore_evas_engine_opengl_glew_init(Ecore_Evas *ee) +{ + Evas_Engine_Info_GL_Glew *einfo; + const char *driver; + int rmethod; + + driver = "gl_glew"; + + rmethod = evas_render_method_lookup(driver); + if (!rmethod) + return 0; + + ee->driver = driver; + evas_output_method_set(ee->evas, rmethod); + + einfo = (Evas_Engine_Info_GL_Glew *)evas_engine_info_get(ee->evas); + if (einfo) + { + /* FIXME: REDRAW_DEBUG missing for now */ + einfo->info.window = ((struct _Ecore_Win32_Window *)ee->prop.window)->window; + einfo->info.depth = ecore_win32_screen_depth_get(); + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + return 0; + } + } + else + { + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); + return 0; + } + + return 1; +} +#endif /* BUILD_ECORE_EVAS_OPENGL_GLEW */ + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_DDRAW +static int +_ecore_evas_engine_software_16_ddraw_init(Ecore_Evas *ee) +{ + Evas_Engine_Info_Software_DDraw *einfo; + const char *driver; + int rmethod; + + driver = "software_16_ddraw"; + + rmethod = evas_render_method_lookup(driver); + if (!rmethod) + return 0; + + ee->driver = driver; + evas_output_method_set(ee->evas, rmethod); + + if (ecore_win32_screen_depth_get() != 16) + return 0; + + einfo = (Evas_Engine_Info_Software_16_DDraw *)evas_engine_info_get(ee->evas); + if (einfo) + { + /* FIXME: REDRAW_DEBUG missing for now */ + einfo->info.window = ((struct _Ecore_Win32_Window *)ee->prop.window)->window; + einfo->info.depth = ecore_win32_screen_depth_get(); + einfo->info.rotation = 0; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + return 0; + } + } + else + { + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); + return 0; + } + + return 1; +} +#endif /* BUILD_ECORE_EVAS_SOFTWARE_16_DDRAW */ + +#ifdef BUILD_ECORE_EVAS_WIN32 +static Ecore_Evas * +_ecore_evas_win32_new_internal(int (*_ecore_evas_engine_init)(Ecore_Evas *ee), + Ecore_Win32_Window *parent, + int x, + int y, + int width, + int height) +{ + Ecore_Evas *ee; + + if (!ecore_win32_init()) + return NULL; + + ee = calloc(1, sizeof(Ecore_Evas)); + if (!ee) + return NULL; + + ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); + + _ecore_evas_win32_init(); + + ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_win32_engine_func; + + if (width < 1) width = 1; + if (height < 1) height = 1; + ee->x = x; + ee->y = y; + ee->w = width; + ee->h = height; + ee->req.x = ee->x; + ee->req.y = ee->y; + ee->req.w = ee->w; + ee->req.h = ee->h; + + ee->prop.max.w = 32767; + ee->prop.max.h = 32767; + ee->prop.layer = 4; + ee->prop.request_pos = 0; + ee->prop.sticky = 0; + /* FIXME: sticky to add */ + ee->prop.window = 0; + + /* init evas here */ + ee->evas = evas_new(); + evas_data_attach_set(ee->evas, ee); + evas_output_size_set(ee->evas, width, height); + evas_output_viewport_set(ee->evas, 0, 0, width, height); + + ee->engine.win32.parent = parent; + ee->prop.window = (Ecore_Window)ecore_win32_window_new(parent, x, y, width, height); + if (!ee->prop.window) + { + _ecore_evas_win32_shutdown(); + free(ee); + return NULL; + } + + if (!_ecore_evas_engine_init(ee)) + { + _ecore_evas_win32_shutdown(); + free(ee); + return NULL; + } + + ee->engine.func->fn_render = _ecore_evas_win32_render; + _ecore_evas_register(ee); + ecore_event_window_register(ee->prop.window, ee, ee->evas, + (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, + (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, + (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, + (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); + + return ee; +} + +#endif /* BUILD_ECORE_EVAS_WIN32 */ + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_GDI + +EAPI Ecore_Evas * +ecore_evas_software_gdi_new(Ecore_Win32_Window *parent, + int x, + int y, + int width, + int height) +{ + return _ecore_evas_win32_new_internal(_ecore_evas_engine_software_gdi_init, + parent, + x, + y, + width, + height); +} + +#else + +EAPI Ecore_Evas * +ecore_evas_software_gdi_new(Ecore_Win32_Window *parent __UNUSED__, + int x __UNUSED__, + int y __UNUSED__, + int width __UNUSED__, + int height __UNUSED__) +{ + return NULL; +} + +#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_GDI */ + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_DDRAW + +EAPI Ecore_Evas * +ecore_evas_software_ddraw_new(Ecore_Win32_Window *parent, + int x, + int y, + int width, + int height) +{ + return _ecore_evas_win32_new_internal(_ecore_evas_engine_software_ddraw_init, + parent, + x, + y, + width, + height); +} + +#else + +EAPI Ecore_Evas * +ecore_evas_software_ddraw_new(Ecore_Win32_Window *parent __UNUSED__, + int x __UNUSED__, + int y __UNUSED__, + int width __UNUSED__, + int height __UNUSED__) +{ + return NULL; +} + +#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_DDRAW */ + + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_DDRAW + +EAPI Ecore_Evas * +ecore_evas_software_16_ddraw_new(Ecore_Win32_Window *parent, + int x, + int y, + int width, + int height) +{ + return _ecore_evas_win32_new_internal(_ecore_evas_engine_software_16_ddraw_init, + parent, + x, + y, + width, + height); +} + +#else + +EAPI Ecore_Evas * +ecore_evas_software_16_ddraw_new(Ecore_Win32_Window *parent __UNUSED__, + int x __UNUSED__, + int y __UNUSED__, + int width __UNUSED__, + int height __UNUSED__) +{ + return NULL; +} + +#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_16_DDRAW */ + + +#ifdef BUILD_ECORE_EVAS_DIRECT3D + +EAPI Ecore_Evas * +ecore_evas_direct3d_new(Ecore_Win32_Window *parent, + int x, + int y, + int width, + int height) +{ + return _ecore_evas_win32_new_internal(_ecore_evas_engine_direct3d_init, + parent, + x, + y, + width, + height); +} + +#else + +EAPI Ecore_Evas * +ecore_evas_direct3d_new(Ecore_Win32_Window *parent __UNUSED__, + int x __UNUSED__, + int y __UNUSED__, + int width __UNUSED__, + int height __UNUSED__) +{ + return NULL; +} + +#endif /* ! BUILD_ECORE_EVAS_DIRECT3D */ + + +#ifdef BUILD_ECORE_EVAS_OPENGL_GLEW + +EAPI Ecore_Evas * +ecore_evas_gl_glew_new(Ecore_Win32_Window *parent, + int x, + int y, + int width, + int height) +{ + return _ecore_evas_win32_new_internal(_ecore_evas_engine_opengl_glew_init, + parent, + x, + y, + width, + height); +} + +#else + +EAPI Ecore_Evas * +ecore_evas_gl_glew_new(Ecore_Win32_Window *parent __UNUSED__, + int x __UNUSED__, + int y __UNUSED__, + int width __UNUSED__, + int height __UNUSED__) +{ + return NULL; +} + +#endif /* BUILD_ECORE_EVAS_OPENGL_GLEW */ + + +#ifdef BUILD_ECORE_EVAS_WIN32 + +EAPI Ecore_Win32_Window * +ecore_evas_win32_window_get(const Ecore_Evas *ee) +{ + return (Ecore_Win32_Window *) ecore_evas_window_get(ee); +} + +#else + +EAPI Ecore_Win32_Window * +ecore_evas_win32_window_get(const Ecore_Evas *ee __UNUSED__) +{ + return NULL; +} + +#endif /* BUILD_ECORE_EVAS_WIN32 */ diff --git a/src/lib/ecore_evas/ecore_evas_wince.c b/src/lib/ecore_evas/ecore_evas_wince.c new file mode 100644 index 0000000..fe0054a --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas_wince.c @@ -0,0 +1,1013 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include /* for NULL */ + +#include +#include "ecore_private.h" +#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_WINCE +# define WIN32_LEAN_AND_MEAN +# include +# undef WIN32_LEAN_AND_MEAN +# include +# include +#endif /* BUILD_ECORE_EVAS_SOFTWARE_16_WINCE */ + +#include "ecore_evas_private.h" +#include "Ecore_Evas.h" + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_WINCE + +#define ECORE_EVAS_EVENT_COUNT 9 + +static int _ecore_evas_init_count = 0; + +static Ecore_Event_Handler *ecore_evas_event_handlers[ECORE_EVAS_EVENT_COUNT]; + +static Eina_Bool _ecore_evas_wince_event_mouse_in(void *data __UNUSED__, int type __UNUSED__, void *event); + +static Eina_Bool _ecore_evas_wince_event_mouse_out(void *data __UNUSED__, int type __UNUSED__, void *event); + +static Eina_Bool _ecore_evas_wince_event_window_focus_in(void *data __UNUSED__, int type __UNUSED__, void *event); + +static Eina_Bool _ecore_evas_wince_event_window_focus_out(void *data __UNUSED__, int type __UNUSED__, void *event); + +static Eina_Bool _ecore_evas_wince_event_window_damage(void *data __UNUSED__, int type __UNUSED__, void *event); + +static Eina_Bool _ecore_evas_wince_event_window_destroy(void *data __UNUSED__, int type __UNUSED__, void *event); + +static Eina_Bool _ecore_evas_wince_event_window_show(void *data __UNUSED__, int type __UNUSED__, void *event); + +static Eina_Bool _ecore_evas_wince_event_window_hide(void *data __UNUSED__, int type __UNUSED__, void *event); + +static Eina_Bool _ecore_evas_wince_event_window_delete_request(void *data __UNUSED__, int type __UNUSED__, void *event); + +/* Private functions */ + +static int +_ecore_evas_wince_render(Ecore_Evas *ee) +{ + int rend = 0; + Eina_List *updates = NULL; + Eina_List *ll; + Ecore_Evas *ee2; + + EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2) + { + if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2); + if (ee2->engine.func->fn_render) + rend |= ee2->engine.func->fn_render(ee2); + if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2); + } + + if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee); + if (ee->prop.avoid_damage) + { + updates = evas_render_updates(ee->evas); + if (updates) evas_render_updates_free(updates); + } + else if ((ee->visible) || + ((ee->should_be_visible) && (ee->prop.fullscreen)) || + ((ee->should_be_visible) && (ee->prop.override))) + { + if (ee->shaped) + { + updates = evas_render_updates(ee->evas); + if (updates) evas_render_updates_free(updates); + } + else + { + updates = evas_render_updates(ee->evas); + if (updates) evas_render_updates_free(updates); + } + } + else + evas_norender(ee->evas); + if (updates) rend = 1; + if (ee->func.fn_post_render) ee->func.fn_post_render(ee); + return rend; +} + +static int +_ecore_evas_wince_init(void) +{ + _ecore_evas_init_count++; + if (_ecore_evas_init_count > 1) + return _ecore_evas_init_count; + + ecore_evas_event_handlers[0] = ecore_event_handler_add(ECORE_WINCE_EVENT_MOUSE_IN, _ecore_evas_wince_event_mouse_in, NULL); + ecore_evas_event_handlers[1] = ecore_event_handler_add(ECORE_WINCE_EVENT_MOUSE_OUT, _ecore_evas_wince_event_mouse_out, NULL); + ecore_evas_event_handlers[2] = ecore_event_handler_add(ECORE_WINCE_EVENT_WINDOW_FOCUS_IN, _ecore_evas_wince_event_window_focus_in, NULL); + ecore_evas_event_handlers[3] = ecore_event_handler_add(ECORE_WINCE_EVENT_WINDOW_FOCUS_OUT, _ecore_evas_wince_event_window_focus_out, NULL); + ecore_evas_event_handlers[4] = ecore_event_handler_add(ECORE_WINCE_EVENT_WINDOW_DAMAGE, _ecore_evas_wince_event_window_damage, NULL); + ecore_evas_event_handlers[5] = ecore_event_handler_add(ECORE_WINCE_EVENT_WINDOW_DESTROY, _ecore_evas_wince_event_window_destroy, NULL); + ecore_evas_event_handlers[6] = ecore_event_handler_add(ECORE_WINCE_EVENT_WINDOW_SHOW, _ecore_evas_wince_event_window_show, NULL); + ecore_evas_event_handlers[7] = ecore_event_handler_add(ECORE_WINCE_EVENT_WINDOW_HIDE, _ecore_evas_wince_event_window_hide, NULL); + ecore_evas_event_handlers[8] = ecore_event_handler_add(ECORE_WINCE_EVENT_WINDOW_DELETE_REQUEST, _ecore_evas_wince_event_window_delete_request, NULL); + + ecore_event_evas_init(); + return _ecore_evas_init_count; +} + +int +_ecore_evas_wince_shutdown(void) +{ + _ecore_evas_init_count--; + if (_ecore_evas_init_count == 0) + { + int i; + + for (i = 0; i < ECORE_EVAS_EVENT_COUNT; i++) + ecore_event_handler_del(ecore_evas_event_handlers[i]); + ecore_event_evas_shutdown(); + } + + if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0; + + return _ecore_evas_init_count; +} + +static Eina_Bool +_ecore_evas_wince_event_mouse_in(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_WinCE_Event_Mouse_In *e; + + INF("mouse in"); + + e = event; + ee = ecore_event_window_match((Ecore_Window)e->window); + if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ + if (e->window != (Ecore_WinCE_Window *)ee->prop.window) return 1; + + if (ee->func.fn_mouse_in) ee->func.fn_mouse_in(ee); + /* FIXME to do */ +/* _ecore_evas_x_modifier_locks_update(ee, e->modifiers); */ + evas_event_feed_mouse_in(ee->evas, e->time, NULL); + _ecore_evas_mouse_move_process(ee, e->x, e->y, e->time); + + return 1; +} + +static Eina_Bool +_ecore_evas_wince_event_mouse_out(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_WinCE_Event_Mouse_Out *e; + + INF("mouse out"); + + e = event; + ee = ecore_event_window_match((Ecore_Window)e->window); + if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ + if (e->window != (Ecore_WinCE_Window *)ee->prop.window) return 1; + + /* FIXME to do */ +/* _ecore_evas_x_modifier_locks_update(ee, e->modifiers); */ + _ecore_evas_mouse_move_process(ee, e->x, e->y, e->time); + + evas_event_feed_mouse_out(ee->evas, e->time, NULL); + if (ee->func.fn_mouse_out) ee->func.fn_mouse_out(ee); + if (ee->prop.cursor.object) evas_object_hide(ee->prop.cursor.object); + + return 1; +} + +static Eina_Bool +_ecore_evas_wince_event_window_focus_in(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_WinCE_Event_Window_Focus_In *e; + + e = event; + ee = ecore_event_window_match(e->window); + if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; + if (e->window != ee->prop.window) return ECORE_CALLBACK_PASS_ON; + + ee->prop.focused = 1; + evas_focus_in(ee->evas); + if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_wince_event_window_focus_out(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_WinCE_Event_Window_Focus_Out *e; + + e = event; + ee = ecore_event_window_match(e->window); + if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; + if (e->window != ee->prop.window) return ECORE_CALLBACK_PASS_ON; + + evas_focus_out(ee->evas); + ee->prop.focused = 0; + if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_wince_event_window_damage(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_WinCE_Event_Window_Damage *e; + + INF("window damage"); + + e = event; + ee = ecore_event_window_match((Ecore_Window)e->window); + if (!ee) return 1; /* pass on event */ + if (e->window != (Ecore_WinCE_Window *)ee->prop.window) return 1; + + if (ee->prop.avoid_damage) + { +#warning [ECORE] [WINCE] No Region code + } + else + { + if (ee->rotation == 0) + evas_damage_rectangle_add(ee->evas, + e->x, + e->y, + e->width, + e->height); + else if (ee->rotation == 90) + evas_damage_rectangle_add(ee->evas, + ee->h - e->y - e->height, + e->x, + e->height, + e->width); + else if (ee->rotation == 180) + evas_damage_rectangle_add(ee->evas, + ee->w - e->x - e->width, + ee->h - e->y - e->height, + e->width, + e->height); + else if (ee->rotation == 270) + evas_damage_rectangle_add(ee->evas, + e->y, + ee->w - e->x - e->width, + e->height, + e->width); + } + + return 1; +} + +static Eina_Bool +_ecore_evas_wince_event_window_destroy(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_WinCE_Event_Window_Destroy *e; + + INF("window destroy"); + + e = event; + ee = ecore_event_window_match((Ecore_Window)e->window); + if (!ee) return 1; /* pass on event */ + if (e->window != (Ecore_WinCE_Window *)ee->prop.window) return 1; + if (ee->func.fn_destroy) ee->func.fn_destroy(ee); + ecore_evas_free(ee); + + return 1; +} + +static Eina_Bool +_ecore_evas_wince_event_window_show(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_WinCE_Event_Window_Show *e; + + INF("window show"); + + e = event; + ee = ecore_event_window_match((Ecore_Window)e->window); + if (!ee) return 1; /* pass on event */ + if (e->window != (Ecore_WinCE_Window *)ee->prop.window) return 1; + if (ee->visible) return 0; /* dont pass it on */ + ee->visible = 1; + if (ee->func.fn_show) ee->func.fn_show(ee); + + return 1; +} + +static Eina_Bool +_ecore_evas_wince_event_window_hide(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_WinCE_Event_Window_Hide *e; + + INF("window hide"); + + e = event; + ee = ecore_event_window_match((Ecore_Window)e->window); + if (!ee) return 1; /* pass on event */ + if (e->window != (Ecore_WinCE_Window *)ee->prop.window) return 1; + if (!ee->visible) return 0; /* dont pass it on */ + ee->visible = 0; + if (ee->func.fn_hide) ee->func.fn_hide(ee); + + return 1; +} + +static Eina_Bool +_ecore_evas_wince_event_window_delete_request(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_WinCE_Event_Window_Delete_Request *e; + + INF("window delete request"); + + e = event; + ee = ecore_event_window_match((Ecore_Window)e->window); + if (!ee) return 1; /* pass on event */ + if (e->window != (Ecore_WinCE_Window *)ee->prop.window) return 1; + if (ee->func.fn_delete_request) ee->func.fn_delete_request(ee); + + return 1; +} + + +/* Ecore_Evas interface */ + +static void +_ecore_evas_wince_free(Ecore_Evas *ee) +{ + INF("ecore evas free"); + + ecore_wince_window_free((Ecore_WinCE_Window *)ee->prop.window); + ecore_event_window_unregister(ee->prop.window); + _ecore_evas_wince_shutdown(); + ecore_wince_shutdown(); +} + +static void +_ecore_evas_wince_callback_delete_request_set(Ecore_Evas *ee, + Ecore_Evas_Event_Cb func) +{ + ee->func.fn_delete_request = func; +} + +static void +_ecore_evas_wince_move(Ecore_Evas *ee, int x, int y) +{ + INF("ecore evas move (%dx%d)", x, y); + ee->req.x = x; + ee->req.y = y; + + if ((x != ee->x) || (y != ee->y)) + { + ee->x = x; + ee->y = y; + ecore_wince_window_move((Ecore_WinCE_Window *)ee->prop.window, x, y); + if (ee->func.fn_move) ee->func.fn_move(ee); + } +} + +static void +_ecore_evas_wince_resize(Ecore_Evas *ee, int width, int height) +{ + INF("ecore evas resize (%dx%d)", width, height); + ee->req.w = width; + ee->req.h = height; + + if ((ee->w != width) || (ee->h != height)) + { + ee->w = width; + ee->h = height; + ecore_wince_window_resize((Ecore_WinCE_Window *)ee->prop.window, width, height); + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + evas_output_size_set(ee->evas, ee->h, ee->w); + evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w); + } + else + { + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + } + /* FIXME: damage and shape */ + + if (ee->func.fn_resize) ee->func.fn_resize(ee); + } +} + +static void +_ecore_evas_wince_move_resize(Ecore_Evas *ee, int x, int y, int width, int height) +{ + INF("ecore evas resize (%dx%d %dx%d)", x, y, width, height); + ee->req.x = x; + ee->req.y = y; + ee->req.w = width; + ee->req.h = height; + + if ((ee->w != width) || (ee->h != height) || (x != ee->x) || (y != ee->y)) + { + int change_size = 0; + int change_pos = 0; + + if ((ee->w != width) || (ee->h != height)) change_size = 1; + if ((x != ee->x) || (y != ee->y)) change_pos = 1; + + ee->x = x; + ee->y = y; + ee->w = width; + ee->h = height; + ecore_wince_window_move_resize((Ecore_WinCE_Window *)ee->prop.window, x, y, width, height); + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + evas_output_size_set(ee->evas, ee->h, ee->w); + evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w); + } + else + { + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + } + /* FIXME: damage and shape */ + if (change_pos) + { + if (ee->func.fn_move) ee->func.fn_move(ee); + } + if (change_size) + { + if (ee->func.fn_resize) ee->func.fn_resize(ee); + } + } +} + +/* static void */ +/* _ecore_evas_wince_rotation_set(Ecore_Evas *ee, int rotation) */ +/* { */ +/* int rot_dif; */ + +/* if (ee->rotation == rotation) return; */ +/* rot_dif = ee->rotation - rotation; */ +/* if (rot_dif < 0) rot_dif = -rot_dif; */ +/* if (!strcmp(ee->driver, "software_ddraw")) */ +/* { */ +/* Evas_Engine_Info_Software_16_WinCE *einfo; */ + +/* einfo = (Evas_Engine_Info_Software_16_WinCE *)evas_engine_info_get(ee->evas); */ +/* if (!einfo) return; */ +/* if (rot_dif != 180) */ +/* { */ +/* int minw, minh, maxw, maxh, basew, baseh, stepw, steph; */ + +/* einfo->info.rotation = rotation; */ +/* evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); */ +/* if (!ee->prop.fullscreen) */ +/* { */ +/* ecore_wince_window_resize(ee->prop.window, ee->h, ee->w); */ +/* ee->expecting_resize.w = ee->h; */ +/* ee->expecting_resize.h = ee->w; */ +/* } */ +/* else */ +/* { */ +/* int w, h; */ + +/* ecore_wince_window_size_get(ee->prop.window, &w, &h); */ +/* ecore_wince_window_resize(ee->prop.window, h, w); */ +/* if ((rotation == 0) || (rotation == 180)) */ +/* { */ +/* evas_output_size_set(ee->evas, ee->w, ee->h); */ +/* evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); */ +/* } */ +/* else */ +/* { */ +/* evas_output_size_set(ee->evas, ee->h, ee->w); */ +/* evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w); */ +/* } */ +/* if (ee->func.fn_resize) ee->func.fn_resize(ee); */ +/* } */ +/* ecore_evas_size_min_get(ee, &minw, &minh); */ +/* ecore_evas_size_max_get(ee, &maxw, &maxh); */ +/* ecore_evas_size_base_get(ee, &basew, &baseh); */ +/* ecore_evas_size_step_get(ee, &stepw, &steph); */ +/* ee->rotation = rotation; */ +/* ecore_evas_size_min_set(ee, minh, minw); */ +/* ecore_evas_size_max_set(ee, maxh, maxw); */ +/* ecore_evas_size_base_set(ee, baseh, basew); */ +/* ecore_evas_size_step_set(ee, steph, stepw); */ +/* _ecore_evas_wince_mouse_move_process(ee, ee->mouse.x, ee->mouse.y, */ +/* ecore_wince_current_time_get()); */ +/* } */ +/* else */ +/* { */ +/* einfo->info.rotation = rotation; */ +/* evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); */ +/* ee->rotation = rotation; */ +/* _ecore_evas_wince_mouse_move_process(ee, ee->mouse.x, ee->mouse.y, */ +/* ecore_wince_current_time_get()); */ +/* if (ee->func.fn_resize) ee->func.fn_resize(ee); */ +/* } */ +/* if ((ee->rotation == 90) || (ee->rotation == 270)) */ +/* evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w); */ +/* else */ +/* evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); */ +/* } */ +/* } */ + +static void +_ecore_evas_wince_show(Ecore_Evas *ee) +{ + INF("ecore evas show"); + + ee->should_be_visible = 1; + if (ee->prop.avoid_damage) + _ecore_evas_wince_render(ee); + ecore_wince_window_show((Ecore_WinCE_Window *)ee->prop.window); +/* if (ee->prop.fullscreen) */ +/* ecore_wince_window_focus(ee->prop.window); */ +} + +static void +_ecore_evas_wince_hide(Ecore_Evas *ee) +{ + INF("ecore evas hide"); + + ecore_wince_window_hide((Ecore_WinCE_Window *)ee->prop.window); + ee->should_be_visible = 0; +} + +/* static void */ +/* _ecore_evas_wince_raise(Ecore_Evas *ee) */ +/* { */ +/* if (!ee->prop.fullscreen) */ +/* ecore_wince_window_raise(ee->prop.window); */ +/* else */ +/* ecore_wince_window_raise(ee->prop.window); */ +/* } */ + +/* static void */ +/* _ecore_evas_wince_lower(Ecore_Evas *ee) */ +/* { */ +/* if (!ee->prop.fullscreen) */ +/* ecore_wince_window_lower(ee->prop.window); */ +/* else */ +/* ecore_wince_window_lower(ee->prop.window); */ +/* } */ + +static void +_ecore_evas_wince_title_set(Ecore_Evas *ee, const char *title) +{ + INF("ecore evas title set"); + + if (ee->prop.title) free(ee->prop.title); + ee->prop.title = NULL; + if (title) ee->prop.title = strdup(title); + ecore_wince_window_title_set((Ecore_WinCE_Window *)ee->prop.window, ee->prop.title); +} + +/* static void */ +/* _ecore_evas_wince_size_min_set(Ecore_Evas *ee, int width, int height) */ +/* { */ +/* if (width < 0) width = 0; */ +/* if (height < 0) height = 0; */ +/* if ((ee->prop.min.w == width) && (ee->prop.min.h == height)) return; */ +/* ee->prop.min.w = width; */ +/* ee->prop.min.h = height; */ +/* ecore_wince_window_size_min_set(ee->prop.window, width, height); */ +/* } */ + +/* static void */ +/* _ecore_evas_wince_size_max_set(Ecore_Evas *ee, int width, int height) */ +/* { */ +/* if (width < 0) width = 0; */ +/* if (height < 0) height = 0; */ +/* if ((ee->prop.max.w == width) && (ee->prop.max.h == height)) return; */ +/* ee->prop.max.w = width; */ +/* ee->prop.max.h = height; */ +/* ecore_wince_window_size_max_set(ee->prop.window, width, height); */ +/* } */ + +/* static void */ +/* _ecore_evas_wince_size_base_set(Ecore_Evas *ee, int width, int height) */ +/* { */ +/* if (width < 0) width = 0; */ +/* if (height < 0) height = 0; */ +/* if ((ee->prop.base.w == width) && (ee->prop.base.h == height)) return; */ +/* ee->prop.base.w = width; */ +/* ee->prop.base.h = height; */ +/* ecore_wince_window_size_base_set(ee->prop.window, width, height); */ +/* } */ + +/* static void */ +/* _ecore_evas_wince_size_step_set(Ecore_Evas *ee, int width, int height) */ +/* { */ +/* if (width < 1) width = 1; */ +/* if (height < 1) height = 1; */ +/* if ((ee->prop.step.w == width) && (ee->prop.step.h == height)) return; */ +/* ee->prop.step.w = width; */ +/* ee->prop.step.h = height; */ +/* ecore_wince_window_size_step_set(ee->prop.window, width, height); */ +/* } */ + +static void +_ecore_evas_wince_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y) +{ +#if 0 + int x, y; + + if (ee->prop.cursor.object) evas_object_del(ee->prop.cursor.object); + + if (obj == NULL) + { + ee->prop.cursor.object = NULL; + ee->prop.cursor.layer = 0; + ee->prop.cursor.hot.x = 0; + ee->prop.cursor.hot.y = 0; + ecore_wince_window_cursor_show(ee->prop.window, 1); + return; + } + + ee->prop.cursor.object = obj; + ee->prop.cursor.layer = layer; + ee->prop.cursor.hot.x = hot_x; + ee->prop.cursor.hot.y = hot_y; + + ecore_wince_window_cursor_show(ee->prop.window, 0); + + evas_pointer_output_xy_get(ee->evas, &x, &y); + evas_object_layer_set(ee->prop.cursor.object, ee->prop.cursor.layer); + evas_object_move(ee->prop.cursor.object, + x - ee->prop.cursor.hot.x, + y - ee->prop.cursor.hot.y); + evas_object_pass_events_set(ee->prop.cursor.object, 1); + if (evas_pointer_inside_get(ee->evas)) + evas_object_show(ee->prop.cursor.object); +#endif +} + +static void +_ecore_evas_wince_focus_set(Ecore_Evas *ee, int on __UNUSED__) +{ + ecore_wince_window_focus(ee->prop.window); +} + +/* static void */ +/* _ecore_evas_wince_iconified_set(Ecore_Evas *ee, int on) */ +/* { */ +/* /\* if (((ee->prop.borderless) && (on)) || *\/ */ +/* /\* ((!ee->prop.borderless) && (!on))) return; *\/ */ +/* ee->prop.iconified = on; */ +/* ecore_wince_window_iconified_set(ee->prop.window, ee->prop.iconified); */ +/* } */ + +/* static void */ +/* _ecore_evas_wince_borderless_set(Ecore_Evas *ee, int on) */ +/* { */ +/* if (((ee->prop.borderless) && (on)) || */ +/* ((!ee->prop.borderless) && (!on))) return; */ +/* ee->prop.borderless = on; */ +/* ecore_wince_window_borderless_set(ee->prop.window, ee->prop.borderless); */ +/* } */ + +static void +_ecore_evas_wince_fullscreen_set(Ecore_Evas *ee, int on) +{ + Evas_Engine_Info_Software_16_WinCE *einfo; + struct _Ecore_WinCE_Window *window; + + INF("ecore evas fullscreen set"); + + if ((ee->engine.wince.state.fullscreen && on) || + (!ee->engine.wince.state.fullscreen && !on)) + return; + + ee->engine.wince.state.fullscreen = on; + ee->prop.fullscreen = on; + + window = (struct _Ecore_WinCE_Window *)ee->prop.window; + + if (on != 0) + { +/* ecore_win32_window_shape_set(ee->engine.win32.window, 0, 0, NULL); */ + ecore_wince_window_fullscreen_set((Ecore_WinCE_Window *)ee->prop.window, on); + ee->w = GetSystemMetrics(SM_CXSCREEN); + ee->h = GetSystemMetrics(SM_CYSCREEN); + ee->req.w = ee->w; + ee->req.h = ee->h; + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + } + else + { + int w; + int h; + + ecore_wince_window_fullscreen_set((Ecore_WinCE_Window *)ee->prop.window, on); + ecore_wince_window_size_get((Ecore_WinCE_Window *)ee->prop.window, &w, &h); + ee->w = w; + ee->h = h; + ee->req.w = ee->w; + ee->req.h = ee->h; + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); +/* ecore_win32_window_shape_set(window, */ +/* window->shape.width, */ +/* window->shape.height, */ +/* window->shape.mask); */ + } + + einfo = (Evas_Engine_Info_Software_16_WinCE *)evas_engine_info_get(ecore_evas_get(ee)); + if (einfo) + { + einfo->info.fullscreen = !!on; +/* einfo->info.layered = window->shape.layered; */ + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + } +} + +static void +_ecore_evas_wince_screen_dpi_get(const Ecore_Evas *ee, int *xdpi, int *ydpi) +{ + HDC dc; + + dc = GetDC(NULL); + if (!dc) + { + if (xdpi) *xdpi = 0; + if (ydpi) *ydpi = 0; + return; + } + + if (xdpi) *xdpi = GetDeviceCaps(dc, LOGPIXELSX); + if (ydpi) *ydpi = GetDeviceCaps(dc, LOGPIXELSY); + + ReleaseDC(NULL, dc); +} + +static Ecore_Evas_Engine_Func _ecore_wince_engine_func = +{ + _ecore_evas_wince_free, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_wince_callback_delete_request_set, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_wince_move, + NULL, + _ecore_evas_wince_resize, + _ecore_evas_wince_move_resize, + NULL, //_ecore_evas_wince_rotation_set, + NULL, /* _ecore_evas_x_shaped_set */ + _ecore_evas_wince_show, + _ecore_evas_wince_hide, + NULL, //_ecore_evas_wince_raise, + NULL, //_ecore_evas_wince_lower, + NULL, //_ecore_evas_wince_activate, + _ecore_evas_wince_title_set, + NULL, /* _ecore_evas_x_name_class_set */ + NULL, //_ecore_evas_wince_size_min_set, + NULL, //_ecore_evas_wince_size_max_set, + NULL, //_ecore_evas_wince_size_base_set, + NULL, //_ecore_evas_wince_size_step_set, + _ecore_evas_wince_cursor_set, + NULL, /* _ecore_evas_x_layer_set */ + _ecore_evas_wince_focus_set, + NULL, //_ecore_evas_wince_iconified_set, + NULL, //_ecore_evas_wince_borderless_set, + NULL, /* _ecore_evas_x_override_set */ + NULL, + _ecore_evas_wince_fullscreen_set, + NULL, /* _ecore_evas_x_avoid_damage_set */ + NULL, /* _ecore_evas_x_withdrawn_set */ + NULL, /* _ecore_evas_x_sticky_set */ + NULL, /* _ecore_evas_x_ignore_events_set */ + NULL, /* _ecore_evas_x_alpha_set */ + NULL, //transparent + NULL, // profiles_set + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + + NULL, // render + NULL, // screen_geometry_get + _ecore_evas_wince_screen_dpi_get +}; + +/* API */ + +static Ecore_Evas * +ecore_evas_software_wince_new_internal(int backend, + Ecore_WinCE_Window *parent, + int x, + int y, + int width, + int height, + int fullscreen) +{ + Evas_Engine_Info_Software_16_WinCE *einfo; + Ecore_Evas *ee; + int rmethod; + + rmethod = evas_render_method_lookup("software_16_wince"); + if (!rmethod) + return NULL; + + if (!ecore_wince_init()) + return NULL; + + ee = calloc(1, sizeof(Ecore_Evas)); + if (!ee) + { + ecore_wince_shutdown(); + return NULL; + } + + ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); + + if (!_ecore_evas_wince_init()) + { + free(ee); + ecore_wince_shutdown(); + return NULL; + } + + ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_wince_engine_func; + + ee->driver = "software_16_wince"; + + if (width < 1) width = 1; + if (height < 1) height = 1; + ee->x = x; + ee->y = y; + ee->w = width; + ee->h = height; + ee->req.x = ee->x; + ee->req.y = ee->y; + ee->req.w = ee->w; + ee->req.h = ee->h; + + ee->prop.max.w = 32767; + ee->prop.max.h = 32767; + ee->prop.layer = 4; + ee->prop.request_pos = 0; + ee->prop.sticky = 0; + /* FIXME: sticky to add */ + + ee->prop.window = (Ecore_Window)ecore_wince_window_new((Ecore_WinCE_Window *)parent, x, y, width, height); + if (!ee->prop.window) + { + _ecore_evas_wince_shutdown(); + free(ee); + ecore_wince_shutdown(); + return NULL; + } + + ecore_wince_window_fullscreen_set((Ecore_WinCE_Window *)ee->prop.window, fullscreen); + + /* init evas here */ + ee->evas = evas_new(); + evas_data_attach_set(ee->evas, ee); + evas_output_method_set(ee->evas, rmethod); + evas_output_size_set(ee->evas, width, height); + evas_output_viewport_set(ee->evas, 0, 0, width, height); + + einfo = (Evas_Engine_Info_Software_16_WinCE *)evas_engine_info_get(ee->evas); + if (einfo) + { + /* FIXME: REDRAW_DEBUG missing for now */ + einfo->info.window = ((struct _Ecore_WinCE_Window *)ee->prop.window)->window; + einfo->info.width = width; + einfo->info.height = height; + einfo->info.backend = backend; + einfo->info.rotation = 0; + einfo->info.fullscreen = fullscreen; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + _ecore_evas_wince_shutdown(); + free(ee); + ecore_wince_shutdown(); + return NULL; + } + + ecore_wince_window_backend_set((Ecore_WinCE_Window *)ee->prop.window, backend); + ecore_wince_window_suspend_cb_set((Ecore_WinCE_Window *)ee->prop.window, einfo->func.suspend); + ecore_wince_window_resume_cb_set((Ecore_WinCE_Window *)ee->prop.window, einfo->func.resume); + } + else + { + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); + _ecore_evas_wince_shutdown(); + free(ee); + ecore_wince_shutdown(); + return NULL; + } + + ee->engine.func->fn_render = _ecore_evas_wince_render; + _ecore_evas_register(ee); + ecore_event_window_register(ee->prop.window, ee, ee->evas, + (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, + (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, + (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, + (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); + evas_focus_in(ee->evas); + + return ee; +} + +#else + +static Ecore_Evas * +ecore_evas_software_wince_new_internal(int backend __UNUSED__, + Ecore_WinCE_Window *parent __UNUSED__, + int x __UNUSED__, + int y __UNUSED__, + int width __UNUSED__, + int height __UNUSED__, + int fullscreen __UNUSED__) +{ + return NULL; +} + +#endif /* BUILD_ECORE_EVAS_SOFTWARE_16_WINCE */ + + +EAPI Ecore_Evas * +ecore_evas_software_wince_new(Ecore_WinCE_Window *parent, + int x, + int y, + int width, + int height) +{ + return ecore_evas_software_wince_new_internal(0, parent, x, y, width, height, 1); +} + +EAPI Ecore_Evas * +ecore_evas_software_wince_fb_new(Ecore_WinCE_Window *parent, + int x, + int y, + int width, + int height) +{ + return ecore_evas_software_wince_new_internal(1, parent, x, y, width, height, 1); +} + +EAPI Ecore_Evas * +ecore_evas_software_wince_gapi_new(Ecore_WinCE_Window *parent, + int x, + int y, + int width, + int height) +{ + return ecore_evas_software_wince_new_internal(2, parent, x, y, width, height, 1); +} + +EAPI Ecore_Evas * +ecore_evas_software_wince_ddraw_new(Ecore_WinCE_Window *parent, + int x, + int y, + int width, + int height) +{ + return ecore_evas_software_wince_new_internal(3, parent, x, y, width, height, 1); +} + +EAPI Ecore_Evas * +ecore_evas_software_wince_gdi_new(Ecore_WinCE_Window *parent, + int x, + int y, + int width, + int height) +{ + return ecore_evas_software_wince_new_internal(4, parent, x, y, width, height, 0); +} + +#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_WINCE + +EAPI Ecore_WinCE_Window * +ecore_evas_software_wince_window_get(const Ecore_Evas *ee) +{ + return (Ecore_WinCE_Window *) ecore_evas_window_get(ee); +} + +#else + +EAPI Ecore_WinCE_Window * +ecore_evas_software_wince_window_get(const Ecore_Evas *ee __UNUSED__) +{ + return NULL; +} + +#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_16_WINCE */ diff --git a/src/lib/ecore_evas/ecore_evas_x.c b/src/lib/ecore_evas/ecore_evas_x.c new file mode 100644 index 0000000..bb95525 --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas_x.c @@ -0,0 +1,4653 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include +#include + +#include "ecore_evas_private.h" +#include "Ecore_Evas.h" + +#ifdef BUILD_ECORE_EVAS_X11 +static int _ecore_evas_init_count = 0; + +static Ecore_Event_Handler *ecore_evas_event_handlers[13]; + +static int leader_ref = 0; +static Ecore_X_Window leader_win = 0; + +static void +_ecore_evas_x_hints_update(Ecore_Evas *ee) +{ + ecore_x_icccm_hints_set + (ee->prop.window, + !ee->prop.focus_skip /* accepts_focus */, + ee->prop.iconified ? ECORE_X_WINDOW_STATE_HINT_ICONIC : + ee->prop.withdrawn ? ECORE_X_WINDOW_STATE_HINT_WITHDRAWN : + ECORE_X_WINDOW_STATE_HINT_NORMAL /* initial_state */, + 0 /* icon_pixmap */, + 0 /* icon_mask */, + 0 /* icon_window */, + ee->prop.group_ee_win /* window_group */, + ee->prop.urgent /* is_urgent */); +} + +static void +_ecore_evas_x_group_leader_set(Ecore_Evas *ee) +{ + leader_ref++; + if (leader_ref == 1) + { + char *id = NULL; + + leader_win = + ecore_x_window_override_new(ee->engine.x.win_root, 1234, 5678, 1, 2); + ecore_x_window_defaults_set(leader_win); + if ((id = getenv("DESKTOP_STARTUP_ID"))) + ecore_x_netwm_startup_id_set(leader_win,id); + ecore_x_icccm_client_leader_set(leader_win, leader_win); + } + ee->engine.x.leader = leader_win; + ecore_x_icccm_client_leader_set(ee->prop.window, leader_win); +} + +static void +_ecore_evas_x_group_leader_unset(Ecore_Evas *ee) +{ + ecore_x_window_prop_property_del(ee->prop.window, + ECORE_X_ATOM_WM_CLIENT_LEADER); + if (ee->engine.x.leader == leader_win) + { + leader_ref--; + if (leader_ref <= 0) + { + ecore_x_window_free(leader_win); + leader_win = 0; + } + ee->engine.x.leader = 0; + } +} + +static void +_ecore_evas_x_group_leader_update(Ecore_Evas *ee) +{ + if (ee->engine.x.leader) + ecore_x_icccm_client_leader_set(ee->prop.window, ee->engine.x.leader); +} + +static void +_ecore_evas_x_protocols_set(Ecore_Evas *ee) +{ + Ecore_X_Atom protos[3]; + unsigned int num = 0, tmp = 0; + + if (ee->func.fn_delete_request) + protos[num++] = ECORE_X_ATOM_WM_DELETE_WINDOW; + protos[num++] = ECORE_X_ATOM_NET_WM_PING; + protos[num++] = ECORE_X_ATOM_NET_WM_SYNC_REQUEST; + ecore_x_icccm_protocol_atoms_set(ee->prop.window, protos, num); + + if (!ee->engine.x.netwm_sync_counter) + ee->engine.x.netwm_sync_counter = ecore_x_sync_counter_new(0); + + tmp = ee->engine.x.netwm_sync_counter; + ecore_x_window_prop_card32_set(ee->prop.window, + ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER, + &tmp, 1); +} + +static void +_ecore_evas_x_sync_set(Ecore_Evas *ee) +{ + Ecore_X_Sync_Counter sync_counter = ee->engine.x.sync_counter; + + if (((ee->should_be_visible) || (ee->visible)) && + ((ecore_x_e_comp_sync_supported_get(ee->engine.x.win_root)) && + (!ee->no_comp_sync) && (_ecore_evas_app_comp_sync))) + { + if (!ee->engine.x.sync_counter) + ee->engine.x.sync_counter = ecore_x_sync_counter_new(0); + } + else + { + if (ee->engine.x.sync_counter) + { + ecore_x_sync_counter_free(ee->engine.x.sync_counter); + ee->engine.x.sync_val = 0; + } + ee->engine.x.sync_counter = 0; + } + if (sync_counter != ee->engine.x.sync_counter) + ecore_x_e_comp_sync_counter_set(ee->prop.window, ee->engine.x.sync_counter); +} + +static void +_ecore_evas_x_sync_clear(Ecore_Evas *ee) +{ + if (!ee->engine.x.sync_counter) return; + ecore_x_sync_counter_free(ee->engine.x.sync_counter); + ee->engine.x.sync_val = 0; + ee->engine.x.sync_counter = 0; +} + +# ifdef BUILD_ECORE_EVAS_OPENGL_X11 +static Ecore_X_Window +_ecore_evas_x_gl_window_new(Ecore_Evas *ee, Ecore_X_Window parent, int x, int y, int w, int h, int override, int argb, const int *opt) +{ + Evas_Engine_Info_GL_X11 *einfo; + Ecore_X_Window win; + + einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas); + if (einfo) + { + int screen; + + if (opt) + { + int op; + + for (op = 0; opt[op]; op++) + { + if (opt[op] == ECORE_EVAS_GL_X11_OPT_INDIRECT) + { + op++; + einfo->indirect = opt[op]; + } + else if (opt[op] == ECORE_EVAS_GL_X11_OPT_VSYNC) + { + op++; + einfo->vsync = opt[op]; + } + } + } + + /* FIXME: this is inefficient as its 1 or more round trips */ + screen = ecore_x_screen_index_get(ecore_x_default_screen_get()); + if (ecore_x_screen_count_get() > 1) + { + Ecore_X_Window *roots; + int num, i; + + num = 0; + roots = ecore_x_window_root_list(&num); + if (roots) + { + Ecore_X_Window root; + + root = ecore_x_window_root_get(parent); + for (i = 0; i < num; i++) + { + if (root == roots[i]) + { + screen = i; + break; + } + } + free(roots); + } + } + + einfo->info.display = ecore_x_display_get(); + einfo->info.screen = screen; + + einfo->info.destination_alpha = argb; + + einfo->info.visual = einfo->func.best_visual_get(einfo); + einfo->info.colormap = einfo->func.best_colormap_get(einfo); + einfo->info.depth = einfo->func.best_depth_get(einfo); + + if ((!einfo->info.visual) || + (!einfo->info.colormap) || (!einfo->info.depth)) + { + WRN("OpenGL X11 init engine '%s' failed - no visual, colormap or depth.", ee->driver); + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + return 0; + } + } + + if (argb) + { + if (override) + win = ecore_x_window_override_argb_new(parent, x, y, w, h); + else + win = ecore_x_window_argb_new(parent, x, y, w, h); + } + else + { + if (override) + win = ecore_x_window_override_new(parent, x, y, w, h); + else + win = ecore_x_window_new(parent, x, y, w, h); + } + + ecore_x_window_pixel_gravity_set(win, ECORE_X_GRAVITY_FORGET); + + /* attr.backing_store = NotUseful; */ + /* attr.override_redirect = override; */ + /* attr.colormap = einfo->info.colormap; */ + /* attr.border_pixel = 0; */ + /* attr.background_pixmap = None; */ + /* attr.event_mask = */ + /* KeyPressMask | KeyReleaseMask | */ + /* ExposureMask | ButtonPressMask | ButtonReleaseMask | */ + /* EnterWindowMask | LeaveWindowMask | */ + /* PointerMotionMask | StructureNotifyMask | VisibilityChangeMask | */ + /* FocusChangeMask | PropertyChangeMask | ColormapChangeMask; */ + /* attr.bit_gravity = ForgetGravity; */ + + /* win = */ + /* XCreateWindow(einfo->info.display, parent, x, y, w, h, 0, */ + /* einfo->info.depth, InputOutput, einfo->info.visual, */ + /* CWBackingStore | CWColormap | CWBackPixmap | */ + /* CWBorderPixel | CWBitGravity | CWEventMask | */ + /* CWOverrideRedirect, &attr); */ + + einfo->info.drawable = win; + + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + ecore_x_window_free(win); + return 0; + } + } + else + win = 0; + + return win; +} +#endif + +static int +_ecore_evas_x_render(Ecore_Evas *ee) +{ + int rend = 0; + Eina_List *updates = NULL; + Eina_List *ll; + Ecore_Evas *ee2; + + if ((!ee->no_comp_sync) && (_ecore_evas_app_comp_sync) && + (ee->engine.x.sync_counter) && (!ee->engine.x.sync_began) && + (!ee->engine.x.sync_cancel)) + return 0; + + EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2) + { + if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2); + if (ee2->engine.func->fn_render) + rend |= ee2->engine.func->fn_render(ee2); + if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2); + } + + if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee); + updates = evas_render_updates(ee->evas); + if (ee->prop.avoid_damage) + { + if (ee->engine.x.using_bg_pixmap) + { + if (updates) + { + Eina_List *l = NULL; + Eina_Rectangle *r; + + EINA_LIST_FOREACH(updates, l, r) + ecore_x_window_area_clear(ee->prop.window, + r->x, r->y, r->w, r->h); + if (ee->shaped) + { + ecore_x_window_shape_mask_set(ee->prop.window, + ee->engine.x.mask); + } + if (ee->alpha) + { +// ecore_x_window_shape_input_mask_set(ee->prop.window, ee->engine.x.mask); + } + _ecore_evas_idle_timeout_update(ee); + rend = 1; + } + } + else + { + if (updates) + { + Eina_List *l = NULL; + Eina_Rectangle *r; + + EINA_LIST_FOREACH(updates, l, r) + { + Ecore_X_Rectangle rect; + Ecore_X_XRegion *tmpr; + + if (!ee->engine.x.damages) + ee->engine.x.damages = ecore_x_xregion_new(); + tmpr = ecore_x_xregion_new(); + if (ee->rotation == 0) + { + rect.x = r->x; + rect.y = r->y; + rect.width = r->w; + rect.height = r->h; + } + else if (ee->rotation == 90) + { + rect.x = r->y; + rect.y = ee->h - r->x - r->w; + rect.width = r->h; + rect.height = r->w; + } + else if (ee->rotation == 180) + { + rect.x = ee->w - r->x - r->w; + rect.y = ee->h - r->y - r->h; + rect.width = r->w; + rect.height = r->h; + } + else if (ee->rotation == 270) + { + rect.x = ee->w - r->y - r->h; + rect.y = r->x; + rect.width = r->h; + rect.height = r->w; + } + ecore_x_xregion_union_rect(tmpr, ee->engine.x.damages, + &rect); + ecore_x_xregion_free(ee->engine.x.damages); + ee->engine.x.damages = tmpr; + } + if (ee->engine.x.damages) + { + if (ee->shaped) + { + + /* if we have a damage pixmap - we can avoid exposures by + * disabling them just for setting the mask */ + ecore_x_event_mask_unset(ee->prop.window, ECORE_X_EVENT_MASK_WINDOW_DAMAGE); + ecore_x_window_shape_mask_set(ee->prop.window, + ee->engine.x.mask); + /* and re-enable them again */ + ecore_x_event_mask_set(ee->prop.window, ECORE_X_EVENT_MASK_WINDOW_DAMAGE); + } + ecore_x_xregion_set(ee->engine.x.damages, ee->engine.x.gc); + ecore_x_pixmap_paste(ee->engine.x.pmap, ee->prop.window, + ee->engine.x.gc, 0, 0, ee->w, ee->h, + 0, 0); + ecore_x_xregion_free(ee->engine.x.damages); + ee->engine.x.damages = NULL; + } + _ecore_evas_idle_timeout_update(ee); + rend = 1; + } + } + } + else if (((ee->visible) && (ee->draw_ok)) || + ((ee->should_be_visible) && (ee->prop.fullscreen)) || + ((ee->should_be_visible) && (ee->prop.override))) + { + if (updates) + { + if (ee->shaped) + { + ecore_x_window_shape_mask_set(ee->prop.window, + ee->engine.x.mask); + } + if (ee->alpha) + { +// ecore_x_window_shape_input_mask_set(ee->prop.window, ee->engine.x.mask); + } + _ecore_evas_idle_timeout_update(ee); + rend = 1; + } + } + else + evas_norender(ee->evas); + evas_render_updates_free(updates); + + if (ee->func.fn_post_render) ee->func.fn_post_render(ee); +/* + if (rend) + { + static int frames = 0; + static double t0 = 0.0; + double t, td; + + t = ecore_time_get(); + frames++; + if ((t - t0) > 1.0) + { + td = t - t0; + printf("FPS: %3.3f\n", (double)frames / td); + frames = 0; + t0 = t; + } + } + */ + + return rend; +} + +static void +_ecore_evas_x_resize_shape(Ecore_Evas *ee) +{ + if (!strcmp(ee->driver, "software_x11")) + { +#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 + Evas_Engine_Info_Software_X11 *einfo; + + einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas); + if (einfo) + { + unsigned int foreground; + Ecore_X_GC gc; + + if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask); + ee->engine.x.mask = ecore_x_pixmap_new(ee->prop.window, ee->w, ee->h, 1); + foreground = 0; + gc = ecore_x_gc_new(ee->engine.x.mask, + ECORE_X_GC_VALUE_MASK_FOREGROUND, + &foreground); + ecore_x_drawable_rectangle_fill(ee->engine.x.mask, gc, + 0, 0, ee->w, ee->h); + ecore_x_gc_free(gc); + einfo->info.mask = ee->engine.x.mask; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + } +#endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */ + } + else if (!strcmp(ee->driver, "software_16_x11")) + { +#if BUILD_ECORE_EVAS_SOFTWARE_16_X11 +# if 0 /* XXX no shaped window support for software_16_x11 */ + Evas_Engine_Info_Software_16_X11 *einfo; + + einfo = (Evas_Engine_Info_Software_16_X11 *)evas_engine_info_get(ee->evas); + if (einfo) + { + if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask); + ee->engine.x.mask = ecore_x_pixmap_new(ee->prop.window, ee->w, ee->h, 1); + einfo->info.mask = ee->engine.x.mask; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + } +# endif /* XXX no shaped window support for software_16_x11 */ +#endif /* BUILD_ECORE_EVAS_SOFTWARE_16_X11 */ + } + if (!strcmp(ee->driver, "software_8_x11")) + { +#if defined (BUILD_ECORE_EVAS_SOFTWARE_8_X11) + Evas_Engine_Info_Software_8_X11 *einfo; + + einfo = (Evas_Engine_Info_Software_8_X11 *)evas_engine_info_get(ee->evas); + if (einfo) + { + unsigned int foreground; + Ecore_X_GC gc; + + if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask); + ee->engine.x.mask = ecore_x_pixmap_new(ee->prop.window, ee->w, ee->h, 1); + foreground = 0; + gc = ecore_x_gc_new(ee->engine.x.mask, + ECORE_X_GC_VALUE_MASK_FOREGROUND, + &foreground); + ecore_x_drawable_rectangle_fill(ee->engine.x.mask, gc, + 0, 0, ee->w, ee->h); + ecore_x_gc_free(gc); + einfo->info.mask = ee->engine.x.mask; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + } +#endif /* BUILD_ECORE_EVAS_SOFTWARE_8_X11 */ + } +} + +/* TODO: we need to make this work for all the states, not just sticky */ +static Eina_Bool +_ecore_evas_x_event_property_change(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_X_Event_Window_Property *e; + int state_change = 0; + + e = event; + ee = ecore_event_window_match(e->win); + if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; /* pass on event */ + if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; + if (e->atom == ECORE_X_ATOM_NET_WM_STATE) + { + unsigned int i, num; + Ecore_X_Window_State *state; + struct { + struct { + unsigned char modal : 1; + unsigned char sticky : 1; + unsigned char maximized_v : 1; + unsigned char maximized_h : 1; + unsigned char shaded : 1; + unsigned char skip_taskbar : 1; + unsigned char skip_pager : 1; + unsigned char fullscreen : 1; + unsigned char above : 1; + unsigned char below : 1; + } x; + struct { + char modal : 1; + char maximized : 1; + char sticky : 1; + char fullscreen : 1; + char focus_skip : 1; + } prop; + } prev; + + prev.x.modal = ee->engine.x.state.modal; + prev.x.sticky = ee->engine.x.state.sticky; + prev.x.maximized_v = ee->engine.x.state.maximized_v; + prev.x.maximized_h = ee->engine.x.state.maximized_h; + prev.x.shaded = ee->engine.x.state.shaded; + prev.x.skip_taskbar = ee->engine.x.state.skip_taskbar; + prev.x.skip_pager = ee->engine.x.state.skip_pager; + prev.x.fullscreen = ee->engine.x.state.fullscreen; + prev.x.above = ee->engine.x.state.above; + prev.x.below = ee->engine.x.state.below; + + prev.prop.modal = ee->prop.modal; + prev.prop.maximized = ee->prop.maximized; + prev.prop.sticky = ee->prop.sticky; + prev.prop.fullscreen = ee->prop.fullscreen; + prev.prop.focus_skip = ee->prop.focus_skip; + + ee->engine.x.state.modal = 0; + ee->engine.x.state.sticky = 0; + ee->engine.x.state.maximized_v = 0; + ee->engine.x.state.maximized_h = 0; + ee->engine.x.state.shaded = 0; + ee->engine.x.state.skip_taskbar = 0; + ee->engine.x.state.skip_pager = 0; + ee->engine.x.state.fullscreen = 0; + ee->engine.x.state.above = 0; + ee->engine.x.state.below = 0; + + ee->prop.modal = 0; + ee->prop.maximized = 0; + ee->prop.sticky = 0; + ee->prop.fullscreen = 0; + ee->prop.focus_skip = 0; + + ecore_x_netwm_window_state_get(e->win, &state, &num); + if (state) + { + for (i = 0; i < num; i++) + { + switch (state[i]) + { + case ECORE_X_WINDOW_STATE_MODAL: + ee->engine.x.state.modal = 1; + ee->prop.modal = 1; + break; + case ECORE_X_WINDOW_STATE_STICKY: + ee->prop.sticky = 1; + ee->engine.x.state.sticky = 1; + break; + case ECORE_X_WINDOW_STATE_MAXIMIZED_VERT: + ee->engine.x.state.maximized_v = 1; + ee->prop.maximized = 1; + break; + case ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ: + ee->engine.x.state.maximized_h = 1; + ee->prop.maximized = 1; + break; + case ECORE_X_WINDOW_STATE_SHADED: + ee->engine.x.state.shaded = 1; + break; + case ECORE_X_WINDOW_STATE_SKIP_TASKBAR: + ee->engine.x.state.skip_taskbar = 1; + ee->prop.focus_skip = 1; + break; + case ECORE_X_WINDOW_STATE_SKIP_PAGER: + ee->engine.x.state.skip_pager = 1; + ee->prop.focus_skip = 1; + break; + case ECORE_X_WINDOW_STATE_FULLSCREEN: + ee->prop.fullscreen = 1; + ee->engine.x.state.fullscreen = 1; + break; + case ECORE_X_WINDOW_STATE_ABOVE: + ee->engine.x.state.above = 1; + break; + case ECORE_X_WINDOW_STATE_BELOW: + ee->engine.x.state.below = 1; + break; + default: + break; + } + } + free(state); + } + if ( +// (prev.x.modal != ee->engine.x.state.modal) || + (prev.x.sticky != ee->engine.x.state.sticky) || + (prev.x.maximized_v != ee->engine.x.state.maximized_v) || + (prev.x.maximized_h != ee->engine.x.state.maximized_h) || +// (prev.x.shaded != ee->engine.x.state.shaded) || +// (prev.x.skip_taskbar != ee->engine.x.state.skip_taskbar) || +// (prev.x.skip_pager != ee->engine.x.state.skip_pager) || + (prev.x.fullscreen != ee->engine.x.state.fullscreen) || +// (prev.x.above != ee->engine.x.state.above) || +// (prev.x.below != ee->engine.x.state.below) || +// (prev.prop.modal != ee->prop.modal) || + (prev.prop.maximized != ee->prop.maximized) || + (prev.prop.sticky != ee->prop.sticky) || + (prev.prop.fullscreen != ee->prop.fullscreen) || + (prev.prop.focus_skip != ee->prop.focus_skip)) + state_change = 1; + } + else if (e->atom == ECORE_X_ATOM_WM_STATE) + { + Ecore_X_Window_State_Hint state; + + // handle WM_STATE changes + state = ecore_x_icccm_state_get(e->win); + switch (state) + { + case ECORE_X_WINDOW_STATE_HINT_WITHDRAWN: + if ((!ee->prop.withdrawn) || (ee->prop.iconified)) + { + state_change = 1; + ee->prop.withdrawn = 1; + ee->prop.iconified = 0; + } + break; + case ECORE_X_WINDOW_STATE_HINT_ICONIC: + if ((!ee->prop.iconified) || (ee->prop.withdrawn)) + { + state_change = 1; + ee->prop.iconified = 1; + ee->prop.withdrawn = 0; + } + break; + case ECORE_X_WINDOW_STATE_HINT_NORMAL: + if ((ee->prop.iconified) || (ee->prop.withdrawn)) + { + state_change = 1; + ee->prop.iconified = 0; + ee->prop.withdrawn = 0; + } + break; + default: + break; + } + } + else if (e->atom == ECORE_X_ATOM_E_PROFILE) + { + char *p = ecore_x_e_window_profile_get(e->win); + if ((p) && (ee->prop.profile)) + { + if (strcmp(p, ee->prop.profile) != 0) + { + free(ee->prop.profile); + ee->prop.profile = strdup(p); + state_change = 1; + } + } + else if ((!p) && (ee->prop.profile)) + { + free(ee->prop.profile); + ee->prop.profile = NULL; + state_change = 1; + } + else if ((p) && (!ee->prop.profile)) + { + ee->prop.profile = strdup(p); + state_change = 1; + } + + if (p) + free(p); + } + + if (state_change) + { + if (ee->func.fn_state_change) ee->func.fn_state_change(ee); + } + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_x_event_visibility_change(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_X_Event_Window_Visibility_Change *e; + + e = event; + ee = ecore_event_window_match(e->win); + if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */ + if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; +// printf("VIS CHANGE OBSCURED: %p %i\n", ee, e->fully_obscured); + if (e->fully_obscured) + { + /* FIXME: round trip */ + if (!ecore_x_screen_is_composited(ee->engine.x.screen_num)) + ee->draw_ok = 0; + } + else + ee->draw_ok = 1; + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_x_event_client_message(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_X_Event_Client_Message *e; + + e = event; + if (e->format != 32) return ECORE_CALLBACK_PASS_ON; + if (e->message_type == ECORE_X_ATOM_E_COMP_SYNC_BEGIN) + { + ee = ecore_event_window_match(e->data.l[0]); + if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */ + if (e->data.l[0] != (long)ee->prop.window) + return ECORE_CALLBACK_PASS_ON; + if (!ee->engine.x.sync_began) + { + // qeue a damage + draw. work around an event re-ordering thing. + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + } + ee->engine.x.sync_began = 1; + ee->engine.x.sync_cancel = 0; + } + else if (e->message_type == ECORE_X_ATOM_E_COMP_SYNC_END) + { + ee = ecore_event_window_match(e->data.l[0]); + if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */ + if (e->data.l[0] != (long)ee->prop.window) + return ECORE_CALLBACK_PASS_ON; + ee->engine.x.sync_began = 0; + ee->engine.x.sync_cancel = 0; + } + else if (e->message_type == ECORE_X_ATOM_E_COMP_SYNC_CANCEL) + { + ee = ecore_event_window_match(e->data.l[0]); + if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */ + if (e->data.l[0] != (long)ee->prop.window) + return ECORE_CALLBACK_PASS_ON; + ee->engine.x.sync_began = 0; + ee->engine.x.sync_cancel = 1; + } + else if ((e->message_type == ECORE_X_ATOM_WM_PROTOCOLS) && + (e->data.l[0] == (int)ECORE_X_ATOM_NET_WM_SYNC_REQUEST)) + { + ee = ecore_event_window_match(e->win); + if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */ + ee->engine.x.netwm_sync_val_lo = (unsigned int)e->data.l[2]; + ee->engine.x.netwm_sync_val_hi = (int)e->data.l[3]; + ee->engine.x.netwm_sync_set = 1; + } + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_x_event_mouse_in(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_X_Event_Mouse_In *e; + + e = event; + ee = ecore_event_window_match(e->win); + if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; /* pass on event */ + if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; +/* { */ +/* time_t t; */ +/* char *ct; */ + +/* const char *modes[] = { */ +/* "MODE_NORMAL", */ +/* "MODE_WHILE_GRABBED", */ +/* "MODE_GRAB", */ +/* "MODE_UNGRAB" */ +/* }; */ +/* const char *details[] = { */ +/* "DETAIL_ANCESTOR", */ +/* "DETAIL_VIRTUAL", */ +/* "DETAIL_INFERIOR", */ +/* "DETAIL_NON_LINEAR", */ +/* "DETAIL_NON_LINEAR_VIRTUAL", */ +/* "DETAIL_POINTER", */ +/* "DETAIL_POINTER_ROOT", */ +/* "DETAIL_DETAIL_NONE" */ +/* }; */ +/* t = time(NULL); */ +/* ct = ctime(&t); */ +/* ct[strlen(ct) - 1] = 0; */ +/* printf("@@ ->IN 0x%x 0x%x %s md=%s dt=%s\n", */ +/* e->win, e->event_win, */ +/* ct, */ +/* modes[e->mode], */ +/* details[e->detail]); */ +/* } */ + // disable. causes more problems than it fixes + // if ((e->mode == ECORE_X_EVENT_MODE_GRAB) || + // (e->mode == ECORE_X_EVENT_MODE_UNGRAB)) + // return 0; + /* if (e->mode != ECORE_X_EVENT_MODE_NORMAL) return 0; */ + if (!ee->in) + { + if (ee->func.fn_mouse_in) ee->func.fn_mouse_in(ee); + ecore_event_evas_modifier_lock_update(ee->evas, e->modifiers); + evas_event_feed_mouse_in(ee->evas, e->time, NULL); + _ecore_evas_mouse_move_process(ee, e->x, e->y, e->time); + ee->in = EINA_TRUE; + } + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_x_event_mouse_out(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_X_Event_Mouse_Out *e; + + e = event; + ee = ecore_event_window_match(e->win); + if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; + /* pass on event */ + if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; +/* { */ +/* time_t t; */ +/* char *ct; */ + +/* const char *modes[] = { */ +/* "MODE_NORMAL", */ +/* "MODE_WHILE_GRABBED", */ +/* "MODE_GRAB", */ +/* "MODE_UNGRAB" */ +/* }; */ +/* const char *details[] = { */ +/* "DETAIL_ANCESTOR", */ +/* "DETAIL_VIRTUAL", */ +/* "DETAIL_INFERIOR", */ +/* "DETAIL_NON_LINEAR", */ +/* "DETAIL_NON_LINEAR_VIRTUAL", */ +/* "DETAIL_POINTER", */ +/* "DETAIL_POINTER_ROOT", */ +/* "DETAIL_DETAIL_NONE" */ +/* }; */ +/* t = time(NULL); */ +/* ct = ctime(&t); */ +/* ct[strlen(ct) - 1] = 0; */ +/* printf("@@ ->OUT 0x%x 0x%x %s md=%s dt=%s\n", */ +/* e->win, e->event_win, */ +/* ct, */ +/* modes[e->mode], */ +/* details[e->detail]); */ +/* } */ + // disable. causes more problems than it fixes + // if ((e->mode == ECORE_X_EVENT_MODE_GRAB) || + // (e->mode == ECORE_X_EVENT_MODE_UNGRAB)) + // return 0; + /* if (e->mode != ECORE_X_EVENT_MODE_NORMAL) return 0; */ +// printf("OUT: ee->in=%i, e->mode=%i, e->detail=%i, dount_count=%i\n", +// ee->in, e->mode, e->detail, evas_event_down_count_get(ee->evas)); + if (ee->in) + { + if ((evas_event_down_count_get(ee->evas) > 0) && + (!((e->mode == ECORE_X_EVENT_MODE_GRAB) && + (e->detail == ECORE_X_EVENT_DETAIL_NON_LINEAR)))) + return ECORE_CALLBACK_PASS_ON; + ecore_event_evas_modifier_lock_update(ee->evas, e->modifiers); + _ecore_evas_mouse_move_process(ee, e->x, e->y, e->time); + if (e->mode == ECORE_X_EVENT_MODE_GRAB) + evas_event_feed_mouse_cancel(ee->evas, e->time, NULL); + evas_event_feed_mouse_out(ee->evas, e->time, NULL); + if (ee->func.fn_mouse_out) ee->func.fn_mouse_out(ee); + if (ee->prop.cursor.object) evas_object_hide(ee->prop.cursor.object); + ee->in = EINA_FALSE; + } + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_x_event_window_focus_in(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_X_Event_Window_Focus_In *e; + + e = event; + ee = ecore_event_window_match(e->win); + if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; /* pass on event */ + if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; +//xx// filtering with these doesnt help +//xx// if (e->mode == ECORE_X_EVENT_MODE_UNGRAB) return ECORE_CALLBACK_PASS_ON; + ee->prop.focused = 1; + evas_focus_in(ee->evas); + if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_x_event_window_focus_out(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_X_Event_Window_Focus_Out *e; + + e = event; + ee = ecore_event_window_match(e->win); + if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; /* pass on event */ + if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; +//xx// filtering with these doesnt help +//xx// if (e->mode == ECORE_X_EVENT_MODE_GRAB) return ECORE_CALLBACK_PASS_ON; + +// if (ee->prop.fullscreen) +// ecore_x_window_focus(ee->prop.window); + evas_focus_out(ee->evas); + ee->prop.focused = 0; + if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_x_event_window_damage(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_X_Event_Window_Damage *e; + + e = event; + ee = ecore_event_window_match(e->win); + if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */ + if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; + if (ee->engine.x.using_bg_pixmap) return ECORE_CALLBACK_PASS_ON; +// printf("EXPOSE %p [%i] %i %i %ix%i\n", ee, ee->prop.avoid_damage, e->x, e->y, e->w, e->h); + if (ee->prop.avoid_damage) + { + Ecore_X_Rectangle rect; + Ecore_X_XRegion *tmpr; + + if (!ee->engine.x.damages) + ee->engine.x.damages = ecore_x_xregion_new(); + tmpr = ecore_x_xregion_new(); + rect.x = e->x; + rect.y = e->y; + rect.width = e->w; + rect.height = e->h; + ecore_x_xregion_union_rect(tmpr, ee->engine.x.damages, &rect); + ecore_x_xregion_free(ee->engine.x.damages); + ee->engine.x.damages = tmpr; +/* no - this breaks things badly. disable. Ecore_X_Rectangle != XRectangle - see + * the typedefs in x's headers and ecore_x's. also same with Region - it's a pointer in x - not an X ID + Ecore_X_Rectangle rect; + Ecore_X_XRegion *tmpr; + + if (!ee->engine.x.damages) ee->engine.x.damages = ecore_x_xregion_new(); + tmpr = ecore_x_xregion_new(); + rect.x = e->x; + rect.y = e->y; + rect.width = e->w; + rect.height = e->h; + ecore_x_xregion_union_rect(tmpr, ee->engine.x.damages, &rect); + ecore_x_xregion_free(ee->engine.x.damages); + ee->engine.x.damages = tmpr; + */ + } + else + { + if (ee->rotation == 0) + evas_damage_rectangle_add(ee->evas, e->x, e->y, e->w, e->h); + else if (ee->rotation == 90) + evas_damage_rectangle_add(ee->evas, + ee->h - e->y - e->h, e->x, e->h, e->w); + else if (ee->rotation == 180) + evas_damage_rectangle_add(ee->evas, ee->w - e->x - e->w, + ee->h - e->y - e->h, e->w, e->h); + else if (ee->rotation == 270) + evas_damage_rectangle_add(ee->evas, e->y, ee->w - e->x - e->w, + e->h, e->w); + } + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_x_event_window_destroy(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_X_Event_Window_Destroy *e; + + e = event; + ee = ecore_event_window_match(e->win); + if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */ + if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; + if (ee->func.fn_destroy) ee->func.fn_destroy(ee); + _ecore_evas_x_sync_clear(ee); + ecore_evas_free(ee); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_x_event_window_configure(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_X_Event_Window_Configure *e; + + e = event; + ee = ecore_event_window_match(e->win); + if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */ + if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; + if (ee->engine.x.direct_resize) return ECORE_CALLBACK_PASS_ON; + + ee->engine.x.configure_coming = 0; + if ((e->from_wm) || (ee->prop.override)) + { + if ((ee->x != e->x) || (ee->y != e->y)) + { + ee->x = e->x; + ee->y = e->y; + ee->req.x = ee->x; + ee->req.y = ee->y; + if (ee->func.fn_move) ee->func.fn_move(ee); + } + } + if ((ee->w != e->w) || (ee->h != e->h)) + { + ee->w = e->w; + ee->h = e->h; + ee->req.w = ee->w; + ee->req.h = ee->h; + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + evas_output_size_set(ee->evas, ee->h, ee->w); + evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w); + } + else + { + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + } + if (ee->prop.avoid_damage) + { + int pdam; + + pdam = ecore_evas_avoid_damage_get(ee); + ecore_evas_avoid_damage_set(ee, 0); + ecore_evas_avoid_damage_set(ee, pdam); + } + if ((ee->shaped) || (ee->alpha)) + _ecore_evas_x_resize_shape(ee); + if ((ee->expecting_resize.w > 0) && (ee->expecting_resize.h > 0)) + { + if ((ee->expecting_resize.w == ee->w) && + (ee->expecting_resize.h == ee->h)) + _ecore_evas_mouse_move_process(ee, ee->mouse.x, ee->mouse.y, + ecore_x_current_time_get()); + ee->expecting_resize.w = 0; + ee->expecting_resize.h = 0; + } + if (ee->func.fn_resize) ee->func.fn_resize(ee); + } + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_x_event_window_delete_request(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_X_Event_Window_Delete_Request *e; + + e = event; + ee = ecore_event_window_match(e->win); + if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */ + if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; + if (ee->func.fn_delete_request) ee->func.fn_delete_request(ee); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_x_event_window_show(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_X_Event_Window_Show *e; + static int first_map_bug = -1; + + e = event; + ee = ecore_event_window_match(e->win); + if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */ + if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; + /* some GL drivers are doing buffer copy in a separate thread. + * we need to check whether GL driver sends SYNC_DRAW_DONE msg afger copying + * that are required in order to exactly render. - added by gl77.lee + */ + if (ee->gl_sync_draw_done < 0) + { + if (getenv("ECORE_EVAS_GL_SYNC_DRAW_DONE")) + ee->gl_sync_draw_done = atoi(getenv("ECORE_EVAS_GL_SYNC_DRAW_DONE")); + else + ee->gl_sync_draw_done = 0; + } + if (first_map_bug < 0) + { + char *bug = NULL; + + if ((bug = getenv("ECORE_EVAS_GL_FIRST_MAP_BUG"))) + first_map_bug = atoi(bug); + else + first_map_bug = 0; + } + if ((first_map_bug) && (!strcmp(ee->driver, "opengl_x11"))) + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + if (ee->visible) return ECORE_CALLBACK_PASS_ON; +// if (ee->visible) return ECORE_CALLBACK_DONE; +// printf("SHOW EVENT %p\n", ee); + ee->visible = 1; + if (ee->func.fn_show) ee->func.fn_show(ee); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_x_event_window_hide(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_X_Event_Window_Hide *e; + + e = event; + ee = ecore_event_window_match(e->win); + if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */ + if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON; + if (ee->in) + { + evas_event_feed_mouse_cancel(ee->evas, e->time, NULL); + evas_event_feed_mouse_out(ee->evas, e->time, NULL); + if (ee->func.fn_mouse_out) ee->func.fn_mouse_out(ee); + if (ee->prop.cursor.object) evas_object_hide(ee->prop.cursor.object); + ee->in = EINA_FALSE; + } + if (!ee->visible) return ECORE_CALLBACK_PASS_ON; +// if (!ee->visible) return ECORE_CALLBACK_DONE; +// printf("HIDE EVENT %p\n", ee); + ee->visible = 0; + if (ee->func.fn_hide) ee->func.fn_hide(ee); + return ECORE_CALLBACK_PASS_ON; +} + +/* FIXME, should be in idler */ +/* FIXME, round trip */ +static void +_ecore_evas_x_size_pos_hints_update(Ecore_Evas *ee) +{ + ecore_x_icccm_size_pos_hints_set(ee->prop.window, + ee->prop.request_pos /*request_pos */, + ECORE_X_GRAVITY_NW /* gravity */, + ee->prop.min.w /* min_w */, + ee->prop.min.h /* min_h */, + ee->prop.max.w /* max_w */, + ee->prop.max.h /* max_h */, + ee->prop.base.w /* base_w */, + ee->prop.base.h /* base_h */, + ee->prop.step.w /* step_x */, + ee->prop.step.h /* step_y */, + ee->prop.aspect /* min_aspect */, + ee->prop.aspect /* max_aspect */); +} + +/* FIXME, should be in idler */ +static void +_ecore_evas_x_state_update(Ecore_Evas *ee) +{ + Ecore_X_Window_State state[10]; + int num = 0; + + if (ee->prop.modal) + state[num++] = ECORE_X_WINDOW_STATE_MODAL; + if (ee->prop.sticky) + state[num++] = ECORE_X_WINDOW_STATE_STICKY; + if (ee->prop.maximized) + state[num++] = ECORE_X_WINDOW_STATE_MAXIMIZED_VERT; + if (ee->prop.maximized) + state[num++] = ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ; +// if (bd->client.netwm.state.shaded) +// state[num++] = ECORE_X_WINDOW_STATE_SHADED; + if (ee->prop.focus_skip) + state[num++] = ECORE_X_WINDOW_STATE_SKIP_TASKBAR; + if (ee->prop.focus_skip) + state[num++] = ECORE_X_WINDOW_STATE_SKIP_PAGER; +// if (bd->client.netwm.state.hidden) +// state[num++] = ECORE_X_WINDOW_STATE_HIDDEN; + if (ee->engine.x.state.fullscreen) + state[num++] = ECORE_X_WINDOW_STATE_FULLSCREEN; + if (ee->engine.x.state.above) + state[num++] = ECORE_X_WINDOW_STATE_ABOVE; + if (ee->engine.x.state.below) + state[num++] = ECORE_X_WINDOW_STATE_BELOW; + if (ee->prop.demand_attention) + state[num++] = ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION; + + ecore_x_netwm_window_state_set(ee->prop.window, state, num); +} + +static void +_ecore_evas_x_layer_update(Ecore_Evas *ee) +{ + if (ee->should_be_visible) + { + /* We need to send a netwm request to the wm */ + /* FIXME: Do we have to remove old state before adding new? */ + if (ee->prop.layer < 3) + { + if (ee->engine.x.state.above) + { + ee->engine.x.state.above = 0; + ecore_x_netwm_state_request_send(ee->prop.window, + ee->engine.x.win_root, + ECORE_X_WINDOW_STATE_ABOVE, -1, 0); + } + if (!ee->engine.x.state.below) + { + ee->engine.x.state.below = 1; + ecore_x_netwm_state_request_send(ee->prop.window, + ee->engine.x.win_root, + ECORE_X_WINDOW_STATE_BELOW, -1, 1); + } + } + else if (ee->prop.layer > 5) + { + if (ee->engine.x.state.below) + { + ee->engine.x.state.below = 0; + ecore_x_netwm_state_request_send(ee->prop.window, + ee->engine.x.win_root, + ECORE_X_WINDOW_STATE_BELOW, -1, 0); + } + if (!ee->engine.x.state.above) + { + ee->engine.x.state.above = 1; + ecore_x_netwm_state_request_send(ee->prop.window, + ee->engine.x.win_root, + ECORE_X_WINDOW_STATE_ABOVE, -1, 1); + } + } + else + { + if (ee->engine.x.state.below) + { + ee->engine.x.state.below = 0; + ecore_x_netwm_state_request_send(ee->prop.window, + ee->engine.x.win_root, + ECORE_X_WINDOW_STATE_BELOW, -1, 0); + } + if (ee->engine.x.state.above) + { + ee->engine.x.state.above = 0; + ecore_x_netwm_state_request_send(ee->prop.window, + ee->engine.x.win_root, + ECORE_X_WINDOW_STATE_ABOVE, -1, 0); + } + } + } + else + { + /* Just set the state */ + if (ee->prop.layer < 3) + { + if ((ee->engine.x.state.above) || (!ee->engine.x.state.below)) + { + ee->engine.x.state.above = 0; + ee->engine.x.state.below = 1; + _ecore_evas_x_state_update(ee); + } + } + else if (ee->prop.layer > 5) + { + if ((!ee->engine.x.state.above) || (ee->engine.x.state.below)) + { + ee->engine.x.state.above = 1; + ee->engine.x.state.below = 0; + _ecore_evas_x_state_update(ee); + } + } + else + { + if ((ee->engine.x.state.above) || (ee->engine.x.state.below)) + { + ee->engine.x.state.above = 0; + ee->engine.x.state.below = 0; + _ecore_evas_x_state_update(ee); + } + } + } + /* FIXME: Set gnome layer */ +} + +static int +_ecore_evas_x_init(void) +{ + _ecore_evas_init_count++; + if (_ecore_evas_init_count > 1) return _ecore_evas_init_count; + ecore_evas_event_handlers[0] = + ecore_event_handler_add(ECORE_X_EVENT_MOUSE_IN, + _ecore_evas_x_event_mouse_in, NULL); + ecore_evas_event_handlers[1] = + ecore_event_handler_add(ECORE_X_EVENT_MOUSE_OUT, + _ecore_evas_x_event_mouse_out, NULL); + ecore_evas_event_handlers[2] = + ecore_event_handler_add(ECORE_X_EVENT_WINDOW_FOCUS_IN, + _ecore_evas_x_event_window_focus_in, NULL); + ecore_evas_event_handlers[3] = + ecore_event_handler_add(ECORE_X_EVENT_WINDOW_FOCUS_OUT, + _ecore_evas_x_event_window_focus_out, NULL); + ecore_evas_event_handlers[4] = + ecore_event_handler_add(ECORE_X_EVENT_WINDOW_DAMAGE, + _ecore_evas_x_event_window_damage, NULL); + ecore_evas_event_handlers[5] = + ecore_event_handler_add(ECORE_X_EVENT_WINDOW_DESTROY, + _ecore_evas_x_event_window_destroy, NULL); + ecore_evas_event_handlers[6] = + ecore_event_handler_add(ECORE_X_EVENT_WINDOW_CONFIGURE, + _ecore_evas_x_event_window_configure, NULL); + ecore_evas_event_handlers[7] = + ecore_event_handler_add(ECORE_X_EVENT_WINDOW_DELETE_REQUEST, + _ecore_evas_x_event_window_delete_request, NULL); + ecore_evas_event_handlers[8] = + ecore_event_handler_add(ECORE_X_EVENT_WINDOW_SHOW, + _ecore_evas_x_event_window_show, NULL); + ecore_evas_event_handlers[9] = + ecore_event_handler_add(ECORE_X_EVENT_WINDOW_HIDE, + _ecore_evas_x_event_window_hide, NULL); + ecore_evas_event_handlers[10] = + ecore_event_handler_add(ECORE_X_EVENT_WINDOW_PROPERTY, + _ecore_evas_x_event_property_change, NULL); + ecore_evas_event_handlers[11] = + ecore_event_handler_add(ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE, + _ecore_evas_x_event_visibility_change, NULL); + ecore_evas_event_handlers[12] = + ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE, + _ecore_evas_x_event_client_message, NULL); + ecore_event_evas_init(); + return _ecore_evas_init_count; +} + +static void +_ecore_evas_x_free(Ecore_Evas *ee) +{ + _ecore_evas_x_group_leader_unset(ee); + _ecore_evas_x_sync_set(ee); + if (ee->engine.x.win_shaped_input) + ecore_x_window_free(ee->engine.x.win_shaped_input); + ecore_x_window_free(ee->prop.window); + if (ee->engine.x.pmap) ecore_x_pixmap_free(ee->engine.x.pmap); + if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask); + if (ee->engine.x.gc) ecore_x_gc_free(ee->engine.x.gc); + if (ee->engine.x.damages) ecore_x_xregion_free(ee->engine.x.damages); + ee->engine.x.pmap = 0; + ee->engine.x.mask = 0; + ee->engine.x.gc = 0; + ee->engine.x.damages = NULL; + ecore_event_window_unregister(ee->prop.window); + while (ee->engine.x.win_extra) + { + Ecore_X_Window *winp; + + winp = ee->engine.x.win_extra->data; + ee->engine.x.win_extra = + eina_list_remove_list(ee->engine.x.win_extra, ee->engine.x.win_extra); + ecore_event_window_unregister(*winp); + free(winp); + } + _ecore_evas_x_shutdown(); + ecore_x_shutdown(); +} + +static void +_ecore_evas_x_callback_delete_request_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +{ + ee->func.fn_delete_request = func; + _ecore_evas_x_protocols_set(ee); + _ecore_evas_x_sync_set(ee); +} + +static void +_ecore_evas_x_move(Ecore_Evas *ee, int x, int y) +{ + ee->req.x = x; + ee->req.y = y; + if (ee->engine.x.direct_resize) + { + if (!ee->engine.x.managed) + { + if ((x != ee->x) || (y != ee->y)) + { + ee->x = x; + ee->y = y; + ecore_x_window_move(ee->prop.window, x, y); + if (!ee->should_be_visible) + { + /* We need to request pos */ + ee->prop.request_pos = 1; + _ecore_evas_x_size_pos_hints_update(ee); + } + if (ee->func.fn_move) ee->func.fn_move(ee); + } + } + } + else + { + if (((ee->x != x) || (ee->y != y)) || + (ee->engine.x.configure_coming)) + { + ee->engine.x.configure_coming = 1; + if (!ee->engine.x.managed) + { + ee->x = x; + ee->y = y; + } + ecore_x_window_move(ee->prop.window, x, y); + } + if (!ee->should_be_visible) + { + /* We need to request pos */ + ee->prop.request_pos = 1; + _ecore_evas_x_size_pos_hints_update(ee); + } + } +} + +static void +_ecore_evas_x_managed_move(Ecore_Evas *ee, int x, int y) +{ + ee->req.x = x; + ee->req.y = y; + if (ee->engine.x.direct_resize) + { + ee->engine.x.managed = 1; + if ((x != ee->x) || (y != ee->y)) + { + ee->x = x; + ee->y = y; + if (ee->func.fn_move) ee->func.fn_move(ee); + } + } +} + +static void +_ecore_evas_x_resize(Ecore_Evas *ee, int w, int h) +{ + ee->req.w = w; + ee->req.h = h; + if (ee->engine.x.direct_resize) + { + if ((ee->w != w) || (ee->h != h)) + { + ee->w = w; + ee->h = h; + ecore_x_window_resize(ee->prop.window, w, h); + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + evas_output_size_set(ee->evas, ee->h, ee->w); + evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w); + } + else + { + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + } + if (ee->prop.avoid_damage) + { + int pdam; + + pdam = ecore_evas_avoid_damage_get(ee); + ecore_evas_avoid_damage_set(ee, 0); + ecore_evas_avoid_damage_set(ee, pdam); + } + if ((ee->shaped) || (ee->alpha)) + _ecore_evas_x_resize_shape(ee); + if (ee->func.fn_resize) ee->func.fn_resize(ee); + } + } + else if (((ee->w != w) || (ee->h != h)) || + (ee->engine.x.configure_coming)) + { + ee->engine.x.configure_coming = 1; + ecore_x_window_resize(ee->prop.window, w, h); + } +} + +static void +_ecore_evas_x_move_resize(Ecore_Evas *ee, int x, int y, int w, int h) +{ + ee->req.x = x; + ee->req.y = y; + ee->req.w = w; + ee->req.h = h; + if (ee->engine.x.direct_resize) + { + if ((ee->w != w) || (ee->h != h) || (x != ee->x) || (y != ee->y)) + { + int change_size = 0, change_pos = 0; + + if ((ee->w != w) || (ee->h != h)) change_size = 1; + if (!ee->engine.x.managed) + { + if ((x != ee->x) || (y != ee->y)) change_pos = 1; + } + ecore_x_window_move_resize(ee->prop.window, x, y, w, h); + if (!ee->engine.x.managed) + { + ee->x = x; + ee->y = y; + } + ee->w = w; + ee->h = h; + if ((ee->rotation == 90) || (ee->rotation == 270)) + { + evas_output_size_set(ee->evas, ee->h, ee->w); + evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w); + } + else + { + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + } + if (ee->prop.avoid_damage) + { + int pdam; + + pdam = ecore_evas_avoid_damage_get(ee); + ecore_evas_avoid_damage_set(ee, 0); + ecore_evas_avoid_damage_set(ee, pdam); + } + if ((ee->shaped) || (ee->alpha)) + _ecore_evas_x_resize_shape(ee); + if (change_pos) + { + if (ee->func.fn_move) ee->func.fn_move(ee); + } + if (change_size) + { + if (ee->func.fn_resize) ee->func.fn_resize(ee); + } + } + } + else if (((ee->w != w) || (ee->h != h) || (ee->x != x) || (ee->y != y)) || + (ee->engine.x.configure_coming)) + { + ee->engine.x.configure_coming = 1; + ecore_x_window_move_resize(ee->prop.window, x, y, w, h); + if (!ee->engine.x.managed) + { + ee->x = x; + ee->y = y; + } + } +} + +static void +_ecore_evas_x_rotation_set_internal(Ecore_Evas *ee, int rotation, int resize, + Evas_Engine_Info *einfo) +{ + int rot_dif; + + rot_dif = ee->rotation - rotation; + if (rot_dif < 0) rot_dif = -rot_dif; + + if (rot_dif != 180) + { + int minw, minh, maxw, maxh, basew, baseh, stepw, steph; + + if (!evas_engine_info_set(ee->evas, einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + + if (!resize) + { + ee->engine.x.configure_coming = 1; + if (!ee->prop.fullscreen) + { + ecore_x_window_resize(ee->prop.window, ee->req.h, ee->req.w); + ee->expecting_resize.w = ee->h; + ee->expecting_resize.h = ee->w; + } + else + { + int w, h; + + ecore_x_window_size_get(ee->prop.window, &w, &h); + ecore_x_window_resize(ee->prop.window, h, w); + if ((rotation == 0) || (rotation == 180)) + { + evas_output_size_set(ee->evas, ee->req.w, ee->req.h); + evas_output_viewport_set(ee->evas, 0, 0, ee->req.w, ee->req.h); + } + else + { + evas_output_size_set(ee->evas, ee->req.h, ee->req.w); + evas_output_viewport_set(ee->evas, 0, 0, ee->req.h, ee->req.w); + } + if (ee->func.fn_resize) ee->func.fn_resize(ee); + } + if ((ee->rotation == 90) || (ee->rotation == 270)) + evas_damage_rectangle_add(ee->evas, 0, 0, ee->req.h, ee->req.w); + else + evas_damage_rectangle_add(ee->evas, 0, 0, ee->req.w, ee->req.h); + } + else + { + /* int w, h; */ + + /* ecore_x_window_size_get(ee->prop.window, &w, &h); */ + if ((rotation == 0) || (rotation == 180)) + { + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); + } + else + { + evas_output_size_set(ee->evas, ee->h, ee->w); + evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w); + } + if (ee->func.fn_resize) ee->func.fn_resize(ee); + if ((ee->rotation == 90) || (ee->rotation == 270)) + evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w); + else + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + } + ecore_evas_size_min_get(ee, &minw, &minh); + ecore_evas_size_max_get(ee, &maxw, &maxh); + ecore_evas_size_base_get(ee, &basew, &baseh); + ecore_evas_size_step_get(ee, &stepw, &steph); + ee->rotation = rotation; + ecore_evas_size_min_set(ee, minh, minw); + ecore_evas_size_max_set(ee, maxh, maxw); + ecore_evas_size_base_set(ee, baseh, basew); + ecore_evas_size_step_set(ee, steph, stepw); + _ecore_evas_mouse_move_process(ee, ee->mouse.x, ee->mouse.y, + ecore_x_current_time_get()); + } + else + { + if (!evas_engine_info_set(ee->evas, einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + ee->rotation = rotation; + _ecore_evas_mouse_move_process(ee, ee->mouse.x, ee->mouse.y, + ecore_x_current_time_get()); + if (ee->func.fn_resize) ee->func.fn_resize(ee); + + if ((ee->rotation == 90) || (ee->rotation == 270)) + evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w); + else + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + } +} + +#define _USE_WIN_ROT_EFFECT 1 + +#if _USE_WIN_ROT_EFFECT +static void _ecore_evas_x_flush_pre(void *data, Evas *e __UNUSED__, void *event_info __UNUSED__); + +typedef struct _Ecore_Evas_X_Rotation_Effect Ecore_Evas_X_Rotation_Effect; +struct _Ecore_Evas_X_Rotation_Effect +{ + Eina_Bool wait_for_comp_reply; +}; + +static Ecore_Evas_X_Rotation_Effect _rot_effect = +{ + EINA_FALSE +}; + +static void +_ecore_evas_x_rotation_effect_setup(void) +{ + _rot_effect.wait_for_comp_reply = EINA_TRUE; +} +#endif /* end of _USE_WIN_ROT_EFFECT */ + +static void +_ecore_evas_x_rotation_set(Ecore_Evas *ee, int rotation, int resize) +{ + if (ee->rotation == rotation) return; + if (!strcmp(ee->driver, "xrender_x11")) return; + +#if _USE_WIN_ROT_EFFECT + int angles[2]; + angles[0] = rotation; + angles[1] = ee->rotation; +#endif /* end of _USE_WIN_ROT_EFFECT */ + + if (!strcmp(ee->driver, "opengl_x11")) + { +#ifdef BUILD_ECORE_EVAS_OPENGL_X11 + Evas_Engine_Info_GL_X11 *einfo; + + einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas); + if (!einfo) return; + einfo->info.rotation = rotation; + _ecore_evas_x_rotation_set_internal(ee, rotation, resize, + (Evas_Engine_Info *)einfo); +# if _USE_WIN_ROT_EFFECT + ecore_x_window_prop_property_set(ee->prop.window, + ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE, + ECORE_X_ATOM_CARDINAL, 32, &angles, 2); +# else + ecore_x_window_prop_property_set(ee->prop.window, + ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE, + ECORE_X_ATOM_CARDINAL, 32, &rotation, 1); +# endif +#endif /* BUILD_ECORE_EVAS_OPENGL_X11 */ + } + else if (!strcmp(ee->driver, "software_x11")) + { +#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 + Evas_Engine_Info_Software_X11 *einfo; + + einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas); + if (!einfo) return; + einfo->info.rotation = rotation; + _ecore_evas_x_rotation_set_internal(ee, rotation, resize, + (Evas_Engine_Info *)einfo); +# if _USE_WIN_ROT_EFFECT + ecore_x_window_prop_property_set(ee->prop.window, + ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE, + ECORE_X_ATOM_CARDINAL, 32, &angles, 2); +# else + ecore_x_window_prop_property_set(ee->prop.window, + ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE, + ECORE_X_ATOM_CARDINAL, 32, &rotation, 1); +# endif +#endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */ + } + else if (!strcmp(ee->driver, "software_16_x11")) + { +#if BUILD_ECORE_EVAS_SOFTWARE_16_X11 + Evas_Engine_Info_Software_16_X11 *einfo; + + einfo = (Evas_Engine_Info_Software_16_X11 *)evas_engine_info_get(ee->evas); + if (!einfo) return; + einfo->info.rotation = rotation; + _ecore_evas_x_rotation_set_internal(ee, rotation, resize, + (Evas_Engine_Info *)einfo); +# if _USE_WIN_ROT_EFFECT + ecore_x_window_prop_property_set(ee->prop.window, + ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE, + ECORE_X_ATOM_CARDINAL, 32, &angles, 2); +# else + ecore_x_window_prop_property_set(ee->prop.window, + ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE, + ECORE_X_ATOM_CARDINAL, 32, &rotation, 1); +# endif +#endif /* BUILD_ECORE_EVAS_SOFTWARE_16_X11 */ + } + else if (!strcmp(ee->driver, "software_8_x11")) + { +#if BUILD_ECORE_EVAS_SOFTWARE_8_X11 + Evas_Engine_Info_Software_8_X11 *einfo; + + einfo = (Evas_Engine_Info_Software_8_X11 *)evas_engine_info_get(ee->evas); + if (!einfo) return; + einfo->info.rotation = rotation; + _ecore_evas_x_rotation_set_internal(ee, rotation, resize, + (Evas_Engine_Info *)einfo); +# if _USE_WIN_ROT_EFFECT + ecore_x_window_prop_property_set(ee->prop.window, + ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE, + ECORE_X_ATOM_CARDINAL, 32, &angles, 2); +# else + ecore_x_window_prop_property_set(ee->prop.window, + ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE, + ECORE_X_ATOM_CARDINAL, 32, &rotation, 1); +# endif +#endif /* BUILD_ECORE_EVAS_SOFTWARE_8_X11 */ + } + +#if _USE_WIN_ROT_EFFECT + if ((ee->visible) && + ((ecore_x_e_comp_sync_supported_get(ee->engine.x.win_root)) && + (!ee->no_comp_sync) && (_ecore_evas_app_comp_sync)) && + (ee->engine.x.sync_counter) && + (ee->engine.x.sync_val > 0)) + { + _ecore_evas_x_rotation_effect_setup(); + _ecore_evas_x_flush_pre(ee, NULL, NULL); + } +#endif /* end of _USE_WIN_ROT_EFFECT */ +} + +static void +_ecore_evas_x_shaped_set(Ecore_Evas *ee, int shaped) +{ + if ((ee->shaped == shaped)) return; + if (!strcmp(ee->driver, "opengl_x11")) return; + if (!strcmp(ee->driver, "software_x11")) + { +#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 + Evas_Engine_Info_Software_X11 *einfo; + + einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas); + ee->shaped = shaped; + if (einfo) + { + if (ee->shaped) + { + unsigned int foreground; + Ecore_X_GC gc; + + if (!ee->engine.x.mask) + ee->engine.x.mask = ecore_x_pixmap_new(ee->prop.window, ee->w, ee->h, 1); + foreground = 0; + gc = ecore_x_gc_new(ee->engine.x.mask, + ECORE_X_GC_VALUE_MASK_FOREGROUND, + &foreground); + ecore_x_drawable_rectangle_fill(ee->engine.x.mask, gc, + 0, 0, ee->w, ee->h); + ecore_x_gc_free(gc); + einfo->info.mask = ee->engine.x.mask; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + ecore_x_window_shape_input_mask_set(ee->prop.window, 0); + } + else + { + if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask); + ee->engine.x.mask = 0; + einfo->info.mask = 0; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + ecore_x_window_shape_mask_set(ee->prop.window, 0); + ecore_x_window_shape_input_mask_set(ee->prop.window, 0); + } + } +#endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */ + } + else if (!strcmp(ee->driver, "software_16_x11")) + { +#if BUILD_ECORE_EVAS_SOFTWARE_16_X11 +# if 0 /* XXX no shaped window support for software_16_x11 */ + Evas_Engine_Info_Software_16_X11 *einfo; + + einfo = (Evas_Engine_Info_Software_16_X11 *)evas_engine_info_get(ee->evas); + ee->shaped = shaped; + if (einfo) + { + if (ee->shaped) + { + ee->engine.x.mask = + ecore_x_pixmap_new(ee->prop.window, ee->w, ee->h, 1); + einfo->info.mask = ee->engine.x.mask; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + } + else + { + if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask); + ee->engine.x.mask = 0; + einfo->info.mask = 0; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + ecore_x_window_shape_mask_set(ee->prop.window, 0); + } + } +# endif /* XXX no shaped window support for software_16_x11 */ +#endif /* BUILD_ECORE_EVAS_SOFTWARE_16_X11 */ + } + if (!strcmp(ee->driver, "software_8_x11")) + { +#if defined (BUILD_ECORE_EVAS_SOFTWARE_8_X11) + Evas_Engine_Info_Software_8_X11 *einfo; + + einfo = (Evas_Engine_Info_Software_8_X11 *)evas_engine_info_get(ee->evas); + ee->shaped = shaped; + if (einfo) + { + if (ee->shaped) + { + unsigned int foreground; + Ecore_X_GC gc; + + if (!ee->engine.x.mask) + ee->engine.x.mask = ecore_x_pixmap_new(ee->prop.window, ee->w, ee->h, 1); + foreground = 0; + gc = ecore_x_gc_new(ee->engine.x.mask, + ECORE_X_GC_VALUE_MASK_FOREGROUND, + &foreground); + ecore_x_drawable_rectangle_fill(ee->engine.x.mask, gc, + 0, 0, ee->w, ee->h); + ecore_x_gc_free(gc); + einfo->info.mask = ee->engine.x.mask; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + ecore_x_window_shape_input_mask_set(ee->prop.window, 0); + } + else + { + if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask); + ee->engine.x.mask = 0; + einfo->info.mask = 0; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + ecore_x_window_shape_mask_set(ee->prop.window, 0); + ecore_x_window_shape_input_mask_set(ee->prop.window, 0); + } + } +#endif /* BUILD_ECORE_EVAS_SOFTWARE_8_X11 */ + } +} + +/* FIXME, round trip */ +static void +_ecore_evas_x_alpha_set(Ecore_Evas *ee, int alpha) +{ + Ecore_X_Window_Attributes att; + char *id = NULL; + + if ((ee->alpha == alpha)) return; + + if (!strcmp(ee->driver, "software_x11")) + { +#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 + Evas_Engine_Info_Software_X11 *einfo; + + einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas); + if (!einfo) return; + + if (!ecore_x_composite_query()) return; + + ee->shaped = 0; + ee->alpha = alpha; + ecore_x_window_free(ee->prop.window); + ecore_event_window_unregister(ee->prop.window); + if (ee->alpha) + { + if (ee->prop.override) + ee->prop.window = ecore_x_window_override_argb_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); + else + ee->prop.window = ecore_x_window_argb_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); + if (!ee->engine.x.mask) + ee->engine.x.mask = ecore_x_pixmap_new(ee->prop.window, ee->req.w, ee->req.h, 1); + } + else + { + if (ee->prop.override) + ee->prop.window = ecore_x_window_override_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); + else + ee->prop.window = ecore_x_window_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); + if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask); + ee->engine.x.mask = 0; + ecore_x_window_shape_input_mask_set(ee->prop.window, 0); + } + + einfo->info.destination_alpha = alpha; + + ecore_x_window_attributes_get(ee->prop.window, &att); + einfo->info.visual = att.visual; + einfo->info.colormap = att.colormap; + einfo->info.depth = att.depth; + +// if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask); +// ee->engine.x.mask = 0; + einfo->info.mask = ee->engine.x.mask; + einfo->info.drawable = ee->prop.window; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + evas_damage_rectangle_add(ee->evas, 0, 0, ee->req.w, ee->req.h); + ecore_x_window_shape_mask_set(ee->prop.window, 0); + ecore_x_input_multi_select(ee->prop.window); + ecore_event_window_register(ee->prop.window, ee, ee->evas, + (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, + (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, + (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, + (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); + if (ee->prop.borderless) + ecore_x_mwm_borderless_set(ee->prop.window, ee->prop.borderless); + if (ee->visible) ecore_x_window_show(ee->prop.window); + if (ee->prop.focused) ecore_x_window_focus(ee->prop.window); + if (ee->prop.title) + { + ecore_x_icccm_title_set(ee->prop.window, ee->prop.title); + ecore_x_netwm_name_set(ee->prop.window, ee->prop.title); + } + if (ee->prop.name) + ecore_x_icccm_name_class_set(ee->prop.window, + ee->prop.name, ee->prop.clas); + _ecore_evas_x_hints_update(ee); + _ecore_evas_x_group_leader_update(ee); + ecore_x_window_defaults_set(ee->prop.window); + _ecore_evas_x_protocols_set(ee); + _ecore_evas_x_sync_set(ee); + _ecore_evas_x_size_pos_hints_update(ee); +#endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */ + if ((id = getenv("DESKTOP_STARTUP_ID"))) + { + ecore_x_netwm_startup_id_set(ee->prop.window, id); + /* NB: on linux this may simply empty the env as opposed to completely + * unset it to being empty - unsure as solartis libc crashes looking + * for the '=' char */ + // putenv((char*)"DESKTOP_STARTUP_ID="); + } + } + else if (!strcmp(ee->driver, "opengl_x11")) + { +#ifdef BUILD_ECORE_EVAS_OPENGL_X11 + Evas_Engine_Info_GL_X11 *einfo; + + einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas); + if (!einfo) return; + + if (!ecore_x_composite_query()) return; + + ee->shaped = 0; + ee->alpha = alpha; + ecore_x_window_free(ee->prop.window); + ecore_event_window_unregister(ee->prop.window); + ee->prop.window = 0; + + einfo->info.destination_alpha = alpha; + + if (ee->engine.x.win_root != 0) + { + /* FIXME: round trip in ecore_x_window_argb_get */ + if (ecore_x_window_argb_get(ee->engine.x.win_root)) + { + ee->prop.window = + _ecore_evas_x_gl_window_new(ee, ee->engine.x.win_root, + ee->req.x, ee->req.y, + ee->req.w, ee->req.h, + ee->prop.override, 1, NULL); + } + else + { + ee->prop.window = + _ecore_evas_x_gl_window_new(ee, ee->engine.x.win_root, + ee->req.x, ee->req.y, + ee->req.w, ee->req.h, + ee->prop.override, ee->alpha, + NULL); + } + } + else + { + ee->prop.window = + _ecore_evas_x_gl_window_new(ee, ee->engine.x.win_root, + ee->req.x, ee->req.y, + ee->req.w, ee->req.h, + ee->prop.override, ee->alpha, NULL); + } + + if (!ee->prop.window) return; +/* + if (ee->alpha) + { + if (ee->prop.override) + ee->prop.window = ecore_x_window_override_argb_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); + else + ee->prop.window = ecore_x_window_argb_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); + if (!ee->engine.x.mask) + ee->engine.x.mask = ecore_x_pixmap_new(ee->prop.window, ee->req.w, ee->req.h, 1); + } + else + { + if (ee->prop.override) + ee->prop.window = ecore_x_window_override_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); + else + ee->prop.window = ecore_x_window_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); + if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask); + ee->engine.x.mask = 0; + ecore_x_window_shape_input_mask_set(ee->prop.window, 0); + } + */ + + ecore_x_window_attributes_get(ee->prop.window, &att); + einfo->info.visual = att.visual; + einfo->info.colormap = att.colormap; + einfo->info.depth = att.depth; + +// if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask); +// ee->engine.x.mask = 0; +// einfo->info.mask = ee->engine.x.mask; + einfo->info.drawable = ee->prop.window; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + evas_damage_rectangle_add(ee->evas, 0, 0, ee->req.w, ee->req.h); +// ecore_x_window_shape_mask_set(ee->prop.window, 0); + ecore_x_input_multi_select(ee->prop.window); + ecore_event_window_register(ee->prop.window, ee, ee->evas, + (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, + (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, + (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, + (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); + if (ee->prop.borderless) + ecore_x_mwm_borderless_set(ee->prop.window, ee->prop.borderless); + if (ee->visible) ecore_x_window_show(ee->prop.window); + if (ee->prop.focused) ecore_x_window_focus(ee->prop.window); + if (ee->prop.title) + { + ecore_x_icccm_title_set(ee->prop.window, ee->prop.title); + ecore_x_netwm_name_set(ee->prop.window, ee->prop.title); + } + if (ee->prop.name) + ecore_x_icccm_name_class_set(ee->prop.window, + ee->prop.name, ee->prop.clas); + _ecore_evas_x_hints_update(ee); + _ecore_evas_x_group_leader_update(ee); + ecore_x_window_defaults_set(ee->prop.window); + _ecore_evas_x_protocols_set(ee); + _ecore_evas_x_sync_set(ee); + _ecore_evas_x_size_pos_hints_update(ee); +#endif /* BUILD_ECORE_EVAS_OPENGL_X11 */ + if ((id = getenv("DESKTOP_STARTUP_ID"))) + { + ecore_x_netwm_startup_id_set(ee->prop.window, id); + /* NB: on linux this may simply empty the env as opposed to completely + * unset it to being empty - unsure as solartis libc crashes looking + * for the '=' char */ + // putenv((char*)"DESKTOP_STARTUP_ID="); + } + } + else if (!strcmp(ee->driver, "software_16_x11")) + { +#if BUILD_ECORE_EVAS_SOFTWARE_16_X11 + Evas_Engine_Info_Software_16_X11 *einfo; + + einfo = (Evas_Engine_Info_Software_16_X11 *)evas_engine_info_get(ee->evas); + if (!einfo) return; + + ee->shaped = 0; + ee->alpha = alpha; + ecore_x_window_free(ee->prop.window); + ecore_event_window_unregister(ee->prop.window); + if (ee->alpha) + { + if (ee->prop.override) + ee->prop.window = ecore_x_window_override_argb_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); + else + ee->prop.window = ecore_x_window_argb_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); + if (!ee->engine.x.mask) + ee->engine.x.mask = ecore_x_pixmap_new(ee->prop.window, ee->req.w, ee->req.h, 1); + } + else + { + if (ee->prop.override) + ee->prop.window = ecore_x_window_override_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); + else + ee->prop.window = ecore_x_window_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); + if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask); + ee->engine.x.mask = 0; + ecore_x_window_shape_input_mask_set(ee->prop.window, 0); + } + +# if 0 /* XXX no alpha window support for software_16_x11 */ + einfo->info.destination_alpha = alpha; +# endif /* XXX no alpha window support for software_16_x11 */ + +# if 0 /* XXX no shaped window support for software_16_x11 */ +// if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask); +// ee->engine.x.mask = 0; + einfo->info.mask = ee->engine.x.mask; +# endif /* XXX no shaped window support for software_16_x11 */ + + einfo->info.drawable = ee->prop.window; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + evas_damage_rectangle_add(ee->evas, 0, 0, ee->req.w, ee->req.h); + ecore_x_window_shape_mask_set(ee->prop.window, 0); + ecore_x_input_multi_select(ee->prop.window); + ecore_event_window_register(ee->prop.window, ee, ee->evas, + (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, + (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, + (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, + (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); + if (ee->prop.borderless) + ecore_x_mwm_borderless_set(ee->prop.window, ee->prop.borderless); + if (ee->visible) ecore_x_window_show(ee->prop.window); + if (ee->prop.focused) ecore_x_window_focus(ee->prop.window); + if (ee->prop.title) + { + ecore_x_icccm_title_set(ee->prop.window, ee->prop.title); + ecore_x_netwm_name_set(ee->prop.window, ee->prop.title); + } + if (ee->prop.name) + ecore_x_icccm_name_class_set(ee->prop.window, + ee->prop.name, ee->prop.clas); + _ecore_evas_x_hints_update(ee); + _ecore_evas_x_group_leader_update(ee); + ecore_x_window_defaults_set(ee->prop.window); + _ecore_evas_x_protocols_set(ee); + _ecore_evas_x_sync_set(ee); + _ecore_evas_x_size_pos_hints_update(ee); +#endif /* BUILD_ECORE_EVAS_SOFTWARE_16_X11 */ + if ((id = getenv("DESKTOP_STARTUP_ID"))) + { + ecore_x_netwm_startup_id_set(ee->prop.window, id); + /* NB: on linux this may simply empty the env as opposed to completely + * unset it to being empty - unsure as solartis libc crashes looking + * for the '=' char */ + // putenv((char*)"DESKTOP_STARTUP_ID="); + } + } + else if (!strcmp(ee->driver, "software_8_x11")) + { +#if defined (BUILD_ECORE_EVAS_SOFTWARE_8_X11) + Evas_Engine_Info_Software_8_X11 *einfo; + + einfo = (Evas_Engine_Info_Software_8_X11 *)evas_engine_info_get(ee->evas); + if (!einfo) return; + + ee->shaped = 0; + ee->alpha = alpha; + ecore_x_window_free(ee->prop.window); + ecore_event_window_unregister(ee->prop.window); + if (ee->alpha) + { + if (ee->prop.override) + ee->prop.window = ecore_x_window_override_argb_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); + else + ee->prop.window = ecore_x_window_argb_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); + if (!ee->engine.x.mask) + ee->engine.x.mask = ecore_x_pixmap_new(ee->prop.window, ee->req.w, ee->req.h, 1); + } + else + { + if (ee->prop.override) + ee->prop.window = ecore_x_window_override_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); + else + ee->prop.window = ecore_x_window_new(ee->engine.x.win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); + if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask); + ee->engine.x.mask = 0; + ecore_x_window_shape_input_mask_set(ee->prop.window, 0); + } + + einfo->info.destination_alpha = alpha; + + ecore_x_window_attributes_get(ee->prop.window, &att); + einfo->info.visual = att.visual; + einfo->info.colormap = att.colormap; + einfo->info.depth = att.depth; + +// if (ee->engine.x.mask) ecore_x_pixmap_free(ee->engine.x.mask); +// ee->engine.x.mask = 0; + einfo->info.mask = ee->engine.x.mask; + einfo->info.drawable = ee->prop.window; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + evas_damage_rectangle_add(ee->evas, 0, 0, ee->req.w, ee->req.h); + ecore_x_window_shape_mask_set(ee->prop.window, 0); + ecore_x_input_multi_select(ee->prop.window); + ecore_event_window_register(ee->prop.window, ee, ee->evas, + (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, + (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, + (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, + (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); + if (ee->prop.borderless) + ecore_x_mwm_borderless_set(ee->prop.window, ee->prop.borderless); + if (ee->visible) ecore_x_window_show(ee->prop.window); + if (ee->prop.focused) ecore_x_window_focus(ee->prop.window); + if (ee->prop.title) + { + ecore_x_icccm_title_set(ee->prop.window, ee->prop.title); + ecore_x_netwm_name_set(ee->prop.window, ee->prop.title); + } + if (ee->prop.name) + ecore_x_icccm_name_class_set(ee->prop.window, + ee->prop.name, ee->prop.clas); + _ecore_evas_x_hints_update(ee); + _ecore_evas_x_group_leader_update(ee); + ecore_x_window_defaults_set(ee->prop.window); + _ecore_evas_x_protocols_set(ee); + _ecore_evas_x_sync_set(ee); + _ecore_evas_x_size_pos_hints_update(ee); + + if ((id = getenv("DESKTOP_STARTUP_ID"))) + { + ecore_x_netwm_startup_id_set(ee->prop.window, id); + /* NB: on linux this may simply empty the env as opposed to completely + * unset it to being empty - unsure as solartis libc crashes looking + * for the '=' char */ + // putenv((char*)"DESKTOP_STARTUP_ID="); + } +#endif /* BUILD_ECORE_EVAS_SOFTWARE_8_X11 */ + } +} + +static void +_ecore_evas_x_transparent_set(Ecore_Evas *ee, int transparent) +{ + if ((ee->transparent == transparent)) return; + + if (!strcmp(ee->driver, "software_x11")) + { +#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 + Evas_Engine_Info_Software_X11 *einfo; + + einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas); + if (!einfo) return; + + ee->transparent = transparent; + einfo->info.destination_alpha = transparent; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); +#endif + } +} + +static void +_ecore_evas_x_window_group_set(Ecore_Evas *ee, const Ecore_Evas *group_ee) +{ + if (ee->prop.group_ee == group_ee) return; + + ee->prop.group_ee = (Ecore_Evas *)group_ee; + if (ee->prop.group_ee) + ee->prop.group_ee_win = group_ee->prop.window; + else + ee->prop.group_ee_win = 0; + _ecore_evas_x_hints_update(ee); +} + +static void +_ecore_evas_x_aspect_set(Ecore_Evas *ee, double aspect) +{ + if (ee->prop.aspect == aspect) return; + + ee->prop.aspect = aspect; + _ecore_evas_x_size_pos_hints_update(ee); +// netwm state +// if (ee->should_be_visible) +// ecore_x_netwm_state_request_send(ee->prop.window, ee->engine.x.win_root, +// ECORE_X_WINDOW_STATE_STICKY, -1, sticky); +// else +// _ecore_evas_x_state_update(ee); +} + +static void +_ecore_evas_x_urgent_set(Ecore_Evas *ee, int urgent) +{ + if (ee->prop.urgent == urgent) return; + + ee->prop.urgent = urgent; + _ecore_evas_x_hints_update(ee); +} + +static void +_ecore_evas_x_modal_set(Ecore_Evas *ee, int modal) +{ + if (ee->prop.modal == modal) return; + + ee->prop.modal = modal; + if (ee->should_be_visible) + ecore_x_netwm_state_request_send(ee->prop.window, ee->engine.x.win_root, + ECORE_X_WINDOW_STATE_MODAL, -1, modal); + else + _ecore_evas_x_state_update(ee); +} + +static void +_ecore_evas_x_demand_attention_set(Ecore_Evas *ee, int demand) +{ + if (ee->prop.demand_attention == demand) return; + + ee->prop.demand_attention = demand; + if (ee->should_be_visible) + ecore_x_netwm_state_request_send(ee->prop.window, ee->engine.x.win_root, + ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION, -1, demand); + else + _ecore_evas_x_state_update(ee); +} + +static void +_ecore_evas_x_focus_skip_set(Ecore_Evas *ee, int skip) +{ + if (ee->prop.focus_skip == skip) return; + + ee->prop.focus_skip = skip; + if (ee->should_be_visible) + { + ecore_x_netwm_state_request_send(ee->prop.window, ee->engine.x.win_root, + ECORE_X_WINDOW_STATE_SKIP_TASKBAR, -1, skip); + ecore_x_netwm_state_request_send(ee->prop.window, ee->engine.x.win_root, + ECORE_X_WINDOW_STATE_SKIP_PAGER, -1, skip); + } + else + _ecore_evas_x_state_update(ee); + _ecore_evas_x_hints_update(ee); +} + +#endif /* BUILD_ECORE_EVAS_X11 */ + +#ifdef BUILD_ECORE_EVAS_X11 +static void +_ecore_evas_x_show(Ecore_Evas *ee) +{ + ee->should_be_visible = 1; + if (ee->prop.avoid_damage) + _ecore_evas_x_render(ee); + _ecore_evas_x_sync_set(ee); + ecore_x_window_show(ee->prop.window); + if (ee->prop.fullscreen) + ecore_x_window_focus(ee->prop.window); +} + +static void +_ecore_evas_x_hide(Ecore_Evas *ee) +{ + ecore_x_window_hide(ee->prop.window); + ee->should_be_visible = 0; + _ecore_evas_x_sync_set(ee); +} + +static void +_ecore_evas_x_raise(Ecore_Evas *ee) +{ + ecore_x_window_raise(ee->prop.window); +} + +static void +_ecore_evas_x_lower(Ecore_Evas *ee) +{ + ecore_x_window_lower(ee->prop.window); +} + +static void +_ecore_evas_x_activate(Ecore_Evas *ee) +{ + ecore_x_netwm_client_active_request(ee->engine.x.win_root, + ee->prop.window, 2, 0); +} + +static void +_ecore_evas_x_title_set(Ecore_Evas *ee, const char *t) +{ + if (ee->prop.title) free(ee->prop.title); + ee->prop.title = NULL; + if (t) ee->prop.title = strdup(t); + ecore_x_icccm_title_set(ee->prop.window, ee->prop.title); + ecore_x_netwm_name_set(ee->prop.window, ee->prop.title); +} + +static void +_ecore_evas_x_name_class_set(Ecore_Evas *ee, const char *n, const char *c) +{ + if (ee->prop.name) free(ee->prop.name); + if (ee->prop.clas) free(ee->prop.clas); + ee->prop.name = NULL; + ee->prop.clas = NULL; + if (n) ee->prop.name = strdup(n); + if (c) ee->prop.clas = strdup(c); + ecore_x_icccm_name_class_set(ee->prop.window, ee->prop.name, ee->prop.clas); +} + +static void +_ecore_evas_x_size_min_set(Ecore_Evas *ee, int w, int h) +{ + if (w < 0) w = 0; + if (h < 0) h = 0; + if ((ee->prop.min.w == w) && (ee->prop.min.h == h)) return; + ee->prop.min.w = w; + ee->prop.min.h = h; + _ecore_evas_x_size_pos_hints_update(ee); +} + +static void +_ecore_evas_x_size_max_set(Ecore_Evas *ee, int w, int h) +{ + if (w < 0) w = 0; + if (h < 0) h = 0; + if ((ee->prop.max.w == w) && (ee->prop.max.h == h)) return; + ee->prop.max.w = w; + ee->prop.max.h = h; + _ecore_evas_x_size_pos_hints_update(ee); +} + +static void +_ecore_evas_x_size_base_set(Ecore_Evas *ee, int w, int h) +{ + if (w < 0) w = 0; + if (h < 0) h = 0; + if ((ee->prop.base.w == w) && (ee->prop.base.h == h)) return; + ee->prop.base.w = w; + ee->prop.base.h = h; + _ecore_evas_x_size_pos_hints_update(ee); +} + +static void +_ecore_evas_x_size_step_set(Ecore_Evas *ee, int w, int h) +{ + if (w < 1) w = 1; + if (h < 1) h = 1; + if ((ee->prop.step.w == w) && (ee->prop.step.h == h)) return; + ee->prop.step.w = w; + ee->prop.step.h = h; + _ecore_evas_x_size_pos_hints_update(ee); +} + +static void +_ecore_evas_object_cursor_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee; + + ee = data; + if (ee) ee->prop.cursor.object = NULL; +} + +static void +_ecore_evas_x_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y) +{ + int x, y; + + if (ee->prop.cursor.object) evas_object_del(ee->prop.cursor.object); + + if (!obj) + { + ee->prop.cursor.object = NULL; + ee->prop.cursor.layer = 0; + ee->prop.cursor.hot.x = 0; + ee->prop.cursor.hot.y = 0; + ecore_x_window_cursor_show(ee->prop.window, 1); + return; + } + + ee->prop.cursor.object = obj; + ee->prop.cursor.layer = layer; + ee->prop.cursor.hot.x = hot_x; + ee->prop.cursor.hot.y = hot_y; + + ecore_x_window_cursor_show(ee->prop.window, 0); + + evas_pointer_output_xy_get(ee->evas, &x, &y); + evas_object_layer_set(ee->prop.cursor.object, ee->prop.cursor.layer); + evas_object_move(ee->prop.cursor.object, + x - ee->prop.cursor.hot.x, + y - ee->prop.cursor.hot.y); + evas_object_pass_events_set(ee->prop.cursor.object, 1); + if (evas_pointer_inside_get(ee->evas)) + evas_object_show(ee->prop.cursor.object); + + evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _ecore_evas_object_cursor_del, ee); +} + +/* + * @param ee + * @param layer If < 3, @a ee will be put below all other windows. + * If > 5, @a ee will be "always-on-top" + * If = 4, @a ee will be put in the default layer. + * Acceptable values range from 1 to 255 (0 reserved for + * desktop windows) + */ +static void +_ecore_evas_x_layer_set(Ecore_Evas *ee, int layer) +{ + if (ee->prop.layer == layer) return; + + /* FIXME: Should this logic be here? */ + if (layer < 1) + layer = 1; + else if (layer > 255) + layer = 255; + + ee->prop.layer = layer; + _ecore_evas_x_layer_update(ee); +} + +static void +_ecore_evas_x_focus_set(Ecore_Evas *ee, int on __UNUSED__) +{ + ecore_x_window_focus(ee->prop.window); +} + +static void +_ecore_evas_x_iconified_set(Ecore_Evas *ee, int on) +{ + if (ee->prop.iconified == on) return; + ee->prop.iconified = on; + _ecore_evas_x_hints_update(ee); + if (on) + ecore_x_icccm_iconic_request_send(ee->prop.window, ee->engine.x.win_root); + else + ecore_evas_show(ee); +} + +static void +_ecore_evas_x_borderless_set(Ecore_Evas *ee, int on) +{ + if (ee->prop.borderless == on) return; + ee->prop.borderless = on; + ecore_x_mwm_borderless_set(ee->prop.window, ee->prop.borderless); +} + +/* FIXME: This function changes the initial state of the ee + * whilest the iconic function changes the current state! */ +static void +_ecore_evas_x_withdrawn_set(Ecore_Evas *ee, int withdrawn) +{ + if (ee->prop.withdrawn == withdrawn) return; + ee->prop.withdrawn = withdrawn; + _ecore_evas_x_hints_update(ee); +} + +static void +_ecore_evas_x_sticky_set(Ecore_Evas *ee, int sticky) +{ + if (ee->prop.sticky == sticky) return; + + /* We dont want to set prop.sticky here as it will cause + * the sticky callback not to get called. Its set on the + * property change event. + * ee->prop.sticky = sticky; + */ + ee->engine.x.state.sticky = sticky; + if (ee->should_be_visible) + ecore_x_netwm_state_request_send(ee->prop.window, ee->engine.x.win_root, + ECORE_X_WINDOW_STATE_STICKY, -1, sticky); + else + _ecore_evas_x_state_update(ee); +} + +static void +_ecore_evas_x_ignore_events_set(Ecore_Evas *ee, int ignore) +{ + if (ee->ignore_events == ignore) return; + + ee->ignore_events = ignore; + if (ee->prop.window) + ecore_x_window_ignore_set(ee->prop.window, ignore); +} + +/* +static void +_ecore_evas_x_reinit_win(Ecore_Evas *ee) +{ + if (!strcmp(ee->driver, "software_x11")) + { +#ifdef BUILD_ECORE_EVAS_X11 + Evas_Engine_Info_Software_X11 *einfo; + + einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas); + if (einfo) + { + einfo->info.drawable = ee->prop.window; + evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); + } +#endif + } + else if (!strcmp(ee->driver, "opengl_x11")) + { +#ifdef BUILD_ECORE_EVAS_OPENGL_X11 + Evas_Engine_Info_GL_X11 *einfo; + + einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas); + if (einfo) + { + einfo->info.drawable = ee->prop.window; + evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); + } +#endif + } +} +*/ + +static void +_ecore_evas_x_override_set(Ecore_Evas *ee, int on) +{ + if (ee->prop.override == on) return; + if (ee->should_be_visible) ecore_x_window_hide(ee->prop.window); + ecore_x_window_override_set(ee->prop.window, on); + if (ee->should_be_visible) ecore_x_window_show(ee->prop.window); + if (ee->prop.focused) ecore_x_window_focus(ee->prop.window); + ee->prop.override = on; +} + +static void +_ecore_evas_x_maximized_set(Ecore_Evas *ee, int on) +{ + if (ee->prop.maximized == on) return; + ee->engine.x.state.maximized_h = 1; + ee->engine.x.state.maximized_v = 1; + ee->prop.maximized = on; + if (ee->should_be_visible) + { + ecore_x_netwm_state_request_send(ee->prop.window, ee->engine.x.win_root, + ECORE_X_WINDOW_STATE_MAXIMIZED_VERT, -1, on); + ecore_x_netwm_state_request_send(ee->prop.window, ee->engine.x.win_root, + ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ, -1, on); + } + else + _ecore_evas_x_state_update(ee); +} + +static void +_ecore_evas_x_fullscreen_set(Ecore_Evas *ee, int on) +{ + if (ee->prop.fullscreen == on) return; + + /* FIXME: Detect if WM is EWMH compliant and handle properly if not, + * i.e. reposition, resize, and change borderless hint */ + ee->engine.x.state.fullscreen = on; + if (ee->should_be_visible) + ecore_x_netwm_state_request_send(ee->prop.window, ee->engine.x.win_root, + ECORE_X_WINDOW_STATE_FULLSCREEN, -1, on); + else + _ecore_evas_x_state_update(ee); +} + +static void +_ecore_evas_x_profiles_set(Ecore_Evas *ee, const char **plist, int n) +{ + /* Ecore_Evas's profile will be updated when WM sets the E_PROFILE. */ + ecore_x_e_window_profile_list_set(ee->prop.window, plist, n); +} + +static void +_ecore_evas_x_avoid_damage_set(Ecore_Evas *ee, int on) +{ + if (ee->prop.avoid_damage == on) return; + if (!strcmp(ee->driver, "opengl_x11")) return; + + if (!strcmp(ee->driver, "software_x11")) + { +#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 + Evas_Engine_Info_Software_X11 *einfo; + + ee->prop.avoid_damage = on; + einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas); + if (einfo) + { + if (ee->prop.avoid_damage) + { + ee->engine.x.pmap = ecore_x_pixmap_new(ee->prop.window, ee->w, ee->h, einfo->info.depth); + ee->engine.x.gc = ecore_x_gc_new(ee->engine.x.pmap, 0, NULL); + einfo->info.drawable = ee->engine.x.pmap; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + if ((ee->rotation == 90) || (ee->rotation == 270)) + evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w); + else + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + if (ee->prop.avoid_damage == ECORE_EVAS_AVOID_DAMAGE_BUILT_IN) + { + ee->engine.x.using_bg_pixmap = 1; + ecore_x_window_pixmap_set(ee->prop.window, ee->engine.x.pmap); + ecore_x_window_area_expose(ee->prop.window, 0, 0, ee->w, ee->h); + } + if (ee->engine.x.direct_resize) + { + /* Turn this off for now + ee->engine.x.using_bg_pixmap = 1; + ecore_x_window_pixmap_set(ee->prop.window, ee->engine.x.pmap); + */ + } + } + else + { + if (ee->engine.x.pmap) ecore_x_pixmap_free(ee->engine.x.pmap); + if (ee->engine.x.gc) ecore_x_gc_free(ee->engine.x.gc); + if (ee->engine.x.using_bg_pixmap) + { + ecore_x_window_pixmap_set(ee->prop.window, 0); + ee->engine.x.using_bg_pixmap = 0; + ecore_x_window_area_expose(ee->prop.window, 0, 0, ee->w, ee->h); + } + ee->engine.x.pmap = 0; + ee->engine.x.gc = 0; + einfo->info.drawable = ee->prop.window; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + } + } +#endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */ + } + else if (!strcmp(ee->driver, "software_16_x11")) + { +#if BUILD_ECORE_EVAS_SOFTWARE_16_X11 + Evas_Engine_Info_Software_16_X11 *einfo; + + ee->prop.avoid_damage = on; + einfo = (Evas_Engine_Info_Software_16_X11 *)evas_engine_info_get(ee->evas); + if (einfo) + { + if (ee->prop.avoid_damage) + { + ee->engine.x.pmap = ecore_x_pixmap_new(ee->prop.window, ee->w, ee->h, 16); + ee->engine.x.gc = ecore_x_gc_new(ee->engine.x.pmap, 0, NULL); + einfo->info.drawable = ee->engine.x.pmap; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + if ((ee->rotation == 90) || (ee->rotation == 270)) + evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w); + else + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + if (ee->engine.x.direct_resize) + { + /* Turn this off for now + ee->engine.x.using_bg_pixmap = 1; + ecore_x_window_pixmap_set(ee->prop.window, ee->engine.x.pmap); + */ + } + } + else + { + if (ee->engine.x.pmap) ecore_x_pixmap_free(ee->engine.x.pmap); + if (ee->engine.x.gc) ecore_x_gc_free(ee->engine.x.gc); + if (ee->engine.x.using_bg_pixmap) + { + ecore_x_window_pixmap_set(ee->prop.window, 0); + ee->engine.x.using_bg_pixmap = 0; + } + ee->engine.x.pmap = 0; + ee->engine.x.gc = 0; + einfo->info.drawable = ee->prop.window; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + } + } +#endif /* BUILD_ECORE_EVAS_SOFTWARE_16_X11 */ + } + else if (!strcmp(ee->driver, "software_8_x11")) + { +#if BUILD_ECORE_EVAS_SOFTWARE_8_X11 + Evas_Engine_Info_Software_8_X11 *einfo; + + ee->prop.avoid_damage = on; + einfo = (Evas_Engine_Info_Software_8_X11 *)evas_engine_info_get(ee->evas); + if (einfo) + { + if (ee->prop.avoid_damage) + { + ee->engine.x.pmap = ecore_x_pixmap_new(ee->prop.window, ee->w, ee->h, einfo->info.depth); + ee->engine.x.gc = ecore_x_gc_new(ee->engine.x.pmap, 0, NULL); + einfo->info.drawable = ee->engine.x.pmap; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + if ((ee->rotation == 90) || (ee->rotation == 270)) + evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w); + else + evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); + if (ee->prop.avoid_damage == ECORE_EVAS_AVOID_DAMAGE_BUILT_IN) + { + ee->engine.x.using_bg_pixmap = 1; + ecore_x_window_pixmap_set(ee->prop.window, ee->engine.x.pmap); + ecore_x_window_area_expose(ee->prop.window, 0, 0, ee->w, ee->h); + } + if (ee->engine.x.direct_resize) + { + /* Turn this off for now + ee->engine.x.using_bg_pixmap = 1; + ecore_x_window_pixmap_set(ee->prop.window, ee->engine.x.pmap); + */ + } + } + else + { + if (ee->engine.x.pmap) ecore_x_pixmap_free(ee->engine.x.pmap); + if (ee->engine.x.gc) ecore_x_gc_free(ee->engine.x.gc); + if (ee->engine.x.using_bg_pixmap) + { + ecore_x_window_pixmap_set(ee->prop.window, 0); + ee->engine.x.using_bg_pixmap = 0; + ecore_x_window_area_expose(ee->prop.window, 0, 0, ee->w, ee->h); + } + ee->engine.x.pmap = 0; + ee->engine.x.gc = 0; + einfo->info.drawable = ee->prop.window; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + } + } +#endif /* BUILD_ECORE_EVAS_SOFTWARE_8_X11 */ + } +} + +static void +_ecore_evas_x_screen_geometry_get(const Ecore_Evas *ee __UNUSED__, int *x, int *y, int *w, int *h) +{ + int outnum = 0; + int px = 0, py = 0, pw = 0, ph = 0; + Ecore_X_Window root; + Ecore_X_Randr_Output *out = NULL; + Ecore_X_Randr_Crtc crtc; + unsigned int val[4] = { 0 }; + + if (ecore_x_window_prop_card32_get + (ee->prop.window, ecore_x_atom_get("E_ZONE_GEOMETRY"), val, 4) == 4) + { + if (x) *x = (int)val[0]; + if (y) *y = (int)val[1]; + if (w) *w = (int)val[2]; + if (h) *h = (int)val[3]; + return; + } + + root = ecore_x_window_root_get(ee->prop.window); + out = ecore_x_randr_window_outputs_get(ee->prop.window, &outnum); + if (!out) + { +norandr: + if (out) free(out); + if (x) *x = 0; + if (y) *y = 0; + ecore_x_window_size_get(root, w, h); + return; + } + crtc = ecore_x_randr_output_crtc_get(root, out[0]); + if (!crtc) goto norandr; + ecore_x_randr_crtc_geometry_get(root, crtc, &px, &py, &pw, &ph); + if ((pw == 0) || (ph == 0)) goto norandr; + if (x) *x = px; + if (y) *y = py; + if (w) *w = pw; + if (h) *h = ph; + free(out); +} + +static void +_ecore_evas_x_screen_dpi_get(const Ecore_Evas *ee, int *xdpi, int *ydpi) +{ + int scdpi, xmm = 0, ymm = 0, outnum = 0, w = 0, h = 0; + int px = 0, py = 0; + Ecore_X_Window root; + Ecore_X_Randr_Output *out = NULL; + Ecore_X_Randr_Crtc crtc; + + root = ecore_x_window_root_get(ee->prop.window); + out = ecore_x_randr_window_outputs_get(ee->prop.window, &outnum); + if (!out) + { +norandr: + if (out) free(out); + scdpi = ecore_x_dpi_get(); + if (xdpi) *xdpi = scdpi; + if (ydpi) *ydpi = scdpi; + return; + } + crtc = ecore_x_randr_output_crtc_get(root, out[0]); + if (!crtc) goto norandr; + ecore_x_randr_crtc_geometry_get(root, crtc, &px, &py, &w, &h); + if ((w == 0) || (h == 0)) goto norandr; + ecore_x_randr_output_size_mm_get(root, out[0], &xmm, &ymm); + if ((xmm == 0) || (ymm == 0)) goto norandr; + if (xdpi) *xdpi = (w * 254) / (xmm * 10); // 25.4mm / inch + if (ydpi) *ydpi = (h * 254) / (ymm * 10); // 25.4mm / inch + free(out); +} + +int +_ecore_evas_x_shutdown(void) +{ + _ecore_evas_init_count--; + if (_ecore_evas_init_count == 0) + { + unsigned int i; + + for (i = 0; i < sizeof(ecore_evas_event_handlers) / sizeof(Ecore_Event_Handler*); i++) + { + if (ecore_evas_event_handlers[i]) + ecore_event_handler_del(ecore_evas_event_handlers[i]); + } + ecore_event_evas_shutdown(); + } + if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0; + return _ecore_evas_init_count; +} + +static Ecore_Evas_Engine_Func _ecore_x_engine_func = +{ + _ecore_evas_x_free, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_x_callback_delete_request_set, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + _ecore_evas_x_move, + _ecore_evas_x_managed_move, + _ecore_evas_x_resize, + _ecore_evas_x_move_resize, + _ecore_evas_x_rotation_set, + _ecore_evas_x_shaped_set, + _ecore_evas_x_show, + _ecore_evas_x_hide, + _ecore_evas_x_raise, + _ecore_evas_x_lower, + _ecore_evas_x_activate, + _ecore_evas_x_title_set, + _ecore_evas_x_name_class_set, + _ecore_evas_x_size_min_set, + _ecore_evas_x_size_max_set, + _ecore_evas_x_size_base_set, + _ecore_evas_x_size_step_set, + _ecore_evas_x_object_cursor_set, + _ecore_evas_x_layer_set, + _ecore_evas_x_focus_set, + _ecore_evas_x_iconified_set, + _ecore_evas_x_borderless_set, + _ecore_evas_x_override_set, + _ecore_evas_x_maximized_set, + _ecore_evas_x_fullscreen_set, + _ecore_evas_x_avoid_damage_set, + _ecore_evas_x_withdrawn_set, + _ecore_evas_x_sticky_set, + _ecore_evas_x_ignore_events_set, + _ecore_evas_x_alpha_set, + _ecore_evas_x_transparent_set, + _ecore_evas_x_profiles_set, + + _ecore_evas_x_window_group_set, + _ecore_evas_x_aspect_set, + _ecore_evas_x_urgent_set, + _ecore_evas_x_modal_set, + _ecore_evas_x_demand_attention_set, + _ecore_evas_x_focus_skip_set, + + NULL, // render + _ecore_evas_x_screen_geometry_get, + _ecore_evas_x_screen_dpi_get +}; +#endif /* BUILD_ECORE_EVAS_X11 */ + +/* + * FIXME: there are some round trips. Especially, we can split + * ecore_x_init in 2 functions and suppress some round trips. + */ + +#if defined (BUILD_ECORE_EVAS_SOFTWARE_X11) || defined (BUILD_ECORE_EVAS_OPENGL_X11) || defined (BUILD_ECORE_EVAS_SOFTWARE_16_X11) || defined (BUILD_ECORE_EVAS_SOFTWARE_8_X11) +static void +_ecore_evas_x_flush_pre(void *data, Evas *e __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee = data; + + if (ee->no_comp_sync) return; + if (!_ecore_evas_app_comp_sync) return; + if (ee->engine.x.sync_counter) + { + if (ee->engine.x.sync_began) + { + ee->engine.x.sync_val++; + if (!ee->engine.x.sync_cancel) + { + if (!ee->semi_sync) + ecore_x_sync_counter_val_wait(ee->engine.x.sync_counter, + ee->engine.x.sync_val); + } + } + } +} + +static void +_ecore_evas_x_flush_post(void *data, Evas *e __UNUSED__, void *event_info __UNUSED__) +{ + Ecore_Evas *ee = data; + + if ((!ee->no_comp_sync) && (_ecore_evas_app_comp_sync) && + (!ee->gl_sync_draw_done)) // added by gl77.lee + { + if (ee->engine.x.sync_counter) + { + if (ee->engine.x.sync_began) + { + if (!ee->engine.x.sync_cancel) + { + ecore_x_e_comp_sync_draw_size_done_send + (ee->engine.x.win_root, ee->prop.window, ee->w, ee->h); + } + } + } + } + if (ee->engine.x.netwm_sync_set) + { + ecore_x_sync_counter_2_set(ee->engine.x.netwm_sync_counter, + ee->engine.x.netwm_sync_val_hi, + ee->engine.x.netwm_sync_val_lo); + ee->engine.x.netwm_sync_set = 0; + } +} +#endif + +/** + * @brief Create Ecore_Evas using software x11. + * @note If ecore is not compiled with support to x11 then nothing is done and NULL is returned. + * @param disp_name The name of the Ecore_Evas to be created. + * @param parent The parent of the Ecore_Evas to be created. + * @param x The X coordinate to be used. + * @param y The Y coordinate to be used. + * @param w The width of the Ecore_Evas to be created. + * @param h The height of the Ecore_Evas to be created. + * @return A handle to the created Ecore_Evas. + */ +#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 +EAPI Ecore_Evas * +ecore_evas_software_x11_new(const char *disp_name, Ecore_X_Window parent, + int x, int y, int w, int h) +{ + Evas_Engine_Info_Software_X11 *einfo; + Ecore_Evas *ee; + int argb = 0, rmethod; + static int redraw_debug = -1; + char *id = NULL; + + rmethod = evas_render_method_lookup("software_x11"); + if (!rmethod) return NULL; + if (!ecore_x_init(disp_name)) return NULL; + ee = calloc(1, sizeof(Ecore_Evas)); + if (!ee) return NULL; + + ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); + + _ecore_evas_x_init(); + + ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_x_engine_func; + + ee->driver = "software_x11"; + if (disp_name) ee->name = strdup(disp_name); + + if (w < 1) w = 1; + if (h < 1) h = 1; + ee->x = x; + ee->y = y; + ee->w = w; + ee->h = h; + ee->req.x = ee->x; + ee->req.y = ee->y; + ee->req.w = ee->w; + ee->req.h = ee->h; + + ee->prop.max.w = 32767; + ee->prop.max.h = 32767; + ee->prop.layer = 4; + ee->prop.request_pos = 0; + ee->prop.sticky = 0; + ee->engine.x.state.sticky = 0; + + /* init evas here */ + ee->evas = evas_new(); + evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_FLUSH_PRE, + _ecore_evas_x_flush_pre, ee); + evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_FLUSH_POST, + _ecore_evas_x_flush_post, ee); + evas_data_attach_set(ee->evas, ee); + evas_output_method_set(ee->evas, rmethod); + evas_output_size_set(ee->evas, w, h); + evas_output_viewport_set(ee->evas, 0, 0, w, h); + + ee->engine.x.win_root = parent; + ee->engine.x.screen_num = 0; + + if (parent != 0) + { + ee->engine.x.screen_num = 1; /* FIXME: get real scren # */ + /* FIXME: round trip in ecore_x_window_argb_get */ + if (ecore_x_window_argb_get(parent)) + { + ee->prop.window = ecore_x_window_argb_new(parent, x, y, w, h); + argb = 1; + } + else + ee->prop.window = ecore_x_window_new(parent, x, y, w, h); + } + else + ee->prop.window = ecore_x_window_new(parent, x, y, w, h); + if ((id = getenv("DESKTOP_STARTUP_ID"))) + { + ecore_x_netwm_startup_id_set(ee->prop.window, id); + /* NB: on linux this may simply empty the env as opposed to completely + * unset it to being empty - unsure as solartis libc crashes looking + * for the '=' char */ +// putenv((char*)"DESKTOP_STARTUP_ID="); + } + einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas); + if (einfo) + { + Ecore_X_Screen *screen; + + /* FIXME: this is inefficient as its 1 or more round trips */ + screen = ecore_x_default_screen_get(); + if (ecore_x_screen_count_get() > 1) + { + Ecore_X_Window *roots; + int num, i; + + num = 0; + roots = ecore_x_window_root_list(&num); + if (roots) + { + Ecore_X_Window root; + + root = ecore_x_window_root_get(parent); + for (i = 0; i < num; i++) + { + if (root == roots[i]) + { + screen = ecore_x_screen_get(i); + break; + } + } + free(roots); + } + } + + einfo->info.destination_alpha = argb; + + if (redraw_debug < 0) + { + if (getenv("REDRAW_DEBUG")) + redraw_debug = atoi(getenv("REDRAW_DEBUG")); + else + redraw_debug = 0; + } + +# ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB + einfo->info.backend = EVAS_ENGINE_INFO_SOFTWARE_X11_BACKEND_XCB; + einfo->info.connection = ecore_x_connection_get(); + einfo->info.screen = screen; +# else + einfo->info.backend = EVAS_ENGINE_INFO_SOFTWARE_X11_BACKEND_XLIB; + einfo->info.connection = ecore_x_display_get(); + einfo->info.screen = NULL; +# endif + einfo->info.drawable = ee->prop.window; + + if (argb) + { + Ecore_X_Window_Attributes at; + + ecore_x_window_attributes_get(ee->prop.window, &at); + einfo->info.visual = at.visual; + einfo->info.colormap = at.colormap; + einfo->info.depth = at.depth; + einfo->info.destination_alpha = 1; + } + else + { + einfo->info.visual = + ecore_x_default_visual_get(einfo->info.connection, screen); + einfo->info.colormap = + ecore_x_default_colormap_get(einfo->info.connection, screen); + einfo->info.depth = + ecore_x_default_depth_get(einfo->info.connection, screen); + einfo->info.destination_alpha = 0; + } + + einfo->info.rotation = 0; + einfo->info.debug = redraw_debug; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + } + + _ecore_evas_x_hints_update(ee); + _ecore_evas_x_group_leader_set(ee); + ecore_x_window_defaults_set(ee->prop.window); + _ecore_evas_x_protocols_set(ee); + _ecore_evas_x_sync_set(ee); + + ee->engine.func->fn_render = _ecore_evas_x_render; + _ecore_evas_register(ee); + ecore_x_input_multi_select(ee->prop.window); + ecore_event_window_register(ee->prop.window, ee, ee->evas, + (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, + (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, + (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, + (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); + return ee; +} +#else +EAPI Ecore_Evas * +ecore_evas_software_x11_new(const char *disp_name __UNUSED__, Ecore_X_Window parent __UNUSED__, + int x __UNUSED__, int y __UNUSED__, int w __UNUSED__, int h __UNUSED__) +{ + return NULL; +} +#endif + +/** + * @brief Get the window from Ecore_Evas using software x11. + * @note If ecore is not compiled with support for x11 or if @p ee was not + * created with ecore_evas_software_x11_new() then nothing is done and + * 0 is returned. + * @param ee The Ecore_Evas from which to get the window. + * @return The window of type Ecore_X_Window. + */ +#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 +EAPI Ecore_X_Window +ecore_evas_software_x11_window_get(const Ecore_Evas *ee) +{ + if (!(!strcmp(ee->driver, "software_x11"))) return 0; + return (Ecore_X_Window) ecore_evas_window_get(ee); +} +#else +EAPI Ecore_X_Window +ecore_evas_software_x11_window_get(const Ecore_Evas *ee __UNUSED__) +{ + return 0; +} +#endif + +/** + * @brief Set the direct_resize of Ecore_Evas using software x11. + * @note If ecore is not compiled with support to x11 then nothing is done. + * @param ee The Ecore_Evas in which to set direct resize. + * @param on Enables the resize of Ecore_Evas if equals EINA_TRUE, disables if equals EINA_FALSE. + */ +#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 +EAPI void +ecore_evas_software_x11_direct_resize_set(Ecore_Evas *ee, Eina_Bool on) +{ + ee->engine.x.direct_resize = on; + if (ee->prop.avoid_damage) + { + if (ee->engine.x.direct_resize) + { +/* turn this off for now + ee->engine.x.using_bg_pixmap = 1; + ecore_x_window_pixmap_set(ee->prop.window, ee->engine.x.pmap); + */ + } + else + { +/* turn this off too- bg pixmap is controlled by avoid damage directly + ee->engine.x.using_bg_pixmap = 0; + ecore_x_window_pixmap_set(ee->prop.window, 0); + ecore_x_window_area_expose(ee->prop.window, 0, 0, ee->w, ee->h); + */ + } + } +} +#else +EAPI void +ecore_evas_software_x11_direct_resize_set(Ecore_Evas *ee __UNUSED__, Eina_Bool on __UNUSED__) +{ +} +#endif + +/** + * @brief Gets if the Ecore_Evas is being directly resized using software x11. + * @note If ecore is not compiled with support to x11 then nothing is done and EINA_FALSE is returned. + * @param ee The Ecore_Evas from which to get direct resize. + * @return EINA_TRUE if the resize was managed directly, otherwise return EINA_FALSE. + */ +#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 +EAPI Eina_Bool +ecore_evas_software_x11_direct_resize_get(const Ecore_Evas *ee) +{ + return ee->engine.x.direct_resize; +} +#else +EAPI Eina_Bool +ecore_evas_software_x11_direct_resize_get(const Ecore_Evas *ee __UNUSED__) +{ + return 0; +} +#endif + +/** + * @brief Add extra window on Ecore_Evas using software x11. + * @note If ecore is not compiled with support to x11 then nothing is done. + * @param ee The Ecore_Evas on which to add the window. + * @param win The window to be added at the Ecore_Evas. + */ +#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 +EAPI void +ecore_evas_software_x11_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win) +{ + Ecore_X_Window *winp; + + winp = malloc(sizeof(Ecore_X_Window)); + if (winp) + { + *winp = win; + ee->engine.x.win_extra = eina_list_append(ee->engine.x.win_extra, winp); + ecore_x_input_multi_select(win); + ecore_event_window_register(win, ee, ee->evas, + (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, + (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, + (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, + (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); + } +} +#else +EAPI void +ecore_evas_software_x11_extra_event_window_add(Ecore_Evas *ee __UNUSED__, Ecore_X_Window win __UNUSED__) +{ +} +#endif + +/** + * @brief Create Ecore_Evas using opengl x11. + * @note If ecore is not compiled with support to x11 then nothing is done and NULL is returned. + * @param disp_name The name of the display of the Ecore_Evas to be created. + * @param parent The parent of the Ecore_Evas to be created. + * @param x The X coordinate to be used. + * @param y The Y coordinate to be used. + * @param w The width of the Ecore_Evas to be created. + * @param h The height of the Ecore_Evas to be created. + * @return The new Ecore_Evas. + */ +#ifdef BUILD_ECORE_EVAS_OPENGL_X11 +EAPI Ecore_Evas * +ecore_evas_gl_x11_new(const char *disp_name, Ecore_X_Window parent, + int x, int y, int w, int h) +{ + return ecore_evas_gl_x11_options_new(disp_name, parent, x, y, w, h, NULL); +} + +EAPI Ecore_Evas * +ecore_evas_gl_x11_options_new(const char *disp_name, Ecore_X_Window parent, + int x, int y, int w, int h, const int *opt) +{ + Ecore_Evas *ee; + int rmethod; + char *id = NULL; + + rmethod = evas_render_method_lookup("gl_x11"); + if (!rmethod) return NULL; + if (!ecore_x_init(disp_name)) return NULL; + ee = calloc(1, sizeof(Ecore_Evas)); + if (!ee) return NULL; + + ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); + + ee->gl_sync_draw_done = -1; // added by gl77.lee + + _ecore_evas_x_init(); + + ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_x_engine_func; + + ee->driver = "opengl_x11"; +#if 1 + ee->semi_sync = 0; // gl engine doesn't need to sync - its whole swaps +#else + if (!getenv("ECORE_EVAS_COMP_NOSEMISYNC")) + ee->semi_sync = 1; // gl engine doesn't need to sync - its whole swaps +// ee->no_comp_sync = 1; // gl engine doesn't need to sync - its whole swaps +#endif + if (disp_name) ee->name = strdup(disp_name); + + if (w < 1) w = 1; + if (h < 1) h = 1; + ee->x = x; + ee->y = y; + ee->w = w; + ee->h = h; + ee->req.x = ee->x; + ee->req.y = ee->y; + ee->req.w = ee->w; + ee->req.h = ee->h; + + ee->prop.max.w = 32767; + ee->prop.max.h = 32767; + ee->prop.layer = 4; + ee->prop.request_pos = 0; + ee->prop.sticky = 0; + ee->engine.x.state.sticky = 0; + + /* init evas here */ + ee->evas = evas_new(); + evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_FLUSH_PRE, _ecore_evas_x_flush_pre, ee); + evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_FLUSH_POST, _ecore_evas_x_flush_post, ee); + evas_data_attach_set(ee->evas, ee); + evas_output_method_set(ee->evas, rmethod); + evas_output_size_set(ee->evas, w, h); + evas_output_viewport_set(ee->evas, 0, 0, w, h); + + if (parent == 0) parent = DefaultRootWindow(ecore_x_display_get()); + ee->engine.x.win_root = parent; + + if (ee->engine.x.win_root != 0) + { + ee->engine.x.screen_num = 1; /* FIXME: get real scren # */ + /* FIXME: round trip in ecore_x_window_argb_get */ + if (ecore_x_window_argb_get(ee->engine.x.win_root)) + { + ee->prop.window = _ecore_evas_x_gl_window_new + (ee, ee->engine.x.win_root, x, y, w, h, 0, 1, opt); + } + else + ee->prop.window = _ecore_evas_x_gl_window_new + (ee, ee->engine.x.win_root, x, y, w, h, 0, 0, opt); + } + else + ee->prop.window = _ecore_evas_x_gl_window_new + (ee, ee->engine.x.win_root, x, y, w, h, 0, 0, opt); + if (!ee->prop.window) + { + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + if ((id = getenv("DESKTOP_STARTUP_ID"))) + { + ecore_x_netwm_startup_id_set(ee->prop.window, id); + /* NB: on linux this may simply empty the env as opposed to completely + * unset it to being empty - unsure as solartis libc crashes looking + * for the '=' char */ +// putenv((char*)"DESKTOP_STARTUP_ID="); + } + + _ecore_evas_x_hints_update(ee); + _ecore_evas_x_group_leader_set(ee); + ecore_x_window_defaults_set(ee->prop.window); + _ecore_evas_x_protocols_set(ee); + _ecore_evas_x_sync_set(ee); + + ee->engine.func->fn_render = _ecore_evas_x_render; + _ecore_evas_register(ee); + ecore_x_input_multi_select(ee->prop.window); + ecore_event_window_register(ee->prop.window, ee, ee->evas, + (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, + (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, + (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, + (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); + + return ee; +} +#else +EAPI Ecore_Evas * +ecore_evas_gl_x11_new(const char *disp_name __UNUSED__, Ecore_X_Window parent __UNUSED__, + int x __UNUSED__, int y __UNUSED__, int w __UNUSED__, int h __UNUSED__) +{ + return NULL; +} +EAPI Ecore_Evas * +ecore_evas_gl_x11_options_new(const char *disp_name __UNUSED__, Ecore_X_Window parent __UNUSED__, + int x __UNUSED__, int y __UNUSED__, int w __UNUSED__, int h __UNUSED__, const int *opt __UNUSED__) +{ + return NULL; +} +#endif /* ! BUILD_ECORE_EVAS_OPENGL_X11 */ + +/** + * @brief Get the window from Ecore_Evas using opengl x11. + * @note If ecore is not compiled with support for x11 or if @p ee was not + * created with ecore_evas_gl_x11_new() then nothing is done and + * 0 is returned. + * @param ee The Ecore_Evas from which to get the window. + * @return The window of type Ecore_X_Window of Ecore_Evas. + */ +#ifdef BUILD_ECORE_EVAS_OPENGL_X11 +EAPI Ecore_X_Window +ecore_evas_gl_x11_window_get(const Ecore_Evas *ee) +{ + if (!(!strcmp(ee->driver, "opengl_x11"))) return 0; + return (Ecore_X_Window) ecore_evas_window_get(ee); +} +#else +EAPI Ecore_X_Window +ecore_evas_gl_x11_window_get(const Ecore_Evas *ee __UNUSED__) +{ + return 0; +} +#endif /* ! BUILD_ECORE_EVAS_OPENGL_X11 */ + +/** + * @brief Set direct_resize for Ecore_Evas using opengl x11. + * @note If ecore is not compiled with support to x11 then nothing is done. + * @param ee The Ecore_Evas in which to set direct resize. + * @param on Enables the resize of Ecore_Evas if equals EINA_TRUE, disables if equals EINA_FALSE. + */ +#ifdef BUILD_ECORE_EVAS_OPENGL_X11 +EAPI void +ecore_evas_gl_x11_direct_resize_set(Ecore_Evas *ee, Eina_Bool on) +{ + ee->engine.x.direct_resize = on; +} +#else +EAPI void +ecore_evas_gl_x11_direct_resize_set(Ecore_Evas *ee __UNUSED__, Eina_Bool on __UNUSED__) +{ +} +#endif /* ! BUILD_ECORE_EVAS_OPENGL_X11 */ + +/** + * @brief Gets if the Ecore_Evas is being directly resized using opengl x11. + * @note If ecore is not compiled with support to x11 then nothing is done and EINA_FALSE is returned. + * @param ee The Ecore_Evas from which to get direct resize. + * @return EINA_TRUE if the resize was managed directly, otherwise return EINA_FALSE. + */ +#ifdef BUILD_ECORE_EVAS_OPENGL_X11 +EAPI Eina_Bool +ecore_evas_gl_x11_direct_resize_get(const Ecore_Evas *ee) +{ + return ee->engine.x.direct_resize; +} +#else +EAPI Eina_Bool +ecore_evas_gl_x11_direct_resize_get(const Ecore_Evas *ee __UNUSED__) +{ + return 0; +} +#endif /* ! BUILD_ECORE_EVAS_OPENGL_X11 */ + +/** + * @brief Add extra window on Ecore_Evas using opengl x11. + * @note If ecore is not compiled with support to x11 then nothing is done. + * @param ee The Ecore_Evas for which to add the window. + * @param win The window to be added at the Ecore_Evas. + */ +#ifdef BUILD_ECORE_EVAS_OPENGL_X11 +EAPI void +ecore_evas_gl_x11_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win) +{ + ecore_evas_software_x11_extra_event_window_add(ee, win); +} +#else +EAPI void +ecore_evas_gl_x11_extra_event_window_add(Ecore_Evas *ee __UNUSED__, Ecore_X_Window win __UNUSED__) +{ +} +#endif /* ! BUILD_ECORE_EVAS_OPENGL_X11 */ + +/** + * @brief Set the functions to be used before and after the swap callback. + * @note If ecore is not compiled with support to x11 then nothing is done and the function is returned. + * @param ee The Ecore_Evas for which to set the swap callback. + * @param data The data for which to set the swap callback. + * @param pre_cb The function to be called before the callback. + * @param post_cb The function to be called after the callback. + */ +#ifdef BUILD_ECORE_EVAS_OPENGL_X11 +EAPI void +ecore_evas_gl_x11_pre_post_swap_callback_set(const Ecore_Evas *ee, void *data, void (*pre_cb) (void *data, Evas *e), void (*post_cb) (void *data, Evas *e)) +{ + Evas_Engine_Info_GL_X11 *einfo; + + if (!(!strcmp(ee->driver, "opengl_x11"))) return; + + einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas); + if (einfo) + { + einfo->callback.pre_swap = pre_cb; + einfo->callback.post_swap = post_cb; + einfo->callback.data = data; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); + } + } +} +#else +EAPI void +ecore_evas_gl_x11_pre_post_swap_callback_set(const Ecore_Evas *ee __UNUSED__, void *data __UNUSED__, void (*pre_cb) (void *data, Evas *e) __UNUSED__, void (*post_cb) (void *data, Evas *e) __UNUSED__) +{ + return; +} +#endif /* ! BUILD_ECORE_EVAS_OPENGL_X11 */ + +EAPI Ecore_Evas * +ecore_evas_xrender_x11_new(const char *disp_name __UNUSED__, Ecore_X_Window parent __UNUSED__, + int x __UNUSED__, int y __UNUSED__, int w __UNUSED__, int h __UNUSED__) +{ + return NULL; +} + +EAPI Ecore_X_Window +ecore_evas_xrender_x11_window_get(const Ecore_Evas *ee __UNUSED__) +{ + return 0; +} + +EAPI void +ecore_evas_xrender_x11_direct_resize_set(Ecore_Evas *ee __UNUSED__, Eina_Bool on __UNUSED__) +{ +} + +EAPI Eina_Bool +ecore_evas_xrender_x11_direct_resize_get(const Ecore_Evas *ee __UNUSED__) +{ + return 0; +} + +EAPI void +ecore_evas_xrender_x11_extra_event_window_add(Ecore_Evas *ee __UNUSED__, Ecore_X_Window win __UNUSED__) +{ +} + +/** + * @brief Create Ecore_Evas using software 16 x11. + * @note If ecore is not compiled with support to x11 then nothing is done and NULL is returned. + * @param disp_name The name of the display of the Ecore_Evas to be created. + * @param parent The parent of the Ecore_Evas to be created. + * @param x The X coordinate to be used. + * @param y The Y coordinate to be used. + * @param w The width of the Ecore_Evas to be created. + * @param h The height of the Ecore_Evas to be created. + * @return The new Ecore_Evas. + */ +#if BUILD_ECORE_EVAS_SOFTWARE_16_X11 +EAPI Ecore_Evas * +ecore_evas_software_x11_16_new(const char *disp_name, Ecore_X_Window parent, + int x, int y, int w, int h) +{ + Evas_Engine_Info_Software_16_X11 *einfo; + Ecore_Evas *ee; + int rmethod; + static int redraw_debug = -1; + + rmethod = evas_render_method_lookup("software_16_x11"); + if (!rmethod) return NULL; + if (!ecore_x_init(disp_name)) return NULL; + ee = calloc(1, sizeof(Ecore_Evas)); + if (!ee) return NULL; + + ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); + + _ecore_evas_x_init(); + + ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_x_engine_func; + + ee->driver = "software_16_x11"; + if (disp_name) ee->name = strdup(disp_name); + + if (w < 1) w = 1; + if (h < 1) h = 1; + ee->x = x; + ee->y = y; + ee->w = w; + ee->h = h; + ee->req.x = ee->x; + ee->req.y = ee->y; + ee->req.w = ee->w; + ee->req.h = ee->h; + + ee->prop.max.w = 32767; + ee->prop.max.h = 32767; + ee->prop.layer = 4; + ee->prop.request_pos = 0; + ee->prop.sticky = 0; + ee->engine.x.state.sticky = 0; + + /* init evas here */ + ee->evas = evas_new(); + evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_FLUSH_PRE, _ecore_evas_x_flush_pre, ee); + evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_FLUSH_POST, _ecore_evas_x_flush_post, ee); + evas_data_attach_set(ee->evas, ee); + evas_output_method_set(ee->evas, rmethod); + evas_output_size_set(ee->evas, w, h); + evas_output_viewport_set(ee->evas, 0, 0, w, h); + + ee->engine.x.win_root = parent; + if (parent != 0) + { + /* FIXME: round trip in ecore_x_window_argb_get */ + if (ecore_x_window_argb_get(parent)) + { + ee->prop.window = ecore_x_window_argb_new(parent, x, y, w, h); + } + else + ee->prop.window = ecore_x_window_new(parent, x, y, w, h); + } + else + ee->prop.window = ecore_x_window_new(parent, x, y, w, h); + if (getenv("DESKTOP_STARTUP_ID")) + { + ecore_x_netwm_startup_id_set(ee->prop.window, + getenv("DESKTOP_STARTUP_ID")); + /* NB: on linux this may simply empty the env as opposed to completely + * unset it to being empty - unsure as solartis libc crashes looking + * for the '=' char */ +// putenv((char*)"DESKTOP_STARTUP_ID="); + } + einfo = (Evas_Engine_Info_Software_16_X11 *)evas_engine_info_get(ee->evas); + + if (einfo) + { + if (ScreenCount(ecore_x_display_get()) > 1) + { + Ecore_X_Window *roots; + int num, i; + + num = 0; + roots = ecore_x_window_root_list(&num); + if (roots) + { + XWindowAttributes at; + + if (XGetWindowAttributes(ecore_x_display_get(), + parent, &at)) + { + for (i = 0; i < num; i++) + { + if (at.root == roots[i]) + break; + } + } + free(roots); + } + } + + if (redraw_debug < 0) + { + if (getenv("REDRAW_DEBUG")) + redraw_debug = atoi(getenv("REDRAW_DEBUG")); + else + redraw_debug = 0; + } + einfo->info.display = ecore_x_display_get(); + einfo->info.drawable = ee->prop.window; + + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + } + else + { + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + + _ecore_evas_x_hints_update(ee); + _ecore_evas_x_group_leader_set(ee); + ecore_x_window_defaults_set(ee->prop.window); + _ecore_evas_x_protocols_set(ee); + _ecore_evas_x_sync_set(ee); + + ee->engine.func->fn_render = _ecore_evas_x_render; + _ecore_evas_register(ee); + ecore_x_input_multi_select(ee->prop.window); + ecore_event_window_register(ee->prop.window, ee, ee->evas, + (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, + (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, + (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, + (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); + return ee; +} +#else +EAPI Ecore_Evas * +ecore_evas_software_x11_16_new(const char *disp_name __UNUSED__, Ecore_X_Window parent __UNUSED__, + int x __UNUSED__, int y __UNUSED__, int w __UNUSED__, int h __UNUSED__) +{ + return NULL; +} +#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_16_X11 */ + +/** + * @brief Get the window from Ecore_Evas using software 16 x11. + * @note If ecore is not compiled with support for x11 or if @p ee was not + * created with ecore_evas_software_x11_16_new() then nothing is done and + * 0 is returned. + * @param ee The Ecore_Evas from which to get the window. + * @return The window of type Ecore_X_Window of Ecore_Evas. + */ +#if BUILD_ECORE_EVAS_SOFTWARE_16_X11 +EAPI Ecore_X_Window +ecore_evas_software_x11_16_window_get(const Ecore_Evas *ee) +{ + if (!(!strcmp(ee->driver, "software_16_x11"))) return 0; + return (Ecore_X_Window) ecore_evas_window_get(ee); +} +#else +EAPI Ecore_X_Window +ecore_evas_software_x11_16_window_get(const Ecore_Evas *ee __UNUSED__) +{ + return 0; +} +#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_16_X11 */ + +/** + * @brief Set direct_resize for Ecore_Evas using software 16 x11. + * @note If ecore is not compiled with support to x11 then nothing is done. + * @param ee The Ecore_Evas in which to set direct resize. + * @param on Enables the resize of Ecore_Evas if equals EINA_TRUE, disables if equals EINA_FALSE. + */ +#if BUILD_ECORE_EVAS_SOFTWARE_16_X11 +EAPI void +ecore_evas_software_x11_16_direct_resize_set(Ecore_Evas *ee, Eina_Bool on) +{ + ee->engine.x.direct_resize = on; + if (ee->prop.avoid_damage) + { + if (ee->engine.x.direct_resize) + { +/* turn this off for now + ee->engine.x.using_bg_pixmap = 1; + ecore_x_window_pixmap_set(ee->prop.window, ee->engine.x.pmap); + */ + } + else + { +/* turn this off too- bg pixmap is controlled by avoid damage directly + ee->engine.x.using_bg_pixmap = 0; + ecore_x_window_pixmap_set(ee->prop.window, 0); + ecore_x_window_area_expose(ee->prop.window, 0, 0, ee->w, ee->h); + */ + } + } +} +#else +EAPI void +ecore_evas_software_x11_16_direct_resize_set(Ecore_Evas *ee __UNUSED__, Eina_Bool on __UNUSED__) +{ +} +#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_16_X11 */ + +/** + * @brief Gets if the Ecore_Evas is being directly resized using software 16 x11. + * @note If ecore is not compiled with support to x11 then nothing is done and 0 is returned. + * @param ee The Ecore_Evas from which to get direct resize. + * @return EINA_TRUE if the resize was managed directly, otherwise return EINA_FALSE. + */ +#if BUILD_ECORE_EVAS_SOFTWARE_16_X11 +EAPI Eina_Bool +ecore_evas_software_x11_16_direct_resize_get(const Ecore_Evas *ee) +{ + return ee->engine.x.direct_resize; +} +#else +EAPI Eina_Bool +ecore_evas_software_x11_16_direct_resize_get(const Ecore_Evas *ee __UNUSED__) +{ + return 0; +} +#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_16_X11 */ + +/** + * @brief Add extra window on Ecore_Evas using software 16 x11. + * @note If ecore is not compiled with support to x11 then nothing is done. + * @param ee The Ecore_Evas on which to add the window. + * @param win The window to be added at the Ecore_Evas. + */ +#if BUILD_ECORE_EVAS_SOFTWARE_16_X11 +EAPI void +ecore_evas_software_x11_16_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win) +{ + Ecore_X_Window *winp; + + winp = malloc(sizeof(Ecore_X_Window)); + if (winp) + { + *winp = win; + ee->engine.x.win_extra = eina_list_append(ee->engine.x.win_extra, winp); + ecore_x_input_multi_select(win); + ecore_event_window_register(win, ee, ee->evas, + (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, + (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, + (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, + (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); + } +} +#else +EAPI void +ecore_evas_software_x11_16_extra_event_window_add(Ecore_Evas *ee __UNUSED__, Ecore_X_Window win __UNUSED__) +{ +} +#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_16_X11 */ + + +/** + * @brief Create Ecore_Evas using software 8 x11. + * @note If ecore is not compiled with support to x11 then nothing is done and NULL is returned. + * @param disp_name The name of the display of the Ecore_Evas to be created. + * @param parent The parent of the Ecore_Evas to be created. + * @param x The X coordinate to be used. + * @param y The Y coordinate to be used. + * @param w The width of the Ecore_Evas to be created. + * @param h The height of the Ecore_Evas to be created. + * @return The new Ecore_Evas. + */ +EAPI Ecore_Evas * +ecore_evas_software_x11_8_new(const char *disp_name, Ecore_X_Window parent, + int x, int y, int w, int h) +{ +#if defined (BUILD_ECORE_EVAS_SOFTWARE_8_X11) + Evas_Engine_Info_Software_8_X11 *einfo; + Ecore_Evas *ee; + int argb = 0; + int rmethod; + static int redraw_debug = -1; + + rmethod = evas_render_method_lookup("software_8_x11"); + if (!rmethod) return NULL; + if (!ecore_x_init(disp_name)) return NULL; + ee = calloc(1, sizeof(Ecore_Evas)); + if (!ee) return NULL; + + ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); + + _ecore_evas_x_init(); + + ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_x_engine_func; + + ee->driver = "software_8_x11"; + if (disp_name) ee->name = strdup(disp_name); + + if (w < 1) w = 1; + if (h < 1) h = 1; + ee->x = x; + ee->y = y; + ee->w = w; + ee->h = h; + ee->req.x = ee->x; + ee->req.y = ee->y; + ee->req.w = ee->w; + ee->req.h = ee->h; + + ee->prop.max.w = 32767; + ee->prop.max.h = 32767; + ee->prop.layer = 4; + ee->prop.request_pos = 0; + ee->prop.sticky = 0; + ee->engine.x.state.sticky = 0; + + /* init evas here */ + ee->evas = evas_new(); + evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_FLUSH_PRE, _ecore_evas_x_flush_pre, ee); + evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_FLUSH_POST, _ecore_evas_x_flush_post, ee); + evas_data_attach_set(ee->evas, ee); + evas_output_method_set(ee->evas, rmethod); + evas_output_size_set(ee->evas, w, h); + evas_output_viewport_set(ee->evas, 0, 0, w, h); + + ee->engine.x.win_root = parent; + // if (parent != 0) + // { + // /* FIXME: round trip in ecore_x_window_argb_get */ + // if (ecore_x_window_argb_get(parent)) + // { + // ee->engine.x.win = ecore_x_window_argb_new(parent, x, y, w, h); + // argb = 1; + // } + // else + // ee->engine.x.win = ecore_x_window_new(parent, x, y, w, h); + // } + // else + ee->prop.window = ecore_x_window_new(parent, x, y, w, h); + if (getenv("DESKTOP_STARTUP_ID")) + { + ecore_x_netwm_startup_id_set(ee->prop.window, + getenv("DESKTOP_STARTUP_ID")); + /* NB: on linux this may simply empty the env as opposed to completely + * unset it to being empty - unsure as solartis libc crashes looking + * for the '=' char */ + // putenv((char*)"DESKTOP_STARTUP_ID="); + } + einfo = (Evas_Engine_Info_Software_8_X11 *)evas_engine_info_get(ee->evas); + if (einfo) + { + xcb_screen_iterator_t iter; + xcb_screen_t *screen; + + /* FIXME: this is inefficient as its a round trip */ + //einfo->info.backend = 1; + screen = ecore_x_default_screen_get(); + iter = xcb_setup_roots_iterator (xcb_get_setup (ecore_x_connection_get())); + if (iter.rem > 1) + { + xcb_get_geometry_cookie_t cookie; + xcb_get_geometry_reply_t *reply; + Ecore_X_Window *roots; + int num; + uint8_t i; + + num = 0; + cookie = xcb_get_geometry_unchecked(ecore_x_connection_get(), parent); + roots = ecore_x_window_root_list(&num); + if (roots) + { + reply = xcb_get_geometry_reply(ecore_x_connection_get(), cookie, NULL); + + if (reply) + { + for (i = 0; i < num; xcb_screen_next (&iter), i++) + { + if (reply->root == roots[i]) + { + screen = iter.data; + break; + } + } + free(reply); + } + free(roots); + } + else + { + reply = xcb_get_geometry_reply(ecore_x_connection_get(), cookie, NULL); + if (reply) free(reply); + } + } + + if (redraw_debug < 0) + { + if (getenv("REDRAW_DEBUG")) + redraw_debug = atoi(getenv("REDRAW_DEBUG")); + else + redraw_debug = 0; + } + einfo->info.connection = ecore_x_connection_get(); + einfo->info.screen = screen; + einfo->info.drawable = ee->prop.window; + if (argb) + { + /* FIXME: round trip */ + xcb_get_geometry_cookie_t cookie_geom; + xcb_get_window_attributes_cookie_t cookie_attr; + xcb_get_geometry_reply_t *reply_geom; + xcb_get_window_attributes_reply_t *reply_attr; + + cookie_geom = xcb_get_geometry_unchecked(ecore_x_connection_get(), ee->prop.window); + cookie_attr = xcb_get_window_attributes_unchecked(ecore_x_connection_get(), ee->prop.window); + + reply_geom = xcb_get_geometry_reply(ecore_x_connection_get(), cookie_geom, NULL); + reply_attr = xcb_get_window_attributes_reply(ecore_x_connection_get(), cookie_attr, NULL); + if (reply_attr && reply_geom) + { + einfo->info.visual = xcb_visualtype_get(ecore_x_default_screen_get(), reply_attr->visual); + einfo->info.colormap = reply_attr->colormap; + einfo->info.depth = reply_geom->depth; + einfo->info.destination_alpha = 1; + free(reply_geom); + free(reply_attr); + } + } + else + { + xcb_screen_t *screen; + + screen = ecore_x_default_screen_get(); + einfo->info.visual = xcb_visualtype_get(screen, screen->root_visual); + einfo->info.colormap = screen->default_colormap; + einfo->info.depth = screen->root_depth; + einfo->info.destination_alpha = 0; + } + einfo->info.rotation = 0; + einfo->info.debug = redraw_debug; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + } + else + { + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; + } + + _ecore_evas_x_hints_update(ee); + _ecore_evas_x_group_leader_set(ee); + ecore_x_window_defaults_set(ee->prop.window); + _ecore_evas_x_protocols_set(ee); + _ecore_evas_x_sync_set(ee); + + ee->engine.func->fn_render = _ecore_evas_x_render; + _ecore_evas_register(ee); + ecore_x_input_multi_select(ee->prop.window); + ecore_event_window_register(ee->prop.window, ee, ee->evas, + (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, + (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, + (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, + (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); + + return ee; +#else + return NULL; + (void)(disp_name); + (void)(parent); + (void)(x); + (void)(y); + (void)(w); + (void)(h); +#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_8_X11 */ +} + +/** + * @brief Get window from Ecore_Evas using software 8 x11. + * @note If ecore is not compiled with support for x11 or if @p ee was not + * created with ecore_evas_software_x11_8_new() then nothing is done and + * 0 is returned. + * @param ee The Ecore_Evas from which to get the window. + * @return The window of type Ecore_X_Window of Ecore_Evas. + */ +EAPI Ecore_X_Window +ecore_evas_software_x11_8_window_get(const Ecore_Evas *ee) +{ +#if defined (BUILD_ECORE_EVAS_SOFTWARE_8_X11) + if (!(!strcmp(ee->driver, "software_8_x11"))) return 0; + return (Ecore_X_Window) ecore_evas_window_get(ee); +#else + return 0; + (void)(ee); +#endif +} + +/** + * @brief Get subwindow from Ecore_Evas using software 8 x11. + * @note If ecore is not compiled with support for x11 or if @p ee was not + * created with ecore_evas_software_x11_8_new() then nothing is done and + * 0 is returned. + * @param ee The Ecore_Evas from which to get the subwindow. + * @return The window of type Ecore_X_Window of Ecore_Evas. + */ +EAPI Ecore_X_Window +ecore_evas_software_x11_8_subwindow_get(const Ecore_Evas *ee) +{ +#if defined (BUILD_ECORE_EVAS_SOFTWARE_8_X11) + if (!(!strcmp(ee->driver, "software_8_x11"))) return 0; + return (Ecore_X_Window) ecore_evas_window_get(ee); +#else + return 0; + (void)(ee); +#endif +} + +/** + * @brief Set direct_size for Ecore_Evas using software 8 x11. + * @note If ecore is not compiled with support to x11 then nothing is done and the function is returned. + * @param ee The Ecore_Evas in which to set direct resize. + * @param on Enables the resize of Ecore_Evas if equals EINA_TRUE, disables if equals EINA_FALSE. + */ +EAPI void +ecore_evas_software_x11_8_direct_resize_set(Ecore_Evas *ee, Eina_Bool on) +{ +#if defined (BUILD_ECORE_EVAS_SOFTWARE_8_X11) + ee->engine.x.direct_resize = on; + if (ee->prop.avoid_damage) + { + if (ee->engine.x.direct_resize) + { + /* turn this off for now + ee->engine.x.using_bg_pixmap = 1; + ecore_x_window_pixmap_set(ee->engine.x.win, ee->engine.x.pmap); + */ + } + else + { + /* turn this off too- bg pixmap is controlled by avoid damage directly + ee->engine.x.using_bg_pixmap = 0; + ecore_x_window_pixmap_set(ee->engine.x.win, 0); + ecore_x_window_area_expose(ee->engine.x.win, 0, 0, ee->w, ee->h); + */ + } + } +#else + return; + (void)(ee); + (void)(on); +#endif +} + +/** + * @brief Gets if the Ecore_Evas is being directly resized using software 8 x11. + * @note If ecore is not compiled with support to x11 then nothing is done and 0 is returned. + * @param ee The Ecore_Evas from which to get direct resize. + * @return EINA_TRUE if the resize was managed directly, otherwise return EINA_FALSE. + */ +EAPI Eina_Bool +ecore_evas_software_x11_8_direct_resize_get(const Ecore_Evas *ee) +{ +#if defined (BUILD_ECORE_EVAS_SOFTWARE_8_X11) + return ee->engine.x.direct_resize; +#else + return 0; + (void)(ee); +#endif +} + +/** + * @brief Add extra window on Ecore_Evas using software 8 x11. + * @note If ecore is not compiled with support to x11 then nothing is done and the function is returned. + * @param ee The Ecore_Evas on which to add the window. + * @param win The window to be added at Ecore_Evas. + */ +EAPI void +ecore_evas_software_x11_8_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win) +{ +#if defined (BUILD_ECORE_EVAS_SOFTWARE_8_X11) + Ecore_X_Window *winp; + + winp = malloc(sizeof(Ecore_X_Window)); + if (winp) + { + *winp = win; + ee->engine.x.win_extra = eina_list_append(ee->engine.x.win_extra, winp); + ecore_x_input_multi_select(win); + ecore_event_window_register(win, ee, ee->evas, + (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, + (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, + (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, + (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); + } +#else + return; + (void)(ee); + (void)(win); +#endif +} + +EAPI void +ecore_evas_x11_leader_set(Ecore_Evas *ee, Ecore_X_Window win) +{ +#ifdef BUILD_ECORE_EVAS_X11 + _ecore_evas_x_group_leader_unset(ee); + ee->engine.x.leader = win; + _ecore_evas_x_group_leader_update(ee); +#else + return; + ee = NULL; + win = 0; +#endif +} + +EAPI Ecore_X_Window +ecore_evas_x11_leader_get(Ecore_Evas *ee) +{ +#ifdef BUILD_ECORE_EVAS_X11 + return ee->engine.x.leader; +#else + return 0; + ee = NULL; +#endif +} + +EAPI void +ecore_evas_x11_leader_default_set(Ecore_Evas *ee) +{ +#ifdef BUILD_ECORE_EVAS_X11 + _ecore_evas_x_group_leader_unset(ee); + _ecore_evas_x_group_leader_set(ee); +#else + return; + ee = NULL; +#endif +} + +#ifdef BUILD_ECORE_EVAS_X11 +static Eina_Bool +_ecore_evas_x11_convert_rectangle_with_angle(Ecore_Evas *ee, Ecore_X_Rectangle *dst_rect, Ecore_X_Rectangle *src_rect) +{ + if ((!src_rect) || (!dst_rect)) return 0; + + if (ee->rotation == 0) + { + dst_rect->x = src_rect->x; + dst_rect->y = src_rect->y; + dst_rect->width = src_rect->width; + dst_rect->height = src_rect->height; + } + else if (ee->rotation == 90) + { + dst_rect->x = src_rect->y; + dst_rect->y = ee->req.h - src_rect->x - src_rect->width; + dst_rect->width = src_rect->height; + dst_rect->height = src_rect->width; + } + else if (ee->rotation == 180) + { + dst_rect->x = ee->req.w - src_rect->x - src_rect->width; + dst_rect->y = ee->req.h - src_rect->y - src_rect->height; + dst_rect->width = src_rect->width; + dst_rect->height = src_rect->height; + } + else if (ee->rotation == 270) + { + dst_rect->x = ee->req.w - src_rect->y - src_rect->height; + dst_rect->y = src_rect->x; + dst_rect->width = src_rect->height; + dst_rect->height = src_rect->width; + } + else + { + return 0; + } + + return 1; +} +#endif + +EAPI void +ecore_evas_x11_shape_input_rectangle_set(Ecore_Evas *ee, int x, int y, int w, int h) +{ +#ifdef BUILD_ECORE_EVAS_X11 + Eina_Bool ret; + Ecore_X_Rectangle src_rect; + Ecore_X_Rectangle dst_rect; + + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_x11_shape_input_rectangle_set"); + return; + } + + src_rect.x = x; + src_rect.y = y; + src_rect.width = w; + src_rect.height = h; + + dst_rect.x = 0; + dst_rect.y = 0; + dst_rect.width = 0; + dst_rect.height = 0; + + ret = _ecore_evas_x11_convert_rectangle_with_angle(ee, &dst_rect, &src_rect); + + if (!ee->engine.x.win_shaped_input) + ee->engine.x.win_shaped_input = ecore_x_window_override_new(ee->engine.x.win_root, + 0, 0, 1, 1); + + if (ret) + ecore_x_window_shape_input_rectangle_set(ee->engine.x.win_shaped_input, + dst_rect.x, dst_rect.y, + dst_rect.width, dst_rect.height); +#else + return; + ee = NULL; + x = 0; + y = 0; + w = 0; + h = 0; +#endif +} + +EAPI void +ecore_evas_x11_shape_input_rectangle_add(Ecore_Evas *ee, int x, int y, int w, int h) +{ +#ifdef BUILD_ECORE_EVAS_X11 + Eina_Bool ret; + Ecore_X_Rectangle src_rect; + Ecore_X_Rectangle dst_rect; + + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_x11_shape_input_rectangle_add"); + return; + } + + src_rect.x = x; + src_rect.y = y; + src_rect.width = w; + src_rect.height = h; + + dst_rect.x = 0; + dst_rect.y = 0; + dst_rect.width = 0; + dst_rect.height = 0; + + ret = _ecore_evas_x11_convert_rectangle_with_angle(ee, &dst_rect, &src_rect); + + if (!ee->engine.x.win_shaped_input) + ee->engine.x.win_shaped_input = ecore_x_window_override_new(ee->engine.x.win_root, + 0, 0, 1, 1); + + if (ret) + ecore_x_window_shape_input_rectangle_add(ee->engine.x.win_shaped_input, + dst_rect.x, dst_rect.y, + dst_rect.width, dst_rect.height); +#else + return; + ee = NULL; + x = 0; + y = 0; + w = 0; + h = 0; +#endif +} + +EAPI void +ecore_evas_x11_shape_input_rectangle_subtract(Ecore_Evas *ee, int x, int y, int w, int h) +{ +#ifdef BUILD_ECORE_EVAS_X11 + Eina_Bool ret; + Ecore_X_Rectangle src_rect; + Ecore_X_Rectangle dst_rect; + + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_x11_shape_input_rectangle_subtract"); + return; + } + + src_rect.x = x; + src_rect.y = y; + src_rect.width = w; + src_rect.height = h; + + dst_rect.x = 0; + dst_rect.y = 0; + dst_rect.width = 0; + dst_rect.height = 0; + + ret = _ecore_evas_x11_convert_rectangle_with_angle(ee, &dst_rect, &src_rect); + + if (!ee->engine.x.win_shaped_input) + ee->engine.x.win_shaped_input = ecore_x_window_override_new(ee->engine.x.win_root, + 0, 0, 1, 1); + + if (ret) + ecore_x_window_shape_input_rectangle_subtract(ee->engine.x.win_shaped_input, + dst_rect.x, dst_rect.y, + dst_rect.width, dst_rect.height); +#else + return; + ee = NULL; + x = 0; + y = 0; + w = 0; + h = 0; +#endif +} + +EAPI void +ecore_evas_x11_shape_input_empty(Ecore_Evas *ee) +{ +#ifdef BUILD_ECORE_EVAS_X11 + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_x11_shape_input_empty"); + return; + } + + if (!ee->engine.x.win_shaped_input) + ee->engine.x.win_shaped_input = ecore_x_window_override_new(ee->engine.x.win_root, 0, 0, 1, 1); + + ecore_x_window_shape_input_rectangle_set(ee->engine.x.win_shaped_input, 0, 0, 0, 0); +#else + return; + ee = NULL; +#endif +} + +EAPI void +ecore_evas_x11_shape_input_reset(Ecore_Evas *ee) +{ +#ifdef BUILD_ECORE_EVAS_X11 + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_x11_shape_input_reset"); + return; + } + + if (!ee->engine.x.win_shaped_input) + ee->engine.x.win_shaped_input = ecore_x_window_override_new(ee->engine.x.win_root, 0, 0, 1, 1); + + ecore_x_window_shape_input_rectangle_set(ee->engine.x.win_shaped_input, 0, 0, 65535, 65535); +#else + return; + ee = NULL; +#endif +} + +EAPI void +ecore_evas_x11_shape_input_apply(Ecore_Evas *ee) +{ +#ifdef BUILD_ECORE_EVAS_X11 + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_x11_shape_input_apply"); + return; + } + + if (!ee->engine.x.win_shaped_input) return; + + ecore_x_window_shape_input_window_set(ee->prop.window, ee->engine.x.win_shaped_input); +#else + return; + ee = NULL; +#endif +} diff --git a/src/lib/ecore_fb/Ecore_Fb.h b/src/lib/ecore_fb/Ecore_Fb.h new file mode 100644 index 0000000..069cccd --- /dev/null +++ b/src/lib/ecore_fb/Ecore_Fb.h @@ -0,0 +1,100 @@ +#ifndef _ECORE_FB_H +#define _ECORE_FB_H + +#include + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +#else +# define EAPI +#endif + +/* FIXME: + * maybe a new module? + * - code to get battery info + * - code to get thermal info + * ecore evas fb isn't good enough for weird things, like multiple fb's, same happens here. + * backlight support using new kernel interface + * absolute axis + * joystick + * ecore_fb_li_device_close_all ? or a shutdown of the subsystem? + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup Ecore_FB_Group Ecore_FB - Frame buffer convenience functions. + * + * Functions used to set up and shut down the Ecore_Framebuffer functions. + * + * @{ + */ + +/** + * @typedef Ecore_Fb_Input_Device + * Input device handler. + */ +typedef struct _Ecore_Fb_Input_Device Ecore_Fb_Input_Device; + +/** + * @enum _Ecore_Fb_Input_Device_Cap + * Device capabilities. + */ +enum _Ecore_Fb_Input_Device_Cap +{ + ECORE_FB_INPUT_DEVICE_CAP_NONE = 0x00000000, + ECORE_FB_INPUT_DEVICE_CAP_RELATIVE = 0x00000001, + ECORE_FB_INPUT_DEVICE_CAP_ABSOLUTE = 0x00000002, + ECORE_FB_INPUT_DEVICE_CAP_KEYS_OR_BUTTONS = 0x00000004 +}; + +/** + * @typedef Ecore_Fb_Input_Device_Cap + * Device capabilities. + */ +typedef enum _Ecore_Fb_Input_Device_Cap Ecore_Fb_Input_Device_Cap; + +/* ecore_fb_vt.c */ +EAPI void ecore_fb_callback_gain_set(void (*func) (void *data), void *data); +EAPI void ecore_fb_callback_lose_set(void (*func) (void *data), void *data); + +/* ecore_fb_li.c */ +EAPI Ecore_Fb_Input_Device *ecore_fb_input_device_open(const char *dev); +EAPI void ecore_fb_input_device_close(Ecore_Fb_Input_Device *dev); +EAPI void ecore_fb_input_device_listen(Ecore_Fb_Input_Device *dev, Eina_Bool listen); +EAPI const char *ecore_fb_input_device_name_get(Ecore_Fb_Input_Device *dev); +EAPI Ecore_Fb_Input_Device_Cap ecore_fb_input_device_cap_get(Ecore_Fb_Input_Device *dev); +EAPI void ecore_fb_input_device_axis_size_set(Ecore_Fb_Input_Device *dev, int w, int h); +EAPI void ecore_fb_input_threshold_click_set(Ecore_Fb_Input_Device *dev, double threshold); +EAPI double ecore_fb_input_threshold_click_get(Ecore_Fb_Input_Device *dev); +EAPI void ecore_fb_input_device_window_set(Ecore_Fb_Input_Device *dev, void *window); + +/* ecore_fb.c */ + +EAPI int ecore_fb_init(const char *name); +EAPI int ecore_fb_shutdown(void); +EAPI void ecore_fb_size_get(int *w, int *h); + +EAPI void ecore_fb_touch_screen_calibrate_set(int xscale, int xtrans, int yscale, int ytrans, int xyswap); +EAPI void ecore_fb_touch_screen_calibrate_get(int *xscale, int *xtrans, int *yscale, int *ytrans, int *xyswap); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/ecore_fb/Makefile.am b/src/lib/ecore_fb/Makefile.am new file mode 100644 index 0000000..9129fec --- /dev/null +++ b/src/lib/ecore_fb/Makefile.am @@ -0,0 +1,34 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_builddir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore_input \ +@TSLIB_CFLAGS@ \ +@EINA_CFLAGS@ + + +lib_LTLIBRARIES = libecore_fb.la +includes_HEADERS = Ecore_Fb.h +includesdir = $(includedir)/ecore-@VMAJ@ + +libecore_fb_la_SOURCES = \ +ecore_fb.c \ +ecore_fb_vt.c \ +ecore_fb_li.c \ +ecore_fb_ts.c +# deprecated sources (might not compile): +# ecore_fb_kbd.c +# ecore_fb_ps2.c + +libecore_fb_la_LIBADD = \ +@TSLIB_LIBS@ \ +$(top_builddir)/src/lib/ecore/libecore.la \ +$(top_builddir)/src/lib/ecore_input/libecore_input.la \ +@EINA_LIBS@ + +libecore_fb_la_LDFLAGS = -version-info @version_info@ @release_info@ + +EXTRA_DIST = \ +ecore_fb_private.h \ +ecore_fb_keytable.h diff --git a/src/lib/ecore_fb/ecore_fb.c b/src/lib/ecore_fb/ecore_fb.c new file mode 100644 index 0000000..5b2b84b --- /dev/null +++ b/src/lib/ecore_fb/ecore_fb.c @@ -0,0 +1,129 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "Ecore_Fb.h" +#include "ecore_fb_private.h" + +static void _ecore_fb_size_get(int *w, int *h); + +static int _ecore_fb_init_count = 0; +static int _ecore_fb_console_w = 0; +static int _ecore_fb_console_h = 0; + +/** + * @addtogroup Ecore_FB_Group Ecore_FB - Frame buffer convenience functions. + * + * @{ + */ + +static sighandler_t oldhand = NULL; + +static void +nosigint(int val __UNUSED__) +{ +} + +/** + * @brief Initialize the Ecore_Fb library. + * + * @param name Device target name. + * @return 1 or greater on success, 0 on error. + * + * This function sets up all the Ecore_Fb library. It returns 0 on + * failure, otherwise it returns the number of times it has already + * been called. + * + * When Ecore_Fb is not used anymore, call ecore_fb_shutdown() to shut down + * the Ecore_Fb library. + */ +EAPI int +ecore_fb_init(const char *name __UNUSED__) +{ + if (++_ecore_fb_init_count != 1) + return _ecore_fb_init_count; + + if (!ecore_fb_vt_init()) + return --_ecore_fb_init_count; + + if (!oldhand) + { + oldhand = signal(SIGINT, nosigint); + } + + _ecore_fb_size_get(&_ecore_fb_console_w, &_ecore_fb_console_h); + + return _ecore_fb_init_count; +} + +/** + * @brief Shut down the Ecore_Fb library. + * + * @return 0 when the library is completely shut down, 1 or + * greater otherwise. + * + * This function shuts down the Ecore_Fb library. It returns 0 when it has + * been called the same number of times than ecore_fb_init(). + */ +EAPI int +ecore_fb_shutdown(void) +{ + if (--_ecore_fb_init_count != 0) + return _ecore_fb_init_count; + + if (oldhand) + { + signal(SIGINT, oldhand); + oldhand = NULL; + } + + ecore_fb_vt_shutdown(); + + return _ecore_fb_init_count; +} + + +/** + * @brief Retrieve the width and height of the current frame buffer in + * pixels. + * + * @param w Pointer to an integer in which to store the width. + * @param h Pointer to an interge in which to store the height. + * + * This function retrieves the size of the current frame buffer in + * pixels. @p w and @p h can be buffers that will be filled with the + * corresponding values. If one of them is @c NULL, nothing will be + * done for that parameter. + */ +EAPI void +ecore_fb_size_get(int *w, int *h) +{ + if (w) *w = _ecore_fb_console_w; + if (h) *h = _ecore_fb_console_h; +} + +static void +_ecore_fb_size_get(int *w, int *h) +{ + struct fb_var_screeninfo fb_var; + int fb; + + fb = open("/dev/fb0", O_RDWR); + if (fb < 0) + goto exit; + + if (ioctl(fb, FBIOGET_VSCREENINFO, &fb_var) == -1) + goto err_ioctl; + + *w = fb_var.xres; + *h = fb_var.yres; + +err_ioctl: + close(fb); +exit: + return; +} + +/** + * @} + */ diff --git a/src/lib/ecore_fb/ecore_fb_kbd.c b/src/lib/ecore_fb/ecore_fb_kbd.c new file mode 100644 index 0000000..f9cdc3d --- /dev/null +++ b/src/lib/ecore_fb/ecore_fb_kbd.c @@ -0,0 +1,326 @@ +static void _ecore_fb_event_free_key_down(void *data, void *ev); +static void _ecore_fb_event_free_key_up(void *data, void *ev); + +static const char *_ecore_fb_kbd_syms[128 * 7] = +{ +#include "ecore_fb_keytable.h" +}; + +static const char *_ecore_fb_btn_syms[128] = +{ + "0x00", + "Escape", + "F1", + "F2", + "F3", + "F4", + "Up", + "Right", + "Left", + "Down", + "Return", + "0x1b", + "0x1c", + "0x1d", + "0x1e", + "0x1f", + "0x20", + "0x21", + "0x22", + "0x23", + "0x24", + "0x25", + "0x26", + "0x27", + "0x28", + "0x29", + "0x2a", + "0x2b", + "0x2c", + "0x2d", + "0x2e", + "0x2f", + "0x30", + "0x31", + "0x32", + "0x33", + "0x34", + "0x35", + "0x36", + "0x37", + "0x38", + "0x39", + "0x3a", + "0x3b", + "0x3c", + "0x3d", + "0x3e", + "0x3f", + "0x40", + "0x41", + "0x42", + "0x43", + "0x44", + "0x45", + "0x46", + "0x47", + "0x48", + "0x49", + "0x4a", + "0x4b", + "0x4c", + "0x4d", + "0x4e", + "0x4f", + "0x50", + "0x51", + "0x52", + "0x53", + "0x54", + "0x55", + "0x56", + "0x57", + "0x58", + "0x59", + "0x5a", + "0x5b", + "0x5c", + "0x5d", + "0x5e", + "0x5f", + "0x60", + "0x61", + "0x62", + "0x63", + "0x64", + "0x65", + "0x66", + "0x67", + "0x68", + "0x69", + "0x6a", + "0x6b", + "0x6c", + "0x6d", + "0x6e", + "0x6f", + "0x70", + "0x71", + "0x72", + "0x73", + "0x74", + "0x75", + "0x76", + "0x77", + "0x78", + "0x79", + "0x7a", + "0x7b", + "0x7c", + "0x7d", + "0x7e", + "0x7f" +}; +static int _ecore_fb_kbd_fd = -1; +static int _ecore_fb_ctrl = 0; +static int _ecore_fb_alt = 0; +static int _ecore_fb_shift = 0; +static int _ecore_fb_lock = 0; + +static Ecore_Fd_Handler *_ecore_fb_kbd_fd_handler_handle = NULL; +static Eina_Bool _ecore_fb_kbd_fd_handler(void *data, Ecore_Fd_Handler *fd_handler); + +static void +_ecore_fb_event_free_key_down(void *data __UNUSED__, void *ev) +{ + Ecore_Fb_Event_Key_Up *e; + e = ev; + free(e->keyname); + if (e->keysymbol) free(e->keysymbol); + if (e->key_compose) free(e->key_compose); + free(e); +} + +static void +_ecore_fb_event_free_key_up(void *data __UNUSED__, void *ev) +{ + Ecore_Fb_Event_Key_Up *e; + + e = ev; + free(e->keyname); + if (e->keysymbol) free(e->keysymbol); + if (e->key_compose) free(e->key_compose); + free(e); +} + +static Eina_Bool +_ecore_fb_kbd_fd_handler(void *data __UNUSED__, Ecore_Fd_Handler *fd_handler __UNUSED__) +{ + int v = 0; + + do + { + unsigned char buf; + + v = read(_ecore_fb_kbd_fd, &buf, 1); + if (v < 0) return EINA_TRUE; + if (v < 1) return EINA_TRUE; + if (!(buf & 0x80)) + { + /* DOWN */ + int vt_switch = -1; + Ecore_Fb_Event_Key_Down *e; + + e = calloc(1, sizeof(Ecore_Fb_Event_Key_Down)); + if (!e) goto retry; + if (_ecore_fb_kbd_fd == _ecore_fb_tty_fd) + { + int add = 0; + + if (_ecore_fb_shift) add = 1; + else if (_ecore_fb_lock) add = 2; + e->keyname = strdup(_ecore_fb_kbd_syms[(buf & 0x7f) * 7]); + e->keysymbol = strdup(_ecore_fb_kbd_syms[((buf & 0x7f) * 7) + add]); + e->key_compose = strdup(_ecore_fb_kbd_syms[((buf & 0x7f) * 7) + 3 + add]); + } + else + e->keyname = strdup(_ecore_fb_btn_syms[buf & 0x7f]); + if (!e->keyname) + { + free(e); + goto retry; + } + e->window = 1; + e->event_window = e->window; + e->root_window = e->window; + e->same_screen = 1; + e->timestamp = ecore_loop_time_get() * 1000.0; + if (!strcmp(e->keyname, "Control_L")) + _ecore_fb_ctrl++; + else if (!strcmp(e->keyname, "Control_R")) + _ecore_fb_ctrl++; + else if (!strcmp(e->keyname, "Alt_L")) + _ecore_fb_alt++; + else if (!strcmp(e->keyname, "Alt_R")) + _ecore_fb_alt++; + else if (!strcmp(e->keyname, "Shift_L")) + _ecore_fb_shift++; + else if (!strcmp(e->keyname, "Shift_R")) + _ecore_fb_shift++; + else if (!strcmp(e->keyname, "Caps_Lock")) + _ecore_fb_lock++; + else if (!strcmp(e->keyname, "F1")) vt_switch = 0; + else if (!strcmp(e->keyname, "F2")) vt_switch = 1; + else if (!strcmp(e->keyname, "F3")) vt_switch = 2; + else if (!strcmp(e->keyname, "F4")) vt_switch = 3; + else if (!strcmp(e->keyname, "F5")) vt_switch = 4; + else if (!strcmp(e->keyname, "F6")) vt_switch = 5; + else if (!strcmp(e->keyname, "F7")) vt_switch = 6; + else if (!strcmp(e->keyname, "F8")) vt_switch = 7; + else if (!strcmp(e->keyname, "F9")) vt_switch = 8; + else if (!strcmp(e->keyname, "F10")) vt_switch = 9; + else if (!strcmp(e->keyname, "F11")) vt_switch = 10; + else if (!strcmp(e->keyname, "F12")) vt_switch = 11; + if (_ecore_fb_ctrl > 2) _ecore_fb_ctrl = 2; + if (_ecore_fb_alt > 2) _ecore_fb_alt = 2; + if ((_ecore_fb_kbd_fd == _ecore_fb_tty_fd) && + (_ecore_fb_ctrl)) + { + const char *ts = _ecore_fb_kbd_syms[(buf & 0x7f) + 3 + 3]; + + if (ts) + { + if (e->key_compose) free(e->key_compose); + e->key_compose = strdup(ts); + } + } + if ((vt_switch >= 0) && + (_ecore_fb_ctrl) && + (_ecore_fb_alt)) + _ecore_fb_vt_switch(vt_switch); + ecore_event_add(ECORE_FB_EVENT_KEY_DOWN, e, _ecore_fb_event_free_key_down, NULL); + } + else + { + /* UP */ + Ecore_Fb_Event_Key_Up *e; + + e = calloc(1, sizeof(Ecore_Fb_Event_Key_Up)); + if (!e) goto retry; + if (_ecore_fb_kbd_fd == _ecore_fb_tty_fd) + { + int add = 0; + + if (_ecore_fb_shift) add = 1; + else if (_ecore_fb_lock) add = 2; + e->keyname = strdup(_ecore_fb_kbd_syms[(buf & 0x7f) * 7]); + e->keysymbol = strdup(_ecore_fb_kbd_syms[((buf & 0x7f) * 7) + add]); + e->key_compose = strdup(_ecore_fb_kbd_syms[((buf & 0x7f) * 7) + 3 + add]); + } + else + e->keyname = strdup(_ecore_fb_btn_syms[buf & 0x7f]); + if (!e->keyname) + { + free(e); + goto retry; + } + e->window = 1; + e->event_window = e->window; + e->root_window = e->window; + e->same_screen = 1; + e->timestamp = ecore_loop_time_get() * 1000.0; + ecore_event_add(ECORE_FB_EVENT_KEY_UP, e, _ecore_fb_event_free_key_up, NULL); + if (!strcmp(e->keyname, "Control_L")) + _ecore_fb_ctrl--; + else if (!strcmp(e->keyname, "Control_R")) + _ecore_fb_ctrl--; + else if (!strcmp(e->keyname, "Alt_L")) + _ecore_fb_alt--; + else if (!strcmp(e->keyname, "Alt_R")) + _ecore_fb_alt--; + else if (!strcmp(e->keyname, "Shift_L")) + _ecore_fb_shift--; + else if (!strcmp(e->keyname, "Shift_R")) + _ecore_fb_shift--; + else if (!strcmp(e->keyname, "Caps_Lock")) + _ecore_fb_lock--; + if (_ecore_fb_ctrl < 0) _ecore_fb_ctrl = 0; + if (_ecore_fb_alt < 0) _ecore_fb_alt = 0; + if (_ecore_fb_shift < 0) _ecore_fb_shift = 0; + if (_ecore_fb_lock < 0) _ecore_fb_lock = 0; + } +retry: + ; + } + while (v > 0); + return EINA_TRUE; +} + +int +ecore_fb_kbd_init(void) +{ + int prev_flags; + + prev_flags = fcntl(_ecore_fb_kbd_fd, F_GETFL); + fcntl(_ecore_fb_kbd_fd, F_SETFL, prev_flags | O_NONBLOCK); + _ecore_fb_kbd_fd_handler_handle = ecore_main_fd_handler_add(_ecore_fb_kbd_fd, + ECORE_FD_READ, + _ecore_fb_kbd_fd_handler, NULL, + NULL, NULL); + if(!_ecore_fb_kbd_fd_handler_handle) return 0; + return 1; +} + +void +ecore_fb_kbd_shutdown(void) +{ + if (_ecore_fb_kbd_fd_handler_handle) + ecore_main_fd_handler_del(_ecore_fb_kbd_fd_handler_handle); + if (_ecore_fb_kbd_fd >= 0) close(_ecore_fb_kbd_fd); + _ecore_fb_kbd_fd = -1; + _ecore_fb_kbd_fd_handler_handle = NULL; + _ecore_fb_ctrl = 0; + _ecore_fb_lock = 0; + _ecore_fb_shift = 0; + _ecore_fb_alt = 0; +} diff --git a/src/lib/ecore_fb/ecore_fb_keytable.h b/src/lib/ecore_fb/ecore_fb_keytable.h new file mode 100644 index 0000000..70bf6b9 --- /dev/null +++ b/src/lib/ecore_fb/ecore_fb_keytable.h @@ -0,0 +1,129 @@ +/* this table was taken from ecore_fb, is the default en layout */ + "0x00", "0x00", "0x00", /**/"", "", "", NULL,/***/ + "Escape", "Escape", "Escape", /**/"", "", "", "\x1b",/***/ + "1", "exclam", "1", /**/"1", "!", "1", NULL,/***/ + "2", "at", "2", /**/"2", "@", "2", "",/***/ + "3", "numbersign", "3", /**/"3", "#", "3", "\x1b",/***/ + "4", "dollar", "4", /**/"4", "$", "4", "\x1c",/***/ + "5", "percent", "5", /**/"5", "%", "5", "\x1d",/***/ + "6", "asciicircumm", "6", /**/"6", "^", "6", "\x1e",/***/ + "7", "ampersand", "7", /**/"7", "&", "7", "\x1f",/***/ + "8", "asterisk", "8", /**/"8", "*", "8", "\x7f",/***/ + "9", "parenleft", "9", /**/"9", "(", "9", NULL,/***/ + "0", "parenright", "0", /**/"0", ")", "0", NULL,/***/ + "minus", "underscore", "minus", /**/"-", "_", "-", NULL,/***/ + "equal", "plus", "equal", /**/"=", "+", "=", NULL,/***/ + "BackSpace", "BackSpace", "BackSpace", /**/"\010","\010","\010", NULL,/***/ + "Tab", "ISO_Left_Tab", "Tab", /**/"\011","", "\011", NULL,/***/ + "q", "Q", "Q", /**/"q", "Q", "Q", "\x11",/***/ + "w", "W", "W", /**/"w", "W", "W", "\x17",/***/ + "e", "E", "E", /**/"e", "E", "E", "\x05",/***/ + "r", "R", "R", /**/"r", "R", "R", "\x12",/***/ + "t", "T", "T", /**/"t", "T", "T", "\x14",/***/ + "y", "Y", "Y", /**/"y", "Y", "Y", "\x19",/***/ + "u", "U", "U", /**/"u", "U", "U", "\x15",/***/ + "i", "I", "I", /**/"i", "I", "I", "\x09",/***/ + "o", "O", "O", /**/"o", "O", "O", "\x0f",/***/ + "p", "P", "P", /**/"p", "P", "P", "\x10",/***/ + "bracketleft", "braceleft", "bracketleft", /**/"[", "{", "[", "\x1b",/***/ + "bracketright", "braceright", "bracketright", /**/"]", "}", "]", "\x1d",/***/ + "Return", "Return", "Return", /**/"\015","\015","\015", NULL,/***/ + "Control_L", "Control_L", "Control_L", /**/"", "", "", NULL,/***/ + "a", "A", "A", /**/"a", "A", "A", "\x01",/***/ + "s", "S", "S", /**/"s", "S", "S", "\x13",/***/ + "d", "D", "D", /**/"d", "D", "D", "\x04",/***/ + "f", "F", "F", /**/"f", "F", "F", "\x06",/***/ + "g", "G", "G", /**/"g", "G", "G", "\x07",/***/ + "h", "h", "H", /**/"h", "H", "H", "\x08",/***/ + "j", "J", "J", /**/"j", "J", "J", "\x0a",/***/ + "k", "K", "K", /**/"k", "K", "K", "\x0b",/***/ + "l", "L", "L", /**/"l", "L", "L", "\x0c",/***/ + "semicolon", "colon", "semicolon", /**/";", ":", ";", NULL,/***/ + "apostrophe", "quotedbl", "apostrophe", /**/"'", "\"", "'", NULL,/***/ + "grave", "asciitilde", "grave", /**/"`", "~", "`", "",/***/ + "Shift_L", "Shift_L", "Shift_L", /**/"", "", "", NULL,/***/ + "backslash", "bar", "backslash", /**/"\\", "|", "\\", "\x1c",/***/ + "z", "Z", "Z", /**/"z", "Z", "Z", "\x1a",/***/ + "x", "X", "X", /**/"x", "X", "X", "\x18",/***/ + "c", "C", "C", /**/"c", "C", "C", "\x03",/***/ + "v", "V", "V", /**/"v", "V", "V", "\x16",/***/ + "b", "B", "B", /**/"b", "B", "B", "\x02",/***/ + "n", "N", "N", /**/"n", "N", "N", "\x0e",/***/ + "m", "M", "M", /**/"m", "M", "M", "\x0d",/***/ + "comma", "less", "comma", /**/",", "<", ",", NULL,/***/ + "period", "greater", "period", /**/".", ">", ".", NULL,/***/ + "slash", "question", "slash", /**/"/", "?", "/", "",/***/ + "Shift_R", "Shift_R", "Shift_R", /**/"", "", "", NULL,/***/ + "KP_Multiply", "KP_Multiply", "KP_Multiply", /**/"", "*", "", NULL,/***/ + "Alt_L", "Alt_L", "Alt_L", /**/"", "", "", NULL,/***/ + "space", "space", "space", /**/" ", " ", " ", "",/***/ + "Caps_Lock", "Caps_Lock", "Caps_Lock", /**/"", "", "", NULL,/***/ + "F1", "F1", "F1", /**/"", "", "", NULL,/***/ + "F2", "F2", "F2", /**/"", "", "", NULL,/***/ + "F3", "F3", "F3", /**/"", "", "", NULL,/***/ + "F4", "F4", "F4", /**/"", "", "", NULL,/***/ + "F5", "F5", "F5", /**/"", "", "", NULL,/***/ + "F6", "F6", "F6", /**/"", "", "", NULL,/***/ + "F7", "F7", "F7", /**/"", "", "", NULL,/***/ + "F8", "F8", "F8", /**/"", "", "", NULL,/***/ + "F9", "F9", "F9", /**/"", "", "", NULL,/***/ + "F10", "F10", "F10", /**/"", "", "", NULL,/***/ + "Num_Lock", "Num_Lock", "Num_Lock", /**/"", "", "", NULL,/***/ + "Scroll_Lock", "Scroll_Lock", "Scroll_Lock", /**/"", "", "", NULL,/***/ + "KP_Home", "KP_7", "KP_Home", /**/"", "7", "", NULL,/***/ + "KP_Up", "KP_8", "KP_Up", /**/"", "8", "", NULL,/***/ + "KP_Prior", "KP_9", "KP_Prior", /**/"", "9", "", NULL,/***/ + "KP_Subtract", "KP_Subtract", "KP_Subtract", /**/"", "", "", NULL,/***/ + "KP_Left", "KP_4", "KP_Left", /**/"", "4", "", NULL,/***/ + "KP_Begin", "KP_5", "KP_Begin", /**/"", "5", "", NULL,/***/ + "KP_Right", "KP_6", "KP_Right", /**/"", "6", "", NULL,/***/ + "KP_Add", "KP_Add", "KP_Add", /**/"", "", "", NULL,/***/ + "KP_End", "KP_1", "KP_End", /**/"", "1", "", NULL,/***/ + "KP_Down", "KP_2", "KP_Down", /**/"", "2", "", NULL,/***/ + "KP_Next", "KP_3", "KP_Next", /**/"", "3", "", NULL,/***/ + "KP_Insert", "KP_0", "KP_Insert", /**/"", "0", "", NULL,/***/ + "KP_Delete", "KP_Decimal", "KP_Delete", /**/"", ".", "", NULL,/***/ + "0x54", "0x54", "0x54", /**/"", "", "", NULL,/***/ + "0x55", "0x55", "0x55", /**/"", "", "", NULL,/***/ + "0x56", "0x56", "0x56", /**/"", "", "", NULL,/***/ + "F11", "F11", "F11", /**/"", "", "", NULL,/***/ + "F12", "F12", "F12", /**/"", "", "", NULL,/***/ + "0x59", "0x59", "0x59", /**/"", "", "", NULL,/***/ + "0x5a", "0x5a", "0x5a", /**/"", "", "", NULL,/***/ + "0x5b", "0x5b", "0x5b", /**/"", "", "", NULL,/***/ + "0x5c", "0x5c", "0x5c", /**/"", "", "", NULL,/***/ + "0x5d", "0x5d", "0x5d", /**/"", "", "", NULL,/***/ + "0x5e", "0x5e", "0x5e", /**/"", "", "", NULL,/***/ + "0x5f", "0x5f", "0x5f", /**/"", "", "", NULL,/***/ + "KP_Enter", "KP_Enter", "KP_Enter", /**/"\015", "\015", "\015", NULL,/***/ + "Control_R", "Control_R", "Control_R", /**/"", "", "", NULL,/***/ + "KP_Divide", "KP_Divide", "KP_Divide", /**/"", "", "", NULL,/***/ + "Print", "Print", "Print", /**/"", "", "", NULL,/***/ + "Alt_R", "Alt_R", "Alt_R", /**/"", "", "", NULL,/***/ + "0x65", "0x65", "0x65", /**/"", "", "", NULL,/***/ + "Home", "Home", "Home", /**/"", "", "", NULL,/***/ + "Up", "Up", "Up", /**/"", "", "", NULL,/***/ + "Prior", "Prior", "Prior", /**/"", "", "", NULL,/***/ + "Left", "Left", "Left", /**/"", "", "", NULL,/***/ + "Right", "Right", "Right", /**/"", "", "", NULL,/***/ + "End", "End", "End", /**/"", "", "", NULL,/***/ + "Down", "Down", "Down", /**/"", "", "", NULL,/***/ + "Next", "Next", "Next", /**/"", "", "", NULL,/***/ + "Insert", "Insert", "Insert", /**/"", "", "", NULL,/***/ + "Delete", "Delete", "Delete", /**/"\177","\177","\177", NULL,/***/ + "0x70", "0x70", "0x70", /**/"", "", "", NULL,/***/ + "0x71", "0x71", "0x71", /**/"", "", "", NULL,/***/ + "0x72", "0x72", "0x72", /**/"", "", "", NULL,/***/ + "0x73", "0x73", "0x73", /**/"", "", "", NULL,/***/ + "0x74", "0x74", "0x74", /**/"", "", "", NULL,/***/ + "0x75", "0x75", "0x75", /**/"", "", "", NULL,/***/ + "0x76", "0x76", "0x76", /**/"", "", "", NULL,/***/ + "Pause", "Pause", "Pause", /**/"", "", "", NULL,/***/ + "0x78", "0x78", "0x78", /**/"", "", "", NULL,/***/ + "0x79", "0x79", "0x79", /**/"", "", "", NULL,/***/ + "0x7a", "0x7a", "0x7a", /**/"", "", "", NULL,/***/ + "0x7b", "0x7b", "0x7b", /**/"", "", "", NULL,/***/ + "0x7c", "0x7c", "0x7c", /**/"", "", "", NULL,/***/ + "Super_L", "Super_L", "Super_L", /**/"", "", "", NULL,/***/ + "Super_R", "Super_R", "Super_R", /**/"", "", "", NULL,/***/ + "0x7f", "0x7f", "0x7f", /**/"", "", "", NULL, /***/ diff --git a/src/lib/ecore_fb/ecore_fb_li.c b/src/lib/ecore_fb/ecore_fb_li.c new file mode 100644 index 0000000..23599c9 --- /dev/null +++ b/src/lib/ecore_fb/ecore_fb_li.c @@ -0,0 +1,721 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "Ecore_Fb.h" +#include "ecore_fb_private.h" + +#define CLICK_THRESHOLD_DEFAULT 0.25 + +static Eina_List *_ecore_fb_li_devices = NULL; + +static const char *_ecore_fb_li_kbd_syms[128 * 7] = +{ +#include "ecore_fb_keytable.h" +}; + +/* Initial Copyright (C) Brad Hards (1999-2002), + * this function is used to tell if "bit" is set in "array" + * it selects a byte from the array, and does a boolean AND + * operation with a byte that only has the relevant bit set. + * eg. to check for the 12th bit, we do (array[1] & 1<<4). + * Moved to static inline in order to force compiler to otimized + * the unsued part away or force a link error if long has an unexpected + * size. + * - bigeasy + */ +extern int long_has_neither_32_nor_64_bits(void); +static inline int +test_bit(int bit, unsigned long *array) +{ + if (sizeof(long) == 4) + return array[bit / 32] & (1 << (bit % 32)); + else if (sizeof(long) == 8) + return array[bit / 64] & (1 << (bit % 64)); + else long_has_neither_32_nor_64_bits(); +} + +static void +_ecore_fb_li_device_event_key(Ecore_Fb_Input_Device *dev, struct input_event *iev) +{ + if (!dev->listen) return; + + /* check for basic keyboard keys */ + if ((iev->code >= KEY_ESC) && (iev->code <= KEY_COMPOSE)) + { + int offset = 0; + const char *keyname = _ecore_fb_li_kbd_syms[iev->code * 7]; + + /* check the key table */ + if (iev->value) + { + /* its a repeated key, dont increment */ + if (iev->value != 2) + { + if (!strcmp(keyname, "Control_L")) + dev->keyboard.ctrl++; + else if (!strcmp(keyname, "Control_R")) + dev->keyboard.ctrl++; + else if (!strcmp(keyname, "Alt_L")) + dev->keyboard.alt++; + else if (!strcmp(keyname, "Alt_R")) + dev->keyboard.alt++; + else if (!strcmp(keyname, "Shift_L")) + dev->keyboard.shift++; + else if (!strcmp(keyname, "Shift_R")) + dev->keyboard.shift++; + else if (!strcmp(keyname, "Caps_Lock")) + dev->keyboard.lock = !dev->keyboard.lock; + if (dev->keyboard.ctrl > 2) dev->keyboard.ctrl = 2; + if (dev->keyboard.alt > 2) dev->keyboard.alt = 2; + if (dev->keyboard.shift > 2) dev->keyboard.shift = 2; + if (dev->keyboard.lock > 1) dev->keyboard.lock = 1; + } + } + else + { + if (!strcmp(keyname, "Control_L")) + dev->keyboard.ctrl--; + else if (!strcmp(keyname, "Control_R")) + dev->keyboard.ctrl--; + else if (!strcmp(keyname, "Alt_L")) + dev->keyboard.alt--; + else if (!strcmp(keyname, "Alt_R")) + dev->keyboard.alt--; + else if (!strcmp(keyname, "Shift_L")) + dev->keyboard.shift--; + else if (!strcmp(keyname, "Shift_R")) + dev->keyboard.shift--; + if (dev->keyboard.ctrl < 0) dev->keyboard.ctrl = 0; + if (dev->keyboard.alt < 0) dev->keyboard.alt = 0; + if (dev->keyboard.shift < 0) dev->keyboard.shift = 0; + if (dev->keyboard.lock < 0) dev->keyboard.lock = 0; + } + + /* sending ecore_input_evas events */ + Ecore_Event_Key *e; + + if (dev->keyboard.shift) offset = 1; + else if (dev->keyboard.lock) offset = 2; + + const char *key = _ecore_fb_li_kbd_syms[(iev->code * 7) + offset]; + const char *compose = _ecore_fb_li_kbd_syms[(iev->code * 7) + 3 + offset]; + + if (dev->keyboard.ctrl) + { + const char *ts = _ecore_fb_li_kbd_syms[(iev->code * 7) + 3 + 3]; + + if (ts) compose = ts; + } + + e = calloc(1, sizeof(Ecore_Event_Key) + strlen(key) + + strlen(keyname) + (compose ? strlen(compose) : 0) + 3); + e->keyname = (char *)(e + 1); + e->key = e->keyname + strlen(keyname) + 1; + e->compose = (compose) ? e->key + strlen(key) + 1 : NULL; + e->string = e->compose; + + strcpy((char *)e->keyname, keyname); + strcpy((char *)e->key, key); + if (compose) + strcpy((char *)e->compose, compose); + + e->modifiers = 0; + if (dev->keyboard.shift) + e->modifiers |= ECORE_EVENT_MODIFIER_SHIFT; + if (dev->keyboard.ctrl) e->modifiers |= ECORE_EVENT_MODIFIER_CTRL; + if (dev->keyboard.alt) e->modifiers |= ECORE_EVENT_MODIFIER_SHIFT; + if (dev->keyboard.lock) e->modifiers |= ECORE_EVENT_LOCK_CAPS; + + e->timestamp = ecore_loop_time_get() * 1000.0; + e->window = (Ecore_Window)dev->window; + e->event_window = (Ecore_Window)dev->window; + e->root_window = (Ecore_Window)dev->window; + e->same_screen = 1; + + if (iev->value) + ecore_event_add(ECORE_EVENT_KEY_DOWN, e, NULL, NULL); + else + ecore_event_add(ECORE_EVENT_KEY_UP, e, NULL, NULL); + } + /* check for mouse button events */ + else if ((iev->code >= BTN_MOUSE) && (iev->code < BTN_JOYSTICK)) + { + int button; + Ecore_Event_Mouse_Button *e; + double current = ecore_loop_time_get(); + + button = ((iev->code & 0x00F) + 1); + // swap 2 and 3 to make middle and right butotn work right. + if (button == 3) button = 2; + else if (button == 2) button = 3; + if (iev->value) + { + dev->mouse.did_double = EINA_FALSE; + dev->mouse.did_triple = EINA_FALSE; + + if (((current - dev->mouse.prev) <= dev->mouse.threshold) && + (button == dev->mouse.prev_button)) + { + dev->mouse.did_double = EINA_TRUE; + if (((current - dev->mouse.last) <= (2 * dev->mouse.threshold)) && + (button == dev->mouse.last_button)) + { + dev->mouse.did_triple = EINA_TRUE; + /* reset */ + dev->mouse.prev = 0; + dev->mouse.last = 0; + current = 0; + } + } + dev->mouse.last = dev->mouse.prev; + dev->mouse.prev = current; + dev->mouse.last_button = dev->mouse.prev_button; + dev->mouse.prev_button = button; + } + + e = calloc(1, sizeof(Ecore_Event_Mouse_Button)); + if (!e) + return; + + e->timestamp = current * 1000.0; + e->window = (Ecore_Window)dev->window; + e->event_window = (Ecore_Window)dev->window; + e->root_window = (Ecore_Window)dev->window; + e->same_screen = 1; + + e->modifiers = 0; + if (dev->keyboard.shift) + e->modifiers |= ECORE_EVENT_MODIFIER_SHIFT; + if (dev->keyboard.ctrl) e->modifiers |= ECORE_EVENT_MODIFIER_CTRL; + if (dev->keyboard.alt) e->modifiers |= ECORE_EVENT_MODIFIER_SHIFT; + if (dev->keyboard.lock) e->modifiers |= ECORE_EVENT_LOCK_CAPS; + + e->x = dev->mouse.x; + e->y = dev->mouse.y; + e->root.x = e->x; + e->root.y = e->y; + e->buttons = button; + + if (dev->mouse.did_double) + e->double_click = 1; + if (dev->mouse.did_triple) + e->triple_click = 1; + + if (iev->value) + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, e, NULL, NULL); + else + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, e, NULL, NULL); + } +} + +static void +_ecore_fb_li_device_event_rel(Ecore_Fb_Input_Device *dev, struct input_event *iev) +{ + if (!dev->listen) return; + /* dispatch the button events if they are queued */ + switch (iev->code) + { + case REL_X: + case REL_Y: + { + Ecore_Event_Mouse_Move *e; + if (iev->code == REL_X) + { + dev->mouse.x += iev->value; + if (dev->mouse.x > dev->mouse.w - 1) + dev->mouse.x = dev->mouse.w; + else if(dev->mouse.x < 0) + dev->mouse.x = 0; + } + else + { + dev->mouse.y += iev->value; + if (dev->mouse.y > dev->mouse.h - 1) + dev->mouse.y = dev->mouse.h; + else if(dev->mouse.y < 0) + dev->mouse.y = 0; + } + + e = calloc(1, sizeof(Ecore_Event_Mouse_Move)); + if (!e) + return; + + e->window = (Ecore_Window)dev->window; + e->event_window = (Ecore_Window)dev->window; + e->root_window = (Ecore_Window)dev->window; + e->same_screen = 1; + + e->modifiers = 0; + if (dev->keyboard.shift) e->modifiers |= ECORE_EVENT_MODIFIER_SHIFT; + if (dev->keyboard.ctrl) e->modifiers |= ECORE_EVENT_MODIFIER_CTRL; + if (dev->keyboard.alt) e->modifiers |= ECORE_EVENT_MODIFIER_SHIFT; + if (dev->keyboard.lock) e->modifiers |= ECORE_EVENT_LOCK_CAPS; + + e->x = dev->mouse.x; + e->y = dev->mouse.y; + e->root.x = e->x; + e->root.y = e->y; + + e->timestamp = ecore_loop_time_get() * 1000.0; + + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL); + + break; + } + case REL_WHEEL: + case REL_HWHEEL: + { + Ecore_Event_Mouse_Wheel *e; + + e = calloc(1, sizeof(Ecore_Event_Mouse_Wheel)); + if (!e) + return; + + e->x = dev->mouse.x; + e->y = dev->mouse.y; + if (iev->code == REL_HWHEEL) e->direction = 1; + e->z = iev->value; + e->root.x = dev->mouse.x; + e->root.y = dev->mouse.y; + + e->window = (Ecore_Window)dev->window; + e->event_window = (Ecore_Window)dev->window; + e->root_window = (Ecore_Window)dev->window; + e->same_screen = 1; + + e->modifiers = 0; + if (dev->keyboard.shift) e->modifiers |= ECORE_EVENT_MODIFIER_SHIFT; + if (dev->keyboard.ctrl) e->modifiers |= ECORE_EVENT_MODIFIER_CTRL; + if (dev->keyboard.alt) e->modifiers |= ECORE_EVENT_MODIFIER_SHIFT; + if (dev->keyboard.lock) e->modifiers |= ECORE_EVENT_LOCK_CAPS; + + e->timestamp = ecore_loop_time_get() * 1000.0; + + ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, e, NULL, NULL); + + break; + } + default: + break; + } +} + +static void +_ecore_fb_li_device_event_abs(Ecore_Fb_Input_Device *dev, struct input_event *iev) +{ + static int prev_pressure = 0; + int pressure; + + if (!dev->listen) return; + switch (iev->code) + { + case ABS_X: + if (dev->mouse.w != 0) + { + int tmp; + + tmp = (int)((double)(iev->value - dev->mouse.min_w) / dev->mouse.rel_w); + if (tmp < 0) dev->mouse.x = 0; + else if (tmp > dev->mouse.w) dev->mouse.x = dev->mouse.w; + else dev->mouse.x = tmp; + dev->mouse.event = ECORE_EVENT_MOUSE_MOVE; + } + break; + + case ABS_Y: + if (dev->mouse.h != 0) + { + int tmp; + + tmp = (int)((double)(iev->value - dev->mouse.min_h) / dev->mouse.rel_h); + if (tmp < 0) dev->mouse.y = 0; + else if (tmp > dev->mouse.h) dev->mouse.y = dev->mouse.h; + else dev->mouse.y = tmp; + dev->mouse.event = ECORE_EVENT_MOUSE_MOVE; + } + break; + + case ABS_PRESSURE: + pressure = iev->value; + if ((pressure) && (!prev_pressure)) + { + /* DOWN: mouse is down, but was not before */ + dev->mouse.event = ECORE_EVENT_MOUSE_BUTTON_DOWN; + } + else if ((!pressure) && (prev_pressure)) + { + /* UP: mouse was down, but is not now */ + dev->mouse.event = ECORE_EVENT_MOUSE_BUTTON_UP; + } + prev_pressure = pressure; + break; + } +} + +static void +_ecore_fb_li_device_event_syn(Ecore_Fb_Input_Device *dev, struct input_event *iev __UNUSED__) +{ + if (!dev->listen) return; + + if (dev->mouse.event == ECORE_EVENT_MOUSE_MOVE) + { + Ecore_Event_Mouse_Move *ev; + ev = calloc(1,sizeof(Ecore_Event_Mouse_Move)); + ev->x = dev->mouse.x; + ev->y = dev->mouse.y; + ev->root.x = ev->x; + ev->root.y = ev->y; + ev->timestamp = ecore_loop_time_get() * 1000.0; + } + else if (dev->mouse.event == ECORE_EVENT_MOUSE_BUTTON_DOWN) + { + Ecore_Event_Mouse_Button *ev; + ev = calloc(1, sizeof(Ecore_Event_Mouse_Button)); + ev->x = dev->mouse.x; + ev->y = dev->mouse.y; + ev->root.x = ev->x; + ev->root.y = ev->y; + ev->buttons = 1; + ev->timestamp = ecore_loop_time_get() * 1000.0; + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, ev, NULL, NULL); + } + else if (dev->mouse.event == ECORE_EVENT_MOUSE_BUTTON_UP) + { + Ecore_Event_Mouse_Button *ev; + ev = calloc(1, sizeof(Ecore_Event_Mouse_Button)); + ev->x = dev->mouse.x; + ev->y = dev->mouse.y; + ev->root.x = ev->x; + ev->root.y = ev->y; + ev->buttons = 1; + ev->timestamp = ecore_loop_time_get() * 1000.0; + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, ev, NULL, NULL); + } +} + +static Eina_Bool +_ecore_fb_li_device_fd_callback(void *data, Ecore_Fd_Handler *fdh __UNUSED__) +{ + Ecore_Fb_Input_Device *dev; + struct input_event ev[64]; + int len; + int i; + + dev = (Ecore_Fb_Input_Device*)data; + /* read up to 64 events at once */ + len = read(dev->fd, &ev, sizeof(ev)); + for(i = 0; i < (int)(len / sizeof(ev[0])); i++) + { + switch(ev[i].type) + { + case EV_SYN: + _ecore_fb_li_device_event_syn(dev, &ev[i]); + break; + case EV_ABS: + _ecore_fb_li_device_event_abs(dev, &ev[i]); + break; + case EV_REL: + _ecore_fb_li_device_event_rel(dev, &ev[i]); + break; + case EV_KEY: + _ecore_fb_li_device_event_key(dev, &ev[i]); + break; + default: + break; + } + } + return EINA_TRUE; +} + +/** + * @addtogroup Ecore_FB_Group Ecore_FB - Frame buffer convenience functions. + * + * @{ + */ + +/** + * @brief Set the listen mode for an input device . + * + * @param dev The device to set the mode of. + * @param listen @c EINA_FALSE to disable listening mode, @c EINA_TRUE to + * enable it. + * + * This function enables or disables listening on the input device @p dev. + * If @p listen is @c EINA_FALSE, listening mode is disabled, if it is + * @c EINA_TRUE, it is enabled. + */ +EAPI void +ecore_fb_input_device_listen(Ecore_Fb_Input_Device *dev, Eina_Bool listen) +{ + if (!dev) return; + if ((listen && dev->listen) || (!listen && !dev->listen)) return; + if (listen) + { + /* if the device already had a handler */ + if (!dev->handler) + dev->handler = ecore_main_fd_handler_add(dev->fd, ECORE_FD_READ, _ecore_fb_li_device_fd_callback, dev, NULL, NULL); + + } + dev->listen = listen; +} + +#ifndef EV_CNT +# define EV_CNT (EV_MAX+1) +#endif + +/** + * @brief Associates an input device with the given @ref Ecore_Evas_Group. + * + * @param dev The input being associated with an @ref Ecore_Evas_Group (not @c NULL). + * @param window The window which this input is being associated to. + * @c NULL will remove any previous association. + * + * Events generated by this device will have a pointer to @p window. If this @p + * window is registered with ecore_event_window_register() or + * ecore_evas_input_event_register(), respective evas events will be delivered + * by the ecore_input_evas system. An example can be seen in the following code: + * + * @code + * Ecore_Evas *ee = ecore_evas_new(NULL, 0, 0, 800, 600, NULL); + * + * ecore_evas_input_event_register(ee); + * + * device = ecore_fb_input_device_open(device_path); + * if (device) + * ecore_fb_input_device_window_set(device, ee); + * + * @endcode + * + * On the previous code, all input captured on the mentioned device will be + * delivered to the @c Ecore_Evas @c ee. + * + * @since 1.1 + */ +EAPI void +ecore_fb_input_device_window_set(Ecore_Fb_Input_Device *dev, void *window) +{ + if (!dev) return; + + dev->window = window; +} + +/** + * @brief Open an input device. + * + * @param dev The device to open. + * @return The @ref Ecore_Fb_Input_Device object that has been opened. + * + * This function opens the input device named @p dev and returns the + * object for it, or returns @c NULL on failure. + */ +EAPI Ecore_Fb_Input_Device * +ecore_fb_input_device_open(const char *dev) +{ + Ecore_Fb_Input_Device *device; + unsigned long event_type_bitmask[EV_CNT / 32 + 1]; + int event_type; + int fd; + + if (!dev) return NULL; + device = calloc(1, sizeof(Ecore_Fb_Input_Device)); + if (!device) return NULL; + + if ((fd = open(dev, O_RDONLY, O_NONBLOCK)) < 0) + { + fprintf(stderr, "[ecore_fb_li:device_open] %s %s", dev, strerror(errno)); + goto error_open; + } + /* query capabilities */ + if (ioctl(fd, EVIOCGBIT(0, EV_MAX), event_type_bitmask) < 0) + { + fprintf(stderr,"[ecore_fb_li:device_open] query capabilities %s %s", dev, strerror(errno)); + goto error_caps; + } + /* query name */ + device->info.name = calloc(256, sizeof(char)); + if (ioctl(fd, EVIOCGNAME(sizeof(char) * 256), device->info.name) < 0) + { + fprintf(stderr, "[ecore_fb_li:device_open] get name %s %s", dev, strerror(errno)); + strcpy(device->info.name, "Unknown"); + } + device->fd = fd; + device->info.dev = strdup(dev); + /* common */ + device->mouse.threshold = CLICK_THRESHOLD_DEFAULT; + + /* set info */ + for (event_type = 0; event_type < EV_MAX; event_type++) + { + if (!test_bit(event_type, event_type_bitmask)) + continue; + switch (event_type) + { + case EV_SYN: + break; + case EV_KEY: + device->info.cap |= ECORE_FB_INPUT_DEVICE_CAP_KEYS_OR_BUTTONS; + break; + case EV_REL: + device->info.cap |= ECORE_FB_INPUT_DEVICE_CAP_RELATIVE; + break; + case EV_ABS: + device->info.cap |= ECORE_FB_INPUT_DEVICE_CAP_ABSOLUTE; + break; + case EV_MSC: + case EV_LED: + case EV_SND: + case EV_REP: + case EV_FF : + case EV_FF_STATUS: + case EV_PWR: + default: + break; + } + } + + _ecore_fb_li_devices = eina_list_append(_ecore_fb_li_devices, device); + return device; + +error_caps: + close(fd); +error_open: + free(device); + return NULL; +} + +/** + * @brief Close the given device. + * + * @param dev The device to close + * + * This function closes the device @p dev. If @p dev is @c NULL, this + * function does nothing. + */ +EAPI void +ecore_fb_input_device_close(Ecore_Fb_Input_Device *dev) +{ + if (!dev || dev->fd < 0) return; + /* close the fd */ + close(dev->fd); + /* remove the element from the list */ + _ecore_fb_li_devices = eina_list_remove(_ecore_fb_li_devices, dev); + free(dev); +} + + +/** + * @brief Set the axis size of the given device. + * + * @param dev The device to set the axis size to. + * @param w The width of the axis. + * @param h The height of the axis. + * + * This function sets set the width @p w and height @p h of the axis + * of device @p dev. If @p dev is a relative input device, a width and + * height must set for it. If its absolute set the ioctl correctly, if + * not, unsupported device. + */ +EAPI void +ecore_fb_input_device_axis_size_set(Ecore_Fb_Input_Device *dev, int w, int h) +{ + if (!dev) return; + if ((w < 0) || (h < 0)) return; + /* FIXME + * this code is for a touchscreen device, + * make it configurable (ABSOLUTE | RELATIVE) + */ + if (dev->info.cap & ECORE_FB_INPUT_DEVICE_CAP_ABSOLUTE) + { + /* FIXME looks like some kernels dont include this struct */ + struct input_absinfo abs_features; + + ioctl(dev->fd, EVIOCGABS(ABS_X), &abs_features); + dev->mouse.min_w = abs_features.minimum; + dev->mouse.rel_w = (double)(abs_features.maximum - abs_features.minimum)/(double)(w); + + ioctl(dev->fd, EVIOCGABS(ABS_Y), &abs_features); + dev->mouse.min_h = abs_features.minimum; + dev->mouse.rel_h = (double)(abs_features.maximum - abs_features.minimum)/(double)(h); + } + else if (!(dev->info.cap & ECORE_FB_INPUT_DEVICE_CAP_RELATIVE)) + return; + + /* update the local values */ + if (dev->mouse.x > w - 1) dev->mouse.x = w -1; + if (dev->mouse.y > h - 1) dev->mouse.y = h -1; + dev->mouse.w = w; + dev->mouse.h = h; +} + +/** + * @brief Retrieve the name of the given device. + * + * @param dev The device to get the name from. + * @return The name of the device. + * + * This function returns the name of the device @p dev. If @p dev is + * @c NULL, this function returns @c NULL. + */ +EAPI const char * +ecore_fb_input_device_name_get(Ecore_Fb_Input_Device *dev) +{ + if (!dev) return NULL; + return dev->info.name; +} + +/** + * @brief Retrieve the capability of the given device. + * + * @param dev The device to get the name from. + * @return The capability of the device. + * + * This function returns the capability of the device @p dev. If @p dev is + * @c NULL, this function returns ECORE_FB_INPUT_DEVICE_CAP_NONE. + */ +EAPI Ecore_Fb_Input_Device_Cap +ecore_fb_input_device_cap_get(Ecore_Fb_Input_Device *dev) +{ + if (!dev) return ECORE_FB_INPUT_DEVICE_CAP_NONE; + return dev->info.cap; +} + +/** + * @brief Set the threshold of mouse clicks of the given device. + * + * @param dev The device to set the threshodl mouse click to. + * @param threshold The threshold value. + * + * This function sets the threshold of mouse clicks of the device + * @p dev to @p threshold. If @p dev is @c NULL, this function does + * nothing. + */ +EAPI void +ecore_fb_input_device_threshold_click_set(Ecore_Fb_Input_Device *dev, double threshold) +{ + if (!dev) return; + if ((threshold == dev->mouse.threshold) || (threshold == 0)) return; + dev->mouse.threshold = threshold; +} + +/** + * @brief Get the threshold of mouse clicks of the given device. + * + * @param dev The device to set the threshodl mouse click from. + * @return The threshold value. + * + * This function returns the threshold of mouse clicks of the device + * @p dev. If @p dev is @c NULL, this function returns 0.0. + */ +EAPI double +ecore_fb_input_device_threshold_click_get(Ecore_Fb_Input_Device *dev) +{ + if (!dev) return 0; + return dev->mouse.threshold; +} + +/** + * @} + */ diff --git a/src/lib/ecore_fb/ecore_fb_private.h b/src/lib/ecore_fb/ecore_fb_private.h new file mode 100644 index 0000000..797f863 --- /dev/null +++ b/src/lib/ecore_fb/ecore_fb_private.h @@ -0,0 +1,94 @@ +#ifndef _ECORE_FB_PRIVATE_H +#define _ECORE_FB_PRIVATE_H + +#include "Ecore.h" +#include "ecore_private.h" +#include "Ecore_Input.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)) + #define kernel_ulong_t unsigned long + #define BITS_PER_LONG 32 + #include + #undef kernel_ulong_t + #undef BITS_PER_LONG +#else + #include +#endif + +#include +#include +#include + +#include + +/* ecore_fb_li.c */ +struct _Ecore_Fb_Input_Device +{ + int fd; + Ecore_Fd_Handler *handler; + int listen; + struct { + Ecore_Fb_Input_Device_Cap cap; + char *name; + char *dev; + } info; + struct + { + /* common mouse */ + int x,y; + int w,h; + + double last; + double prev; + double threshold; + Eina_Bool did_double; + Eina_Bool did_triple; + /* absolute axis */ + int min_w, min_h; + double rel_w, rel_h; + int event; + int prev_button; + int last_button; + } mouse; + struct + { + int shift; + int ctrl; + int alt; + int lock; + } keyboard; + void *window; +}; + +/* ecore_fb_ts.c */ +EAPI int ecore_fb_ts_init(void); +EAPI void ecore_fb_ts_shutdown(void); +EAPI void ecore_fb_ts_events_window_set(void *window); +EAPI void *ecore_fb_ts_events_window_get(void); +EAPI void ecore_fb_ts_event_window_set(void *window); + +/* ecore_fb_vt.c */ +int ecore_fb_vt_init(void); +void ecore_fb_vt_shutdown(void); + +/* hacks to stop people NEEDING #include */ +#ifndef TS_SET_CAL +#define TS_SET_CAL 0x4014660b +#endif +#ifndef TS_GET_CAL +#define TS_GET_CAL 0x8014660a +#endif + +#endif diff --git a/src/lib/ecore_fb/ecore_fb_ps2.c b/src/lib/ecore_fb/ecore_fb_ps2.c new file mode 100644 index 0000000..fdff3a8 --- /dev/null +++ b/src/lib/ecore_fb/ecore_fb_ps2.c @@ -0,0 +1,223 @@ +typedef struct _Ecore_Fb_Ps2_Event Ecore_Fb_Ps2_Event; +struct _Ecore_Fb_Ps2_Event +{ + unsigned char button; + unsigned char x; + unsigned char y; + unsigned char z; +}; + +static int _ecore_fb_ps2_event_byte_count = 0; +static Ecore_Fb_Ps2_Event _ecore_fb_ps2_event; +static int _ecore_fb_ps2_fd = 0; +static Eina_Bool _ecore_fb_ps2_fd_handler(void *data, Ecore_Fd_Handler *fd_handler); + +int +ecore_fb_ps2_init(void) +{ + _ecore_fb_ps2_fd = open("/dev/psaux", O_RDWR); + if (_ecore_fb_ps2_fd >= 0) + { + prev_flags = fcntl(_ecore_fb_ps2_fd, F_GETFL); + fcntl(_ecore_fb_ps2_fd, F_SETFL, prev_flags | O_NONBLOCK); + _ecore_fb_ts_fd_handler_handle = ecore_main_fd_handler_add(_ecore_fb_ps2_fd, + ECORE_FD_READ, + _ecore_fb_ps2_fd_handler, NULL, NULL, NULL); + if (!_ecore_fb_ts_fd_handler_handle) + { + close(_ecore_fb_ps2_fd); + return 0; + } + return 1; + } + return 0; +} + +void +ecore_fb_ps2_shutdown(void) +{ + if (_ecore_fb_ps2_fd > 0) close(_ecore_fb_ps2_fd); + _ecore_fb_ps2_fd = 0; +} + +static Eina_Bool +_ecore_fb_ps2_fd_handler(void *data __UNUSED__, Ecore_Fd_Handler *fd_handler __UNUSED__) +{ + static int prev_x = 0, prev_y = 0, prev_button = 0; + static double last_time = 0; + static double last_last_time = 0; + int v = 0; + + do + { + int x, y, button, i; + int num; + char *ptr; + double t; + static int did_double = 0; + static int did_triple = 0; + + ptr = (char *)&(_ecore_fb_ps2_event); + ptr += _ecore_fb_ps2_event_byte_count; + num = sizeof(Ecore_Fb_Ps2_Event) - _ecore_fb_ps2_event_byte_count; + v = read(_ecore_fb_ps2_fd, ptr, num); + if (v < 0) return EINA_TRUE; + _ecore_fb_ps2_event_byte_count += v; + if (v < num) return EINA_TRUE; + t = ecore_loop_time_get(); + _ecore_fb_ps2_event_byte_count = 0; + if (_ecore_fb_ps2_event.button & 0x10) + x = prev_x + (0xffffff00 | _ecore_fb_ps2_event.x); + else + x = prev_x + _ecore_fb_ps2_event.x; + if (_ecore_fb_ps2_event.button & 0x20) + y = prev_y - (0xffffff00 | _ecore_fb_ps2_event.y); + else + y = prev_y - _ecore_fb_ps2_event.y; + button = _ecore_fb_ps2_event.button & 0x7; + if (x < 0) x = 0; + if (y < 0) y = 0; + if (x >= _ecore_fb_console_w) x = _ecore_fb_console_w - 1; + if (y >= _ecore_fb_console_h) y = _ecore_fb_console_h - 1; + /* add event to queue */ + /* always add a move event */ + if (1) + { + /* MOVE: mouse is down and was */ + Ecore_Event_Mouse_Move *e; + + e = calloc(1, sizeof(Ecore_Fb_Event_Mouse_Move)); + if (!e) goto retry; + e->x = x; + e->y = y; + e->root.x = e->x; + e->root.y = e->y; + e->window = 1; + e->event_window = e->window; + e->root_window = e->window; + e->same_screen = 1; + e->timestamp = ecore_loop_time_get() * 1000.0; + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL); + } + for (i = 1; i <= 3; i++) + { + int mask; + + mask = 1 << (i - 1); + if (((button & mask)) && (!(prev_button & mask))) + { + /* DOWN: mouse is down, but was not now */ + Ecore_Event_Mouse_Button *e; + + e = calloc(1, sizeof(Ecore_Event_Mouse_Button)); + if (!e) goto retry; + e->x = x; + e->y = y; + e->root.x = e->x; + e->root.y = e->y; + e->button = i; + e->window = 1; + e->event_window = e->window; + e->root_window = e->window; + e->same_screen = 1; + if ((t - last_time) <= _ecore_fb_double_click_time) + { + e->double_click = 1; + did_double = 1; + } + else + { + did_double = 0; + did_triple = 0; + } + if ((t - last_last_time) <= (2 * _ecore_fb_double_click_time)) + { + did_triple = 1; + e->triple_click = 1; + } + else + { + did_triple = 0; + } + e->timestamp = ecore_loop_time_get() * 1000.0; + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, e, NULL, NULL); + } + else if ((!(button & mask)) && ((prev_button & mask))) + { + /* UP: mouse was down, but is not now */ + Ecore_Event_Mouse_Button *e; + + e = calloc(1, sizeof(Ecore_Event_Mouse_Button)); + if (!e) goto retry; + e->x = x; + e->y = y; + e->root.x = e->x; + e->root.y = e->y; + e->button = i; + e->window = 1; + e->event_window = e->window; + e->root_window = e->window; + e->same_screen = 1; + if (did_double) + e->double_click = 1; + if (did_triple) + e->triple_click = 1; + e->timestamp = ecore_loop_time_get() * 1000.0; + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, e, NULL, NULL); + } + } + if (did_triple) + { + last_time = 0; + last_last_time = 0; + } + else + { + last_last_time = last_time; + last_time = t; + } + retry: + prev_x = x; + prev_y = y; + prev_button = button; + } + while (v > 0); + return EINA_TRUE; +} +/** + * @defgroup Ecore_FB_Click_Group Framebuffer Double Click Functions + * + * Functions that deal with the double click time of the framebuffer. + */ + +/** + * Sets the timeout for a double and triple clicks to be flagged. + * + * This sets the time between clicks before the double_click flag is + * set in a button down event. If 3 clicks occur within double this + * time, the triple_click flag is also set. + * + * @param t The time in seconds + * @ingroup Ecore_FB_Click_Group + */ +EAPI void +ecore_fb_double_click_time_set(double t) +{ + if (t < 0.0) t = 0.0; + _ecore_fb_double_click_time = t; +} + +/** + * Retrieves the double and triple click flag timeout. + * + * See @ref ecore_x_double_click_time_set for more information. + * + * @return The timeout for double clicks in seconds. + * @ingroup Ecore_FB_Click_Group + */ +EAPI double +ecore_fb_double_click_time_get(void) +{ + return _ecore_fb_double_click_time; +} + diff --git a/src/lib/ecore_fb/ecore_fb_ts.c b/src/lib/ecore_fb/ecore_fb_ts.c new file mode 100644 index 0000000..a33bb36 --- /dev/null +++ b/src/lib/ecore_fb/ecore_fb_ts.c @@ -0,0 +1,362 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_TSLIB +# include +# include +#endif + +#include "Ecore_Fb.h" +#include "ecore_fb_private.h" + +typedef struct _Ecore_Fb_Ts_Event Ecore_Fb_Ts_Event; +typedef struct _Ecore_Fb_Ts_Calibrate Ecore_Fb_Ts_Calibrate; +typedef struct _Ecore_Fb_Ts_Backlight Ecore_Fb_Ts_Backlight; +typedef struct _Ecore_Fb_Ts_Contrast Ecore_Fb_Ts_Contrast; +typedef struct _Ecore_Fb_Ts_Led Ecore_Fb_Ts_Led; +typedef struct _Ecore_Fb_Ts_Flite Ecore_Fb_Ts_Flite; + +struct _Ecore_Fb_Ts_Event +{ + unsigned short pressure; + unsigned short x; + unsigned short y; + unsigned short _unused; +}; + +struct _Ecore_Fb_Ts_Calibrate +{ + int xscale; + int xtrans; + int yscale; + int ytrans; + int xyswap; +}; + +struct _Ecore_Fb_Ts_Backlight +{ + int on; + unsigned char brightness; +}; + +struct _Ecore_Fb_Ts_Contrast +{ + unsigned char contrast; +}; + +struct _Ecore_Fb_Ts_Led +{ + unsigned char on; + unsigned char blink_time; + unsigned char on_time; + unsigned char off_time; +}; + +struct _Ecore_Fb_Ts_Flite +{ + unsigned char mode; + unsigned char pwr; + unsigned char brightness; +}; + +static Eina_Bool _ecore_fb_ts_fd_handler(void *data, Ecore_Fd_Handler *fd_handler); +static int _ecore_fb_ts_fd = -1; +static int _ecore_fb_ts_event_byte_count = 0; +static int _ecore_fb_ts_apply_cal = 0; +static Ecore_Fb_Ts_Event _ecore_fb_ts_event; +static Ecore_Fb_Ts_Calibrate _ecore_fb_ts_cal = {1,1,0,0,0}; +static Ecore_Fd_Handler *_ecore_fb_ts_fd_handler_handle = NULL; + +#ifdef HAVE_TSLIB +struct tsdev *_ecore_fb_tslib_tsdev = NULL; +struct ts_sample _ecore_fb_tslib_event; +#endif + +static double _ecore_fb_double_click_time = 0.25; +static void *_ecore_fb_ts_event_window = NULL; + +EAPI int +ecore_fb_ts_init(void) +{ +#ifdef HAVE_TSLIB + char *tslib_tsdevice = NULL; + if ( (tslib_tsdevice = getenv("TSLIB_TSDEVICE")) ) + { + printf( "ECORE_FB: TSLIB_TSDEVICE = '%s'\n", tslib_tsdevice ); + _ecore_fb_tslib_tsdev = ts_open( tslib_tsdevice, 1 ); /* 1 = nonblocking, 0 = blocking */ + + if ( !_ecore_fb_tslib_tsdev ) + { + printf( "ECORE_FB: Can't ts_open (%s)\n", strerror( errno ) ); + return 0; + } + + if ( ts_config( _ecore_fb_tslib_tsdev ) ) + { + printf( "ECORE_FB: Can't ts_config (%s)\n", strerror( errno ) ); + return 0; + } + _ecore_fb_ts_fd = ts_fd( _ecore_fb_tslib_tsdev ); + if ( _ecore_fb_ts_fd < 0 ) + { + printf( "ECORE_FB: Can't open touchscreen (%s)\n", strerror( errno ) ); + return 0; + } + } +#else + _ecore_fb_ts_fd = open("/dev/touchscreen/0", O_RDONLY); +#endif + if (_ecore_fb_ts_fd >= 0) + { + _ecore_fb_ts_fd_handler_handle = ecore_main_fd_handler_add(_ecore_fb_ts_fd, + ECORE_FD_READ, + _ecore_fb_ts_fd_handler, NULL, + NULL, NULL); + if (!_ecore_fb_ts_fd_handler_handle) + { + close(_ecore_fb_ts_fd); + return 0; + } + // FIXME _ecore_fb_kbd_fd = open("/dev/touchscreen/key", O_RDONLY); + return 1; + } + return 0; +} + +EAPI void +ecore_fb_ts_shutdown(void) +{ + if (_ecore_fb_ts_fd_handler_handle) + ecore_main_fd_handler_del(_ecore_fb_ts_fd_handler_handle); + if (_ecore_fb_ts_fd >= 0) close(_ecore_fb_ts_fd); + _ecore_fb_ts_fd = -1; + _ecore_fb_ts_fd_handler_handle = NULL; + _ecore_fb_ts_event_window = NULL; +} + +EAPI void +ecore_fb_ts_event_window_set(void *window) +{ + _ecore_fb_ts_event_window = window; +} + +EAPI void * +ecore_fb_ts_event_window_get(void) +{ + return _ecore_fb_ts_event_window; +} + +/** + * @defgroup Ecore_FB_Calibrate_Group Framebuffer Calibration Functions + * + * Functions that calibrate the screen. + */ + + +/** + * Calibrates the touschreen using the given parameters. + * @param xscale X scaling, where 256 = 1.0 + * @param xtrans X translation. + * @param yscale Y scaling. + * @param ytrans Y translation. + * @param xyswap Swap X & Y flag. + * @ingroup Ecore_FB_Calibrate_Group + */ +EAPI void +ecore_fb_touch_screen_calibrate_set(int xscale, int xtrans, int yscale, int ytrans, int xyswap) +{ + Ecore_Fb_Ts_Calibrate cal; + + if (_ecore_fb_ts_fd < 0) return; + cal.xscale = xscale; + cal.xtrans = xtrans; + cal.yscale = yscale; + cal.ytrans = ytrans; + cal.xyswap = xyswap; + if (ioctl(_ecore_fb_ts_fd, TS_SET_CAL, (void *)&cal)) + { + _ecore_fb_ts_cal = cal; + _ecore_fb_ts_apply_cal = 1; + } +} + +/** + * Retrieves the calibration parameters of the touchscreen. + * @param xscale Pointer to an integer in which to store the X scaling. + * Note that 256 = 1.0. + * @param xtrans Pointer to an integer in which to store the X translation. + * @param yscale Pointer to an integer in which to store the Y scaling. + * @param ytrans Pointer to an integer in which to store the Y translation. + * @param xyswap Pointer to an integer in which to store the Swap X & Y flag. + * @ingroup Ecore_FB_Calibrate_Group + */ +EAPI void +ecore_fb_touch_screen_calibrate_get(int *xscale, int *xtrans, int *yscale, int *ytrans, int *xyswap) +{ + Ecore_Fb_Ts_Calibrate cal; + + if (_ecore_fb_ts_fd < 0) return; + if (!_ecore_fb_ts_apply_cal) + { + if (ioctl(_ecore_fb_ts_fd, TS_GET_CAL, (void *)&cal)) + _ecore_fb_ts_cal = cal; + } + else + cal = _ecore_fb_ts_cal; + if (xscale) *xscale = cal.xscale; + if (xtrans) *xtrans = cal.xtrans; + if (yscale) *yscale = cal.yscale; + if (ytrans) *ytrans = cal.ytrans; + if (xyswap) *xyswap = cal.xyswap; +} + +static Eina_Bool +_ecore_fb_ts_fd_handler(void *data __UNUSED__, Ecore_Fd_Handler *fd_handler __UNUSED__) +{ + static int prev_x = 0, prev_y = 0, prev_pressure = 0; + static double last_time = 0; + static double last_last_time = 0; + int v = 0; + + do + { + int x, y, pressure; + int num; + char *ptr; + double t = 0.0; + static int did_double = 0; + static int did_triple = 0; + +#ifdef HAVE_TSLIB + if (_ecore_fb_ts_apply_cal) + num = ts_read_raw(_ecore_fb_tslib_tsdev, &_ecore_fb_tslib_event, 1); + else + num = ts_read(_ecore_fb_tslib_tsdev, &_ecore_fb_tslib_event, 1); + if (num != 1) return 1; /* no more samples at this time */ + x = _ecore_fb_tslib_event.x; + y = _ecore_fb_tslib_event.y; + pressure = _ecore_fb_tslib_event.pressure; + v = 1; /* loop, there might be more samples */ +#else + ptr = (char *)&(_ecore_fb_ts_event); + ptr += _ecore_fb_ts_event_byte_count; + num = sizeof(Ecore_Fb_Ts_Event) - _ecore_fb_ts_event_byte_count; + v = read(_ecore_fb_ts_fd, ptr, num); + if (v < 0) return 1; + _ecore_fb_ts_event_byte_count += v; + if (v < num) return 1; + _ecore_fb_ts_event_byte_count = 0; + if (_ecore_fb_ts_apply_cal) + { + x = ((_ecore_fb_ts_cal.xscale * _ecore_fb_ts_event.x) >> 8) + _ecore_fb_ts_cal.xtrans; + y = ((_ecore_fb_ts_cal.yscale * _ecore_fb_ts_event.y) >> 8) + _ecore_fb_ts_cal.ytrans; + } + else + { + x = _ecore_fb_ts_event.x; + y = _ecore_fb_ts_event.y; + } + pressure = _ecore_fb_ts_event.pressure; +#endif + t = ecore_loop_time_get(); + /* add event to queue */ + /* always add a move event */ + if ((pressure) || (prev_pressure)) + { + /* MOVE: mouse is down and was */ + Ecore_Event_Mouse_Move *e; + + e = calloc(1, sizeof(Ecore_Event_Mouse_Move)); + if (!e) goto retry; + e->x = x; + e->y = y; + e->root.x = e->x; + e->root.y = e->y; + e->window = 1; + e->event_window = e->window; + e->root_window = e->window; + e->same_screen = 1; + e->timestamp = ecore_loop_time_get() * 1000.0; + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL); + } + if ((pressure) && (!prev_pressure)) + { + /* DOWN: mouse is down, but was not now */ + Ecore_Event_Mouse_Button *e; + + e = calloc(1, sizeof(Ecore_Event_Mouse_Button)); + if (!e) goto retry; + e->x = x; + e->y = y; + e->root.x = e->x; + e->root.y = e->y; + e->buttons = 1; + if ((t - last_time) <= _ecore_fb_double_click_time) + { + e->double_click = 1; + did_double = 1; + } + else + { + did_double = 0; + did_triple = 0; + } + if ((t - last_last_time) <= (2 * _ecore_fb_double_click_time)) + { + did_triple = 1; + e->triple_click = 1; + } + else + { + did_triple = 0; + } + e->window = 1; + e->event_window = e->window; + e->root_window = e->window; + e->same_screen = 1; + e->timestamp = ecore_loop_time_get() * 1000.0; + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, e, NULL, NULL); + } + else if ((!pressure) && (prev_pressure)) + { + /* UP: mouse was down, but is not now */ + Ecore_Event_Mouse_Button *e; + + e = calloc(1, sizeof(Ecore_Event_Mouse_Button)); + if (!e) goto retry; + e->x = prev_x; + e->y = prev_y; + e->root.x = e->x; + e->root.y = e->y; + e->buttons = 1; + if (did_double) + e->double_click = 1; + if (did_triple) + e->triple_click = 1; + e->window = 1; + e->event_window = e->window; + e->root_window = e->window; + e->same_screen = 1; + e->timestamp = ecore_loop_time_get() * 1000.0; + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, e, NULL, NULL); + } + if (did_triple) + { + last_time = 0; + last_last_time = 0; + } + else + { + last_last_time = last_time; + last_time = t; + } +retry: + prev_x = x; + prev_y = y; + prev_pressure = pressure; + } + while (v > 0); + return 1; +} + diff --git a/src/lib/ecore_fb/ecore_fb_vt.c b/src/lib/ecore_fb/ecore_fb_vt.c new file mode 100644 index 0000000..09e3f37 --- /dev/null +++ b/src/lib/ecore_fb/ecore_fb_vt.c @@ -0,0 +1,322 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "Ecore_Fb.h" +#include "ecore_fb_private.h" + +static int _ecore_fb_vt_do_switch = 0; + +static int _ecore_fb_vt_tty0_fd = -1; +static int _ecore_fb_vt_tty_fd = -1; +static int _ecore_fb_vt_current_vt = 0; +static int _ecore_fb_vt_prev_vt = 0; + +static struct termios _ecore_fb_tty_prev_tio_mode; +static struct vt_mode _ecore_fb_vt_prev_mode; + +static Eina_Bool _ecore_fb_signal_usr_handler(void *data, int type, void *ev); +static Ecore_Event_Handler *_ecore_fb_user_handler = NULL; +static int _ecore_fb_tty_prev_mode = 0; +static int _ecore_fb_tty_prev_kd_mode = 0; + +/* callbacks for an attach/release of a vt */ +static void (*_ecore_fb_func_fb_lost) (void *data) = NULL; +static void *_ecore_fb_func_fb_lost_data = NULL; +static void (*_ecore_fb_func_fb_gain) (void *data) = NULL; +static void *_ecore_fb_func_fb_gain_data = NULL; + +/* FIXME what is the filter for? */ +static Ecore_Event_Filter *_ecore_fb_filter_handler = NULL; + +/* prototypes */ +/* XXX: unused +static void _ecore_fb_vt_switch(int vt); +static void *_ecore_fb_event_filter_start(void *data); +static Eina_Bool _ecore_fb_event_filter_filter(void *data, void *loop_data, int type, void *event); +static void _ecore_fb_event_filter_end(void *data, void *loop_data); +*/ + +static Eina_Bool +_ecore_fb_signal_usr_handler(void *data __UNUSED__, int type __UNUSED__, void *ev) +{ + Ecore_Event_Signal_User *e; + + e = (Ecore_Event_Signal_User *)ev; + if (e->number == 1) + { + /* release vt */ + if (_ecore_fb_func_fb_lost) _ecore_fb_func_fb_lost(_ecore_fb_func_fb_lost_data); + /* TODO stop listening from the devices? let the callback do it? */ + ioctl(_ecore_fb_vt_tty_fd, VT_RELDISP, 1); + } + else if (e->number == 2) + { + /* attach vt */ + if (_ecore_fb_func_fb_gain) _ecore_fb_func_fb_gain(_ecore_fb_func_fb_gain_data); + /* TODO reattach all devices */ + } + return 1; +} + +/* XXX: unused +static void +_ecore_fb_vt_switch(int vt) +{ + vt++; + if (_ecore_fb_vt_tty_fd != 0) + { + if (vt != _ecore_fb_vt_current_vt) + { + tcsetattr(_ecore_fb_vt_tty_fd, TCSAFLUSH, &_ecore_fb_tty_prev_tio_mode); + ioctl(_ecore_fb_vt_tty_fd, KDSETMODE, _ecore_fb_tty_prev_kd_mode); + ioctl(_ecore_fb_vt_tty_fd, KDSKBMODE, _ecore_fb_tty_prev_mode); + } + } + ioctl(_ecore_fb_vt_tty_fd, VT_ACTIVATE, vt); +} +*/ + +static int +_ecore_fb_vt_setup(void) +{ + char buf[64]; +// XXX: unused +// struct termios tio; + struct vt_mode new_vtmode; + + if (_ecore_fb_vt_current_vt != _ecore_fb_vt_prev_vt) + { + snprintf(buf, sizeof(buf), "/dev/tty%i", _ecore_fb_vt_current_vt); + if ((_ecore_fb_vt_tty_fd = open(buf, O_RDWR)) < 0) + { + printf("[ecore_fb:vt_setup] can't open tty %d\n", _ecore_fb_vt_current_vt); + return 0; + } + close(_ecore_fb_vt_tty0_fd); + _ecore_fb_vt_tty0_fd = -1; + /* FIXME detach the process from current tty ? */ + } + else + _ecore_fb_vt_tty_fd = _ecore_fb_vt_tty0_fd; + /* for backup */ + tcgetattr(_ecore_fb_vt_tty_fd, &_ecore_fb_tty_prev_tio_mode); + ioctl(_ecore_fb_vt_tty_fd, KDGETMODE, &_ecore_fb_tty_prev_kd_mode); + ioctl(_ecore_fb_vt_tty_fd, VT_GETMODE, &_ecore_fb_vt_prev_mode); + + if (ioctl(_ecore_fb_vt_tty_fd, KDSETMODE, KD_GRAPHICS) < 0) + { + perror("[ecore_fb:vt_setup] can't set the mode to KD_GRAPHICS"); + close(_ecore_fb_vt_tty_fd); + _ecore_fb_vt_tty_fd = -1; + return 0; + } + ioctl(_ecore_fb_vt_tty_fd, KDGKBMODE, &_ecore_fb_tty_prev_mode); + + /* support of switching */ + new_vtmode.mode = VT_PROCESS; + new_vtmode.waitv = 0; + new_vtmode.relsig = SIGUSR1; + new_vtmode.acqsig = SIGUSR2; + if (ioctl(_ecore_fb_vt_tty_fd, VT_SETMODE, &new_vtmode) < 0) + { + perror("[ecore_fb:vt_setup] can't set the tty mode"); + close(_ecore_fb_vt_tty_fd); + _ecore_fb_vt_tty_fd = -1; + return 0; + } + /* register signal handlers when alloc/detach of vt */ + _ecore_fb_user_handler = ecore_event_handler_add(ECORE_EVENT_SIGNAL_USER, + _ecore_fb_signal_usr_handler, + NULL); + /* What does this do? */ + /* + _ecore_fb_filter_handler = ecore_event_filter_add(_ecore_fb_event_filter_start, _ecore_fb_event_filter_filter, _ecore_fb_event_filter_end, NULL); + */ + + usleep(40000); + if (ioctl(_ecore_fb_vt_tty_fd, VT_ACTIVATE, _ecore_fb_vt_current_vt) < 0) + { + perror("[ecore_fb:vt_setup] error on VT_ACTIVATE"); + close(_ecore_fb_vt_tty_fd); + _ecore_fb_vt_tty_fd = -1; + return 0; + } + if(ioctl(_ecore_fb_vt_tty_fd, VT_WAITACTIVE, _ecore_fb_vt_current_vt) < 0) + { + perror("[ecore_fb:vt_setup] error on VT_WAITACTIVE"); + close(_ecore_fb_vt_tty_fd); + _ecore_fb_vt_tty_fd = -1; + return 0; + } + /* FIXME assign the fb to the tty in case isn't setup */ + return 1; +} + +int +ecore_fb_vt_init(void) +{ + struct vt_stat vtstat; + + /* as root you can allocate another tty */ + if (!geteuid()) + _ecore_fb_vt_do_switch = 1; + if ((_ecore_fb_vt_tty0_fd = open("/dev/tty0", O_RDONLY)) < 0) + { + printf("[ecore_fb:init] can't open /dev/tty0\n"); + return 0; + } + /* query current vt state */ + if ((ioctl(_ecore_fb_vt_tty0_fd, VT_GETSTATE, &vtstat)) < 0) + { + printf("[ecore_fb:init] can't get current tty state\n"); + return 0; + } + _ecore_fb_vt_prev_vt = vtstat.v_active; + /* switch to another tty */ + if (_ecore_fb_vt_do_switch) + { + int vtno; + + if ((ioctl(_ecore_fb_vt_tty0_fd, VT_OPENQRY, &vtno) < 0)) + { + printf("[ecore_fb:init] can't query for a vt\n"); + return 0; + } + _ecore_fb_vt_current_vt = vtno; + } + /* use current tty */ + else + _ecore_fb_vt_current_vt = _ecore_fb_vt_prev_vt; + if (!_ecore_fb_vt_setup()) + { + printf("[ecore_fb:init] can't setup the vt, restoring previous mode...\n"); + /* TODO finish this */ + if (_ecore_fb_vt_do_switch) + { + printf("[ecore_fb:init] switching back to vt %d\n", _ecore_fb_vt_prev_vt); + } + return 0; + } + return 1; +} + +void +ecore_fb_vt_shutdown(void) +{ + /* restore the previous mode */ + if (_ecore_fb_vt_tty_fd != -1) + { + tcsetattr(_ecore_fb_vt_tty_fd, TCSAFLUSH, &_ecore_fb_tty_prev_tio_mode); + ioctl(_ecore_fb_vt_tty_fd, KDSETMODE, _ecore_fb_tty_prev_kd_mode); + ioctl(_ecore_fb_vt_tty_fd, KDSKBMODE, _ecore_fb_tty_prev_mode); + ioctl(_ecore_fb_vt_tty_fd, VT_SETMODE, &_ecore_fb_vt_prev_mode); + /* go back to previous vt */ + close(_ecore_fb_vt_tty_fd); + _ecore_fb_vt_tty_fd = -1; + } + + if (_ecore_fb_user_handler) ecore_event_handler_del(_ecore_fb_user_handler); + _ecore_fb_user_handler = NULL; + + if (_ecore_fb_filter_handler) ecore_event_filter_del(_ecore_fb_filter_handler); + _ecore_fb_filter_handler = NULL; +} + +/** + * @addtogroup Ecore_FB_Group Ecore_FB - Frame buffer convenience functions. + * + * @{ + */ + +/** + * @brief Set a callback called when a virtual terminal is gained. + * + * @param func The callback called when vt is gained. + * @param data The data to pass to the callback. + * + * This function sets the callback @p func which will be called when a + * virtual terminal is gained (for example you press Ctrl-Alt-F1 to go + * to vt1 and your app was using vt1). @p data will be pass to @p func if + * the callback is called. + */ +EAPI void +ecore_fb_callback_gain_set(void (*func) (void *data), void *data) +{ + _ecore_fb_func_fb_gain = func; + _ecore_fb_func_fb_gain_data = data; +} + +/** + * @brief Set a callback called when a virtual terminal is lost. + * + * @param func The callback called when vt is lost. + * @param data The data to pass to the callback. + * + * This function sets the callback @p func which will be called when a + * virtual terminal is lost (someone wants the tv from you and you + * want to give up that vt). @p data will be pass to @p func if the + * callback is called. + */ +EAPI void +ecore_fb_callback_lose_set(void (*func) (void *data), void *data) +{ + _ecore_fb_func_fb_lost = func; + _ecore_fb_func_fb_lost_data = data; + +} + +/** + * @} + */ + +/* + * This filter should take into account that the MOUSE_MOVE event can be + * triggered by a mouse, not just a touchscreen device, so you can't discard + * them (only those generated by a device that sends events with absolute + * coordinates). + +typedef struct _Ecore_Fb_Filter_Data Ecore_Fb_Filter_Data; + +struct _Ecore_Fb_Filter_Data +{ + int last_event_type; +}; + +static void * +_ecore_fb_event_filter_start(void *data __UNUSED__) +{ + Ecore_Fb_Filter_Data *filter_data; + + filter_data = calloc(1, sizeof(Ecore_Fb_Filter_Data)); + return filter_data; +} + +static Eina_Bool +_ecore_fb_event_filter_filter(void *data __UNUSED__, void *loop_data,int type, void *event __UNUSED__) +{ + Ecore_Fb_Filter_Data *filter_data; + + filter_data = loop_data; + if (!filter_data) return EINA_TRUE; + if (type == ECORE_EVENT_MOUSE_MOVE) + { + if ((filter_data->last_event_type) == ECORE_EVENT_MOUSE_MOVE) + { + filter_data->last_event_type = type; + return EINA_FALSE; + } + } + filter_data->last_event_type = type; + return EINA_TRUE; +} + +static void +_ecore_fb_event_filter_end(void *data __UNUSED__, void *loop_data) +{ + Ecore_Fb_Filter_Data *filter_data; + + filter_data = loop_data; + if (filter_data) free(filter_data); +} +*/ diff --git a/src/lib/ecore_file/Ecore_File.h b/src/lib/ecore_file/Ecore_File.h new file mode 100644 index 0000000..30f3bd7 --- /dev/null +++ b/src/lib/ecore_file/Ecore_File.h @@ -0,0 +1,190 @@ +#ifndef ECORE_FILE_H +#define ECORE_FILE_H + +/* + * TODO: + * - More events, move/rename of directory file + */ + +#include + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_ECORE_FILE_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_ECORE_FILE_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +/** + * @file Ecore_File.h + * @brief Files utility functions + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup Ecore_File_Group Ecore_File - Files and directories convenience functions + * + * @{ + */ + +/** + * @typedef Ecore_File_Monitor + * Abstract type used when monitoring a directory. + */ +typedef struct _Ecore_File_Monitor Ecore_File_Monitor; + +/** + * @typedef Ecore_File_Download_Job + * Abstract type used when aborting a download. + */ +typedef struct _Ecore_File_Download_Job Ecore_File_Download_Job; + +/** + * @typedef _Ecore_File_Event + * The event type returned when a file or directory is monitored. + */ +typedef enum _Ecore_File_Event +{ + ECORE_FILE_EVENT_NONE, /**< No event. */ + ECORE_FILE_EVENT_CREATED_FILE, /**< Created file event. */ + ECORE_FILE_EVENT_CREATED_DIRECTORY, /**< Created directory event. */ + ECORE_FILE_EVENT_DELETED_FILE, /**< Deleted file event. */ + ECORE_FILE_EVENT_DELETED_DIRECTORY, /**< Deleted directory event. */ + ECORE_FILE_EVENT_DELETED_SELF, /**< Deleted monitored directory event. */ + ECORE_FILE_EVENT_MODIFIED, /**< Modified file or directory event. */ + ECORE_FILE_EVENT_CLOSED /**< Closed file event */ +} Ecore_File_Event; + +/** + * @typedef Ecore_File_Monitor_Cb + * Callback type used when a monitored directory has changes. + */ +typedef void (*Ecore_File_Monitor_Cb)(void *data, Ecore_File_Monitor *em, Ecore_File_Event event, const char *path); + +/** + * @typedef Ecore_File_Download_Completion_Cb + * Callback type used when a download is finished. + */ +typedef void (*Ecore_File_Download_Completion_Cb)(void *data, const char *file, int status); + +/** + * @typedef _Ecore_File_Progress_Return + * What to do with the download as a return from the + * Ecore_File_Download_Progress_Cb function, if provided. + */ +typedef enum _Ecore_File_Progress_Return +{ + ECORE_FILE_PROGRESS_CONTINUE = 0, /**< Continue the download. */ + ECORE_FILE_PROGRESS_ABORT = 1 /**< Abort the download. */ +} Ecore_File_Progress_Return; + +/** + * @typedef Ecore_File_Download_Progress_Cb + * Callback type used while a download is in progress. + */ +typedef int (*Ecore_File_Download_Progress_Cb)(void *data, + const char *file, + long int dltotal, + long int dlnow, + long int ultotal, + long int ulnow); + +/* File operations */ + +EAPI int ecore_file_init (void); +EAPI int ecore_file_shutdown (void); +EAPI long long ecore_file_mod_time (const char *file); +EAPI long long ecore_file_size (const char *file); +EAPI Eina_Bool ecore_file_exists (const char *file); +EAPI Eina_Bool ecore_file_is_dir (const char *file); +EAPI Eina_Bool ecore_file_mkdir (const char *dir); +EAPI int ecore_file_mkdirs (const char **dirs); +EAPI int ecore_file_mksubdirs (const char *base, const char **subdirs); +EAPI Eina_Bool ecore_file_rmdir (const char *dir); +EAPI Eina_Bool ecore_file_recursive_rm (const char *dir); +EAPI Eina_Bool ecore_file_mkpath (const char *path); +EAPI int ecore_file_mkpaths (const char **paths); +EAPI Eina_Bool ecore_file_cp (const char *src, const char *dst); +EAPI Eina_Bool ecore_file_mv (const char *src, const char *dst); +EAPI Eina_Bool ecore_file_symlink (const char *src, const char *dest); +EAPI char *ecore_file_realpath (const char *file); +EAPI Eina_Bool ecore_file_unlink (const char *file); +EAPI Eina_Bool ecore_file_remove (const char *file); +EAPI const char *ecore_file_file_get (const char *path); +EAPI char *ecore_file_dir_get (const char *path); +EAPI Eina_Bool ecore_file_can_read (const char *file); +EAPI Eina_Bool ecore_file_can_write (const char *file); +EAPI Eina_Bool ecore_file_can_exec (const char *file); +EAPI char *ecore_file_readlink (const char *link); +EAPI Eina_List *ecore_file_ls (const char *dir); +EAPI Eina_Iterator *ecore_file_ls_iterator (const char *dir); +EAPI char *ecore_file_app_exe_get (const char *app); +EAPI char *ecore_file_escape_name (const char *filename); +EAPI char *ecore_file_strip_ext (const char *file); +EAPI int ecore_file_dir_is_empty (const char *dir); + +/* Monitoring */ + +EAPI Ecore_File_Monitor *ecore_file_monitor_add(const char *path, + Ecore_File_Monitor_Cb func, + void *data); +EAPI void ecore_file_monitor_del(Ecore_File_Monitor *ecore_file_monitor); +EAPI const char *ecore_file_monitor_path_get(Ecore_File_Monitor *ecore_file_monitor); + +/* Path */ + +EAPI Eina_Bool ecore_file_path_dir_exists(const char *in_dir); +EAPI Eina_Bool ecore_file_app_installed(const char *exe); +EAPI Eina_List *ecore_file_app_list(void); + +/* Download */ + +EAPI Eina_Bool ecore_file_download(const char *url, + const char *dst, + Ecore_File_Download_Completion_Cb completion_cb, + Ecore_File_Download_Progress_Cb progress_cb, + void *data, + Ecore_File_Download_Job **job_ret); +EAPI Eina_Bool ecore_file_download_full(const char *url, + const char *dst, + Ecore_File_Download_Completion_Cb completion_cb, + Ecore_File_Download_Progress_Cb progress_cb, + void *data, + Ecore_File_Download_Job **job_ret, + Eina_Hash *headers); + +EAPI void ecore_file_download_abort_all(void); +EAPI void ecore_file_download_abort(Ecore_File_Download_Job *job); +EAPI Eina_Bool ecore_file_download_protocol_available(const char *protocol); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/ecore_file/Makefile.am b/src/lib/ecore_file/Makefile.am new file mode 100644 index 0000000..ab23ace --- /dev/null +++ b/src/lib/ecore_file/Makefile.am @@ -0,0 +1,41 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore_con \ +-I$(top_builddir)/src/lib/ecore \ +@EFL_ECORE_FILE_BUILD@ \ +@CURL_CFLAGS@ \ +@EVIL_CFLAGS@ \ +@EINA_CFLAGS@ \ +@WIN32_CPPFLAGS@ + +AM_CFLAGS = @WIN32_CFLAGS@ + +if BUILD_ECORE_CON +lib_ecore_con_la = $(top_builddir)/src/lib/ecore_con/libecore_con.la +endif + +lib_LTLIBRARIES = libecore_file.la +includes_HEADERS = Ecore_File.h +includesdir = $(includedir)/ecore-@VMAJ@ + +libecore_file_la_SOURCES = \ +ecore_file.c \ +ecore_file_monitor.c \ +ecore_file_monitor_inotify.c \ +ecore_file_monitor_win32.c \ +ecore_file_monitor_poll.c \ +ecore_file_path.c \ +ecore_file_download.c + +libecore_file_la_LIBADD = \ +$(top_builddir)/src/lib/ecore/libecore.la \ +$(lib_ecore_con_la) \ +@EVIL_LIBS@ \ +@EINA_LIBS@ + +libecore_file_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ + +EXTRA_DIST = ecore_file_private.h + diff --git a/src/lib/ecore_file/ecore_file.c b/src/lib/ecore_file/ecore_file.c new file mode 100644 index 0000000..fd06f7d --- /dev/null +++ b/src/lib/ecore_file/ecore_file.c @@ -0,0 +1,1109 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#ifndef _MSC_VER +# include +# include +#endif + +#ifdef _WIN32 +# include +#endif + +#ifdef HAVE_FEATURES_H +# include +#endif +#include +#include + +#ifdef HAVE_ATFILE_SOURCE +# include +#endif + +#include "ecore_file_private.h" + +int _ecore_file_log_dom = -1; +static int _ecore_file_init_count = 0; + +/* externally accessible functions */ + +/** + * @addtogroup Ecore_File_Group Ecore_File - Files and directories convenience functions + * + * @{ + */ + +/** + * @brief Initialize the Ecore_File library. + * + * @return 1 or greater on success, 0 on error. + * + * This function sets up Ecore_File and the services it will use + * (monitoring, downloading, PATH related feature). It returns 0 on + * failure, otherwise it returns the number of times it has already + * been called. + * + * When Ecore_File is not used anymore, call ecore_file_shutdown() + * to shut down the Ecore_File library. + */ +EAPI int +ecore_file_init() +{ + if (++_ecore_file_init_count != 1) + return _ecore_file_init_count; + + if (!ecore_init()) + return --_ecore_file_init_count; + + _ecore_file_log_dom = eina_log_domain_register + ("ecore_file", ECORE_FILE_DEFAULT_LOG_COLOR); + if(_ecore_file_log_dom < 0) + { + EINA_LOG_ERR("Impossible to create a log domain for the ecore file module."); + return --_ecore_file_init_count; + } + ecore_file_path_init(); + ecore_file_monitor_init(); + ecore_file_download_init(); + + /* FIXME: were the tests disabled for a good reason ? */ + + /* + if (!ecore_file_monitor_init()) + goto shutdown_ecore_file_path; + + if (!ecore_file_download_init()) + goto shutdown_ecore_file_monitor; + */ + + return _ecore_file_init_count; + + /* + shutdown_ecore_file_monitor: + ecore_file_monitor_shutdown(); + shutdown_ecore_file_path: + ecore_file_path_shutdown(); + + return --_ecore_file_init_count; + */ +} + +/** + * @brief Shut down the Ecore_File library. + * + * @return 0 when the library is completely shut down, 1 or + * greater otherwise. + * + * This function shuts down the Ecore_File library. It returns 0 when it has + * been called the same number of times than ecore_file_init(). In that case + * it shuts down all the services it uses. + */ +EAPI int +ecore_file_shutdown() +{ + if (--_ecore_file_init_count != 0) + return _ecore_file_init_count; + + ecore_file_download_shutdown(); + ecore_file_monitor_shutdown(); + ecore_file_path_shutdown(); + + eina_log_domain_unregister(_ecore_file_log_dom); + _ecore_file_log_dom = -1; + + ecore_shutdown(); + + return _ecore_file_init_count; +} + +/** + * @brief Get the time of the last modification to the given file. + * + * @param file The name of the file. + * @return Return the time of the last data modification, or 0 on + * failure. + * + * This function returns the time of the last modification of + * @p file. On failure, it returns 0. + */ +EAPI long long +ecore_file_mod_time(const char *file) +{ + struct stat st; + + if (stat(file, &st) < 0) return 0; + return st.st_mtime; +} + +/** + * @brief Get the size of the given file. + * + * @param file The name of the file. + * @return Return the size of the file in bytes, or 0 on failure. + * + * This function returns the size of @p file in bytes. On failure, it + * returns 0. + */ +EAPI long long +ecore_file_size(const char *file) +{ + struct stat st; + + if (stat(file, &st) < 0) return 0; + return st.st_size; +} + +/** + * @brief Check if the given file exists. + * + * @param file The name of the file. + * @return @c EINA_TRUE if the @p file exists, @c EINA_FALSE otherwise. + * + * This function returns @c EINA_TRUE if @p file exists on local filesystem, + * @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_file_exists(const char *file) +{ + struct stat st; + if (!file) return EINA_FALSE; + + /*Workaround so that "/" returns a true, otherwise we can't monitor "/" in ecore_file_monitor*/ + if (stat(file, &st) < 0 && strcmp(file, "/")) return EINA_FALSE; + return EINA_TRUE; +} + +/** + * @brief Check if the given file is a directory. + * + * @param file The name of the file. + * @return @c EINA_TRUE if the file exists and is a directory, @c EINA_FALSE + * otherwise. + * + * This function returns @c EINA_TRUE if @p file exists exists and is a + * directory on local filesystem, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_file_is_dir(const char *file) +{ + struct stat st; + + if (stat(file, &st) < 0) return EINA_FALSE; + if (S_ISDIR(st.st_mode)) return EINA_TRUE; + return EINA_FALSE; +} + +static mode_t default_mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; + +/** + * @brief Create a new directory. + * + * @param dir The name of the directory to create + * @return @c EINA_TRUE on successful creation, @c EINA_FALSE otherwise. + * + * This function creates the directory @p dir with the mode S_IRUSR | + * S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH. On + * success, it returns @c EINA_TRUE, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_file_mkdir(const char *dir) +{ + if (mkdir(dir, default_mode) < 0) return EINA_FALSE; + return EINA_TRUE; +} + +/** + * @brief Create complete directory in a batch. + * + * @param dirs The list of directories, null terminated. + * @return The number of successful directories created, -1 if dirs is + * @c NULL. + * + * This function creates all the directories that are in the null + * terminated array @p dirs. The function loops over the directories + * and call ecore_file_mkdir(). This function returns -1 if @p dirs is + * @c NULL, otherwise if returns the number of suceesfully created + * directories. + */ +EAPI int +ecore_file_mkdirs(const char **dirs) +{ + int i = 0; + + if (!dirs) return -1; + + for (; *dirs; dirs++) + if (ecore_file_mkdir(*dirs)) + i++; + return i; +} + +/** + * @brief Create complete list of sub-directories in a batch (optimized). + * + * @param base The base directory to act on. + * @param subdirs The list of directories, null terminated. + * @return number of successful directories created, -1 on failure. + * + * This function creates all the directories that are in the null + * terminated array @p dirs in the @p base directory. If @p base does + * not exist, it will be created. The function loops over the directories + * and call ecore_file_mkdir(). The whole path of the directories must + * exist. So if base/a/b/c wants to be created, @p subdirs must + * contain "a", "a/b" and "a/b/c", in that order. This function + * returns -1 if @p dirs or @p base are @c NULL, or if @p base is + * empty ("\0"). It returns 0 is @p base is not a directory or + * invalid, or if it can't be created. Otherwise if returns the number + * of suceesfully created directories. + */ +EAPI int +ecore_file_mksubdirs(const char *base, const char **subdirs) +{ +#ifndef HAVE_ATFILE_SOURCE + char buf[PATH_MAX]; + int baselen; +#else + int fd; + DIR *dir; +#endif + int i; + + if (!subdirs) return -1; + if ((!base) || (base[0] == '\0')) return -1; + + if ((!ecore_file_is_dir(base)) && (!ecore_file_mkpath(base))) + return 0; + +#ifndef HAVE_ATFILE_SOURCE + baselen = eina_strlcpy(buf, base, sizeof(buf)); + if ((baselen < 1) || (baselen + 1 >= (int)sizeof(buf))) + return 0; + + if (buf[baselen - 1] != '/') + { + buf[baselen] = '/'; + baselen++; + } +#else + dir = opendir(base); + if (!dir) + return 0; + fd = dirfd(dir); +#endif + + i = 0; + for (; *subdirs; subdirs++) + { + struct stat st; + +#ifndef HAVE_ATFILE_SOURCE + eina_strlcpy(buf + baselen, *subdirs, sizeof(buf) - baselen); + if (stat(buf, &st) == 0) +#else + if (fstatat(fd, *subdirs, &st, 0) == 0) +#endif + { + if (S_ISDIR(st.st_mode)) + { + i++; + continue; + } + } + else + { + if (errno == ENOENT) + { +#ifndef HAVE_ATFILE_SOURCE + if (mkdir(buf, default_mode) == 0) +#else + if (mkdirat(fd, *subdirs, default_mode) == 0) +#endif + { + i++; + continue; + } + } + } + } + +#ifdef HAVE_ATFILE_SOURCE + closedir(dir); +#endif + + return i; +} + +/** + * @brief Delete the given directory. + * + * @param dir The name of the directory to delete. + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * This function deletes @p dir. It returns @c EINA_TRUE on success, + * @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_file_rmdir(const char *dir) +{ + if (rmdir(dir) < 0) return EINA_FALSE; + return EINA_TRUE; +} + +/** + * @brief Delete the given file. + * + * @param file The name of the file to delete. + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * This function deletes @p file. It returns @c EINA_TRUE on success, + * @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_file_unlink(const char *file) +{ + if (unlink(file) < 0) return EINA_FALSE; + return EINA_TRUE; +} + +/** + * @brief Remove the given file or directory. + * + * @param file The name of the file or directory to delete. + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * This function removes @p file. It returns @c EINA_TRUE on success, + * @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_file_remove(const char *file) +{ + if (remove(file) < 0) return EINA_FALSE; + return EINA_TRUE; +} + +/** + * @brief Delete the given directory and all its contents. + * + * @param dir The name of the directory to delete. + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * This function delete @p dir and all its contents. If @p dir is a + * link only the link is removed. It returns @c EINA_TRUE on success, + * @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_file_recursive_rm(const char *dir) +{ + Eina_Iterator *it; + char buf[PATH_MAX]; + struct stat st; + int ret; + + if (readlink(dir, buf, sizeof(buf)) > 0) + return ecore_file_unlink(dir); + + ret = stat(dir, &st); + if ((ret == 0) && (S_ISDIR(st.st_mode))) + { + Eina_File_Direct_Info *info; + + ret = 1; + if (stat(dir, &st) == -1) return EINA_FALSE; /* WOOT: WHY ARE WE CALLING STAT TWO TIMES ??? */ + + it = eina_file_direct_ls(dir); + EINA_ITERATOR_FOREACH(it, info) + { + if (!ecore_file_recursive_rm(info->path)) + ret = 0; + } + eina_iterator_free(it); + + if (!ecore_file_rmdir(dir)) ret = 0; + if (ret) + return EINA_TRUE; + else + return EINA_FALSE; + } + else + { + if (ret == -1) return EINA_FALSE; + return ecore_file_unlink(dir); + } +} + +static inline Eina_Bool +_ecore_file_mkpath_if_not_exists(const char *path) +{ + struct stat st; + + /* Windows: path like C: or D: etc are valid, but stat() returns an error */ +#ifdef _WIN32 + if ((strlen(path) == 2) && + ((path[0] >= 'a' && path[0] <= 'z') || + (path[0] >= 'A' && path[0] <= 'Z')) && + (path[1] == ':')) + return EINA_TRUE; +#endif + + if (stat(path, &st) < 0) + return ecore_file_mkdir(path); + else if (!S_ISDIR(st.st_mode)) + return EINA_FALSE; + else + return EINA_TRUE; +} + +/** + * @brief Create a complete path. + * + * @param path The path to create + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * This function creates @p path and all the subdirectories it + * contains. The separator is '/' or '\'. If @p path exists, this + * function returns @c EINA_TRUE immediately. It returns @c EINA_TRUE on + * success, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_file_mkpath(const char *path) +{ + char ss[PATH_MAX]; + unsigned int i; + + if (ecore_file_is_dir(path)) + return EINA_TRUE; + + for (i = 0; path[i] != '\0'; ss[i] = path[i], i++) + { + if (i == sizeof(ss) - 1) return EINA_FALSE; + if (((path[i] == '/') || (path[i] == '\\')) && (i > 0)) + { + ss[i] = '\0'; + if (!_ecore_file_mkpath_if_not_exists(ss)) + return EINA_FALSE; + } + } + ss[i] = '\0'; + return _ecore_file_mkpath_if_not_exists(ss); +} + +/** + * @brief Create complete paths in a batch. + * + * @param paths list of paths, null terminated. + * @return number of successful paths created, -1 if paths is NULL. + * + * This function creates all the directories that are in the null + * terminated array @p paths. The function loops over the directories + * and call ecore_file_mkpath(), hence on Windows, '\' must be + * replaced by '/' before calling that function. This function + * returns -1 if @p paths is @c NULL. Otherwise if returns the number + * of suceesfully created directories. + */ +EAPI int +ecore_file_mkpaths(const char **paths) +{ + int i = 0; + + if (!paths) return -1; + + for (; *paths; paths++) + if (ecore_file_mkpath(*paths)) + i++; + return i; +} + +/** + * @brief Copy the given file to the given destination. + * + * @param src The name of the source file. + * @param dst The name of the destination file. + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * This function copies @p src to @p dst. If the absolute path name of + * @p src and @p dst can not be computed, or if they are equal, or if + * the copy fails, the function returns @c EINA_FALSE, otherwise it + * returns @c EINA_TRUE. + */ +EAPI Eina_Bool +ecore_file_cp(const char *src, const char *dst) +{ + FILE *f1, *f2; + char buf[16384]; + char realpath1[PATH_MAX], realpath2[PATH_MAX]; + size_t num; + Eina_Bool ret = EINA_TRUE; + + if (!realpath(src, realpath1)) return EINA_FALSE; + if (realpath(dst, realpath2) && !strcmp(realpath1, realpath2)) return EINA_FALSE; + + f1 = fopen(src, "rb"); + if (!f1) return EINA_FALSE; + f2 = fopen(dst, "wb"); + if (!f2) + { + fclose(f1); + return EINA_FALSE; + } + while ((num = fread(buf, 1, sizeof(buf), f1)) > 0) + { + if (fwrite(buf, 1, num, f2) != num) ret = EINA_FALSE; + } + fclose(f1); + fclose(f2); + return ret; +} + +/** + * @brief Move the given file to the given destination. + * + * @param src The name of the source file. + * @param dst The name of the destination file. + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * This function moves @p src to @p dst. It returns @c EINA_TRUE on + * success, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_file_mv(const char *src, const char *dst) +{ + char buf[PATH_MAX]; + int fd; + + if (rename(src, dst)) + { + // File cannot be moved directly because + // it resides on a different mount point. + if (errno == EXDEV) + { + struct stat st; + + // Make sure this is a regular file before + // we do anything fancy. + stat(src, &st); + if (S_ISREG(st.st_mode)) + { + char *dir; + + dir = ecore_file_dir_get(dst); + // Since we can't directly rename, try to + // copy to temp file in the dst directory + // and then rename. + snprintf(buf, sizeof(buf), "%s/.%s.tmp.XXXXXX", + dir, ecore_file_file_get(dst)); + free(dir); + fd = mkstemp(buf); + if (fd < 0) goto FAIL; + close(fd); + + // Copy to temp file + if (!ecore_file_cp(src, buf)) + goto FAIL; + + // Set file permissions of temp file to match src + chmod(buf, st.st_mode); + + // Try to atomically move temp file to dst + if (rename(buf, dst)) + { + // If we still cannot atomically move + // do a normal copy and hope for the best. + if (!ecore_file_cp(buf, dst)) + goto FAIL; + } + + // Delete temporary file and src + ecore_file_unlink(buf); + ecore_file_unlink(src); + goto PASS; + } + } + goto FAIL; + } + +PASS: + return EINA_TRUE; + +FAIL: + return EINA_FALSE; +} + +/** + * @brief Create a symbolic link. + * + * @param src The name of the file to link. + * @param dest The name of link. + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * This function create the symbolic link @p dest of @p src. This + * function does not work on Windows. It returns @c EINA_TRUE on success, + * @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_file_symlink(const char *src, const char *dest) +{ + if (!symlink(src, dest)) return EINA_TRUE; + + return EINA_FALSE; +} + +/** + * @brief Get the canonicalized absolute path name. + * + * @param file The file path. + * @return The canonicalized absolute pathname or an empty string on + * failure. + * + * This function returns the absolute path name of @p file as a newly + * allocated string. If @p file is @c NULL, or on error, this function + * returns an empty string. Otherwise, it returns the absolute path + * name. When not needed anymore, the returned value must be freed. + */ +EAPI char * +ecore_file_realpath(const char *file) +{ + char buf[PATH_MAX]; + + /* + * Some implementations of realpath do not conform to the SUS. + * And as a result we must prevent a null arg from being passed. + */ + if (!file) return strdup(""); + if (!realpath(file, buf)) return strdup(""); + + return strdup(buf); +} + +/** + * Get the filename from a given path. + * + * @param path The complete path. + * @return The file name. + * + * This function returns the file name of @p path. If @p path is + * @c NULL, the functions returns @c NULL. + */ +EAPI const char * +ecore_file_file_get(const char *path) +{ + char *result = NULL; + + if (!path) return NULL; + if ((result = strrchr(path, '/'))) result++; + else result = (char *)path; + return result; +} + +/** + * @brief Get the directory where the given file resides. + * + * @param file The name of the file. + * @return The directory name. + * + * This function returns the directory where @p file resides as anewly + * allocated string. If @p file is @c NULL or on error, this function + * returns @c NULL. When not needed anymore, the returned value must + * be freed. + */ +EAPI char * +ecore_file_dir_get(const char *file) +{ + char *p; + char buf[PATH_MAX]; + + if (!file) return NULL; + strncpy(buf, file, PATH_MAX); + buf[PATH_MAX - 1] = 0; + p = dirname(buf); + return strdup(p); +} + +/** + * @brief Check if the given file can be read. + * + * @param file The name of the file. + * @return @c EINA_TRUE if the @p file is readable, @c EINA_FALSE otherwise. + * + * This function returns @c EINA_TRUE if @p file can be read, @c EINA_FALSE + * otherwise. + */ +EAPI Eina_Bool +ecore_file_can_read(const char *file) +{ + if (!file) return EINA_FALSE; + if (!access(file, R_OK)) return EINA_TRUE; + return EINA_FALSE; +} + +/** + * @brief Check if the given file can be written. + * + * @param file The name of the file. + * @return @c EINA_TRUE if the @p file is writable, @c EINA_FALSE otherwise. + * + * This function returns @c EINA_TRUE if @p file can be written, @c EINA_FALSE + * otherwise. + */ +EAPI Eina_Bool +ecore_file_can_write(const char *file) +{ + if (!file) return EINA_FALSE; + if (!access(file, W_OK)) return EINA_TRUE; + return EINA_FALSE; +} + +/** + * @brief Check if the given file can be executed. + * + * @param file The name of the file. + * @return @c EINA_TRUE if the @p file can be executed, @c EINA_FALSE + * otherwise. + * + * This function returns @c EINA_TRUE if @p file can be executed, @c EINA_FALSE + * otherwise. + */ +EAPI Eina_Bool +ecore_file_can_exec(const char *file) +{ + if (!file) return EINA_FALSE; + if (!access(file, X_OK)) return EINA_TRUE; + return EINA_FALSE; +} + +/** + * @brief Get the path pointed by the given link. + * + * @param lnk The name of the link. + * @return The path pointed by link or NULL. + * + * This function returns the path pointed by @p link as a newly + * allocated string. This function does not work on Windows. On + * failure, the function returns @c NULL. When not needed anymore, the + * returned value must be freed. + */ +EAPI char * +ecore_file_readlink(const char *lnk) +{ + char buf[PATH_MAX]; + int count; + + if ((count = readlink(lnk, buf, sizeof(buf) - 1)) < 0) return NULL; + buf[count] = 0; + return strdup(buf); +} + +/** + * @brief Get the list of the files and directories in the given + * directory. + * + * @param dir The name of the directory to list + * @return Return an Eina_List containing all the files in the directory; + * on failure it returns NULL. + * + * This function returns a list of allocated strings of all the files + * and directories contained in @p dir. The list will be sorted with + * strcoll as compare function. That means that you may want to set + * the current locale for the category LC_COLLATE with + * setlocale(). For more information see the manual pages of strcoll + * and setlocale. The list will not contain the directory entries for + * '.' and '..'. On failure, @c NULL is returned. When not needed + * anymore, the list elements must be freed. + */ +EAPI Eina_List * +ecore_file_ls(const char *dir) +{ + Eina_File_Direct_Info *info; + Eina_Iterator *ls; + Eina_List *list = NULL; + + ls = eina_file_direct_ls(dir); + if (!ls) return NULL; + + EINA_ITERATOR_FOREACH(ls, info) + { + char *f; + + f = strdup(info->path + info->name_start); + list = eina_list_append(list, f); + } + eina_iterator_free(ls); + + list = eina_list_sort(list, eina_list_count(list), EINA_COMPARE_CB(strcoll)); + + return list; +} + +/** + * @brief Return the executable from the given command. + * + * @param app The application command, with parameters. + * @return The executable from @p app as a newly allocated string. Arguments + * are removed and escape characters are handled. If @p app is @c NULL, or + * on failure, the function returns @c NULL. When not needed anymore, the + * returned value must be freed. + */ +EAPI char * +ecore_file_app_exe_get(const char *app) +{ + char *p, *pp, *exe1 = NULL, *exe2 = NULL; + char *exe = NULL; + int in_quot_dbl = 0, in_quot_sing = 0, restart = 0; + + if (!app) return NULL; + + p = (char *)app; +restart: + while ((*p) && (isspace((unsigned char)*p))) p++; + exe1 = p; + while (*p) + { + if (in_quot_sing) + { + if (*p == '\'') + in_quot_sing = 0; + } + else if (in_quot_dbl) + { + if (*p == '\"') + in_quot_dbl = 0; + } + else + { + if (*p == '\'') + in_quot_sing = 1; + else if (*p == '\"') + in_quot_dbl = 1; + if ((isspace((unsigned char)*p)) && ((p <= app) || (p[-1] == '\\'))) + break; + } + p++; + } + exe2 = p; + if (exe2 == exe1) return NULL; + if (*exe1 == '~') + { + char *homedir; + int len; + + /* Skip ~ */ + exe1++; + + homedir = getenv("HOME"); + if (!homedir) return NULL; + len = strlen(homedir); + if (exe) free(exe); + exe = malloc(len + exe2 - exe1 + 2); + if (!exe) return NULL; + pp = exe; + if (len) + { + strcpy(exe, homedir); + pp += len; + if (*(pp - 1) != '/') + { + *pp = '/'; + pp++; + } + } + } + else + { + if (exe) free(exe); + exe = malloc(exe2 - exe1 + 1); + if (!exe) return NULL; + pp = exe; + } + p = exe1; + restart = 0; + in_quot_dbl = 0; + in_quot_sing = 0; + while (*p) + { + if (in_quot_sing) + { + if (*p == '\'') + in_quot_sing = 0; + else + { + *pp = *p; + pp++; + } + } + else if (in_quot_dbl) + { + if (*p == '\"') + in_quot_dbl = 0; + else + { + /* technically this is wrong. double quotes also accept + * special chars: + * + * $, `, \ + */ + *pp = *p; + pp++; + } + } + else + { + /* technically we should handle special chars: + * + * $, `, \, etc. + */ + if ((p > exe1) && (p[-1] == '\\')) + { + if (*p != '\n') + { + *pp = *p; + pp++; + } + } + else if ((p > exe1) && (*p == '=')) + { + restart = 1; + *pp = *p; + pp++; + } + else if (*p == '\'') + in_quot_sing = 1; + else if (*p == '\"') + in_quot_dbl = 1; + else if (isspace((unsigned char)*p)) + { + if (restart) + goto restart; + else + break; + } + else + { + *pp = *p; + pp++; + } + } + p++; + } + *pp = 0; + return exe; +} + +/** + * @brief Add the escape sequence ('\\') to the given file name. + * + * @param filename The file name. + * @return The file name with special characters escaped. + * + * This function adds the escape sequence ('\\') to the given file + * name and returns the result as a newly allocated string. If the + * length of the returned string is longer than PATH_MAX, or on + * failure, @c NULL is returned. When not needed anymore, the returned + * value must be freed. + */ +EAPI char * +ecore_file_escape_name(const char *filename) +{ + const char *p; + char *q; + char buf[PATH_MAX]; + + p = filename; + q = buf; + while (*p) + { + if ((q - buf) > (PATH_MAX - 6)) return NULL; + if ( + (*p == ' ') || (*p == '\t') || (*p == '\n') || + (*p == '\\') || (*p == '\'') || (*p == '\"') || + (*p == ';') || (*p == '!') || (*p == '#') || + (*p == '$') || (*p == '%') || (*p == '&') || + (*p == '*') || (*p == '(') || (*p == ')') || + (*p == '[') || (*p == ']') || (*p == '{') || + (*p == '}') || (*p == '|') || (*p == '<') || + (*p == '>') || (*p == '?') + ) + { + *q = '\\'; + q++; + } + *q = *p; + q++; + p++; + } + *q = 0; + return strdup(buf); +} + +/** + * @brief Remove the extension from the given file name. + * + * @param path The name of the file. + * @return A newly allocated string with the extension stripped out or + * @c NULL on errors. + * + * This function removes the extension from @p path and returns the + * result as a newly allocated string. If @p path is @c NULL, or on + * failure, the function returns @c NULL. When not needed anymore, the + * returned value must be freed. + */ +EAPI char * +ecore_file_strip_ext(const char *path) +{ + char *p, *file = NULL; + + if (!path) + return NULL; + + p = strrchr(path, '.'); + if (!p) + file = strdup(path); + else if (p != path) + { + file = malloc(((p - path) + 1) * sizeof(char)); + if (file) + { + memcpy(file, path, (p - path)); + file[p - path] = 0; + } + } + + return file; +} + +/** + * @brief Check if the given directory is empty. + * + * @param dir The name of the directory to check. + * @return @c 1 if directory is empty, @c 0 if it has at least one file or + * @c -1 in case of errors. + * + * This functions checks if @p dir is empty. The '.' and '..' files + * will be ignored. If @p dir is empty, 1 is returned, if it contains + * at least one file, @c 0 is returned. On failure, @c -1 is returned. + */ +EAPI int +ecore_file_dir_is_empty(const char *dir) +{ + Eina_File_Direct_Info *info; + Eina_Iterator *it; + + it = eina_file_direct_ls(dir); + if (!it) return -1; + + EINA_ITERATOR_FOREACH(it, info) + { + eina_iterator_free(it); + return 0; + } + + eina_iterator_free(it); + return 1; +} + +/** + * @} + */ diff --git a/src/lib/ecore_file/ecore_file_download.c b/src/lib/ecore_file/ecore_file_download.c new file mode 100644 index 0000000..ea8550d --- /dev/null +++ b/src/lib/ecore_file/ecore_file_download.c @@ -0,0 +1,449 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#ifdef BUILD_ECORE_CON +# include "Ecore_Con.h" +#endif + +#include "ecore_file_private.h" + +#ifdef BUILD_ECORE_CON + +#define ECORE_MAGIC_FILE_DOWNLOAD_JOB 0xf7427cb8 +#define ECORE_FILE_DOWNLOAD_TIMEOUT 30 + +struct _Ecore_File_Download_Job +{ + ECORE_MAGIC; + + Ecore_Con_Url *url_con; + FILE *file; + + char *dst; + + Ecore_File_Download_Completion_Cb completion_cb; + Ecore_File_Download_Progress_Cb progress_cb; +}; + +#ifdef HAVE_CURL +Ecore_File_Download_Job *_ecore_file_download_curl(const char *url, const char *dst, + Ecore_File_Download_Completion_Cb completion_cb, + Ecore_File_Download_Progress_Cb progress_cb, + void *data, + Eina_Hash *headers); + +static Eina_Bool _ecore_file_download_url_complete_cb(void *data, int type, void *event); +static Eina_Bool _ecore_file_download_url_progress_cb(void *data, int type, void *event); +#endif + +static Ecore_Event_Handler *_url_complete_handler = NULL; +static Ecore_Event_Handler *_url_progress_download = NULL; +static Eina_List *_job_list; + +static int download_init = 0; + +#endif /* BUILD_ECORE_CON */ + +int +ecore_file_download_init(void) +{ +#ifdef BUILD_ECORE_CON + download_init++; + if (download_init > 1) return 1; + if (!ecore_con_init()) return 0; + if (!ecore_con_url_init()) + { + ecore_con_shutdown(); + return 0; + } +# ifdef HAVE_CURL + _url_complete_handler = ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, _ecore_file_download_url_complete_cb, NULL); + _url_progress_download = ecore_event_handler_add(ECORE_CON_EVENT_URL_PROGRESS, _ecore_file_download_url_progress_cb, NULL); +# endif +#endif /* BUILD_ECORE_CON */ + return 1; +} + +void +ecore_file_download_shutdown(void) +{ +#ifdef BUILD_ECORE_CON + download_init--; + if (download_init > 0) return; + if (_url_complete_handler) + ecore_event_handler_del(_url_complete_handler); + if (_url_progress_download) + ecore_event_handler_del(_url_progress_download); + _url_complete_handler = NULL; + _url_progress_download = NULL; + ecore_file_download_abort_all(); + ecore_con_url_shutdown(); + ecore_con_shutdown(); +#endif /* BUILD_ECORE_CON */ +} + +#ifdef BUILD_ECORE_CON +# ifdef HAVE_CURL +static Eina_Bool +_ecore_file_download_headers_foreach_cb(const Eina_Hash *hash __UNUSED__, const void *key, void *data, void *fdata) +{ + Ecore_File_Download_Job *job = fdata; + ecore_con_url_additional_header_add(job->url_con, key, data); + + return EINA_TRUE; +} +# endif +#endif + +static Eina_Bool +_ecore_file_download(const char *url, + const char *dst, + Ecore_File_Download_Completion_Cb completion_cb, + Ecore_File_Download_Progress_Cb progress_cb, + void *data, + Ecore_File_Download_Job **job_ret, + Eina_Hash *headers) +{ +#ifdef BUILD_ECORE_CON + char *dir = ecore_file_dir_get(dst); + + if (!ecore_file_is_dir(dir)) + { + ERR("%s is not a directory", dir); + free(dir); + return EINA_FALSE; + } + free(dir); + if (ecore_file_exists(dst)) + { + WRN("%s already exists", dst); + return EINA_FALSE; + } + + if (!strncmp(url, "file://", 7)) + { + /* FIXME: Maybe fork? Might take a while to copy. + * Check filesize? */ + /* Just copy it */ + + url += 7; + /* skip hostname */ + url = strchr(url, '/'); + return ecore_file_cp(url, dst); + } +# ifdef HAVE_CURL + else if ((!strncmp(url, "http://", 7)) || (!strncmp(url, "https://", 8)) || + (!strncmp(url, "ftp://", 6))) + { + /* download */ + Ecore_File_Download_Job *job; + + job = _ecore_file_download_curl(url, dst, completion_cb, progress_cb, data, headers); + if(job_ret) *job_ret = job; + if(job) + return EINA_TRUE; + else + { + ERR("no job returned\n"); + return EINA_FALSE; + } + return job ? EINA_TRUE : EINA_FALSE; + } +# else + else if ((!strncmp(url, "http://", 7)) || (!strncmp(url, "https://", 8)) || + (!strncmp(url, "ftp://", 6))) + { + (void)completion_cb; + (void)progress_cb; + (void)data; + (void)job_ret; + (void)headers; + return EINA_FALSE; + } +# endif + else + { + return EINA_FALSE; + } +#else + (void)url; + (void)dst; + (void)completion_cb; + (void)progress_cb; + (void)data; + (void)job_ret; + (void)headers; + return EINA_FALSE; +#endif /* BUILD_ECORE_CON */ +} + +/** + * @addtogroup Ecore_File_Group Ecore_File - Files and directories convenience functions + * + * @{ + */ + +/** + * @brief Download the given url to the given destination. + * + * @param url The complete url to download. + * @param dst The local file to save the downloaded to. + * @param completion_cb A callback called on download complete. + * @param progress_cb A callback called during the download operation. + * @param data User data passed to both callbacks. + * @param job_ret Job used to abort the download. + * @return @c EINA_TRUE if the download start or @c EINA_FALSE on failure. + * + * This function starts the download of the URL @p url and saves it to + * @p dst. @p url must provide the protocol, including 'http://', + * 'ftp://' or 'file://'. Ecore_File must be compiled with CURL to + * download using http and ftp protocols. If @p dst is ill-formed, or + * if it already exists, the function returns @c EINA_FALSE. When the + * download is complete, the callback @p completion_cb is called and + * @p data is passed to it. The @p status parameter of @p completion_cb + * will be filled with the status of the download (200, 404,...). The + * @p progress_cb is called during the download operation, each time a + * packet is received or when CURL wants. It can be used to display the + * percentage of the downloaded file. Return 0 from this callback, if provided, + * to continue the operation or anything else to abort the download. The only + * operations that can be aborted are those with protocol 'http' or 'ftp'. In + * that case @p job_ret can be filled. It can be used with + * ecore_file_download_abort() or ecore_file_download_abort_all() to + * respectively abort one or all download operations. This function returns + * @c EINA_TRUE if the download starts, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_file_download(const char *url, + const char *dst, + Ecore_File_Download_Completion_Cb completion_cb, + Ecore_File_Download_Progress_Cb progress_cb, + void *data, + Ecore_File_Download_Job **job_ret) +{ + return _ecore_file_download(url, dst, completion_cb, progress_cb, data, job_ret, NULL); +} + +/** + * @brief Download the given url to the given destination with additional headers. + * + * @param url The complete url to download. + * @param dst The local file to save the downloaded to. + * @param completion_cb A callback called on download complete. + * @param progress_cb A callback called during the download operation. + * @param data User data passed to both callbacks. + * @param job_ret Job used to abort the download. + * @param headers pointer of header lists. + * @return @c EINA_TRUE if the download start or @c EINA_FALSE on failure. + */ +EAPI Eina_Bool +ecore_file_download_full(const char *url, + const char *dst, + Ecore_File_Download_Completion_Cb completion_cb, + Ecore_File_Download_Progress_Cb progress_cb, + void *data, + Ecore_File_Download_Job **job_ret, + Eina_Hash *headers) +{ + return _ecore_file_download(url, dst, completion_cb, progress_cb, data, job_ret, headers); +} + +/** + * @brief Check if the given protocol is available. + * + * @param protocol The protocol to check. + * @return @c EINA_TRUE if protocol is handled, @c EINA_FALSE otherwise. + * + * This function returns @c EINA_TRUE if @p protocol is supported, + * @c EINA_FALSE otherwise. @p protocol can be 'http://', 'ftp://' or + * 'file://'. Ecore_FILE must be compiled with CURL to handle http and + * ftp protocols. + */ +EAPI Eina_Bool +ecore_file_download_protocol_available(const char *protocol) +{ +#ifdef BUILD_ECORE_CON + if (!strncmp(protocol, "file://", 7)) return EINA_TRUE; +# ifdef HAVE_CURL + else if (!strncmp(protocol, "http://", 7)) return EINA_TRUE; + else if (!strncmp(protocol, "ftp://", 6)) return EINA_TRUE; +# endif +#else + (void)protocol; +#endif /* BUILD_ECORE_CON */ + + return EINA_FALSE; +} + +#ifdef BUILD_ECORE_CON + +# ifdef HAVE_CURL +static int +_ecore_file_download_url_compare_job(const void *data1, const void *data2) +{ + const Ecore_File_Download_Job *job = data1; + const Ecore_Con_Url *url = data2; + + if (job->url_con == url) return 0; + return -1; +} + +static Eina_Bool +_ecore_file_download_url_complete_cb(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Con_Event_Url_Complete *ev = event; + Ecore_File_Download_Job *job; + + job = eina_list_search_unsorted(_job_list, _ecore_file_download_url_compare_job, ev->url_con); + if (!ECORE_MAGIC_CHECK(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB)) return ECORE_CALLBACK_PASS_ON; + + fclose(job->file); + if (job->completion_cb) + job->completion_cb(ecore_con_url_data_get(job->url_con), job->dst, ev->status); + + _job_list = eina_list_remove(_job_list, job); + free(job->dst); + ecore_con_url_free(job->url_con); + free(job); + + return ECORE_CALLBACK_DONE; +} + +static Eina_Bool +_ecore_file_download_url_progress_cb(void *data __UNUSED__, int type __UNUSED__, void *event) +{ +/* this reports the downloads progress. if we return 0, then download + * continues, if we return anything else, then the download stops */ + Ecore_Con_Event_Url_Progress *ev = event; + Ecore_File_Download_Job *job; + + job = eina_list_search_unsorted(_job_list, _ecore_file_download_url_compare_job, ev->url_con); + if (!ECORE_MAGIC_CHECK(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB)) return ECORE_CALLBACK_PASS_ON; + + if (job->progress_cb) + if (job->progress_cb(ecore_con_url_data_get(job->url_con), job->dst, + (long int) ev->down.total, (long int) ev->down.now, + (long int) ev->up.total, (long int) ev->up.now) != 0) + { + _job_list = eina_list_remove(_job_list, job); + fclose(job->file); + free(job->dst); + free(job); + + return ECORE_CALLBACK_PASS_ON; + } + + return ECORE_CALLBACK_DONE; +} + +Ecore_File_Download_Job * +_ecore_file_download_curl(const char *url, const char *dst, + Ecore_File_Download_Completion_Cb completion_cb, + Ecore_File_Download_Progress_Cb progress_cb, + void *data, + Eina_Hash *headers) +{ + Ecore_File_Download_Job *job; + + job = calloc(1, sizeof(Ecore_File_Download_Job)); + if (!job) return NULL; + + ECORE_MAGIC_SET(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB); + + job->file = fopen(dst, "wb"); + if (!job->file) + { + free(job); + return NULL; + } + job->url_con = ecore_con_url_new(url); + if (!job->url_con) + { + fclose(job->file); + free(job); + return NULL; + } + + if (headers) eina_hash_foreach(headers, _ecore_file_download_headers_foreach_cb, job); + ecore_con_url_fd_set(job->url_con, fileno(job->file)); + ecore_con_url_data_set(job->url_con, data); + + job->dst = strdup(dst); + + job->completion_cb = completion_cb; + job->progress_cb = progress_cb; + _job_list = eina_list_append(_job_list, job); + + if (!ecore_con_url_get(job->url_con)) + { + ecore_con_url_free(job->url_con); + _job_list = eina_list_remove(_job_list, job); + fclose(job->file); + ecore_file_remove(job->dst); + free(job->dst); + free(job); + return NULL; + } + + return job; +} +# endif +#endif + +/** + * @brief Abort the given download job and call the completion_cb + * callbck with a status of 1 (error). + * + * @param job The download job to abort. + * + * This function aborts a download operation started by + * ecore_file_download(). @p job is the #Ecore_File_Download_Job + * structure filled by ecore_file_download(). If it is @c NULL, this + * function does nothing. To abort all the currently downloading + * operations, call ecore_file_download_abort_all(). + */ +EAPI void +ecore_file_download_abort(Ecore_File_Download_Job *job) +{ + if (!job) + return; + +#ifdef BUILD_ECORE_CON + if (job->completion_cb) + job->completion_cb(ecore_con_url_data_get(job->url_con), job->dst, 1); +# ifdef HAVE_CURL + ecore_con_url_free(job->url_con); +# endif + _job_list = eina_list_remove(_job_list, job); + fclose(job->file); + free(job->dst); + free(job); +#endif /* BUILD_ECORE_CON */ +} + +/** + * @brief Abort all downloads. + * + * This function aborts all the downloads that have been started by + * ecore_file_download(). It loops over the started downloads and call + * ecore_file_download_abort() for each of them. To abort only one + * specific download operation, call ecore_file_download_abort(). + */ +EAPI void +ecore_file_download_abort_all(void) +{ +#ifdef BUILD_ECORE_CON + Ecore_File_Download_Job *job; + + EINA_LIST_FREE(_job_list, job) + ecore_file_download_abort(job); +#endif /* BUILD_ECORE_CON */ +} + +/** + * @} + */ diff --git a/src/lib/ecore_file/ecore_file_monitor.c b/src/lib/ecore_file/ecore_file_monitor.c new file mode 100644 index 0000000..8b07589 --- /dev/null +++ b/src/lib/ecore_file/ecore_file_monitor.c @@ -0,0 +1,180 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "ecore_file_private.h" + +typedef enum { + ECORE_FILE_MONITOR_TYPE_NONE, +#ifdef HAVE_INOTIFY + ECORE_FILE_MONITOR_TYPE_INOTIFY, +#endif +#ifdef HAVE_NOTIFY_WIN32 + ECORE_FILE_MONITOR_TYPE_NOTIFY_WIN32, +#endif +#ifdef HAVE_POLL + ECORE_FILE_MONITOR_TYPE_POLL +#endif +} Ecore_File_Monitor_Type; + +static Ecore_File_Monitor_Type monitor_type = ECORE_FILE_MONITOR_TYPE_NONE; + +int +ecore_file_monitor_init(void) +{ +#ifdef HAVE_INOTIFY + monitor_type = ECORE_FILE_MONITOR_TYPE_INOTIFY; + if (ecore_file_monitor_inotify_init()) + return 1; +#endif +#ifdef HAVE_NOTIFY_WIN32 + monitor_type = ECORE_FILE_MONITOR_TYPE_NOTIFY_WIN32; + if (ecore_file_monitor_win32_init()) + return 1; +#endif +#ifdef HAVE_POLL + monitor_type = ECORE_FILE_MONITOR_TYPE_POLL; + if (ecore_file_monitor_poll_init()) + return 1; +#endif + monitor_type = ECORE_FILE_MONITOR_TYPE_NONE; + return 0; +} + +void +ecore_file_monitor_shutdown(void) +{ + switch (monitor_type) + { + case ECORE_FILE_MONITOR_TYPE_NONE: + break; +#ifdef HAVE_INOTIFY + case ECORE_FILE_MONITOR_TYPE_INOTIFY: + ecore_file_monitor_inotify_shutdown(); + break; +#endif +#ifdef HAVE_NOTIFY_WIN32 + case ECORE_FILE_MONITOR_TYPE_NOTIFY_WIN32: + ecore_file_monitor_win32_shutdown(); + break; +#endif +#ifdef HAVE_POLL + case ECORE_FILE_MONITOR_TYPE_POLL: + ecore_file_monitor_poll_shutdown(); + break; +#endif + } +} + +/** + * @addtogroup Ecore_File_Group Ecore_File - Files and directories convenience functions + * + * @{ + */ + +/** + * @brief Monitor the given path using inotify, Windows notification, or polling. + * + * @param path The path to monitor. + * @param func The function to call on changes. + * @param data The data passed to func. + * @return An Ecore_File_Monitor pointer or NULL on failure. + * + * This function monitors @p path. If @p path is @c NULL, or is an + * empty string, or none of the notify methods (Inotify, Windows + * notification or polling) is available, or if @p path is not a file, + * the function returns @c NULL. Otherwise, it returns a newly + * allocated Ecore_File_Monitor object and the monitoring begins. When + * one of the Ecore_File_Event event is notified, @p func is called + * and @p data is passed to @p func. Call ecore_file_monitor_del() to + * stop the monitoring. + */ +EAPI Ecore_File_Monitor * +ecore_file_monitor_add(const char *path, + Ecore_File_Monitor_Cb func, + void *data) +{ + if (!path || !*path) + return NULL; + + switch (monitor_type) + { + case ECORE_FILE_MONITOR_TYPE_NONE: + return NULL; +#ifdef HAVE_INOTIFY + case ECORE_FILE_MONITOR_TYPE_INOTIFY: + return ecore_file_monitor_inotify_add(path, func, data); +#endif +#ifdef HAVE_NOTIFY_WIN32 + case ECORE_FILE_MONITOR_TYPE_NOTIFY_WIN32: + return ecore_file_monitor_win32_add(path, func, data); +#endif +#ifdef HAVE_POLL + case ECORE_FILE_MONITOR_TYPE_POLL: + return ecore_file_monitor_poll_add(path, func, data); +#endif + } + return NULL; +} + +/** + * @brief Stop the monitoring of the given path. + * + * @param em The Ecore_File_Monitor to stop. + * + * This function stops the the monitoring of the path that has been + * monitored by ecore_file_monitor_add(). @p em must be the value + * returned by ecore_file_monitor_add(). If @p em is @c NULL, or none + * of the notify methods (Inotify, Windows notification or polling) is + * availablethis function does nothing. + */ +EAPI void +ecore_file_monitor_del(Ecore_File_Monitor *em) +{ + if (!em) + return; + + switch (monitor_type) + { + case ECORE_FILE_MONITOR_TYPE_NONE: + break; +#ifdef HAVE_INOTIFY + case ECORE_FILE_MONITOR_TYPE_INOTIFY: + ecore_file_monitor_inotify_del(em); + break; +#endif +#ifdef HAVE_NOTIFY_WIN32 + case ECORE_FILE_MONITOR_TYPE_NOTIFY_WIN32: + ecore_file_monitor_win32_del(em); + break; +#endif +#ifdef HAVE_POLL + case ECORE_FILE_MONITOR_TYPE_POLL: + ecore_file_monitor_poll_del(em); + break; +#endif + } +} + +/** + * @brief Get the monitored path. + * + * @param em The Ecore_File_Monitor to query. + * @return The path that is monitored by @p em. + * + * This function returns the monitored path that has been + * monitored by ecore_file_monitor_add(). @p em must be the value + * returned by ecore_file_monitor_add(). If @p em is @c NULL, the + * function returns @c NULL. + */ +EAPI const char * +ecore_file_monitor_path_get(Ecore_File_Monitor *em) +{ + if (!em) + return NULL; + return em->path; +} + +/** + * @} + */ diff --git a/src/lib/ecore_file/ecore_file_monitor_inotify.c b/src/lib/ecore_file/ecore_file_monitor_inotify.c new file mode 100644 index 0000000..30226d3 --- /dev/null +++ b/src/lib/ecore_file/ecore_file_monitor_inotify.c @@ -0,0 +1,370 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include "ecore_file_private.h" + +/* + * TODO: + * + * - Listen to these events: + * IN_ACCESS, IN_ATTRIB, IN_CLOSE_WRITE, IN_CLOSE_NOWRITE, IN_OPEN + * - Read all events first, then call the callbacks. This will prevent several + * callbacks with the typic save cycle (delete file, new file) + * - Listen to IN_IGNORED, emitted when the watch is removed + */ + +#ifdef HAVE_INOTIFY + +#ifdef HAVE_SYS_INOTIFY +# include +#else +# include +# include +#endif + +#ifndef HAVE_SYS_INOTIFY +static inline int inotify_init(void); +static inline int inotify_add_watch(int fd, const char *name, __u32 mask); +static inline int inotify_rm_watch(int fd, __u32 wd); +#endif + + +typedef struct _Ecore_File_Monitor_Inotify Ecore_File_Monitor_Inotify; + +#define ECORE_FILE_MONITOR_INOTIFY(x) ((Ecore_File_Monitor_Inotify *)(x)) + +struct _Ecore_File_Monitor_Inotify +{ + Ecore_File_Monitor monitor; + int wd; +}; + +static Ecore_Fd_Handler *_fdh = NULL; +static Ecore_File_Monitor *_monitors = NULL; +static pid_t _inotify_fd_pid = -1; + +static Eina_Bool _ecore_file_monitor_inotify_handler(void *data, Ecore_Fd_Handler *fdh); +static Ecore_File_Monitor *_ecore_file_monitor_inotify_monitor_find(int wd); +static void _ecore_file_monitor_inotify_events(Ecore_File_Monitor *em, char *file, int mask); +static int _ecore_file_monitor_inotify_monitor(Ecore_File_Monitor *em, const char *path); +#if 0 +static void _ecore_file_monitor_inotify_print(char *file, int mask); +#endif + +int +ecore_file_monitor_inotify_init(void) +{ + int fd; + + fd = inotify_init(); + if (fd < 0) + return 0; + + _fdh = ecore_main_fd_handler_add(fd, ECORE_FD_READ, _ecore_file_monitor_inotify_handler, + NULL, NULL, NULL); + if (!_fdh) + { + close(fd); + return 0; + } + + _inotify_fd_pid = getpid(); + return 1; +} + +int +ecore_file_monitor_inotify_shutdown(void) +{ + int fd; + + while(_monitors) + ecore_file_monitor_inotify_del(_monitors); + + if (_fdh) + { + fd = ecore_main_fd_handler_fd_get(_fdh); + ecore_main_fd_handler_del(_fdh); + close(fd); + } + _inotify_fd_pid = -1; + return 1; +} + +Ecore_File_Monitor * +ecore_file_monitor_inotify_add(const char *path, + void (*func) (void *data, Ecore_File_Monitor *em, + Ecore_File_Event event, + const char *path), + void *data) +{ + Ecore_File_Monitor *em; + int len; + + if (_inotify_fd_pid == -1) return NULL; + + if (_inotify_fd_pid != getpid()) + { + ecore_file_monitor_inotify_shutdown(); + ecore_file_monitor_inotify_init(); + } + + em = calloc(1, sizeof(Ecore_File_Monitor_Inotify)); + if (!em) return NULL; + + em->func = func; + em->data = data; + + em->path = strdup(path); + len = strlen(em->path); + if (em->path[len - 1] == '/' && strcmp(em->path, "/")) + em->path[len - 1] = 0; + + _monitors = ECORE_FILE_MONITOR(eina_inlist_append(EINA_INLIST_GET(_monitors), EINA_INLIST_GET(em))); + + if (ecore_file_exists(em->path)) + { + if (!_ecore_file_monitor_inotify_monitor(em, em->path)) + return NULL; + } + else + { + ecore_file_monitor_inotify_del(em); + return NULL; + } + + return em; +} + +void +ecore_file_monitor_inotify_del(Ecore_File_Monitor *em) +{ + int fd; + + if (_monitors) + _monitors = ECORE_FILE_MONITOR(eina_inlist_remove(EINA_INLIST_GET(_monitors), EINA_INLIST_GET(em))); + + fd = ecore_main_fd_handler_fd_get(_fdh); + if (ECORE_FILE_MONITOR_INOTIFY(em)->wd) + inotify_rm_watch(fd, ECORE_FILE_MONITOR_INOTIFY(em)->wd); + free(em->path); + free(em); +} + +static Eina_Bool +_ecore_file_monitor_inotify_handler(void *data __UNUSED__, Ecore_Fd_Handler *fdh) +{ + Ecore_File_Monitor *em; + char buffer[16384]; + struct inotify_event *event; + int i = 0; + int event_size; + ssize_t size; + + size = read(ecore_main_fd_handler_fd_get(fdh), buffer, sizeof(buffer)); + while (i < size) + { + event = (struct inotify_event *)&buffer[i]; + event_size = sizeof(struct inotify_event) + event->len; + i += event_size; + + em = _ecore_file_monitor_inotify_monitor_find(event->wd); + if (!em) continue; + + _ecore_file_monitor_inotify_events(em, (event->len ? event->name : NULL), event->mask); + } + + return ECORE_CALLBACK_RENEW; +} + +static Ecore_File_Monitor * +_ecore_file_monitor_inotify_monitor_find(int wd) +{ + Ecore_File_Monitor *l; + + EINA_INLIST_FOREACH(_monitors, l) + { + if (ECORE_FILE_MONITOR_INOTIFY(l)->wd == wd) + return l; + } + return NULL; +} + +static void +_ecore_file_monitor_inotify_events(Ecore_File_Monitor *em, char *file, int mask) +{ + char buf[PATH_MAX]; + int isdir; + + if ((file) && (file[0])) + snprintf(buf, sizeof(buf), "%s/%s", em->path, file); + else + strcpy(buf, em->path); + isdir = mask & IN_ISDIR; + +#if 0 + _ecore_file_monitor_inotify_print(buf, mask); +#endif + + if (mask & IN_ATTRIB) + { + em->func(em->data, em, ECORE_FILE_EVENT_MODIFIED, buf); + } + if (mask & IN_CLOSE_WRITE) + { + if (!isdir) + em->func(em->data, em, ECORE_FILE_EVENT_CLOSED, buf); + } + if (mask & IN_MODIFY) + { + if (!isdir) + em->func(em->data, em, ECORE_FILE_EVENT_MODIFIED, buf); + } + if (mask & IN_MOVED_FROM) + { + if (isdir) + em->func(em->data, em, ECORE_FILE_EVENT_DELETED_DIRECTORY, buf); + else + em->func(em->data, em, ECORE_FILE_EVENT_DELETED_FILE, buf); + } + if (mask & IN_MOVED_TO) + { + if (isdir) + em->func(em->data, em, ECORE_FILE_EVENT_CREATED_DIRECTORY, buf); + else + em->func(em->data, em, ECORE_FILE_EVENT_CREATED_FILE, buf); + } + if (mask & IN_DELETE) + { + if (isdir) + em->func(em->data, em, ECORE_FILE_EVENT_DELETED_DIRECTORY, buf); + else + em->func(em->data, em, ECORE_FILE_EVENT_DELETED_FILE, buf); + } + if (mask & IN_CREATE) + { + if (isdir) + em->func(em->data, em, ECORE_FILE_EVENT_CREATED_DIRECTORY, buf); + else + em->func(em->data, em, ECORE_FILE_EVENT_CREATED_FILE, buf); + } + if (mask & IN_DELETE_SELF) + { + em->func(em->data, em, ECORE_FILE_EVENT_DELETED_SELF, em->path); + } + if (mask & IN_MOVE_SELF) + { + /* We just call delete. The dir is gone... */ + em->func(em->data, em, ECORE_FILE_EVENT_DELETED_SELF, em->path); + } + if (mask & IN_UNMOUNT) + { + /* We just call delete. The dir is gone... */ + em->func(em->data, em, ECORE_FILE_EVENT_DELETED_SELF, em->path); + } + if (mask & IN_IGNORED) + { + /* The watch is removed. If the file name still exists monitor the new one, + * else delete it */ + if (ecore_file_exists(em->path)) + { + if (_ecore_file_monitor_inotify_monitor(em, em->path)) + em->func(em->data, em, ECORE_FILE_EVENT_DELETED_SELF, em->path); + } + else + em->func(em->data, em, ECORE_FILE_EVENT_DELETED_SELF, em->path); + } +} + +static int +_ecore_file_monitor_inotify_monitor(Ecore_File_Monitor *em, const char *path) +{ + int mask = + IN_ATTRIB | + IN_CLOSE_WRITE | + IN_MOVED_FROM | + IN_MOVED_TO | + IN_DELETE | + IN_CREATE | + IN_MODIFY | + IN_DELETE_SELF | + IN_MOVE_SELF | + IN_UNMOUNT; + + ECORE_FILE_MONITOR_INOTIFY(em)->wd = + inotify_add_watch(ecore_main_fd_handler_fd_get(_fdh), path, mask); + if (ECORE_FILE_MONITOR_INOTIFY(em)->wd < 0) + { + INF("inotify_add_watch failed, file was deleted"); + ecore_file_monitor_inotify_del(em); + return 0; + } + return 1; +} + +#ifndef HAVE_SYS_INOTIFY +static inline int +inotify_init(void) +{ + return syscall(__NR_inotify_init); +} + +static inline int +inotify_add_watch(int fd, const char *name, __u32 mask) +{ + return syscall(__NR_inotify_add_watch, fd, name, mask); +} + +static inline int +inotify_rm_watch(int fd, __u32 wd) +{ + return syscall(__NR_inotify_rm_watch, fd, wd); +} +#endif + +#if 0 +static void +_ecore_file_monitor_inotify_print(char *file, int mask) +{ + const char *type; + + if (mask & IN_ISDIR) + type = "dir"; + else + type = "file"; + + if (mask & IN_ACCESS) + INF("Inotify accessed %s: %s", type, file); + if (mask & IN_MODIFY) + INF("Inotify modified %s: %s", type, file); + if (mask & IN_ATTRIB) + INF("Inotify attributes %s: %s", type, file); + if (mask & IN_CLOSE_WRITE) + INF("Inotify close write %s: %s", type, file); + if (mask & IN_CLOSE_NOWRITE) + INF("Inotify close write %s: %s", type, file); + if (mask & IN_OPEN) + INF("Inotify open %s: %s", type, file); + if (mask & IN_MOVED_FROM) + INF("Inotify moved from %s: %s", type, file); + if (mask & IN_MOVED_TO) + INF("Inotify moved to %s: %s", type, file); + if (mask & IN_DELETE) + INF("Inotify delete %s: %s", type, file); + if (mask & IN_CREATE) + INF("Inotify create %s: %s", type, file); + if (mask & IN_DELETE_SELF) + INF("Inotify delete self %s: %s", type, file); + if (mask & IN_MOVE_SELF) + INF("Inotify move self %s: %s", type, file); + if (mask & IN_UNMOUNT) + INF("Inotify unmount %s: %s", type, file); +} +#endif +#endif /* HAVE_INOTIFY */ diff --git a/src/lib/ecore_file/ecore_file_monitor_poll.c b/src/lib/ecore_file/ecore_file_monitor_poll.c new file mode 100644 index 0000000..49bfcb6 --- /dev/null +++ b/src/lib/ecore_file/ecore_file_monitor_poll.c @@ -0,0 +1,340 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "ecore_file_private.h" + +#ifdef HAVE_POLL + +/* + * TODO: + * - Implement recursive as an option! + * - Keep whole path or just name of file? (Memory or CPU...) + * - Remove requests without files? + * - Change poll time + */ + +typedef struct _Ecore_File_Monitor_Poll Ecore_File_Monitor_Poll; + +#define ECORE_FILE_MONITOR_POLL(x) ((Ecore_File_Monitor_Poll *)(x)) + +struct _Ecore_File_Monitor_Poll +{ + Ecore_File_Monitor monitor; + int mtime; + unsigned char deleted; +}; + +#define ECORE_FILE_INTERVAL_MIN 1.0 +#define ECORE_FILE_INTERVAL_STEP 0.5 +#define ECORE_FILE_INTERVAL_MAX 5.0 + +static double _interval = ECORE_FILE_INTERVAL_MIN; +static Ecore_Timer *_timer = NULL; +static Ecore_File_Monitor *_monitors = NULL; +static int _lock = 0; + +static Eina_Bool _ecore_file_monitor_poll_handler(void *data); +static void _ecore_file_monitor_poll_check(Ecore_File_Monitor *em); +static int _ecore_file_monitor_poll_checking(Ecore_File_Monitor *em, char *name); + +int +ecore_file_monitor_poll_init(void) +{ + return 1; +} + +int +ecore_file_monitor_poll_shutdown(void) +{ + while(_monitors) + ecore_file_monitor_poll_del(_monitors); + + if (_timer) + { + ecore_timer_del(_timer); + _timer = NULL; + } + return 1; +} + +Ecore_File_Monitor * +ecore_file_monitor_poll_add(const char *path, + void (*func) (void *data, Ecore_File_Monitor *em, + Ecore_File_Event event, + const char *path), + void *data) +{ + Ecore_File_Monitor *em; + size_t len; + + if (!path) return NULL; + if (!func) return NULL; + + em = calloc(1, sizeof(Ecore_File_Monitor_Poll)); + if (!em) return NULL; + + if (!_timer) + _timer = ecore_timer_add(_interval, _ecore_file_monitor_poll_handler, NULL); + else + ecore_timer_interval_set(_timer, ECORE_FILE_INTERVAL_MIN); + + em->path = strdup(path); + len = strlen(em->path); + if (em->path[len - 1] == '/' && strcmp(em->path, "/")) + em->path[len - 1] = 0; + + em->func = func; + em->data = data; + + ECORE_FILE_MONITOR_POLL(em)->mtime = ecore_file_mod_time(em->path); + _monitors = ECORE_FILE_MONITOR(eina_inlist_append(EINA_INLIST_GET(_monitors), EINA_INLIST_GET(em))); + + if (ecore_file_exists(em->path)) + { + if (ecore_file_is_dir(em->path)) + { + /* Check for subdirs */ + Eina_List *files; + char *file; + + files = ecore_file_ls(em->path); + EINA_LIST_FREE(files, file) + { + Ecore_File *f; + char buf[PATH_MAX]; + + f = calloc(1, sizeof(Ecore_File)); + if (!f) + { + free(file); + continue; + } + + snprintf(buf, sizeof(buf), "%s/%s", em->path, file); + f->name = file; + f->mtime = ecore_file_mod_time(buf); + f->is_dir = ecore_file_is_dir(buf); + em->files = (Ecore_File *) eina_inlist_append(EINA_INLIST_GET(em->files), EINA_INLIST_GET(f)); + } + } + } + else + { + ecore_file_monitor_poll_del(em); + return NULL; + } + + return em; +} + +void +ecore_file_monitor_poll_del(Ecore_File_Monitor *em) +{ + Ecore_File *l; + + if (_lock) + { + ECORE_FILE_MONITOR_POLL(em)->deleted = 1; + return; + } + + /* Remove files */ + /*It's possible there weren't any files to monitor, so check if the list is init*/ + if (em->files) + { + for (l = em->files; l;) + { + Ecore_File *file = l; + + l = (Ecore_File *) EINA_INLIST_GET(l)->next; + free(file->name); + free(file); + } + } + + if (_monitors) + _monitors = ECORE_FILE_MONITOR(eina_inlist_remove(EINA_INLIST_GET(_monitors), EINA_INLIST_GET(em))); + + free(em->path); + free(em); + + if (_timer) + { + if (!_monitors) + { + ecore_timer_del(_timer); + _timer = NULL; + } + else + ecore_timer_interval_set(_timer, ECORE_FILE_INTERVAL_MIN); + } +} + +static Eina_Bool +_ecore_file_monitor_poll_handler(void *data __UNUSED__) +{ + Ecore_File_Monitor *l; + + _interval += ECORE_FILE_INTERVAL_STEP; + + _lock = 1; + EINA_INLIST_FOREACH(_monitors, l) + _ecore_file_monitor_poll_check(l); + _lock = 0; + + if (_interval > ECORE_FILE_INTERVAL_MAX) + _interval = ECORE_FILE_INTERVAL_MAX; + ecore_timer_interval_set(_timer, _interval); + + for (l = _monitors; l;) + { + Ecore_File_Monitor *em = l; + + l = ECORE_FILE_MONITOR(EINA_INLIST_GET(l)->next); + if (ECORE_FILE_MONITOR_POLL(em)->deleted) + ecore_file_monitor_del(em); + } + return ECORE_CALLBACK_RENEW; +} + +static void +_ecore_file_monitor_poll_check(Ecore_File_Monitor *em) +{ + int mtime; + + mtime = ecore_file_mod_time(em->path); + if (mtime < ECORE_FILE_MONITOR_POLL(em)->mtime) + { + Ecore_File *l; + Ecore_File_Event event; + + /* Notify all files deleted */ + for (l = em->files; l;) + { + Ecore_File *f = l; + char buf[PATH_MAX]; + + l = (Ecore_File *) EINA_INLIST_GET(l)->next; + + snprintf(buf, sizeof(buf), "%s/%s", em->path, f->name); + if (f->is_dir) + event = ECORE_FILE_EVENT_DELETED_DIRECTORY; + else + event = ECORE_FILE_EVENT_DELETED_FILE; + em->func(em->data, em, event, buf); + free(f->name); + free(f); + } + em->files = NULL; + em->func(em->data, em, ECORE_FILE_EVENT_DELETED_SELF, em->path); + _interval = ECORE_FILE_INTERVAL_MIN; + } + else + { + Ecore_File *l; + + /* Check for changed files */ + for (l = em->files; l;) + { + Ecore_File *f = l; + char buf[PATH_MAX]; + int mt; + Ecore_File_Event event; + + l = (Ecore_File *) EINA_INLIST_GET(l)->next; + + snprintf(buf, sizeof(buf), "%s/%s", em->path, f->name); + mt = ecore_file_mod_time(buf); + if (mt < f->mtime) + { + if (f->is_dir) + event = ECORE_FILE_EVENT_DELETED_DIRECTORY; + else + event = ECORE_FILE_EVENT_DELETED_FILE; + + em->func(em->data, em, event, buf); + em->files = (Ecore_File *) eina_inlist_remove(EINA_INLIST_GET(em->files), EINA_INLIST_GET(f)); + free(f->name); + free(f); + _interval = ECORE_FILE_INTERVAL_MIN; + } + else if ((mt > f->mtime) && !(f->is_dir)) + { + em->func(em->data, em, ECORE_FILE_EVENT_MODIFIED, buf); + _interval = ECORE_FILE_INTERVAL_MIN; + f->mtime = mt; + } + else + f->mtime = mt; + } + + /* Check for new files */ + if (ECORE_FILE_MONITOR_POLL(em)->mtime < mtime) + { + Eina_List *files; + Eina_List *fl; + char *file; + + /* Files have been added or removed */ + files = ecore_file_ls(em->path); + if (files) + { + /* Are we a directory? We should check first, rather than rely on null here*/ + EINA_LIST_FOREACH(files, fl, file) + { + Ecore_File *f; + char buf[PATH_MAX]; + Ecore_File_Event event; + + if (_ecore_file_monitor_poll_checking(em, file)) + continue; + + snprintf(buf, sizeof(buf), "%s/%s", em->path, file); + f = calloc(1, sizeof(Ecore_File)); + if (!f) + continue; + + f->name = strdup(file); + f->mtime = ecore_file_mod_time(buf); + f->is_dir = ecore_file_is_dir(buf); + if (f->is_dir) + event = ECORE_FILE_EVENT_CREATED_DIRECTORY; + else + event = ECORE_FILE_EVENT_CREATED_FILE; + em->func(em->data, em, event, buf); + em->files = (Ecore_File *) eina_inlist_append(EINA_INLIST_GET(em->files), EINA_INLIST_GET(f)); + } + while (files) + { + file = eina_list_data_get(files); + free(file); + files = eina_list_remove_list(files, files); + } + } + + if (!ecore_file_is_dir(em->path)) + em->func(em->data, em, ECORE_FILE_EVENT_MODIFIED, em->path); + _interval = ECORE_FILE_INTERVAL_MIN; + } + } + ECORE_FILE_MONITOR_POLL(em)->mtime = mtime; +} + +static int +_ecore_file_monitor_poll_checking(Ecore_File_Monitor *em, char *name) +{ + Ecore_File *l; + + EINA_INLIST_FOREACH(em->files, l) + { + if (!strcmp(l->name, name)) + return 1; + } + return 0; +} +#endif diff --git a/src/lib/ecore_file/ecore_file_monitor_win32.c b/src/lib/ecore_file/ecore_file_monitor_win32.c new file mode 100644 index 0000000..7f3af09 --- /dev/null +++ b/src/lib/ecore_file/ecore_file_monitor_win32.c @@ -0,0 +1,310 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_NOTIFY_WIN32 + +# define WIN32_LEAN_AND_MEAN +# include +# undef WIN32_LEAN_AND_MEAN +# include + +# include "ecore_file_private.h" + + +typedef struct _Ecore_File_Monitor_Win32 Ecore_File_Monitor_Win32; +typedef struct _Ecore_File_Monitor_Win32_Data Ecore_File_Monitor_Win32_Data; + +/* 4096 = 256 * sizeof(FILE_NOTIFY_INFORMATION) */ +# define ECORE_FILE_MONITOR_WIN32_BUFFER_SIZE 4096 +# define ECORE_FILE_MONITOR_WIN32(x) ((Ecore_File_Monitor_Win32 *)(x)) + +struct _Ecore_File_Monitor_Win32_Data +{ + char buffer[ECORE_FILE_MONITOR_WIN32_BUFFER_SIZE]; + OVERLAPPED overlapped; + HANDLE handle; + HANDLE event; + Ecore_File_Monitor *monitor; + Ecore_Win32_Handler *h; + DWORD buf_length; + int is_dir; +}; + +struct _Ecore_File_Monitor_Win32 +{ + Ecore_File_Monitor monitor; + Ecore_File_Monitor_Win32_Data *file; + Ecore_File_Monitor_Win32_Data *dir; +}; + +static Ecore_File_Monitor *_monitors = NULL; + +static Eina_Bool _ecore_file_monitor_win32_cb(void *data, Ecore_Win32_Handler *wh); + + +static Ecore_File_Monitor_Win32_Data * +_ecore_file_monitor_win32_data_new(Ecore_File_Monitor *monitor, int type) +{ + Ecore_File_Monitor_Win32_Data *md; + DWORD filter; + + md = (Ecore_File_Monitor_Win32_Data *)calloc(1, sizeof(Ecore_File_Monitor_Win32_Data)); + if (!md) return NULL; + + md->handle = CreateFile(monitor->path, + FILE_LIST_DIRECTORY, + FILE_SHARE_READ | + FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | + FILE_FLAG_OVERLAPPED, + NULL); + if (md->handle == INVALID_HANDLE_VALUE) + goto free_md; + + md->event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!md->event) + goto close_handle; + + ZeroMemory (&md->overlapped, sizeof(md->overlapped)); + md->overlapped.hEvent = md->event; + + filter = (type == 0) ? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME; + filter |= + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_LAST_ACCESS | + FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_SECURITY; + + if (!ReadDirectoryChangesW(md->handle, + md->buffer, + ECORE_FILE_MONITOR_WIN32_BUFFER_SIZE, + FALSE, + filter, + &md->buf_length, + &md->overlapped, + NULL)) + goto close_event; + + md->h = ecore_main_win32_handler_add(md->event, + _ecore_file_monitor_win32_cb, + md); + if (!md->h) + goto close_event; + + md->monitor = monitor; + md->is_dir = type; + + return md; + + close_event: + CloseHandle(md->event); + close_handle: + CloseHandle(md->handle); + free_md: + free(md); + + return NULL; +} + +static void +_ecore_file_monitor_win32_data_free(Ecore_File_Monitor_Win32_Data *md) +{ + if (!md) return; + + CloseHandle(md->event); + CloseHandle (md->handle); + free (md); +} + +static Eina_Bool +_ecore_file_monitor_win32_cb(void *data, Ecore_Win32_Handler *wh) +{ + char filename[PATH_MAX]; + PFILE_NOTIFY_INFORMATION fni; + Ecore_File_Monitor_Win32_Data *md; + wchar_t *wname; + char *name; + DWORD filter; + DWORD offset; + DWORD buf_length; + Ecore_File_Event event = ECORE_FILE_EVENT_NONE; + + md = (Ecore_File_Monitor_Win32_Data *)data; + + if (!GetOverlappedResult (md->handle, &md->overlapped, &buf_length, TRUE)) + return 1; + + fni = (PFILE_NOTIFY_INFORMATION)md->buffer; + do { + if (!fni) + break; + offset = fni->NextEntryOffset; + + wname = (wchar_t *)malloc(sizeof(wchar_t) * (fni->FileNameLength + 1)); + if (!wname) + return 0; + + memcpy(wname, fni->FileName, fni->FileNameLength); + wname[fni->FileNameLength]='\0'; + name = evil_wchar_to_char(wname); + free(wname); + if (!name) + return 0; + + _snprintf(filename, PATH_MAX, "%s\\%s", md->monitor->path, name); + free(name); + + switch (fni->Action) + { + case FILE_ACTION_ADDED: + if (md->is_dir) + event = ECORE_FILE_EVENT_CREATED_DIRECTORY; + else + event = ECORE_FILE_EVENT_CREATED_FILE; + break; + case FILE_ACTION_REMOVED: + if (md->is_dir) + event = ECORE_FILE_EVENT_DELETED_DIRECTORY; + else + event = ECORE_FILE_EVENT_DELETED_FILE; + break; + case FILE_ACTION_MODIFIED: + if (!md->is_dir) + event = ECORE_FILE_EVENT_MODIFIED; + break; + case FILE_ACTION_RENAMED_OLD_NAME: + if (md->is_dir) + event = ECORE_FILE_EVENT_DELETED_DIRECTORY; + else + event = ECORE_FILE_EVENT_DELETED_FILE; + break; + case FILE_ACTION_RENAMED_NEW_NAME: + if (md->is_dir) + event = ECORE_FILE_EVENT_CREATED_DIRECTORY; + else + event = ECORE_FILE_EVENT_CREATED_FILE; + break; + default: + fprintf(stderr, "unknown event\n"); + event = ECORE_FILE_EVENT_NONE; + break; + } + if (event != ECORE_FILE_EVENT_NONE) + md->monitor->func(md->monitor->data, md->monitor, event, filename); + + fni = (PFILE_NOTIFY_INFORMATION)((LPBYTE)fni + offset); + } while (offset); + + filter = (md->is_dir == 0) ? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME; + filter |= + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_LAST_ACCESS | + FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_SECURITY; + + ReadDirectoryChangesW(md->handle, + md->buffer, + ECORE_FILE_MONITOR_WIN32_BUFFER_SIZE, + FALSE, + filter, + &md->buf_length, + &md->overlapped, + NULL); + return 1; +} + +int +ecore_file_monitor_win32_init(void) +{ + return 1; +} + +int +ecore_file_monitor_win32_shutdown(void) +{ + return 1; +} + +Ecore_File_Monitor * +ecore_file_monitor_win32_add(const char *path, + void (*func) (void *data, Ecore_File_Monitor *em, + Ecore_File_Event event, + const char *path), + void *data) +{ + Ecore_File_Monitor_Win32 *m; + Ecore_File_Monitor *em; + size_t len; + + if (!path || (*path == '\0')) return NULL; + if (!ecore_file_exists(path) || !ecore_file_is_dir(path)) + return NULL; + if (!func) return NULL; + + em = (Ecore_File_Monitor *)calloc(1, sizeof(Ecore_File_Monitor_Win32)); + if (!em) return NULL; + + em->func = func; + em->data = data; + + em->path = strdup(path); + if (!em->path) + { + free(em); + return NULL; + } + len = strlen(em->path); + if (em->path[len - 1] == '/' || em->path[len - 1] == '\\') + em->path[len - 1] = '\0'; + + m = ECORE_FILE_MONITOR_WIN32(em); + + m->file = _ecore_file_monitor_win32_data_new(em, 0); + if (!m->file) + { + free(em->path); + free(em); + return NULL; + } + + m->dir = _ecore_file_monitor_win32_data_new(em, 1); + if (!m->dir) + { + _ecore_file_monitor_win32_data_free(m->file); + free(em->path); + free(em); + return NULL; + } + + _monitors = ECORE_FILE_MONITOR(eina_inlist_append(EINA_INLIST_GET(_monitors), EINA_INLIST_GET(em))); + + return em; +} + +void +ecore_file_monitor_win32_del(Ecore_File_Monitor *em) +{ + Ecore_File_Monitor_Win32 *m; + + if (!em) + return; + + m = ECORE_FILE_MONITOR_WIN32(em); + _ecore_file_monitor_win32_data_free(m->dir); + _ecore_file_monitor_win32_data_free(m->file); + free(em->path); + free(em); +} + +#endif diff --git a/src/lib/ecore_file/ecore_file_path.c b/src/lib/ecore_file/ecore_file_path.c new file mode 100644 index 0000000..3c06e9b --- /dev/null +++ b/src/lib/ecore_file/ecore_file_path.c @@ -0,0 +1,184 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#undef alloca +#ifdef HAVE_ALLOCA_H +# include +#elif defined __GNUC__ +# define alloca __builtin_alloca +#elif defined _AIX +# define alloca __alloca +#elif defined _MSC_VER +# include +# define alloca _alloca +#else +# include +# ifdef __cplusplus +extern "C" +# endif +void *alloca (size_t); +#endif + +#include +#include +#include + +#include "ecore_file_private.h" + +static Eina_List *__ecore_file_path_bin = NULL; + +static Eina_List *_ecore_file_path_from_env(const char *env); + +void +ecore_file_path_init(void) +{ + __ecore_file_path_bin = _ecore_file_path_from_env("PATH"); +} + +void +ecore_file_path_shutdown(void) +{ + char *dir; + + EINA_LIST_FREE(__ecore_file_path_bin, dir) + eina_stringshare_del(dir); +} + +Eina_List * +_ecore_file_path_from_env(const char *env) +{ + Eina_List *path = NULL; + char *env_tmp, *env_path, *p, *last; + + env_tmp = getenv(env); + if (!env_tmp) + return path; + + env_path = alloca(sizeof(char) * strlen(env_tmp) + 1); + memset(env_path, 0, strlen(env_tmp)); + strcpy(env_path, env_tmp); + last = env_path; + for (p = env_path; *p; p++) + { + if (*p == ':') + *p = '\0'; + + if (!*p) + { + if (!ecore_file_path_dir_exists(last)) + path = eina_list_append(path, eina_stringshare_add(last)); + last = p + 1; + } + } + if (p > last) + path = eina_list_append(path, eina_stringshare_add(last)); + + return path; +} + +/** + * @addtogroup Ecore_File_Group Ecore_File - Files and directories convenience functions + * + * @{ + */ + +/** + * @brief Check if the given directory is in PATH. + * + * @param in_dir The name of the directory to search in PATH. + * @return @c EINA_TRUE if the directory exist in PATH, @c EINA_FALSE otherwise. + * + * This function checks if @p in_dir is in the environment variable + * PATH. If @p in_dir is @c NULL, or if PATH is empty, or @p in_dir is + * not in PATH, the function returns @c EINA_FALSE, otherwise it returns + * @c EINA_TRUE. + */ +EAPI Eina_Bool +ecore_file_path_dir_exists(const char *in_dir) +{ + Eina_List *l; + char *dir; + + if (!in_dir) + return EINA_FALSE; + + if (!__ecore_file_path_bin) return EINA_FALSE; + EINA_LIST_FOREACH(__ecore_file_path_bin, l, dir) + { + if (strcmp(dir, in_dir)) + return EINA_TRUE; + } + + return EINA_FALSE; +} + +/** + * @brief Check if the given application is installed. + * + * @param exe The name of the application + * @return @c EINA_TRUE if the @p exe is in PATH and is executable, + * @c EINA_FALSE otherwise. + * + * This function checks if @p exe exists in PATH and is executable. If + * @p exe is @c NULL or is not executable, the function returns + * @c EINA_FALSE, otherwise it returns @c EINA_TRUE. + */ +EAPI Eina_Bool +ecore_file_app_installed(const char *exe) +{ + Eina_List *l; + char *dir; + char buf[PATH_MAX]; + + if (!exe) return EINA_FALSE; + if (ecore_file_can_exec(exe)) return EINA_TRUE; + + EINA_LIST_FOREACH(__ecore_file_path_bin, l, dir) + { + snprintf(buf, sizeof(buf), "%s/%s", dir, exe); + if (ecore_file_can_exec(buf)) + return EINA_TRUE; + } + + return EINA_FALSE; +} + +/** + * @brief Get a list of all the applications installed on the system. + * + * @return An Eina_List containing all the executable files in the + * system. + * + * This function returns a list of allocated strings of all the + * executable files. If no files are found, the function returns + * @c NULL. When not needed anymore, the element of the list must be + * freed. + */ +EAPI Eina_List * +ecore_file_app_list(void) +{ + Eina_List *list = NULL; + Eina_List *files; + Eina_List *l; + char buf[PATH_MAX], *dir, *exe; + + EINA_LIST_FOREACH(__ecore_file_path_bin, l, dir) + { + files = ecore_file_ls(dir); + EINA_LIST_FREE(files, exe) + { + snprintf(buf, sizeof(buf), "%s/%s", dir, exe); + if ((ecore_file_can_exec(buf)) && + (!ecore_file_is_dir(buf))) + list = eina_list_append(list, strdup(buf)); + free(exe); + } + } + + return list; +} + +/** + * @} + */ diff --git a/src/lib/ecore_file/ecore_file_private.h b/src/lib/ecore_file/ecore_file_private.h new file mode 100644 index 0000000..45d2cbd --- /dev/null +++ b/src/lib/ecore_file/ecore_file_private.h @@ -0,0 +1,129 @@ +#ifndef ECORE_FILE_PRIVATE_H_ +#define ECORE_FILE_PRIVATE_H_ + +#ifdef __linux__ +# include +#endif + +#ifdef HAVE_EVIL +# include +#endif + +#ifdef HAVE_ESCAPE +# include +#endif + +#include +#include + +#include "Ecore.h" +#include "ecore_private.h" + +#include "Ecore_File.h" + +extern int _ecore_file_log_dom; + +#ifdef ECORE_FILE_DEFAULT_LOG_COLOR +#undef ECORE_FILE_DEFAULT_LOG_COLOR +#endif +#define ECORE_FILE_DEFAULT_LOG_COLOR EINA_COLOR_BLUE + +#ifdef ERR +# undef ERR +#endif +#define ERR(...) EINA_LOG_DOM_ERR(_ecore_file_log_dom, __VA_ARGS__) + +#ifdef DBG +# undef DBG +#endif +#define DBG(...) EINA_LOG_DOM_DBG(_ecore_file_log_dom, __VA_ARGS__) + +#ifdef INF +# undef INF +#endif +#define INF(...) EINA_LOG_DOM_INFO(_ecore_file_log_dom, __VA_ARGS__) + +#ifdef WRN +# undef WRN +#endif +#define WRN(...) EINA_LOG_DOM_WARN(_ecore_file_log_dom, __VA_ARGS__) + +#ifdef CRIT +# undef CRIT +#endif +#define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_file_log_dom, __VA_ARGS__) + +/* ecore_file_monitor */ +int ecore_file_monitor_init(void); +void ecore_file_monitor_shutdown(void); + +#define ECORE_FILE_MONITOR(x) ((Ecore_File_Monitor *)(x)) + +typedef struct _Ecore_File Ecore_File; +struct _Ecore_File +{ + EINA_INLIST; + char *name; + int mtime; + unsigned char is_dir; +}; + +struct _Ecore_File_Monitor +{ + EINA_INLIST; + void (*func) (void *data, + Ecore_File_Monitor *ecore_file_monitor, + Ecore_File_Event event, + const char *path); + + char *path; + void *data; + Ecore_File *files; +}; + +#ifdef HAVE_INOTIFY +int ecore_file_monitor_inotify_init(void); +int ecore_file_monitor_inotify_shutdown(void); +Ecore_File_Monitor *ecore_file_monitor_inotify_add(const char *path, + void (*func) (void *data, + Ecore_File_Monitor *ecore_file_monitor, + Ecore_File_Event event, + const char *path), + void *data); +void ecore_file_monitor_inotify_del(Ecore_File_Monitor *ecore_file_monitor); +#endif + +#ifdef HAVE_NOTIFY_WIN32 +int ecore_file_monitor_win32_init(void); +int ecore_file_monitor_win32_shutdown(void); +Ecore_File_Monitor *ecore_file_monitor_win32_add(const char *path, + void (*func) (void *data, + Ecore_File_Monitor *ecore_file_monitor, + Ecore_File_Event event, + const char *path), + void *data); +void ecore_file_monitor_win32_del(Ecore_File_Monitor *ecore_file_monitor); +#endif + +#ifdef HAVE_POLL +int ecore_file_monitor_poll_init(void); +int ecore_file_monitor_poll_shutdown(void); +Ecore_File_Monitor *ecore_file_monitor_poll_add(const char *path, + void (*func) (void *data, + Ecore_File_Monitor *ecore_file_monitor, + Ecore_File_Event event, + const char *path), + void *data); +void ecore_file_monitor_poll_del(Ecore_File_Monitor *ecore_file_monitor); + +#endif + +/* ecore_file_path */ +void ecore_file_path_init(void); +void ecore_file_path_shutdown(void); + +/* ecore_file_download */ +int ecore_file_download_init(void); +void ecore_file_download_shutdown(void); + +#endif diff --git a/src/lib/ecore_imf/Ecore_IMF.h b/src/lib/ecore_imf/Ecore_IMF.h new file mode 100644 index 0000000..679aad4 --- /dev/null +++ b/src/lib/ecore_imf/Ecore_IMF.h @@ -0,0 +1,572 @@ +#ifndef _ECORE_IMF_H +#define _ECORE_IMF_H + +#include + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_ECORE_IMF_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_ECORE_IMF_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup Ecore_IMF_Context_Group + * + * @{ + */ +/* ecore_imf_context_input_panel_event_callback_add() flag */ +typedef enum +{ + ECORE_IMF_INPUT_PANEL_STATE_EVENT, /**< called when the state of the input panel is changed. @since 1.7 */ + ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, /**< called when the language of the input panel is changed. @since 1.7 */ + ECORE_IMF_INPUT_PANEL_SHIFT_MODE_EVENT, /**< called when the shift key state of the input panel is changed @since 1.7 */ + ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, /**< called when the size of the input panel is changed. @since 1.7 */ + ECORE_IMF_CANDIDATE_PANEL_STATE_EVENT, /**< called when the state of the candidate word panel is changed. @since 1.7 */ + ECORE_IMF_CANDIDATE_PANEL_GEOMETRY_EVENT /**< called when the size of the candidate word panel is changed. @since 1.7 */ +} Ecore_IMF_Input_Panel_Event; + +typedef enum +{ + ECORE_IMF_INPUT_PANEL_STATE_SHOW, /**< Notification after the display of the input panel @since 1.7 */ + ECORE_IMF_INPUT_PANEL_STATE_HIDE, /**< Notification prior to the dismissal of the input panel @since 1.7 */ + ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW /**< Notification prior to the display of the input panel @since 1.7 */ +} Ecore_IMF_Input_Panel_State; + +typedef enum +{ + ECORE_IMF_INPUT_PANEL_SHIFT_MODE_OFF, /**< @since 1.7 */ + ECORE_IMF_INPUT_PANEL_SHIFT_MODE_ON /**< @since 1.7 */ +} Ecore_IMF_Input_Panel_Shift_Mode; + +typedef enum +{ + ECORE_IMF_CANDIDATE_PANEL_SHOW, /**< Notification after the display of the candidate word panel @since 1.7 */ + ECORE_IMF_CANDIDATE_PANEL_HIDE /**< Notification prior to the dismissal of the candidate word panel @since 1.7 */ +} Ecore_IMF_Candidate_Panel_State; + +/* Events sent by the Input Method */ +typedef struct _Ecore_IMF_Event_Preedit_Start Ecore_IMF_Event_Preedit_Start; +typedef struct _Ecore_IMF_Event_Preedit_End Ecore_IMF_Event_Preedit_End; +typedef struct _Ecore_IMF_Event_Preedit_Changed Ecore_IMF_Event_Preedit_Changed; +typedef struct _Ecore_IMF_Event_Commit Ecore_IMF_Event_Commit; +typedef struct _Ecore_IMF_Event_Delete_Surrounding Ecore_IMF_Event_Delete_Surrounding; + +/* Events to filter */ +typedef struct _Ecore_IMF_Event_Mouse_Down Ecore_IMF_Event_Mouse_Down; +typedef struct _Ecore_IMF_Event_Mouse_Up Ecore_IMF_Event_Mouse_Up; +typedef struct _Ecore_IMF_Event_Mouse_In Ecore_IMF_Event_Mouse_In; +typedef struct _Ecore_IMF_Event_Mouse_Out Ecore_IMF_Event_Mouse_Out; +typedef struct _Ecore_IMF_Event_Mouse_Move Ecore_IMF_Event_Mouse_Move; +typedef struct _Ecore_IMF_Event_Mouse_Wheel Ecore_IMF_Event_Mouse_Wheel; +typedef struct _Ecore_IMF_Event_Key_Down Ecore_IMF_Event_Key_Down; +typedef struct _Ecore_IMF_Event_Key_Up Ecore_IMF_Event_Key_Up; +typedef union _Ecore_IMF_Event Ecore_IMF_Event; + +typedef struct _Ecore_IMF_Context Ecore_IMF_Context; /**< An Input Method Context */ +typedef struct _Ecore_IMF_Context_Class Ecore_IMF_Context_Class; /**< An Input Method Context class */ +typedef struct _Ecore_IMF_Context_Info Ecore_IMF_Context_Info; /**< An Input Method Context info */ + +/* Preedit attribute info */ +typedef struct _Ecore_IMF_Preedit_Attr Ecore_IMF_Preedit_Attr; + +EAPI extern int ECORE_IMF_EVENT_PREEDIT_START; +EAPI extern int ECORE_IMF_EVENT_PREEDIT_END; +EAPI extern int ECORE_IMF_EVENT_PREEDIT_CHANGED; +EAPI extern int ECORE_IMF_EVENT_COMMIT; +EAPI extern int ECORE_IMF_EVENT_DELETE_SURROUNDING; + +typedef void (*Ecore_IMF_Event_Cb) (void *data, Ecore_IMF_Context *ctx, void *event_info); + +/** + * @typedef Ecore_IMF_Callback_Type + * + * Ecore IMF Event callback types. + * + * @see ecore_imf_context_event_callback_add() + */ +typedef enum +{ + ECORE_IMF_CALLBACK_PREEDIT_START, /**< "PREEDIT_START" is called when a new preediting sequence starts. @since 1.2 */ + ECORE_IMF_CALLBACK_PREEDIT_END, /**< "PREEDIT_END" is called when a preediting sequence has been completed or canceled. @since 1.2 */ + ECORE_IMF_CALLBACK_PREEDIT_CHANGED, /**< "PREEDIT_CHANGED" is called whenever the preedit sequence currently being entered has changed. @since 1.2 */ + ECORE_IMF_CALLBACK_COMMIT, /**< "COMMIT" is called when a complete input sequence has been entered by the user @since 1.2 */ + ECORE_IMF_CALLBACK_DELETE_SURROUNDING /**< "DELETE_SURROUNDING" is called when the input method needs to delete all or part of the context surrounding the cursor @since 1.2 */ +} Ecore_IMF_Callback_Type; + +/** + * @typedef Ecore_IMF_Event_Type + * + * Ecore IMF event types. + * + * @see ecore_imf_context_filter_event() + */ +typedef enum +{ + ECORE_IMF_EVENT_MOUSE_DOWN, /**< Mouse Down event */ + ECORE_IMF_EVENT_MOUSE_UP, /**< Mouse Up event */ + ECORE_IMF_EVENT_MOUSE_IN, /**< Mouse In event */ + ECORE_IMF_EVENT_MOUSE_OUT, /**< Mouse Out event */ + ECORE_IMF_EVENT_MOUSE_MOVE, /**< Mouse Move event */ + ECORE_IMF_EVENT_MOUSE_WHEEL, /**< Mouse Wheel event */ + ECORE_IMF_EVENT_KEY_DOWN, /**< Key Down event */ + ECORE_IMF_EVENT_KEY_UP /**< Key Up event */ +} Ecore_IMF_Event_Type; +/** + * @typedef Ecore_IMF_Keyboard_Modifiers + * Type for Ecore_IMF keyboard modifiers + */ +typedef enum +{ + ECORE_IMF_KEYBOARD_MODIFIER_NONE = 0, /**< No active modifiers */ + ECORE_IMF_KEYBOARD_MODIFIER_CTRL = 1 << 0, /**< "Control" is pressed */ + ECORE_IMF_KEYBOARD_MODIFIER_ALT = 1 << 1, /**< "Alt" is pressed */ + ECORE_IMF_KEYBOARD_MODIFIER_SHIFT = 1 << 2, /**< "Shift" is pressed */ + ECORE_IMF_KEYBOARD_MODIFIER_WIN = 1 << 3, /**< "Win" (between "Ctrl" and "Alt") is pressed */ + ECORE_IMF_KEYBOARD_MODIFIER_ALTGR = 1 << 4 /**< "AltGr" is pressed @since 1.7 */ +} Ecore_IMF_Keyboard_Modifiers; + +/** + * @typedef Ecore_IMF_Keyboard_Locks + * Type for Ecore_IMF keyboard locks + */ +typedef enum +{ + ECORE_IMF_KEYBOARD_LOCK_NONE = 0, /**< No locks are active */ + ECORE_IMF_KEYBOARD_LOCK_NUM = 1 << 0, /**< "Num" lock is active */ + ECORE_IMF_KEYBOARD_LOCK_CAPS = 1 << 1, /**< "Caps" lock is active */ + ECORE_IMF_KEYBOARD_LOCK_SCROLL = 1 << 2 /**< "Scroll" lock is active */ +} Ecore_IMF_Keyboard_Locks; + +/** + * @typedef Ecore_IMF_Mouse_Flags + * Type for Ecore_IMF mouse flags + */ +typedef enum +{ + ECORE_IMF_MOUSE_NONE = 0, /**< A single click */ + ECORE_IMF_MOUSE_DOUBLE_CLICK = 1 << 0, /**< A double click */ + ECORE_IMF_MOUSE_TRIPLE_CLICK = 1 << 1 /**< A triple click */ +} Ecore_IMF_Mouse_Flags; + +typedef enum +{ + ECORE_IMF_INPUT_MODE_ALPHA = 1 << 0, + ECORE_IMF_INPUT_MODE_NUMERIC = 1 << 1, + ECORE_IMF_INPUT_MODE_SPECIAL = 1 << 2, + ECORE_IMF_INPUT_MODE_HEXA = 1 << 3, + ECORE_IMF_INPUT_MODE_TELE = 1 << 4, + ECORE_IMF_INPUT_MODE_FULL = (ECORE_IMF_INPUT_MODE_ALPHA | ECORE_IMF_INPUT_MODE_NUMERIC | ECORE_IMF_INPUT_MODE_SPECIAL), + ECORE_IMF_INPUT_MODE_INVISIBLE = 1 << 29, + ECORE_IMF_INPUT_MODE_AUTOCAP = 1 << 30 +} Ecore_IMF_Input_Mode; + +/** + * @typedef Ecore_IMF_Preedit_Type + * + * Ecore IMF Preedit style types + * + * @see ecore_imf_context_preedit_string_with_attributes_get() + */ +typedef enum +{ + ECORE_IMF_PREEDIT_TYPE_NONE, /**< None style @since 1.1 */ + ECORE_IMF_PREEDIT_TYPE_SUB1, /**< Substring style 1 @since 1.1 */ + ECORE_IMF_PREEDIT_TYPE_SUB2, /**< Substring style 2 @since 1.1 */ + ECORE_IMF_PREEDIT_TYPE_SUB3 /**< Substring style 3 @since 1.1 */ +} Ecore_IMF_Preedit_Type; + +/** + * @typedef Ecore_IMF_Autocapital_Type + * + * Autocapitalization Types. + * + * @see ecore_imf_context_autocapital_type_set() + */ +typedef enum +{ + ECORE_IMF_AUTOCAPITAL_TYPE_NONE, /**< No auto-capitalization when typing @since 1.1 */ + ECORE_IMF_AUTOCAPITAL_TYPE_WORD, /**< Autocapitalize each word typed @since 1.1 */ + ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE, /**< Autocapitalize the start of each sentence @since 1.1 */ + ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER, /**< Autocapitalize all letters @since 1.1 */ +} Ecore_IMF_Autocapital_Type; + +/** + * @typedef Ecore_IMF_Input_Panel_Layout + * + * Input panel (virtual keyboard) layout types. + * + * @see ecore_imf_context_input_panel_layout_set() + */ +typedef enum +{ + ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL, /**< Default layout */ + ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBER, /**< Number layout */ + ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL, /**< Email layout */ + ECORE_IMF_INPUT_PANEL_LAYOUT_URL, /**< URL layout */ + ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER, /**< Phone Number layout */ + ECORE_IMF_INPUT_PANEL_LAYOUT_IP, /**< IP layout */ + ECORE_IMF_INPUT_PANEL_LAYOUT_MONTH, /**< Month layout */ + ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY, /**< Number Only layout */ + ECORE_IMF_INPUT_PANEL_LAYOUT_INVALID, /**< Never use this */ + ECORE_IMF_INPUT_PANEL_LAYOUT_HEX, /**< Hexadecimal layout @since 1.2 */ + ECORE_IMF_INPUT_PANEL_LAYOUT_TERMINAL, /**< Command-line terminal layout @since 1.2 */ + ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD /**< Like normal, but no auto-correct, no auto-capitalization etc. @since 1.2 */ +} Ecore_IMF_Input_Panel_Layout; + +/** + * @typedef Ecore_IMF_Input_Panel_Lang + * + * Input panel (virtual keyboard) language modes. + * + * @see ecore_imf_context_input_panel_language_set() + */ +typedef enum +{ + ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC, /**< Automatic @since 1.2 */ + ECORE_IMF_INPUT_PANEL_LANG_ALPHABET /**< Alphabet @since 1.2 */ +} Ecore_IMF_Input_Panel_Lang; + +/** + * @typedef Ecore_IMF_Input_Panel_Return_Key_Type + * + * "Return" Key types on the input panel (virtual keyboard). + * + * @see ecore_imf_context_input_panel_return_key_type_set() + */ +typedef enum +{ + ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT, /**< Default @since 1.2 */ + ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DONE, /**< Done @since 1.2 */ + ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_GO, /**< Go @since 1.2 */ + ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_JOIN, /**< Join @since 1.2 */ + ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_LOGIN, /**< Login @since 1.2 */ + ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_NEXT, /**< Next @since 1.2 */ + ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEARCH, /**< Search or magnifier icon @since 1.2 */ + ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEND /**< Send @since 1.2 */ +} Ecore_IMF_Input_Panel_Return_Key_Type; + +struct _Ecore_IMF_Event_Preedit_Start +{ + Ecore_IMF_Context *ctx; +}; + +struct _Ecore_IMF_Event_Preedit_End +{ + Ecore_IMF_Context *ctx; +}; + +struct _Ecore_IMF_Event_Preedit_Changed +{ + Ecore_IMF_Context *ctx; +}; + +struct _Ecore_IMF_Event_Commit +{ + Ecore_IMF_Context *ctx; + char *str; +}; + +struct _Ecore_IMF_Event_Delete_Surrounding +{ + Ecore_IMF_Context *ctx; + int offset; + int n_chars; +}; + +struct _Ecore_IMF_Event_Mouse_Down +{ + int button; /**< The button which has been pressed */ + struct { + int x, y; + } output; + struct { + int x, y; + } canvas; + Ecore_IMF_Keyboard_Modifiers modifiers; /**< The keyboard modifiers active when the event has been emitted */ + Ecore_IMF_Keyboard_Locks locks; /**< The keyboard locks active when the event has been emitted */ + Ecore_IMF_Mouse_Flags flags; /**< The flags corresponding the mouse click (single, double or triple click) */ + unsigned int timestamp; /**< The timestamp when the event occurred */ +}; + +struct _Ecore_IMF_Event_Mouse_Up +{ + int button; /**< The button which has been pressed */ + struct { + int x, y; + } output; + struct { + int x, y; + } canvas; + Ecore_IMF_Keyboard_Modifiers modifiers; /**< The keyboard modifiers active when the event has been emitted */ + Ecore_IMF_Keyboard_Locks locks; /**< The keyboard locks active when the event has been emitted */ + Ecore_IMF_Mouse_Flags flags; /**< The flags corresponding the mouse click (single, double or triple click) */ + unsigned int timestamp; /**< The timestamp when the event occurred */ +}; + +struct _Ecore_IMF_Event_Mouse_In +{ + int buttons; + struct { + int x, y; + } output; + struct { + int x, y; + } canvas; + Ecore_IMF_Keyboard_Modifiers modifiers; /**< The keyboard modifiers active when the event has been emitted */ + Ecore_IMF_Keyboard_Locks locks; /**< The keyboard locks active when the event has been emitted */ + unsigned int timestamp; /**< The timestamp when the event occurred */ +}; + +struct _Ecore_IMF_Event_Mouse_Out +{ + int buttons; + struct { + int x, y; + } output; + struct { + int x, y; + } canvas; + Ecore_IMF_Keyboard_Modifiers modifiers; /**< The keyboard modifiers active when the event has been emitted */ + Ecore_IMF_Keyboard_Locks locks; /**< The keyboard locks active when the event has been emitted */ + unsigned int timestamp; /**< The timestamp when the event occurred */ +}; + +struct _Ecore_IMF_Event_Mouse_Move +{ + int buttons; + struct { + struct { + int x, y; + } output; + struct { + int x, y; + } canvas; + } cur, prev; + Ecore_IMF_Keyboard_Modifiers modifiers; /**< The keyboard modifiers active when the event has been emitted */ + Ecore_IMF_Keyboard_Locks locks; /**< The keyboard locks active when the event has been emitted */ + unsigned int timestamp; /**< The timestamp when the event occurred */ +}; + +struct _Ecore_IMF_Event_Mouse_Wheel +{ + int direction; /* 0 = default up/down wheel */ + int z; /* ...,-2,-1 = down, 1,2,... = up */ + struct { + int x, y; + } output; + struct { + int x, y; + } canvas; + Ecore_IMF_Keyboard_Modifiers modifiers; /**< The keyboard modifiers active when the event has been emitted */ + Ecore_IMF_Keyboard_Locks locks; /**< The keyboard locks active when the event has been emitted */ + unsigned int timestamp; /**< The timestamp when the event occurred */ +}; + +struct _Ecore_IMF_Event_Key_Down +{ + const char *keyname; /**< The string name of the key pressed */ + Ecore_IMF_Keyboard_Modifiers modifiers; /**< The keyboard modifiers active when the event has been emitted */ + Ecore_IMF_Keyboard_Locks locks; /**< The keyboard locks active when the event has been emitted */ + const char *key; /**< The logical key : (eg shift+1 == exclamation) */ + const char *string; /**< A UTF8 string if this keystroke has produced a visible string to be ADDED */ + const char *compose; /**< A UTF8 string if this keystroke has modified a string in the middle of being composed - this string replaces the previous one */ + unsigned int timestamp; /**< The timestamp when the event occurred */ +}; + +struct _Ecore_IMF_Event_Key_Up +{ + const char *keyname; /**< The string name of the key pressed */ + Ecore_IMF_Keyboard_Modifiers modifiers; /**< The keyboard modifiers active when the event has been emitted */ + Ecore_IMF_Keyboard_Locks locks; /**< The keyboard locks active when the event has been emitted */ + const char *key; /**< The logical key : (eg shift+1 == exclamation) */ + const char *string; /**< A UTF8 string if this keystroke has produced a visible string to be ADDED */ + const char *compose; /**< A UTF8 string if this keystroke has modified a string in the middle of being composed - this string replaces the previous one */ + unsigned int timestamp; /**< The timestamp when the event occurred */ +}; + +union _Ecore_IMF_Event +{ + Ecore_IMF_Event_Mouse_Down mouse_down; + Ecore_IMF_Event_Mouse_Up mouse_up; + Ecore_IMF_Event_Mouse_In mouse_in; + Ecore_IMF_Event_Mouse_Out mouse_out; + Ecore_IMF_Event_Mouse_Move mouse_move; + Ecore_IMF_Event_Mouse_Wheel mouse_wheel; + Ecore_IMF_Event_Key_Down key_down; + Ecore_IMF_Event_Key_Up key_up; +}; + +struct _Ecore_IMF_Preedit_Attr +{ + Ecore_IMF_Preedit_Type preedit_type; /**< preedit style type */ + unsigned int start_index; /**< start index of the range (in bytes) */ + unsigned int end_index; /**< end index of the range (in bytes) */ +}; + +struct _Ecore_IMF_Context_Class +{ + void (*add) (Ecore_IMF_Context *ctx); + void (*del) (Ecore_IMF_Context *ctx); + void (*client_window_set) (Ecore_IMF_Context *ctx, void *window); + void (*client_canvas_set) (Ecore_IMF_Context *ctx, void *canvas); + void (*show) (Ecore_IMF_Context *ctx); + void (*hide) (Ecore_IMF_Context *ctx); + void (*preedit_string_get) (Ecore_IMF_Context *ctx, char **str, int *cursor_pos); + void (*focus_in) (Ecore_IMF_Context *ctx); + void (*focus_out) (Ecore_IMF_Context *ctx); + void (*reset) (Ecore_IMF_Context *ctx); + void (*cursor_position_set) (Ecore_IMF_Context *ctx, int cursor_pos); + void (*use_preedit_set) (Ecore_IMF_Context *ctx, Eina_Bool use_preedit); + void (*input_mode_set) (Ecore_IMF_Context *ctx, Ecore_IMF_Input_Mode input_mode); + Eina_Bool (*filter_event) (Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event); + void (*preedit_string_with_attributes_get) (Ecore_IMF_Context *ctx, char **str, Eina_List **attrs, int *cursor_pos); + void (*prediction_allow_set)(Ecore_IMF_Context *ctx, Eina_Bool prediction); + void (*autocapital_type_set)(Ecore_IMF_Context *ctx, Ecore_IMF_Autocapital_Type autocapital_type); + void (*control_panel_show) (Ecore_IMF_Context *ctx); + void (*control_panel_hide) (Ecore_IMF_Context *ctx); + void (*input_panel_layout_set) (Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Layout layout); + Ecore_IMF_Input_Panel_Layout (*input_panel_layout_get) (Ecore_IMF_Context *ctx); + void (*input_panel_language_set) (Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Lang lang); + Ecore_IMF_Input_Panel_Lang (*input_panel_language_get) (Ecore_IMF_Context *ctx); + void (*cursor_location_set) (Ecore_IMF_Context *ctx, int x, int y, int w, int h); + void (*input_panel_imdata_set)(Ecore_IMF_Context *ctx, const void* data, int len); + void (*input_panel_imdata_get)(Ecore_IMF_Context *ctx, void* data, int *len); + void (*input_panel_return_key_type_set) (Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Return_Key_Type return_key_type); + void (*input_panel_return_key_disabled_set) (Ecore_IMF_Context *ctx, Eina_Bool disabled); + void (*input_panel_caps_lock_mode_set) (Ecore_IMF_Context *ctx, Eina_Bool mode); + void (*input_panel_geometry_get)(Ecore_IMF_Context *ctx, int *x, int *y, int *w, int *h); + Ecore_IMF_Input_Panel_State (*input_panel_state_get) (Ecore_IMF_Context *ctx); + void (*input_panel_event_callback_add) (Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Event type, void (*func) (void *data, Ecore_IMF_Context *ctx, int value), void *data); + void (*input_panel_event_callback_del) (Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Event type, void (*func) (void *data, Ecore_IMF_Context *ctx, int value)); + void (*input_panel_language_locale_get) (Ecore_IMF_Context *ctx, char **lang); + void (*candidate_panel_geometry_get)(Ecore_IMF_Context *ctx, int *x, int *y, int *w, int *h); +}; + +struct _Ecore_IMF_Context_Info +{ + const char *id; /* ID */ + const char *description; /* Human readable description */ + const char *default_locales; /* Languages for which this context is the default, separated by : */ + const char *canvas_type; /* The canvas type used by the input method. Eg.: evas */ + int canvas_required; /* Whether the canvas usage is required for this input method */ +}; + +/** + * @} + */ + +EAPI int ecore_imf_init(void); +EAPI int ecore_imf_shutdown(void); + +EAPI void ecore_imf_module_register(const Ecore_IMF_Context_Info *info, Ecore_IMF_Context *(*imf_module_create)(void), Ecore_IMF_Context *(*imf_module_exit)(void)); + +EAPI Eina_List *ecore_imf_context_available_ids_get(void); +EAPI Eina_List *ecore_imf_context_available_ids_by_canvas_type_get(const char *canvas_type); +EAPI const char *ecore_imf_context_default_id_get(void); +EAPI const char *ecore_imf_context_default_id_by_canvas_type_get(const char *canvas_type); +EAPI const Ecore_IMF_Context_Info *ecore_imf_context_info_by_id_get(const char *id); + +EAPI Ecore_IMF_Context *ecore_imf_context_add(const char *id); +EAPI const Ecore_IMF_Context_Info *ecore_imf_context_info_get(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_del(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_client_window_set(Ecore_IMF_Context *ctx, void *window); +EAPI void *ecore_imf_context_client_window_get(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_client_canvas_set(Ecore_IMF_Context *ctx, void *canvas); +EAPI void *ecore_imf_context_client_canvas_get(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_show(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_hide(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_preedit_string_get(Ecore_IMF_Context *ctx, char **str, int *cursor_pos); +EAPI void ecore_imf_context_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx, char **str, Eina_List **attrs, int *cursor_pos); +EAPI void ecore_imf_context_focus_in(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_focus_out(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_reset(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_cursor_position_set(Ecore_IMF_Context *ctx, int cursor_pos); +EAPI void ecore_imf_context_cursor_location_set(Ecore_IMF_Context *ctx, int x, int y, int w, int h); +EAPI void ecore_imf_context_use_preedit_set(Ecore_IMF_Context *ctx, Eina_Bool use_preedit); +EAPI void ecore_imf_context_retrieve_surrounding_callback_set(Ecore_IMF_Context *ctx, Eina_Bool (*func)(void *data, Ecore_IMF_Context *ctx, char **text, int *cursor_pos), const void *data); +EAPI void ecore_imf_context_input_mode_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Mode input_mode); +EAPI Ecore_IMF_Input_Mode ecore_imf_context_input_mode_get(Ecore_IMF_Context *ctx); +EAPI Eina_Bool ecore_imf_context_filter_event(Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event); + +/* plugin specific functions */ +EAPI Ecore_IMF_Context *ecore_imf_context_new(const Ecore_IMF_Context_Class *ctxc); +EAPI void ecore_imf_context_data_set(Ecore_IMF_Context *ctx, void *data); +EAPI void *ecore_imf_context_data_get(Ecore_IMF_Context *ctx); +EAPI Eina_Bool ecore_imf_context_surrounding_get(Ecore_IMF_Context *ctx, char **text, int *cursor_pos); +EAPI void ecore_imf_context_preedit_start_event_add(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_preedit_end_event_add(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_preedit_changed_event_add(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_commit_event_add(Ecore_IMF_Context *ctx, const char *str); +EAPI void ecore_imf_context_delete_surrounding_event_add(Ecore_IMF_Context *ctx, int offset, int n_chars); +EAPI void ecore_imf_context_event_callback_add(Ecore_IMF_Context *ctx, Ecore_IMF_Callback_Type type, Ecore_IMF_Event_Cb func, const void *data); +EAPI void *ecore_imf_context_event_callback_del(Ecore_IMF_Context *ctx, Ecore_IMF_Callback_Type type, Ecore_IMF_Event_Cb func); +EAPI void ecore_imf_context_event_callback_call(Ecore_IMF_Context *ctx, Ecore_IMF_Callback_Type type, void *event_info); +EAPI void ecore_imf_context_prediction_allow_set(Ecore_IMF_Context *ctx, Eina_Bool prediction); +EAPI Eina_Bool ecore_imf_context_prediction_allow_get(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_autocapital_type_set(Ecore_IMF_Context *ctx, Ecore_IMF_Autocapital_Type autocapital_type); +EAPI Ecore_IMF_Autocapital_Type ecore_imf_context_autocapital_type_get(Ecore_IMF_Context *ctx); + +EAPI void ecore_imf_context_control_panel_show(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_control_panel_hide(Ecore_IMF_Context *ctx); + +EAPI void ecore_imf_context_input_panel_show(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_input_panel_hide(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_input_panel_layout_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Layout layout); +EAPI Ecore_IMF_Input_Panel_Layout ecore_imf_context_input_panel_layout_get(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_input_panel_language_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Lang lang); +EAPI Ecore_IMF_Input_Panel_Lang ecore_imf_context_input_panel_language_get(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_input_panel_enabled_set(Ecore_IMF_Context *ctx, Eina_Bool enable); +EAPI Eina_Bool ecore_imf_context_input_panel_enabled_get(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_input_panel_imdata_set(Ecore_IMF_Context *ctx, const void *data, int len); +EAPI void ecore_imf_context_input_panel_imdata_get(Ecore_IMF_Context *ctx, void *data, int *len); +EAPI void ecore_imf_context_input_panel_return_key_type_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Return_Key_Type return_key_type); +EAPI Ecore_IMF_Input_Panel_Return_Key_Type ecore_imf_context_input_panel_return_key_type_get(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_input_panel_return_key_disabled_set(Ecore_IMF_Context *ctx, Eina_Bool disabled); +EAPI Eina_Bool ecore_imf_context_input_panel_return_key_disabled_get(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_input_panel_caps_lock_mode_set(Ecore_IMF_Context *ctx, Eina_Bool mode); +EAPI Eina_Bool ecore_imf_context_input_panel_caps_lock_mode_get(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_input_panel_geometry_get(Ecore_IMF_Context *ctx, int *x, int *y, int *w, int *h); +EAPI Ecore_IMF_Input_Panel_State ecore_imf_context_input_panel_state_get(Ecore_IMF_Context *ctx); +EAPI void ecore_imf_context_input_panel_event_callback_add(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Event type, void (*func) (void *data, Ecore_IMF_Context *ctx, int value), const void *data); +EAPI void ecore_imf_context_input_panel_event_callback_del(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Event type, void (*func) (void *data, Ecore_IMF_Context *ctx, int value)); +EAPI void ecore_imf_context_input_panel_language_locale_get(Ecore_IMF_Context *ctx, char **lang); +EAPI void ecore_imf_context_candidate_panel_geometry_get(Ecore_IMF_Context *ctx, int *x, int *y, int *w, int *h); + +/* The following entry points must be exported by each input method module + */ + +/* + * int imf_module_init (const Ecore_IMF_Context_Info **info); + * void imf_module_exit (void); + * Ecore_IMF_Context *imf_module_create (void); + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/ecore_imf/Makefile.am b/src/lib/ecore_imf/Makefile.am new file mode 100644 index 0000000..10f6c2f --- /dev/null +++ b/src/lib/ecore_imf/Makefile.am @@ -0,0 +1,28 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_srcdir)/src/lib/ecore \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +@EFL_ECORE_IMF_BUILD@ \ +@EVIL_CFLAGS@ \ +@EINA_CFLAGS@ + +AM_CFLAGS = @WIN32_CFLAGS@ + +lib_LTLIBRARIES = libecore_imf.la +includes_HEADERS = Ecore_IMF.h +includesdir = $(includedir)/ecore-@VMAJ@ + +libecore_imf_la_SOURCES = \ +ecore_imf.c \ +ecore_imf_context.c \ +ecore_imf_module.c + +libecore_imf_la_LIBADD = \ +$(top_builddir)/src/lib/ecore/libecore.la \ +@EINA_LIBS@ \ +@EVIL_LIBS@ + +libecore_imf_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ + +EXTRA_DIST = ecore_imf_private.h diff --git a/src/lib/ecore_imf/ecore_imf.c b/src/lib/ecore_imf/ecore_imf.c new file mode 100644 index 0000000..7cf8a4a --- /dev/null +++ b/src/lib/ecore_imf/ecore_imf.c @@ -0,0 +1,73 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "Ecore_IMF.h" +#include "ecore_imf_private.h" + +EAPI int ECORE_IMF_EVENT_PREEDIT_START = 0; +EAPI int ECORE_IMF_EVENT_PREEDIT_END = 0; +EAPI int ECORE_IMF_EVENT_PREEDIT_CHANGED = 0; +EAPI int ECORE_IMF_EVENT_COMMIT = 0; +EAPI int ECORE_IMF_EVENT_DELETE_SURROUNDING = 0; + +int _ecore_imf_log_dom = -1; +static int _ecore_imf_init_count = 0; + +/** + * @defgroup Ecore_IMF_Lib_Group Ecore Input Method Library Functions + * + * Utility functions that set up and shut down the Ecore Input Method + * library. + */ + +/** + * Initialises the Ecore_IMF library. + * @return Number of times the library has been initialised without being + * shut down. + * @ingroup Ecore_IMF_Lib_Group + */ +EAPI int +ecore_imf_init(void) +{ + if (++_ecore_imf_init_count != 1) return _ecore_imf_init_count; + + if (!ecore_init()) return --_ecore_imf_init_count; + _ecore_imf_log_dom = eina_log_domain_register + ("ecore_imf", ECORE_IMF_DEFAULT_LOG_COLOR); + if (_ecore_imf_log_dom < 0) + { + EINA_LOG_ERR("Impossible to create a log domain for the Ecore IMF module."); + ecore_shutdown(); + return --_ecore_imf_init_count; + } + ecore_imf_module_init(); + + ECORE_IMF_EVENT_PREEDIT_START = ecore_event_type_new(); + ECORE_IMF_EVENT_PREEDIT_END = ecore_event_type_new(); + ECORE_IMF_EVENT_PREEDIT_CHANGED = ecore_event_type_new(); + ECORE_IMF_EVENT_COMMIT = ecore_event_type_new(); + ECORE_IMF_EVENT_DELETE_SURROUNDING = ecore_event_type_new(); + + return _ecore_imf_init_count; +} + +/** + * Shuts down the Ecore_IMF library. + * @return Number of times the library has been initialised without being + * shut down. + * @ingroup Ecore_IMF_Lib_Group + */ +EAPI int +ecore_imf_shutdown(void) +{ + if (--_ecore_imf_init_count != 0) return _ecore_imf_init_count; + ecore_imf_module_shutdown(); + eina_log_domain_unregister(_ecore_imf_log_dom); + _ecore_imf_log_dom = -1; + ecore_shutdown(); + return _ecore_imf_init_count; +} diff --git a/src/lib/ecore_imf/ecore_imf_context.c b/src/lib/ecore_imf/ecore_imf_context.c new file mode 100644 index 0000000..0ae316a --- /dev/null +++ b/src/lib/ecore_imf/ecore_imf_context.c @@ -0,0 +1,1896 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include +#include + +#include "Ecore_IMF.h" +#include "ecore_imf_private.h" + +/** + * @defgroup Ecore_IMF_Context_Group Ecore Input Method Context Functions + * + * Functions that operate on Ecore Input Method Context objects. + + * Ecore Input Method Context Function defines the interface for EFL input methods. + * An input method is used by EFL text input widgets like elm_entry + * (based on edje_entry) to map from key events to Unicode character strings. + * + * The default input method can be set through setting the ECORE_IMF_MODULE environment variable. + * + * An input method may consume multiple key events in sequence and finally output the composed result. + * This is called preediting, and an input method may provide feedback about + * this process by displaying the intermediate composition states as preedit text. + * + * Immodule is plugin to connect your application and input method framework such as SCIM, ibus, and so on.@n + * ecore_imf_init() should be called to initialize and load immodule.@n + * ecore_imf_shutdown() is used for shutdowning and unloading immodule. + * + * An example of usage of these functions can be found at: + * @li @ref ecore_imf_example_c + */ + +/** + * Get the list of the available Input Method Context ids. + * + * Note that the caller is responsible for freeing the Eina_List + * when finished with it. There is no need to finish the list strings. + * + * @return Return an Eina_List of strings; + * on failure it returns NULL. + * @ingroup Ecore_IMF_Context_Group + */ +EAPI Eina_List * +ecore_imf_context_available_ids_get(void) +{ + return ecore_imf_module_context_ids_get(); +} + +EAPI Eina_List * +ecore_imf_context_available_ids_by_canvas_type_get(const char *canvas_type) +{ + return ecore_imf_module_context_ids_by_canvas_type_get(canvas_type); +} + +/* + * Match @locale against @against. + * + * 'en_US' against 'en_US' => 4 + * 'en_US' against 'en' => 3 + * 'en', 'en_UK' against 'en_US' => 2 + * all locales, against '*' => 1 + */ +static int +_ecore_imf_context_match_locale(const char *locale, const char *against, int against_len) +{ + if (strcmp(against, "*") == 0) + return 1; + + if (strcasecmp(locale, against) == 0) + return 4; + + if (strncasecmp(locale, against, 2) == 0) + return (against_len == 2) ? 3 : 2; + + return 0; +} + +/** + * Get the id of the default Input Method Context. + * The id may to used to create a new instance of an Input Method + * Context object. + * + * @return Return a string containing the id of the default Input + * Method Context; on failure it returns NULL. + * @ingroup Ecore_IMF_Context_Group + */ +EAPI const char * +ecore_imf_context_default_id_get(void) +{ + return ecore_imf_context_default_id_by_canvas_type_get(NULL); +} + +EAPI const char * +ecore_imf_context_default_id_by_canvas_type_get(const char *canvas_type) +{ + const char *id; + Eina_List *modules; + Ecore_IMF_Module *module; + char *locale; + char *tmp; + int best_goodness = 0; + + id = getenv("ECORE_IMF_MODULE"); + if (id) + { + if (strcmp(id, "none") == 0) return NULL; + if (ecore_imf_module_get(id)) return id; + } + + modules = ecore_imf_module_available_get(); + if (!modules) return NULL; + + locale = setlocale(LC_CTYPE, NULL); + if (!locale) return NULL; + + locale = strdup(locale); + + tmp = strchr(locale, '.'); + if (tmp) *tmp = '\0'; + tmp = strchr(locale, '@'); + if (tmp) *tmp = '\0'; + + id = NULL; + + EINA_LIST_FREE(modules, module) + { + if (canvas_type && + strcmp(module->info->canvas_type, canvas_type) == 0) + continue; + + const char *p = module->info->default_locales; + while (p) + { + const char *q = strchr(p, ':'); + int goodness = _ecore_imf_context_match_locale(locale, p, q ? (size_t)(q - p) : strlen (p)); + + if (goodness > best_goodness) + { + id = module->info->id; + best_goodness = goodness; + } + + p = q ? q + 1 : NULL; + } + } + + free(locale); + return id; +} + +/** + * Retrieve the info for the Input Method Context with @p id. + * + * @param id The Input Method Context id to query for. + * @return Return a #Ecore_IMF_Context_Info for the Input Method Context with @p id; + * on failure it returns NULL. + * @ingroup Ecore_IMF_Context_Group + * + * Example + * @code + * + * const char *ctx_id; + * const Ecore_IMF_Context_Info *ctx_info; + * Ecore_IMF_Context *imf_context; + * ctx_id = ecore_imf_context_default_id_get(); + * if (ctx_id) + * { + * ctx_info = ecore_imf_context_info_by_id_get(ctx_id); + * if (!ctx_info->canvas_type || + * strcmp(ctx_info->canvas_type, "evas") == 0) + * { + * imf_context = ecore_imf_context_add(ctx_id); + * } + * else + * { + * ctx_id = ecore_imf_context_default_id_by_canvas_type_get("evas"); + * if (ctx_id) + * { + * imf_context = ecore_imf_context_add(ctx_id); + * } + * } + * } + * @endcode + */ +EAPI const Ecore_IMF_Context_Info * +ecore_imf_context_info_by_id_get(const char *id) +{ + Ecore_IMF_Module *module; + + if (!id) return NULL; + module = ecore_imf_module_get(id); + if (!module) return NULL; + return module->info; +} + +/** + * Create a new Input Method Context defined by the given id. + * + * @param id The Input Method Context id. + * @return A newly allocated Input Method Context; + * on failure it returns NULL. + * @ingroup Ecore_IMF_Context_Group + */ +EAPI Ecore_IMF_Context * +ecore_imf_context_add(const char *id) +{ + Ecore_IMF_Context *ctx; + + if (!id) return NULL; + ctx = ecore_imf_module_context_create(id); + if (!ctx || !ctx->klass) return NULL; + if (ctx->klass->add) ctx->klass->add(ctx); + /* default use_preedit is EINA_TRUE, so let's make sure it's + * set on the immodule */ + ecore_imf_context_use_preedit_set(ctx, EINA_TRUE); + + /* default prediction is EINA_TRUE, so let's make sure it's + * set on the immodule */ + ecore_imf_context_prediction_allow_set(ctx, EINA_TRUE); + + /* default autocapital type is SENTENCE type, so let's make sure it's + * set on the immodule */ + ecore_imf_context_autocapital_type_set(ctx, ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE); + + /* default input panel enabled status is EINA_TRUE, so let's make sure it's + * set on the immodule */ + ecore_imf_context_input_panel_enabled_set(ctx, EINA_TRUE); + + /* default input panel layout type is NORMAL type, so let's make sure it's + * set on the immodule */ + ecore_imf_context_input_panel_layout_set(ctx, ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL); + + /* default input_mode is ECORE_IMF_INPUT_MODE_FULL, so let's make sure it's + * set on the immodule */ + ecore_imf_context_input_mode_set(ctx, ECORE_IMF_INPUT_MODE_FULL); + return ctx; +} + +/** + * Retrieve the info for the given Input Method Context. + * + * @param ctx An #Ecore_IMF_Context. + * @return Return a #Ecore_IMF_Context_Info for the given Input Method Context; + * on failure it returns NULL. + * @ingroup Ecore_IMF_Context_Group + */ +EAPI const Ecore_IMF_Context_Info * +ecore_imf_context_info_get(Ecore_IMF_Context *ctx) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_info_get"); + return NULL; + } + return ctx->module->info; +} + +/** + * Delete the given Input Method Context and free its memory. + * + * @param ctx An #Ecore_IMF_Context. + * @ingroup Ecore_IMF_Context_Group + */ +EAPI void +ecore_imf_context_del(Ecore_IMF_Context *ctx) +{ + Ecore_IMF_Func_Node *fn; + + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_del"); + return; + } + if (ctx->klass->del) ctx->klass->del(ctx); + + if (ctx->callbacks) + { + EINA_LIST_FREE(ctx->callbacks, fn) + free(fn); + } + + ECORE_MAGIC_SET(ctx, ECORE_MAGIC_NONE); + free(ctx); +} + +/** + * Set the client window for the Input Method Context; this is the + * Ecore_X_Window when using X11, Ecore_Win32_Window when using Win32, etc. + * This window is used in order to correctly position status windows, and may + * also be used for purposes internal to the Input Method Context. + * + * @param ctx An #Ecore_IMF_Context. + * @param window The client window. This may be @c NULL to indicate + * that the previous client window no longer exists. + * @ingroup Ecore_IMF_Context_Group + */ +EAPI void +ecore_imf_context_client_window_set(Ecore_IMF_Context *ctx, void *window) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_client_window_set"); + return; + } + if (ctx->klass->client_window_set) ctx->klass->client_window_set(ctx, window); + ctx->window = window; +} + +/** + * Get the client window of the Input Method Context + * + * See @ref ecore_imf_context_client_window_set for more details. + * + * @param ctx An #Ecore_IMF_Context. + * @return Return the client window. + * @ingroup Ecore_IMF_Context_Group + * @since 1.1.0 + */ +EAPI void * +ecore_imf_context_client_window_get(Ecore_IMF_Context *ctx) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_client_window_get"); + return NULL; + } + return ctx->window; +} + +/** + * Set the client canvas for the Input Method Context; this is the + * canvas in which the input appears. + * The canvas type can be determined by using the context canvas type. + * Actually only canvas with type "evas" (Evas *) is supported. + * This canvas may be used in order to correctly position status windows, and may + * also be used for purposes internal to the Input Method Context. + * + * @param ctx An #Ecore_IMF_Context. + * @param canvas The client canvas. This may be @c NULL to indicate + * that the previous client canvas no longer exists. + * @ingroup Ecore_IMF_Context_Group + */ +EAPI void +ecore_imf_context_client_canvas_set(Ecore_IMF_Context *ctx, void *canvas) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_client_canvas_set"); + return; + } + if (ctx->klass->client_canvas_set) ctx->klass->client_canvas_set(ctx, canvas); + ctx->client_canvas = canvas; +} + +/** + * Get the client canvas of the Input Method Context. + * + * See @ref ecore_imf_context_client_canvas_set for more details. + * + * @param ctx An #Ecore_IMF_Context. + * @return Return the client canvas. + * @ingroup Ecore_IMF_Context_Group + * @since 1.1.0 + */ +EAPI void * +ecore_imf_context_client_canvas_get(Ecore_IMF_Context *ctx) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_client_canvas_get"); + return NULL; + } + return ctx->client_canvas; +} + +/** + * Ask the Input Method Context to show itself. + * + * @param ctx An #Ecore_IMF_Context. + * @ingroup Ecore_IMF_Context_Group + */ +EAPI void +ecore_imf_context_show(Ecore_IMF_Context *ctx) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_show"); + return; + } + if (ctx->klass->show) ctx->klass->show(ctx); +} + +/** + * Ask the Input Method Context to hide itself. + * + * @param ctx An #Ecore_IMF_Context. + * @ingroup Ecore_IMF_Context_Group + */ +EAPI void +ecore_imf_context_hide(Ecore_IMF_Context *ctx) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_hide"); + return; + } + if (ctx->klass->hide) ctx->klass->hide(ctx); +} + +/** + * Retrieve the current preedit string and cursor position + * for the Input Method Context. + * + * @param ctx An #Ecore_IMF_Context. + * @param str Location to store the retrieved string. The + * string retrieved must be freed with free(). + * @param cursor_pos Location to store position of cursor (in characters) + * within the preedit string. + * @ingroup Ecore_IMF_Context_Group + */ +EAPI void +ecore_imf_context_preedit_string_get(Ecore_IMF_Context *ctx, char **str, int *cursor_pos) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_preedit_string_get"); + return; + } + if (ctx->klass->preedit_string_get) + ctx->klass->preedit_string_get(ctx, str, cursor_pos); + else + { + if (str) *str = strdup(""); + if (cursor_pos) *cursor_pos = 0; + } +} + +/** + * Retrieve the current preedit string, attributes and + * cursor position for the Input Method Context. + * + * @param ctx An #Ecore_IMF_Context. + * @param str Location to store the retrieved string. The + * string retrieved must be freed with free(). + * @param attrs an Eina_List of attributes + * @param cursor_pos Location to store position of cursor (in characters) + * within the preedit string. + * @ingroup Ecore_IMF_Context_Group + * + * Example + * @code + * char *preedit_string; + * int cursor_pos; + * Eina_List *attrs = NULL, *l = NULL; + * Ecore_IMF_Preedit_Attr *attr; + * + * ecore_imf_context_preedit_string_with_attributes_get(imf_context, + * &preedit_string, + * &attrs, &cursor_pos); + * if (!preedit_string) return; + * + * if (strlen(preedit_string) > 0) + * { + * if (attrs) + * { + * EINA_LIST_FOREACH(attrs, l, attr) + * { + * if (attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB1) + * { + * // Something to do + * } + * else if (attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB2) + * { + * // Something to do + * } + * else if (attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB3) + * { + * // Something to do + * } + * } + * } + * } + * + * // delete attribute list + * EINA_LIST_FREE(attrs, attr) free(attr); + * + * free(preedit_string); + * @endcode + * @since 1.1.0 + */ +EAPI void +ecore_imf_context_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx, char **str, Eina_List **attrs, int *cursor_pos) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_preedit_string_with_attributes_get"); + return; + } + if (ctx->klass->preedit_string_with_attributes_get) + ctx->klass->preedit_string_with_attributes_get(ctx, str, attrs, cursor_pos); + else + { + if (str) *str = strdup(""); + if (attrs) *attrs = NULL; + if (cursor_pos) *cursor_pos = 0; + } +} + +/** + * Notify the Input Method Context that the widget to which its + * correspond has gained focus. + * + * @param ctx An #Ecore_IMF_Context. + * @ingroup Ecore_IMF_Context_Group + * + * Example + * @code + * static void + * _focus_in_cb(void *data, Evas_Object *o, const char *emission, const char *source) + * { + * ecore_imf_context_reset(imf_context); + * ecore_imf_context_focus_in(imf_context); + * } + * + * evas_object_event_callback_add(obj, EVAS_CALLBACK_FOCUS_IN, _focus_in_cb, ed); + * @endcode + */ +EAPI void +ecore_imf_context_focus_in(Ecore_IMF_Context *ctx) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_focus_in"); + return; + } + if (ctx->klass->focus_in) ctx->klass->focus_in(ctx); +} + +/** + * Notify the Input Method Context that the widget to which its + * correspond has lost focus. + * + * @param ctx An #Ecore_IMF_Context. + * @ingroup Ecore_IMF_Context_Group + * + * Example + * @code + * static void + * _focus_out_cb(void *data, Evas_Object *o, const char *emission, const char *source) + * { + * ecore_imf_context_reset(imf_context); + * ecore_imf_context_focus_out(imf_context); + * } + * + * evas_object_event_callback_add(obj, EVAS_CALLBACK_FOCUS_OUT, _focus_out_cb, ed); + * @endcode + */ +EAPI void +ecore_imf_context_focus_out(Ecore_IMF_Context *ctx) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_focus_out"); + return; + } + if (ctx->klass->focus_out) ctx->klass->focus_out(ctx); +} + +/** + * Notify the Input Method Context that a change such as a + * change in cursor position has been made. This will typically + * cause the Input Method Context to clear the preedit state. + * + * @param ctx An #Ecore_IMF_Context. + * @ingroup Ecore_IMF_Context_Group + * + * Example + * @code + * static void + * _focus_out_cb(void *data, Evas_Object *o, const char *emission, const char *source) + * { + * ecore_imf_context_reset(imf_context); + * ecore_imf_context_focus_out(imf_context); + * } + * + * evas_object_event_callback_add(obj, EVAS_CALLBACK_FOCUS_OUT, _focus_out_cb, ed); + * @endcode + */ +EAPI void +ecore_imf_context_reset(Ecore_IMF_Context *ctx) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_reset"); + return; + } + if (ctx->klass->reset) ctx->klass->reset(ctx); +} + +/** + * Notify the Input Method Context that a change in the cursor + * position has been made. + * + * @param ctx An #Ecore_IMF_Context. + * @param cursor_pos New cursor position in characters. + * @ingroup Ecore_IMF_Context_Group + */ +EAPI void +ecore_imf_context_cursor_position_set(Ecore_IMF_Context *ctx, int cursor_pos) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_cursor_position_set"); + return; + } + if (ctx->klass->cursor_position_set) ctx->klass->cursor_position_set(ctx, cursor_pos); +} + +/** + * Notify the Input Method Context that a change in the cursor + * location has been made. The location is relative to the canvas. + * The cursor location can be used to determine the position of + * candidate word window in the immodule. + * + * @param ctx An #Ecore_IMF_Context. + * @param x cursor x position. + * @param y cursor y position. + * @param w cursor width. + * @param h cursor height. + * @ingroup Ecore_IMF_Context_Group + * @since 1.1.0 + */ +EAPI void +ecore_imf_context_cursor_location_set(Ecore_IMF_Context *ctx, int x, int y, int w, int h) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_cursor_location_set"); + return; + } + if (ctx->klass->cursor_location_set) ctx->klass->cursor_location_set(ctx, x, y, w, h); +} + +/** + * Set whether the IM context should use the preedit string + * to display feedback. If @c use_preedit is @c EINA_FALSE (default + * is @c EINA_TRUE), then the IM context may use some other method to display + * feedback, such as displaying it in a child of the root window. + * + * @param ctx An #Ecore_IMF_Context. + * @param use_preedit Whether the IM context should use the preedit string. + * @ingroup Ecore_IMF_Context_Group + */ +EAPI void +ecore_imf_context_use_preedit_set(Ecore_IMF_Context *ctx, Eina_Bool use_preedit) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_use_preedit_set"); + return; + } + if (ctx->klass->use_preedit_set) ctx->klass->use_preedit_set(ctx, use_preedit); +} + +/** + * Set whether the IM context should allow to use the text prediction. + * If @p prediction is @c EINA_FALSE (default is @c EINA_TRUE), then the IM + * context will not display the text prediction window. + * + * @param ctx An #Ecore_IMF_Context. + * @param prediction Whether the IM context should allow to use the text prediction. + * @ingroup Ecore_IMF_Context_Group + * @since 1.1.0 + */ +EAPI void +ecore_imf_context_prediction_allow_set(Ecore_IMF_Context *ctx, Eina_Bool prediction) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_prediction_allow_set"); + return; + } + + ctx->allow_prediction = prediction; + + if (ctx->klass->prediction_allow_set) + ctx->klass->prediction_allow_set(ctx, prediction); +} + +/** + * Get whether the IM context should allow to use the text prediction. + * + * @param ctx An #Ecore_IMF_Context. + * @return @c EINA_TRUE if it allows to use the text prediction, otherwise + * @c EINA_FALSE. + * @ingroup Ecore_IMF_Context_Group + * @since 1.1.0 + */ +EAPI Eina_Bool +ecore_imf_context_prediction_allow_get(Ecore_IMF_Context *ctx) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_prediction_allow_get"); + return EINA_FALSE; + } + + return ctx->allow_prediction; +} + +/** + * Set the autocapitalization type on the immodule. + * + * @param ctx An #Ecore_IMF_Context. + * @param autocapital_type the autocapitalization type. + * @ingroup Ecore_IMF_Context_Group + * @since 1.1.0 + */ +EAPI void +ecore_imf_context_autocapital_type_set(Ecore_IMF_Context *ctx, Ecore_IMF_Autocapital_Type autocapital_type) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_autocapital_type_set"); + return; + } + + ctx->autocapital_type = autocapital_type; + + if (ctx->klass->autocapital_type_set) ctx->klass->autocapital_type_set(ctx, autocapital_type); +} + +/** + * Get the autocapitalization type. + * + * @param ctx An #Ecore_IMF_Context. + * @return The autocapital type being used by @p ctx. + * @ingroup Ecore_IMF_Context_Group + * @since 1.1.0 + */ +EAPI Ecore_IMF_Autocapital_Type +ecore_imf_context_autocapital_type_get(Ecore_IMF_Context *ctx) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_autocapital_allow_get"); + return ECORE_IMF_AUTOCAPITAL_TYPE_NONE; + } + + return ctx->autocapital_type; +} + +/** + * Set the callback to be used on surrounding_get request. + * + * This callback will be called when the Input Method Context + * module requests the surrounding context. + * + * @param ctx An #Ecore_IMF_Context. + * @param func The callback to be called. + * @param data The data pointer to be passed to @p func + * @ingroup Ecore_IMF_Context_Group + */ +EAPI void +ecore_imf_context_retrieve_surrounding_callback_set(Ecore_IMF_Context *ctx, Eina_Bool (*func)(void *data, Ecore_IMF_Context *ctx, char **text, int *cursor_pos), const void *data) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_retrieve_surrounding_callback_set"); + return; + } + + ctx->retrieve_surrounding_func = func; + ctx->retrieve_surrounding_data = (void *) data; +} + +/** + * Set the input mode used by the Ecore Input Context. + * + * The input mode can be one of the input modes defined in + * Ecore_IMF_Input_Mode. The default input mode is + * ECORE_IMF_INPUT_MODE_FULL. + * + * @param ctx An #Ecore_IMF_Context. + * @param input_mode The input mode to be used by @p ctx. + * @ingroup Ecore_IMF_Context_Group + */ +EAPI void +ecore_imf_context_input_mode_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Mode input_mode) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_mode_set"); + return; + } + if (ctx->klass->input_mode_set) ctx->klass->input_mode_set(ctx, input_mode); + ctx->input_mode = input_mode; +} + +/** + * Get the input mode being used by the Ecore Input Context. + * + * See @ref ecore_imf_context_input_mode_set for more details. + * + * @param ctx An #Ecore_IMF_Context. + * @return The input mode being used by @p ctx. + * @ingroup Ecore_IMF_Context_Group + */ +EAPI Ecore_IMF_Input_Mode +ecore_imf_context_input_mode_get(Ecore_IMF_Context *ctx) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_mode_set"); + return 0; + } + return ctx->input_mode; +} + +/** + * Allow an Ecore Input Context to internally handle an event. + * If this function returns @c EINA_TRUE, then no further processing + * should be done for this event. + * + * Input methods must be able to accept all types of events (simply + * returning @c EINA_FALSE if the event was not handled), but there is no + * obligation of any events to be submitted to this function. + * + * @param ctx An #Ecore_IMF_Context. + * @param type The type of event defined by #Ecore_IMF_Event_Type. + * @param event The event itself. + * @return @c EINA_TRUE if the event was handled; otherwise @c EINA_FALSE. + * @ingroup Ecore_IMF_Context_Group + * + * Example + * @code + * static void + * _key_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) + * { + * Evas_Event_Key_Down *ev = event_info; + * if (!ev->keyname) return; + * + * if (imf_context) + * { + * Ecore_IMF_Event_Key_Down ecore_ev; + * ecore_imf_evas_event_key_down_wrap(ev, &ecore_ev); + * if (ecore_imf_context_filter_event(imf_context, + * ECORE_IMF_EVENT_KEY_DOWN, + * (Ecore_IMF_Event *)&ecore_ev)) + * return; + * } + * } + * + * evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, data); + * @endcode + */ +EAPI Eina_Bool +ecore_imf_context_filter_event(Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_filter_event"); + return EINA_FALSE; + } + if (ctx->klass->filter_event) return ctx->klass->filter_event(ctx, type, event); + return EINA_FALSE; +} + +/** + * @defgroup Ecore_IMF_Context_Module_Group Ecore Input Method Context Module Functions + * + * Functions that should be used by Ecore Input Method Context modules. + */ + +/** + * Creates a new Input Method Context with klass specified by @p ctxc. + * + * This method should be used by modules implementing the Input + * Method Context interface. + * + * @param ctxc An #Ecore_IMF_Context_Class. + * @return A new #Ecore_IMF_Context; on failure it returns NULL. + * @ingroup Ecore_IMF_Context_Module_Group + */ +EAPI Ecore_IMF_Context * +ecore_imf_context_new(const Ecore_IMF_Context_Class *ctxc) +{ + Ecore_IMF_Context *ctx; + + if (!ctxc) return NULL; + ctx = calloc(1, sizeof(Ecore_IMF_Context)); + if (!ctx) return NULL; + ECORE_MAGIC_SET(ctx, ECORE_MAGIC_CONTEXT); + ctx->klass = ctxc; + ctx->data = NULL; + ctx->retrieve_surrounding_func = NULL; + ctx->retrieve_surrounding_data = NULL; + return ctx; +} + +/** + * Set the Input Method Context specific data. + * + * Note that this method should be used by modules to set + * the Input Method Context specific data and it's not meant to + * be used by applications to store application specific data. + * + * @param ctx An #Ecore_IMF_Context. + * @param data The Input Method Context specific data. + * @return A new #Ecore_IMF_Context; on failure it returns NULL. + * @ingroup Ecore_IMF_Context_Module_Group + */ +EAPI void +ecore_imf_context_data_set(Ecore_IMF_Context *ctx, void *data) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_data_set"); + return; + } + ctx->data = data; +} + +/** + * Get the Input Method Context specific data. + * + * See @ref ecore_imf_context_data_set for more details. + * + * @param ctx An #Ecore_IMF_Context. + * @return The Input Method Context specific data. + * @ingroup Ecore_IMF_Context_Module_Group + */ +EAPI void *ecore_imf_context_data_get(Ecore_IMF_Context *ctx) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_data_get"); + return NULL; + } + return ctx->data; +} + +/** + * Retrieve context around insertion point. + * Input methods typically want context in order to constrain input text based on existing text; + * this is important for languages such as Thai where only some sequences of characters are allowed. + * In addition, the text around the insertion point can be used for supporting autocapital feature. + * + * This function is implemented by calling the + * Ecore_IMF_Context::retrieve_surrounding_func ( + * set using #ecore_imf_context_retrieve_surrounding_callback_set). + * + * There is no obligation for a widget to respond to the + * retrieve_surrounding_func, so input methods must be prepared + * to function without context. + * + * @param ctx An #Ecore_IMF_Context. + * @param text Location to store a UTF-8 encoded string of text + * holding context around the insertion point. + * If the function returns @c EINA_TRUE, then you must free + * the result stored in this location with free(). + * @param cursor_pos Location to store the position in characters of + * the insertion cursor within @p text. + * @return @c EINA_TRUE if surrounding text was provided; otherwise + * @c EINA_FALSE. + * @ingroup Ecore_IMF_Context_Module_Group + */ +EAPI Eina_Bool +ecore_imf_context_surrounding_get(Ecore_IMF_Context *ctx, char **text, int *cursor_pos) +{ + int result = EINA_FALSE; + + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_surrounding_get"); + return EINA_FALSE; + } + + if (ctx->retrieve_surrounding_func) + { + result = ctx->retrieve_surrounding_func(ctx->retrieve_surrounding_data, ctx, text, cursor_pos); + if (!result) + { + if (text) *text = NULL; + if (cursor_pos) *cursor_pos = 0; + } + } + return result; +} + +static void +_ecore_imf_event_free_preedit(void *data __UNUSED__, void *event) +{ + free(event); +} + +/** + * Adds ECORE_IMF_EVENT_PREEDIT_START to the event queue. + * + * ECORE_IMF_EVENT_PREEDIT_START should be added when a new preedit sequence starts. + * It's asynchronous method to put event to the event queue. + * ecore_imf_context_event_callback_call() can be used as synchronous method. + * + * @param ctx An #Ecore_IMF_Context. + * @ingroup Ecore_IMF_Context_Module_Group + */ +EAPI void +ecore_imf_context_preedit_start_event_add(Ecore_IMF_Context *ctx) +{ + Ecore_IMF_Event_Commit *ev; + + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_preedit_start_event_add"); + return; + } + + ev = malloc(sizeof(Ecore_IMF_Event_Preedit_Start)); + ev->ctx = ctx; + ecore_event_add(ECORE_IMF_EVENT_PREEDIT_START, + ev, _ecore_imf_event_free_preedit, NULL); +} + +/** + * Adds ECORE_IMF_EVENT_PREEDIT_END to the event queue. + * + * ECORE_IMF_EVENT_PREEDIT_END should be added when a new preedit sequence has been completed or canceled. + * It's asynchronous method to put event to the event queue. + * ecore_imf_context_event_callback_call() can be used as synchronous method. + * + * @param ctx An #Ecore_IMF_Context. + * @ingroup Ecore_IMF_Context_Module_Group + */ +EAPI void +ecore_imf_context_preedit_end_event_add(Ecore_IMF_Context *ctx) +{ + Ecore_IMF_Event_Commit *ev; + + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_preedit_end_event_add"); + return; + } + + ev = malloc(sizeof(Ecore_IMF_Event_Preedit_End)); + ev->ctx = ctx; + ecore_event_add(ECORE_IMF_EVENT_PREEDIT_END, + ev, _ecore_imf_event_free_preedit, NULL); +} + +/** + * Adds ECORE_IMF_EVENT_PREEDIT_CHANGED to the event queue. + * + * It's asynchronous method to put event to the event queue. + * ecore_imf_context_event_callback_call() can be used as synchronous method. + * + * @param ctx An #Ecore_IMF_Context. + * @ingroup Ecore_IMF_Context_Module_Group + */ +EAPI void +ecore_imf_context_preedit_changed_event_add(Ecore_IMF_Context *ctx) +{ + Ecore_IMF_Event_Commit *ev; + + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_preedit_changed_event_add"); + return; + } + + ev = malloc(sizeof(Ecore_IMF_Event_Preedit_Changed)); + ev->ctx = ctx; + ecore_event_add(ECORE_IMF_EVENT_PREEDIT_CHANGED, + ev, _ecore_imf_event_free_preedit, NULL); +} + +static void +_ecore_imf_event_free_commit(void *data __UNUSED__, void *event) +{ + Ecore_IMF_Event_Commit *ev; + + ev = event; + if (ev->str) free(ev->str); + free(ev); +} + +/** + * Adds ECORE_IMF_EVENT_COMMIT to the event queue. + * + * It's asynchronous method to put event to the event queue. + * ecore_imf_context_event_callback_call() can be used as synchronous method. + * + * @param ctx An #Ecore_IMF_Context. + * @param str The committed string. + * @ingroup Ecore_IMF_Context_Module_Group + */ +EAPI void +ecore_imf_context_commit_event_add(Ecore_IMF_Context *ctx, const char *str) +{ + Ecore_IMF_Event_Commit *ev; + + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_commit_event_add"); + return; + } + + ev = malloc(sizeof(Ecore_IMF_Event_Commit)); + ev->ctx = ctx; + ev->str = str ? strdup(str) : NULL; + ecore_event_add(ECORE_IMF_EVENT_COMMIT, + ev, _ecore_imf_event_free_commit, NULL); + +} + +static void +_ecore_imf_event_free_delete_surrounding(void *data __UNUSED__, void *event) +{ + free(event); +} + +/** + * Adds ECORE_IMF_EVENT_DELETE_SURROUNDING to the event queue. + * + * Asks the widget that the input context is attached to to delete characters around the cursor position + * by adding the ECORE_IMF_EVENT_DELETE_SURROUNDING to the event queue. + * Note that offset and n_chars are in characters not in bytes. + * + * It's asynchronous method to put ECORE_IMF_EVENT_DELETE_SURROUNDING event to the event queue. + * ecore_imf_context_event_callback_call() can be used as synchronous method. + * + * @param ctx An #Ecore_IMF_Context. + * @param offset The start offset of surrounding to be deleted. + * @param n_chars The number of characters to be deleted. + * @ingroup Ecore_IMF_Context_Module_Group + */ +EAPI void +ecore_imf_context_delete_surrounding_event_add(Ecore_IMF_Context *ctx, int offset, int n_chars) +{ + Ecore_IMF_Event_Delete_Surrounding *ev; + + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_delete_surrounding_event_add"); + return; + } + + ev = malloc(sizeof(Ecore_IMF_Event_Delete_Surrounding)); + ev->ctx = ctx; + ev->offset = offset; + ev->n_chars = n_chars; + ecore_event_add(ECORE_IMF_EVENT_DELETE_SURROUNDING, + ev, _ecore_imf_event_free_delete_surrounding, NULL); +} + +/** + * Add (register) a callback function to a given context event. + * + * This function adds a function callback to the context @p ctx when the + * event of type @p type occurs on it. The function pointer is @p + * func. + * + * The event type @p type to trigger the function may be one of + * #ECORE_IMF_CALLBACK_PREEDIT_START, #ECORE_IMF_CALLBACK_PREEDIT_END, + * #ECORE_IMF_CALLBACK_PREEDIT_CHANGED, #ECORE_IMF_CALLBACK_COMMIT and + * #ECORE_IMF_CALLBACK_DELETE_SURROUNDING. + * + * @param ctx Ecore_IMF_Context to attach a callback to. + * @param type The type of event that will trigger the callback + * @param func The (callback) function to be called when the event is + * triggered + * @param data The data pointer to be passed to @p func + * @ingroup Ecore_IMF_Context_Group + * @since 1.2.0 + * + * Example + * @code + * static void + * _imf_event_commit_cb(void *data, Ecore_IMF_Context *ctx, void *event_info) + * { + * char *commit_str = event_info; + * // something to do + * } + * + * ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_COMMIT, _imf_event_commit_cb, data); + * @endcode + */ +EAPI void +ecore_imf_context_event_callback_add(Ecore_IMF_Context *ctx, Ecore_IMF_Callback_Type type, Ecore_IMF_Event_Cb func, const void *data) +{ + Ecore_IMF_Func_Node *fn = NULL; + + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_event_callback_add"); + return; + } + + if (!func) return; + + fn = calloc(1, sizeof (Ecore_IMF_Func_Node)); + if (!fn) return; + + fn->func = func; + fn->data = data; + fn->type = type; + + ctx->callbacks = eina_list_append(ctx->callbacks, fn); +} + +/** + * Delete (unregister) a callback function registered to a given + * context event. + * + * This function removes a function callback from the context @p ctx when the + * event of type @p type occurs on it. The function pointer is @p + * func. + * + * @see ecore_imf_context_event_callback_add() for more details + * + * @param ctx Ecore_IMF_Context to remove a callback from. + * @param type The type of event that was triggering the callback + * @param func The (callback) function that was to be called when the event was triggered + * @return the data pointer + * @ingroup Ecore_IMF_Context_Group + * @since 1.2.0 + */ +EAPI void * +ecore_imf_context_event_callback_del(Ecore_IMF_Context *ctx, Ecore_IMF_Callback_Type type, Ecore_IMF_Event_Cb func) +{ + Eina_List *l = NULL; + Eina_List *l_next = NULL; + Ecore_IMF_Func_Node *fn = NULL; + + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_event_callback_del"); + return NULL; + } + + if (!func) return NULL; + if (!ctx->callbacks) return NULL; + + EINA_LIST_FOREACH_SAFE(ctx->callbacks, l, l_next, fn) + { + if ((fn) && (fn->func == func) && (fn->type == type)) + { + void *tmp = (void *)fn->data; + free(fn); + ctx->callbacks = eina_list_remove_list(ctx->callbacks, l); + return tmp; + } + } + return NULL; +} + +/** + * Call a given callback on the context @p ctx. + * + * ecore_imf_context_preedit_start_event_add(), ecore_imf_context_preedit_end_event_add(), + * ecore_imf_context_preedit_changed_event_add(), ecore_imf_context_commit_event_add() and + * ecore_imf_context_delete_surrounding_event_add() APIs are asynchronous + * because those API adds each event to the event queue. + * + * This API provides the way to call each callback function immediately. + * + * @param ctx Ecore_IMF_Context. + * @param type The type of event that will trigger the callback + * @param event_info The pointer to event specific struct or information to + * pass to the callback functions registered on this event + * @ingroup Ecore_IMF_Context_Module_Group + * @since 1.2.0 + */ +EAPI void +ecore_imf_context_event_callback_call(Ecore_IMF_Context *ctx, Ecore_IMF_Callback_Type type, void *event_info) +{ + Ecore_IMF_Func_Node *fn = NULL; + Eina_List *l = NULL; + + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_event_callback_call"); + return; + } + + EINA_LIST_FOREACH(ctx->callbacks, l, fn) + { + if ((fn) && (fn->type == type) && (fn->func)) + fn->func(fn->data, ctx, event_info); + } +} + +/** + * Ask the Input Method Context to show the control panel of using Input Method. + * + * @param ctx An #Ecore_IMF_Context. + * @ingroup Ecore_IMF_Context_Group + * @since 1.1.0 + */ +EAPI void +ecore_imf_context_control_panel_show(Ecore_IMF_Context *ctx) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_control_panel_show"); + return; + } + + if (ctx->klass->control_panel_show) ctx->klass->control_panel_show(ctx); +} + +/** + * Ask the Input Method Context to hide the control panel of using Input Method. + * + * @param ctx An #Ecore_IMF_Context. + * @ingroup Ecore_IMF_Context_Group + * @since 1.1.0 + */ +EAPI void +ecore_imf_context_control_panel_hide(Ecore_IMF_Context *ctx) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_control_panel_hide"); + return; + } + + if (ctx->klass->control_panel_hide) ctx->klass->control_panel_hide(ctx); +} + +/** + * Ask the Input Method Context to show the input panel (virtual keyboard). + * + * @param ctx An #Ecore_IMF_Context. + * @ingroup Ecore_IMF_Context_Group + * @since 1.1.0 + */ +EAPI void +ecore_imf_context_input_panel_show(Ecore_IMF_Context *ctx) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_panel_show"); + return; + } + + if (ctx->klass->show) ctx->klass->show(ctx); +} + +/** + * Ask the Input Method Context to hide the input panel. + * + * @param ctx An #Ecore_IMF_Context. + * @ingroup Ecore_IMF_Context_Group + * @since 1.1.0 + */ +EAPI void +ecore_imf_context_input_panel_hide(Ecore_IMF_Context *ctx) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_panel_hide"); + return; + } + + if (ctx->klass->hide) ctx->klass->hide(ctx); +} + +/** + * Set the layout of the input panel. + * + * @param ctx An #Ecore_IMF_Context. + * @param layout see #Ecore_IMF_Input_Panel_Layout + * @ingroup Ecore_IMF_Context_Group + * @since 1.1.0 + */ +EAPI void +ecore_imf_context_input_panel_layout_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Layout layout) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_panel_layout_set"); + return; + } + + if (ctx->klass->input_panel_layout_set) + ctx->klass->input_panel_layout_set(ctx, layout); + + ctx->input_panel_layout = layout; +} + +/** + * Get the layout of the current active input panel. + * + * @param ctx An #Ecore_IMF_Context. + * @return layout see #Ecore_IMF_Input_Panel_Layout + * @ingroup Ecore_IMF_Context_Group + * @since 1.1.0 + */ +EAPI Ecore_IMF_Input_Panel_Layout +ecore_imf_context_input_panel_layout_get(Ecore_IMF_Context *ctx) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_panel_layout_get"); + return ECORE_IMF_INPUT_PANEL_LAYOUT_INVALID; + } + + if (ctx->klass->input_panel_layout_get) + return ctx->input_panel_layout; + else + return ECORE_IMF_INPUT_PANEL_LAYOUT_INVALID; +} + +/** + * Set the language of the input panel. + * This API can be used when you want to show the English keyboard. + * + * @param ctx An #Ecore_IMF_Context. + * @param lang the language to be set to the input panel. + * @ingroup Ecore_IMF_Context_Group + * @since 1.1.0 + */ +EAPI void +ecore_imf_context_input_panel_language_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Lang lang) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_panel_language_set"); + return; + } + + if (ctx->klass->input_panel_language_set) ctx->klass->input_panel_language_set(ctx, lang); + ctx->input_panel_lang = lang; +} + +/** + * Get the language of the input panel. + * + * See @ref ecore_imf_context_input_panel_language_set for more details. + * + * @param ctx An #Ecore_IMF_Context. + * @return Ecore_IMF_Input_Panel_Lang + * @ingroup Ecore_IMF_Context_Group + * @since 1.1.0 + */ +EAPI Ecore_IMF_Input_Panel_Lang +ecore_imf_context_input_panel_language_get(Ecore_IMF_Context *ctx) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_panel_language_get"); + return ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC; + } + + return ctx->input_panel_lang; +} + +/** + * Set whether the Input Method Context should request to show the input panel automatically + * when the widget has focus. + * + * @param ctx An #Ecore_IMF_Context. + * @param enabled If true, the input panel will be shown when the widget is clicked or has focus. + * @ingroup Ecore_IMF_Context_Group + * @since 1.1.0 + */ +EAPI void +ecore_imf_context_input_panel_enabled_set(Ecore_IMF_Context *ctx, + Eina_Bool enabled) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_panel_enabled_set"); + return; + } + + ctx->input_panel_enabled = enabled; +} + +/** + * Get whether the Input Method Context requests to show the input panel automatically. + * + * @param ctx An #Ecore_IMF_Context. + * @return Return the attribute to show the input panel automatically + * @ingroup Ecore_IMF_Context_Group + * @since 1.1.0 + */ +EAPI Eina_Bool +ecore_imf_context_input_panel_enabled_get(Ecore_IMF_Context *ctx) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_panel_enabled_get"); + return EINA_FALSE; + } + + return ctx->input_panel_enabled; +} + +/** + * Set the input panel-specific data to deliver to the input panel. + * This API is used by applications to deliver specific data to the input panel. + * The data format MUST be negotiated by both application and the input panel. + * The size and format of data are defined by the input panel. + * + * @param ctx An #Ecore_IMF_Context. + * @param data The specific data to be set to the input panel. + * @param len the length of data, in bytes, to send to the input panel + * @ingroup Ecore_IMF_Context_Group + * @since 1.2.0 + */ +EAPI void +ecore_imf_context_input_panel_imdata_set(Ecore_IMF_Context *ctx, const void *data, int len) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_panel_imdata_set"); + return; + } + + if (!data) return; + + if (ctx->klass->input_panel_imdata_set) + ctx->klass->input_panel_imdata_set(ctx, data, len); +} + +/** + * Get the specific data of the current active input panel. + * + * @param ctx An #Ecore_IMF_Context. + * @param data The specific data to be got from the input panel + * @param len The length of data + * @ingroup Ecore_IMF_Context_Group + * @since 1.2.0 + */ +EAPI void +ecore_imf_context_input_panel_imdata_get(Ecore_IMF_Context *ctx, void *data, int *len) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_panel_imdata_get"); + return; + } + + if (!data) return; + + if (ctx->klass->input_panel_imdata_get) + ctx->klass->input_panel_imdata_get(ctx, data, len); +} + +/** + * Set the "return" key type. This type is used to set string or icon on the "return" key of the input panel. + * + * An input panel displays the string or icon associated with this type + * + * @param ctx An #Ecore_IMF_Context. + * @param return_key_type The type of "return" key on the input panel + * @ingroup Ecore_IMF_Context_Group + * @since 1.2.0 + */ +EAPI void +ecore_imf_context_input_panel_return_key_type_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Return_Key_Type return_key_type) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_panel_return_key_type_set"); + return; + } + + ctx->input_panel_return_key_type = return_key_type; + if (ctx->klass->input_panel_return_key_type_set) ctx->klass->input_panel_return_key_type_set(ctx, return_key_type); +} + +/** + * Get the "return" key type. + * + * @see ecore_imf_context_input_panel_return_key_type_set() for more details + * + * @param ctx An #Ecore_IMF_Context. + * @return The type of "return" key on the input panel + * @ingroup Ecore_IMF_Context_Group + * @since 1.2.0 + */ +EAPI Ecore_IMF_Input_Panel_Return_Key_Type +ecore_imf_context_input_panel_return_key_type_get(Ecore_IMF_Context *ctx) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_panel_return_key_type_get"); + return EINA_FALSE; + } + + return ctx->input_panel_return_key_type; +} + +/** + * Set the return key on the input panel to be disabled. + * + * @param ctx An #Ecore_IMF_Context. + * @param disabled The state + * @ingroup Ecore_IMF_Context_Group + * @since 1.2.0 + */ +EAPI void +ecore_imf_context_input_panel_return_key_disabled_set(Ecore_IMF_Context *ctx, Eina_Bool disabled) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_panel_return_key_disabled_set"); + return; + } + + ctx->input_panel_return_key_disabled = disabled; + if (ctx->klass->input_panel_return_key_disabled_set) ctx->klass->input_panel_return_key_disabled_set(ctx, disabled); +} + +/** + * Get whether the return key on the input panel should be disabled or not. + * + * @param ctx An #Ecore_IMF_Context. + * @return @c EINA_TRUE if it should be disabled. + * @ingroup Ecore_IMF_Context_Group + * @since 1.2.0 + */ +EAPI Eina_Bool +ecore_imf_context_input_panel_return_key_disabled_get(Ecore_IMF_Context *ctx) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_panel_return_key_disabled_get"); + return EINA_FALSE; + } + + return ctx->input_panel_return_key_disabled; +} + +/** + * Set the caps lock mode on the input panel. + * + * @param ctx An #Ecore_IMF_Context. + * @param mode Turn on caps lock on the input panel if @c EINA_TRUE. + * @ingroup Ecore_IMF_Context_Group + * @since 1.2.0 + */ +EAPI void +ecore_imf_context_input_panel_caps_lock_mode_set(Ecore_IMF_Context *ctx, Eina_Bool mode) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_panel_caps_lock_mode_set"); + return; + } + + if (ctx->klass->input_panel_caps_lock_mode_set) + ctx->klass->input_panel_caps_lock_mode_set(ctx, mode); + + ctx->input_panel_caps_lock_mode = mode; +} + +/** + * Get the caps lock mode on the input panel. + * + * @param ctx An #Ecore_IMF_Context. + * @return @c EINA_TRUE if the caps lock is turned on. + * @ingroup Ecore_IMF_Context_Group + * @since 1.2.0 + */ +EAPI Eina_Bool +ecore_imf_context_input_panel_caps_lock_mode_get(Ecore_IMF_Context *ctx) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_panel_caps_lock_mode_get"); + return EINA_FALSE; + } + + return ctx->input_panel_caps_lock_mode; +} + +/** + * Get the position of the current active input panel. + * + * @param ctx An #Ecore_IMF_Context. + * @param x top-left x co-ordinate of the input panel + * @param y top-left y co-ordinate of the input panel + * @param w width of the input panel + * @param h height of the input panel + * @ingroup Ecore_IMF_Context_Group + * @since 1.3 + */ +EAPI void +ecore_imf_context_input_panel_geometry_get(Ecore_IMF_Context *ctx, int *x, int *y, int *w, int *h) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_panel_geometry_get"); + return; + } + + if (ctx->klass->input_panel_geometry_get) + ctx->klass->input_panel_geometry_get(ctx, x, y, w, h); +} + +/** + * Get state of current active input panel. + * + * @param ctx An #Ecore_IMF_Context. + * @return The state of input panel. + * @ingroup Ecore_IMF_Context_Group + * @since 1.3 + */ +EAPI Ecore_IMF_Input_Panel_State +ecore_imf_context_input_panel_state_get(Ecore_IMF_Context *ctx) +{ + Ecore_IMF_Input_Panel_State state = ECORE_IMF_INPUT_PANEL_STATE_HIDE; + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_panel_state_get"); + return ECORE_IMF_INPUT_PANEL_STATE_HIDE; + } + + if (ctx->klass->input_panel_state_get) + state = ctx->klass->input_panel_state_get(ctx); + + return state; +} + +/** + * Register a callback function which will be called if there is change in input panel state,language,mode etc. + * In order to deregister the callback function + * Use @ref ecore_imf_context_input_panel_event_callback_del. + * + * @param ctx An #Ecore_IMF_Context + * @param type event type + * @param func the callback function + * @param data application-input panel specific data. + * @ingroup Ecore_IMF_Context_Group + * @since 1.3 + */ +EAPI void +ecore_imf_context_input_panel_event_callback_add(Ecore_IMF_Context *ctx, + Ecore_IMF_Input_Panel_Event type, + void (*func) (void *data, Ecore_IMF_Context *ctx, int value), + const void *data) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_panel_event_callback_add"); + return; + } + + if (ctx->klass->input_panel_event_callback_add) + ctx->klass->input_panel_event_callback_add(ctx, type, func, (void *)data); +} + +/** + * Unregister a callback function which will be called if there is change in input panel state, language, mode etc. + * + * @param ctx An #Ecore_IMF_Context. + * @param type An #Ecore_IMF_Input_Panel_Event. + * @param func the callback function + * @ingroup Ecore_IMF_Context_Group + * @since 1.3 + */ +EAPI void +ecore_imf_context_input_panel_event_callback_del(Ecore_IMF_Context *ctx, + Ecore_IMF_Input_Panel_Event type, + void (*func) (void *data, Ecore_IMF_Context *ctx, int value)) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_panel_event_callback_del"); + return; + } + + if (ctx->klass->input_panel_event_callback_del) + ctx->klass->input_panel_event_callback_del(ctx, type, func); +} + +/** + * Get the current language locale of the input panel. + * + * ex) fr_FR + * + * @param ctx An #Ecore_IMF_Context. + * @param lang Location to store the retrieved language string. The + * string retrieved must be freed with free(). + * @ingroup Ecore_IMF_Context_Group + * @since 1.3 + */ +EAPI void +ecore_imf_context_input_panel_language_locale_get(Ecore_IMF_Context *ctx, char **lang) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_input_panel_language_locale_get"); + return; + } + + if (ctx->klass->input_panel_language_locale_get) + ctx->klass->input_panel_language_locale_get(ctx, lang); + else + { + if (lang) *lang = strdup(""); + } +} + +/** + * Get the geometry information of the candidate panel. + * + * @param ctx An #Ecore_IMF_Context. + * @param x top-left x co-ordinate of the candidate panel + * @param y top-left y co-ordinate of the candidate panel + * @param w width of the candidate panel + * @param h height of the candidate panel + * @ingroup Ecore_IMF_Context_Group + * @since 1.3 + */ +EAPI void +ecore_imf_context_candidate_panel_geometry_get(Ecore_IMF_Context *ctx, int *x, int *y, int *w, int *h) +{ + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_candidate_panel_geometry_get"); + return; + } + + if (ctx->klass->candidate_panel_geometry_get) + ctx->klass->candidate_panel_geometry_get(ctx, x, y, w, h); +} + diff --git a/src/lib/ecore_imf/ecore_imf_module.c b/src/lib/ecore_imf/ecore_imf_module.c new file mode 100644 index 0000000..946f5bc --- /dev/null +++ b/src/lib/ecore_imf/ecore_imf_module.c @@ -0,0 +1,212 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include + +#include "Ecore_IMF.h" +#include "ecore_imf_private.h" + +static void _ecore_imf_module_free(Ecore_IMF_Module *module); +static int _ecore_imf_modules_exists(const char *ctx_id); + +typedef struct _Ecore_IMF_Selector +{ + const char *toselect; + void *selected; +} Ecore_IMF_Selector; + +static Eina_Hash *modules = NULL; +static Eina_Array *module_list = NULL; + +void +ecore_imf_module_init(void) +{ + char *homedir; + + module_list = eina_module_list_get(NULL, PACKAGE_LIB_DIR "/ecore/immodules", 0, NULL, NULL); + homedir = eina_module_environment_path_get("HOME", "/.ecore/immodules"); + if (homedir) + { + module_list = eina_module_list_get(module_list, homedir, 0, NULL, NULL); + free(homedir); + } + eina_module_list_load(module_list); +} + +void +ecore_imf_module_shutdown(void) +{ + if (modules) + { + eina_hash_free(modules); + modules = NULL; + } + if (module_list) + { + eina_module_list_free(module_list); + eina_array_free(module_list); + module_list = NULL; + } +} + +static Eina_Bool +_hash_module_available_get(const Eina_Hash *hash __UNUSED__, int *data, void *list) +{ + *(Eina_List**)list = eina_list_append(*(Eina_List**)list, data); + return EINA_TRUE; +} + +Eina_List * +ecore_imf_module_available_get(void) +{ + Eina_List *values = NULL; + Eina_Iterator *it = NULL; + + if (!modules) return NULL; + + it = eina_hash_iterator_data_new(modules); + if (!it) + return NULL; + + eina_iterator_foreach(it, EINA_EACH_CB(_hash_module_available_get), &values); + eina_iterator_free(it); + + return values; +} + +Ecore_IMF_Module * +ecore_imf_module_get(const char *ctx_id) +{ + if (!modules) return NULL; + return eina_hash_find(modules, ctx_id); +} + +Ecore_IMF_Context * +ecore_imf_module_context_create(const char *ctx_id) +{ + Ecore_IMF_Module *module; + Ecore_IMF_Context *ctx = NULL; + + if (!modules) return NULL; + module = eina_hash_find(modules, ctx_id); + if (module) + { + ctx = module->create(); + if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) + { + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_module_context_create"); + return NULL; + } + ctx->module = module; + } + return ctx; +} + +static Eina_Bool +_hash_ids_get(const Eina_Hash *hash __UNUSED__, const char *key, void *list) +{ + *(Eina_List**)list = eina_list_append(*(Eina_List**)list, key); + return EINA_TRUE; +} + +Eina_List * +ecore_imf_module_context_ids_get(void) +{ + Eina_List *l = NULL; + Eina_Iterator *it = NULL; + + if (!modules) return NULL; + + it = eina_hash_iterator_key_new(modules); + if (!it) + return NULL; + + eina_iterator_foreach(it, EINA_EACH_CB(_hash_ids_get), &l); + eina_iterator_free(it); + + return l; +} + +static Eina_Bool +_hash_ids_by_canvas_type_get(const Eina_Hash *hash __UNUSED__, void *data, void *fdata) +{ + Ecore_IMF_Module *module = data; + Ecore_IMF_Selector *selector = fdata; + + if (!strcmp(module->info->canvas_type, selector->toselect)) + selector->selected = eina_list_append(selector->selected, (void *)module->info->id); + + return EINA_TRUE; +} + +Eina_List * +ecore_imf_module_context_ids_by_canvas_type_get(const char *canvas_type) +{ + Ecore_IMF_Selector selector; + Eina_List *values = NULL; + Eina_Iterator *it = NULL; + + if (!modules) return NULL; + + if (!canvas_type) + return ecore_imf_module_context_ids_get(); + + it = eina_hash_iterator_data_new(modules); + if (!it) + return NULL; + + selector.toselect = canvas_type; + selector.selected = values; + eina_iterator_foreach(it, EINA_EACH_CB(_hash_ids_by_canvas_type_get), &selector); + eina_iterator_free(it); + + return values; +} + +EAPI void +ecore_imf_module_register(const Ecore_IMF_Context_Info *info, + Ecore_IMF_Context *(*imf_module_create)(void), + Ecore_IMF_Context *(*imf_module_exit)(void)) +{ + Ecore_IMF_Module *module; + + if (_ecore_imf_modules_exists(info->id)) return; + + if (!modules) + modules = eina_hash_string_superfast_new(EINA_FREE_CB(_ecore_imf_module_free)); + + module = malloc(sizeof(Ecore_IMF_Module)); + module->info = info; + /* cache imf_module_create as it may be used several times */ + module->create = imf_module_create; + module->exit = imf_module_exit; + + eina_hash_add(modules, info->id, module); +} + +static void +_ecore_imf_module_free(Ecore_IMF_Module *module) +{ + if (module->exit) module->exit(); + free(module); +} + +static int +_ecore_imf_modules_exists(const char *ctx_id) +{ + if (!modules) return 0; + if (!ctx_id) return 0; + + if (eina_hash_find(modules, ctx_id)) + return 1; + + return 0; +} diff --git a/src/lib/ecore_imf/ecore_imf_private.h b/src/lib/ecore_imf/ecore_imf_private.h new file mode 100644 index 0000000..b4ff0f2 --- /dev/null +++ b/src/lib/ecore_imf/ecore_imf_private.h @@ -0,0 +1,84 @@ +#ifndef _ECORE_IMF_PRIVATE_H +#define _ECORE_IMF_PRIVATE_H + +#define ECORE_MAGIC_CONTEXT 0x56c1b39a + +#ifdef ECORE_IMF_DEFAULT_LOG_COLOR +#undef ECORE_IMF_DEFAULT_LOG_COLOR +#endif +#define ECORE_IMF_DEFAULT_LOG_COLOR EINA_COLOR_BLUE + +extern int _ecore_imf_log_dom; +#ifdef ERR +# undef ERR +#endif +#define ERR(...) EINA_LOG_DOM_ERR(_ecore_imf_log_dom, __VA_ARGS__) + +#ifdef DBG +# undef DBG +#endif +#define DBG(...) EINA_LOG_DOM_DBG(_ecore_imf_log_dom, __VA_ARGS__) + +#ifdef INF +# undef INF +#endif +#define INF(...) EINA_LOG_DOM_INFO(_ecore_imf_log_dom, __VA_ARGS__) + +#ifdef WRN +# undef WRN +#endif +#define WRN(...) EINA_LOG_DOM_WARN(_ecore_imf_log_dom, __VA_ARGS__) + +#ifdef CRIT +# undef CRIT +#endif +#define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_imf_log_dom, __VA_ARGS__) + +typedef struct _Ecore_IMF_Module Ecore_IMF_Module; +typedef struct _Ecore_IMF_Func_Node Ecore_IMF_Func_Node; + +struct _Ecore_IMF_Context +{ + ECORE_MAGIC; + const Ecore_IMF_Module *module; + const Ecore_IMF_Context_Class *klass; + void *data; + int input_mode; + void *window; + void *client_canvas; + Eina_Bool (*retrieve_surrounding_func)(void *data, Ecore_IMF_Context *ctx, char **text, int *cursor_pos); + void *retrieve_surrounding_data; + Eina_List *callbacks; + Ecore_IMF_Autocapital_Type autocapital_type; + Ecore_IMF_Input_Panel_Layout input_panel_layout; + Ecore_IMF_Input_Panel_Lang input_panel_lang; + Ecore_IMF_Input_Panel_Return_Key_Type input_panel_return_key_type; + Eina_Bool allow_prediction : 1; + Eina_Bool input_panel_enabled : 1; + Eina_Bool input_panel_return_key_disabled : 1; + Eina_Bool input_panel_caps_lock_mode : 1; +}; + +struct _Ecore_IMF_Module +{ + const Ecore_IMF_Context_Info *info; + Ecore_IMF_Context *(*create)(void); + Ecore_IMF_Context *(*exit)(void); +}; + +struct _Ecore_IMF_Func_Node +{ + void (*func) (); + const void *data; + Ecore_IMF_Callback_Type type; +}; + +void ecore_imf_module_init(void); +void ecore_imf_module_shutdown(void); +Eina_List *ecore_imf_module_available_get(void); +Ecore_IMF_Module *ecore_imf_module_get(const char *ctx_id); +Ecore_IMF_Context *ecore_imf_module_context_create(const char *ctx_id); +Eina_List *ecore_imf_module_context_ids_get(void); +Eina_List *ecore_imf_module_context_ids_by_canvas_type_get(const char *canvas_type); + +#endif diff --git a/src/lib/ecore_imf_evas/Ecore_IMF_Evas.h b/src/lib/ecore_imf_evas/Ecore_IMF_Evas.h new file mode 100644 index 0000000..5f7cdb9 --- /dev/null +++ b/src/lib/ecore_imf_evas/Ecore_IMF_Evas.h @@ -0,0 +1,50 @@ +#ifndef _ECORE_IMF_EVAS_H +#define _ECORE_IMF_EVAS_H + +#include +#include + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_ECORE_IMF_EVAS_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_ECORE_IMF_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +#ifdef __cplusplus +extern "C" { +#endif + +EAPI void ecore_imf_evas_event_mouse_in_wrap(Evas_Event_Mouse_In *evas_event, Ecore_IMF_Event_Mouse_In *imf_event); +EAPI void ecore_imf_evas_event_mouse_out_wrap(Evas_Event_Mouse_Out *evas_event, Ecore_IMF_Event_Mouse_Out *imf_event); +EAPI void ecore_imf_evas_event_mouse_move_wrap(Evas_Event_Mouse_Move *evas_event, Ecore_IMF_Event_Mouse_Move *imf_event); +EAPI void ecore_imf_evas_event_mouse_down_wrap(Evas_Event_Mouse_Down *evas_event, Ecore_IMF_Event_Mouse_Down *imf_event); +EAPI void ecore_imf_evas_event_mouse_up_wrap(Evas_Event_Mouse_Up *evas_event, Ecore_IMF_Event_Mouse_Up *imf_event); +EAPI void ecore_imf_evas_event_mouse_wheel_wrap(Evas_Event_Mouse_Wheel *evas_event, Ecore_IMF_Event_Mouse_Wheel *imf_event); +EAPI void ecore_imf_evas_event_key_down_wrap(Evas_Event_Key_Down *evas_event, Ecore_IMF_Event_Key_Down *imf_event); +EAPI void ecore_imf_evas_event_key_up_wrap(Evas_Event_Key_Up *evas_event, Ecore_IMF_Event_Key_Up *imf_event); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/ecore_imf_evas/Makefile.am b/src/lib/ecore_imf_evas/Makefile.am new file mode 100644 index 0000000..fa5c491 --- /dev/null +++ b/src/lib/ecore_imf_evas/Makefile.am @@ -0,0 +1,22 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore_imf \ +@EFL_ECORE_IMF_EVAS_BUILD@ \ +@EVAS_CFLAGS@ \ +@EINA_CFLAGS@ + +lib_LTLIBRARIES = libecore_imf_evas.la +includes_HEADERS = Ecore_IMF_Evas.h +includesdir = $(includedir)/ecore-@VMAJ@ + +libecore_imf_evas_la_SOURCES = \ +ecore_imf_evas.c + +libecore_imf_evas_la_LIBADD = \ +$(top_builddir)/src/lib/ecore_imf/libecore_imf.la \ +@EVAS_LIBS@ \ +@EINA_LIBS@ + +libecore_imf_evas_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ diff --git a/src/lib/ecore_imf_evas/ecore_imf_evas.c b/src/lib/ecore_imf_evas/ecore_imf_evas.c new file mode 100644 index 0000000..cd6ec41 --- /dev/null +++ b/src/lib/ecore_imf_evas/ecore_imf_evas.c @@ -0,0 +1,309 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "Ecore_IMF_Evas.h" + +/** + * @defgroup Ecore_IMF_Evas_Group Ecore Input Method Context Evas Helper Functions + * + * Helper functions to make it easy to use Evas with Ecore_IMF. + * Converts each event from Evas to the corresponding event of Ecore_IMF. + * + * An example of usage of these functions can be found at: + * @li @ref ecore_imf_example_c + */ + +static const char *_ecore_imf_evas_event_empty = ""; + +/* Converts the Evas modifiers to Ecore_IMF keyboard modifiers */ +static void +_ecore_imf_evas_event_modifiers_wrap(Evas_Modifier *evas_modifiers, + Ecore_IMF_Keyboard_Modifiers *imf_keyboard_modifiers) +{ + if (!evas_modifiers || !imf_keyboard_modifiers) + return; + + *imf_keyboard_modifiers = ECORE_IMF_KEYBOARD_MODIFIER_NONE; + if (evas_key_modifier_is_set(evas_modifiers, "Control")) + *imf_keyboard_modifiers |= ECORE_IMF_KEYBOARD_MODIFIER_CTRL; + if (evas_key_modifier_is_set(evas_modifiers, "Alt")) + *imf_keyboard_modifiers |= ECORE_IMF_KEYBOARD_MODIFIER_ALT; + if (evas_key_modifier_is_set(evas_modifiers, "Shift")) + *imf_keyboard_modifiers |= ECORE_IMF_KEYBOARD_MODIFIER_SHIFT; + if (evas_key_modifier_is_set(evas_modifiers, "Super") || evas_key_modifier_is_set(evas_modifiers, "Hyper")) + *imf_keyboard_modifiers |= ECORE_IMF_KEYBOARD_MODIFIER_WIN; + if (evas_key_modifier_is_set(evas_modifiers, "AltGr")) + *imf_keyboard_modifiers |= ECORE_IMF_KEYBOARD_MODIFIER_ALTGR; +} + +/* Converts the Evas locks to Ecore_IMF keyboard locks */ +static void +_ecore_imf_evas_event_locks_wrap(Evas_Lock *evas_locks, + Ecore_IMF_Keyboard_Locks *imf_keyboard_locks) +{ + if (!evas_locks || !imf_keyboard_locks) + return; + + *imf_keyboard_locks = ECORE_IMF_KEYBOARD_LOCK_NONE; + if (evas_key_lock_is_set(evas_locks, "Num_Lock")) + *imf_keyboard_locks |= ECORE_IMF_KEYBOARD_LOCK_NUM; + if (evas_key_lock_is_set(evas_locks, "Caps_Lock")) + *imf_keyboard_locks |= ECORE_IMF_KEYBOARD_LOCK_CAPS; + if (evas_key_lock_is_set(evas_locks, "Scroll_Lock")) + *imf_keyboard_locks |= ECORE_IMF_KEYBOARD_LOCK_SCROLL; +} + +/* Converts the Evas mouse flags to Ecore_IMF mouse flags */ +static void +_ecore_imf_evas_event_mouse_flags_wrap(Evas_Button_Flags evas_flags, + Ecore_IMF_Mouse_Flags *imf_flags) +{ + if (!imf_flags) + return; + + *imf_flags = ECORE_IMF_MOUSE_NONE; + if (evas_flags & EVAS_BUTTON_DOUBLE_CLICK) + *imf_flags |= ECORE_IMF_MOUSE_DOUBLE_CLICK; + if (evas_flags & EVAS_BUTTON_TRIPLE_CLICK) + *imf_flags |= ECORE_IMF_MOUSE_TRIPLE_CLICK; +} + +/** + * Converts a "mouse_in" event from Evas to the corresponding event of Ecore_IMF. + * + * @param evas_event The received Evas event. + * @param imf_event The location to store the converted Ecore_IMF event. + * @ingroup Ecore_IMF_Evas_Group + */ +EAPI void +ecore_imf_evas_event_mouse_in_wrap(Evas_Event_Mouse_In *evas_event, + Ecore_IMF_Event_Mouse_In *imf_event) +{ + if (!evas_event || !imf_event) + return; + + imf_event->buttons = evas_event->buttons; + imf_event->output.x = evas_event->output.x; + imf_event->output.y = evas_event->output.y; + imf_event->canvas.x = evas_event->canvas.x; + imf_event->canvas.y = evas_event->canvas.y; + imf_event->timestamp = evas_event->timestamp; + _ecore_imf_evas_event_modifiers_wrap(evas_event->modifiers, &imf_event->modifiers); + _ecore_imf_evas_event_locks_wrap(evas_event->locks, &imf_event->locks); +} + +/** + * Converts a "mouse_out" event from Evas to the corresponding event of Ecore_IMF. + * + * @param evas_event The received Evas event. + * @param imf_event The location to store the converted Ecore_IMF event. + * @ingroup Ecore_IMF_Evas_Group + */ +EAPI void +ecore_imf_evas_event_mouse_out_wrap(Evas_Event_Mouse_Out *evas_event, + Ecore_IMF_Event_Mouse_Out *imf_event) +{ + if (!evas_event || !imf_event) + return; + + imf_event->buttons = evas_event->buttons; + imf_event->output.x = evas_event->output.x; + imf_event->output.y = evas_event->output.y; + imf_event->canvas.x = evas_event->canvas.x; + imf_event->canvas.y = evas_event->canvas.y; + imf_event->timestamp = evas_event->timestamp; + _ecore_imf_evas_event_modifiers_wrap(evas_event->modifiers, &imf_event->modifiers); + _ecore_imf_evas_event_locks_wrap(evas_event->locks, &imf_event->locks); +} + +/** + * Converts a "mouse_move" event from Evas to the corresponding event of Ecore_IMF. + * + * @param evas_event The received Evas event. + * @param imf_event The location to store the converted Ecore_IMF event. + * @ingroup Ecore_IMF_Evas_Group + */ +EAPI void +ecore_imf_evas_event_mouse_move_wrap(Evas_Event_Mouse_Move *evas_event, + Ecore_IMF_Event_Mouse_Move *imf_event) +{ + if (!evas_event || !imf_event) + return; + + imf_event->buttons = evas_event->buttons; + imf_event->cur.output.x = evas_event->cur.output.x; + imf_event->cur.output.y = evas_event->cur.output.y; + imf_event->prev.output.x = evas_event->prev.output.x; + imf_event->prev.output.y = evas_event->prev.output.y; + imf_event->cur.canvas.x = evas_event->cur.canvas.x; + imf_event->cur.canvas.y = evas_event->cur.canvas.y; + imf_event->prev.canvas.x = evas_event->prev.canvas.x; + imf_event->prev.canvas.y = evas_event->prev.canvas.y; + imf_event->timestamp = evas_event->timestamp; + _ecore_imf_evas_event_modifiers_wrap(evas_event->modifiers, &imf_event->modifiers); + _ecore_imf_evas_event_locks_wrap(evas_event->locks, &imf_event->locks); +} + +/** + * Converts a "mouse_down" event from Evas to the corresponding event of Ecore_IMF. + * + * @param evas_event The received Evas event. + * @param imf_event The location to store the converted Ecore_IMF event. + * @ingroup Ecore_IMF_Evas_Group + */ +EAPI void +ecore_imf_evas_event_mouse_down_wrap(Evas_Event_Mouse_Down *evas_event, + Ecore_IMF_Event_Mouse_Down *imf_event) +{ + if (!evas_event || !imf_event) + return; + + imf_event->button = evas_event->button; + imf_event->output.x = evas_event->output.x; + imf_event->output.y = evas_event->output.y; + imf_event->canvas.x = evas_event->canvas.x; + imf_event->canvas.y = evas_event->canvas.y; + imf_event->timestamp = evas_event->timestamp; + _ecore_imf_evas_event_modifiers_wrap(evas_event->modifiers, &imf_event->modifiers); + _ecore_imf_evas_event_locks_wrap(evas_event->locks, &imf_event->locks); + _ecore_imf_evas_event_mouse_flags_wrap(evas_event->flags, &imf_event->flags); +} + +/** + * Converts a "mouse_up" event from Evas to the corresponding event of Ecore_IMF. + * + * @param evas_event The received Evas event. + * @param imf_event The location to store the converted Ecore_IMF event. + * @ingroup Ecore_IMF_Evas_Group + */ +EAPI void +ecore_imf_evas_event_mouse_up_wrap(Evas_Event_Mouse_Up *evas_event, + Ecore_IMF_Event_Mouse_Up *imf_event) +{ + if (!evas_event || !imf_event) + return; + + imf_event->button = evas_event->button; + imf_event->output.x = evas_event->output.x; + imf_event->output.y = evas_event->output.y; + imf_event->canvas.x = evas_event->canvas.x; + imf_event->canvas.y = evas_event->canvas.y; + imf_event->timestamp = evas_event->timestamp; + _ecore_imf_evas_event_modifiers_wrap(evas_event->modifiers, &imf_event->modifiers); + _ecore_imf_evas_event_locks_wrap(evas_event->locks, &imf_event->locks); + _ecore_imf_evas_event_mouse_flags_wrap(evas_event->flags, &imf_event->flags); +} + +/** + * Converts a "mouse_wheel" event from Evas to the corresponding event of Ecore_IMF. + * + * @param evas_event The received Evas event. + * @param imf_event The location to store the converted Ecore_IMF event. + * @ingroup Ecore_IMF_Evas_Group + */ +EAPI void +ecore_imf_evas_event_mouse_wheel_wrap(Evas_Event_Mouse_Wheel *evas_event, + Ecore_IMF_Event_Mouse_Wheel *imf_event) +{ + if (!evas_event || !imf_event) + return; + + imf_event->direction = evas_event->direction; + imf_event->z = evas_event->z; + imf_event->output.x = evas_event->output.x; + imf_event->output.y = evas_event->output.y; + imf_event->canvas.x = evas_event->canvas.x; + imf_event->canvas.y = evas_event->canvas.y; + imf_event->timestamp = evas_event->timestamp; + _ecore_imf_evas_event_modifiers_wrap(evas_event->modifiers, &imf_event->modifiers); + _ecore_imf_evas_event_locks_wrap(evas_event->locks, &imf_event->locks); + imf_event->timestamp = evas_event->timestamp; +} + +/** + * Converts a "key_down" event from Evas to the corresponding event of Ecore_IMF. + * + * @param evas_event The received Evas event. + * @param imf_event The location to store the converted Ecore_IMF event. + * @ingroup Ecore_IMF_Evas_Group + * + * Example + * @code + * static void + * _key_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) + * { + * Evas_Event_Key_Down *ev = event_info; + * if (!ev->keyname) return; + * + * if (imf_context) + * { + * Ecore_IMF_Event_Key_Down ecore_ev; + * ecore_imf_evas_event_key_down_wrap(ev, &ecore_ev); + * if (ecore_imf_context_filter_event(imf_context, + * ECORE_IMF_EVENT_KEY_DOWN, + * (Ecore_IMF_Event *)&ecore_ev)) + * return; + * } + * } + * + * evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, data); + * @endcode + */ +EAPI void +ecore_imf_evas_event_key_down_wrap(Evas_Event_Key_Down *evas_event, + Ecore_IMF_Event_Key_Down *imf_event) +{ + if (!evas_event || !imf_event) + return; + + imf_event->keyname = evas_event->keyname ? evas_event->keyname : _ecore_imf_evas_event_empty; + imf_event->key = evas_event->key ? evas_event->key : _ecore_imf_evas_event_empty; + imf_event->string = evas_event->string ? evas_event->string : _ecore_imf_evas_event_empty; + imf_event->compose = evas_event->compose ? evas_event->compose : _ecore_imf_evas_event_empty; + imf_event->timestamp = evas_event->timestamp; + _ecore_imf_evas_event_modifiers_wrap(evas_event->modifiers, &imf_event->modifiers); + _ecore_imf_evas_event_locks_wrap(evas_event->locks, &imf_event->locks); +} + +/** + * Converts a "key_up" event from Evas to the corresponding event of Ecore_IMF. + * + * @param evas_event The received Evas event. + * @param imf_event The location to store the converted Ecore_IMF event. + * @ingroup Ecore_IMF_Evas_Group + * + * Example + * @code + * static void + * _key_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) + * { + * Evas_Event_Key_Up *ev = event_info; + * if (!ev->keyname) return; + * + * if (imf_context) + * { + * Ecore_IMF_Event_Key_Up ecore_ev; + * ecore_imf_evas_event_key_up_wrap(ev, &ecore_ev); + * if (ecore_imf_context_filter_event(imf_context, + * ECORE_IMF_EVENT_KEY_UP, + * (Ecore_IMF_Event *)&ecore_ev)) + * return; + * } + * } + * + * evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_UP, _key_up_cb, data); + * @endcode + */ +EAPI void +ecore_imf_evas_event_key_up_wrap(Evas_Event_Key_Up *evas_event, + Ecore_IMF_Event_Key_Up *imf_event) +{ + imf_event->keyname = evas_event->keyname ? evas_event->keyname : _ecore_imf_evas_event_empty; + imf_event->key = evas_event->key ? evas_event->key : _ecore_imf_evas_event_empty; + imf_event->string = evas_event->string ? evas_event->string : _ecore_imf_evas_event_empty; + imf_event->compose = evas_event->compose ? evas_event->compose : _ecore_imf_evas_event_empty; + imf_event->timestamp = evas_event->timestamp; + _ecore_imf_evas_event_modifiers_wrap(evas_event->modifiers, &imf_event->modifiers); + _ecore_imf_evas_event_locks_wrap(evas_event->locks, &imf_event->locks); +} diff --git a/src/lib/ecore_input/Ecore_Input.h b/src/lib/ecore_input/Ecore_Input.h new file mode 100644 index 0000000..376703c --- /dev/null +++ b/src/lib/ecore_input/Ecore_Input.h @@ -0,0 +1,234 @@ +#ifndef _ECORE_INPUT_H +#define _ECORE_INPUT_H + +#ifdef _WIN32 +# include +#else +# include +#endif + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_ECORE_INPUT_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_ECORE_INPUT_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + EAPI extern int ECORE_EVENT_KEY_DOWN; + EAPI extern int ECORE_EVENT_KEY_UP; + EAPI extern int ECORE_EVENT_MOUSE_BUTTON_DOWN; + EAPI extern int ECORE_EVENT_MOUSE_BUTTON_UP; + EAPI extern int ECORE_EVENT_MOUSE_MOVE; + EAPI extern int ECORE_EVENT_MOUSE_WHEEL; + EAPI extern int ECORE_EVENT_MOUSE_IN; + EAPI extern int ECORE_EVENT_MOUSE_OUT; + +#define ECORE_EVENT_MODIFIER_SHIFT 0x0001 +#define ECORE_EVENT_MODIFIER_CTRL 0x0002 +#define ECORE_EVENT_MODIFIER_ALT 0x0004 +#define ECORE_EVENT_MODIFIER_WIN 0x0008 +#define ECORE_EVENT_MODIFIER_SCROLL 0x0010 +#define ECORE_EVENT_MODIFIER_NUM 0x0020 +#define ECORE_EVENT_MODIFIER_CAPS 0x0040 +#define ECORE_EVENT_LOCK_SCROLL 0x0080 +#define ECORE_EVENT_LOCK_NUM 0x0100 +#define ECORE_EVENT_LOCK_CAPS 0x0200 +#define ECORE_EVENT_LOCK_SHIFT 0x0300 +#define ECORE_EVENT_MODIFIER_ALTGR 0x0400 /**< @since 1.7 */ + + typedef uintptr_t Ecore_Window; + typedef struct _Ecore_Event_Key Ecore_Event_Key; + typedef struct _Ecore_Event_Mouse_Button Ecore_Event_Mouse_Button; + typedef struct _Ecore_Event_Mouse_Wheel Ecore_Event_Mouse_Wheel; + typedef struct _Ecore_Event_Mouse_Move Ecore_Event_Mouse_Move; + typedef struct _Ecore_Event_Mouse_IO Ecore_Event_Mouse_IO; + typedef struct _Ecore_Event_Modifiers Ecore_Event_Modifiers; + + typedef enum _Ecore_Event_Modifier + { + ECORE_NONE, + ECORE_SHIFT, + ECORE_CTRL, + ECORE_ALT, + ECORE_WIN, + ECORE_SCROLL, + ECORE_CAPS, + ECORE_MODE, /**< @since 1.7 */ + ECORE_LAST + } Ecore_Event_Modifier; + + typedef enum _Ecore_Event_Press + { + ECORE_DOWN, + ECORE_UP + } Ecore_Event_Press; + + typedef enum _Ecore_Event_IO + { + ECORE_IN, + ECORE_OUT + } Ecore_Event_IO; + + typedef enum _Ecore_Compose_State + { + ECORE_COMPOSE_NONE, + ECORE_COMPOSE_MIDDLE, + ECORE_COMPOSE_DONE + } Ecore_Compose_State; + + struct _Ecore_Event_Key + { + const char *keyname; + const char *key; + const char *string; + const char *compose; + Ecore_Window window; + Ecore_Window root_window; + Ecore_Window event_window; + + unsigned int timestamp; + unsigned int modifiers; + + int same_screen; + }; + + struct _Ecore_Event_Mouse_Button + { + Ecore_Window window; + Ecore_Window root_window; + Ecore_Window event_window; + + unsigned int timestamp; + unsigned int modifiers; + unsigned int buttons; + unsigned int double_click; + unsigned int triple_click; + int same_screen; + + int x; + int y; + struct { + int x; + int y; + } root; + + struct { + int device; /* 0 if normal mouse, 1+ for other mouse-devices (eg multi-touch - other fingers) */ + double radius, radius_x, radius_y; /* radius of press point - radius_x and y if its an ellipse (radius is the average of the 2) */ + double pressure; /* pressure - 1.0 == normal, > 1.0 == more, 0.0 == none */ + double angle; /* angle relative to perpendicular (0.0 == perpendicular), in degrees */ + double x, y; /* same as x, y root.x, root.y, but with sub-pixel precision, if available */ + struct { + double x, y; + } root; + } multi; + }; + + struct _Ecore_Event_Mouse_Wheel + { + Ecore_Window window; + Ecore_Window root_window; + Ecore_Window event_window; + + unsigned int timestamp; + unsigned int modifiers; + + int same_screen; + int direction; + int z; + + int x; + int y; + struct { + int x; + int y; + } root; + }; + + struct _Ecore_Event_Mouse_Move + { + Ecore_Window window; + Ecore_Window root_window; + Ecore_Window event_window; + + unsigned int timestamp; + unsigned int modifiers; + + int same_screen; + + int x; + int y; + struct { + int x; + int y; + } root; + + struct { + int device; /* 0 if normal mouse, 1+ for other mouse-devices (eg multi-touch - other fingers) */ + double radius, radius_x, radius_y; /* radius of press point - radius_x and y if its an ellipse (radius is the average of the 2) */ + double pressure; /* pressure - 1.0 == normal, > 1.0 == more, 0.0 == none */ + double angle; /* angle relative to perpendicular (0.0 == perpendicular), in degrees */ + double x, y; /* same as x, y root.x, root.y, but with sub-pixel precision, if available */ + struct { + double x, y; + } root; + } multi; + }; + + struct _Ecore_Event_Mouse_IO + { + Ecore_Window window; + Ecore_Window event_window; + + unsigned int timestamp; + unsigned int modifiers; + + int x; + int y; + }; + + struct _Ecore_Event_Modifiers + { + unsigned int size; + unsigned int array[ECORE_LAST]; + }; + + EAPI int ecore_event_init(void); + EAPI int ecore_event_shutdown(void); + + EAPI unsigned int ecore_event_modifier_mask(Ecore_Event_Modifier modifier); + EAPI Ecore_Event_Modifier ecore_event_update_modifier(const char *key, Ecore_Event_Modifiers *modifiers, int inc); + + /** + * @since 1.7 + */ + EAPI Ecore_Compose_State ecore_compose_get(const Eina_List *seq, char **seqstr_ret); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/ecore_input/Makefile.am b/src/lib/ecore_input/Makefile.am new file mode 100644 index 0000000..da00da7 --- /dev/null +++ b/src/lib/ecore_input/Makefile.am @@ -0,0 +1,26 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_builddir)/src/lib/ecore \ +@EFL_ECORE_INPUT_BUILD@ \ +@EINA_CFLAGS@ \ +@EVIL_CFLAGS@ + +lib_LTLIBRARIES = libecore_input.la +includes_HEADERS = Ecore_Input.h +includesdir = $(includedir)/ecore-@VMAJ@ + +libecore_input_la_SOURCES = \ +ecore_input.c \ +ecore_input_compose.c \ +ecore_input_compose.h + +libecore_input_la_LIBADD = \ +$(top_builddir)/src/lib/ecore/libecore.la \ +@EINA_LIBS@ \ +@EVIL_LIBS@ + +libecore_input_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ + +EXTRA_DIST = ecore_input_private.h diff --git a/src/lib/ecore_input/ecore_input.c b/src/lib/ecore_input/ecore_input.c new file mode 100644 index 0000000..8f4b1f9 --- /dev/null +++ b/src/lib/ecore_input/ecore_input.c @@ -0,0 +1,127 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "Ecore.h" +#include "ecore_private.h" + +#include "Ecore_Input.h" +#include "ecore_input_private.h" + + +int _ecore_input_log_dom = -1; + +EAPI int ECORE_EVENT_KEY_DOWN = 0; +EAPI int ECORE_EVENT_KEY_UP = 0; +EAPI int ECORE_EVENT_MOUSE_BUTTON_DOWN = 0; +EAPI int ECORE_EVENT_MOUSE_BUTTON_UP = 0; +EAPI int ECORE_EVENT_MOUSE_MOVE = 0; +EAPI int ECORE_EVENT_MOUSE_WHEEL = 0; +EAPI int ECORE_EVENT_MOUSE_IN = 0; +EAPI int ECORE_EVENT_MOUSE_OUT = 0; + +static int _ecore_event_init_count = 0; + +EAPI int +ecore_event_init(void) +{ + if (++_ecore_event_init_count != 1) + return _ecore_event_init_count; + if (!ecore_init()) + { + _ecore_event_init_count--; + return 0; + } + + _ecore_input_log_dom = eina_log_domain_register + ("ecore_input", ECORE_INPUT_DEFAULT_LOG_COLOR); + if(_ecore_input_log_dom < 0) + { + EINA_LOG_ERR("Impossible to create a log domain for the ecore input module."); + return --_ecore_event_init_count; + } + + ECORE_EVENT_KEY_DOWN = ecore_event_type_new(); + ECORE_EVENT_KEY_UP = ecore_event_type_new(); + ECORE_EVENT_MOUSE_BUTTON_DOWN = ecore_event_type_new(); + ECORE_EVENT_MOUSE_BUTTON_UP = ecore_event_type_new(); + ECORE_EVENT_MOUSE_MOVE = ecore_event_type_new(); + ECORE_EVENT_MOUSE_WHEEL = ecore_event_type_new(); + ECORE_EVENT_MOUSE_IN = ecore_event_type_new(); + ECORE_EVENT_MOUSE_OUT = ecore_event_type_new(); + + return _ecore_event_init_count; +} + +EAPI int +ecore_event_shutdown(void) +{ + if (--_ecore_event_init_count != 0) + return _ecore_event_init_count; + + ECORE_EVENT_KEY_DOWN = 0; + ECORE_EVENT_KEY_UP = 0; + ECORE_EVENT_MOUSE_BUTTON_DOWN = 0; + ECORE_EVENT_MOUSE_BUTTON_UP = 0; + ECORE_EVENT_MOUSE_MOVE = 0; + ECORE_EVENT_MOUSE_WHEEL = 0; + ECORE_EVENT_MOUSE_IN = 0; + ECORE_EVENT_MOUSE_OUT = 0; + eina_log_domain_unregister(_ecore_input_log_dom); + _ecore_input_log_dom = -1; + ecore_shutdown(); + return _ecore_event_init_count; +} + +typedef struct _Ecore_Event_Modifier_Match Ecore_Event_Modifier_Match; +struct _Ecore_Event_Modifier_Match +{ + const char *key; + Ecore_Event_Modifier modifier; + unsigned int event_modifier; +}; + +static const Ecore_Event_Modifier_Match matchs[] = { + { "Shift_L", ECORE_SHIFT, ECORE_EVENT_MODIFIER_SHIFT }, + { "Shift_R", ECORE_SHIFT, ECORE_EVENT_MODIFIER_SHIFT }, + { "Alt_L", ECORE_ALT, ECORE_EVENT_MODIFIER_ALT }, + { "Alt_R", ECORE_ALT, ECORE_EVENT_MODIFIER_ALT }, + { "Control_L", ECORE_CTRL, ECORE_EVENT_MODIFIER_CTRL }, + { "Control_R", ECORE_CTRL, ECORE_EVENT_MODIFIER_CTRL }, + { "Caps_Lock", ECORE_CAPS, ECORE_EVENT_MODIFIER_CAPS }, + { "Super_L", ECORE_WIN, ECORE_EVENT_MODIFIER_WIN }, + { "Super_R", ECORE_WIN, ECORE_EVENT_MODIFIER_WIN }, + { "ISO_Level3_Shift", ECORE_MODE, ECORE_EVENT_MODIFIER_ALTGR }, + { "Scroll_Lock", ECORE_SCROLL, ECORE_EVENT_MODIFIER_SCROLL } +}; + +EAPI unsigned int +ecore_event_modifier_mask(Ecore_Event_Modifier modifier) +{ + size_t i; + + for (i = 0; i < sizeof (matchs) / sizeof (Ecore_Event_Modifier_Match); i++) + if (matchs[i].modifier == modifier) + return matchs[i].event_modifier; + + return 0; +} + +EAPI Ecore_Event_Modifier +ecore_event_update_modifier(const char *key, Ecore_Event_Modifiers *modifiers, int inc) +{ + size_t i; + + for (i = 0; i < sizeof (matchs) / sizeof (Ecore_Event_Modifier_Match); i++) + if (strcmp(matchs[i].key, key) == 0) + { + if (modifiers && matchs[i].modifier < modifiers->size) + modifiers->array[matchs[i].modifier] += inc; + return matchs[i].modifier; + } + + return ECORE_NONE; +} diff --git a/src/lib/ecore_input/ecore_input_compose.c b/src/lib/ecore_input/ecore_input_compose.c new file mode 100644 index 0000000..5335a7f --- /dev/null +++ b/src/lib/ecore_input/ecore_input_compose.c @@ -0,0 +1,61 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "Ecore.h" +#include "ecore_private.h" + +#include "Ecore_Input.h" +#include "ecore_input_private.h" + +// some info on a big big big compose table +// http://cgit.freedesktop.org/xorg/lib/libX11/plain/nls/en_US.UTF-8/Compose.pre +// isolate compose tree into its own file - hand crafted into static const c +#include "ecore_input_compose.h" + +EAPI Ecore_Compose_State +ecore_compose_get(const Eina_List *seq, char **seqstr_ret) +{ + Comp *c, *cend; + Eina_List *l; + const char *s; + int i = 0; + + if (!seq) return ECORE_COMPOSE_NONE; + l = (Eina_List *)seq; + s = l->data; + cend = (Comp *)comp + (sizeof(comp) / sizeof(comp[0])); + for (c = (Comp *)comp; c->s && s;) + { + // doesn't match -> jump to next level entry + if (!(!strcmp(s, c->s))) + { + c += c->jump + 1; + if (c >= cend) + { + return ECORE_COMPOSE_NONE; + } + } + else + { + cend = c + c->jump; + // advance to next sequence member + l = l->next; + i++; + if (l) s = l->data; + else s = NULL; + c++; + // if advanced item jump is an endpoint - it's the string we want + if (c->jump == 0) + { + if (seqstr_ret) *seqstr_ret = strdup(c->s); + return ECORE_COMPOSE_DONE; + } + } + } + if (i == 0) return ECORE_COMPOSE_NONE; + return ECORE_COMPOSE_MIDDLE; +} diff --git a/src/lib/ecore_input/ecore_input_compose.h b/src/lib/ecore_input/ecore_input_compose.h new file mode 100644 index 0000000..9fbfb76 --- /dev/null +++ b/src/lib/ecore_input/ecore_input_compose.h @@ -0,0 +1,9895 @@ +typedef struct _Comp Comp; +struct _Comp { + const char *s; + int jump; +}; + +static const Comp comp[] = { + {"dead_breve", 124}, + {"dead_breve", 1}, + {"˘", 0}, + {"g", 1}, + {"ğ", 0}, + {"a", 1}, + {"ă", 0}, + {"Greek_IOTA", 1}, + {"Ῐ", 0}, + {"dead_grave", 4}, + {"a", 1}, + {"ằ", 0}, + {"A", 1}, + {"Ằ", 0}, + {"Greek_iota", 1}, + {"ῐ", 0}, + {"e", 1}, + {"ĕ", 0}, + {"agrave", 1}, + {"ằ", 0}, + {"o", 1}, + {"ŏ", 0}, + {"Greek_upsilon", 1}, + {"ῠ", 0}, + {"ahook", 1}, + {"ẳ", 0}, + {"dead_belowdot", 4}, + {"a", 1}, + {"ặ", 0}, + {"A", 1}, + {"Ặ", 0}, + {"space", 1}, + {"˘", 0}, + {"Cyrillic_I", 1}, + {"Й", 0}, + {"Multi_key", 15}, + {"exclam", 4}, + {"a", 1}, + {"ặ", 0}, + {"A", 1}, + {"Ặ", 0}, + {"cedilla", 4}, + {"e", 1}, + {"ḝ", 0}, + {"E", 1}, + {"Ḝ", 0}, + {"comma", 4}, + {"e", 1}, + {"ḝ", 0}, + {"E", 1}, + {"Ḝ", 0}, + {"i", 1}, + {"ĭ", 0}, + {"dead_tilde", 4}, + {"a", 1}, + {"ẵ", 0}, + {"A", 1}, + {"Ẵ", 0}, + {"Cyrillic_a", 1}, + {"ӑ", 0}, + {"Cyrillic_U", 1}, + {"Ў", 0}, + {"nobreakspace", 1}, + {"̆", 0}, + {"u", 1}, + {"ŭ", 0}, + {"G", 1}, + {"Ğ", 0}, + {"Greek_ALPHA", 1}, + {"Ᾰ", 0}, + {"atilde", 1}, + {"ẵ", 0}, + {"Cyrillic_ie", 1}, + {"ӗ", 0}, + {"E", 1}, + {"Ĕ", 0}, + {"Cyrillic_i", 1}, + {"й", 0}, + {"Atilde", 1}, + {"Ẵ", 0}, + {"Cyrillic_zhe", 1}, + {"ӂ", 0}, + {"Greek_alpha", 1}, + {"ᾰ", 0}, + {"Ahook", 1}, + {"Ẳ", 0}, + {"O", 1}, + {"Ŏ", 0}, + {"A", 1}, + {"Ă", 0}, + {"Cyrillic_A", 1}, + {"Ӑ", 0}, + {"dead_hook", 4}, + {"a", 1}, + {"ẳ", 0}, + {"A", 1}, + {"Ẳ", 0}, + {"Cyrillic_ZHE", 1}, + {"Ӂ", 0}, + {"Cyrillic_IE", 1}, + {"Ӗ", 0}, + {"Aacute", 1}, + {"Ắ", 0}, + {"dead_cedilla", 4}, + {"e", 1}, + {"ḝ", 0}, + {"E", 1}, + {"Ḝ", 0}, + {"aacute", 1}, + {"ắ", 0}, + {"dead_acute", 4}, + {"a", 1}, + {"ắ", 0}, + {"A", 1}, + {"Ắ", 0}, + {"Agrave", 1}, + {"Ằ", 0}, + {"I", 1}, + {"Ĭ", 0}, + {"U", 1}, + {"Ŭ", 0}, + {"Cyrillic_u", 1}, + {"ў", 0}, + {"Greek_UPSILON", 1}, + {"Ῠ", 0}, + {"dead_grave", 351}, + {"W", 1}, + {"Ẁ", 0}, + {"dead_breve", 4}, + {"a", 1}, + {"ằ", 0}, + {"A", 1}, + {"Ằ", 0}, + {"a", 1}, + {"à", 0}, + {"Greek_IOTA", 1}, + {"Ὶ", 0}, + {"dead_grave", 1}, + {"`", 0}, + {"dead_horn", 8}, + {"o", 1}, + {"ờ", 0}, + {"u", 1}, + {"ừ", 0}, + {"O", 1}, + {"Ờ", 0}, + {"U", 1}, + {"Ừ", 0}, + {"Greek_iota", 1}, + {"ὶ", 0}, + {"dead_circumflex", 12}, + {"a", 1}, + {"ầ", 0}, + {"e", 1}, + {"ề", 0}, + {"o", 1}, + {"ồ", 0}, + {"E", 1}, + {"Ề", 0}, + {"O", 1}, + {"Ồ", 0}, + {"A", 1}, + {"Ầ", 0}, + {"Greek_OMICRON", 1}, + {"Ὸ", 0}, + {"Acircumflex", 1}, + {"Ầ", 0}, + {"Cyrillic_er", 1}, + {"р̀", 0}, + {"e", 1}, + {"è", 0}, + {"o", 1}, + {"ò", 0}, + {"Udiaeresis", 1}, + {"Ǜ", 0}, + {"Greek_upsilon", 1}, + {"ὺ", 0}, + {"uhorn", 1}, + {"ừ", 0}, + {"space", 1}, + {"`", 0}, + {"dead_macron", 8}, + {"e", 1}, + {"ḕ", 0}, + {"o", 1}, + {"ṑ", 0}, + {"E", 1}, + {"Ḕ", 0}, + {"O", 1}, + {"Ṑ", 0}, + {"acircumflex", 1}, + {"ầ", 0}, + {"Ecircumflex", 1}, + {"Ề", 0}, + {"Cyrillic_I", 1}, + {"Ѝ", 0}, + {"y", 1}, + {"ỳ", 0}, + {"Multi_key", 115}, + {"b", 4}, + {"a", 1}, + {"ằ", 0}, + {"A", 1}, + {"Ằ", 0}, + {"parenright", 26}, + {"Greek_IOTA", 1}, + {"Ἲ", 0}, + {"Greek_iota", 1}, + {"ἲ", 0}, + {"Greek_OMICRON", 1}, + {"Ὂ", 0}, + {"Greek_upsilon", 1}, + {"ὒ", 0}, + {"Greek_epsilon", 1}, + {"ἒ", 0}, + {"Greek_ALPHA", 1}, + {"Ἂ", 0}, + {"Greek_omicron", 1}, + {"ὂ", 0}, + {"Greek_eta", 1}, + {"ἢ", 0}, + {"Greek_alpha", 1}, + {"ἂ", 0}, + {"Greek_ETA", 1}, + {"Ἢ", 0}, + {"Greek_EPSILON", 1}, + {"Ἒ", 0}, + {"Greek_omega", 1}, + {"ὢ", 0}, + {"Greek_OMEGA", 1}, + {"Ὢ", 0}, + {"quotedbl", 8}, + {"Greek_iota", 1}, + {"ῒ", 0}, + {"Greek_upsilon", 1}, + {"ῢ", 0}, + {"u", 1}, + {"ǜ", 0}, + {"U", 1}, + {"Ǜ", 0}, + {"plus", 8}, + {"o", 1}, + {"ờ", 0}, + {"u", 1}, + {"ừ", 0}, + {"O", 1}, + {"Ờ", 0}, + {"U", 1}, + {"Ừ", 0}, + {"underscore", 8}, + {"e", 1}, + {"ḕ", 0}, + {"o", 1}, + {"ṑ", 0}, + {"E", 1}, + {"Ḕ", 0}, + {"O", 1}, + {"Ṑ", 0}, + {"macron", 8}, + {"e", 1}, + {"ḕ", 0}, + {"o", 1}, + {"ṑ", 0}, + {"E", 1}, + {"Ḕ", 0}, + {"O", 1}, + {"Ṑ", 0}, + {"parenleft", 28}, + {"Greek_IOTA", 1}, + {"Ἳ", 0}, + {"Greek_iota", 1}, + {"ἳ", 0}, + {"Greek_OMICRON", 1}, + {"Ὃ", 0}, + {"Greek_upsilon", 1}, + {"ὓ", 0}, + {"Greek_epsilon", 1}, + {"ἓ", 0}, + {"Greek_ALPHA", 1}, + {"Ἃ", 0}, + {"Greek_omicron", 1}, + {"ὃ", 0}, + {"Greek_eta", 1}, + {"ἣ", 0}, + {"Greek_alpha", 1}, + {"ἃ", 0}, + {"Greek_ETA", 1}, + {"Ἣ", 0}, + {"Greek_EPSILON", 1}, + {"Ἓ", 0}, + {"Greek_omega", 1}, + {"ὣ", 0}, + {"Greek_OMEGA", 1}, + {"Ὣ", 0}, + {"Greek_UPSILON", 1}, + {"Ὓ", 0}, + {"U", 4}, + {"a", 1}, + {"ằ", 0}, + {"A", 1}, + {"Ằ", 0}, + {"asciicircum", 12}, + {"a", 1}, + {"ầ", 0}, + {"e", 1}, + {"ề", 0}, + {"o", 1}, + {"ồ", 0}, + {"E", 1}, + {"Ề", 0}, + {"O", 1}, + {"Ồ", 0}, + {"A", 1}, + {"Ầ", 0}, + {"Cyrillic_O", 1}, + {"О̀", 0}, + {"i", 1}, + {"ì", 0}, + {"n", 1}, + {"ǹ", 0}, + {"Cyrillic_a", 1}, + {"а̀", 0}, + {"Ohorn", 1}, + {"Ờ", 0}, + {"ohorn", 1}, + {"ờ", 0}, + {"Cyrillic_ER", 1}, + {"Р̀", 0}, + {"Greek_epsilon", 1}, + {"ὲ", 0}, + {"Cyrillic_U", 1}, + {"У̀", 0}, + {"nobreakspace", 1}, + {"̀", 0}, + {"V", 1}, + {"Ǜ", 0}, + {"Ocircumflex", 1}, + {"Ồ", 0}, + {"omacron", 1}, + {"ṑ", 0}, + {"ocircumflex", 1}, + {"ồ", 0}, + {"u", 1}, + {"ù", 0}, + {"Greek_ALPHA", 1}, + {"Ὰ", 0}, + {"Cyrillic_ie", 1}, + {"ѐ", 0}, + {"emacron", 1}, + {"ḕ", 0}, + {"E", 1}, + {"È", 0}, + {"Greek_iotadieresis", 1}, + {"ῒ", 0}, + {"Y", 1}, + {"Ỳ", 0}, + {"Cyrillic_i", 1}, + {"ѝ", 0}, + {"dead_dasia", 28}, + {"Greek_IOTA", 1}, + {"Ἳ", 0}, + {"Greek_iota", 1}, + {"ἳ", 0}, + {"Greek_OMICRON", 1}, + {"Ὃ", 0}, + {"Greek_upsilon", 1}, + {"ὓ", 0}, + {"Greek_epsilon", 1}, + {"ἓ", 0}, + {"Greek_ALPHA", 1}, + {"Ἃ", 0}, + {"Greek_omicron", 1}, + {"ὃ", 0}, + {"Greek_eta", 1}, + {"ἣ", 0}, + {"Greek_alpha", 1}, + {"ἃ", 0}, + {"Greek_ETA", 1}, + {"Ἣ", 0}, + {"Greek_EPSILON", 1}, + {"Ἓ", 0}, + {"Greek_omega", 1}, + {"ὣ", 0}, + {"Greek_OMEGA", 1}, + {"Ὣ", 0}, + {"Greek_UPSILON", 1}, + {"Ὓ", 0}, + {"Greek_upsilondieresis", 1}, + {"ῢ", 0}, + {"Greek_omicron", 1}, + {"ὸ", 0}, + {"Greek_eta", 1}, + {"ὴ", 0}, + {"Abreve", 1}, + {"Ằ", 0}, + {"dead_psili", 26}, + {"Greek_IOTA", 1}, + {"Ἲ", 0}, + {"Greek_iota", 1}, + {"ἲ", 0}, + {"Greek_OMICRON", 1}, + {"Ὂ", 0}, + {"Greek_upsilon", 1}, + {"ὒ", 0}, + {"Greek_epsilon", 1}, + {"ἒ", 0}, + {"Greek_ALPHA", 1}, + {"Ἂ", 0}, + {"Greek_omicron", 1}, + {"ὂ", 0}, + {"Greek_eta", 1}, + {"ἢ", 0}, + {"Greek_alpha", 1}, + {"ἂ", 0}, + {"Greek_ETA", 1}, + {"Ἢ", 0}, + {"Greek_EPSILON", 1}, + {"Ἒ", 0}, + {"Greek_omega", 1}, + {"ὢ", 0}, + {"Greek_OMEGA", 1}, + {"Ὢ", 0}, + {"Greek_alpha", 1}, + {"ὰ", 0}, + {"ecircumflex", 1}, + {"ề", 0}, + {"w", 1}, + {"ẁ", 0}, + {"Greek_ETA", 1}, + {"Ὴ", 0}, + {"Cyrillic_o", 1}, + {"о̀", 0}, + {"Emacron", 1}, + {"Ḕ", 0}, + {"v", 1}, + {"ǜ", 0}, + {"O", 1}, + {"Ò", 0}, + {"abreve", 1}, + {"ằ", 0}, + {"A", 1}, + {"À", 0}, + {"Greek_EPSILON", 1}, + {"Ὲ", 0}, + {"Cyrillic_A", 1}, + {"А̀", 0}, + {"Omacron", 1}, + {"Ṑ", 0}, + {"Cyrillic_IE", 1}, + {"Ѐ", 0}, + {"Greek_omega", 1}, + {"ὼ", 0}, + {"dead_diaeresis", 8}, + {"Greek_iota", 1}, + {"ῒ", 0}, + {"Greek_upsilon", 1}, + {"ῢ", 0}, + {"u", 1}, + {"ǜ", 0}, + {"U", 1}, + {"Ǜ", 0}, + {"Uhorn", 1}, + {"Ừ", 0}, + {"Greek_OMEGA", 1}, + {"Ὼ", 0}, + {"udiaeresis", 1}, + {"ǜ", 0}, + {"I", 1}, + {"Ì", 0}, + {"N", 1}, + {"Ǹ", 0}, + {"U", 1}, + {"Ù", 0}, + {"Cyrillic_u", 1}, + {"у̀", 0}, + {"Greek_UPSILON", 1}, + {"Ὺ", 0}, + {"dead_horn", 99}, + {"Uhook", 1}, + {"Ử", 0}, + {"Obelowdot", 1}, + {"Ợ", 0}, + {"Ograve", 1}, + {"Ờ", 0}, + {"dead_grave", 8}, + {"o", 1}, + {"ờ", 0}, + {"u", 1}, + {"ừ", 0}, + {"O", 1}, + {"Ờ", 0}, + {"U", 1}, + {"Ừ", 0}, + {"dead_horn", 1}, + {"̛", 0}, + {"Oacute", 1}, + {"Ớ", 0}, + {"ohook", 1}, + {"ở", 0}, + {"o", 1}, + {"ơ", 0}, + {"Utilde", 1}, + {"Ữ", 0}, + {"dead_belowdot", 8}, + {"o", 1}, + {"ợ", 0}, + {"u", 1}, + {"ự", 0}, + {"O", 1}, + {"Ợ", 0}, + {"U", 1}, + {"Ự", 0}, + {"space", 1}, + {"̛", 0}, + {"ubelowdot", 1}, + {"ự", 0}, + {"oacute", 1}, + {"ớ", 0}, + {"uhook", 1}, + {"ử", 0}, + {"dead_tilde", 8}, + {"o", 1}, + {"ỡ", 0}, + {"u", 1}, + {"ữ", 0}, + {"O", 1}, + {"Ỡ", 0}, + {"U", 1}, + {"Ữ", 0}, + {"Uacute", 1}, + {"Ứ", 0}, + {"Ugrave", 1}, + {"Ừ", 0}, + {"nobreakspace", 1}, + {"̛", 0}, + {"uacute", 1}, + {"ứ", 0}, + {"u", 1}, + {"ư", 0}, + {"otilde", 1}, + {"ỡ", 0}, + {"utilde", 1}, + {"ữ", 0}, + {"Otilde", 1}, + {"Ỡ", 0}, + {"ograve", 1}, + {"ờ", 0}, + {"Ohook", 1}, + {"Ở", 0}, + {"O", 1}, + {"Ơ", 0}, + {"Ubelowdot", 1}, + {"Ự", 0}, + {"dead_hook", 8}, + {"o", 1}, + {"ở", 0}, + {"u", 1}, + {"ử", 0}, + {"O", 1}, + {"Ở", 0}, + {"U", 1}, + {"Ử", 0}, + {"ugrave", 1}, + {"ừ", 0}, + {"obelowdot", 1}, + {"ợ", 0}, + {"dead_acute", 8}, + {"o", 1}, + {"ớ", 0}, + {"u", 1}, + {"ứ", 0}, + {"O", 1}, + {"Ớ", 0}, + {"U", 1}, + {"Ứ", 0}, + {"U", 1}, + {"Ư", 0}, + {"dead_circumflex", 335}, + {"minus", 1}, + {"⁻", 0}, + {"W", 1}, + {"Ŵ", 0}, + {"g", 1}, + {"ĝ", 0}, + {"a", 1}, + {"â", 0}, + {"Ograve", 1}, + {"Ồ", 0}, + {"dead_circumflex", 1}, + {"^", 0}, + {"dead_grave", 12}, + {"a", 1}, + {"ầ", 0}, + {"e", 1}, + {"ề", 0}, + {"o", 1}, + {"ồ", 0}, + {"E", 1}, + {"Ề", 0}, + {"O", 1}, + {"Ồ", 0}, + {"A", 1}, + {"Ầ", 0}, + {"Ehook", 1}, + {"Ể", 0}, + {"1", 1}, + {"¹", 0}, + {"C", 1}, + {"Ĉ", 0}, + {"KP_4", 1}, + {"⁴", 0}, + {"Oacute", 1}, + {"Ố", 0}, + {"Cyrillic_er", 1}, + {"р̂", 0}, + {"ohook", 1}, + {"ổ", 0}, + {"e", 1}, + {"ê", 0}, + {"agrave", 1}, + {"ầ", 0}, + {"KP_6", 1}, + {"⁶", 0}, + {"o", 1}, + {"ô", 0}, + {"ahook", 1}, + {"ẩ", 0}, + {"dead_belowdot", 12}, + {"a", 1}, + {"ậ", 0}, + {"e", 1}, + {"ệ", 0}, + {"o", 1}, + {"ộ", 0}, + {"E", 1}, + {"Ệ", 0}, + {"O", 1}, + {"Ộ", 0}, + {"A", 1}, + {"Ậ", 0}, + {"space", 1}, + {"^", 0}, + {"KP_8", 1}, + {"⁸", 0}, + {"Etilde", 1}, + {"Ễ", 0}, + {"Cyrillic_I", 1}, + {"И̂", 0}, + {"y", 1}, + {"ŷ", 0}, + {"Multi_key", 83}, + {"exclam", 12}, + {"a", 1}, + {"ậ", 0}, + {"e", 1}, + {"ệ", 0}, + {"o", 1}, + {"ộ", 0}, + {"E", 1}, + {"Ệ", 0}, + {"O", 1}, + {"Ộ", 0}, + {"A", 1}, + {"Ậ", 0}, + {"t", 4}, + {"M", 1}, + {"™", 0}, + {"m", 1}, + {"™", 0}, + {"underbar", 24}, + {"a", 1}, + {"ª", 0}, + {"o", 1}, + {"º", 0}, + {"l", 1}, + {"ˡ", 0}, + {"y", 1}, + {"ʸ", 0}, + {"i", 1}, + {"ⁱ", 0}, + {"n", 1}, + {"ⁿ", 0}, + {"j", 1}, + {"ʲ", 0}, + {"x", 1}, + {"ˣ", 0}, + {"w", 1}, + {"ʷ", 0}, + {"r", 1}, + {"ʳ", 0}, + {"s", 1}, + {"ˢ", 0}, + {"h", 1}, + {"ʰ", 0}, + {"S", 4}, + {"M", 1}, + {"℠", 0}, + {"m", 1}, + {"℠", 0}, + {"underscore", 24}, + {"a", 1}, + {"ª", 0}, + {"o", 1}, + {"º", 0}, + {"l", 1}, + {"ˡ", 0}, + {"y", 1}, + {"ʸ", 0}, + {"i", 1}, + {"ⁱ", 0}, + {"n", 1}, + {"ⁿ", 0}, + {"j", 1}, + {"ʲ", 0}, + {"x", 1}, + {"ˣ", 0}, + {"w", 1}, + {"ʷ", 0}, + {"r", 1}, + {"ʳ", 0}, + {"s", 1}, + {"ˢ", 0}, + {"h", 1}, + {"ʰ", 0}, + {"s", 4}, + {"M", 1}, + {"℠", 0}, + {"m", 1}, + {"℠", 0}, + {"T", 4}, + {"M", 1}, + {"™", 0}, + {"m", 1}, + {"™", 0}, + {"oacute", 1}, + {"ố", 0}, + {"Cyrillic_O", 1}, + {"О̂", 0}, + {"i", 1}, + {"î", 0}, + {"KP_9", 1}, + {"⁹", 0}, + {"equal", 1}, + {"⁼", 0}, + {"KP_Space", 1}, + {"²", 0}, + {"dead_tilde", 12}, + {"a", 1}, + {"ẫ", 0}, + {"e", 1}, + {"ễ", 0}, + {"o", 1}, + {"ỗ", 0}, + {"E", 1}, + {"Ễ", 0}, + {"O", 1}, + {"Ỗ", 0}, + {"A", 1}, + {"Ẫ", 0}, + {"7", 1}, + {"⁷", 0}, + {"Cyrillic_a", 1}, + {"а̂", 0}, + {"j", 1}, + {"ĵ", 0}, + {"parenright", 1}, + {"⁾", 0}, + {"Eacute", 1}, + {"Ế", 0}, + {"Cyrillic_ER", 1}, + {"Р̂", 0}, + {"KP_7", 1}, + {"⁷", 0}, + {"Cyrillic_U", 1}, + {"У̂", 0}, + {"nobreakspace", 1}, + {"̂", 0}, + {"u", 1}, + {"û", 0}, + {"z", 1}, + {"ẑ", 0}, + {"G", 1}, + {"Ĝ", 0}, + {"otilde", 1}, + {"ỗ", 0}, + {"H", 1}, + {"Ĥ", 0}, + {"8", 1}, + {"⁸", 0}, + {"KP_1", 1}, + {"¹", 0}, + {"atilde", 1}, + {"ẫ", 0}, + {"3", 1}, + {"³", 0}, + {"Cyrillic_ie", 1}, + {"е̂", 0}, + {"E", 1}, + {"Ê", 0}, + {"S", 1}, + {"Ŝ", 0}, + {"2", 1}, + {"²", 0}, + {"Y", 1}, + {"Ŷ", 0}, + {"Cyrillic_i", 1}, + {"и̂", 0}, + {"Otilde", 1}, + {"Ỗ", 0}, + {"Atilde", 1}, + {"Ẫ", 0}, + {"egrave", 1}, + {"ề", 0}, + {"ograve", 1}, + {"ồ", 0}, + {"plus", 1}, + {"⁺", 0}, + {"6", 1}, + {"⁶", 0}, + {"Ahook", 1}, + {"Ẩ", 0}, + {"w", 1}, + {"ŵ", 0}, + {"Ohook", 1}, + {"Ổ", 0}, + {"Cyrillic_o", 1}, + {"о̂", 0}, + {"4", 1}, + {"⁴", 0}, + {"KP_3", 1}, + {"³", 0}, + {"eacute", 1}, + {"ế", 0}, + {"J", 1}, + {"Ĵ", 0}, + {"O", 1}, + {"Ô", 0}, + {"s", 1}, + {"ŝ", 0}, + {"Z", 1}, + {"Ẑ", 0}, + {"KP_0", 1}, + {"⁰", 0}, + {"A", 1}, + {"Â", 0}, + {"c", 1}, + {"ĉ", 0}, + {"KP_Add", 1}, + {"⁺", 0}, + {"KP_2", 1}, + {"²", 0}, + {"Cyrillic_A", 1}, + {"А̂", 0}, + {"dead_hook", 12}, + {"a", 1}, + {"ẩ", 0}, + {"e", 1}, + {"ể", 0}, + {"o", 1}, + {"ổ", 0}, + {"E", 1}, + {"Ể", 0}, + {"O", 1}, + {"Ổ", 0}, + {"A", 1}, + {"Ẩ", 0}, + {"5", 1}, + {"⁵", 0}, + {"KP_5", 1}, + {"⁵", 0}, + {"9", 1}, + {"⁹", 0}, + {"Cyrillic_IE", 1}, + {"Е̂", 0}, + {"Egrave", 1}, + {"Ề", 0}, + {"0", 1}, + {"⁰", 0}, + {"Aacute", 1}, + {"Ấ", 0}, + {"etilde", 1}, + {"ễ", 0}, + {"aacute", 1}, + {"ấ", 0}, + {"dead_acute", 12}, + {"a", 1}, + {"ấ", 0}, + {"e", 1}, + {"ế", 0}, + {"o", 1}, + {"ố", 0}, + {"E", 1}, + {"Ế", 0}, + {"O", 1}, + {"Ố", 0}, + {"A", 1}, + {"Ấ", 0}, + {"Agrave", 1}, + {"Ầ", 0}, + {"parenleft", 1}, + {"⁽", 0}, + {"h", 1}, + {"ĥ", 0}, + {"I", 1}, + {"Î", 0}, + {"ehook", 1}, + {"ể", 0}, + {"U", 1}, + {"Û", 0}, + {"Cyrillic_u", 1}, + {"у̂", 0}, + {"KP_Equal", 1}, + {"⁼", 0}, + {"dead_currency", 103}, + {"W", 1}, + {"₩", 0}, + {"g", 1}, + {"₲", 0}, + {"a", 1}, + {"؋", 0}, + {"dead_currency", 1}, + {"¤", 0}, + {"C", 1}, + {"₡", 0}, + {"e", 1}, + {"€", 0}, + {"F", 1}, + {"₣", 0}, + {"o", 1}, + {"௹", 0}, + {"l", 1}, + {"£", 0}, + {"t", 1}, + {"৳", 0}, + {"thorn", 1}, + {"৲", 0}, + {"space", 1}, + {"¤", 0}, + {"y", 1}, + {"¥", 0}, + {"b", 1}, + {"฿", 0}, + {"i", 1}, + {"﷼", 0}, + {"k", 1}, + {"₭", 0}, + {"n", 1}, + {"₦", 0}, + {"ccedilla", 1}, + {"₵", 0}, + {"nobreakspace", 1}, + {"¤", 0}, + {"u", 1}, + {"元", 0}, + {"G", 1}, + {"₲", 0}, + {"H", 1}, + {"₴", 0}, + {"E", 1}, + {"₠", 0}, + {"S", 1}, + {"$", 0}, + {"Y", 1}, + {"円", 0}, + {"f", 1}, + {"ƒ", 0}, + {"d", 1}, + {"₫", 0}, + {"D", 1}, + {"₯", 0}, + {"w", 1}, + {"₩", 0}, + {"p", 1}, + {"₰", 0}, + {"P", 1}, + {"₧", 0}, + {"M", 1}, + {"ℳ", 0}, + {"O", 1}, + {"૱", 0}, + {"m", 1}, + {"₥", 0}, + {"r", 1}, + {"₢", 0}, + {"s", 1}, + {"₪", 0}, + {"A", 1}, + {"₳", 0}, + {"R", 1}, + {"₨", 0}, + {"THORN", 1}, + {"৲", 0}, + {"c", 1}, + {"¢", 0}, + {"L", 1}, + {"₤", 0}, + {"T", 1}, + {"₮", 0}, + {"Ccedilla", 1}, + {"₵", 0}, + {"K", 1}, + {"₭", 0}, + {"B", 1}, + {"₱", 0}, + {"dead_cedilla", 4}, + {"C", 1}, + {"₵", 0}, + {"c", 1}, + {"₵", 0}, + {"h", 1}, + {"₴", 0}, + {"I", 1}, + {"៛", 0}, + {"N", 1}, + {"₦", 0}, + {"U", 1}, + {"圓", 0}, + {"dead_belowdiaeresis", 7}, + {"u", 1}, + {"ṳ", 0}, + {"dead_diaeresis", 2}, + {"equal", 1}, + {"⩷", 0}, + {"U", 1}, + {"Ṳ", 0}, + {"dead_belowdot", 167}, + {"minus", 1}, + {"⨪", 0}, + {"W", 1}, + {"Ẉ", 0}, + {"dead_breve", 4}, + {"a", 1}, + {"ặ", 0}, + {"A", 1}, + {"Ặ", 0}, + {"a", 1}, + {"ạ", 0}, + {"dead_circumflex", 12}, + {"a", 1}, + {"ậ", 0}, + {"e", 1}, + {"ệ", 0}, + {"o", 1}, + {"ộ", 0}, + {"E", 1}, + {"Ệ", 0}, + {"O", 1}, + {"Ộ", 0}, + {"A", 1}, + {"Ậ", 0}, + {"dead_horn", 8}, + {"o", 1}, + {"ợ", 0}, + {"u", 1}, + {"ự", 0}, + {"O", 1}, + {"Ợ", 0}, + {"U", 1}, + {"Ự", 0}, + {"Acircumflex", 1}, + {"Ậ", 0}, + {"e", 1}, + {"ẹ", 0}, + {"o", 1}, + {"ọ", 0}, + {"l", 1}, + {"ḷ", 0}, + {"t", 1}, + {"ṭ", 0}, + {"dead_belowdot", 1}, + {"̣", 0}, + {"uhorn", 1}, + {"ự", 0}, + {"space", 1}, + {"̣", 0}, + {"dead_macron", 8}, + {"l", 1}, + {"ḹ", 0}, + {"r", 1}, + {"ṝ", 0}, + {"R", 1}, + {"Ṝ", 0}, + {"L", 1}, + {"Ḹ", 0}, + {"acircumflex", 1}, + {"ậ", 0}, + {"Ecircumflex", 1}, + {"Ệ", 0}, + {"y", 1}, + {"ỵ", 0}, + {"b", 1}, + {"ḅ", 0}, + {"Multi_key", 9}, + {"plus", 8}, + {"o", 1}, + {"ợ", 0}, + {"u", 1}, + {"ự", 0}, + {"O", 1}, + {"Ợ", 0}, + {"U", 1}, + {"Ự", 0}, + {"i", 1}, + {"ị", 0}, + {"k", 1}, + {"ḳ", 0}, + {"n", 1}, + {"ṇ", 0}, + {"equal", 1}, + {"⩦", 0}, + {"Ohorn", 1}, + {"Ợ", 0}, + {"ohorn", 1}, + {"ợ", 0}, + {"sabovedot", 1}, + {"ṩ", 0}, + {"nobreakspace", 1}, + {"̣", 0}, + {"V", 1}, + {"Ṿ", 0}, + {"Ocircumflex", 1}, + {"Ộ", 0}, + {"ocircumflex", 1}, + {"ộ", 0}, + {"u", 1}, + {"ụ", 0}, + {"z", 1}, + {"ẓ", 0}, + {"H", 1}, + {"Ḥ", 0}, + {"E", 1}, + {"Ẹ", 0}, + {"S", 1}, + {"Ṣ", 0}, + {"Y", 1}, + {"Ỵ", 0}, + {"d", 1}, + {"ḍ", 0}, + {"D", 1}, + {"Ḍ", 0}, + {"Abreve", 1}, + {"Ặ", 0}, + {"plus", 1}, + {"⨥", 0}, + {"ecircumflex", 1}, + {"ệ", 0}, + {"dead_abovedot", 4}, + {"S", 1}, + {"Ṩ", 0}, + {"s", 1}, + {"ṩ", 0}, + {"w", 1}, + {"ẉ", 0}, + {"v", 1}, + {"ṿ", 0}, + {"M", 1}, + {"Ṃ", 0}, + {"O", 1}, + {"Ọ", 0}, + {"abreve", 1}, + {"ặ", 0}, + {"m", 1}, + {"ṃ", 0}, + {"r", 1}, + {"ṛ", 0}, + {"s", 1}, + {"ṣ", 0}, + {"Z", 1}, + {"Ẓ", 0}, + {"A", 1}, + {"Ạ", 0}, + {"R", 1}, + {"Ṛ", 0}, + {"L", 1}, + {"Ḷ", 0}, + {"T", 1}, + {"Ṭ", 0}, + {"K", 1}, + {"Ḳ", 0}, + {"B", 1}, + {"Ḅ", 0}, + {"Sabovedot", 1}, + {"Ṩ", 0}, + {"Uhorn", 1}, + {"Ự", 0}, + {"h", 1}, + {"ḥ", 0}, + {"I", 1}, + {"Ị", 0}, + {"N", 1}, + {"Ṇ", 0}, + {"U", 1}, + {"Ụ", 0}, + {"dead_macron", 224}, + {"adiaeresis", 1}, + {"ǟ", 0}, + {"g", 1}, + {"ḡ", 0}, + {"a", 1}, + {"ā", 0}, + {"Greek_IOTA", 1}, + {"Ῑ", 0}, + {"Ograve", 1}, + {"Ṑ", 0}, + {"dead_grave", 8}, + {"e", 1}, + {"ḕ", 0}, + {"o", 1}, + {"ṑ", 0}, + {"E", 1}, + {"Ḕ", 0}, + {"O", 1}, + {"Ṑ", 0}, + {"Greek_iota", 1}, + {"ῑ", 0}, + {"Oacute", 1}, + {"Ṓ", 0}, + {"Cyrillic_er", 1}, + {"р̄", 0}, + {"e", 1}, + {"ē", 0}, + {"o", 1}, + {"ō", 0}, + {"Udiaeresis", 1}, + {"Ǖ", 0}, + {"Greek_upsilon", 1}, + {"ῡ", 0}, + {"dead_belowdot", 8}, + {"l", 1}, + {"ḹ", 0}, + {"r", 1}, + {"ṝ", 0}, + {"R", 1}, + {"Ṝ", 0}, + {"L", 1}, + {"Ḹ", 0}, + {"space", 1}, + {"¯", 0}, + {"dead_macron", 1}, + {"¯", 0}, + {"Cyrillic_I", 1}, + {"Ӣ", 0}, + {"y", 1}, + {"ȳ", 0}, + {"Multi_key", 41}, + {"period", 8}, + {"a", 1}, + {"ǡ", 0}, + {"o", 1}, + {"ȱ", 0}, + {"O", 1}, + {"Ȱ", 0}, + {"A", 1}, + {"Ǡ", 0}, + {"exclam", 8}, + {"l", 1}, + {"ḹ", 0}, + {"r", 1}, + {"ṝ", 0}, + {"R", 1}, + {"Ṝ", 0}, + {"L", 1}, + {"Ḹ", 0}, + {"quotedbl", 12}, + {"a", 1}, + {"ǟ", 0}, + {"o", 1}, + {"ȫ", 0}, + {"u", 1}, + {"ǖ", 0}, + {"O", 1}, + {"Ȫ", 0}, + {"A", 1}, + {"Ǟ", 0}, + {"U", 1}, + {"Ǖ", 0}, + {"asciitilde", 4}, + {"o", 1}, + {"ȭ", 0}, + {"O", 1}, + {"Ȭ", 0}, + {"semicolon", 4}, + {"o", 1}, + {"ǭ", 0}, + {"O", 1}, + {"Ǭ", 0}, + {"oacute", 1}, + {"ṓ", 0}, + {"Cyrillic_O", 1}, + {"О̄", 0}, + {"i", 1}, + {"ī", 0}, + {"dead_tilde", 4}, + {"o", 1}, + {"ȭ", 0}, + {"O", 1}, + {"Ȭ", 0}, + {"Cyrillic_a", 1}, + {"а̄", 0}, + {"Eacute", 1}, + {"Ḗ", 0}, + {"Cyrillic_ER", 1}, + {"Р̄", 0}, + {"Cyrillic_U", 1}, + {"Ӯ", 0}, + {"nobreakspace", 1}, + {"̄", 0}, + {"V", 1}, + {"Ǖ", 0}, + {"AE", 1}, + {"Ǣ", 0}, + {"u", 1}, + {"ū", 0}, + {"G", 1}, + {"Ḡ", 0}, + {"Greek_ALPHA", 1}, + {"Ᾱ", 0}, + {"otilde", 1}, + {"ȭ", 0}, + {"Cyrillic_ie", 1}, + {"е̄", 0}, + {"E", 1}, + {"Ē", 0}, + {"Y", 1}, + {"Ȳ", 0}, + {"Cyrillic_i", 1}, + {"ӣ", 0}, + {"dead_ogonek", 4}, + {"o", 1}, + {"ǭ", 0}, + {"O", 1}, + {"Ǭ", 0}, + {"odiaeresis", 1}, + {"ȫ", 0}, + {"Otilde", 1}, + {"Ȭ", 0}, + {"egrave", 1}, + {"ḕ", 0}, + {"dead_greek", 12}, + {"a", 1}, + {"ᾱ", 0}, + {"i", 1}, + {"ῑ", 0}, + {"u", 1}, + {"ῡ", 0}, + {"A", 1}, + {"Ᾱ", 0}, + {"I", 1}, + {"Ῑ", 0}, + {"U", 1}, + {"Ῡ", 0}, + {"ograve", 1}, + {"ṑ", 0}, + {"Greek_alpha", 1}, + {"ᾱ", 0}, + {"dead_abovedot", 8}, + {"a", 1}, + {"ǡ", 0}, + {"o", 1}, + {"ȱ", 0}, + {"O", 1}, + {"Ȱ", 0}, + {"A", 1}, + {"Ǡ", 0}, + {"Cyrillic_o", 1}, + {"о̄", 0}, + {"eacute", 1}, + {"ḗ", 0}, + {"v", 1}, + {"ǖ", 0}, + {"O", 1}, + {"Ō", 0}, + {"A", 1}, + {"Ā", 0}, + {"Odiaeresis", 1}, + {"Ȫ", 0}, + {"Cyrillic_A", 1}, + {"А̄", 0}, + {"Cyrillic_IE", 1}, + {"Е̄", 0}, + {"Egrave", 1}, + {"Ḕ", 0}, + {"dead_diaeresis", 12}, + {"a", 1}, + {"ǟ", 0}, + {"o", 1}, + {"ȫ", 0}, + {"u", 1}, + {"ǖ", 0}, + {"O", 1}, + {"Ȫ", 0}, + {"A", 1}, + {"Ǟ", 0}, + {"U", 1}, + {"Ǖ", 0}, + {"Adiaeresis", 1}, + {"Ǟ", 0}, + {"dead_acute", 8}, + {"e", 1}, + {"ḗ", 0}, + {"o", 1}, + {"ṓ", 0}, + {"E", 1}, + {"Ḗ", 0}, + {"O", 1}, + {"Ṓ", 0}, + {"udiaeresis", 1}, + {"ǖ", 0}, + {"I", 1}, + {"Ī", 0}, + {"U", 1}, + {"Ū", 0}, + {"Cyrillic_u", 1}, + {"ӯ", 0}, + {"ae", 1}, + {"ǣ", 0}, + {"Greek_UPSILON", 1}, + {"Ῡ", 0}, + {"dead_doublegrave", 24}, + {"Cyrillic_er", 1}, + {"р̏", 0}, + {"Cyrillic_I", 1}, + {"И̏", 0}, + {"Cyrillic_O", 1}, + {"О̏", 0}, + {"Cyrillic_a", 1}, + {"а̏", 0}, + {"Cyrillic_ER", 1}, + {"Р̏", 0}, + {"Cyrillic_U", 1}, + {"У̏", 0}, + {"Cyrillic_ie", 1}, + {"е̏", 0}, + {"Cyrillic_i", 1}, + {"и̏", 0}, + {"Cyrillic_o", 1}, + {"о̏", 0}, + {"Cyrillic_A", 1}, + {"А̏", 0}, + {"Cyrillic_IE", 1}, + {"Е̏", 0}, + {"Cyrillic_u", 1}, + {"у̏", 0}, + {"Multi_key", 5833}, + {"backslash", 5}, + {"minus", 1}, + {"⍀", 0}, + {"o", 2}, + {"slash", 1}, + {"🙌", 0}, + {"minus", 59}, + {"backslash", 1}, + {"⍀", 0}, + {"minus", 6}, + {"minus", 1}, + {"—", 0}, + {"period", 1}, + {"–", 0}, + {"space", 1}, + {"­", 0}, + {"a", 1}, + {"ā", 0}, + {"e", 1}, + {"ē", 0}, + {"o", 1}, + {"ō", 0}, + {"l", 1}, + {"£", 0}, + {"space", 1}, + {"~", 0}, + {"y", 1}, + {"¥", 0}, + {"i", 1}, + {"ī", 0}, + {"parenright", 1}, + {"}", 0}, + {"u", 1}, + {"ū", 0}, + {"E", 1}, + {"Ē", 0}, + {"Y", 1}, + {"¥", 0}, + {"d", 1}, + {"đ", 0}, + {"D", 1}, + {"Đ", 0}, + {"plus", 1}, + {"±", 0}, + {"colon", 1}, + {"÷", 0}, + {"O", 1}, + {"Ō", 0}, + {"A", 1}, + {"Ā", 0}, + {"L", 1}, + {"£", 0}, + {"comma", 1}, + {"¬", 0}, + {"slash", 1}, + {"⌿", 0}, + {"greater", 1}, + {"→", 0}, + {"parenleft", 1}, + {"{", 0}, + {"I", 1}, + {"Ī", 0}, + {"U", 1}, + {"Ū", 0}, + {"asciicircum", 1}, + {"¯", 0}, + {"period", 130}, + {"minus", 1}, + {"·", 0}, + {"period", 1}, + {"…", 0}, + {"W", 1}, + {"Ẇ", 0}, + {"g", 1}, + {"ġ", 0}, + {"a", 1}, + {"ȧ", 0}, + {"C", 1}, + {"Ċ", 0}, + {"exclam", 4}, + {"S", 1}, + {"Ṩ", 0}, + {"s", 1}, + {"ṩ", 0}, + {"less", 1}, + {"‹", 0}, + {"e", 1}, + {"ė", 0}, + {"F", 1}, + {"Ḟ", 0}, + {"o", 1}, + {"ȯ", 0}, + {"t", 1}, + {"ṫ", 0}, + {"dead_belowdot", 4}, + {"S", 1}, + {"Ṩ", 0}, + {"s", 1}, + {"ṩ", 0}, + {"y", 1}, + {"ẏ", 0}, + {"b", 1}, + {"ḃ", 0}, + {"i", 1}, + {"ı", 0}, + {"n", 1}, + {"ṅ", 0}, + {"equal", 1}, + {"•", 0}, + {"dead_caron", 4}, + {"S", 1}, + {"Ṧ", 0}, + {"s", 1}, + {"ṧ", 0}, + {"x", 1}, + {"ẋ", 0}, + {"z", 1}, + {"ż", 0}, + {"G", 1}, + {"Ġ", 0}, + {"Sacute", 1}, + {"Ṥ", 0}, + {"H", 1}, + {"Ḣ", 0}, + {"E", 1}, + {"Ė", 0}, + {"S", 1}, + {"Ṡ", 0}, + {"Y", 1}, + {"Ẏ", 0}, + {"scaron", 1}, + {"ṧ", 0}, + {"f", 1}, + {"ḟ", 0}, + {"d", 1}, + {"ḋ", 0}, + {"Scaron", 1}, + {"Ṧ", 0}, + {"D", 1}, + {"Ḋ", 0}, + {"acute", 4}, + {"S", 1}, + {"Ṥ", 0}, + {"s", 1}, + {"ṥ", 0}, + {"w", 1}, + {"ẇ", 0}, + {"p", 1}, + {"ṗ", 0}, + {"P", 1}, + {"Ṗ", 0}, + {"apostrophe", 4}, + {"S", 1}, + {"Ṥ", 0}, + {"s", 1}, + {"ṥ", 0}, + {"M", 1}, + {"Ṁ", 0}, + {"O", 1}, + {"Ȯ", 0}, + {"m", 1}, + {"ṁ", 0}, + {"r", 1}, + {"ṙ", 0}, + {"s", 1}, + {"ṡ", 0}, + {"Z", 1}, + {"Ż", 0}, + {"sacute", 1}, + {"ṥ", 0}, + {"A", 1}, + {"Ȧ", 0}, + {"R", 1}, + {"Ṙ", 0}, + {"c", 1}, + {"ċ", 0}, + {"T", 1}, + {"Ṫ", 0}, + {"greater", 1}, + {"›", 0}, + {"B", 1}, + {"Ḃ", 0}, + {"dead_acute", 4}, + {"S", 1}, + {"Ṥ", 0}, + {"s", 1}, + {"ṥ", 0}, + {"X", 1}, + {"Ẋ", 0}, + {"h", 1}, + {"ḣ", 0}, + {"I", 1}, + {"İ", 0}, + {"N", 1}, + {"Ṅ", 0}, + {"asciicircum", 1}, + {"·", 0}, + {"W", 4}, + {"equal", 1}, + {"₩", 0}, + {"asciicircum", 1}, + {"Ŵ", 0}, + {"g", 10}, + {"period", 1}, + {"ġ", 0}, + {"breve", 1}, + {"ğ", 0}, + {"comma", 1}, + {"ģ", 0}, + {"parenleft", 1}, + {"ğ", 0}, + {"U", 1}, + {"ğ", 0}, + {"a", 30}, + {"minus", 1}, + {"ā", 0}, + {"a", 1}, + {"å", 0}, + {"e", 1}, + {"æ", 0}, + {"diaeresis", 1}, + {"ä", 0}, + {"quotedbl", 1}, + {"ä", 0}, + {"acute", 1}, + {"á", 0}, + {"underscore", 1}, + {"ā", 0}, + {"apostrophe", 1}, + {"á", 0}, + {"asterisk", 1}, + {"å", 0}, + {"comma", 1}, + {"ą", 0}, + {"asciitilde", 1}, + {"ã", 0}, + {"greater", 1}, + {"â", 0}, + {"parenleft", 1}, + {"ă", 0}, + {"grave", 1}, + {"à", 0}, + {"asciicircum", 1}, + {"â", 0}, + {"Greek_IOTA", 4}, + {"quotedbl", 1}, + {"Ϊ", 0}, + {"apostrophe", 1}, + {"Ί", 0}, + {"Greek_iota", 485}, + {"dead_grave", 58}, + {"parenright", 12}, + {"Greek_ALPHA", 1}, + {"ᾊ", 0}, + {"Greek_eta", 1}, + {"ᾒ", 0}, + {"Greek_alpha", 1}, + {"ᾂ", 0}, + {"Greek_ETA", 1}, + {"ᾚ", 0}, + {"Greek_omega", 1}, + {"ᾢ", 0}, + {"Greek_OMEGA", 1}, + {"ᾪ", 0}, + {"dead_dasia", 12}, + {"Greek_ALPHA", 1}, + {"ᾋ", 0}, + {"Greek_eta", 1}, + {"ᾓ", 0}, + {"Greek_alpha", 1}, + {"ᾃ", 0}, + {"Greek_ETA", 1}, + {"ᾛ", 0}, + {"Greek_omega", 1}, + {"ᾣ", 0}, + {"Greek_OMEGA", 1}, + {"ᾫ", 0}, + {"Greek_eta", 1}, + {"ῂ", 0}, + {"dead_psili", 12}, + {"Greek_ALPHA", 1}, + {"ᾊ", 0}, + {"Greek_eta", 1}, + {"ᾒ", 0}, + {"Greek_alpha", 1}, + {"ᾂ", 0}, + {"Greek_ETA", 1}, + {"ᾚ", 0}, + {"Greek_omega", 1}, + {"ᾢ", 0}, + {"Greek_OMEGA", 1}, + {"ᾪ", 0}, + {"Greek_alpha", 1}, + {"ᾲ", 0}, + {"Greek_omega", 1}, + {"ῲ", 0}, + {"parenleft", 12}, + {"Greek_ALPHA", 1}, + {"ᾋ", 0}, + {"Greek_eta", 1}, + {"ᾓ", 0}, + {"Greek_alpha", 1}, + {"ᾃ", 0}, + {"Greek_ETA", 1}, + {"ᾛ", 0}, + {"Greek_omega", 1}, + {"ᾣ", 0}, + {"Greek_OMEGA", 1}, + {"ᾫ", 0}, + {"dead_tilde", 58}, + {"parenright", 12}, + {"Greek_ALPHA", 1}, + {"ᾎ", 0}, + {"Greek_eta", 1}, + {"ᾖ", 0}, + {"Greek_alpha", 1}, + {"ᾆ", 0}, + {"Greek_ETA", 1}, + {"ᾞ", 0}, + {"Greek_omega", 1}, + {"ᾦ", 0}, + {"Greek_OMEGA", 1}, + {"ᾮ", 0}, + {"dead_dasia", 12}, + {"Greek_ALPHA", 1}, + {"ᾏ", 0}, + {"Greek_eta", 1}, + {"ᾗ", 0}, + {"Greek_alpha", 1}, + {"ᾇ", 0}, + {"Greek_ETA", 1}, + {"ᾟ", 0}, + {"Greek_omega", 1}, + {"ᾧ", 0}, + {"Greek_OMEGA", 1}, + {"ᾯ", 0}, + {"Greek_eta", 1}, + {"ῇ", 0}, + {"dead_psili", 12}, + {"Greek_ALPHA", 1}, + {"ᾎ", 0}, + {"Greek_eta", 1}, + {"ᾖ", 0}, + {"Greek_alpha", 1}, + {"ᾆ", 0}, + {"Greek_ETA", 1}, + {"ᾞ", 0}, + {"Greek_omega", 1}, + {"ᾦ", 0}, + {"Greek_OMEGA", 1}, + {"ᾮ", 0}, + {"Greek_alpha", 1}, + {"ᾷ", 0}, + {"Greek_omega", 1}, + {"ῷ", 0}, + {"parenleft", 12}, + {"Greek_ALPHA", 1}, + {"ᾏ", 0}, + {"Greek_eta", 1}, + {"ᾗ", 0}, + {"Greek_alpha", 1}, + {"ᾇ", 0}, + {"Greek_ETA", 1}, + {"ᾟ", 0}, + {"Greek_omega", 1}, + {"ᾧ", 0}, + {"Greek_OMEGA", 1}, + {"ᾯ", 0}, + {"parenright", 12}, + {"Greek_ALPHA", 1}, + {"ᾈ", 0}, + {"Greek_eta", 1}, + {"ᾐ", 0}, + {"Greek_alpha", 1}, + {"ᾀ", 0}, + {"Greek_ETA", 1}, + {"ᾘ", 0}, + {"Greek_omega", 1}, + {"ᾠ", 0}, + {"Greek_OMEGA", 1}, + {"ᾨ", 0}, + {"Greek_ALPHA", 1}, + {"ᾼ", 0}, + {"dead_dasia", 12}, + {"Greek_ALPHA", 1}, + {"ᾉ", 0}, + {"Greek_eta", 1}, + {"ᾑ", 0}, + {"Greek_alpha", 1}, + {"ᾁ", 0}, + {"Greek_ETA", 1}, + {"ᾙ", 0}, + {"Greek_omega", 1}, + {"ᾡ", 0}, + {"Greek_OMEGA", 1}, + {"ᾩ", 0}, + {"Greek_eta", 1}, + {"ῃ", 0}, + {"dead_psili", 12}, + {"Greek_ALPHA", 1}, + {"ᾈ", 0}, + {"Greek_eta", 1}, + {"ᾐ", 0}, + {"Greek_alpha", 1}, + {"ᾀ", 0}, + {"Greek_ETA", 1}, + {"ᾘ", 0}, + {"Greek_omega", 1}, + {"ᾠ", 0}, + {"Greek_OMEGA", 1}, + {"ᾨ", 0}, + {"quotedbl", 1}, + {"ϊ", 0}, + {"Greek_alpha", 1}, + {"ᾳ", 0}, + {"acute", 58}, + {"parenright", 12}, + {"Greek_ALPHA", 1}, + {"ᾌ", 0}, + {"Greek_eta", 1}, + {"ᾔ", 0}, + {"Greek_alpha", 1}, + {"ᾄ", 0}, + {"Greek_ETA", 1}, + {"ᾜ", 0}, + {"Greek_omega", 1}, + {"ᾤ", 0}, + {"Greek_OMEGA", 1}, + {"ᾬ", 0}, + {"dead_dasia", 12}, + {"Greek_ALPHA", 1}, + {"ᾍ", 0}, + {"Greek_eta", 1}, + {"ᾕ", 0}, + {"Greek_alpha", 1}, + {"ᾅ", 0}, + {"Greek_ETA", 1}, + {"ᾝ", 0}, + {"Greek_omega", 1}, + {"ᾥ", 0}, + {"Greek_OMEGA", 1}, + {"ᾭ", 0}, + {"Greek_eta", 1}, + {"ῄ", 0}, + {"dead_psili", 12}, + {"Greek_ALPHA", 1}, + {"ᾌ", 0}, + {"Greek_eta", 1}, + {"ᾔ", 0}, + {"Greek_alpha", 1}, + {"ᾄ", 0}, + {"Greek_ETA", 1}, + {"ᾜ", 0}, + {"Greek_omega", 1}, + {"ᾤ", 0}, + {"Greek_OMEGA", 1}, + {"ᾬ", 0}, + {"Greek_alpha", 1}, + {"ᾴ", 0}, + {"Greek_omega", 1}, + {"ῴ", 0}, + {"parenleft", 12}, + {"Greek_ALPHA", 1}, + {"ᾍ", 0}, + {"Greek_eta", 1}, + {"ᾕ", 0}, + {"Greek_alpha", 1}, + {"ᾅ", 0}, + {"Greek_ETA", 1}, + {"ᾝ", 0}, + {"Greek_omega", 1}, + {"ᾥ", 0}, + {"Greek_OMEGA", 1}, + {"ᾭ", 0}, + {"Greek_ETA", 1}, + {"ῌ", 0}, + {"apostrophe", 58}, + {"parenright", 12}, + {"Greek_ALPHA", 1}, + {"ᾌ", 0}, + {"Greek_eta", 1}, + {"ᾔ", 0}, + {"Greek_alpha", 1}, + {"ᾄ", 0}, + {"Greek_ETA", 1}, + {"ᾜ", 0}, + {"Greek_omega", 1}, + {"ᾤ", 0}, + {"Greek_OMEGA", 1}, + {"ᾬ", 0}, + {"dead_dasia", 12}, + {"Greek_ALPHA", 1}, + {"ᾍ", 0}, + {"Greek_eta", 1}, + {"ᾕ", 0}, + {"Greek_alpha", 1}, + {"ᾅ", 0}, + {"Greek_ETA", 1}, + {"ᾝ", 0}, + {"Greek_omega", 1}, + {"ᾥ", 0}, + {"Greek_OMEGA", 1}, + {"ᾭ", 0}, + {"Greek_eta", 1}, + {"ῄ", 0}, + {"dead_psili", 12}, + {"Greek_ALPHA", 1}, + {"ᾌ", 0}, + {"Greek_eta", 1}, + {"ᾔ", 0}, + {"Greek_alpha", 1}, + {"ᾄ", 0}, + {"Greek_ETA", 1}, + {"ᾜ", 0}, + {"Greek_omega", 1}, + {"ᾤ", 0}, + {"Greek_OMEGA", 1}, + {"ᾬ", 0}, + {"Greek_alpha", 1}, + {"ᾴ", 0}, + {"Greek_omega", 1}, + {"ῴ", 0}, + {"parenleft", 12}, + {"Greek_ALPHA", 1}, + {"ᾍ", 0}, + {"Greek_eta", 1}, + {"ᾕ", 0}, + {"Greek_alpha", 1}, + {"ᾅ", 0}, + {"Greek_ETA", 1}, + {"ᾝ", 0}, + {"Greek_omega", 1}, + {"ᾥ", 0}, + {"Greek_OMEGA", 1}, + {"ᾭ", 0}, + {"Greek_omegaaccent", 1}, + {"ῴ", 0}, + {"asciitilde", 58}, + {"parenright", 12}, + {"Greek_ALPHA", 1}, + {"ᾎ", 0}, + {"Greek_eta", 1}, + {"ᾖ", 0}, + {"Greek_alpha", 1}, + {"ᾆ", 0}, + {"Greek_ETA", 1}, + {"ᾞ", 0}, + {"Greek_omega", 1}, + {"ᾦ", 0}, + {"Greek_OMEGA", 1}, + {"ᾮ", 0}, + {"dead_dasia", 12}, + {"Greek_ALPHA", 1}, + {"ᾏ", 0}, + {"Greek_eta", 1}, + {"ᾗ", 0}, + {"Greek_alpha", 1}, + {"ᾇ", 0}, + {"Greek_ETA", 1}, + {"ᾟ", 0}, + {"Greek_omega", 1}, + {"ᾧ", 0}, + {"Greek_OMEGA", 1}, + {"ᾯ", 0}, + {"Greek_eta", 1}, + {"ῇ", 0}, + {"dead_psili", 12}, + {"Greek_ALPHA", 1}, + {"ᾎ", 0}, + {"Greek_eta", 1}, + {"ᾖ", 0}, + {"Greek_alpha", 1}, + {"ᾆ", 0}, + {"Greek_ETA", 1}, + {"ᾞ", 0}, + {"Greek_omega", 1}, + {"ᾦ", 0}, + {"Greek_OMEGA", 1}, + {"ᾮ", 0}, + {"Greek_alpha", 1}, + {"ᾷ", 0}, + {"Greek_omega", 1}, + {"ῷ", 0}, + {"parenleft", 12}, + {"Greek_ALPHA", 1}, + {"ᾏ", 0}, + {"Greek_eta", 1}, + {"ᾗ", 0}, + {"Greek_alpha", 1}, + {"ᾇ", 0}, + {"Greek_ETA", 1}, + {"ᾟ", 0}, + {"Greek_omega", 1}, + {"ᾧ", 0}, + {"Greek_OMEGA", 1}, + {"ᾯ", 0}, + {"Greek_omega", 1}, + {"ῳ", 0}, + {"Greek_OMEGA", 1}, + {"ῼ", 0}, + {"dead_acute", 58}, + {"parenright", 12}, + {"Greek_ALPHA", 1}, + {"ᾌ", 0}, + {"Greek_eta", 1}, + {"ᾔ", 0}, + {"Greek_alpha", 1}, + {"ᾄ", 0}, + {"Greek_ETA", 1}, + {"ᾜ", 0}, + {"Greek_omega", 1}, + {"ᾤ", 0}, + {"Greek_OMEGA", 1}, + {"ᾬ", 0}, + {"dead_dasia", 12}, + {"Greek_ALPHA", 1}, + {"ᾍ", 0}, + {"Greek_eta", 1}, + {"ᾕ", 0}, + {"Greek_alpha", 1}, + {"ᾅ", 0}, + {"Greek_ETA", 1}, + {"ᾝ", 0}, + {"Greek_omega", 1}, + {"ᾥ", 0}, + {"Greek_OMEGA", 1}, + {"ᾭ", 0}, + {"Greek_eta", 1}, + {"ῄ", 0}, + {"dead_psili", 12}, + {"Greek_ALPHA", 1}, + {"ᾌ", 0}, + {"Greek_eta", 1}, + {"ᾔ", 0}, + {"Greek_alpha", 1}, + {"ᾄ", 0}, + {"Greek_ETA", 1}, + {"ᾜ", 0}, + {"Greek_omega", 1}, + {"ᾤ", 0}, + {"Greek_OMEGA", 1}, + {"ᾬ", 0}, + {"Greek_alpha", 1}, + {"ᾴ", 0}, + {"Greek_omega", 1}, + {"ῴ", 0}, + {"parenleft", 12}, + {"Greek_ALPHA", 1}, + {"ᾍ", 0}, + {"Greek_eta", 1}, + {"ᾕ", 0}, + {"Greek_alpha", 1}, + {"ᾅ", 0}, + {"Greek_ETA", 1}, + {"ᾝ", 0}, + {"Greek_omega", 1}, + {"ᾥ", 0}, + {"Greek_OMEGA", 1}, + {"ᾭ", 0}, + {"Greek_alphaaccent", 1}, + {"ᾴ", 0}, + {"parenleft", 12}, + {"Greek_ALPHA", 1}, + {"ᾉ", 0}, + {"Greek_eta", 1}, + {"ᾑ", 0}, + {"Greek_alpha", 1}, + {"ᾁ", 0}, + {"Greek_ETA", 1}, + {"ᾙ", 0}, + {"Greek_omega", 1}, + {"ᾡ", 0}, + {"Greek_OMEGA", 1}, + {"ᾩ", 0}, + {"grave", 58}, + {"parenright", 12}, + {"Greek_ALPHA", 1}, + {"ᾊ", 0}, + {"Greek_eta", 1}, + {"ᾒ", 0}, + {"Greek_alpha", 1}, + {"ᾂ", 0}, + {"Greek_ETA", 1}, + {"ᾚ", 0}, + {"Greek_omega", 1}, + {"ᾢ", 0}, + {"Greek_OMEGA", 1}, + {"ᾪ", 0}, + {"dead_dasia", 12}, + {"Greek_ALPHA", 1}, + {"ᾋ", 0}, + {"Greek_eta", 1}, + {"ᾓ", 0}, + {"Greek_alpha", 1}, + {"ᾃ", 0}, + {"Greek_ETA", 1}, + {"ᾛ", 0}, + {"Greek_omega", 1}, + {"ᾣ", 0}, + {"Greek_OMEGA", 1}, + {"ᾫ", 0}, + {"Greek_eta", 1}, + {"ῂ", 0}, + {"dead_psili", 12}, + {"Greek_ALPHA", 1}, + {"ᾊ", 0}, + {"Greek_eta", 1}, + {"ᾒ", 0}, + {"Greek_alpha", 1}, + {"ᾂ", 0}, + {"Greek_ETA", 1}, + {"ᾚ", 0}, + {"Greek_omega", 1}, + {"ᾢ", 0}, + {"Greek_OMEGA", 1}, + {"ᾪ", 0}, + {"Greek_alpha", 1}, + {"ᾲ", 0}, + {"Greek_omega", 1}, + {"ῲ", 0}, + {"parenleft", 12}, + {"Greek_ALPHA", 1}, + {"ᾋ", 0}, + {"Greek_eta", 1}, + {"ᾓ", 0}, + {"Greek_alpha", 1}, + {"ᾃ", 0}, + {"Greek_ETA", 1}, + {"ᾛ", 0}, + {"Greek_omega", 1}, + {"ᾣ", 0}, + {"Greek_OMEGA", 1}, + {"ᾫ", 0}, + {"Greek_etaaccent", 1}, + {"ῄ", 0}, + {"1", 21}, + {"1", 2}, + {"0", 1}, + {"⅒", 0}, + {"7", 1}, + {"⅐", 0}, + {"8", 1}, + {"⅛", 0}, + {"3", 1}, + {"⅓", 0}, + {"2", 1}, + {"½", 0}, + {"6", 1}, + {"⅙", 0}, + {"4", 1}, + {"¼", 0}, + {"5", 1}, + {"⅕", 0}, + {"9", 1}, + {"⅑", 0}, + {"asciicircum", 1}, + {"¹", 0}, + {"Greek_OMICRON", 2}, + {"apostrophe", 1}, + {"Ό", 0}, + {"C", 26}, + {"period", 1}, + {"Ċ", 0}, + {"C", 3}, + {"C", 2}, + {"P", 1}, + {"☭", 0}, + {"less", 1}, + {"Č", 0}, + {"o", 1}, + {"©", 0}, + {"equal", 1}, + {"€", 0}, + {"E", 1}, + {"₠", 0}, + {"apostrophe", 1}, + {"Ć", 0}, + {"O", 1}, + {"©", 0}, + {"r", 1}, + {"₢", 0}, + {"bar", 1}, + {"¢", 0}, + {"comma", 1}, + {"Ç", 0}, + {"slash", 1}, + {"₡", 0}, + {"exclam", 108}, + {"W", 1}, + {"Ẉ", 0}, + {"a", 1}, + {"ạ", 0}, + {"dead_horn", 8}, + {"o", 1}, + {"ợ", 0}, + {"u", 1}, + {"ự", 0}, + {"O", 1}, + {"Ợ", 0}, + {"U", 1}, + {"Ự", 0}, + {"exclam", 1}, + {"¡", 0}, + {"e", 1}, + {"ẹ", 0}, + {"o", 1}, + {"ọ", 0}, + {"l", 1}, + {"ḷ", 0}, + {"t", 1}, + {"ṭ", 0}, + {"uhorn", 1}, + {"ự", 0}, + {"y", 1}, + {"ỵ", 0}, + {"b", 1}, + {"ḅ", 0}, + {"i", 1}, + {"ị", 0}, + {"k", 1}, + {"ḳ", 0}, + {"n", 1}, + {"ṇ", 0}, + {"Ohorn", 1}, + {"Ợ", 0}, + {"ohorn", 1}, + {"ợ", 0}, + {"V", 1}, + {"Ṿ", 0}, + {"u", 1}, + {"ụ", 0}, + {"z", 1}, + {"ẓ", 0}, + {"H", 1}, + {"Ḥ", 0}, + {"E", 1}, + {"Ẹ", 0}, + {"S", 1}, + {"Ṣ", 0}, + {"Y", 1}, + {"Ỵ", 0}, + {"d", 1}, + {"ḍ", 0}, + {"D", 1}, + {"Ḍ", 0}, + {"plus", 8}, + {"o", 1}, + {"ợ", 0}, + {"u", 1}, + {"ự", 0}, + {"O", 1}, + {"Ợ", 0}, + {"U", 1}, + {"Ự", 0}, + {"w", 1}, + {"ẉ", 0}, + {"v", 1}, + {"ṿ", 0}, + {"question", 1}, + {"‽", 0}, + {"M", 1}, + {"Ṃ", 0}, + {"O", 1}, + {"Ọ", 0}, + {"m", 1}, + {"ṃ", 0}, + {"r", 1}, + {"ṛ", 0}, + {"s", 1}, + {"ṣ", 0}, + {"Z", 1}, + {"Ẓ", 0}, + {"A", 1}, + {"Ạ", 0}, + {"R", 1}, + {"Ṛ", 0}, + {"L", 1}, + {"Ḷ", 0}, + {"T", 1}, + {"Ṭ", 0}, + {"K", 1}, + {"Ḳ", 0}, + {"B", 1}, + {"Ḅ", 0}, + {"Uhorn", 1}, + {"Ự", 0}, + {"h", 1}, + {"ḥ", 0}, + {"I", 1}, + {"Ị", 0}, + {"N", 1}, + {"Ṇ", 0}, + {"U", 1}, + {"Ụ", 0}, + {"asciicircum", 1}, + {"¦", 0}, + {"less", 56}, + {"minus", 1}, + {"←", 0}, + {"C", 1}, + {"Č", 0}, + {"less", 1}, + {"«", 0}, + {"e", 1}, + {"ě", 0}, + {"l", 1}, + {"ľ", 0}, + {"t", 1}, + {"ť", 0}, + {"space", 1}, + {"ˇ", 0}, + {"n", 1}, + {"ň", 0}, + {"equal", 1}, + {"≤", 0}, + {"z", 1}, + {"ž", 0}, + {"3", 1}, + {"♥", 0}, + {"E", 1}, + {"Ě", 0}, + {"S", 1}, + {"Š", 0}, + {"d", 1}, + {"ď", 0}, + {"D", 1}, + {"Ď", 0}, + {"quotedbl", 1}, + {"“", 0}, + {"underscore", 1}, + {"≤", 0}, + {"apostrophe", 1}, + {"‘", 0}, + {"r", 1}, + {"ř", 0}, + {"s", 1}, + {"š", 0}, + {"Z", 1}, + {"Ž", 0}, + {"R", 1}, + {"Ř", 0}, + {"c", 1}, + {"č", 0}, + {"L", 1}, + {"Ľ", 0}, + {"T", 1}, + {"Ť", 0}, + {"slash", 1}, + {"\\", 0}, + {"greater", 1}, + {"⋄", 0}, + {"N", 1}, + {"Ň", 0}, + {"KP_Divide", 46}, + {"g", 1}, + {"ǥ", 0}, + {"o", 1}, + {"ø", 0}, + {"l", 1}, + {"ł", 0}, + {"t", 1}, + {"ŧ", 0}, + {"b", 1}, + {"ƀ", 0}, + {"i", 1}, + {"ɨ", 0}, + {"Cyrillic_GHE", 1}, + {"Ғ", 0}, + {"leftarrow", 1}, + {"↚", 0}, + {"Cyrillic_KA", 1}, + {"Ҟ", 0}, + {"rightarrow", 1}, + {"↛", 0}, + {"z", 1}, + {"ƶ", 0}, + {"G", 1}, + {"Ǥ", 0}, + {"H", 1}, + {"Ħ", 0}, + {"d", 1}, + {"đ", 0}, + {"Cyrillic_ka", 1}, + {"ҟ", 0}, + {"D", 1}, + {"Đ", 0}, + {"O", 1}, + {"Ø", 0}, + {"Z", 1}, + {"Ƶ", 0}, + {"L", 1}, + {"Ł", 0}, + {"T", 1}, + {"Ŧ", 0}, + {"Cyrillic_ghe", 1}, + {"ғ", 0}, + {"h", 1}, + {"ħ", 0}, + {"I", 1}, + {"Ɨ", 0}, + {"F", 8}, + {"period", 1}, + {"Ḟ", 0}, + {"l", 1}, + {"ffl", 0}, + {"i", 1}, + {"ffi", 0}, + {"r", 1}, + {"₣", 0}, + {"e", 28}, + {"minus", 1}, + {"ē", 0}, + {"period", 1}, + {"ė", 0}, + {"less", 1}, + {"ě", 0}, + {"e", 1}, + {"ə", 0}, + {"diaeresis", 1}, + {"ë", 0}, + {"equal", 1}, + {"€", 0}, + {"quotedbl", 1}, + {"ë", 0}, + {"acute", 1}, + {"é", 0}, + {"underscore", 1}, + {"ē", 0}, + {"apostrophe", 1}, + {"é", 0}, + {"comma", 1}, + {"ę", 0}, + {"greater", 1}, + {"ê", 0}, + {"grave", 1}, + {"è", 0}, + {"asciicircum", 1}, + {"ê", 0}, + {"o", 52}, + {"minus", 1}, + {"ō", 0}, + {"a", 1}, + {"å", 0}, + {"C", 1}, + {"©", 0}, + {"e", 1}, + {"œ", 0}, + {"o", 1}, + {"°", 0}, + {"diaeresis", 1}, + {"ö", 0}, + {"y", 1}, + {"ẙ", 0}, + {"x", 1}, + {"¤", 0}, + {"u", 1}, + {"ů", 0}, + {"quotedbl", 1}, + {"ö", 0}, + {"acute", 1}, + {"ó", 0}, + {"w", 1}, + {"ẘ", 0}, + {"underscore", 1}, + {"ō", 0}, + {"apostrophe", 1}, + {"ó", 0}, + {"r", 1}, + {"®", 0}, + {"s", 1}, + {"§", 0}, + {"A", 1}, + {"Å", 0}, + {"R", 1}, + {"®", 0}, + {"c", 1}, + {"©", 0}, + {"asciitilde", 1}, + {"õ", 0}, + {"slash", 1}, + {"ø", 0}, + {"greater", 1}, + {"ô", 0}, + {"X", 1}, + {"¤", 0}, + {"grave", 1}, + {"ò", 0}, + {"U", 1}, + {"Ů", 0}, + {"asciicircum", 1}, + {"ô", 0}, + {"l", 12}, + {"minus", 1}, + {"£", 0}, + {"less", 1}, + {"ľ", 0}, + {"v", 1}, + {"|", 0}, + {"apostrophe", 1}, + {"ĺ", 0}, + {"comma", 1}, + {"ļ", 0}, + {"slash", 1}, + {"ł", 0}, + {"Greek_upsilon", 4}, + {"quotedbl", 1}, + {"ϋ", 0}, + {"apostrophe", 1}, + {"ύ", 0}, + {"t", 16}, + {"minus", 1}, + {"ŧ", 0}, + {"period", 1}, + {"ṫ", 0}, + {"less", 1}, + {"ť", 0}, + {"M", 1}, + {"™", 0}, + {"m", 1}, + {"™", 0}, + {"comma", 1}, + {"ţ", 0}, + {"slash", 1}, + {"ŧ", 0}, + {"h", 1}, + {"þ", 0}, + {"diaeresis", 42}, + {"a", 1}, + {"ä", 0}, + {"dead_grave", 1}, + {"῭", 0}, + {"e", 1}, + {"ë", 0}, + {"o", 1}, + {"ö", 0}, + {"y", 1}, + {"ÿ", 0}, + {"i", 1}, + {"ï", 0}, + {"dead_tilde", 1}, + {"῁", 0}, + {"u", 1}, + {"ü", 0}, + {"E", 1}, + {"Ë", 0}, + {"Y", 1}, + {"Ÿ", 0}, + {"acute", 1}, + {"΅", 0}, + {"apostrophe", 1}, + {"΅", 0}, + {"O", 1}, + {"Ö", 0}, + {"asterisk", 1}, + {"⍣", 0}, + {"A", 1}, + {"Ä", 0}, + {"asciitilde", 1}, + {"῁", 0}, + {"greater", 1}, + {"⍩", 0}, + {"dead_acute", 1}, + {"΅", 0}, + {"I", 1}, + {"Ï", 0}, + {"grave", 1}, + {"῭", 0}, + {"U", 1}, + {"Ü", 0}, + {"space", 22}, + {"minus", 1}, + {"~", 0}, + {"period", 1}, + {" ", 0}, + {"less", 1}, + {"ˇ", 0}, + {"space", 1}, + {" ", 0}, + {"apostrophe", 1}, + {"'", 0}, + {"comma", 1}, + {"¸", 0}, + {"asciitilde", 1}, + {"~", 0}, + {"greater", 1}, + {"^", 0}, + {"parenleft", 1}, + {"˘", 0}, + {"grave", 1}, + {"`", 0}, + {"asciicircum", 1}, + {"^", 0}, + {"percent", 2}, + {"o", 1}, + {"‰", 0}, + {"y", 14}, + {"minus", 1}, + {"¥", 0}, + {"diaeresis", 1}, + {"ÿ", 0}, + {"equal", 1}, + {"¥", 0}, + {"quotedbl", 1}, + {"ÿ", 0}, + {"acute", 1}, + {"ý", 0}, + {"apostrophe", 1}, + {"ý", 0}, + {"asciicircum", 1}, + {"ŷ", 0}, + {"b", 83}, + {"period", 1}, + {"ḃ", 0}, + {"g", 1}, + {"ğ", 0}, + {"a", 1}, + {"ă", 0}, + {"Greek_IOTA", 1}, + {"Ῐ", 0}, + {"Greek_iota", 1}, + {"ῐ", 0}, + {"exclam", 4}, + {"a", 1}, + {"ặ", 0}, + {"A", 1}, + {"Ặ", 0}, + {"e", 1}, + {"ĕ", 0}, + {"o", 1}, + {"ŏ", 0}, + {"Greek_upsilon", 1}, + {"ῠ", 0}, + {"dead_belowdot", 4}, + {"a", 1}, + {"ặ", 0}, + {"A", 1}, + {"Ặ", 0}, + {"Cyrillic_I", 1}, + {"Й", 0}, + {"i", 1}, + {"ĭ", 0}, + {"Cyrillic_a", 1}, + {"ӑ", 0}, + {"Cyrillic_U", 1}, + {"Ў", 0}, + {"u", 1}, + {"ŭ", 0}, + {"G", 1}, + {"Ğ", 0}, + {"Greek_ALPHA", 1}, + {"Ᾰ", 0}, + {"Cyrillic_ie", 1}, + {"ӗ", 0}, + {"E", 1}, + {"Ĕ", 0}, + {"Cyrillic_i", 1}, + {"й", 0}, + {"Cyrillic_zhe", 1}, + {"ӂ", 0}, + {"cedilla", 4}, + {"e", 1}, + {"ḝ", 0}, + {"E", 1}, + {"Ḝ", 0}, + {"Greek_alpha", 1}, + {"ᾰ", 0}, + {"O", 1}, + {"Ŏ", 0}, + {"A", 1}, + {"Ă", 0}, + {"Cyrillic_A", 1}, + {"Ӑ", 0}, + {"comma", 4}, + {"e", 1}, + {"ḝ", 0}, + {"E", 1}, + {"Ḝ", 0}, + {"Cyrillic_ZHE", 1}, + {"Ӂ", 0}, + {"Cyrillic_IE", 1}, + {"Ӗ", 0}, + {"dead_cedilla", 4}, + {"e", 1}, + {"ḝ", 0}, + {"E", 1}, + {"Ḝ", 0}, + {"I", 1}, + {"Ĭ", 0}, + {"U", 1}, + {"Ŭ", 0}, + {"Cyrillic_u", 1}, + {"ў", 0}, + {"Greek_UPSILON", 1}, + {"Ῠ", 0}, + {"i", 28}, + {"minus", 1}, + {"ī", 0}, + {"period", 1}, + {"ı", 0}, + {"diaeresis", 1}, + {"ï", 0}, + {"j", 1}, + {"ij", 0}, + {"quotedbl", 1}, + {"ï", 0}, + {"acute", 1}, + {"í", 0}, + {"underscore", 1}, + {"ī", 0}, + {"apostrophe", 1}, + {"í", 0}, + {"comma", 1}, + {"į", 0}, + {"asciitilde", 1}, + {"ĩ", 0}, + {"greater", 1}, + {"î", 0}, + {"semicolon", 1}, + {"į", 0}, + {"grave", 1}, + {"ì", 0}, + {"asciicircum", 1}, + {"î", 0}, + {"k", 4}, + {"k", 1}, + {"ĸ", 0}, + {"comma", 1}, + {"ķ", 0}, + {"n", 10}, + {"g", 1}, + {"ŋ", 0}, + {"less", 1}, + {"ň", 0}, + {"apostrophe", 1}, + {"ń", 0}, + {"comma", 1}, + {"ņ", 0}, + {"asciitilde", 1}, + {"ñ", 0}, + {"equal", 40}, + {"W", 1}, + {"₩", 0}, + {"C", 1}, + {"€", 0}, + {"e", 1}, + {"€", 0}, + {"o", 1}, + {"ő", 0}, + {"y", 1}, + {"¥", 0}, + {"Cyrillic_U", 1}, + {"Ӳ", 0}, + {"u", 1}, + {"ű", 0}, + {"E", 1}, + {"€", 0}, + {"Y", 1}, + {"¥", 0}, + {"d", 1}, + {"₫", 0}, + {"underscore", 1}, + {"≡", 0}, + {"O", 1}, + {"Ő", 0}, + {"Cyrillic_ES", 1}, + {"€", 0}, + {"c", 1}, + {"€", 0}, + {"L", 1}, + {"₤", 0}, + {"slash", 1}, + {"≠", 0}, + {"Cyrillic_IE", 1}, + {"€", 0}, + {"N", 1}, + {"₦", 0}, + {"U", 1}, + {"Ű", 0}, + {"Cyrillic_u", 1}, + {"ӳ", 0}, + {"7", 2}, + {"8", 1}, + {"⅞", 0}, + {"parenright", 32}, + {"minus", 1}, + {"}", 0}, + {"Greek_IOTA", 1}, + {"Ἰ", 0}, + {"Greek_iota", 1}, + {"ἰ", 0}, + {"Greek_OMICRON", 1}, + {"Ὀ", 0}, + {"Greek_upsilon", 1}, + {"ὐ", 0}, + {"parenright", 1}, + {"]", 0}, + {"Greek_epsilon", 1}, + {"ἐ", 0}, + {"Greek_ALPHA", 1}, + {"Ἀ", 0}, + {"Greek_omicron", 1}, + {"ὀ", 0}, + {"Greek_eta", 1}, + {"ἠ", 0}, + {"Greek_rho", 1}, + {"ῤ", 0}, + {"Greek_alpha", 1}, + {"ἀ", 0}, + {"Greek_ETA", 1}, + {"Ἠ", 0}, + {"Greek_EPSILON", 1}, + {"Ἐ", 0}, + {"Greek_omega", 1}, + {"ὠ", 0}, + {"Greek_OMEGA", 1}, + {"Ὠ", 0}, + {"x", 6}, + {"o", 1}, + {"¤", 0}, + {"x", 1}, + {"×", 0}, + {"O", 1}, + {"¤", 0}, + {"Greek_epsilon", 2}, + {"apostrophe", 1}, + {"έ", 0}, + {"braceleft", 2}, + {"braceright", 1}, + {"∅", 0}, + {"underbar", 54}, + {"1", 1}, + {"₁", 0}, + {"KP_4", 1}, + {"₄", 0}, + {"KP_6", 1}, + {"₆", 0}, + {"KP_8", 1}, + {"₈", 0}, + {"KP_9", 1}, + {"₉", 0}, + {"equal", 1}, + {"₌", 0}, + {"KP_Space", 1}, + {"₂", 0}, + {"7", 1}, + {"₇", 0}, + {"parenright", 1}, + {"₎", 0}, + {"KP_7", 1}, + {"₇", 0}, + {"8", 1}, + {"₈", 0}, + {"KP_1", 1}, + {"₁", 0}, + {"3", 1}, + {"₃", 0}, + {"2", 1}, + {"₂", 0}, + {"plus", 1}, + {"₊", 0}, + {"6", 1}, + {"₆", 0}, + {"4", 1}, + {"₄", 0}, + {"KP_3", 1}, + {"₃", 0}, + {"KP_0", 1}, + {"₀", 0}, + {"KP_Add", 1}, + {"₊", 0}, + {"KP_2", 1}, + {"₂", 0}, + {"5", 1}, + {"₅", 0}, + {"KP_5", 1}, + {"₅", 0}, + {"9", 1}, + {"₉", 0}, + {"0", 1}, + {"₀", 0}, + {"parenleft", 1}, + {"₍", 0}, + {"KP_Equal", 1}, + {"₌", 0}, + {"V", 2}, + {"L", 1}, + {"|", 0}, + {"u", 28}, + {"minus", 1}, + {"ū", 0}, + {"diaeresis", 1}, + {"ü", 0}, + {"u", 1}, + {"ŭ", 0}, + {"quotedbl", 1}, + {"ü", 0}, + {"acute", 1}, + {"ú", 0}, + {"underscore", 1}, + {"ū", 0}, + {"apostrophe", 1}, + {"ú", 0}, + {"asterisk", 1}, + {"ů", 0}, + {"comma", 1}, + {"ų", 0}, + {"asciitilde", 1}, + {"ũ", 0}, + {"slash", 1}, + {"µ", 0}, + {"greater", 1}, + {"û", 0}, + {"grave", 1}, + {"ù", 0}, + {"asciicircum", 1}, + {"û", 0}, + {"breve", 4}, + {"g", 1}, + {"ğ", 0}, + {"G", 1}, + {"Ğ", 0}, + {"z", 6}, + {"period", 1}, + {"ż", 0}, + {"less", 1}, + {"ž", 0}, + {"apostrophe", 1}, + {"ź", 0}, + {"G", 10}, + {"period", 1}, + {"Ġ", 0}, + {"breve", 1}, + {"Ğ", 0}, + {"comma", 1}, + {"Ģ", 0}, + {"parenleft", 1}, + {"Ğ", 0}, + {"U", 1}, + {"Ğ", 0}, + {"Greek_ALPHA", 2}, + {"apostrophe", 1}, + {"Ά", 0}, + {"bracketleft", 2}, + {"bracketright", 1}, + {"⌷", 0}, + {"H", 2}, + {"comma", 1}, + {"Ḩ", 0}, + {"8", 2}, + {"8", 1}, + {"∞", 0}, + {"3", 8}, + {"8", 1}, + {"⅜", 0}, + {"4", 1}, + {"¾", 0}, + {"5", 1}, + {"⅗", 0}, + {"asciicircum", 1}, + {"³", 0}, + {"E", 26}, + {"minus", 1}, + {"Ē", 0}, + {"period", 1}, + {"Ė", 0}, + {"less", 1}, + {"Ě", 0}, + {"diaeresis", 1}, + {"Ë", 0}, + {"equal", 1}, + {"€", 0}, + {"quotedbl", 1}, + {"Ë", 0}, + {"acute", 1}, + {"É", 0}, + {"underscore", 1}, + {"Ē", 0}, + {"apostrophe", 1}, + {"É", 0}, + {"comma", 1}, + {"Ę", 0}, + {"greater", 1}, + {"Ê", 0}, + {"grave", 1}, + {"È", 0}, + {"asciicircum", 1}, + {"Ê", 0}, + {"S", 18}, + {"period", 1}, + {"Ṡ", 0}, + {"exclam", 1}, + {"§", 0}, + {"less", 1}, + {"Š", 0}, + {"S", 1}, + {"ẞ", 0}, + {"apostrophe", 1}, + {"Ś", 0}, + {"M", 1}, + {"℠", 0}, + {"O", 1}, + {"§", 0}, + {"m", 1}, + {"℠", 0}, + {"comma", 1}, + {"Ş", 0}, + {"2", 6}, + {"3", 1}, + {"⅔", 0}, + {"5", 1}, + {"⅖", 0}, + {"asciicircum", 1}, + {"²", 0}, + {"Y", 14}, + {"minus", 1}, + {"¥", 0}, + {"diaeresis", 1}, + {"Ÿ", 0}, + {"equal", 1}, + {"¥", 0}, + {"quotedbl", 1}, + {"Ÿ", 0}, + {"acute", 1}, + {"Ý", 0}, + {"apostrophe", 1}, + {"Ý", 0}, + {"asciicircum", 1}, + {"Ŷ", 0}, + {"f", 12}, + {"period", 1}, + {"ḟ", 0}, + {"l", 1}, + {"fl", 0}, + {"i", 1}, + {"fi", 0}, + {"S", 1}, + {"ſ", 0}, + {"f", 1}, + {"ff", 0}, + {"s", 1}, + {"ſ", 0}, + {"Greek_omicron", 2}, + {"apostrophe", 1}, + {"ό", 0}, + {"Greek_eta", 2}, + {"apostrophe", 1}, + {"ή", 0}, + {"d", 14}, + {"minus", 1}, + {"đ", 0}, + {"period", 1}, + {"ḋ", 0}, + {"less", 1}, + {"ď", 0}, + {"i", 1}, + {"⌀", 0}, + {"equal", 1}, + {"₫", 0}, + {"comma", 1}, + {"ḑ", 0}, + {"h", 1}, + {"ð", 0}, + {"D", 10}, + {"minus", 1}, + {"Đ", 0}, + {"period", 1}, + {"Ḋ", 0}, + {"less", 1}, + {"Ď", 0}, + {"H", 1}, + {"Ð", 0}, + {"comma", 1}, + {"Ḑ", 0}, + {"quotedbl", 137}, + {"W", 1}, + {"Ẅ", 0}, + {"a", 1}, + {"ä", 0}, + {"Greek_IOTA", 1}, + {"Ϊ", 0}, + {"Greek_iota", 1}, + {"ϊ", 0}, + {"less", 1}, + {"“", 0}, + {"Umacron", 1}, + {"Ṻ", 0}, + {"Cyrillic_ZE", 1}, + {"Ӟ", 0}, + {"e", 1}, + {"ë", 0}, + {"o", 1}, + {"ö", 0}, + {"Cyrillic_ze", 1}, + {"ӟ", 0}, + {"t", 1}, + {"ẗ", 0}, + {"Greek_upsilon", 1}, + {"ϋ", 0}, + {"dead_macron", 4}, + {"u", 1}, + {"ṻ", 0}, + {"U", 1}, + {"Ṻ", 0}, + {"Cyrillic_I", 1}, + {"Ӥ", 0}, + {"y", 1}, + {"ÿ", 0}, + {"Cyrillic_O", 1}, + {"Ӧ", 0}, + {"i", 1}, + {"ï", 0}, + {"Ukrainian_I", 1}, + {"Ї", 0}, + {"dead_tilde", 4}, + {"o", 1}, + {"ṏ", 0}, + {"O", 1}, + {"Ṏ", 0}, + {"Cyrillic_che", 1}, + {"ӵ", 0}, + {"Cyrillic_a", 1}, + {"ӓ", 0}, + {"x", 1}, + {"ẍ", 0}, + {"Cyrillic_U", 1}, + {"Ӱ", 0}, + {"u", 1}, + {"ü", 0}, + {"otilde", 1}, + {"ṏ", 0}, + {"H", 1}, + {"Ḧ", 0}, + {"Cyrillic_YERU", 1}, + {"Ӹ", 0}, + {"Cyrillic_ie", 1}, + {"ё", 0}, + {"E", 1}, + {"Ë", 0}, + {"Y", 1}, + {"Ÿ", 0}, + {"Cyrillic_i", 1}, + {"ӥ", 0}, + {"Otilde", 1}, + {"Ṏ", 0}, + {"Cyrillic_zhe", 1}, + {"ӝ", 0}, + {"quotedbl", 1}, + {"¨", 0}, + {"umacron", 1}, + {"ṻ", 0}, + {"Cyrillic_yeru", 1}, + {"ӹ", 0}, + {"acute", 1}, + {"̈́", 0}, + {"w", 1}, + {"ẅ", 0}, + {"Cyrillic_CHE", 1}, + {"Ӵ", 0}, + {"Cyrillic_o", 1}, + {"ӧ", 0}, + {"Ukrainian_i", 1}, + {"ї", 0}, + {"Cyrillic_E", 1}, + {"Ӭ", 0}, + {"underscore", 4}, + {"u", 1}, + {"ṻ", 0}, + {"U", 1}, + {"Ṻ", 0}, + {"apostrophe", 1}, + {"̈́", 0}, + {"O", 1}, + {"Ö", 0}, + {"macron", 4}, + {"u", 1}, + {"ṻ", 0}, + {"U", 1}, + {"Ṻ", 0}, + {"A", 1}, + {"Ä", 0}, + {"Cyrillic_A", 1}, + {"Ӓ", 0}, + {"comma", 1}, + {"„", 0}, + {"asciitilde", 4}, + {"o", 1}, + {"ṏ", 0}, + {"O", 1}, + {"Ṏ", 0}, + {"greater", 1}, + {"”", 0}, + {"Cyrillic_ZHE", 1}, + {"Ӝ", 0}, + {"Cyrillic_IE", 1}, + {"Ё", 0}, + {"Cyrillic_e", 1}, + {"ӭ", 0}, + {"dead_acute", 1}, + {"̈́", 0}, + {"X", 1}, + {"Ẍ", 0}, + {"h", 1}, + {"ḧ", 0}, + {"I", 1}, + {"Ï", 0}, + {"U", 1}, + {"Ü", 0}, + {"Cyrillic_u", 1}, + {"ӱ", 0}, + {"Greek_UPSILON", 1}, + {"Ϋ", 0}, + {"plus", 12}, + {"minus", 1}, + {"±", 0}, + {"o", 1}, + {"ơ", 0}, + {"u", 1}, + {"ư", 0}, + {"plus", 1}, + {"#", 0}, + {"O", 1}, + {"Ơ", 0}, + {"U", 1}, + {"Ư", 0}, + {"cedilla", 44}, + {"g", 1}, + {"ģ", 0}, + {"C", 1}, + {"Ç", 0}, + {"e", 1}, + {"ȩ", 0}, + {"l", 1}, + {"ļ", 0}, + {"t", 1}, + {"ţ", 0}, + {"k", 1}, + {"ķ", 0}, + {"n", 1}, + {"ņ", 0}, + {"G", 1}, + {"Ģ", 0}, + {"H", 1}, + {"Ḩ", 0}, + {"E", 1}, + {"Ȩ", 0}, + {"S", 1}, + {"Ş", 0}, + {"d", 1}, + {"ḑ", 0}, + {"D", 1}, + {"Ḑ", 0}, + {"r", 1}, + {"ŗ", 0}, + {"s", 1}, + {"ş", 0}, + {"R", 1}, + {"Ŗ", 0}, + {"c", 1}, + {"ç", 0}, + {"L", 1}, + {"Ļ", 0}, + {"T", 1}, + {"Ţ", 0}, + {"K", 1}, + {"Ķ", 0}, + {"h", 1}, + {"ḩ", 0}, + {"N", 1}, + {"Ņ", 0}, + {"Greek_alpha", 2}, + {"apostrophe", 1}, + {"ά", 0}, + {"dead_abovedot", 3}, + {"f", 2}, + {"s", 1}, + {"ẛ", 0}, + {"acute", 463}, + {"W", 1}, + {"Ẃ", 0}, + {"dead_breve", 4}, + {"a", 1}, + {"ắ", 0}, + {"A", 1}, + {"Ắ", 0}, + {"g", 1}, + {"ǵ", 0}, + {"a", 1}, + {"á", 0}, + {"Greek_IOTA", 1}, + {"Ί", 0}, + {"Greek_iota", 1}, + {"ί", 0}, + {"dead_horn", 8}, + {"o", 1}, + {"ớ", 0}, + {"u", 1}, + {"ứ", 0}, + {"O", 1}, + {"Ớ", 0}, + {"U", 1}, + {"Ứ", 0}, + {"dead_circumflex", 12}, + {"a", 1}, + {"ấ", 0}, + {"e", 1}, + {"ế", 0}, + {"o", 1}, + {"ố", 0}, + {"E", 1}, + {"Ế", 0}, + {"O", 1}, + {"Ố", 0}, + {"A", 1}, + {"Ấ", 0}, + {"Greek_OMICRON", 1}, + {"Ό", 0}, + {"Acircumflex", 1}, + {"Ấ", 0}, + {"C", 1}, + {"Ć", 0}, + {"Cyrillic_er", 1}, + {"р́", 0}, + {"e", 1}, + {"é", 0}, + {"KP_Divide", 4}, + {"o", 1}, + {"ǿ", 0}, + {"O", 1}, + {"Ǿ", 0}, + {"Utilde", 1}, + {"Ṹ", 0}, + {"o", 1}, + {"ó", 0}, + {"l", 1}, + {"ĺ", 0}, + {"Udiaeresis", 1}, + {"Ǘ", 0}, + {"Greek_upsilon", 1}, + {"ύ", 0}, + {"uhorn", 1}, + {"ứ", 0}, + {"dead_macron", 8}, + {"e", 1}, + {"ḗ", 0}, + {"o", 1}, + {"ṓ", 0}, + {"E", 1}, + {"Ḗ", 0}, + {"O", 1}, + {"Ṓ", 0}, + {"acircumflex", 1}, + {"ấ", 0}, + {"Ecircumflex", 1}, + {"Ế", 0}, + {"Cyrillic_I", 1}, + {"И́", 0}, + {"y", 1}, + {"ý", 0}, + {"b", 4}, + {"a", 1}, + {"ắ", 0}, + {"A", 1}, + {"Ắ", 0}, + {"idiaeresis", 1}, + {"ḯ", 0}, + {"Cyrillic_O", 1}, + {"О́", 0}, + {"i", 1}, + {"í", 0}, + {"k", 1}, + {"ḱ", 0}, + {"n", 1}, + {"ń", 0}, + {"ccedilla", 1}, + {"ḉ", 0}, + {"Cyrillic_GHE", 1}, + {"Ѓ", 0}, + {"dead_tilde", 8}, + {"o", 1}, + {"ṍ", 0}, + {"u", 1}, + {"ṹ", 0}, + {"O", 1}, + {"Ṍ", 0}, + {"U", 1}, + {"Ṹ", 0}, + {"Cyrillic_a", 1}, + {"а́", 0}, + {"parenright", 26}, + {"Greek_IOTA", 1}, + {"Ἴ", 0}, + {"Greek_iota", 1}, + {"ἴ", 0}, + {"Greek_OMICRON", 1}, + {"Ὄ", 0}, + {"Greek_upsilon", 1}, + {"ὔ", 0}, + {"Greek_epsilon", 1}, + {"ἔ", 0}, + {"Greek_ALPHA", 1}, + {"Ἄ", 0}, + {"Greek_omicron", 1}, + {"ὄ", 0}, + {"Greek_eta", 1}, + {"ἤ", 0}, + {"Greek_alpha", 1}, + {"ἄ", 0}, + {"Greek_ETA", 1}, + {"Ἤ", 0}, + {"Greek_EPSILON", 1}, + {"Ἔ", 0}, + {"Greek_omega", 1}, + {"ὤ", 0}, + {"Greek_OMEGA", 1}, + {"Ὤ", 0}, + {"Ohorn", 1}, + {"Ớ", 0}, + {"ohorn", 1}, + {"ớ", 0}, + {"Cyrillic_ER", 1}, + {"Р́", 0}, + {"Greek_epsilon", 1}, + {"έ", 0}, + {"Cyrillic_KA", 1}, + {"Ќ", 0}, + {"Cyrillic_U", 1}, + {"У́", 0}, + {"dead_abovering", 4}, + {"a", 1}, + {"ǻ", 0}, + {"A", 1}, + {"Ǻ", 0}, + {"Ocircumflex", 1}, + {"Ố", 0}, + {"AE", 1}, + {"Ǽ", 0}, + {"omacron", 1}, + {"ṓ", 0}, + {"ocircumflex", 1}, + {"ố", 0}, + {"u", 1}, + {"ú", 0}, + {"z", 1}, + {"ź", 0}, + {"G", 1}, + {"Ǵ", 0}, + {"Greek_ALPHA", 1}, + {"Ά", 0}, + {"otilde", 1}, + {"ṍ", 0}, + {"utilde", 1}, + {"ṹ", 0}, + {"Cyrillic_ie", 1}, + {"е́", 0}, + {"emacron", 1}, + {"ḗ", 0}, + {"E", 1}, + {"É", 0}, + {"S", 1}, + {"Ś", 0}, + {"Greek_iotadieresis", 1}, + {"ΐ", 0}, + {"Y", 1}, + {"Ý", 0}, + {"Cyrillic_i", 1}, + {"и́", 0}, + {"dead_dasia", 28}, + {"Greek_IOTA", 1}, + {"Ἵ", 0}, + {"Greek_iota", 1}, + {"ἵ", 0}, + {"Greek_OMICRON", 1}, + {"Ὅ", 0}, + {"Greek_upsilon", 1}, + {"ὕ", 0}, + {"Greek_epsilon", 1}, + {"ἕ", 0}, + {"Greek_ALPHA", 1}, + {"Ἅ", 0}, + {"Greek_omicron", 1}, + {"ὅ", 0}, + {"Greek_eta", 1}, + {"ἥ", 0}, + {"Greek_alpha", 1}, + {"ἅ", 0}, + {"Greek_ETA", 1}, + {"Ἥ", 0}, + {"Greek_EPSILON", 1}, + {"Ἕ", 0}, + {"Greek_omega", 1}, + {"ὥ", 0}, + {"Greek_OMEGA", 1}, + {"Ὥ", 0}, + {"Greek_UPSILON", 1}, + {"Ὕ", 0}, + {"Greek_upsilondieresis", 1}, + {"ΰ", 0}, + {"Greek_omicron", 1}, + {"ό", 0}, + {"Greek_eta", 1}, + {"ή", 0}, + {"Otilde", 1}, + {"Ṍ", 0}, + {"Cyrillic_ka", 1}, + {"ќ", 0}, + {"Aring", 1}, + {"Ǻ", 0}, + {"Abreve", 1}, + {"Ắ", 0}, + {"dead_psili", 26}, + {"Greek_IOTA", 1}, + {"Ἴ", 0}, + {"Greek_iota", 1}, + {"ἴ", 0}, + {"Greek_OMICRON", 1}, + {"Ὄ", 0}, + {"Greek_upsilon", 1}, + {"ὔ", 0}, + {"Greek_epsilon", 1}, + {"ἔ", 0}, + {"Greek_ALPHA", 1}, + {"Ἄ", 0}, + {"Greek_omicron", 1}, + {"ὄ", 0}, + {"Greek_eta", 1}, + {"ἤ", 0}, + {"Greek_alpha", 1}, + {"ἄ", 0}, + {"Greek_ETA", 1}, + {"Ἤ", 0}, + {"Greek_EPSILON", 1}, + {"Ἔ", 0}, + {"Greek_omega", 1}, + {"ὤ", 0}, + {"Greek_OMEGA", 1}, + {"Ὤ", 0}, + {"quotedbl", 12}, + {"Greek_iota", 1}, + {"ΐ", 0}, + {"Greek_upsilon", 1}, + {"ΰ", 0}, + {"i", 1}, + {"ḯ", 0}, + {"u", 1}, + {"ǘ", 0}, + {"I", 1}, + {"Ḯ", 0}, + {"U", 1}, + {"Ǘ", 0}, + {"plus", 8}, + {"o", 1}, + {"ớ", 0}, + {"u", 1}, + {"ứ", 0}, + {"O", 1}, + {"Ớ", 0}, + {"U", 1}, + {"Ứ", 0}, + {"cedilla", 4}, + {"C", 1}, + {"Ḉ", 0}, + {"c", 1}, + {"ḉ", 0}, + {"Greek_alpha", 1}, + {"ά", 0}, + {"ecircumflex", 1}, + {"ế", 0}, + {"w", 1}, + {"ẃ", 0}, + {"Greek_ETA", 1}, + {"Ή", 0}, + {"Cyrillic_o", 1}, + {"о́", 0}, + {"Emacron", 1}, + {"Ḗ", 0}, + {"Ooblique", 1}, + {"Ǿ", 0}, + {"p", 1}, + {"ṕ", 0}, + {"underscore", 8}, + {"e", 1}, + {"ḗ", 0}, + {"o", 1}, + {"ṓ", 0}, + {"E", 1}, + {"Ḗ", 0}, + {"O", 1}, + {"Ṓ", 0}, + {"P", 1}, + {"Ṕ", 0}, + {"M", 1}, + {"Ḿ", 0}, + {"O", 1}, + {"Ó", 0}, + {"abreve", 1}, + {"ắ", 0}, + {"m", 1}, + {"ḿ", 0}, + {"r", 1}, + {"ŕ", 0}, + {"s", 1}, + {"ś", 0}, + {"Z", 1}, + {"Ź", 0}, + {"macron", 8}, + {"e", 1}, + {"ḗ", 0}, + {"o", 1}, + {"ṓ", 0}, + {"E", 1}, + {"Ḗ", 0}, + {"O", 1}, + {"Ṓ", 0}, + {"A", 1}, + {"Á", 0}, + {"R", 1}, + {"Ŕ", 0}, + {"c", 1}, + {"ć", 0}, + {"Idiaeresis", 1}, + {"Ḯ", 0}, + {"L", 1}, + {"Ĺ", 0}, + {"Greek_EPSILON", 1}, + {"Έ", 0}, + {"Cyrillic_A", 1}, + {"А́", 0}, + {"comma", 4}, + {"C", 1}, + {"Ḉ", 0}, + {"c", 1}, + {"ḉ", 0}, + {"asciitilde", 8}, + {"o", 1}, + {"ṍ", 0}, + {"u", 1}, + {"ṹ", 0}, + {"O", 1}, + {"Ṍ", 0}, + {"U", 1}, + {"Ṹ", 0}, + {"Ccedilla", 1}, + {"Ḉ", 0}, + {"slash", 4}, + {"o", 1}, + {"ǿ", 0}, + {"O", 1}, + {"Ǿ", 0}, + {"aring", 1}, + {"ǻ", 0}, + {"K", 1}, + {"Ḱ", 0}, + {"Omacron", 1}, + {"Ṓ", 0}, + {"Cyrillic_IE", 1}, + {"Е́", 0}, + {"dead_cedilla", 4}, + {"C", 1}, + {"Ḉ", 0}, + {"c", 1}, + {"ḉ", 0}, + {"Greek_omega", 1}, + {"ώ", 0}, + {"dead_diaeresis", 12}, + {"Greek_iota", 1}, + {"ΐ", 0}, + {"Greek_upsilon", 1}, + {"ΰ", 0}, + {"i", 1}, + {"ḯ", 0}, + {"u", 1}, + {"ǘ", 0}, + {"I", 1}, + {"Ḯ", 0}, + {"U", 1}, + {"Ǘ", 0}, + {"Uhorn", 1}, + {"Ứ", 0}, + {"Greek_OMEGA", 1}, + {"Ώ", 0}, + {"oslash", 1}, + {"ǿ", 0}, + {"Cyrillic_ghe", 1}, + {"ѓ", 0}, + {"parenleft", 28}, + {"Greek_IOTA", 1}, + {"Ἵ", 0}, + {"Greek_iota", 1}, + {"ἵ", 0}, + {"Greek_OMICRON", 1}, + {"Ὅ", 0}, + {"Greek_upsilon", 1}, + {"ὕ", 0}, + {"Greek_epsilon", 1}, + {"ἕ", 0}, + {"Greek_ALPHA", 1}, + {"Ἅ", 0}, + {"Greek_omicron", 1}, + {"ὅ", 0}, + {"Greek_eta", 1}, + {"ἥ", 0}, + {"Greek_alpha", 1}, + {"ἅ", 0}, + {"Greek_ETA", 1}, + {"Ἥ", 0}, + {"Greek_EPSILON", 1}, + {"Ἕ", 0}, + {"Greek_omega", 1}, + {"ὥ", 0}, + {"Greek_OMEGA", 1}, + {"Ὥ", 0}, + {"Greek_UPSILON", 1}, + {"Ὕ", 0}, + {"udiaeresis", 1}, + {"ǘ", 0}, + {"I", 1}, + {"Í", 0}, + {"N", 1}, + {"Ń", 0}, + {"U", 1}, + {"Ú", 0}, + {"Cyrillic_u", 1}, + {"у́", 0}, + {"ae", 1}, + {"ǽ", 0}, + {"asciicircum", 12}, + {"a", 1}, + {"ấ", 0}, + {"e", 1}, + {"ế", 0}, + {"o", 1}, + {"ố", 0}, + {"E", 1}, + {"Ế", 0}, + {"O", 1}, + {"Ố", 0}, + {"A", 1}, + {"Ấ", 0}, + {"Greek_UPSILON", 1}, + {"Ύ", 0}, + {"Cyrillic_pe", 2}, + {"Cyrillic_a", 1}, + {"§", 0}, + {"w", 2}, + {"asciicircum", 1}, + {"ŵ", 0}, + {"Greek_ETA", 2}, + {"apostrophe", 1}, + {"Ή", 0}, + {"4", 2}, + {"5", 1}, + {"⅘", 0}, + {"bracketright", 2}, + {"bracketleft", 1}, + {"⌷", 0}, + {"colon", 6}, + {"minus", 1}, + {"÷", 0}, + {"parenright", 1}, + {"☺", 0}, + {"parenleft", 1}, + {"☹", 0}, + {"p", 4}, + {"period", 1}, + {"ṗ", 0}, + {"exclam", 1}, + {"¶", 0}, + {"underscore", 230}, + {"adiaeresis", 1}, + {"ǟ", 0}, + {"period", 8}, + {"a", 1}, + {"ǡ", 0}, + {"o", 1}, + {"ȱ", 0}, + {"O", 1}, + {"Ȱ", 0}, + {"A", 1}, + {"Ǡ", 0}, + {"g", 1}, + {"ḡ", 0}, + {"a", 1}, + {"ā", 0}, + {"Greek_IOTA", 1}, + {"Ῑ", 0}, + {"Greek_iota", 1}, + {"ῑ", 0}, + {"1", 1}, + {"₁", 0}, + {"exclam", 8}, + {"l", 1}, + {"ḹ", 0}, + {"r", 1}, + {"ṝ", 0}, + {"R", 1}, + {"Ṝ", 0}, + {"L", 1}, + {"Ḹ", 0}, + {"KP_4", 1}, + {"₄", 0}, + {"less", 1}, + {"≤", 0}, + {"Cyrillic_er", 1}, + {"р̄", 0}, + {"o", 1}, + {"ō", 0}, + {"e", 1}, + {"ē", 0}, + {"KP_6", 1}, + {"₆", 0}, + {"Udiaeresis", 1}, + {"Ǖ", 0}, + {"Greek_upsilon", 1}, + {"ῡ", 0}, + {"dead_belowdot", 8}, + {"l", 1}, + {"ḹ", 0}, + {"r", 1}, + {"ṝ", 0}, + {"R", 1}, + {"Ṝ", 0}, + {"L", 1}, + {"Ḹ", 0}, + {"KP_8", 1}, + {"₈", 0}, + {"Cyrillic_I", 1}, + {"Ӣ", 0}, + {"y", 1}, + {"ȳ", 0}, + {"Cyrillic_O", 1}, + {"О̄", 0}, + {"i", 1}, + {"ī", 0}, + {"KP_9", 1}, + {"₉", 0}, + {"equal", 1}, + {"₌", 0}, + {"KP_Space", 1}, + {"₂", 0}, + {"dead_tilde", 4}, + {"o", 1}, + {"ȭ", 0}, + {"O", 1}, + {"Ȭ", 0}, + {"7", 1}, + {"₇", 0}, + {"Cyrillic_a", 1}, + {"а̄", 0}, + {"parenright", 1}, + {"₎", 0}, + {"Cyrillic_ER", 1}, + {"Р̄", 0}, + {"KP_7", 1}, + {"₇", 0}, + {"Cyrillic_U", 1}, + {"Ӯ", 0}, + {"AE", 1}, + {"Ǣ", 0}, + {"u", 1}, + {"ū", 0}, + {"G", 1}, + {"Ḡ", 0}, + {"Greek_ALPHA", 1}, + {"Ᾱ", 0}, + {"otilde", 1}, + {"ȭ", 0}, + {"8", 1}, + {"₈", 0}, + {"KP_1", 1}, + {"₁", 0}, + {"3", 1}, + {"₃", 0}, + {"Cyrillic_ie", 1}, + {"е̄", 0}, + {"E", 1}, + {"Ē", 0}, + {"2", 1}, + {"₂", 0}, + {"Y", 1}, + {"Ȳ", 0}, + {"Cyrillic_i", 1}, + {"ӣ", 0}, + {"dead_ogonek", 4}, + {"o", 1}, + {"ǭ", 0}, + {"O", 1}, + {"Ǭ", 0}, + {"odiaeresis", 1}, + {"ȫ", 0}, + {"Otilde", 1}, + {"Ȭ", 0}, + {"quotedbl", 12}, + {"a", 1}, + {"ǟ", 0}, + {"o", 1}, + {"ȫ", 0}, + {"u", 1}, + {"ǖ", 0}, + {"O", 1}, + {"Ȫ", 0}, + {"A", 1}, + {"Ǟ", 0}, + {"U", 1}, + {"Ǖ", 0}, + {"plus", 1}, + {"₊", 0}, + {"6", 1}, + {"₆", 0}, + {"Greek_alpha", 1}, + {"ᾱ", 0}, + {"dead_abovedot", 8}, + {"a", 1}, + {"ǡ", 0}, + {"o", 1}, + {"ȱ", 0}, + {"O", 1}, + {"Ȱ", 0}, + {"A", 1}, + {"Ǡ", 0}, + {"Cyrillic_o", 1}, + {"о̄", 0}, + {"4", 1}, + {"₄", 0}, + {"KP_3", 1}, + {"₃", 0}, + {"underscore", 1}, + {"¯", 0}, + {"apostrophe", 1}, + {"⍘", 0}, + {"O", 1}, + {"Ō", 0}, + {"KP_0", 1}, + {"₀", 0}, + {"A", 1}, + {"Ā", 0}, + {"KP_Add", 1}, + {"₊", 0}, + {"Odiaeresis", 1}, + {"Ȫ", 0}, + {"KP_2", 1}, + {"₂", 0}, + {"Cyrillic_A", 1}, + {"А̄", 0}, + {"asciitilde", 4}, + {"o", 1}, + {"ȭ", 0}, + {"O", 1}, + {"Ȭ", 0}, + {"5", 1}, + {"₅", 0}, + {"greater", 1}, + {"≥", 0}, + {"semicolon", 4}, + {"o", 1}, + {"ǭ", 0}, + {"O", 1}, + {"Ǭ", 0}, + {"KP_5", 1}, + {"₅", 0}, + {"9", 1}, + {"₉", 0}, + {"Cyrillic_IE", 1}, + {"Е̄", 0}, + {"0", 1}, + {"₀", 0}, + {"dead_diaeresis", 12}, + {"a", 1}, + {"ǟ", 0}, + {"o", 1}, + {"ȫ", 0}, + {"u", 1}, + {"ǖ", 0}, + {"O", 1}, + {"Ȫ", 0}, + {"A", 1}, + {"Ǟ", 0}, + {"U", 1}, + {"Ǖ", 0}, + {"Adiaeresis", 1}, + {"Ǟ", 0}, + {"parenleft", 1}, + {"₍", 0}, + {"udiaeresis", 1}, + {"ǖ", 0}, + {"I", 1}, + {"Ī", 0}, + {"U", 1}, + {"Ū", 0}, + {"Cyrillic_u", 1}, + {"ӯ", 0}, + {"ae", 1}, + {"ǣ", 0}, + {"asciicircum", 1}, + {"¯", 0}, + {"Greek_UPSILON", 1}, + {"Ῡ", 0}, + {"KP_Equal", 1}, + {"₌", 0}, + {"v", 8}, + {"l", 1}, + {"|", 0}, + {"z", 1}, + {"ž", 0}, + {"Z", 1}, + {"Ž", 0}, + {"slash", 1}, + {"√", 0}, + {"P", 8}, + {"period", 1}, + {"Ṗ", 0}, + {"exclam", 1}, + {"¶", 0}, + {"t", 1}, + {"₧", 0}, + {"P", 1}, + {"¶", 0}, + {"question", 106}, + {"dead_breve", 4}, + {"a", 1}, + {"ẳ", 0}, + {"A", 1}, + {"Ẳ", 0}, + {"a", 1}, + {"ả", 0}, + {"dead_circumflex", 12}, + {"a", 1}, + {"ẩ", 0}, + {"e", 1}, + {"ể", 0}, + {"o", 1}, + {"ổ", 0}, + {"E", 1}, + {"Ể", 0}, + {"O", 1}, + {"Ổ", 0}, + {"A", 1}, + {"Ẩ", 0}, + {"dead_horn", 8}, + {"o", 1}, + {"ở", 0}, + {"u", 1}, + {"ử", 0}, + {"O", 1}, + {"Ở", 0}, + {"U", 1}, + {"Ử", 0}, + {"Acircumflex", 1}, + {"Ẩ", 0}, + {"exclam", 1}, + {"⸘", 0}, + {"e", 1}, + {"ẻ", 0}, + {"o", 1}, + {"ỏ", 0}, + {"uhorn", 1}, + {"ử", 0}, + {"acircumflex", 1}, + {"ẩ", 0}, + {"Ecircumflex", 1}, + {"Ể", 0}, + {"y", 1}, + {"ỷ", 0}, + {"b", 4}, + {"a", 1}, + {"ẳ", 0}, + {"A", 1}, + {"Ẳ", 0}, + {"i", 1}, + {"ỉ", 0}, + {"Ohorn", 1}, + {"Ở", 0}, + {"ohorn", 1}, + {"ở", 0}, + {"Ocircumflex", 1}, + {"Ổ", 0}, + {"ocircumflex", 1}, + {"ổ", 0}, + {"u", 1}, + {"ủ", 0}, + {"E", 1}, + {"Ẻ", 0}, + {"Y", 1}, + {"Ỷ", 0}, + {"Abreve", 1}, + {"Ẳ", 0}, + {"plus", 8}, + {"o", 1}, + {"ở", 0}, + {"u", 1}, + {"ử", 0}, + {"O", 1}, + {"Ở", 0}, + {"U", 1}, + {"Ử", 0}, + {"ecircumflex", 1}, + {"ể", 0}, + {"question", 1}, + {"¿", 0}, + {"O", 1}, + {"Ỏ", 0}, + {"abreve", 1}, + {"ẳ", 0}, + {"A", 1}, + {"Ả", 0}, + {"Uhorn", 1}, + {"Ử", 0}, + {"I", 1}, + {"Ỉ", 0}, + {"U", 1}, + {"Ủ", 0}, + {"asciicircum", 12}, + {"a", 1}, + {"ẩ", 0}, + {"e", 1}, + {"ể", 0}, + {"o", 1}, + {"ổ", 0}, + {"E", 1}, + {"Ể", 0}, + {"O", 1}, + {"Ổ", 0}, + {"A", 1}, + {"Ẩ", 0}, + {"apostrophe", 470}, + {"W", 1}, + {"Ẃ", 0}, + {"dead_breve", 4}, + {"a", 1}, + {"ắ", 0}, + {"A", 1}, + {"Ắ", 0}, + {"g", 1}, + {"ǵ", 0}, + {"a", 1}, + {"á", 0}, + {"Greek_IOTA", 1}, + {"Ί", 0}, + {"Greek_iota", 1}, + {"ί", 0}, + {"dead_horn", 8}, + {"o", 1}, + {"ớ", 0}, + {"u", 1}, + {"ứ", 0}, + {"O", 1}, + {"Ớ", 0}, + {"U", 1}, + {"Ứ", 0}, + {"dead_circumflex", 12}, + {"a", 1}, + {"ấ", 0}, + {"e", 1}, + {"ế", 0}, + {"o", 1}, + {"ố", 0}, + {"E", 1}, + {"Ế", 0}, + {"O", 1}, + {"Ố", 0}, + {"A", 1}, + {"Ấ", 0}, + {"Greek_OMICRON", 1}, + {"Ό", 0}, + {"Acircumflex", 1}, + {"Ấ", 0}, + {"C", 1}, + {"Ć", 0}, + {"less", 1}, + {"‘", 0}, + {"Cyrillic_er", 1}, + {"р́", 0}, + {"e", 1}, + {"é", 0}, + {"KP_Divide", 4}, + {"o", 1}, + {"ǿ", 0}, + {"O", 1}, + {"Ǿ", 0}, + {"Utilde", 1}, + {"Ṹ", 0}, + {"o", 1}, + {"ó", 0}, + {"l", 1}, + {"ĺ", 0}, + {"Udiaeresis", 1}, + {"Ǘ", 0}, + {"Greek_upsilon", 1}, + {"ύ", 0}, + {"uhorn", 1}, + {"ứ", 0}, + {"space", 1}, + {"'", 0}, + {"dead_macron", 8}, + {"e", 1}, + {"ḗ", 0}, + {"o", 1}, + {"ṓ", 0}, + {"E", 1}, + {"Ḗ", 0}, + {"O", 1}, + {"Ṓ", 0}, + {"acircumflex", 1}, + {"ấ", 0}, + {"Ecircumflex", 1}, + {"Ế", 0}, + {"Cyrillic_I", 1}, + {"И́", 0}, + {"y", 1}, + {"ý", 0}, + {"b", 4}, + {"a", 1}, + {"ắ", 0}, + {"A", 1}, + {"Ắ", 0}, + {"idiaeresis", 1}, + {"ḯ", 0}, + {"Cyrillic_O", 1}, + {"О́", 0}, + {"i", 1}, + {"í", 0}, + {"k", 1}, + {"ḱ", 0}, + {"n", 1}, + {"ń", 0}, + {"ccedilla", 1}, + {"ḉ", 0}, + {"Cyrillic_GHE", 1}, + {"Ѓ", 0}, + {"dead_tilde", 8}, + {"o", 1}, + {"ṍ", 0}, + {"u", 1}, + {"ṹ", 0}, + {"O", 1}, + {"Ṍ", 0}, + {"U", 1}, + {"Ṹ", 0}, + {"Cyrillic_a", 1}, + {"а́", 0}, + {"parenright", 26}, + {"Greek_IOTA", 1}, + {"Ἴ", 0}, + {"Greek_iota", 1}, + {"ἴ", 0}, + {"Greek_OMICRON", 1}, + {"Ὄ", 0}, + {"Greek_upsilon", 1}, + {"ὔ", 0}, + {"Greek_epsilon", 1}, + {"ἔ", 0}, + {"Greek_ALPHA", 1}, + {"Ἄ", 0}, + {"Greek_omicron", 1}, + {"ὄ", 0}, + {"Greek_eta", 1}, + {"ἤ", 0}, + {"Greek_alpha", 1}, + {"ἄ", 0}, + {"Greek_ETA", 1}, + {"Ἤ", 0}, + {"Greek_EPSILON", 1}, + {"Ἔ", 0}, + {"Greek_omega", 1}, + {"ὤ", 0}, + {"Greek_OMEGA", 1}, + {"Ὤ", 0}, + {"Ohorn", 1}, + {"Ớ", 0}, + {"ohorn", 1}, + {"ớ", 0}, + {"Cyrillic_ER", 1}, + {"Р́", 0}, + {"Greek_epsilon", 1}, + {"έ", 0}, + {"Cyrillic_KA", 1}, + {"Ќ", 0}, + {"Cyrillic_U", 1}, + {"У́", 0}, + {"dead_abovering", 4}, + {"a", 1}, + {"ǻ", 0}, + {"A", 1}, + {"Ǻ", 0}, + {"Ocircumflex", 1}, + {"Ố", 0}, + {"AE", 1}, + {"Ǽ", 0}, + {"omacron", 1}, + {"ṓ", 0}, + {"ocircumflex", 1}, + {"ố", 0}, + {"u", 1}, + {"ú", 0}, + {"z", 1}, + {"ź", 0}, + {"G", 1}, + {"Ǵ", 0}, + {"Greek_ALPHA", 1}, + {"Ά", 0}, + {"otilde", 1}, + {"ṍ", 0}, + {"utilde", 1}, + {"ṹ", 0}, + {"Cyrillic_ie", 1}, + {"е́", 0}, + {"emacron", 1}, + {"ḗ", 0}, + {"E", 1}, + {"É", 0}, + {"S", 1}, + {"Ś", 0}, + {"Greek_iotadieresis", 1}, + {"ΐ", 0}, + {"Y", 1}, + {"Ý", 0}, + {"Cyrillic_i", 1}, + {"и́", 0}, + {"dead_dasia", 28}, + {"Greek_IOTA", 1}, + {"Ἵ", 0}, + {"Greek_iota", 1}, + {"ἵ", 0}, + {"Greek_OMICRON", 1}, + {"Ὅ", 0}, + {"Greek_upsilon", 1}, + {"ὕ", 0}, + {"Greek_epsilon", 1}, + {"ἕ", 0}, + {"Greek_ALPHA", 1}, + {"Ἅ", 0}, + {"Greek_omicron", 1}, + {"ὅ", 0}, + {"Greek_eta", 1}, + {"ἥ", 0}, + {"Greek_alpha", 1}, + {"ἅ", 0}, + {"Greek_ETA", 1}, + {"Ἥ", 0}, + {"Greek_EPSILON", 1}, + {"Ἕ", 0}, + {"Greek_omega", 1}, + {"ὥ", 0}, + {"Greek_OMEGA", 1}, + {"Ὥ", 0}, + {"Greek_UPSILON", 1}, + {"Ὕ", 0}, + {"Greek_upsilondieresis", 1}, + {"ΰ", 0}, + {"Greek_omicron", 1}, + {"ό", 0}, + {"Greek_eta", 1}, + {"ή", 0}, + {"Otilde", 1}, + {"Ṍ", 0}, + {"Cyrillic_ka", 1}, + {"ќ", 0}, + {"Aring", 1}, + {"Ǻ", 0}, + {"Abreve", 1}, + {"Ắ", 0}, + {"dead_psili", 26}, + {"Greek_IOTA", 1}, + {"Ἴ", 0}, + {"Greek_iota", 1}, + {"ἴ", 0}, + {"Greek_OMICRON", 1}, + {"Ὄ", 0}, + {"Greek_upsilon", 1}, + {"ὔ", 0}, + {"Greek_epsilon", 1}, + {"ἔ", 0}, + {"Greek_ALPHA", 1}, + {"Ἄ", 0}, + {"Greek_omicron", 1}, + {"ὄ", 0}, + {"Greek_eta", 1}, + {"ἤ", 0}, + {"Greek_alpha", 1}, + {"ἄ", 0}, + {"Greek_ETA", 1}, + {"Ἤ", 0}, + {"Greek_EPSILON", 1}, + {"Ἔ", 0}, + {"Greek_omega", 1}, + {"ὤ", 0}, + {"Greek_OMEGA", 1}, + {"Ὤ", 0}, + {"quotedbl", 14}, + {"Greek_iota", 1}, + {"ΐ", 0}, + {"Greek_upsilon", 1}, + {"ΰ", 0}, + {"space", 1}, + {"΅", 0}, + {"i", 1}, + {"ḯ", 0}, + {"u", 1}, + {"ǘ", 0}, + {"I", 1}, + {"Ḯ", 0}, + {"U", 1}, + {"Ǘ", 0}, + {"plus", 8}, + {"o", 1}, + {"ớ", 0}, + {"u", 1}, + {"ứ", 0}, + {"O", 1}, + {"Ớ", 0}, + {"U", 1}, + {"Ứ", 0}, + {"cedilla", 4}, + {"C", 1}, + {"Ḉ", 0}, + {"c", 1}, + {"ḉ", 0}, + {"Greek_alpha", 1}, + {"ά", 0}, + {"ecircumflex", 1}, + {"ế", 0}, + {"w", 1}, + {"ẃ", 0}, + {"Greek_ETA", 1}, + {"Ή", 0}, + {"Cyrillic_o", 1}, + {"о́", 0}, + {"Emacron", 1}, + {"Ḗ", 0}, + {"Ooblique", 1}, + {"Ǿ", 0}, + {"p", 1}, + {"ṕ", 0}, + {"underscore", 8}, + {"e", 1}, + {"ḗ", 0}, + {"o", 1}, + {"ṓ", 0}, + {"E", 1}, + {"Ḗ", 0}, + {"O", 1}, + {"Ṓ", 0}, + {"P", 1}, + {"Ṕ", 0}, + {"apostrophe", 1}, + {"´", 0}, + {"M", 1}, + {"Ḿ", 0}, + {"O", 1}, + {"Ó", 0}, + {"abreve", 1}, + {"ắ", 0}, + {"m", 1}, + {"ḿ", 0}, + {"r", 1}, + {"ŕ", 0}, + {"s", 1}, + {"ś", 0}, + {"Z", 1}, + {"Ź", 0}, + {"macron", 8}, + {"e", 1}, + {"ḗ", 0}, + {"o", 1}, + {"ṓ", 0}, + {"E", 1}, + {"Ḗ", 0}, + {"O", 1}, + {"Ṓ", 0}, + {"A", 1}, + {"Á", 0}, + {"R", 1}, + {"Ŕ", 0}, + {"c", 1}, + {"ć", 0}, + {"Idiaeresis", 1}, + {"Ḯ", 0}, + {"L", 1}, + {"Ĺ", 0}, + {"Greek_EPSILON", 1}, + {"Έ", 0}, + {"Cyrillic_A", 1}, + {"А́", 0}, + {"comma", 1}, + {"‚", 0}, + {"asciitilde", 8}, + {"o", 1}, + {"ṍ", 0}, + {"u", 1}, + {"ṹ", 0}, + {"O", 1}, + {"Ṍ", 0}, + {"U", 1}, + {"Ṹ", 0}, + {"Ccedilla", 1}, + {"Ḉ", 0}, + {"slash", 4}, + {"o", 1}, + {"ǿ", 0}, + {"O", 1}, + {"Ǿ", 0}, + {"aring", 1}, + {"ǻ", 0}, + {"greater", 1}, + {"’", 0}, + {"K", 1}, + {"Ḱ", 0}, + {"Omacron", 1}, + {"Ṓ", 0}, + {"Cyrillic_IE", 1}, + {"Е́", 0}, + {"dead_cedilla", 4}, + {"C", 1}, + {"Ḉ", 0}, + {"c", 1}, + {"ḉ", 0}, + {"Greek_omega", 1}, + {"ώ", 0}, + {"dead_diaeresis", 12}, + {"Greek_iota", 1}, + {"ΐ", 0}, + {"Greek_upsilon", 1}, + {"ΰ", 0}, + {"i", 1}, + {"ḯ", 0}, + {"u", 1}, + {"ǘ", 0}, + {"I", 1}, + {"Ḯ", 0}, + {"U", 1}, + {"Ǘ", 0}, + {"Uhorn", 1}, + {"Ứ", 0}, + {"Greek_OMEGA", 1}, + {"Ώ", 0}, + {"oslash", 1}, + {"ǿ", 0}, + {"Cyrillic_ghe", 1}, + {"ѓ", 0}, + {"parenleft", 28}, + {"Greek_IOTA", 1}, + {"Ἵ", 0}, + {"Greek_iota", 1}, + {"ἵ", 0}, + {"Greek_OMICRON", 1}, + {"Ὅ", 0}, + {"Greek_upsilon", 1}, + {"ὕ", 0}, + {"Greek_epsilon", 1}, + {"ἕ", 0}, + {"Greek_ALPHA", 1}, + {"Ἅ", 0}, + {"Greek_omicron", 1}, + {"ὅ", 0}, + {"Greek_eta", 1}, + {"ἥ", 0}, + {"Greek_alpha", 1}, + {"ἅ", 0}, + {"Greek_ETA", 1}, + {"Ἥ", 0}, + {"Greek_EPSILON", 1}, + {"Ἕ", 0}, + {"Greek_omega", 1}, + {"ὥ", 0}, + {"Greek_OMEGA", 1}, + {"Ὥ", 0}, + {"Greek_UPSILON", 1}, + {"Ὕ", 0}, + {"udiaeresis", 1}, + {"ǘ", 0}, + {"I", 1}, + {"Í", 0}, + {"N", 1}, + {"Ń", 0}, + {"U", 1}, + {"Ú", 0}, + {"Cyrillic_u", 1}, + {"у́", 0}, + {"ae", 1}, + {"ǽ", 0}, + {"asciicircum", 12}, + {"a", 1}, + {"ấ", 0}, + {"e", 1}, + {"ế", 0}, + {"o", 1}, + {"ố", 0}, + {"E", 1}, + {"Ế", 0}, + {"O", 1}, + {"Ố", 0}, + {"A", 1}, + {"Ấ", 0}, + {"Greek_UPSILON", 1}, + {"Ύ", 0}, + {"M", 2}, + {"period", 1}, + {"Ṁ", 0}, + {"O", 40}, + {"minus", 1}, + {"Ō", 0}, + {"C", 1}, + {"©", 0}, + {"diaeresis", 1}, + {"Ö", 0}, + {"x", 1}, + {"¤", 0}, + {"E", 1}, + {"Œ", 0}, + {"S", 1}, + {"§", 0}, + {"quotedbl", 1}, + {"Ö", 0}, + {"acute", 1}, + {"Ó", 0}, + {"underscore", 1}, + {"Ō", 0}, + {"apostrophe", 1}, + {"Ó", 0}, + {"r", 1}, + {"®", 0}, + {"A", 1}, + {"Ⓐ", 0}, + {"R", 1}, + {"®", 0}, + {"c", 1}, + {"©", 0}, + {"asciitilde", 1}, + {"Õ", 0}, + {"slash", 1}, + {"Ø", 0}, + {"greater", 1}, + {"Ô", 0}, + {"X", 1}, + {"¤", 0}, + {"grave", 1}, + {"Ò", 0}, + {"asciicircum", 1}, + {"Ô", 0}, + {"m", 6}, + {"period", 1}, + {"ṁ", 0}, + {"u", 1}, + {"µ", 0}, + {"slash", 1}, + {"₥", 0}, + {"r", 6}, + {"less", 1}, + {"ř", 0}, + {"apostrophe", 1}, + {"ŕ", 0}, + {"comma", 1}, + {"ŗ", 0}, + {"s", 20}, + {"period", 1}, + {"ṡ", 0}, + {"exclam", 1}, + {"§", 0}, + {"less", 1}, + {"š", 0}, + {"o", 1}, + {"§", 0}, + {"cedilla", 1}, + {"ş", 0}, + {"apostrophe", 1}, + {"ś", 0}, + {"M", 1}, + {"℠", 0}, + {"m", 1}, + {"℠", 0}, + {"s", 1}, + {"ß", 0}, + {"comma", 1}, + {"ş", 0}, + {"asterisk", 17}, + {"a", 1}, + {"å", 0}, + {"diaeresis", 1}, + {"⍣", 0}, + {"u", 1}, + {"ů", 0}, + {"apostrophe", 4}, + {"a", 1}, + {"ǻ", 0}, + {"A", 1}, + {"Ǻ", 0}, + {"A", 1}, + {"Å", 0}, + {"0", 1}, + {"°", 0}, + {"U", 1}, + {"Ů", 0}, + {"Z", 6}, + {"period", 1}, + {"Ż", 0}, + {"less", 1}, + {"Ž", 0}, + {"apostrophe", 1}, + {"Ź", 0}, + {"bar", 6}, + {"C", 1}, + {"¢", 0}, + {"c", 1}, + {"¢", 0}, + {"asciitilde", 1}, + {"⍭", 0}, + {"macron", 166}, + {"adiaeresis", 1}, + {"ǟ", 0}, + {"period", 8}, + {"a", 1}, + {"ǡ", 0}, + {"o", 1}, + {"ȱ", 0}, + {"O", 1}, + {"Ȱ", 0}, + {"A", 1}, + {"Ǡ", 0}, + {"g", 1}, + {"ḡ", 0}, + {"a", 1}, + {"ā", 0}, + {"Greek_IOTA", 1}, + {"Ῑ", 0}, + {"Greek_iota", 1}, + {"ῑ", 0}, + {"exclam", 8}, + {"l", 1}, + {"ḹ", 0}, + {"r", 1}, + {"ṝ", 0}, + {"R", 1}, + {"Ṝ", 0}, + {"L", 1}, + {"Ḹ", 0}, + {"Cyrillic_er", 1}, + {"р̄", 0}, + {"e", 1}, + {"ē", 0}, + {"o", 1}, + {"ō", 0}, + {"Udiaeresis", 1}, + {"Ǖ", 0}, + {"Greek_upsilon", 1}, + {"ῡ", 0}, + {"dead_belowdot", 8}, + {"l", 1}, + {"ḹ", 0}, + {"r", 1}, + {"ṝ", 0}, + {"R", 1}, + {"Ṝ", 0}, + {"L", 1}, + {"Ḹ", 0}, + {"Cyrillic_I", 1}, + {"Ӣ", 0}, + {"y", 1}, + {"ȳ", 0}, + {"Cyrillic_O", 1}, + {"О̄", 0}, + {"i", 1}, + {"ī", 0}, + {"dead_tilde", 4}, + {"o", 1}, + {"ȭ", 0}, + {"O", 1}, + {"Ȭ", 0}, + {"Cyrillic_a", 1}, + {"а̄", 0}, + {"Cyrillic_ER", 1}, + {"Р̄", 0}, + {"Cyrillic_U", 1}, + {"Ӯ", 0}, + {"AE", 1}, + {"Ǣ", 0}, + {"u", 1}, + {"ū", 0}, + {"G", 1}, + {"Ḡ", 0}, + {"Greek_ALPHA", 1}, + {"Ᾱ", 0}, + {"otilde", 1}, + {"ȭ", 0}, + {"Cyrillic_ie", 1}, + {"е̄", 0}, + {"E", 1}, + {"Ē", 0}, + {"Y", 1}, + {"Ȳ", 0}, + {"Cyrillic_i", 1}, + {"ӣ", 0}, + {"dead_ogonek", 4}, + {"o", 1}, + {"ǭ", 0}, + {"O", 1}, + {"Ǭ", 0}, + {"odiaeresis", 1}, + {"ȫ", 0}, + {"Otilde", 1}, + {"Ȭ", 0}, + {"quotedbl", 12}, + {"a", 1}, + {"ǟ", 0}, + {"o", 1}, + {"ȫ", 0}, + {"u", 1}, + {"ǖ", 0}, + {"O", 1}, + {"Ȫ", 0}, + {"A", 1}, + {"Ǟ", 0}, + {"U", 1}, + {"Ǖ", 0}, + {"Greek_alpha", 1}, + {"ᾱ", 0}, + {"dead_abovedot", 8}, + {"a", 1}, + {"ǡ", 0}, + {"o", 1}, + {"ȱ", 0}, + {"O", 1}, + {"Ȱ", 0}, + {"A", 1}, + {"Ǡ", 0}, + {"Cyrillic_o", 1}, + {"о̄", 0}, + {"O", 1}, + {"Ō", 0}, + {"A", 1}, + {"Ā", 0}, + {"Odiaeresis", 1}, + {"Ȫ", 0}, + {"Cyrillic_A", 1}, + {"А̄", 0}, + {"asciitilde", 4}, + {"o", 1}, + {"ȭ", 0}, + {"O", 1}, + {"Ȭ", 0}, + {"semicolon", 4}, + {"o", 1}, + {"ǭ", 0}, + {"O", 1}, + {"Ǭ", 0}, + {"Cyrillic_IE", 1}, + {"Е̄", 0}, + {"dead_diaeresis", 12}, + {"a", 1}, + {"ǟ", 0}, + {"o", 1}, + {"ȫ", 0}, + {"u", 1}, + {"ǖ", 0}, + {"O", 1}, + {"Ȫ", 0}, + {"A", 1}, + {"Ǟ", 0}, + {"U", 1}, + {"Ǖ", 0}, + {"Adiaeresis", 1}, + {"Ǟ", 0}, + {"udiaeresis", 1}, + {"ǖ", 0}, + {"I", 1}, + {"Ī", 0}, + {"U", 1}, + {"Ū", 0}, + {"Cyrillic_u", 1}, + {"ӯ", 0}, + {"ae", 1}, + {"ǣ", 0}, + {"Greek_UPSILON", 1}, + {"Ῡ", 0}, + {"A", 32}, + {"minus", 1}, + {"Ā", 0}, + {"diaeresis", 1}, + {"Ä", 0}, + {"E", 1}, + {"Æ", 0}, + {"quotedbl", 1}, + {"Ä", 0}, + {"acute", 1}, + {"Á", 0}, + {"underscore", 1}, + {"Ā", 0}, + {"apostrophe", 1}, + {"Á", 0}, + {"asterisk", 1}, + {"Å", 0}, + {"A", 1}, + {"Å", 0}, + {"comma", 1}, + {"Ą", 0}, + {"T", 1}, + {"@", 0}, + {"asciitilde", 1}, + {"Ã", 0}, + {"greater", 1}, + {"Â", 0}, + {"parenleft", 1}, + {"Ă", 0}, + {"grave", 1}, + {"À", 0}, + {"asciicircum", 1}, + {"Â", 0}, + {"R", 10}, + {"less", 1}, + {"Ř", 0}, + {"apostrophe", 1}, + {"Ŕ", 0}, + {"O", 1}, + {"®", 0}, + {"s", 1}, + {"₨", 0}, + {"comma", 1}, + {"Ŗ", 0}, + {"Cyrillic_ES", 2}, + {"equal", 1}, + {"€", 0}, + {"c", 98}, + {"period", 1}, + {"ċ", 0}, + {"g", 1}, + {"ǧ", 0}, + {"a", 1}, + {"ǎ", 0}, + {"ezh", 1}, + {"ǯ", 0}, + {"C", 1}, + {"Č", 0}, + {"less", 1}, + {"č", 0}, + {"e", 1}, + {"ě", 0}, + {"o", 1}, + {"ǒ", 0}, + {"l", 1}, + {"ľ", 0}, + {"Udiaeresis", 1}, + {"Ǚ", 0}, + {"t", 1}, + {"ť", 0}, + {"i", 1}, + {"ǐ", 0}, + {"k", 1}, + {"ǩ", 0}, + {"n", 1}, + {"ň", 0}, + {"equal", 1}, + {"€", 0}, + {"j", 1}, + {"ǰ", 0}, + {"u", 1}, + {"ǔ", 0}, + {"z", 1}, + {"ž", 0}, + {"G", 1}, + {"Ǧ", 0}, + {"H", 1}, + {"Ȟ", 0}, + {"E", 1}, + {"Ě", 0}, + {"S", 1}, + {"Š", 0}, + {"d", 1}, + {"ď", 0}, + {"D", 1}, + {"Ď", 0}, + {"quotedbl", 4}, + {"u", 1}, + {"ǚ", 0}, + {"U", 1}, + {"Ǚ", 0}, + {"apostrophe", 1}, + {"ć", 0}, + {"O", 1}, + {"Ǒ", 0}, + {"r", 1}, + {"ř", 0}, + {"s", 1}, + {"š", 0}, + {"Z", 1}, + {"Ž", 0}, + {"bar", 1}, + {"¢", 0}, + {"EZH", 1}, + {"Ǯ", 0}, + {"A", 1}, + {"Ǎ", 0}, + {"R", 1}, + {"Ř", 0}, + {"c", 1}, + {"č", 0}, + {"L", 1}, + {"Ľ", 0}, + {"comma", 1}, + {"ç", 0}, + {"T", 1}, + {"Ť", 0}, + {"slash", 1}, + {"¢", 0}, + {"K", 1}, + {"Ǩ", 0}, + {"dead_diaeresis", 4}, + {"u", 1}, + {"ǚ", 0}, + {"U", 1}, + {"Ǚ", 0}, + {"h", 1}, + {"ȟ", 0}, + {"udiaeresis", 1}, + {"ǚ", 0}, + {"I", 1}, + {"Ǐ", 0}, + {"N", 1}, + {"Ň", 0}, + {"U", 1}, + {"Ǔ", 0}, + {"numbersign", 14}, + {"e", 1}, + {"♪", 0}, + {"b", 1}, + {"♭", 0}, + {"q", 1}, + {"♩", 0}, + {"E", 1}, + {"♫", 0}, + {"S", 1}, + {"♬", 0}, + {"f", 1}, + {"♮", 0}, + {"numbersign", 1}, + {"♯", 0}, + {"L", 14}, + {"minus", 1}, + {"£", 0}, + {"less", 1}, + {"Ľ", 0}, + {"equal", 1}, + {"₤", 0}, + {"V", 1}, + {"|", 0}, + {"apostrophe", 1}, + {"Ĺ", 0}, + {"comma", 1}, + {"Ļ", 0}, + {"slash", 1}, + {"Ł", 0}, + {"Greek_EPSILON", 2}, + {"apostrophe", 1}, + {"Έ", 0}, + {"comma", 66}, + {"minus", 1}, + {"¬", 0}, + {"g", 1}, + {"ģ", 0}, + {"a", 1}, + {"ą", 0}, + {"C", 1}, + {"Ç", 0}, + {"e", 1}, + {"ę", 0}, + {"l", 1}, + {"ļ", 0}, + {"t", 1}, + {"ţ", 0}, + {"space", 1}, + {"¸", 0}, + {"i", 1}, + {"į", 0}, + {"k", 1}, + {"ķ", 0}, + {"n", 1}, + {"ņ", 0}, + {"u", 1}, + {"ų", 0}, + {"G", 1}, + {"Ģ", 0}, + {"H", 1}, + {"Ḩ", 0}, + {"E", 1}, + {"Ę", 0}, + {"S", 1}, + {"Ş", 0}, + {"d", 1}, + {"ḑ", 0}, + {"D", 1}, + {"Ḑ", 0}, + {"quotedbl", 1}, + {"„", 0}, + {"apostrophe", 1}, + {"‚", 0}, + {"r", 1}, + {"ŗ", 0}, + {"s", 1}, + {"ş", 0}, + {"A", 1}, + {"Ą", 0}, + {"R", 1}, + {"Ŗ", 0}, + {"c", 1}, + {"ç", 0}, + {"L", 1}, + {"Ļ", 0}, + {"comma", 1}, + {"¸", 0}, + {"T", 1}, + {"Ţ", 0}, + {"K", 1}, + {"Ķ", 0}, + {"h", 1}, + {"ḩ", 0}, + {"I", 1}, + {"Į", 0}, + {"N", 1}, + {"Ņ", 0}, + {"U", 1}, + {"Ų", 0}, + {"T", 16}, + {"minus", 1}, + {"Ŧ", 0}, + {"period", 1}, + {"Ṫ", 0}, + {"less", 1}, + {"Ť", 0}, + {"H", 1}, + {"Þ", 0}, + {"M", 1}, + {"™", 0}, + {"m", 1}, + {"™", 0}, + {"comma", 1}, + {"Ţ", 0}, + {"slash", 1}, + {"Ŧ", 0}, + {"asciitilde", 222}, + {"dead_breve", 4}, + {"a", 1}, + {"ẵ", 0}, + {"A", 1}, + {"Ẵ", 0}, + {"a", 1}, + {"ã", 0}, + {"Greek_iota", 1}, + {"ῖ", 0}, + {"dead_horn", 8}, + {"o", 1}, + {"ỡ", 0}, + {"u", 1}, + {"ữ", 0}, + {"O", 1}, + {"Ỡ", 0}, + {"U", 1}, + {"Ữ", 0}, + {"dead_circumflex", 12}, + {"a", 1}, + {"ẫ", 0}, + {"e", 1}, + {"ễ", 0}, + {"o", 1}, + {"ỗ", 0}, + {"E", 1}, + {"Ễ", 0}, + {"O", 1}, + {"Ỗ", 0}, + {"A", 1}, + {"Ẫ", 0}, + {"Acircumflex", 1}, + {"Ẫ", 0}, + {"e", 1}, + {"ẽ", 0}, + {"o", 1}, + {"õ", 0}, + {"Greek_upsilon", 1}, + {"ῦ", 0}, + {"diaeresis", 1}, + {"⍨", 0}, + {"uhorn", 1}, + {"ữ", 0}, + {"space", 1}, + {"~", 0}, + {"acircumflex", 1}, + {"ẫ", 0}, + {"Ecircumflex", 1}, + {"Ễ", 0}, + {"y", 1}, + {"ỹ", 0}, + {"b", 4}, + {"a", 1}, + {"ẵ", 0}, + {"A", 1}, + {"Ẵ", 0}, + {"i", 1}, + {"ĩ", 0}, + {"n", 1}, + {"ñ", 0}, + {"parenright", 18}, + {"Greek_IOTA", 1}, + {"Ἶ", 0}, + {"Greek_iota", 1}, + {"ἶ", 0}, + {"Greek_upsilon", 1}, + {"ὖ", 0}, + {"Greek_ALPHA", 1}, + {"Ἆ", 0}, + {"Greek_eta", 1}, + {"ἦ", 0}, + {"Greek_alpha", 1}, + {"ἆ", 0}, + {"Greek_ETA", 1}, + {"Ἦ", 0}, + {"Greek_omega", 1}, + {"ὦ", 0}, + {"Greek_OMEGA", 1}, + {"Ὦ", 0}, + {"Ohorn", 1}, + {"Ỡ", 0}, + {"ohorn", 1}, + {"ỡ", 0}, + {"Ocircumflex", 1}, + {"Ỗ", 0}, + {"V", 1}, + {"Ṽ", 0}, + {"ocircumflex", 1}, + {"ỗ", 0}, + {"u", 1}, + {"ũ", 0}, + {"E", 1}, + {"Ẽ", 0}, + {"Greek_iotadieresis", 1}, + {"ῗ", 0}, + {"Y", 1}, + {"Ỹ", 0}, + {"dead_dasia", 20}, + {"Greek_IOTA", 1}, + {"Ἷ", 0}, + {"Greek_iota", 1}, + {"ἷ", 0}, + {"Greek_upsilon", 1}, + {"ὗ", 0}, + {"Greek_ALPHA", 1}, + {"Ἇ", 0}, + {"Greek_eta", 1}, + {"ἧ", 0}, + {"Greek_alpha", 1}, + {"ἇ", 0}, + {"Greek_ETA", 1}, + {"Ἧ", 0}, + {"Greek_omega", 1}, + {"ὧ", 0}, + {"Greek_OMEGA", 1}, + {"Ὧ", 0}, + {"Greek_UPSILON", 1}, + {"Ὗ", 0}, + {"Greek_upsilondieresis", 1}, + {"ῧ", 0}, + {"Greek_eta", 1}, + {"ῆ", 0}, + {"Abreve", 1}, + {"Ẵ", 0}, + {"dead_psili", 18}, + {"Greek_IOTA", 1}, + {"Ἶ", 0}, + {"Greek_iota", 1}, + {"ἶ", 0}, + {"Greek_upsilon", 1}, + {"ὖ", 0}, + {"Greek_ALPHA", 1}, + {"Ἆ", 0}, + {"Greek_eta", 1}, + {"ἦ", 0}, + {"Greek_alpha", 1}, + {"ἆ", 0}, + {"Greek_ETA", 1}, + {"Ἦ", 0}, + {"Greek_omega", 1}, + {"ὦ", 0}, + {"Greek_OMEGA", 1}, + {"Ὦ", 0}, + {"quotedbl", 4}, + {"Greek_iota", 1}, + {"ῗ", 0}, + {"Greek_upsilon", 1}, + {"ῧ", 0}, + {"plus", 8}, + {"o", 1}, + {"ỡ", 0}, + {"u", 1}, + {"ữ", 0}, + {"O", 1}, + {"Ỡ", 0}, + {"U", 1}, + {"Ữ", 0}, + {"Greek_alpha", 1}, + {"ᾶ", 0}, + {"ecircumflex", 1}, + {"ễ", 0}, + {"v", 1}, + {"ṽ", 0}, + {"O", 1}, + {"Õ", 0}, + {"abreve", 1}, + {"ẵ", 0}, + {"bar", 1}, + {"⍭", 0}, + {"A", 1}, + {"Ã", 0}, + {"0", 1}, + {"⍬", 0}, + {"Greek_omega", 1}, + {"ῶ", 0}, + {"dead_diaeresis", 4}, + {"Greek_iota", 1}, + {"ῗ", 0}, + {"Greek_upsilon", 1}, + {"ῧ", 0}, + {"Uhorn", 1}, + {"Ữ", 0}, + {"parenleft", 20}, + {"Greek_IOTA", 1}, + {"Ἷ", 0}, + {"Greek_iota", 1}, + {"ἷ", 0}, + {"Greek_upsilon", 1}, + {"ὗ", 0}, + {"Greek_ALPHA", 1}, + {"Ἇ", 0}, + {"Greek_eta", 1}, + {"ἧ", 0}, + {"Greek_alpha", 1}, + {"ἇ", 0}, + {"Greek_ETA", 1}, + {"Ἧ", 0}, + {"Greek_omega", 1}, + {"ὧ", 0}, + {"Greek_OMEGA", 1}, + {"Ὧ", 0}, + {"Greek_UPSILON", 1}, + {"Ὗ", 0}, + {"I", 1}, + {"Ĩ", 0}, + {"N", 1}, + {"Ñ", 0}, + {"U", 1}, + {"Ũ", 0}, + {"asciicircum", 12}, + {"a", 1}, + {"ẫ", 0}, + {"e", 1}, + {"ễ", 0}, + {"o", 1}, + {"ỗ", 0}, + {"E", 1}, + {"Ễ", 0}, + {"O", 1}, + {"Ỗ", 0}, + {"A", 1}, + {"Ẫ", 0}, + {"slash", 66}, + {"minus", 1}, + {"⌿", 0}, + {"g", 1}, + {"ǥ", 0}, + {"C", 1}, + {"₡", 0}, + {"less", 1}, + {"\\", 0}, + {"o", 1}, + {"ø", 0}, + {"l", 1}, + {"ł", 0}, + {"t", 1}, + {"ŧ", 0}, + {"b", 1}, + {"ƀ", 0}, + {"i", 1}, + {"ɨ", 0}, + {"equal", 1}, + {"≠", 0}, + {"Cyrillic_GHE", 1}, + {"Ғ", 0}, + {"leftarrow", 1}, + {"↚", 0}, + {"Cyrillic_KA", 1}, + {"Ҟ", 0}, + {"u", 1}, + {"µ", 0}, + {"rightarrow", 1}, + {"↛", 0}, + {"z", 1}, + {"ƶ", 0}, + {"G", 1}, + {"Ǥ", 0}, + {"H", 1}, + {"Ħ", 0}, + {"d", 1}, + {"đ", 0}, + {"Cyrillic_ka", 1}, + {"ҟ", 0}, + {"D", 1}, + {"Đ", 0}, + {"v", 1}, + {"√", 0}, + {"O", 1}, + {"Ø", 0}, + {"m", 1}, + {"₥", 0}, + {"Z", 1}, + {"Ƶ", 0}, + {"c", 1}, + {"¢", 0}, + {"L", 1}, + {"Ł", 0}, + {"T", 1}, + {"Ŧ", 0}, + {"slash", 1}, + {"\\", 0}, + {"Cyrillic_ghe", 1}, + {"ғ", 0}, + {"h", 1}, + {"ħ", 0}, + {"I", 1}, + {"Ɨ", 0}, + {"asciicircum", 1}, + {"|", 0}, + {"5", 4}, + {"8", 1}, + {"⅝", 0}, + {"6", 1}, + {"⅚", 0}, + {"Cyrillic_EN", 4}, + {"Cyrillic_O", 1}, + {"№", 0}, + {"Cyrillic_o", 1}, + {"№", 0}, + {"greater", 36}, + {"a", 1}, + {"â", 0}, + {"less", 1}, + {"⋄", 0}, + {"e", 1}, + {"ê", 0}, + {"o", 1}, + {"ô", 0}, + {"diaeresis", 1}, + {"⍩", 0}, + {"space", 1}, + {"^", 0}, + {"i", 1}, + {"î", 0}, + {"equal", 1}, + {"≥", 0}, + {"u", 1}, + {"û", 0}, + {"E", 1}, + {"Ê", 0}, + {"quotedbl", 1}, + {"”", 0}, + {"underscore", 1}, + {"≥", 0}, + {"apostrophe", 1}, + {"’", 0}, + {"O", 1}, + {"Ô", 0}, + {"A", 1}, + {"Â", 0}, + {"greater", 1}, + {"»", 0}, + {"I", 1}, + {"Î", 0}, + {"U", 1}, + {"Û", 0}, + {"semicolon", 22}, + {"a", 1}, + {"ą", 0}, + {"e", 1}, + {"ę", 0}, + {"o", 1}, + {"ǫ", 0}, + {"i", 1}, + {"į", 0}, + {"u", 1}, + {"ų", 0}, + {"E", 1}, + {"Ę", 0}, + {"underscore", 1}, + {"⍮", 0}, + {"O", 1}, + {"Ǫ", 0}, + {"A", 1}, + {"Ą", 0}, + {"I", 1}, + {"Į", 0}, + {"U", 1}, + {"Ų", 0}, + {"K", 2}, + {"comma", 1}, + {"Ķ", 0}, + {"Cyrillic_IE", 2}, + {"equal", 1}, + {"€", 0}, + {"B", 2}, + {"period", 1}, + {"Ḃ", 0}, + {"0", 6}, + {"3", 1}, + {"↉", 0}, + {"asterisk", 1}, + {"°", 0}, + {"asciitilde", 1}, + {"⍬", 0}, + {"Greek_omega", 2}, + {"apostrophe", 1}, + {"ώ", 0}, + {"Greek_OMEGA", 2}, + {"apostrophe", 1}, + {"Ώ", 0}, + {"X", 4}, + {"o", 1}, + {"¤", 0}, + {"O", 1}, + {"¤", 0}, + {"parenleft", 971}, + {"minus", 1}, + {"{", 0}, + {"W", 2}, + {"parenright", 1}, + {"Ⓦ", 0}, + {"g", 2}, + {"parenright", 1}, + {"ⓖ", 0}, + {"kana_KE", 2}, + {"parenright", 1}, + {"㋘", 0}, + {"a", 2}, + {"parenright", 1}, + {"ⓐ", 0}, + {"Greek_IOTA", 1}, + {"Ἱ", 0}, + {"Greek_iota", 1}, + {"ἱ", 0}, + {"1", 65}, + {"1", 2}, + {"parenright", 1}, + {"⑪", 0}, + {"KP_4", 2}, + {"parenright", 1}, + {"⑭", 0}, + {"KP_6", 2}, + {"parenright", 1}, + {"⑯", 0}, + {"KP_8", 2}, + {"parenright", 1}, + {"⑱", 0}, + {"KP_9", 2}, + {"parenright", 1}, + {"⑲", 0}, + {"KP_Space", 2}, + {"parenright", 1}, + {"⑫", 0}, + {"7", 2}, + {"parenright", 1}, + {"⑰", 0}, + {"parenright", 1}, + {"①", 0}, + {"KP_7", 2}, + {"parenright", 1}, + {"⑰", 0}, + {"8", 2}, + {"parenright", 1}, + {"⑱", 0}, + {"KP_1", 2}, + {"parenright", 1}, + {"⑪", 0}, + {"3", 2}, + {"parenright", 1}, + {"⑬", 0}, + {"2", 2}, + {"parenright", 1}, + {"⑫", 0}, + {"6", 2}, + {"parenright", 1}, + {"⑯", 0}, + {"4", 2}, + {"parenright", 1}, + {"⑭", 0}, + {"KP_3", 2}, + {"parenright", 1}, + {"⑬", 0}, + {"KP_0", 2}, + {"parenright", 1}, + {"⑩", 0}, + {"KP_2", 2}, + {"parenright", 1}, + {"⑫", 0}, + {"5", 2}, + {"parenright", 1}, + {"⑮", 0}, + {"KP_5", 2}, + {"parenright", 1}, + {"⑮", 0}, + {"9", 2}, + {"parenright", 1}, + {"⑲", 0}, + {"0", 2}, + {"parenright", 1}, + {"⑩", 0}, + {"Greek_OMICRON", 1}, + {"Ὁ", 0}, + {"C", 2}, + {"parenright", 1}, + {"Ⓒ", 0}, + {"KP_4", 65}, + {"1", 2}, + {"parenright", 1}, + {"㊶", 0}, + {"KP_4", 2}, + {"parenright", 1}, + {"㊹", 0}, + {"KP_6", 2}, + {"parenright", 1}, + {"㊻", 0}, + {"KP_8", 2}, + {"parenright", 1}, + {"㊽", 0}, + {"KP_9", 2}, + {"parenright", 1}, + {"㊾", 0}, + {"KP_Space", 2}, + {"parenright", 1}, + {"㊷", 0}, + {"7", 2}, + {"parenright", 1}, + {"㊼", 0}, + {"parenright", 1}, + {"④", 0}, + {"KP_7", 2}, + {"parenright", 1}, + {"㊼", 0}, + {"8", 2}, + {"parenright", 1}, + {"㊽", 0}, + {"KP_1", 2}, + {"parenright", 1}, + {"㊶", 0}, + {"3", 2}, + {"parenright", 1}, + {"㊸", 0}, + {"2", 2}, + {"parenright", 1}, + {"㊷", 0}, + {"6", 2}, + {"parenright", 1}, + {"㊻", 0}, + {"4", 2}, + {"parenright", 1}, + {"㊹", 0}, + {"KP_3", 2}, + {"parenright", 1}, + {"㊸", 0}, + {"KP_0", 2}, + {"parenright", 1}, + {"㊵", 0}, + {"KP_2", 2}, + {"parenright", 1}, + {"㊷", 0}, + {"5", 2}, + {"parenright", 1}, + {"㊺", 0}, + {"KP_5", 2}, + {"parenright", 1}, + {"㊺", 0}, + {"9", 2}, + {"parenright", 1}, + {"㊾", 0}, + {"0", 2}, + {"parenright", 1}, + {"㊵", 0}, + {"kana_SA", 2}, + {"parenright", 1}, + {"㋚", 0}, + {"e", 2}, + {"parenright", 1}, + {"ⓔ", 0}, + {"F", 2}, + {"parenright", 1}, + {"Ⓕ", 0}, + {"KP_6", 2}, + {"parenright", 1}, + {"⑥", 0}, + {"o", 2}, + {"parenright", 1}, + {"ⓞ", 0}, + {"l", 2}, + {"parenright", 1}, + {"ⓛ", 0}, + {"kana_SE", 2}, + {"parenright", 1}, + {"㋝", 0}, + {"kana_SU", 2}, + {"parenright", 1}, + {"㋜", 0}, + {"t", 2}, + {"parenright", 1}, + {"ⓣ", 0}, + {"kana_ME", 2}, + {"parenright", 1}, + {"㋱", 0}, + {"Greek_upsilon", 1}, + {"ὑ", 0}, + {"kana_WO", 2}, + {"parenright", 1}, + {"㋾", 0}, + {"space", 1}, + {"˘", 0}, + {"KP_8", 2}, + {"parenright", 1}, + {"⑧", 0}, + {"Greek_RHO", 1}, + {"Ῥ", 0}, + {"Q", 2}, + {"parenright", 1}, + {"Ⓠ", 0}, + {"y", 2}, + {"parenright", 1}, + {"ⓨ", 0}, + {"b", 2}, + {"parenright", 1}, + {"ⓑ", 0}, + {"kana_YO", 2}, + {"parenright", 1}, + {"㋵", 0}, + {"i", 2}, + {"parenright", 1}, + {"ⓘ", 0}, + {"kana_MA", 2}, + {"parenright", 1}, + {"㋮", 0}, + {"k", 2}, + {"parenright", 1}, + {"ⓚ", 0}, + {"n", 2}, + {"parenright", 1}, + {"ⓝ", 0}, + {"KP_9", 2}, + {"parenright", 1}, + {"⑨", 0}, + {"KP_Space", 65}, + {"1", 2}, + {"parenright", 1}, + {"㉑", 0}, + {"KP_4", 2}, + {"parenright", 1}, + {"㉔", 0}, + {"KP_6", 2}, + {"parenright", 1}, + {"㉖", 0}, + {"KP_8", 2}, + {"parenright", 1}, + {"㉘", 0}, + {"KP_9", 2}, + {"parenright", 1}, + {"㉙", 0}, + {"KP_Space", 2}, + {"parenright", 1}, + {"㉒", 0}, + {"7", 2}, + {"parenright", 1}, + {"㉗", 0}, + {"parenright", 1}, + {"②", 0}, + {"KP_7", 2}, + {"parenright", 1}, + {"㉗", 0}, + {"8", 2}, + {"parenright", 1}, + {"㉘", 0}, + {"KP_1", 2}, + {"parenright", 1}, + {"㉑", 0}, + {"3", 2}, + {"parenright", 1}, + {"㉓", 0}, + {"2", 2}, + {"parenright", 1}, + {"㉒", 0}, + {"6", 2}, + {"parenright", 1}, + {"㉖", 0}, + {"4", 2}, + {"parenright", 1}, + {"㉔", 0}, + {"KP_3", 2}, + {"parenright", 1}, + {"㉓", 0}, + {"KP_0", 2}, + {"parenright", 1}, + {"⑳", 0}, + {"KP_2", 2}, + {"parenright", 1}, + {"㉒", 0}, + {"5", 2}, + {"parenright", 1}, + {"㉕", 0}, + {"KP_5", 2}, + {"parenright", 1}, + {"㉕", 0}, + {"9", 2}, + {"parenright", 1}, + {"㉙", 0}, + {"0", 2}, + {"parenright", 1}, + {"⑳", 0}, + {"kana_YU", 2}, + {"parenright", 1}, + {"㋴", 0}, + {"kana_TE", 2}, + {"parenright", 1}, + {"㋢", 0}, + {"7", 2}, + {"parenright", 1}, + {"⑦", 0}, + {"kana_NU", 2}, + {"parenright", 1}, + {"㋦", 0}, + {"kana_HO", 2}, + {"parenright", 1}, + {"㋭", 0}, + {"kana_HI", 2}, + {"parenright", 1}, + {"㋪", 0}, + {"j", 2}, + {"parenright", 1}, + {"ⓙ", 0}, + {"kana_E", 2}, + {"parenright", 1}, + {"㋓", 0}, + {"x", 2}, + {"parenright", 1}, + {"ⓧ", 0}, + {"Greek_epsilon", 1}, + {"ἑ", 0}, + {"q", 2}, + {"parenright", 1}, + {"ⓠ", 0}, + {"KP_7", 2}, + {"parenright", 1}, + {"⑦", 0}, + {"kana_I", 2}, + {"parenright", 1}, + {"㋑", 0}, + {"kana_WA", 2}, + {"parenright", 1}, + {"㋻", 0}, + {"kana_RU", 2}, + {"parenright", 1}, + {"㋸", 0}, + {"V", 2}, + {"parenright", 1}, + {"Ⓥ", 0}, + {"u", 2}, + {"parenright", 1}, + {"ⓤ", 0}, + {"kana_NI", 2}, + {"parenright", 1}, + {"㋥", 0}, + {"kana_MU", 2}, + {"parenright", 1}, + {"㋰", 0}, + {"kana_CHI", 2}, + {"parenright", 1}, + {"㋠", 0}, + {"kana_HA", 2}, + {"parenright", 1}, + {"㋩", 0}, + {"z", 2}, + {"parenright", 1}, + {"ⓩ", 0}, + {"G", 2}, + {"parenright", 1}, + {"Ⓖ", 0}, + {"Greek_ALPHA", 1}, + {"Ἁ", 0}, + {"H", 2}, + {"parenright", 1}, + {"Ⓗ", 0}, + {"8", 2}, + {"parenright", 1}, + {"⑧", 0}, + {"KP_1", 65}, + {"1", 2}, + {"parenright", 1}, + {"⑪", 0}, + {"KP_4", 2}, + {"parenright", 1}, + {"⑭", 0}, + {"KP_6", 2}, + {"parenright", 1}, + {"⑯", 0}, + {"KP_8", 2}, + {"parenright", 1}, + {"⑱", 0}, + {"KP_9", 2}, + {"parenright", 1}, + {"⑲", 0}, + {"KP_Space", 2}, + {"parenright", 1}, + {"⑫", 0}, + {"7", 2}, + {"parenright", 1}, + {"⑰", 0}, + {"parenright", 1}, + {"①", 0}, + {"KP_7", 2}, + {"parenright", 1}, + {"⑰", 0}, + {"8", 2}, + {"parenright", 1}, + {"⑱", 0}, + {"KP_1", 2}, + {"parenright", 1}, + {"⑪", 0}, + {"3", 2}, + {"parenright", 1}, + {"⑬", 0}, + {"2", 2}, + {"parenright", 1}, + {"⑫", 0}, + {"6", 2}, + {"parenright", 1}, + {"⑯", 0}, + {"4", 2}, + {"parenright", 1}, + {"⑭", 0}, + {"KP_3", 2}, + {"parenright", 1}, + {"⑬", 0}, + {"KP_0", 2}, + {"parenright", 1}, + {"⑩", 0}, + {"KP_2", 2}, + {"parenright", 1}, + {"⑫", 0}, + {"5", 2}, + {"parenright", 1}, + {"⑮", 0}, + {"KP_5", 2}, + {"parenright", 1}, + {"⑮", 0}, + {"9", 2}, + {"parenright", 1}, + {"⑲", 0}, + {"0", 2}, + {"parenright", 1}, + {"⑩", 0}, + {"3", 65}, + {"1", 2}, + {"parenright", 1}, + {"㉛", 0}, + {"KP_4", 2}, + {"parenright", 1}, + {"㉞", 0}, + {"KP_6", 2}, + {"parenright", 1}, + {"㊱", 0}, + {"KP_8", 2}, + {"parenright", 1}, + {"㊳", 0}, + {"KP_9", 2}, + {"parenright", 1}, + {"㊴", 0}, + {"KP_Space", 2}, + {"parenright", 1}, + {"㉜", 0}, + {"7", 2}, + {"parenright", 1}, + {"㊲", 0}, + {"parenright", 1}, + {"③", 0}, + {"KP_7", 2}, + {"parenright", 1}, + {"㊲", 0}, + {"8", 2}, + {"parenright", 1}, + {"㊳", 0}, + {"KP_1", 2}, + {"parenright", 1}, + {"㉛", 0}, + {"3", 2}, + {"parenright", 1}, + {"㉝", 0}, + {"2", 2}, + {"parenright", 1}, + {"㉜", 0}, + {"6", 2}, + {"parenright", 1}, + {"㊱", 0}, + {"4", 2}, + {"parenright", 1}, + {"㉞", 0}, + {"KP_3", 2}, + {"parenright", 1}, + {"㉝", 0}, + {"KP_0", 2}, + {"parenright", 1}, + {"㉚", 0}, + {"KP_2", 2}, + {"parenright", 1}, + {"㉜", 0}, + {"5", 2}, + {"parenright", 1}, + {"㉟", 0}, + {"KP_5", 2}, + {"parenright", 1}, + {"㉟", 0}, + {"9", 2}, + {"parenright", 1}, + {"㊴", 0}, + {"0", 2}, + {"parenright", 1}, + {"㉚", 0}, + {"E", 2}, + {"parenright", 1}, + {"Ⓔ", 0}, + {"S", 2}, + {"parenright", 1}, + {"Ⓢ", 0}, + {"2", 65}, + {"1", 2}, + {"parenright", 1}, + {"㉑", 0}, + {"KP_4", 2}, + {"parenright", 1}, + {"㉔", 0}, + {"KP_6", 2}, + {"parenright", 1}, + {"㉖", 0}, + {"KP_8", 2}, + {"parenright", 1}, + {"㉘", 0}, + {"KP_9", 2}, + {"parenright", 1}, + {"㉙", 0}, + {"KP_Space", 2}, + {"parenright", 1}, + {"㉒", 0}, + {"7", 2}, + {"parenright", 1}, + {"㉗", 0}, + {"parenright", 1}, + {"②", 0}, + {"KP_7", 2}, + {"parenright", 1}, + {"㉗", 0}, + {"8", 2}, + {"parenright", 1}, + {"㉘", 0}, + {"KP_1", 2}, + {"parenright", 1}, + {"㉑", 0}, + {"3", 2}, + {"parenright", 1}, + {"㉓", 0}, + {"2", 2}, + {"parenright", 1}, + {"㉒", 0}, + {"6", 2}, + {"parenright", 1}, + {"㉖", 0}, + {"4", 2}, + {"parenright", 1}, + {"㉔", 0}, + {"KP_3", 2}, + {"parenright", 1}, + {"㉓", 0}, + {"KP_0", 2}, + {"parenright", 1}, + {"⑳", 0}, + {"KP_2", 2}, + {"parenright", 1}, + {"㉒", 0}, + {"5", 2}, + {"parenright", 1}, + {"㉕", 0}, + {"KP_5", 2}, + {"parenright", 1}, + {"㉕", 0}, + {"9", 2}, + {"parenright", 1}, + {"㉙", 0}, + {"0", 2}, + {"parenright", 1}, + {"⑳", 0}, + {"Y", 2}, + {"parenright", 1}, + {"Ⓨ", 0}, + {"kana_RA", 2}, + {"parenright", 1}, + {"㋶", 0}, + {"f", 2}, + {"parenright", 1}, + {"ⓕ", 0}, + {"Greek_omicron", 1}, + {"ὁ", 0}, + {"Greek_eta", 1}, + {"ἡ", 0}, + {"kana_HE", 2}, + {"parenright", 1}, + {"㋬", 0}, + {"Greek_rho", 1}, + {"ῥ", 0}, + {"kana_KO", 2}, + {"parenright", 1}, + {"㋙", 0}, + {"d", 2}, + {"parenright", 1}, + {"ⓓ", 0}, + {"kana_NE", 2}, + {"parenright", 1}, + {"㋧", 0}, + {"D", 2}, + {"parenright", 1}, + {"Ⓓ", 0}, + {"kana_FU", 2}, + {"parenright", 1}, + {"㋫", 0}, + {"6", 2}, + {"parenright", 1}, + {"⑥", 0}, + {"Greek_alpha", 1}, + {"ἁ", 0}, + {"kana_A", 2}, + {"parenright", 1}, + {"㋐", 0}, + {"w", 2}, + {"parenright", 1}, + {"ⓦ", 0}, + {"Greek_ETA", 1}, + {"Ἡ", 0}, + {"4", 65}, + {"1", 2}, + {"parenright", 1}, + {"㊶", 0}, + {"KP_4", 2}, + {"parenright", 1}, + {"㊹", 0}, + {"KP_6", 2}, + {"parenright", 1}, + {"㊻", 0}, + {"KP_8", 2}, + {"parenright", 1}, + {"㊽", 0}, + {"KP_9", 2}, + {"parenright", 1}, + {"㊾", 0}, + {"KP_Space", 2}, + {"parenright", 1}, + {"㊷", 0}, + {"7", 2}, + {"parenright", 1}, + {"㊼", 0}, + {"parenright", 1}, + {"④", 0}, + {"KP_7", 2}, + {"parenright", 1}, + {"㊼", 0}, + {"8", 2}, + {"parenright", 1}, + {"㊽", 0}, + {"KP_1", 2}, + {"parenright", 1}, + {"㊶", 0}, + {"3", 2}, + {"parenright", 1}, + {"㊸", 0}, + {"2", 2}, + {"parenright", 1}, + {"㊷", 0}, + {"6", 2}, + {"parenright", 1}, + {"㊻", 0}, + {"4", 2}, + {"parenright", 1}, + {"㊹", 0}, + {"KP_3", 2}, + {"parenright", 1}, + {"㊸", 0}, + {"KP_0", 2}, + {"parenright", 1}, + {"㊵", 0}, + {"KP_2", 2}, + {"parenright", 1}, + {"㊷", 0}, + {"5", 2}, + {"parenright", 1}, + {"㊺", 0}, + {"KP_5", 2}, + {"parenright", 1}, + {"㊺", 0}, + {"9", 2}, + {"parenright", 1}, + {"㊾", 0}, + {"0", 2}, + {"parenright", 1}, + {"㊵", 0}, + {"kana_KU", 2}, + {"parenright", 1}, + {"㋗", 0}, + {"KP_3", 65}, + {"1", 2}, + {"parenright", 1}, + {"㉛", 0}, + {"KP_4", 2}, + {"parenright", 1}, + {"㉞", 0}, + {"KP_6", 2}, + {"parenright", 1}, + {"㊱", 0}, + {"KP_8", 2}, + {"parenright", 1}, + {"㊳", 0}, + {"KP_9", 2}, + {"parenright", 1}, + {"㊴", 0}, + {"KP_Space", 2}, + {"parenright", 1}, + {"㉜", 0}, + {"7", 2}, + {"parenright", 1}, + {"㊲", 0}, + {"parenright", 1}, + {"③", 0}, + {"KP_7", 2}, + {"parenright", 1}, + {"㊲", 0}, + {"8", 2}, + {"parenright", 1}, + {"㊳", 0}, + {"KP_1", 2}, + {"parenright", 1}, + {"㉛", 0}, + {"3", 2}, + {"parenright", 1}, + {"㉝", 0}, + {"2", 2}, + {"parenright", 1}, + {"㉜", 0}, + {"6", 2}, + {"parenright", 1}, + {"㊱", 0}, + {"4", 2}, + {"parenright", 1}, + {"㉞", 0}, + {"KP_3", 2}, + {"parenright", 1}, + {"㉝", 0}, + {"KP_0", 2}, + {"parenright", 1}, + {"㉚", 0}, + {"KP_2", 2}, + {"parenright", 1}, + {"㉜", 0}, + {"5", 2}, + {"parenright", 1}, + {"㉟", 0}, + {"KP_5", 2}, + {"parenright", 1}, + {"㉟", 0}, + {"9", 2}, + {"parenright", 1}, + {"㊴", 0}, + {"0", 2}, + {"parenright", 1}, + {"㉚", 0}, + {"p", 2}, + {"parenright", 1}, + {"ⓟ", 0}, + {"J", 2}, + {"parenright", 1}, + {"Ⓙ", 0}, + {"kana_YA", 2}, + {"parenright", 1}, + {"㋳", 0}, + {"v", 2}, + {"parenright", 1}, + {"ⓥ", 0}, + {"P", 2}, + {"parenright", 1}, + {"Ⓟ", 0}, + {"M", 2}, + {"parenright", 1}, + {"Ⓜ", 0}, + {"O", 2}, + {"parenright", 1}, + {"Ⓞ", 0}, + {"m", 2}, + {"parenright", 1}, + {"ⓜ", 0}, + {"r", 2}, + {"parenright", 1}, + {"ⓡ", 0}, + {"s", 2}, + {"parenright", 1}, + {"ⓢ", 0}, + {"Z", 2}, + {"parenright", 1}, + {"Ⓩ", 0}, + {"kana_U", 2}, + {"parenright", 1}, + {"㋒", 0}, + {"KP_0", 2}, + {"parenright", 1}, + {"⓪", 0}, + {"A", 2}, + {"parenright", 1}, + {"Ⓐ", 0}, + {"R", 2}, + {"parenright", 1}, + {"Ⓡ", 0}, + {"kana_TO", 2}, + {"parenright", 1}, + {"㋣", 0}, + {"kana_TA", 2}, + {"parenright", 1}, + {"㋟", 0}, + {"c", 2}, + {"parenright", 1}, + {"ⓒ", 0}, + {"kana_RO", 2}, + {"parenright", 1}, + {"㋺", 0}, + {"L", 2}, + {"parenright", 1}, + {"Ⓛ", 0}, + {"Greek_EPSILON", 1}, + {"Ἑ", 0}, + {"KP_2", 65}, + {"1", 2}, + {"parenright", 1}, + {"㉑", 0}, + {"KP_4", 2}, + {"parenright", 1}, + {"㉔", 0}, + {"KP_6", 2}, + {"parenright", 1}, + {"㉖", 0}, + {"KP_8", 2}, + {"parenright", 1}, + {"㉘", 0}, + {"KP_9", 2}, + {"parenright", 1}, + {"㉙", 0}, + {"KP_Space", 2}, + {"parenright", 1}, + {"㉒", 0}, + {"7", 2}, + {"parenright", 1}, + {"㉗", 0}, + {"parenright", 1}, + {"②", 0}, + {"KP_7", 2}, + {"parenright", 1}, + {"㉗", 0}, + {"8", 2}, + {"parenright", 1}, + {"㉘", 0}, + {"KP_1", 2}, + {"parenright", 1}, + {"㉑", 0}, + {"3", 2}, + {"parenright", 1}, + {"㉓", 0}, + {"2", 2}, + {"parenright", 1}, + {"㉒", 0}, + {"6", 2}, + {"parenright", 1}, + {"㉖", 0}, + {"4", 2}, + {"parenright", 1}, + {"㉔", 0}, + {"KP_3", 2}, + {"parenright", 1}, + {"㉓", 0}, + {"KP_0", 2}, + {"parenright", 1}, + {"⑳", 0}, + {"KP_2", 2}, + {"parenright", 1}, + {"㉒", 0}, + {"5", 2}, + {"parenright", 1}, + {"㉕", 0}, + {"KP_5", 2}, + {"parenright", 1}, + {"㉕", 0}, + {"9", 2}, + {"parenright", 1}, + {"㉙", 0}, + {"0", 2}, + {"parenright", 1}, + {"⑳", 0}, + {"kana_O", 2}, + {"parenright", 1}, + {"㋔", 0}, + {"kana_RI", 2}, + {"parenright", 1}, + {"㋷", 0}, + {"T", 2}, + {"parenright", 1}, + {"Ⓣ", 0}, + {"kana_KA", 2}, + {"parenright", 1}, + {"㋕", 0}, + {"kana_MI", 2}, + {"parenright", 1}, + {"㋯", 0}, + {"5", 8}, + {"parenright", 1}, + {"⑤", 0}, + {"KP_0", 2}, + {"parenright", 1}, + {"㊿", 0}, + {"0", 2}, + {"parenright", 1}, + {"㊿", 0}, + {"kana_KI", 2}, + {"parenright", 1}, + {"㋖", 0}, + {"KP_5", 8}, + {"parenright", 1}, + {"⑤", 0}, + {"KP_0", 2}, + {"parenright", 1}, + {"㊿", 0}, + {"0", 2}, + {"parenright", 1}, + {"㊿", 0}, + {"K", 2}, + {"parenright", 1}, + {"Ⓚ", 0}, + {"9", 2}, + {"parenright", 1}, + {"⑨", 0}, + {"kana_SO", 2}, + {"parenright", 1}, + {"㋞", 0}, + {"B", 2}, + {"parenright", 1}, + {"Ⓑ", 0}, + {"kana_TSU", 2}, + {"parenright", 1}, + {"㋡", 0}, + {"0", 2}, + {"parenright", 1}, + {"⓪", 0}, + {"kana_MO", 2}, + {"parenright", 1}, + {"㋲", 0}, + {"Greek_omega", 1}, + {"ὡ", 0}, + {"kana_NO", 2}, + {"parenright", 1}, + {"㋨", 0}, + {"Greek_OMEGA", 1}, + {"Ὡ", 0}, + {"kana_NA", 2}, + {"parenright", 1}, + {"㋤", 0}, + {"X", 2}, + {"parenright", 1}, + {"Ⓧ", 0}, + {"parenleft", 1}, + {"[", 0}, + {"h", 2}, + {"parenright", 1}, + {"ⓗ", 0}, + {"I", 2}, + {"parenright", 1}, + {"Ⓘ", 0}, + {"N", 2}, + {"parenright", 1}, + {"Ⓝ", 0}, + {"kana_SHI", 2}, + {"parenright", 1}, + {"㋛", 0}, + {"U", 2}, + {"parenright", 1}, + {"Ⓤ", 0}, + {"kana_RE", 2}, + {"parenright", 1}, + {"㋹", 0}, + {"Greek_UPSILON", 1}, + {"Ὑ", 0}, + {"h", 2}, + {"comma", 1}, + {"ḩ", 0}, + {"I", 28}, + {"minus", 1}, + {"Ī", 0}, + {"period", 1}, + {"İ", 0}, + {"diaeresis", 1}, + {"Ï", 0}, + {"j", 1}, + {"IJ", 0}, + {"quotedbl", 1}, + {"Ï", 0}, + {"acute", 1}, + {"Í", 0}, + {"underscore", 1}, + {"Ī", 0}, + {"J", 1}, + {"IJ", 0}, + {"apostrophe", 1}, + {"Í", 0}, + {"comma", 1}, + {"Į", 0}, + {"asciitilde", 1}, + {"Ĩ", 0}, + {"greater", 1}, + {"Î", 0}, + {"grave", 1}, + {"Ì", 0}, + {"asciicircum", 1}, + {"Î", 0}, + {"N", 16}, + {"less", 1}, + {"Ň", 0}, + {"o", 1}, + {"№", 0}, + {"equal", 1}, + {"₦", 0}, + {"G", 1}, + {"Ŋ", 0}, + {"apostrophe", 1}, + {"Ń", 0}, + {"O", 1}, + {"№", 0}, + {"comma", 1}, + {"Ņ", 0}, + {"asciitilde", 1}, + {"Ñ", 0}, + {"grave", 362}, + {"W", 1}, + {"Ẁ", 0}, + {"dead_breve", 4}, + {"a", 1}, + {"ằ", 0}, + {"A", 1}, + {"Ằ", 0}, + {"a", 1}, + {"à", 0}, + {"Greek_IOTA", 1}, + {"Ὶ", 0}, + {"Greek_iota", 1}, + {"ὶ", 0}, + {"dead_horn", 8}, + {"o", 1}, + {"ờ", 0}, + {"u", 1}, + {"ừ", 0}, + {"O", 1}, + {"Ờ", 0}, + {"U", 1}, + {"Ừ", 0}, + {"dead_circumflex", 12}, + {"a", 1}, + {"ầ", 0}, + {"e", 1}, + {"ề", 0}, + {"o", 1}, + {"ồ", 0}, + {"E", 1}, + {"Ề", 0}, + {"O", 1}, + {"Ồ", 0}, + {"A", 1}, + {"Ầ", 0}, + {"Greek_OMICRON", 1}, + {"Ὸ", 0}, + {"Acircumflex", 1}, + {"Ầ", 0}, + {"Cyrillic_er", 1}, + {"р̀", 0}, + {"e", 1}, + {"è", 0}, + {"o", 1}, + {"ò", 0}, + {"Udiaeresis", 1}, + {"Ǜ", 0}, + {"Greek_upsilon", 1}, + {"ὺ", 0}, + {"uhorn", 1}, + {"ừ", 0}, + {"space", 1}, + {"`", 0}, + {"dead_macron", 8}, + {"e", 1}, + {"ḕ", 0}, + {"o", 1}, + {"ṑ", 0}, + {"E", 1}, + {"Ḕ", 0}, + {"O", 1}, + {"Ṑ", 0}, + {"acircumflex", 1}, + {"ầ", 0}, + {"Ecircumflex", 1}, + {"Ề", 0}, + {"Cyrillic_I", 1}, + {"Ѝ", 0}, + {"y", 1}, + {"ỳ", 0}, + {"b", 4}, + {"a", 1}, + {"ằ", 0}, + {"A", 1}, + {"Ằ", 0}, + {"Cyrillic_O", 1}, + {"О̀", 0}, + {"i", 1}, + {"ì", 0}, + {"n", 1}, + {"ǹ", 0}, + {"Cyrillic_a", 1}, + {"а̀", 0}, + {"parenright", 26}, + {"Greek_IOTA", 1}, + {"Ἲ", 0}, + {"Greek_iota", 1}, + {"ἲ", 0}, + {"Greek_OMICRON", 1}, + {"Ὂ", 0}, + {"Greek_upsilon", 1}, + {"ὒ", 0}, + {"Greek_epsilon", 1}, + {"ἒ", 0}, + {"Greek_ALPHA", 1}, + {"Ἂ", 0}, + {"Greek_omicron", 1}, + {"ὂ", 0}, + {"Greek_eta", 1}, + {"ἢ", 0}, + {"Greek_alpha", 1}, + {"ἂ", 0}, + {"Greek_ETA", 1}, + {"Ἢ", 0}, + {"Greek_EPSILON", 1}, + {"Ἒ", 0}, + {"Greek_omega", 1}, + {"ὢ", 0}, + {"Greek_OMEGA", 1}, + {"Ὢ", 0}, + {"Ohorn", 1}, + {"Ờ", 0}, + {"ohorn", 1}, + {"ờ", 0}, + {"Cyrillic_ER", 1}, + {"Р̀", 0}, + {"Greek_epsilon", 1}, + {"ὲ", 0}, + {"Cyrillic_U", 1}, + {"У̀", 0}, + {"Ocircumflex", 1}, + {"Ồ", 0}, + {"omacron", 1}, + {"ṑ", 0}, + {"ocircumflex", 1}, + {"ồ", 0}, + {"u", 1}, + {"ù", 0}, + {"Greek_ALPHA", 1}, + {"Ὰ", 0}, + {"Cyrillic_ie", 1}, + {"ѐ", 0}, + {"emacron", 1}, + {"ḕ", 0}, + {"E", 1}, + {"È", 0}, + {"Greek_iotadieresis", 1}, + {"ῒ", 0}, + {"Y", 1}, + {"Ỳ", 0}, + {"Cyrillic_i", 1}, + {"ѝ", 0}, + {"dead_dasia", 28}, + {"Greek_IOTA", 1}, + {"Ἳ", 0}, + {"Greek_iota", 1}, + {"ἳ", 0}, + {"Greek_OMICRON", 1}, + {"Ὃ", 0}, + {"Greek_upsilon", 1}, + {"ὓ", 0}, + {"Greek_epsilon", 1}, + {"ἓ", 0}, + {"Greek_ALPHA", 1}, + {"Ἃ", 0}, + {"Greek_omicron", 1}, + {"ὃ", 0}, + {"Greek_eta", 1}, + {"ἣ", 0}, + {"Greek_alpha", 1}, + {"ἃ", 0}, + {"Greek_ETA", 1}, + {"Ἣ", 0}, + {"Greek_EPSILON", 1}, + {"Ἓ", 0}, + {"Greek_omega", 1}, + {"ὣ", 0}, + {"Greek_OMEGA", 1}, + {"Ὣ", 0}, + {"Greek_UPSILON", 1}, + {"Ὓ", 0}, + {"Greek_upsilondieresis", 1}, + {"ῢ", 0}, + {"Greek_omicron", 1}, + {"ὸ", 0}, + {"Greek_eta", 1}, + {"ὴ", 0}, + {"Abreve", 1}, + {"Ằ", 0}, + {"dead_psili", 26}, + {"Greek_IOTA", 1}, + {"Ἲ", 0}, + {"Greek_iota", 1}, + {"ἲ", 0}, + {"Greek_OMICRON", 1}, + {"Ὂ", 0}, + {"Greek_upsilon", 1}, + {"ὒ", 0}, + {"Greek_epsilon", 1}, + {"ἒ", 0}, + {"Greek_ALPHA", 1}, + {"Ἂ", 0}, + {"Greek_omicron", 1}, + {"ὂ", 0}, + {"Greek_eta", 1}, + {"ἢ", 0}, + {"Greek_alpha", 1}, + {"ἂ", 0}, + {"Greek_ETA", 1}, + {"Ἢ", 0}, + {"Greek_EPSILON", 1}, + {"Ἒ", 0}, + {"Greek_omega", 1}, + {"ὢ", 0}, + {"Greek_OMEGA", 1}, + {"Ὢ", 0}, + {"quotedbl", 8}, + {"Greek_iota", 1}, + {"ῒ", 0}, + {"Greek_upsilon", 1}, + {"ῢ", 0}, + {"u", 1}, + {"ǜ", 0}, + {"U", 1}, + {"Ǜ", 0}, + {"plus", 8}, + {"o", 1}, + {"ờ", 0}, + {"u", 1}, + {"ừ", 0}, + {"O", 1}, + {"Ờ", 0}, + {"U", 1}, + {"Ừ", 0}, + {"Greek_alpha", 1}, + {"ὰ", 0}, + {"ecircumflex", 1}, + {"ề", 0}, + {"w", 1}, + {"ẁ", 0}, + {"Greek_ETA", 1}, + {"Ὴ", 0}, + {"Cyrillic_o", 1}, + {"о̀", 0}, + {"Emacron", 1}, + {"Ḕ", 0}, + {"underscore", 8}, + {"e", 1}, + {"ḕ", 0}, + {"o", 1}, + {"ṑ", 0}, + {"E", 1}, + {"Ḕ", 0}, + {"O", 1}, + {"Ṑ", 0}, + {"O", 1}, + {"Ò", 0}, + {"abreve", 1}, + {"ằ", 0}, + {"macron", 8}, + {"e", 1}, + {"ḕ", 0}, + {"o", 1}, + {"ṑ", 0}, + {"E", 1}, + {"Ḕ", 0}, + {"O", 1}, + {"Ṑ", 0}, + {"A", 1}, + {"À", 0}, + {"Greek_EPSILON", 1}, + {"Ὲ", 0}, + {"Cyrillic_A", 1}, + {"А̀", 0}, + {"Omacron", 1}, + {"Ṑ", 0}, + {"Cyrillic_IE", 1}, + {"Ѐ", 0}, + {"Greek_omega", 1}, + {"ὼ", 0}, + {"dead_diaeresis", 8}, + {"Greek_iota", 1}, + {"ῒ", 0}, + {"Greek_upsilon", 1}, + {"ῢ", 0}, + {"u", 1}, + {"ǜ", 0}, + {"U", 1}, + {"Ǜ", 0}, + {"Uhorn", 1}, + {"Ừ", 0}, + {"Greek_OMEGA", 1}, + {"Ὼ", 0}, + {"parenleft", 28}, + {"Greek_IOTA", 1}, + {"Ἳ", 0}, + {"Greek_iota", 1}, + {"ἳ", 0}, + {"Greek_OMICRON", 1}, + {"Ὃ", 0}, + {"Greek_upsilon", 1}, + {"ὓ", 0}, + {"Greek_epsilon", 1}, + {"ἓ", 0}, + {"Greek_ALPHA", 1}, + {"Ἃ", 0}, + {"Greek_omicron", 1}, + {"ὃ", 0}, + {"Greek_eta", 1}, + {"ἣ", 0}, + {"Greek_alpha", 1}, + {"ἃ", 0}, + {"Greek_ETA", 1}, + {"Ἣ", 0}, + {"Greek_EPSILON", 1}, + {"Ἓ", 0}, + {"Greek_omega", 1}, + {"ὣ", 0}, + {"Greek_OMEGA", 1}, + {"Ὣ", 0}, + {"Greek_UPSILON", 1}, + {"Ὓ", 0}, + {"udiaeresis", 1}, + {"ǜ", 0}, + {"I", 1}, + {"Ì", 0}, + {"N", 1}, + {"Ǹ", 0}, + {"grave", 24}, + {"Cyrillic_er", 1}, + {"р̏", 0}, + {"Cyrillic_I", 1}, + {"И̏", 0}, + {"Cyrillic_O", 1}, + {"О̏", 0}, + {"Cyrillic_a", 1}, + {"а̏", 0}, + {"Cyrillic_ER", 1}, + {"Р̏", 0}, + {"Cyrillic_U", 1}, + {"У̏", 0}, + {"Cyrillic_ie", 1}, + {"е̏", 0}, + {"Cyrillic_i", 1}, + {"и̏", 0}, + {"Cyrillic_o", 1}, + {"о̏", 0}, + {"Cyrillic_A", 1}, + {"А̏", 0}, + {"Cyrillic_IE", 1}, + {"Е̏", 0}, + {"Cyrillic_u", 1}, + {"у̏", 0}, + {"U", 1}, + {"Ù", 0}, + {"Cyrillic_u", 1}, + {"у̀", 0}, + {"asciicircum", 12}, + {"a", 1}, + {"ầ", 0}, + {"e", 1}, + {"ề", 0}, + {"o", 1}, + {"ồ", 0}, + {"E", 1}, + {"Ề", 0}, + {"O", 1}, + {"Ồ", 0}, + {"A", 1}, + {"Ầ", 0}, + {"Greek_UPSILON", 1}, + {"Ὺ", 0}, + {"U", 106}, + {"minus", 1}, + {"Ū", 0}, + {"g", 1}, + {"ğ", 0}, + {"a", 1}, + {"ă", 0}, + {"Greek_IOTA", 1}, + {"Ῐ", 0}, + {"Greek_iota", 1}, + {"ῐ", 0}, + {"exclam", 4}, + {"a", 1}, + {"ặ", 0}, + {"A", 1}, + {"Ặ", 0}, + {"e", 1}, + {"ĕ", 0}, + {"o", 1}, + {"ŏ", 0}, + {"Greek_upsilon", 1}, + {"ῠ", 0}, + {"diaeresis", 1}, + {"Ü", 0}, + {"dead_belowdot", 4}, + {"a", 1}, + {"ặ", 0}, + {"A", 1}, + {"Ặ", 0}, + {"space", 5}, + {"comma", 4}, + {"e", 1}, + {"ḝ", 0}, + {"E", 1}, + {"Ḝ", 0}, + {"Cyrillic_I", 1}, + {"Й", 0}, + {"i", 1}, + {"ĭ", 0}, + {"Cyrillic_a", 1}, + {"ӑ", 0}, + {"Cyrillic_U", 1}, + {"Ў", 0}, + {"u", 1}, + {"ŭ", 0}, + {"G", 1}, + {"Ğ", 0}, + {"Greek_ALPHA", 1}, + {"Ᾰ", 0}, + {"Cyrillic_ie", 1}, + {"ӗ", 0}, + {"E", 1}, + {"Ĕ", 0}, + {"Cyrillic_i", 1}, + {"й", 0}, + {"Cyrillic_zhe", 1}, + {"ӂ", 0}, + {"quotedbl", 1}, + {"Ü", 0}, + {"cedilla", 4}, + {"e", 1}, + {"ḝ", 0}, + {"E", 1}, + {"Ḝ", 0}, + {"Greek_alpha", 1}, + {"ᾰ", 0}, + {"acute", 1}, + {"Ú", 0}, + {"underscore", 1}, + {"Ū", 0}, + {"apostrophe", 1}, + {"Ú", 0}, + {"O", 1}, + {"Ŏ", 0}, + {"asterisk", 1}, + {"Ů", 0}, + {"A", 1}, + {"Ă", 0}, + {"Cyrillic_A", 1}, + {"Ӑ", 0}, + {"comma", 1}, + {"Ų", 0}, + {"asciitilde", 1}, + {"Ũ", 0}, + {"greater", 1}, + {"Û", 0}, + {"Cyrillic_ZHE", 1}, + {"Ӂ", 0}, + {"Cyrillic_IE", 1}, + {"Ӗ", 0}, + {"dead_cedilla", 4}, + {"e", 1}, + {"ḝ", 0}, + {"E", 1}, + {"Ḝ", 0}, + {"I", 1}, + {"Ĭ", 0}, + {"grave", 1}, + {"Ù", 0}, + {"U", 1}, + {"Ŭ", 0}, + {"Cyrillic_u", 1}, + {"ў", 0}, + {"asciicircum", 1}, + {"Û", 0}, + {"Greek_UPSILON", 1}, + {"Ῠ", 0}, + {"asciicircum", 214}, + {"minus", 1}, + {"¯", 0}, + {"period", 1}, + {"·", 0}, + {"W", 1}, + {"Ŵ", 0}, + {"g", 1}, + {"ĝ", 0}, + {"a", 1}, + {"â", 0}, + {"1", 1}, + {"¹", 0}, + {"C", 1}, + {"Ĉ", 0}, + {"KP_4", 1}, + {"⁴", 0}, + {"exclam", 12}, + {"a", 1}, + {"ậ", 0}, + {"e", 1}, + {"ệ", 0}, + {"o", 1}, + {"ộ", 0}, + {"E", 1}, + {"Ệ", 0}, + {"O", 1}, + {"Ộ", 0}, + {"A", 1}, + {"Ậ", 0}, + {"Cyrillic_er", 1}, + {"р̂", 0}, + {"o", 1}, + {"ô", 0}, + {"e", 1}, + {"ê", 0}, + {"KP_6", 1}, + {"⁶", 0}, + {"dead_belowdot", 12}, + {"a", 1}, + {"ậ", 0}, + {"e", 1}, + {"ệ", 0}, + {"o", 1}, + {"ộ", 0}, + {"E", 1}, + {"Ệ", 0}, + {"O", 1}, + {"Ộ", 0}, + {"A", 1}, + {"Ậ", 0}, + {"space", 1}, + {"^", 0}, + {"KP_8", 1}, + {"⁸", 0}, + {"Cyrillic_I", 1}, + {"И̂", 0}, + {"y", 1}, + {"ŷ", 0}, + {"Cyrillic_O", 1}, + {"О̂", 0}, + {"i", 1}, + {"î", 0}, + {"KP_9", 1}, + {"⁹", 0}, + {"equal", 1}, + {"⁼", 0}, + {"KP_Space", 1}, + {"²", 0}, + {"7", 1}, + {"⁷", 0}, + {"Cyrillic_a", 1}, + {"а̂", 0}, + {"j", 1}, + {"ĵ", 0}, + {"parenright", 1}, + {"⁾", 0}, + {"Cyrillic_ER", 1}, + {"Р̂", 0}, + {"KP_7", 1}, + {"⁷", 0}, + {"underbar", 24}, + {"a", 1}, + {"ª", 0}, + {"o", 1}, + {"º", 0}, + {"l", 1}, + {"ˡ", 0}, + {"y", 1}, + {"ʸ", 0}, + {"i", 1}, + {"ⁱ", 0}, + {"n", 1}, + {"ⁿ", 0}, + {"j", 1}, + {"ʲ", 0}, + {"x", 1}, + {"ˣ", 0}, + {"w", 1}, + {"ʷ", 0}, + {"r", 1}, + {"ʳ", 0}, + {"s", 1}, + {"ˢ", 0}, + {"h", 1}, + {"ʰ", 0}, + {"Cyrillic_U", 1}, + {"У̂", 0}, + {"u", 1}, + {"û", 0}, + {"z", 1}, + {"ẑ", 0}, + {"G", 1}, + {"Ĝ", 0}, + {"H", 1}, + {"Ĥ", 0}, + {"8", 1}, + {"⁸", 0}, + {"KP_1", 1}, + {"¹", 0}, + {"3", 1}, + {"³", 0}, + {"Cyrillic_ie", 1}, + {"е̂", 0}, + {"E", 1}, + {"Ê", 0}, + {"S", 1}, + {"Ŝ", 0}, + {"2", 1}, + {"²", 0}, + {"Y", 1}, + {"Ŷ", 0}, + {"Cyrillic_i", 1}, + {"и̂", 0}, + {"plus", 1}, + {"⁺", 0}, + {"6", 1}, + {"⁶", 0}, + {"w", 1}, + {"ŵ", 0}, + {"Cyrillic_o", 1}, + {"о̂", 0}, + {"4", 1}, + {"⁴", 0}, + {"KP_3", 1}, + {"³", 0}, + {"underscore", 24}, + {"a", 1}, + {"ª", 0}, + {"o", 1}, + {"º", 0}, + {"l", 1}, + {"ˡ", 0}, + {"y", 1}, + {"ʸ", 0}, + {"i", 1}, + {"ⁱ", 0}, + {"n", 1}, + {"ⁿ", 0}, + {"j", 1}, + {"ʲ", 0}, + {"x", 1}, + {"ˣ", 0}, + {"w", 1}, + {"ʷ", 0}, + {"r", 1}, + {"ʳ", 0}, + {"s", 1}, + {"ˢ", 0}, + {"h", 1}, + {"ʰ", 0}, + {"J", 1}, + {"Ĵ", 0}, + {"O", 1}, + {"Ô", 0}, + {"s", 1}, + {"ŝ", 0}, + {"Z", 1}, + {"Ẑ", 0}, + {"KP_0", 1}, + {"⁰", 0}, + {"A", 1}, + {"Â", 0}, + {"c", 1}, + {"ĉ", 0}, + {"KP_Add", 1}, + {"⁺", 0}, + {"KP_2", 1}, + {"²", 0}, + {"Cyrillic_A", 1}, + {"А̂", 0}, + {"slash", 1}, + {"|", 0}, + {"5", 1}, + {"⁵", 0}, + {"KP_5", 1}, + {"⁵", 0}, + {"9", 1}, + {"⁹", 0}, + {"Cyrillic_IE", 1}, + {"Е̂", 0}, + {"0", 1}, + {"⁰", 0}, + {"parenleft", 1}, + {"⁽", 0}, + {"h", 1}, + {"ĥ", 0}, + {"I", 1}, + {"Î", 0}, + {"U", 1}, + {"Û", 0}, + {"Cyrillic_u", 1}, + {"у̂", 0}, + {"KP_Equal", 1}, + {"⁼", 0}, + {"Greek_UPSILON", 4}, + {"quotedbl", 1}, + {"Ϋ", 0}, + {"apostrophe", 1}, + {"Ύ", 0}, + {"dead_belowcircumflex", 24}, + {"e", 1}, + {"ḙ", 0}, + {"l", 1}, + {"ḽ", 0}, + {"t", 1}, + {"ṱ", 0}, + {"n", 1}, + {"ṋ", 0}, + {"u", 1}, + {"ṷ", 0}, + {"E", 1}, + {"Ḙ", 0}, + {"d", 1}, + {"ḓ", 0}, + {"D", 1}, + {"Ḓ", 0}, + {"L", 1}, + {"Ḽ", 0}, + {"T", 1}, + {"Ṱ", 0}, + {"N", 1}, + {"Ṋ", 0}, + {"U", 1}, + {"Ṷ", 0}, + {"dead_caron", 134}, + {"minus", 1}, + {"₋", 0}, + {"g", 1}, + {"ǧ", 0}, + {"a", 1}, + {"ǎ", 0}, + {"1", 1}, + {"₁", 0}, + {"ezh", 1}, + {"ǯ", 0}, + {"C", 1}, + {"Č", 0}, + {"e", 1}, + {"ě", 0}, + {"o", 1}, + {"ǒ", 0}, + {"l", 1}, + {"ľ", 0}, + {"Udiaeresis", 1}, + {"Ǚ", 0}, + {"t", 1}, + {"ť", 0}, + {"space", 1}, + {"ˇ", 0}, + {"Multi_key", 5}, + {"quotedbl", 4}, + {"u", 1}, + {"ǚ", 0}, + {"U", 1}, + {"Ǚ", 0}, + {"i", 1}, + {"ǐ", 0}, + {"k", 1}, + {"ǩ", 0}, + {"n", 1}, + {"ň", 0}, + {"equal", 1}, + {"₌", 0}, + {"dead_caron", 1}, + {"ˇ", 0}, + {"7", 1}, + {"₇", 0}, + {"j", 1}, + {"ǰ", 0}, + {"parenright", 1}, + {"₎", 0}, + {"sabovedot", 1}, + {"ṧ", 0}, + {"nobreakspace", 1}, + {"̌", 0}, + {"V", 1}, + {"Ǚ", 0}, + {"u", 1}, + {"ǔ", 0}, + {"z", 1}, + {"ž", 0}, + {"G", 1}, + {"Ǧ", 0}, + {"H", 1}, + {"Ȟ", 0}, + {"8", 1}, + {"₈", 0}, + {"3", 1}, + {"₃", 0}, + {"E", 1}, + {"Ě", 0}, + {"S", 1}, + {"Š", 0}, + {"2", 1}, + {"₂", 0}, + {"d", 1}, + {"ď", 0}, + {"D", 1}, + {"Ď", 0}, + {"plus", 1}, + {"₊", 0}, + {"6", 1}, + {"₆", 0}, + {"dead_abovedot", 4}, + {"S", 1}, + {"Ṧ", 0}, + {"s", 1}, + {"ṧ", 0}, + {"4", 1}, + {"₄", 0}, + {"v", 1}, + {"ǚ", 0}, + {"O", 1}, + {"Ǒ", 0}, + {"r", 1}, + {"ř", 0}, + {"s", 1}, + {"š", 0}, + {"Z", 1}, + {"Ž", 0}, + {"EZH", 1}, + {"Ǯ", 0}, + {"A", 1}, + {"Ǎ", 0}, + {"R", 1}, + {"Ř", 0}, + {"c", 1}, + {"č", 0}, + {"L", 1}, + {"Ľ", 0}, + {"T", 1}, + {"Ť", 0}, + {"5", 1}, + {"₅", 0}, + {"K", 1}, + {"Ǩ", 0}, + {"9", 1}, + {"₉", 0}, + {"0", 1}, + {"₀", 0}, + {"Sabovedot", 1}, + {"Ṧ", 0}, + {"dead_diaeresis", 4}, + {"u", 1}, + {"ǚ", 0}, + {"U", 1}, + {"Ǚ", 0}, + {"parenleft", 1}, + {"₍", 0}, + {"h", 1}, + {"ȟ", 0}, + {"udiaeresis", 1}, + {"ǚ", 0}, + {"I", 1}, + {"Ǐ", 0}, + {"N", 1}, + {"Ň", 0}, + {"U", 1}, + {"Ǔ", 0}, + {"dead_tilde", 266}, + {"dead_breve", 4}, + {"a", 1}, + {"ẵ", 0}, + {"A", 1}, + {"Ẵ", 0}, + {"a", 1}, + {"ã", 0}, + {"Greek_iota", 1}, + {"ῖ", 0}, + {"dead_horn", 8}, + {"o", 1}, + {"ỡ", 0}, + {"u", 1}, + {"ữ", 0}, + {"O", 1}, + {"Ỡ", 0}, + {"U", 1}, + {"Ữ", 0}, + {"dead_circumflex", 12}, + {"a", 1}, + {"ẫ", 0}, + {"e", 1}, + {"ễ", 0}, + {"o", 1}, + {"ỗ", 0}, + {"E", 1}, + {"Ễ", 0}, + {"O", 1}, + {"Ỗ", 0}, + {"A", 1}, + {"Ẫ", 0}, + {"Acircumflex", 1}, + {"Ẫ", 0}, + {"less", 1}, + {"≲", 0}, + {"Oacute", 1}, + {"Ṍ", 0}, + {"e", 1}, + {"ẽ", 0}, + {"o", 1}, + {"õ", 0}, + {"Greek_upsilon", 1}, + {"ῦ", 0}, + {"uhorn", 1}, + {"ữ", 0}, + {"space", 1}, + {"~", 0}, + {"dead_macron", 4}, + {"o", 1}, + {"ȭ", 0}, + {"O", 1}, + {"Ȭ", 0}, + {"acircumflex", 1}, + {"ẫ", 0}, + {"Ecircumflex", 1}, + {"Ễ", 0}, + {"y", 1}, + {"ỹ", 0}, + {"Multi_key", 77}, + {"b", 4}, + {"a", 1}, + {"ẵ", 0}, + {"A", 1}, + {"Ẵ", 0}, + {"parenright", 18}, + {"Greek_IOTA", 1}, + {"Ἶ", 0}, + {"Greek_iota", 1}, + {"ἶ", 0}, + {"Greek_upsilon", 1}, + {"ὖ", 0}, + {"Greek_ALPHA", 1}, + {"Ἆ", 0}, + {"Greek_eta", 1}, + {"ἦ", 0}, + {"Greek_alpha", 1}, + {"ἆ", 0}, + {"Greek_ETA", 1}, + {"Ἦ", 0}, + {"Greek_omega", 1}, + {"ὦ", 0}, + {"Greek_OMEGA", 1}, + {"Ὦ", 0}, + {"quotedbl", 4}, + {"Greek_iota", 1}, + {"ῗ", 0}, + {"Greek_upsilon", 1}, + {"ῧ", 0}, + {"plus", 8}, + {"o", 1}, + {"ỡ", 0}, + {"u", 1}, + {"ữ", 0}, + {"O", 1}, + {"Ỡ", 0}, + {"U", 1}, + {"Ữ", 0}, + {"parenleft", 20}, + {"Greek_IOTA", 1}, + {"Ἷ", 0}, + {"Greek_iota", 1}, + {"ἷ", 0}, + {"Greek_upsilon", 1}, + {"ὗ", 0}, + {"Greek_ALPHA", 1}, + {"Ἇ", 0}, + {"Greek_eta", 1}, + {"ἧ", 0}, + {"Greek_alpha", 1}, + {"ἇ", 0}, + {"Greek_ETA", 1}, + {"Ἧ", 0}, + {"Greek_omega", 1}, + {"ὧ", 0}, + {"Greek_OMEGA", 1}, + {"Ὧ", 0}, + {"Greek_UPSILON", 1}, + {"Ὗ", 0}, + {"U", 4}, + {"a", 1}, + {"ẵ", 0}, + {"A", 1}, + {"Ẵ", 0}, + {"asciicircum", 12}, + {"a", 1}, + {"ẫ", 0}, + {"e", 1}, + {"ễ", 0}, + {"o", 1}, + {"ỗ", 0}, + {"E", 1}, + {"Ễ", 0}, + {"O", 1}, + {"Ỗ", 0}, + {"A", 1}, + {"Ẫ", 0}, + {"oacute", 1}, + {"ṍ", 0}, + {"i", 1}, + {"ĩ", 0}, + {"n", 1}, + {"ñ", 0}, + {"equal", 1}, + {"≃", 0}, + {"dead_tilde", 1}, + {"~", 0}, + {"Uacute", 1}, + {"Ṹ", 0}, + {"Ohorn", 1}, + {"Ỡ", 0}, + {"ohorn", 1}, + {"ỡ", 0}, + {"nobreakspace", 1}, + {"̃", 0}, + {"V", 1}, + {"Ṽ", 0}, + {"Ocircumflex", 1}, + {"Ỗ", 0}, + {"omacron", 1}, + {"ȭ", 0}, + {"uacute", 1}, + {"ṹ", 0}, + {"ocircumflex", 1}, + {"ỗ", 0}, + {"u", 1}, + {"ũ", 0}, + {"E", 1}, + {"Ẽ", 0}, + {"Greek_iotadieresis", 1}, + {"ῗ", 0}, + {"Y", 1}, + {"Ỹ", 0}, + {"dead_dasia", 20}, + {"Greek_IOTA", 1}, + {"Ἷ", 0}, + {"Greek_iota", 1}, + {"ἷ", 0}, + {"Greek_upsilon", 1}, + {"ὗ", 0}, + {"Greek_ALPHA", 1}, + {"Ἇ", 0}, + {"Greek_eta", 1}, + {"ἧ", 0}, + {"Greek_alpha", 1}, + {"ἇ", 0}, + {"Greek_ETA", 1}, + {"Ἧ", 0}, + {"Greek_omega", 1}, + {"ὧ", 0}, + {"Greek_OMEGA", 1}, + {"Ὧ", 0}, + {"Greek_UPSILON", 1}, + {"Ὗ", 0}, + {"Greek_upsilondieresis", 1}, + {"ῧ", 0}, + {"odiaeresis", 1}, + {"ṏ", 0}, + {"Greek_eta", 1}, + {"ῆ", 0}, + {"Abreve", 1}, + {"Ẵ", 0}, + {"dead_psili", 18}, + {"Greek_IOTA", 1}, + {"Ἶ", 0}, + {"Greek_iota", 1}, + {"ἶ", 0}, + {"Greek_upsilon", 1}, + {"ὖ", 0}, + {"Greek_ALPHA", 1}, + {"Ἆ", 0}, + {"Greek_eta", 1}, + {"ἦ", 0}, + {"Greek_alpha", 1}, + {"ἆ", 0}, + {"Greek_ETA", 1}, + {"Ἦ", 0}, + {"Greek_omega", 1}, + {"ὦ", 0}, + {"Greek_OMEGA", 1}, + {"Ὦ", 0}, + {"Greek_alpha", 1}, + {"ᾶ", 0}, + {"ecircumflex", 1}, + {"ễ", 0}, + {"v", 1}, + {"ṽ", 0}, + {"O", 1}, + {"Õ", 0}, + {"abreve", 1}, + {"ẵ", 0}, + {"A", 1}, + {"Ã", 0}, + {"Odiaeresis", 1}, + {"Ṏ", 0}, + {"greater", 1}, + {"≳", 0}, + {"Omacron", 1}, + {"Ȭ", 0}, + {"Greek_omega", 1}, + {"ῶ", 0}, + {"dead_diaeresis", 8}, + {"Greek_iota", 1}, + {"ῗ", 0}, + {"o", 1}, + {"ṏ", 0}, + {"Greek_upsilon", 1}, + {"ῧ", 0}, + {"O", 1}, + {"Ṏ", 0}, + {"Uhorn", 1}, + {"Ữ", 0}, + {"dead_acute", 8}, + {"o", 1}, + {"ṍ", 0}, + {"u", 1}, + {"ṹ", 0}, + {"O", 1}, + {"Ṍ", 0}, + {"U", 1}, + {"Ṹ", 0}, + {"I", 1}, + {"Ĩ", 0}, + {"N", 1}, + {"Ñ", 0}, + {"U", 1}, + {"Ũ", 0}, + {"dead_belowcomma", 14}, + {"t", 1}, + {"ț", 0}, + {"space", 1}, + {",", 0}, + {"dead_belowcomma", 1}, + {",", 0}, + {"nobreakspace", 1}, + {"̦", 0}, + {"S", 1}, + {"Ș", 0}, + {"s", 1}, + {"ș", 0}, + {"T", 1}, + {"Ț", 0}, + {"dead_doubleacute", 18}, + {"o", 1}, + {"ő", 0}, + {"space", 1}, + {"˝", 0}, + {"Cyrillic_U", 1}, + {"Ӳ", 0}, + {"dead_doubleacute", 1}, + {"˝", 0}, + {"nobreakspace", 1}, + {"̋", 0}, + {"u", 1}, + {"ű", 0}, + {"O", 1}, + {"Ő", 0}, + {"U", 1}, + {"Ű", 0}, + {"Cyrillic_u", 1}, + {"ӳ", 0}, + {"dead_abovering", 27}, + {"a", 1}, + {"å", 0}, + {"space", 1}, + {"°", 0}, + {"y", 1}, + {"ẙ", 0}, + {"dead_abovering", 1}, + {"°", 0}, + {"nobreakspace", 1}, + {"̊", 0}, + {"u", 1}, + {"ů", 0}, + {"w", 1}, + {"ẘ", 0}, + {"A", 1}, + {"Å", 0}, + {"Aacute", 1}, + {"Ǻ", 0}, + {"aacute", 1}, + {"ǻ", 0}, + {"dead_acute", 4}, + {"a", 1}, + {"ǻ", 0}, + {"A", 1}, + {"Ǻ", 0}, + {"U", 1}, + {"Ů", 0}, + {"Greek_accentdieresis", 4}, + {"Greek_iota", 1}, + {"ΐ", 0}, + {"Greek_upsilon", 1}, + {"ΰ", 0}, + {"dead_voiced_sound", 46}, + {"kana_KE", 1}, + {"ゲ", 0}, + {"kana_SA", 1}, + {"ザ", 0}, + {"kana_SE", 1}, + {"ゼ", 0}, + {"kana_SU", 1}, + {"ズ", 0}, + {"kana_WO", 1}, + {"ヺ", 0}, + {"kana_TE", 1}, + {"デ", 0}, + {"kana_HO", 1}, + {"ボ", 0}, + {"kana_HI", 1}, + {"ビ", 0}, + {"kana_WA", 1}, + {"ヷ", 0}, + {"kana_CHI", 1}, + {"ヂ", 0}, + {"kana_HA", 1}, + {"バ", 0}, + {"kana_HE", 1}, + {"ベ", 0}, + {"kana_KO", 1}, + {"ゴ", 0}, + {"kana_FU", 1}, + {"ブ", 0}, + {"kana_KU", 1}, + {"グ", 0}, + {"kana_U", 1}, + {"ヴ", 0}, + {"kana_TO", 1}, + {"ド", 0}, + {"kana_TA", 1}, + {"ダ", 0}, + {"kana_KA", 1}, + {"ガ", 0}, + {"kana_KI", 1}, + {"ギ", 0}, + {"kana_SO", 1}, + {"ゾ", 0}, + {"kana_TSU", 1}, + {"ヅ", 0}, + {"kana_SHI", 1}, + {"ジ", 0}, + {"dead_belowtilde", 14}, + {"e", 1}, + {"ḛ", 0}, + {"i", 1}, + {"ḭ", 0}, + {"u", 1}, + {"ṵ", 0}, + {"E", 1}, + {"Ḛ", 0}, + {"plus", 1}, + {"⨦", 0}, + {"I", 1}, + {"Ḭ", 0}, + {"U", 1}, + {"Ṵ", 0}, + {"dead_ogonek", 35}, + {"a", 1}, + {"ą", 0}, + {"e", 1}, + {"ę", 0}, + {"o", 1}, + {"ǫ", 0}, + {"space", 1}, + {"˛", 0}, + {"dead_macron", 4}, + {"o", 1}, + {"ǭ", 0}, + {"O", 1}, + {"Ǭ", 0}, + {"i", 1}, + {"į", 0}, + {"nobreakspace", 1}, + {"̨", 0}, + {"omacron", 1}, + {"ǭ", 0}, + {"u", 1}, + {"ų", 0}, + {"E", 1}, + {"Ę", 0}, + {"dead_ogonek", 1}, + {"˛", 0}, + {"O", 1}, + {"Ǫ", 0}, + {"A", 1}, + {"Ą", 0}, + {"Omacron", 1}, + {"Ǭ", 0}, + {"I", 1}, + {"Į", 0}, + {"U", 1}, + {"Ų", 0}, + {"dead_dasia", 32}, + {"Greek_IOTA", 1}, + {"Ἱ", 0}, + {"Greek_iota", 1}, + {"ἱ", 0}, + {"Greek_OMICRON", 1}, + {"Ὁ", 0}, + {"Greek_upsilon", 1}, + {"ὑ", 0}, + {"Greek_RHO", 1}, + {"Ῥ", 0}, + {"Greek_epsilon", 1}, + {"ἑ", 0}, + {"Greek_ALPHA", 1}, + {"Ἁ", 0}, + {"Greek_omicron", 1}, + {"ὁ", 0}, + {"Greek_eta", 1}, + {"ἡ", 0}, + {"Greek_rho", 1}, + {"ῥ", 0}, + {"Greek_alpha", 1}, + {"ἁ", 0}, + {"Greek_ETA", 1}, + {"Ἡ", 0}, + {"Greek_EPSILON", 1}, + {"Ἑ", 0}, + {"Greek_omega", 1}, + {"ὡ", 0}, + {"Greek_OMEGA", 1}, + {"Ὡ", 0}, + {"Greek_UPSILON", 1}, + {"Ὑ", 0}, + {"dead_iota", 491}, + {"dead_grave", 59}, + {"Multi_key", 26}, + {"parenright", 12}, + {"Greek_ALPHA", 1}, + {"ᾊ", 0}, + {"Greek_eta", 1}, + {"ᾒ", 0}, + {"Greek_alpha", 1}, + {"ᾂ", 0}, + {"Greek_ETA", 1}, + {"ᾚ", 0}, + {"Greek_omega", 1}, + {"ᾢ", 0}, + {"Greek_OMEGA", 1}, + {"ᾪ", 0}, + {"parenleft", 12}, + {"Greek_ALPHA", 1}, + {"ᾋ", 0}, + {"Greek_eta", 1}, + {"ᾓ", 0}, + {"Greek_alpha", 1}, + {"ᾃ", 0}, + {"Greek_ETA", 1}, + {"ᾛ", 0}, + {"Greek_omega", 1}, + {"ᾣ", 0}, + {"Greek_OMEGA", 1}, + {"ᾫ", 0}, + {"dead_dasia", 12}, + {"Greek_ALPHA", 1}, + {"ᾋ", 0}, + {"Greek_eta", 1}, + {"ᾓ", 0}, + {"Greek_alpha", 1}, + {"ᾃ", 0}, + {"Greek_ETA", 1}, + {"ᾛ", 0}, + {"Greek_omega", 1}, + {"ᾣ", 0}, + {"Greek_OMEGA", 1}, + {"ᾫ", 0}, + {"Greek_eta", 1}, + {"ῂ", 0}, + {"dead_psili", 12}, + {"Greek_ALPHA", 1}, + {"ᾊ", 0}, + {"Greek_eta", 1}, + {"ᾒ", 0}, + {"Greek_alpha", 1}, + {"ᾂ", 0}, + {"Greek_ETA", 1}, + {"ᾚ", 0}, + {"Greek_omega", 1}, + {"ᾢ", 0}, + {"Greek_OMEGA", 1}, + {"ᾪ", 0}, + {"Greek_alpha", 1}, + {"ᾲ", 0}, + {"Greek_omega", 1}, + {"ῲ", 0}, + {"space", 1}, + {"ͺ", 0}, + {"Multi_key", 262}, + {"parenright", 12}, + {"Greek_ALPHA", 1}, + {"ᾈ", 0}, + {"Greek_eta", 1}, + {"ᾐ", 0}, + {"Greek_alpha", 1}, + {"ᾀ", 0}, + {"Greek_ETA", 1}, + {"ᾘ", 0}, + {"Greek_omega", 1}, + {"ᾠ", 0}, + {"Greek_OMEGA", 1}, + {"ᾨ", 0}, + {"acute", 58}, + {"parenright", 12}, + {"Greek_ALPHA", 1}, + {"ᾌ", 0}, + {"Greek_eta", 1}, + {"ᾔ", 0}, + {"Greek_alpha", 1}, + {"ᾄ", 0}, + {"Greek_ETA", 1}, + {"ᾜ", 0}, + {"Greek_omega", 1}, + {"ᾤ", 0}, + {"Greek_OMEGA", 1}, + {"ᾬ", 0}, + {"dead_dasia", 12}, + {"Greek_ALPHA", 1}, + {"ᾍ", 0}, + {"Greek_eta", 1}, + {"ᾕ", 0}, + {"Greek_alpha", 1}, + {"ᾅ", 0}, + {"Greek_ETA", 1}, + {"ᾝ", 0}, + {"Greek_omega", 1}, + {"ᾥ", 0}, + {"Greek_OMEGA", 1}, + {"ᾭ", 0}, + {"Greek_eta", 1}, + {"ῄ", 0}, + {"dead_psili", 12}, + {"Greek_ALPHA", 1}, + {"ᾌ", 0}, + {"Greek_eta", 1}, + {"ᾔ", 0}, + {"Greek_alpha", 1}, + {"ᾄ", 0}, + {"Greek_ETA", 1}, + {"ᾜ", 0}, + {"Greek_omega", 1}, + {"ᾤ", 0}, + {"Greek_OMEGA", 1}, + {"ᾬ", 0}, + {"Greek_alpha", 1}, + {"ᾴ", 0}, + {"Greek_omega", 1}, + {"ῴ", 0}, + {"parenleft", 12}, + {"Greek_ALPHA", 1}, + {"ᾍ", 0}, + {"Greek_eta", 1}, + {"ᾕ", 0}, + {"Greek_alpha", 1}, + {"ᾅ", 0}, + {"Greek_ETA", 1}, + {"ᾝ", 0}, + {"Greek_omega", 1}, + {"ᾥ", 0}, + {"Greek_OMEGA", 1}, + {"ᾭ", 0}, + {"apostrophe", 58}, + {"parenright", 12}, + {"Greek_ALPHA", 1}, + {"ᾌ", 0}, + {"Greek_eta", 1}, + {"ᾔ", 0}, + {"Greek_alpha", 1}, + {"ᾄ", 0}, + {"Greek_ETA", 1}, + {"ᾜ", 0}, + {"Greek_omega", 1}, + {"ᾤ", 0}, + {"Greek_OMEGA", 1}, + {"ᾬ", 0}, + {"dead_dasia", 12}, + {"Greek_ALPHA", 1}, + {"ᾍ", 0}, + {"Greek_eta", 1}, + {"ᾕ", 0}, + {"Greek_alpha", 1}, + {"ᾅ", 0}, + {"Greek_ETA", 1}, + {"ᾝ", 0}, + {"Greek_omega", 1}, + {"ᾥ", 0}, + {"Greek_OMEGA", 1}, + {"ᾭ", 0}, + {"Greek_eta", 1}, + {"ῄ", 0}, + {"dead_psili", 12}, + {"Greek_ALPHA", 1}, + {"ᾌ", 0}, + {"Greek_eta", 1}, + {"ᾔ", 0}, + {"Greek_alpha", 1}, + {"ᾄ", 0}, + {"Greek_ETA", 1}, + {"ᾜ", 0}, + {"Greek_omega", 1}, + {"ᾤ", 0}, + {"Greek_OMEGA", 1}, + {"ᾬ", 0}, + {"Greek_alpha", 1}, + {"ᾴ", 0}, + {"Greek_omega", 1}, + {"ῴ", 0}, + {"parenleft", 12}, + {"Greek_ALPHA", 1}, + {"ᾍ", 0}, + {"Greek_eta", 1}, + {"ᾕ", 0}, + {"Greek_alpha", 1}, + {"ᾅ", 0}, + {"Greek_ETA", 1}, + {"ᾝ", 0}, + {"Greek_omega", 1}, + {"ᾥ", 0}, + {"Greek_OMEGA", 1}, + {"ᾭ", 0}, + {"asciitilde", 58}, + {"parenright", 12}, + {"Greek_ALPHA", 1}, + {"ᾎ", 0}, + {"Greek_eta", 1}, + {"ᾖ", 0}, + {"Greek_alpha", 1}, + {"ᾆ", 0}, + {"Greek_ETA", 1}, + {"ᾞ", 0}, + {"Greek_omega", 1}, + {"ᾦ", 0}, + {"Greek_OMEGA", 1}, + {"ᾮ", 0}, + {"dead_dasia", 12}, + {"Greek_ALPHA", 1}, + {"ᾏ", 0}, + {"Greek_eta", 1}, + {"ᾗ", 0}, + {"Greek_alpha", 1}, + {"ᾇ", 0}, + {"Greek_ETA", 1}, + {"ᾟ", 0}, + {"Greek_omega", 1}, + {"ᾧ", 0}, + {"Greek_OMEGA", 1}, + {"ᾯ", 0}, + {"Greek_eta", 1}, + {"ῇ", 0}, + {"dead_psili", 12}, + {"Greek_ALPHA", 1}, + {"ᾎ", 0}, + {"Greek_eta", 1}, + {"ᾖ", 0}, + {"Greek_alpha", 1}, + {"ᾆ", 0}, + {"Greek_ETA", 1}, + {"ᾞ", 0}, + {"Greek_omega", 1}, + {"ᾦ", 0}, + {"Greek_OMEGA", 1}, + {"ᾮ", 0}, + {"Greek_alpha", 1}, + {"ᾷ", 0}, + {"Greek_omega", 1}, + {"ῷ", 0}, + {"parenleft", 12}, + {"Greek_ALPHA", 1}, + {"ᾏ", 0}, + {"Greek_eta", 1}, + {"ᾗ", 0}, + {"Greek_alpha", 1}, + {"ᾇ", 0}, + {"Greek_ETA", 1}, + {"ᾟ", 0}, + {"Greek_omega", 1}, + {"ᾧ", 0}, + {"Greek_OMEGA", 1}, + {"ᾯ", 0}, + {"parenleft", 12}, + {"Greek_ALPHA", 1}, + {"ᾉ", 0}, + {"Greek_eta", 1}, + {"ᾑ", 0}, + {"Greek_alpha", 1}, + {"ᾁ", 0}, + {"Greek_ETA", 1}, + {"ᾙ", 0}, + {"Greek_omega", 1}, + {"ᾡ", 0}, + {"Greek_OMEGA", 1}, + {"ᾩ", 0}, + {"grave", 58}, + {"parenright", 12}, + {"Greek_ALPHA", 1}, + {"ᾊ", 0}, + {"Greek_eta", 1}, + {"ᾒ", 0}, + {"Greek_alpha", 1}, + {"ᾂ", 0}, + {"Greek_ETA", 1}, + {"ᾚ", 0}, + {"Greek_omega", 1}, + {"ᾢ", 0}, + {"Greek_OMEGA", 1}, + {"ᾪ", 0}, + {"dead_dasia", 12}, + {"Greek_ALPHA", 1}, + {"ᾋ", 0}, + {"Greek_eta", 1}, + {"ᾓ", 0}, + {"Greek_alpha", 1}, + {"ᾃ", 0}, + {"Greek_ETA", 1}, + {"ᾛ", 0}, + {"Greek_omega", 1}, + {"ᾣ", 0}, + {"Greek_OMEGA", 1}, + {"ᾫ", 0}, + {"Greek_eta", 1}, + {"ῂ", 0}, + {"dead_psili", 12}, + {"Greek_ALPHA", 1}, + {"ᾊ", 0}, + {"Greek_eta", 1}, + {"ᾒ", 0}, + {"Greek_alpha", 1}, + {"ᾂ", 0}, + {"Greek_ETA", 1}, + {"ᾚ", 0}, + {"Greek_omega", 1}, + {"ᾢ", 0}, + {"Greek_OMEGA", 1}, + {"ᾪ", 0}, + {"Greek_alpha", 1}, + {"ᾲ", 0}, + {"Greek_omega", 1}, + {"ῲ", 0}, + {"parenleft", 12}, + {"Greek_ALPHA", 1}, + {"ᾋ", 0}, + {"Greek_eta", 1}, + {"ᾓ", 0}, + {"Greek_alpha", 1}, + {"ᾃ", 0}, + {"Greek_ETA", 1}, + {"ᾛ", 0}, + {"Greek_omega", 1}, + {"ᾣ", 0}, + {"Greek_OMEGA", 1}, + {"ᾫ", 0}, + {"dead_tilde", 59}, + {"Multi_key", 26}, + {"parenright", 12}, + {"Greek_ALPHA", 1}, + {"ᾎ", 0}, + {"Greek_eta", 1}, + {"ᾖ", 0}, + {"Greek_alpha", 1}, + {"ᾆ", 0}, + {"Greek_ETA", 1}, + {"ᾞ", 0}, + {"Greek_omega", 1}, + {"ᾦ", 0}, + {"Greek_OMEGA", 1}, + {"ᾮ", 0}, + {"parenleft", 12}, + {"Greek_ALPHA", 1}, + {"ᾏ", 0}, + {"Greek_eta", 1}, + {"ᾗ", 0}, + {"Greek_alpha", 1}, + {"ᾇ", 0}, + {"Greek_ETA", 1}, + {"ᾟ", 0}, + {"Greek_omega", 1}, + {"ᾧ", 0}, + {"Greek_OMEGA", 1}, + {"ᾯ", 0}, + {"dead_dasia", 12}, + {"Greek_ALPHA", 1}, + {"ᾏ", 0}, + {"Greek_eta", 1}, + {"ᾗ", 0}, + {"Greek_alpha", 1}, + {"ᾇ", 0}, + {"Greek_ETA", 1}, + {"ᾟ", 0}, + {"Greek_omega", 1}, + {"ᾧ", 0}, + {"Greek_OMEGA", 1}, + {"ᾯ", 0}, + {"Greek_eta", 1}, + {"ῇ", 0}, + {"dead_psili", 12}, + {"Greek_ALPHA", 1}, + {"ᾎ", 0}, + {"Greek_eta", 1}, + {"ᾖ", 0}, + {"Greek_alpha", 1}, + {"ᾆ", 0}, + {"Greek_ETA", 1}, + {"ᾞ", 0}, + {"Greek_omega", 1}, + {"ᾦ", 0}, + {"Greek_OMEGA", 1}, + {"ᾮ", 0}, + {"Greek_alpha", 1}, + {"ᾷ", 0}, + {"Greek_omega", 1}, + {"ῷ", 0}, + {"Greek_ALPHA", 1}, + {"ᾼ", 0}, + {"dead_dasia", 12}, + {"Greek_ALPHA", 1}, + {"ᾉ", 0}, + {"Greek_eta", 1}, + {"ᾑ", 0}, + {"Greek_alpha", 1}, + {"ᾁ", 0}, + {"Greek_ETA", 1}, + {"ᾙ", 0}, + {"Greek_omega", 1}, + {"ᾡ", 0}, + {"Greek_OMEGA", 1}, + {"ᾩ", 0}, + {"Greek_eta", 1}, + {"ῃ", 0}, + {"dead_iota", 1}, + {"ͺ", 0}, + {"dead_psili", 12}, + {"Greek_ALPHA", 1}, + {"ᾈ", 0}, + {"Greek_eta", 1}, + {"ᾐ", 0}, + {"Greek_alpha", 1}, + {"ᾀ", 0}, + {"Greek_ETA", 1}, + {"ᾘ", 0}, + {"Greek_omega", 1}, + {"ᾠ", 0}, + {"Greek_OMEGA", 1}, + {"ᾨ", 0}, + {"Greek_alpha", 1}, + {"ᾳ", 0}, + {"Greek_ETA", 1}, + {"ῌ", 0}, + {"Greek_omegaaccent", 1}, + {"ῴ", 0}, + {"Greek_omega", 1}, + {"ῳ", 0}, + {"Greek_OMEGA", 1}, + {"ῼ", 0}, + {"dead_acute", 59}, + {"Multi_key", 26}, + {"parenright", 12}, + {"Greek_ALPHA", 1}, + {"ᾌ", 0}, + {"Greek_eta", 1}, + {"ᾔ", 0}, + {"Greek_alpha", 1}, + {"ᾄ", 0}, + {"Greek_ETA", 1}, + {"ᾜ", 0}, + {"Greek_omega", 1}, + {"ᾤ", 0}, + {"Greek_OMEGA", 1}, + {"ᾬ", 0}, + {"parenleft", 12}, + {"Greek_ALPHA", 1}, + {"ᾍ", 0}, + {"Greek_eta", 1}, + {"ᾕ", 0}, + {"Greek_alpha", 1}, + {"ᾅ", 0}, + {"Greek_ETA", 1}, + {"ᾝ", 0}, + {"Greek_omega", 1}, + {"ᾥ", 0}, + {"Greek_OMEGA", 1}, + {"ᾭ", 0}, + {"dead_dasia", 12}, + {"Greek_ALPHA", 1}, + {"ᾍ", 0}, + {"Greek_eta", 1}, + {"ᾕ", 0}, + {"Greek_alpha", 1}, + {"ᾅ", 0}, + {"Greek_ETA", 1}, + {"ᾝ", 0}, + {"Greek_omega", 1}, + {"ᾥ", 0}, + {"Greek_OMEGA", 1}, + {"ᾭ", 0}, + {"Greek_eta", 1}, + {"ῄ", 0}, + {"dead_psili", 12}, + {"Greek_ALPHA", 1}, + {"ᾌ", 0}, + {"Greek_eta", 1}, + {"ᾔ", 0}, + {"Greek_alpha", 1}, + {"ᾄ", 0}, + {"Greek_ETA", 1}, + {"ᾜ", 0}, + {"Greek_omega", 1}, + {"ᾤ", 0}, + {"Greek_OMEGA", 1}, + {"ᾬ", 0}, + {"Greek_alpha", 1}, + {"ᾴ", 0}, + {"Greek_omega", 1}, + {"ῴ", 0}, + {"Greek_alphaaccent", 1}, + {"ᾴ", 0}, + {"Greek_etaaccent", 1}, + {"ῄ", 0}, + {"dead_greek", 121}, + {"W", 1}, + {"Ω", 0}, + {"g", 1}, + {"γ", 0}, + {"a", 1}, + {"α", 0}, + {"e", 1}, + {"ε", 0}, + {"F", 1}, + {"Φ", 0}, + {"o", 1}, + {"ο", 0}, + {"l", 1}, + {"λ", 0}, + {"t", 1}, + {"τ", 0}, + {"space", 1}, + {"µ", 0}, + {"dead_macron", 12}, + {"a", 1}, + {"ᾱ", 0}, + {"i", 1}, + {"ῑ", 0}, + {"u", 1}, + {"ῡ", 0}, + {"A", 1}, + {"Ᾱ", 0}, + {"I", 1}, + {"Ῑ", 0}, + {"U", 1}, + {"Ῡ", 0}, + {"Q", 1}, + {"Χ", 0}, + {"y", 1}, + {"ψ", 0}, + {"b", 1}, + {"β", 0}, + {"i", 1}, + {"ι", 0}, + {"k", 1}, + {"κ", 0}, + {"n", 1}, + {"ν", 0}, + {"j", 1}, + {"θ", 0}, + {"x", 1}, + {"ξ", 0}, + {"q", 1}, + {"χ", 0}, + {"nobreakspace", 1}, + {"µ", 0}, + {"u", 1}, + {"υ", 0}, + {"z", 1}, + {"ζ", 0}, + {"G", 1}, + {"Γ", 0}, + {"H", 1}, + {"Η", 0}, + {"E", 1}, + {"Ε", 0}, + {"S", 1}, + {"Σ", 0}, + {"Y", 1}, + {"Ψ", 0}, + {"f", 1}, + {"φ", 0}, + {"d", 1}, + {"δ", 0}, + {"dead_greek", 1}, + {"µ", 0}, + {"D", 1}, + {"Δ", 0}, + {"w", 1}, + {"ω", 0}, + {"p", 1}, + {"π", 0}, + {"J", 1}, + {"Θ", 0}, + {"P", 1}, + {"Π", 0}, + {"M", 1}, + {"Μ", 0}, + {"O", 1}, + {"Ο", 0}, + {"m", 1}, + {"μ", 0}, + {"r", 1}, + {"ρ", 0}, + {"s", 1}, + {"σ", 0}, + {"Z", 1}, + {"Ζ", 0}, + {"dead_stroke", 2}, + {"r", 1}, + {"ϼ", 0}, + {"A", 1}, + {"Α", 0}, + {"R", 1}, + {"Ρ", 0}, + {"L", 1}, + {"Λ", 0}, + {"T", 1}, + {"Τ", 0}, + {"dead_hook", 2}, + {"U", 1}, + {"ϒ", 0}, + {"K", 1}, + {"Κ", 0}, + {"B", 1}, + {"Β", 0}, + {"X", 1}, + {"Ξ", 0}, + {"h", 1}, + {"η", 0}, + {"I", 1}, + {"Ι", 0}, + {"N", 1}, + {"Ν", 0}, + {"U", 1}, + {"Υ", 0}, + {"dead_invertedbreve", 24}, + {"Cyrillic_er", 1}, + {"р̑", 0}, + {"Cyrillic_I", 1}, + {"И̑", 0}, + {"Cyrillic_O", 1}, + {"О̑", 0}, + {"Cyrillic_a", 1}, + {"а̑", 0}, + {"Cyrillic_ER", 1}, + {"Р̑", 0}, + {"Cyrillic_U", 1}, + {"У̑", 0}, + {"Cyrillic_ie", 1}, + {"е̑", 0}, + {"Cyrillic_i", 1}, + {"и̑", 0}, + {"Cyrillic_o", 1}, + {"о̑", 0}, + {"Cyrillic_A", 1}, + {"А̑", 0}, + {"Cyrillic_IE", 1}, + {"Е̑", 0}, + {"Cyrillic_u", 1}, + {"у̑", 0}, + {"dead_psili", 28}, + {"Greek_IOTA", 1}, + {"Ἰ", 0}, + {"Greek_iota", 1}, + {"ἰ", 0}, + {"Greek_OMICRON", 1}, + {"Ὀ", 0}, + {"Greek_upsilon", 1}, + {"ὐ", 0}, + {"Greek_epsilon", 1}, + {"ἐ", 0}, + {"Greek_ALPHA", 1}, + {"Ἀ", 0}, + {"Greek_omicron", 1}, + {"ὀ", 0}, + {"Greek_eta", 1}, + {"ἠ", 0}, + {"Greek_rho", 1}, + {"ῤ", 0}, + {"Greek_alpha", 1}, + {"ἀ", 0}, + {"Greek_ETA", 1}, + {"Ἠ", 0}, + {"Greek_EPSILON", 1}, + {"Ἐ", 0}, + {"Greek_omega", 1}, + {"ὠ", 0}, + {"Greek_OMEGA", 1}, + {"Ὠ", 0}, + {"dead_abovedot", 159}, + {"W", 1}, + {"Ẇ", 0}, + {"g", 1}, + {"ġ", 0}, + {"a", 1}, + {"ȧ", 0}, + {"C", 1}, + {"Ċ", 0}, + {"e", 1}, + {"ė", 0}, + {"F", 1}, + {"Ḟ", 0}, + {"o", 1}, + {"ȯ", 0}, + {"l", 1}, + {"ŀ", 0}, + {"t", 1}, + {"ṫ", 0}, + {"dead_belowdot", 4}, + {"S", 1}, + {"Ṩ", 0}, + {"s", 1}, + {"ṩ", 0}, + {"space", 1}, + {"˙", 0}, + {"dead_macron", 8}, + {"a", 1}, + {"ǡ", 0}, + {"o", 1}, + {"ȱ", 0}, + {"O", 1}, + {"Ȱ", 0}, + {"A", 1}, + {"Ǡ", 0}, + {"y", 1}, + {"ẏ", 0}, + {"b", 1}, + {"ḃ", 0}, + {"Multi_key", 23}, + {"exclam", 4}, + {"S", 1}, + {"Ṩ", 0}, + {"s", 1}, + {"ṩ", 0}, + {"f", 2}, + {"s", 1}, + {"ẛ", 0}, + {"acute", 4}, + {"S", 1}, + {"Ṥ", 0}, + {"s", 1}, + {"ṥ", 0}, + {"apostrophe", 4}, + {"S", 1}, + {"Ṥ", 0}, + {"s", 1}, + {"ṥ", 0}, + {"c", 4}, + {"S", 1}, + {"Ṧ", 0}, + {"s", 1}, + {"ṧ", 0}, + {"i", 1}, + {"ı", 0}, + {"n", 1}, + {"ṅ", 0}, + {"dead_caron", 4}, + {"S", 1}, + {"Ṧ", 0}, + {"s", 1}, + {"ṧ", 0}, + {"j", 1}, + {"ȷ", 0}, + {"x", 1}, + {"ẋ", 0}, + {"amacron", 1}, + {"ǡ", 0}, + {"nobreakspace", 1}, + {"̇", 0}, + {"omacron", 1}, + {"ȱ", 0}, + {"z", 1}, + {"ż", 0}, + {"G", 1}, + {"Ġ", 0}, + {"Sacute", 1}, + {"Ṥ", 0}, + {"H", 1}, + {"Ḣ", 0}, + {"E", 1}, + {"Ė", 0}, + {"S", 1}, + {"Ṡ", 0}, + {"Y", 1}, + {"Ẏ", 0}, + {"scaron", 1}, + {"ṧ", 0}, + {"f", 1}, + {"ḟ", 0}, + {"d", 1}, + {"ḋ", 0}, + {"Scaron", 1}, + {"Ṧ", 0}, + {"D", 1}, + {"Ḋ", 0}, + {"dead_abovedot", 1}, + {"˙", 0}, + {"w", 1}, + {"ẇ", 0}, + {"p", 1}, + {"ṗ", 0}, + {"P", 1}, + {"Ṗ", 0}, + {"M", 1}, + {"Ṁ", 0}, + {"O", 1}, + {"Ȯ", 0}, + {"m", 1}, + {"ṁ", 0}, + {"r", 1}, + {"ṙ", 0}, + {"s", 1}, + {"ṡ", 0}, + {"Z", 1}, + {"Ż", 0}, + {"sacute", 1}, + {"ṥ", 0}, + {"dead_stroke", 2}, + {"j", 1}, + {"ɟ", 0}, + {"A", 1}, + {"Ȧ", 0}, + {"R", 1}, + {"Ṙ", 0}, + {"c", 1}, + {"ċ", 0}, + {"L", 1}, + {"Ŀ", 0}, + {"T", 1}, + {"Ṫ", 0}, + {"Omacron", 1}, + {"Ȱ", 0}, + {"B", 1}, + {"Ḃ", 0}, + {"Amacron", 1}, + {"Ǡ", 0}, + {"dead_acute", 4}, + {"S", 1}, + {"Ṥ", 0}, + {"s", 1}, + {"ṥ", 0}, + {"X", 1}, + {"Ẋ", 0}, + {"h", 1}, + {"ḣ", 0}, + {"I", 1}, + {"İ", 0}, + {"N", 1}, + {"Ṅ", 0}, + {"dead_double_grave", 24}, + {"a", 1}, + {"ȁ", 0}, + {"e", 1}, + {"ȅ", 0}, + {"o", 1}, + {"ȍ", 0}, + {"i", 1}, + {"ȉ", 0}, + {"u", 1}, + {"ȕ", 0}, + {"E", 1}, + {"Ȅ", 0}, + {"O", 1}, + {"Ȍ", 0}, + {"r", 1}, + {"ȑ", 0}, + {"A", 1}, + {"Ȁ", 0}, + {"R", 1}, + {"Ȑ", 0}, + {"I", 1}, + {"Ȉ", 0}, + {"U", 1}, + {"Ȕ", 0}, + {"dead_semivoiced_sound", 10}, + {"kana_HO", 1}, + {"ポ", 0}, + {"kana_HI", 1}, + {"ピ", 0}, + {"kana_HA", 1}, + {"パ", 0}, + {"kana_HE", 1}, + {"ペ", 0}, + {"kana_FU", 1}, + {"プ", 0}, + {"dead_stroke", 101}, + {"g", 1}, + {"ǥ", 0}, + {"a", 1}, + {"ⱥ", 0}, + {"C", 1}, + {"Ȼ", 0}, + {"less", 1}, + {"≮", 0}, + {"Oacute", 1}, + {"Ǿ", 0}, + {"e", 1}, + {"ɇ", 0}, + {"o", 1}, + {"ø", 0}, + {"l", 1}, + {"ł", 0}, + {"t", 1}, + {"ŧ", 0}, + {"space", 1}, + {"/", 0}, + {"y", 1}, + {"ɏ", 0}, + {"b", 1}, + {"ƀ", 0}, + {"oacute", 1}, + {"ǿ", 0}, + {"i", 1}, + {"ɨ", 0}, + {"equal", 1}, + {"≠", 0}, + {"j", 1}, + {"ɉ", 0}, + {"nobreakspace", 1}, + {"̸", 0}, + {"u", 1}, + {"ʉ", 0}, + {"greaterthanequal", 1}, + {"≱", 0}, + {"z", 1}, + {"ƶ", 0}, + {"G", 1}, + {"Ǥ", 0}, + {"H", 1}, + {"Ħ", 0}, + {"E", 1}, + {"Ɇ", 0}, + {"2", 1}, + {"ƻ", 0}, + {"Y", 1}, + {"Ɏ", 0}, + {"d", 1}, + {"đ", 0}, + {"dead_greek", 2}, + {"r", 1}, + {"ϼ", 0}, + {"D", 1}, + {"Đ", 0}, + {"dead_abovedot", 2}, + {"j", 1}, + {"ɟ", 0}, + {"lessthanequal", 1}, + {"≰", 0}, + {"p", 1}, + {"ᵽ", 0}, + {"J", 1}, + {"Ɉ", 0}, + {"P", 1}, + {"Ᵽ", 0}, + {"O", 1}, + {"Ø", 0}, + {"r", 1}, + {"ɍ", 0}, + {"Z", 1}, + {"Ƶ", 0}, + {"dead_stroke", 1}, + {"/", 0}, + {"A", 1}, + {"Ⱥ", 0}, + {"R", 1}, + {"Ɍ", 0}, + {"c", 1}, + {"ȼ", 0}, + {"L", 1}, + {"Ł", 0}, + {"T", 1}, + {"Ŧ", 0}, + {"greater", 1}, + {"≯", 0}, + {"B", 1}, + {"Ƀ", 0}, + {"dead_acute", 4}, + {"o", 1}, + {"ǿ", 0}, + {"O", 1}, + {"Ǿ", 0}, + {"h", 1}, + {"ħ", 0}, + {"I", 1}, + {"Ɨ", 0}, + {"U", 1}, + {"Ʉ", 0}, + {"dead_hook", 179}, + {"W", 1}, + {"Ⱳ", 0}, + {"dead_breve", 4}, + {"a", 1}, + {"ẳ", 0}, + {"A", 1}, + {"Ẳ", 0}, + {"g", 1}, + {"ɠ", 0}, + {"a", 1}, + {"ả", 0}, + {"dead_circumflex", 12}, + {"a", 1}, + {"ẩ", 0}, + {"e", 1}, + {"ể", 0}, + {"o", 1}, + {"ổ", 0}, + {"E", 1}, + {"Ể", 0}, + {"O", 1}, + {"Ổ", 0}, + {"A", 1}, + {"Ẩ", 0}, + {"dead_horn", 8}, + {"o", 1}, + {"ở", 0}, + {"u", 1}, + {"ử", 0}, + {"O", 1}, + {"Ở", 0}, + {"U", 1}, + {"Ử", 0}, + {"Acircumflex", 1}, + {"Ẩ", 0}, + {"C", 1}, + {"Ƈ", 0}, + {"e", 1}, + {"ẻ", 0}, + {"F", 1}, + {"Ƒ", 0}, + {"o", 1}, + {"ỏ", 0}, + {"t", 1}, + {"ƭ", 0}, + {"schwa", 1}, + {"ɚ", 0}, + {"uhorn", 1}, + {"ử", 0}, + {"space", 1}, + {"̉", 0}, + {"acircumflex", 1}, + {"ẩ", 0}, + {"Ecircumflex", 1}, + {"Ể", 0}, + {"y", 1}, + {"ỷ", 0}, + {"b", 1}, + {"ɓ", 0}, + {"Multi_key", 32}, + {"b", 4}, + {"a", 1}, + {"ẳ", 0}, + {"A", 1}, + {"Ẳ", 0}, + {"plus", 8}, + {"o", 1}, + {"ở", 0}, + {"u", 1}, + {"ử", 0}, + {"O", 1}, + {"Ở", 0}, + {"U", 1}, + {"Ử", 0}, + {"U", 4}, + {"a", 1}, + {"ẳ", 0}, + {"A", 1}, + {"Ẳ", 0}, + {"asciicircum", 12}, + {"a", 1}, + {"ẩ", 0}, + {"e", 1}, + {"ể", 0}, + {"o", 1}, + {"ổ", 0}, + {"E", 1}, + {"Ể", 0}, + {"O", 1}, + {"Ổ", 0}, + {"A", 1}, + {"Ẩ", 0}, + {"i", 1}, + {"ỉ", 0}, + {"k", 1}, + {"ƙ", 0}, + {"n", 1}, + {"ɲ", 0}, + {"Ohorn", 1}, + {"Ở", 0}, + {"ohorn", 1}, + {"ở", 0}, + {"q", 1}, + {"ʠ", 0}, + {"nobreakspace", 1}, + {"̉", 0}, + {"V", 1}, + {"Ʋ", 0}, + {"Ocircumflex", 1}, + {"Ổ", 0}, + {"ocircumflex", 1}, + {"ổ", 0}, + {"u", 1}, + {"ủ", 0}, + {"z", 1}, + {"ȥ", 0}, + {"G", 1}, + {"Ɠ", 0}, + {"E", 1}, + {"Ẻ", 0}, + {"Y", 1}, + {"Ỷ", 0}, + {"f", 1}, + {"ƒ", 0}, + {"d", 1}, + {"ɗ", 0}, + {"dead_greek", 2}, + {"U", 1}, + {"ϒ", 0}, + {"D", 1}, + {"Ɗ", 0}, + {"Abreve", 1}, + {"Ẳ", 0}, + {"ecircumflex", 1}, + {"ể", 0}, + {"w", 1}, + {"ⱳ", 0}, + {"p", 1}, + {"ƥ", 0}, + {"v", 1}, + {"ʋ", 0}, + {"P", 1}, + {"Ƥ", 0}, + {"M", 1}, + {"Ɱ", 0}, + {"O", 1}, + {"Ỏ", 0}, + {"abreve", 1}, + {"ẳ", 0}, + {"m", 1}, + {"ɱ", 0}, + {"r", 1}, + {"ɼ", 0}, + {"s", 1}, + {"ʂ", 0}, + {"Z", 1}, + {"Ȥ", 0}, + {"A", 1}, + {"Ả", 0}, + {"c", 1}, + {"ƈ", 0}, + {"T", 1}, + {"Ƭ", 0}, + {"dead_hook", 1}, + {"̉", 0}, + {"K", 1}, + {"Ƙ", 0}, + {"B", 1}, + {"Ɓ", 0}, + {"Uhorn", 1}, + {"Ử", 0}, + {"h", 1}, + {"ɦ", 0}, + {"I", 1}, + {"Ỉ", 0}, + {"N", 1}, + {"Ɲ", 0}, + {"U", 1}, + {"Ủ", 0}, + {"dead_belowbreve", 4}, + {"H", 1}, + {"Ḫ", 0}, + {"h", 1}, + {"ḫ", 0}, + {"dead_cedilla", 73}, + {"dead_breve", 4}, + {"e", 1}, + {"ḝ", 0}, + {"E", 1}, + {"Ḝ", 0}, + {"g", 1}, + {"ģ", 0}, + {"dead_currency", 4}, + {"C", 1}, + {"₵", 0}, + {"c", 1}, + {"₵", 0}, + {"C", 1}, + {"Ç", 0}, + {"e", 1}, + {"ȩ", 0}, + {"l", 1}, + {"ļ", 0}, + {"t", 1}, + {"ţ", 0}, + {"ColonSign", 1}, + {"₵", 0}, + {"space", 1}, + {"¸", 0}, + {"k", 1}, + {"ķ", 0}, + {"n", 1}, + {"ņ", 0}, + {"nobreakspace", 1}, + {"̧", 0}, + {"G", 1}, + {"Ģ", 0}, + {"H", 1}, + {"Ḩ", 0}, + {"E", 1}, + {"Ȩ", 0}, + {"S", 1}, + {"Ş", 0}, + {"Cacute", 1}, + {"Ḉ", 0}, + {"d", 1}, + {"ḑ", 0}, + {"D", 1}, + {"Ḑ", 0}, + {"cent", 1}, + {"₵", 0}, + {"cacute", 1}, + {"ḉ", 0}, + {"r", 1}, + {"ŗ", 0}, + {"s", 1}, + {"ş", 0}, + {"R", 1}, + {"Ŗ", 0}, + {"c", 1}, + {"ç", 0}, + {"L", 1}, + {"Ļ", 0}, + {"T", 1}, + {"Ţ", 0}, + {"K", 1}, + {"Ķ", 0}, + {"dead_cedilla", 1}, + {"¸", 0}, + {"dead_acute", 4}, + {"C", 1}, + {"Ḉ", 0}, + {"c", 1}, + {"ḉ", 0}, + {"h", 1}, + {"ḩ", 0}, + {"N", 1}, + {"Ņ", 0}, + {"dead_inverted_breve", 24}, + {"a", 1}, + {"ȃ", 0}, + {"e", 1}, + {"ȇ", 0}, + {"o", 1}, + {"ȏ", 0}, + {"i", 1}, + {"ȋ", 0}, + {"u", 1}, + {"ȗ", 0}, + {"E", 1}, + {"Ȇ", 0}, + {"O", 1}, + {"Ȏ", 0}, + {"r", 1}, + {"ȓ", 0}, + {"A", 1}, + {"Ȃ", 0}, + {"R", 1}, + {"Ȓ", 0}, + {"I", 1}, + {"Ȋ", 0}, + {"U", 1}, + {"Ȗ", 0}, + {"dead_diaeresis", 190}, + {"W", 1}, + {"Ẅ", 0}, + {"a", 1}, + {"ä", 0}, + {"Greek_IOTA", 1}, + {"Ϊ", 0}, + {"dead_grave", 4}, + {"u", 1}, + {"ǜ", 0}, + {"U", 1}, + {"Ǜ", 0}, + {"Greek_iota", 1}, + {"ϊ", 0}, + {"Umacron", 1}, + {"Ṻ", 0}, + {"Cyrillic_ZE", 1}, + {"Ӟ", 0}, + {"dead_belowdiaeresis", 2}, + {"equal", 1}, + {"⩷", 0}, + {"e", 1}, + {"ë", 0}, + {"o", 1}, + {"ö", 0}, + {"iacute", 1}, + {"ḯ", 0}, + {"Cyrillic_ze", 1}, + {"ӟ", 0}, + {"t", 1}, + {"ẗ", 0}, + {"Greek_upsilon", 1}, + {"ϋ", 0}, + {"space", 1}, + {"\"", 0}, + {"dead_macron", 12}, + {"a", 1}, + {"ǟ", 0}, + {"o", 1}, + {"ȫ", 0}, + {"u", 1}, + {"ṻ", 0}, + {"O", 1}, + {"Ȫ", 0}, + {"A", 1}, + {"Ǟ", 0}, + {"U", 1}, + {"Ṻ", 0}, + {"Cyrillic_I", 1}, + {"Ӥ", 0}, + {"y", 1}, + {"ÿ", 0}, + {"Multi_key", 15}, + {"underscore", 4}, + {"u", 1}, + {"ṻ", 0}, + {"U", 1}, + {"Ṻ", 0}, + {"macron", 4}, + {"u", 1}, + {"ṻ", 0}, + {"U", 1}, + {"Ṻ", 0}, + {"asciitilde", 4}, + {"o", 1}, + {"ṏ", 0}, + {"O", 1}, + {"Ṏ", 0}, + {"Cyrillic_O", 1}, + {"Ӧ", 0}, + {"i", 1}, + {"ï", 0}, + {"Ukrainian_I", 1}, + {"Ї", 0}, + {"dead_caron", 4}, + {"u", 1}, + {"ǚ", 0}, + {"U", 1}, + {"Ǚ", 0}, + {"dead_tilde", 4}, + {"o", 1}, + {"ṏ", 0}, + {"O", 1}, + {"Ṏ", 0}, + {"Cyrillic_che", 1}, + {"ӵ", 0}, + {"Uacute", 1}, + {"Ǘ", 0}, + {"Cyrillic_a", 1}, + {"ӓ", 0}, + {"Ugrave", 1}, + {"Ǜ", 0}, + {"x", 1}, + {"ẍ", 0}, + {"amacron", 1}, + {"ǟ", 0}, + {"Cyrillic_U", 1}, + {"Ӱ", 0}, + {"nobreakspace", 1}, + {"̈", 0}, + {"omacron", 1}, + {"ȫ", 0}, + {"uacute", 1}, + {"ǘ", 0}, + {"u", 1}, + {"ü", 0}, + {"otilde", 1}, + {"ṏ", 0}, + {"Iacute", 1}, + {"Ḯ", 0}, + {"H", 1}, + {"Ḧ", 0}, + {"Cyrillic_YERU", 1}, + {"Ӹ", 0}, + {"Cyrillic_ie", 1}, + {"ё", 0}, + {"E", 1}, + {"Ë", 0}, + {"Y", 1}, + {"Ÿ", 0}, + {"Cyrillic_i", 1}, + {"ӥ", 0}, + {"Otilde", 1}, + {"Ṏ", 0}, + {"Cyrillic_zhe", 1}, + {"ӝ", 0}, + {"umacron", 1}, + {"ṻ", 0}, + {"Cyrillic_yeru", 1}, + {"ӹ", 0}, + {"acute", 1}, + {"̈́", 0}, + {"w", 1}, + {"ẅ", 0}, + {"Cyrillic_CHE", 1}, + {"Ӵ", 0}, + {"Cyrillic_o", 1}, + {"ӧ", 0}, + {"Ukrainian_i", 1}, + {"ї", 0}, + {"Cyrillic_E", 1}, + {"Ӭ", 0}, + {"apostrophe", 1}, + {"̈́", 0}, + {"O", 1}, + {"Ö", 0}, + {"A", 1}, + {"Ä", 0}, + {"Cyrillic_A", 1}, + {"Ӓ", 0}, + {"ugrave", 1}, + {"ǜ", 0}, + {"Omacron", 1}, + {"Ȫ", 0}, + {"Cyrillic_ZHE", 1}, + {"Ӝ", 0}, + {"Cyrillic_IE", 1}, + {"Ё", 0}, + {"dead_diaeresis", 1}, + {"¨", 0}, + {"Amacron", 1}, + {"Ǟ", 0}, + {"Cyrillic_e", 1}, + {"ӭ", 0}, + {"dead_acute", 14}, + {"Greek_iota", 1}, + {"ΐ", 0}, + {"Greek_upsilon", 1}, + {"ΰ", 0}, + {"space", 1}, + {"΅", 0}, + {"i", 1}, + {"ḯ", 0}, + {"u", 1}, + {"ǘ", 0}, + {"I", 1}, + {"Ḯ", 0}, + {"U", 1}, + {"Ǘ", 0}, + {"X", 1}, + {"Ẍ", 0}, + {"h", 1}, + {"ḧ", 0}, + {"I", 1}, + {"Ï", 0}, + {"U", 1}, + {"Ü", 0}, + {"Cyrillic_u", 1}, + {"ӱ", 0}, + {"Greek_UPSILON", 1}, + {"Ϋ", 0}, + {"dead_acute", 500}, + {"W", 1}, + {"Ẃ", 0}, + {"dead_breve", 4}, + {"a", 1}, + {"ắ", 0}, + {"A", 1}, + {"Ắ", 0}, + {"g", 1}, + {"ǵ", 0}, + {"a", 1}, + {"á", 0}, + {"Greek_IOTA", 1}, + {"Ί", 0}, + {"Greek_iota", 1}, + {"ί", 0}, + {"dead_horn", 8}, + {"o", 1}, + {"ớ", 0}, + {"u", 1}, + {"ứ", 0}, + {"O", 1}, + {"Ớ", 0}, + {"U", 1}, + {"Ứ", 0}, + {"dead_circumflex", 12}, + {"a", 1}, + {"ấ", 0}, + {"e", 1}, + {"ế", 0}, + {"o", 1}, + {"ố", 0}, + {"E", 1}, + {"Ế", 0}, + {"O", 1}, + {"Ố", 0}, + {"A", 1}, + {"Ấ", 0}, + {"Greek_OMICRON", 1}, + {"Ό", 0}, + {"Acircumflex", 1}, + {"Ấ", 0}, + {"C", 1}, + {"Ć", 0}, + {"Cyrillic_er", 1}, + {"р́", 0}, + {"e", 1}, + {"é", 0}, + {"Utilde", 1}, + {"Ṹ", 0}, + {"o", 1}, + {"ó", 0}, + {"l", 1}, + {"ĺ", 0}, + {"Udiaeresis", 1}, + {"Ǘ", 0}, + {"Greek_upsilon", 1}, + {"ύ", 0}, + {"uhorn", 1}, + {"ứ", 0}, + {"space", 1}, + {"'", 0}, + {"dead_macron", 8}, + {"e", 1}, + {"ḗ", 0}, + {"o", 1}, + {"ṓ", 0}, + {"E", 1}, + {"Ḗ", 0}, + {"O", 1}, + {"Ṓ", 0}, + {"acircumflex", 1}, + {"ấ", 0}, + {"Ecircumflex", 1}, + {"Ế", 0}, + {"Cyrillic_I", 1}, + {"И́", 0}, + {"y", 1}, + {"ý", 0}, + {"Multi_key", 153}, + {"KP_Divide", 4}, + {"o", 1}, + {"ǿ", 0}, + {"O", 1}, + {"Ǿ", 0}, + {"o", 4}, + {"a", 1}, + {"ǻ", 0}, + {"A", 1}, + {"Ǻ", 0}, + {"b", 4}, + {"a", 1}, + {"ắ", 0}, + {"A", 1}, + {"Ắ", 0}, + {"parenright", 26}, + {"Greek_IOTA", 1}, + {"Ἴ", 0}, + {"Greek_iota", 1}, + {"ἴ", 0}, + {"Greek_OMICRON", 1}, + {"Ὄ", 0}, + {"Greek_upsilon", 1}, + {"ὔ", 0}, + {"Greek_epsilon", 1}, + {"ἔ", 0}, + {"Greek_ALPHA", 1}, + {"Ἄ", 0}, + {"Greek_omicron", 1}, + {"ὄ", 0}, + {"Greek_eta", 1}, + {"ἤ", 0}, + {"Greek_alpha", 1}, + {"ἄ", 0}, + {"Greek_ETA", 1}, + {"Ἤ", 0}, + {"Greek_EPSILON", 1}, + {"Ἔ", 0}, + {"Greek_omega", 1}, + {"ὤ", 0}, + {"Greek_OMEGA", 1}, + {"Ὤ", 0}, + {"quotedbl", 12}, + {"Greek_iota", 1}, + {"ΐ", 0}, + {"Greek_upsilon", 1}, + {"ΰ", 0}, + {"i", 1}, + {"ḯ", 0}, + {"u", 1}, + {"ǘ", 0}, + {"I", 1}, + {"Ḯ", 0}, + {"U", 1}, + {"Ǘ", 0}, + {"plus", 8}, + {"o", 1}, + {"ớ", 0}, + {"u", 1}, + {"ứ", 0}, + {"O", 1}, + {"Ớ", 0}, + {"U", 1}, + {"Ứ", 0}, + {"cedilla", 4}, + {"C", 1}, + {"Ḉ", 0}, + {"c", 1}, + {"ḉ", 0}, + {"underscore", 8}, + {"e", 1}, + {"ḗ", 0}, + {"o", 1}, + {"ṓ", 0}, + {"E", 1}, + {"Ḗ", 0}, + {"O", 1}, + {"Ṓ", 0}, + {"macron", 8}, + {"e", 1}, + {"ḗ", 0}, + {"o", 1}, + {"ṓ", 0}, + {"E", 1}, + {"Ḗ", 0}, + {"O", 1}, + {"Ṓ", 0}, + {"comma", 4}, + {"C", 1}, + {"Ḉ", 0}, + {"c", 1}, + {"ḉ", 0}, + {"asciitilde", 8}, + {"o", 1}, + {"ṍ", 0}, + {"u", 1}, + {"ṹ", 0}, + {"O", 1}, + {"Ṍ", 0}, + {"U", 1}, + {"Ṹ", 0}, + {"slash", 4}, + {"o", 1}, + {"ǿ", 0}, + {"O", 1}, + {"Ǿ", 0}, + {"parenleft", 28}, + {"Greek_IOTA", 1}, + {"Ἵ", 0}, + {"Greek_iota", 1}, + {"ἵ", 0}, + {"Greek_OMICRON", 1}, + {"Ὅ", 0}, + {"Greek_upsilon", 1}, + {"ὕ", 0}, + {"Greek_epsilon", 1}, + {"ἕ", 0}, + {"Greek_ALPHA", 1}, + {"Ἅ", 0}, + {"Greek_omicron", 1}, + {"ὅ", 0}, + {"Greek_eta", 1}, + {"ἥ", 0}, + {"Greek_alpha", 1}, + {"ἅ", 0}, + {"Greek_ETA", 1}, + {"Ἥ", 0}, + {"Greek_EPSILON", 1}, + {"Ἕ", 0}, + {"Greek_omega", 1}, + {"ὥ", 0}, + {"Greek_OMEGA", 1}, + {"Ὥ", 0}, + {"Greek_UPSILON", 1}, + {"Ὕ", 0}, + {"U", 4}, + {"a", 1}, + {"ắ", 0}, + {"A", 1}, + {"Ắ", 0}, + {"asciicircum", 12}, + {"a", 1}, + {"ấ", 0}, + {"e", 1}, + {"ế", 0}, + {"o", 1}, + {"ố", 0}, + {"E", 1}, + {"Ế", 0}, + {"O", 1}, + {"Ố", 0}, + {"A", 1}, + {"Ấ", 0}, + {"idiaeresis", 1}, + {"ḯ", 0}, + {"Cyrillic_O", 1}, + {"О́", 0}, + {"i", 1}, + {"í", 0}, + {"k", 1}, + {"ḱ", 0}, + {"n", 1}, + {"ń", 0}, + {"ccedilla", 1}, + {"ḉ", 0}, + {"Cyrillic_GHE", 1}, + {"Ѓ", 0}, + {"dead_tilde", 8}, + {"o", 1}, + {"ṍ", 0}, + {"u", 1}, + {"ṹ", 0}, + {"O", 1}, + {"Ṍ", 0}, + {"U", 1}, + {"Ṹ", 0}, + {"Cyrillic_a", 1}, + {"а́", 0}, + {"Ohorn", 1}, + {"Ớ", 0}, + {"ohorn", 1}, + {"ớ", 0}, + {"sabovedot", 1}, + {"ṥ", 0}, + {"Cyrillic_ER", 1}, + {"Р́", 0}, + {"Greek_epsilon", 1}, + {"έ", 0}, + {"Cyrillic_KA", 1}, + {"Ќ", 0}, + {"Cyrillic_U", 1}, + {"У́", 0}, + {"dead_abovering", 4}, + {"a", 1}, + {"ǻ", 0}, + {"A", 1}, + {"Ǻ", 0}, + {"nobreakspace", 1}, + {"́", 0}, + {"V", 1}, + {"Ǘ", 0}, + {"Ocircumflex", 1}, + {"Ố", 0}, + {"AE", 1}, + {"Ǽ", 0}, + {"omacron", 1}, + {"ṓ", 0}, + {"ocircumflex", 1}, + {"ố", 0}, + {"u", 1}, + {"ú", 0}, + {"z", 1}, + {"ź", 0}, + {"G", 1}, + {"Ǵ", 0}, + {"Greek_ALPHA", 1}, + {"Ά", 0}, + {"otilde", 1}, + {"ṍ", 0}, + {"utilde", 1}, + {"ṹ", 0}, + {"Cyrillic_ie", 1}, + {"е́", 0}, + {"emacron", 1}, + {"ḗ", 0}, + {"E", 1}, + {"É", 0}, + {"S", 1}, + {"Ś", 0}, + {"Greek_iotadieresis", 1}, + {"ΐ", 0}, + {"Y", 1}, + {"Ý", 0}, + {"Cyrillic_i", 1}, + {"и́", 0}, + {"dead_dasia", 28}, + {"Greek_IOTA", 1}, + {"Ἵ", 0}, + {"Greek_iota", 1}, + {"ἵ", 0}, + {"Greek_OMICRON", 1}, + {"Ὅ", 0}, + {"Greek_upsilon", 1}, + {"ὕ", 0}, + {"Greek_epsilon", 1}, + {"ἕ", 0}, + {"Greek_ALPHA", 1}, + {"Ἅ", 0}, + {"Greek_omicron", 1}, + {"ὅ", 0}, + {"Greek_eta", 1}, + {"ἥ", 0}, + {"Greek_alpha", 1}, + {"ἅ", 0}, + {"Greek_ETA", 1}, + {"Ἥ", 0}, + {"Greek_EPSILON", 1}, + {"Ἕ", 0}, + {"Greek_omega", 1}, + {"ὥ", 0}, + {"Greek_OMEGA", 1}, + {"Ὥ", 0}, + {"Greek_UPSILON", 1}, + {"Ὕ", 0}, + {"Greek_upsilondieresis", 1}, + {"ΰ", 0}, + {"Greek_omicron", 1}, + {"ό", 0}, + {"Greek_eta", 1}, + {"ή", 0}, + {"Otilde", 1}, + {"Ṍ", 0}, + {"Cyrillic_ka", 1}, + {"ќ", 0}, + {"Aring", 1}, + {"Ǻ", 0}, + {"Abreve", 1}, + {"Ắ", 0}, + {"dead_psili", 26}, + {"Greek_IOTA", 1}, + {"Ἴ", 0}, + {"Greek_iota", 1}, + {"ἴ", 0}, + {"Greek_OMICRON", 1}, + {"Ὄ", 0}, + {"Greek_upsilon", 1}, + {"ὔ", 0}, + {"Greek_epsilon", 1}, + {"ἔ", 0}, + {"Greek_ALPHA", 1}, + {"Ἄ", 0}, + {"Greek_omicron", 1}, + {"ὄ", 0}, + {"Greek_eta", 1}, + {"ἤ", 0}, + {"Greek_alpha", 1}, + {"ἄ", 0}, + {"Greek_ETA", 1}, + {"Ἤ", 0}, + {"Greek_EPSILON", 1}, + {"Ἔ", 0}, + {"Greek_omega", 1}, + {"ὤ", 0}, + {"Greek_OMEGA", 1}, + {"Ὤ", 0}, + {"Greek_alpha", 1}, + {"ά", 0}, + {"ecircumflex", 1}, + {"ế", 0}, + {"dead_abovedot", 4}, + {"S", 1}, + {"Ṥ", 0}, + {"s", 1}, + {"ṥ", 0}, + {"w", 1}, + {"ẃ", 0}, + {"Greek_ETA", 1}, + {"Ή", 0}, + {"Cyrillic_o", 1}, + {"о́", 0}, + {"Emacron", 1}, + {"Ḗ", 0}, + {"Ooblique", 1}, + {"Ǿ", 0}, + {"p", 1}, + {"ṕ", 0}, + {"v", 1}, + {"ǘ", 0}, + {"P", 1}, + {"Ṕ", 0}, + {"M", 1}, + {"Ḿ", 0}, + {"O", 1}, + {"Ó", 0}, + {"abreve", 1}, + {"ắ", 0}, + {"m", 1}, + {"ḿ", 0}, + {"r", 1}, + {"ŕ", 0}, + {"s", 1}, + {"ś", 0}, + {"Z", 1}, + {"Ź", 0}, + {"dead_stroke", 4}, + {"o", 1}, + {"ǿ", 0}, + {"O", 1}, + {"Ǿ", 0}, + {"A", 1}, + {"Á", 0}, + {"R", 1}, + {"Ŕ", 0}, + {"c", 1}, + {"ć", 0}, + {"Idiaeresis", 1}, + {"Ḯ", 0}, + {"L", 1}, + {"Ĺ", 0}, + {"Greek_EPSILON", 1}, + {"Έ", 0}, + {"Cyrillic_A", 1}, + {"А́", 0}, + {"Ccedilla", 1}, + {"Ḉ", 0}, + {"aring", 1}, + {"ǻ", 0}, + {"K", 1}, + {"Ḱ", 0}, + {"Omacron", 1}, + {"Ṓ", 0}, + {"Cyrillic_IE", 1}, + {"Е́", 0}, + {"Sabovedot", 1}, + {"Ṥ", 0}, + {"dead_cedilla", 4}, + {"C", 1}, + {"Ḉ", 0}, + {"c", 1}, + {"ḉ", 0}, + {"Greek_omega", 1}, + {"ώ", 0}, + {"dead_diaeresis", 14}, + {"Greek_iota", 1}, + {"ΐ", 0}, + {"Greek_upsilon", 1}, + {"ΰ", 0}, + {"space", 1}, + {"΅", 0}, + {"i", 1}, + {"ḯ", 0}, + {"u", 1}, + {"ǘ", 0}, + {"I", 1}, + {"Ḯ", 0}, + {"U", 1}, + {"Ǘ", 0}, + {"Uhorn", 1}, + {"Ứ", 0}, + {"Greek_OMEGA", 1}, + {"Ώ", 0}, + {"dead_acute", 1}, + {"´", 0}, + {"oslash", 1}, + {"ǿ", 0}, + {"Cyrillic_ghe", 1}, + {"ѓ", 0}, + {"udiaeresis", 1}, + {"ǘ", 0}, + {"I", 1}, + {"Í", 0}, + {"N", 1}, + {"Ń", 0}, + {"U", 1}, + {"Ú", 0}, + {"Cyrillic_u", 1}, + {"у́", 0}, + {"ae", 1}, + {"ǽ", 0}, + {"Greek_UPSILON", 1}, + {"Ύ", 0}, + {"dead_belowmacron", 34}, + {"l", 1}, + {"ḻ", 0}, + {"t", 1}, + {"ṯ", 0}, + {"b", 1}, + {"ḇ", 0}, + {"k", 1}, + {"ḵ", 0}, + {"n", 1}, + {"ṉ", 0}, + {"z", 1}, + {"ẕ", 0}, + {"d", 1}, + {"ḏ", 0}, + {"D", 1}, + {"Ḏ", 0}, + {"r", 1}, + {"ṟ", 0}, + {"Z", 1}, + {"Ẕ", 0}, + {"R", 1}, + {"Ṟ", 0}, + {"L", 1}, + {"Ḻ", 0}, + {"T", 1}, + {"Ṯ", 0}, + {"K", 1}, + {"Ḵ", 0}, + {"B", 1}, + {"Ḇ", 0}, + {"h", 1}, + {"ẖ", 0}, + {"N", 1}, + {"Ṉ", 0}, + {"dead_belowring", 6}, + {"a", 1}, + {"ḁ", 0}, + {"bar", 1}, + {"⫰", 0}, + {"A", 1}, + {"Ḁ", 0}, + {NULL, 0}, +}; diff --git a/src/lib/ecore_input/ecore_input_private.h b/src/lib/ecore_input/ecore_input_private.h new file mode 100644 index 0000000..5660a20 --- /dev/null +++ b/src/lib/ecore_input/ecore_input_private.h @@ -0,0 +1,37 @@ +#ifndef _ECORE_INPUT_PRIVATE_H +#define _ECORE_INPUT_PRIVATE_H + +extern int _ecore_input_log_dom; + +#ifdef ECORE_INPUT_DEFAULT_LOG_COLOR +# undef ECORE_INPUT_DEFAULT_LOG_COLOR +#endif + +#define ECORE_INPUT_DEFAULT_LOG_COLOR EINA_COLOR_BLUE + +#ifdef ERR +# undef ERR +#endif +#define ERR(...) EINA_LOG_DOM_ERR(_ecore_input_log_dom, __VA_ARGS__) + +#ifdef DBG +# undef DBG +#endif +#define DBG(...) EINA_LOG_DOM_DBG(_ecore_input_log_dom, __VA_ARGS__) + +#ifdef INF +# undef INF +#endif +#define INF(...) EINA_LOG_DOM_INFO(_ecore_input_log_dom, __VA_ARGS__) + +#ifdef WRN +# undef WRN +#endif +#define WRN(...) EINA_LOG_DOM_WARN(_ecore_input_log_dom, __VA_ARGS__) + +#ifdef CRIT +# undef CRIT +#endif +#define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_input_log_dom, __VA_ARGS__) + +#endif diff --git a/src/lib/ecore_input_evas/Ecore_Input_Evas.h b/src/lib/ecore_input_evas/Ecore_Input_Evas.h new file mode 100644 index 0000000..c97274e --- /dev/null +++ b/src/lib/ecore_input_evas/Ecore_Input_Evas.h @@ -0,0 +1,64 @@ +#ifndef _ECORE_INPUT_EVAS_H +#define _ECORE_INPUT_EVAS_H + +#include + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_ECORE_INPUT_EVAS_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_ECORE_INPUT_EVAS_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*Ecore_Event_Mouse_Move_Cb)(void *window, int x, int y, unsigned int timestamp); +typedef void (*Ecore_Event_Multi_Move_Cb)(void *window, int device, int x, int y, double radius, double radius_x, double radius_y, double pressure, double angle, double mx, double my, unsigned int timestamp); +typedef void (*Ecore_Event_Multi_Down_Cb)(void *window, int device, int x, int y, double radius, double radius_x, double radius_y, double pressure, double angle, double mx, double my, Evas_Button_Flags flags, unsigned int timestamp); +typedef void (*Ecore_Event_Multi_Up_Cb)(void *window, int device, int x, int y, double radius, double radius_x, double radius_y, double pressure, double angle, double mx, double my, Evas_Button_Flags flags, unsigned int timestamp); + +EAPI int ecore_event_evas_init(void); +EAPI int ecore_event_evas_shutdown(void); + +EAPI Eina_Bool ecore_event_evas_key_down(void *data, int type, void *event); +EAPI Eina_Bool ecore_event_evas_key_up(void *data, int type, void *event); +EAPI Eina_Bool ecore_event_evas_mouse_button_up(void *data, int type, void *event); +EAPI Eina_Bool ecore_event_evas_mouse_button_down(void *data, int type, void *event); +EAPI Eina_Bool ecore_event_evas_mouse_wheel(void *data, int type, void *event); +EAPI Eina_Bool ecore_event_evas_mouse_move(void *data, int type, void *event); +EAPI Eina_Bool ecore_event_evas_mouse_in(void *data, int type, void *event); +EAPI Eina_Bool ecore_event_evas_mouse_out(void *data, int type, void *event); + +EAPI void ecore_event_window_register(Ecore_Window id, void *window, Evas *evas, Ecore_Event_Mouse_Move_Cb move_mouse, Ecore_Event_Multi_Move_Cb move_multi, Ecore_Event_Multi_Down_Cb down_multi, Ecore_Event_Multi_Up_Cb up_multi); +EAPI void ecore_event_window_unregister(Ecore_Window id); +EAPI void *ecore_event_window_match(Ecore_Window id); +EAPI void ecore_event_window_ignore_events(Ecore_Window id, int ignore_event); + +EAPI void ecore_event_evas_modifier_lock_update(Evas *e, unsigned int modifiers); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/ecore_input_evas/Makefile.am b/src/lib/ecore_input_evas/Makefile.am new file mode 100644 index 0000000..ab5cd3b --- /dev/null +++ b/src/lib/ecore_input_evas/Makefile.am @@ -0,0 +1,29 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_srcdir)/src/lib/ecore_input \ +-I$(top_builddir)/src/lib/ecore_input \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_builddir)/src/lib/ecore \ +@EFL_ECORE_INPUT_EVAS_BUILD@ \ +@EVAS_CFLAGS@ \ +@EINA_CFLAGS@ \ +@EVIL_CFLAGS@ + +lib_LTLIBRARIES = libecore_input_evas.la +includes_HEADERS = Ecore_Input_Evas.h +includesdir = $(includedir)/ecore-@VMAJ@ + +libecore_input_evas_la_SOURCES = \ +ecore_input_evas.c + +libecore_input_evas_la_LIBADD = \ +$(top_builddir)/src/lib/ecore_input/libecore_input.la \ +$(top_builddir)/src/lib/ecore/libecore.la \ +@EVAS_LIBS@ \ +@EINA_LIBS@ \ +@EVIL_LIBS@ + +libecore_input_evas_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ + +EXTRA_DIST = ecore_input_evas_private.h diff --git a/src/lib/ecore_input_evas/ecore_input_evas.c b/src/lib/ecore_input_evas/ecore_input_evas.c new file mode 100644 index 0000000..8ac41aa --- /dev/null +++ b/src/lib/ecore_input_evas/ecore_input_evas.c @@ -0,0 +1,418 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "Ecore.h" +#include "Ecore_Input.h" + +#include "Ecore_Input_Evas.h" +#include "ecore_input_evas_private.h" + +int _ecore_input_evas_log_dom = -1; + +typedef struct _Ecore_Input_Window Ecore_Input_Window; +struct _Ecore_Input_Window +{ + Evas *evas; + void *window; + Ecore_Event_Mouse_Move_Cb move_mouse; + Ecore_Event_Multi_Move_Cb move_multi; + Ecore_Event_Multi_Down_Cb down_multi; + Ecore_Event_Multi_Up_Cb up_multi; + int ignore_event; +}; + +static int _ecore_event_evas_init_count = 0; +static Ecore_Event_Handler *ecore_event_evas_handlers[8]; +static Eina_Hash *_window_hash = NULL; + +EAPI void +ecore_event_evas_modifier_lock_update(Evas *e, unsigned int modifiers) +{ + if (modifiers & ECORE_EVENT_MODIFIER_SHIFT) + evas_key_modifier_on(e, "Shift"); + else evas_key_modifier_off(e, "Shift"); + + if (modifiers & ECORE_EVENT_MODIFIER_CTRL) + evas_key_modifier_on(e, "Control"); + else evas_key_modifier_off(e, "Control"); + + if (modifiers & ECORE_EVENT_MODIFIER_ALT) + evas_key_modifier_on(e, "Alt"); + else evas_key_modifier_off(e, "Alt"); + + if (modifiers & ECORE_EVENT_MODIFIER_WIN) + { + evas_key_modifier_on(e, "Super"); + evas_key_modifier_on(e, "Hyper"); + } + else + { + evas_key_modifier_off(e, "Super"); + evas_key_modifier_off(e, "Hyper"); + } + + if (modifiers & ECORE_EVENT_MODIFIER_ALTGR) + evas_key_modifier_on(e, "AltGr"); + else evas_key_modifier_off(e, "AltGr"); + + if (modifiers & ECORE_EVENT_LOCK_SCROLL) + evas_key_lock_on(e, "Scroll_Lock"); + else evas_key_lock_off(e, "Scroll_Lock"); + + if (modifiers & ECORE_EVENT_LOCK_NUM) + evas_key_lock_on(e, "Num_Lock"); + else evas_key_lock_off(e, "Num_Lock"); + + if (modifiers & ECORE_EVENT_LOCK_CAPS) + evas_key_lock_on(e, "Caps_Lock"); + else evas_key_lock_off(e, "Caps_Lock"); + + if (modifiers & ECORE_EVENT_LOCK_SHIFT) + evas_key_lock_on(e, "Shift_Lock"); + else evas_key_lock_off(e, "Shift_Lock"); +} + +EAPI void +ecore_event_window_register(Ecore_Window id, void *window, Evas *evas, + Ecore_Event_Mouse_Move_Cb move_mouse, + Ecore_Event_Multi_Move_Cb move_multi, + Ecore_Event_Multi_Down_Cb down_multi, + Ecore_Event_Multi_Up_Cb up_multi) +{ + Ecore_Input_Window *w; + + w = calloc(1, sizeof(Ecore_Input_Window)); + if (!w) return; + + w->evas = evas; + w->window = window; + w->move_mouse = move_mouse; + w->move_multi = move_multi; + w->down_multi = down_multi; + w->up_multi = up_multi; + w->ignore_event = 0; + + eina_hash_add(_window_hash, &id, w); + + evas_key_modifier_add(evas, "Shift"); + evas_key_modifier_add(evas, "Control"); + evas_key_modifier_add(evas, "Alt"); + evas_key_modifier_add(evas, "Meta"); + evas_key_modifier_add(evas, "Hyper"); + evas_key_modifier_add(evas, "Super"); + evas_key_modifier_add(evas, "AltGr"); + evas_key_lock_add(evas, "Caps_Lock"); + evas_key_lock_add(evas, "Num_Lock"); + evas_key_lock_add(evas, "Scroll_Lock"); +} + +EAPI void +ecore_event_window_unregister(Ecore_Window id) +{ + eina_hash_del(_window_hash, &id, NULL); +} + +EAPI void * +ecore_event_window_match(Ecore_Window id) +{ + Ecore_Input_Window *lookup; + + lookup = eina_hash_find(_window_hash, &id); + if (lookup) return lookup->window; + return NULL; +} + +EAPI void +ecore_event_window_ignore_events(Ecore_Window id, int ignore_event) +{ + Ecore_Input_Window *lookup; + + lookup = eina_hash_find(_window_hash, &id); + if (!lookup) return; + lookup->ignore_event = ignore_event; +} + +static Ecore_Input_Window* +_ecore_event_window_match(Ecore_Window id) +{ + Ecore_Input_Window *lookup; + + lookup = eina_hash_find(_window_hash, &id); + if (!lookup) return NULL; + if (lookup->ignore_event) return NULL; /* Pass on event. */ + return lookup; +} + +static Eina_Bool +_ecore_event_evas_key(Ecore_Event_Key *e, Ecore_Event_Press press) +{ + Ecore_Input_Window *lookup; + + lookup = _ecore_event_window_match(e->event_window); + if (!lookup) return ECORE_CALLBACK_PASS_ON; + ecore_event_evas_modifier_lock_update(lookup->evas, e->modifiers); + if (press == ECORE_DOWN) + evas_event_feed_key_down(lookup->evas, e->keyname, e->key, e->string, e->compose, e->timestamp, NULL); + else + evas_event_feed_key_up(lookup->evas, e->keyname, e->key, e->string, e->compose, e->timestamp, NULL); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_event_evas_mouse_button(Ecore_Event_Mouse_Button *e, Ecore_Event_Press press) +{ + Ecore_Input_Window *lookup; + Evas_Button_Flags flags = EVAS_BUTTON_NONE; + + lookup = _ecore_event_window_match(e->event_window); + if (!lookup) return ECORE_CALLBACK_PASS_ON; + if (e->double_click) flags |= EVAS_BUTTON_DOUBLE_CLICK; + if (e->triple_click) flags |= EVAS_BUTTON_TRIPLE_CLICK; + if (e->multi.device == 0) + { + ecore_event_evas_modifier_lock_update(lookup->evas, e->modifiers); + if (press == ECORE_DOWN) + evas_event_feed_mouse_down(lookup->evas, e->buttons, flags, + e->timestamp, NULL); + else + evas_event_feed_mouse_up(lookup->evas, e->buttons, flags, + e->timestamp, NULL); + } + else + { + if (press == ECORE_DOWN) + { + if (lookup->down_multi) + lookup->down_multi(lookup->window, e->multi.device, + e->x, e->y, e->multi.radius, + e->multi.radius_x, e->multi.radius_y, + e->multi.pressure, e->multi.angle, + e->multi.x, e->multi.y, flags, + e->timestamp); + else + evas_event_feed_multi_down(lookup->evas, e->multi.device, + e->x, e->y, e->multi.radius, + e->multi.radius_x, e->multi.radius_y, + e->multi.pressure, e->multi.angle, + e->multi.x, e->multi.y, flags, + e->timestamp, NULL); + } + else + { + if (lookup->up_multi) + lookup->up_multi(lookup->window, e->multi.device, + e->x, e->y, e->multi.radius, + e->multi.radius_x, e->multi.radius_y, + e->multi.pressure, e->multi.angle, + e->multi.x, e->multi.y, flags, + e->timestamp); + else + evas_event_feed_multi_up(lookup->evas, e->multi.device, + e->x, e->y, e->multi.radius, + e->multi.radius_x, e->multi.radius_y, + e->multi.pressure, e->multi.angle, + e->multi.x, e->multi.y, flags, + e->timestamp, NULL); + } + } + return ECORE_CALLBACK_PASS_ON; +} + +EAPI Eina_Bool +ecore_event_evas_mouse_move(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Event_Mouse_Move *e; + Ecore_Input_Window *lookup; + + e = event; + lookup = _ecore_event_window_match(e->event_window); + if (!lookup) return ECORE_CALLBACK_PASS_ON; + if (e->multi.device == 0) + { + ecore_event_evas_modifier_lock_update(lookup->evas, e->modifiers); + if (lookup->move_mouse) + lookup->move_mouse(lookup->window, e->x, e->y, e->timestamp); + else + evas_event_feed_mouse_move(lookup->evas, e->x, e->y, e->timestamp, + NULL); + } + else + { + if (lookup->move_multi) + lookup->move_multi(lookup->window, e->multi.device, + e->x, e->y, e->multi.radius, + e->multi.radius_x, e->multi.radius_y, + e->multi.pressure, e->multi.angle, + e->multi.x, e->multi.y, e->timestamp); + else + evas_event_feed_multi_move(lookup->evas, e->multi.device, + e->x, e->y, e->multi.radius, + e->multi.radius_x, e->multi.radius_y, + e->multi.pressure, e->multi.angle, + e->multi.x, e->multi.y, e->timestamp, + NULL); + } + return ECORE_CALLBACK_PASS_ON; +} + +EAPI Eina_Bool +ecore_event_evas_mouse_button_down(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + return _ecore_event_evas_mouse_button((Ecore_Event_Mouse_Button *)event, ECORE_DOWN); +} + +EAPI Eina_Bool +ecore_event_evas_mouse_button_up(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + return _ecore_event_evas_mouse_button((Ecore_Event_Mouse_Button *)event, ECORE_UP); +} + +static Eina_Bool +_ecore_event_evas_mouse_io(Ecore_Event_Mouse_IO *e, Ecore_Event_IO io) +{ + Ecore_Input_Window *lookup; + + lookup = _ecore_event_window_match(e->event_window); + if (!lookup) return ECORE_CALLBACK_PASS_ON; + ecore_event_evas_modifier_lock_update(lookup->evas, e->modifiers); + switch (io) + { + case ECORE_IN: + evas_event_feed_mouse_in(lookup->evas, e->timestamp, NULL); + break; + case ECORE_OUT: + evas_event_feed_mouse_out(lookup->evas, e->timestamp, NULL); + break; + default: + break; + } + + lookup->move_mouse(lookup->window, e->x, e->y, e->timestamp); + return ECORE_CALLBACK_PASS_ON; +} + +EAPI Eina_Bool +ecore_event_evas_key_down(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + return _ecore_event_evas_key((Ecore_Event_Key *)event, ECORE_DOWN); +} + +EAPI Eina_Bool +ecore_event_evas_key_up(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + return _ecore_event_evas_key((Ecore_Event_Key *)event, ECORE_UP); +} + +EAPI Eina_Bool +ecore_event_evas_mouse_wheel(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Event_Mouse_Wheel *e; + Ecore_Input_Window *lookup; + + e = event; + lookup = _ecore_event_window_match(e->event_window); + if (!lookup) return ECORE_CALLBACK_PASS_ON; + ecore_event_evas_modifier_lock_update(lookup->evas, e->modifiers); + evas_event_feed_mouse_wheel(lookup->evas, e->direction, e->z, e->timestamp, NULL); + return ECORE_CALLBACK_PASS_ON; +} + +EAPI Eina_Bool +ecore_event_evas_mouse_in(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + return _ecore_event_evas_mouse_io((Ecore_Event_Mouse_IO *)event, ECORE_IN); +} + +EAPI Eina_Bool +ecore_event_evas_mouse_out(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + return _ecore_event_evas_mouse_io((Ecore_Event_Mouse_IO *)event, ECORE_OUT); +} + +EAPI int +ecore_event_evas_init(void) +{ + if (++_ecore_event_evas_init_count != 1) + return _ecore_event_evas_init_count; + + _ecore_input_evas_log_dom = eina_log_domain_register + ("ecore_input_evas", ECORE_INPUT_EVAS_DEFAULT_LOG_COLOR); + if (_ecore_input_evas_log_dom < 0) + { + EINA_LOG_ERR("Impossible to create a log domain for the ecore input evas_module."); + return --_ecore_event_evas_init_count; + } + + if (!ecore_init()) + { + return --_ecore_event_evas_init_count; + } + + if (!ecore_event_init()) + { + goto shutdown_ecore; + } + + ecore_event_evas_handlers[0] = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, + ecore_event_evas_key_down, + NULL); + ecore_event_evas_handlers[1] = ecore_event_handler_add(ECORE_EVENT_KEY_UP, + ecore_event_evas_key_up, + NULL); + ecore_event_evas_handlers[2] = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, + ecore_event_evas_mouse_button_down, + NULL); + ecore_event_evas_handlers[3] = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, + ecore_event_evas_mouse_button_up, + NULL); + ecore_event_evas_handlers[4] = ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE, + ecore_event_evas_mouse_move, + NULL); + ecore_event_evas_handlers[5] = ecore_event_handler_add(ECORE_EVENT_MOUSE_WHEEL, + ecore_event_evas_mouse_wheel, + NULL); + ecore_event_evas_handlers[6] = ecore_event_handler_add(ECORE_EVENT_MOUSE_IN, + ecore_event_evas_mouse_in, + NULL); + ecore_event_evas_handlers[7] = ecore_event_handler_add(ECORE_EVENT_MOUSE_OUT, + ecore_event_evas_mouse_out, + NULL); + + _window_hash = eina_hash_pointer_new(free); + + return _ecore_event_evas_init_count; + + shutdown_ecore: + ecore_shutdown(); + + return --_ecore_event_evas_init_count; +} + +EAPI int +ecore_event_evas_shutdown(void) +{ + size_t i; + + if (--_ecore_event_evas_init_count != 0) + return _ecore_event_evas_init_count; + + eina_hash_free(_window_hash); + _window_hash = NULL; + for (i = 0; i < sizeof(ecore_event_evas_handlers) / sizeof(Ecore_Event_Handler *); i++) + { + ecore_event_handler_del(ecore_event_evas_handlers[i]); + ecore_event_evas_handlers[i] = NULL; + } + + ecore_event_shutdown(); + ecore_shutdown(); + + eina_log_domain_unregister(_ecore_input_evas_log_dom); + _ecore_input_evas_log_dom = -1; + + return _ecore_event_evas_init_count; +} diff --git a/src/lib/ecore_input_evas/ecore_input_evas_private.h b/src/lib/ecore_input_evas/ecore_input_evas_private.h new file mode 100644 index 0000000..c19cfbf --- /dev/null +++ b/src/lib/ecore_input_evas/ecore_input_evas_private.h @@ -0,0 +1,37 @@ +#ifndef _ECORE_INPUT_PRIVATE_H +#define _ECORE_INPUT_PRIVATE_H + +extern int _ecore_input_evas_log_dom; + +#ifdef ECORE_INPUT_EVAS_DEFAULT_LOG_COLOR +#undef ECORE_INPUT_EVAS_DEFAULT_LOG_COLOR +#endif + +#define ECORE_INPUT_EVAS_DEFAULT_LOG_COLOR EINA_COLOR_BLUE + +#ifdef ERR +#undef ERR +#endif +#define ERR(...) EINA_LOG_DOM_ERR(_ecore_input_evas_log_dom, __VA_ARGS__) + +#ifdef DBG +#undef DBG +#endif +#define DBG(...) EINA_LOG_DOM_DBG(_ecore_input_evas_log_dom, __VA_ARGS__) + +#ifdef INF +#undef INF +#endif +#define INF(...) EINA_LOG_DOM_INFO(_ecore_input_evas_log_dom, __VA_ARGS__) + +#ifdef WRN +#undef WRN +#endif +#define WRN(...) EINA_LOG_DOM_WARN(_ecore_input_evas_log_dom, __VA_ARGS__) + +#ifdef CRIT +#undef CRIT +#endif +#define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_input_evas_log_dom, __VA_ARGS__) + +#endif diff --git a/src/lib/ecore_ipc/Ecore_Ipc.h b/src/lib/ecore_ipc/Ecore_Ipc.h new file mode 100644 index 0000000..f77870f --- /dev/null +++ b/src/lib/ecore_ipc/Ecore_Ipc.h @@ -0,0 +1,328 @@ +#ifndef _ECORE_IPC_H +#define _ECORE_IPC_H + +#include + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_ECORE_IPC_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif +# else +# define EAPI __declspec(dllimport) +# endif +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif + +/** + * @file Ecore_Ipc.h + * @brief Ecore inter-process communication functions. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _Ecore_Ipc_Server Ecore_Ipc_Server; /**< An IPC connection handle */ +typedef struct _Ecore_Ipc_Client Ecore_Ipc_Client; /**< An IPC connection handle */ + +EAPI unsigned short _ecore_ipc_swap_16(unsigned short v); +EAPI unsigned int _ecore_ipc_swap_32(unsigned int v); +EAPI unsigned long long _ecore_ipc_swap_64(unsigned long long v); + +#ifdef WORDS_BIGENDIAN +#define ECORE_IPC_SWAP2NET64(x) _ecore_ipc_swap_64(x) +#define ECORE_IPC_SWAP2CPU64(x) _ecore_ipc_swap_64(x) +#define ECORE_IPC_SWAP2NET32(x) _ecore_ipc_swap_32(x) +#define ECORE_IPC_SWAP2CPU32(x) _ecore_ipc_swap_32(x) +#define ECORE_IPC_SWAP2NET16(x) _ecore_ipc_swap_16(x) +#define ECORE_IPC_SWAP2CPU16(x) _ecore_ipc_swap_16(x) +#define ECORE_IPC_SWAP2NET8(x) (x) +#define ECORE_IPC_SWAP2CPU8(x) (x) +#else +#define ECORE_IPC_SWAP2NET64(x) (x) +#define ECORE_IPC_SWAP2CPU64(x) (x) +#define ECORE_IPC_SWAP2NET32(x) (x) +#define ECORE_IPC_SWAP2CPU32(x) (x) +#define ECORE_IPC_SWAP2NET16(x) (x) +#define ECORE_IPC_SWAP2CPU16(x) (x) +#define ECORE_IPC_SWAP2NET8(x) (x) +#define ECORE_IPC_SWAP2CPU8(x) (x) +#endif + +/* 1, 2, 4 and 8 byte datatypes */ +/* unpacking */ +#define ECORE_IPC_GET64(v)\ + { \ + p->v = ECORE_IPC_SWAP2CPU64(*(long long *)(ptr)); \ + ptr += 8; \ + } +#define ECORE_IPC_GET32(v)\ + { \ + p->v = ECORE_IPC_SWAP2CPU32(*(int *)(ptr)); \ + ptr += 4; \ + } +#define ECORE_IPC_GET16(v)\ + { \ + p->v = ECORE_IPC_SWAP2CPU16(*(short *)(ptr)); \ + ptr += 2; \ + } +#define ECORE_IPC_GET8(v) \ + { \ + p->v = ECORE_IPC_SWAP2CPU8(*(char *)(ptr)); \ + ptr += 1; \ + } +/* packing */ +#define ECORE_IPC_PUT64(v)\ + { \ + *(long long *)(ptr) = ECORE_IPC_SWAP2NET64(p->v); \ + ptr += 8; \ + } +#define ECORE_IPC_PUT32(v)\ + { \ + *(int *)(ptr) = ECORE_IPC_SWAP2NET32(p->v); \ + ptr += 4; \ + } +#define ECORE_IPC_PUT16(v)\ + { \ + *(short *)(ptr) = ECORE_IPC_SWAP2NET16(p->v); \ + ptr += 2; \ + } +#define ECORE_IPC_PUT8(v) \ + { \ + *(char *)(ptr) = ECORE_IPC_SWAP2NET8(p->v); \ + ptr += 1; \ + } +/* padding data */ +#define ECORE_IPC_PAD8() ptr += 1 +#define ECORE_IPC_PAD16() ptr += 2 +#define ECORE_IPC_PAD32() ptr += 4 +#define ECORE_IPC_PAD64() ptr += 8 + +/* counting data when encoding lists */ +#define ECORE_IPC_CNT8() len += 1 +#define ECORE_IPC_CNT16() len += 2 +#define ECORE_IPC_CNT32() len += 4 +#define ECORE_IPC_CNT64() len += 8 + +/* strings */ +#define ECORE_IPC_CHEKS() if (*((unsigned char *)d + s - 1) != 0) return 0; +#define ECORE_IPC_GETS(v) \ + { \ + if (ptr < ((unsigned char *)d + s)) \ + { \ + p->v = (char *)ptr; \ + ptr += strlen(p->v) + 1; \ + } \ + } +#define ECORE_IPC_PUTS(v, l)\ + { \ + strcpy((char *)ptr, p->v); \ + ptr += l + 1; \ + } + +/* handy to calculate what sized block we need to alloc */ +#define ECORE_IPC_SLEN(l, v) ((l = strlen(p->v)) + 1) +#define ECORE_IPC_CNTS(v) len += strlen(p->v) + 1 + +/* saves typing function headers */ +#define ECORE_IPC_DEC_STRUCT_PROTO(x) static int x(void *d, int s, void *pp) +#define ECORE_IPC_ENC_STRUCT_PROTO(x) static void *x(void *pp, int *s) +#define ECORE_IPC_DEC_EINA_LIST_PROTO(x) static Eina_List *x(void *d, int s) +#define ECORE_IPC_ENC_EINA_LIST_PROTO(x) static void *x(Eina_List *lp, int *s) + + +/* decoder setup - saves typing. requires data packet of exact size, or fail */ +#define ECORE_IPC_DEC_STRUCT_HEAD_EXACT(typ, x) \ + typ *p; \ + unsigned char *ptr; \ + p = (typ *)pp; \ + if (!d) return 0; if (s != (x)) return 0; \ + ptr = d; +/* decoder setup - saves typing. requires data packet of a minimum size */ +#define ECORE_IPC_DEC_STRUCT_HEAD_MIN(typ, x) \ + typ *p; \ + unsigned char *ptr; \ + p = (typ *)pp; \ + if (!d) return 0; if (s < (x)) return 0; \ + ptr = d; +/* footer for the hell of it */ +#define ECORE_IPC_DEC_STRUCT_FOOT() return 1 +/* header for encoder - gives native strct type and size of flattened packet */ +#define ECORE_IPC_ENC_STRUCT_HEAD(typ, sz) \ + typ *p; \ + unsigned char *d, *ptr; \ + int len; \ + *s = 0; \ + if(!pp) return NULL; \ + p = (typ *)pp; \ + len = sz; \ + d = malloc(len); \ + if (!d) return NULL; \ + *s = len; \ + ptr = d; +/* footer for the hell of it */ +#define ECORE_IPC_ENC_STRUCT_FOOT() return d + +#define ECORE_IPC_DEC_EINA_LIST_HEAD(typ) \ + unsigned char *ptr; \ + Eina_List *l; \ + typ *p; \ + l = NULL; \ + ptr = d; \ + while(ptr < (unsigned char *)(d + s)) \ + { \ + p = malloc(sizeof(typ)); + +#define ECORE_IPC_DEC_EINA_LIST_FOOT() \ + l = eina_list_append(l, p); \ + } \ + return l +#define ECORE_IPC_ENC_EINA_LIST_HEAD_START(typ) \ + Eina_List *l; \ + typ *p; \ + unsigned char *d, *ptr; \ + int len; \ + *s = 0; \ + len = 0; \ + for (l = lp; l; l = l->next) \ + { \ + p = l->data; +#define ECORE_IPC_ENC_EINA_LIST_HEAD_FINISH() \ + } \ + d = malloc(len); \ + if(!d) return NULL; \ + *s = len; \ + ptr = d; \ + for (l = lp; l; l = l->next) \ + { \ + p = l->data; + +#define ECORE_IPC_ENC_EINA_LIST_FOOT() \ + } \ + return d + +typedef enum _Ecore_Ipc_Type +{ + ECORE_IPC_LOCAL_USER, + ECORE_IPC_LOCAL_SYSTEM, + ECORE_IPC_REMOTE_SYSTEM, + ECORE_IPC_USE_SSL = (1 << 4), + ECORE_IPC_NO_PROXY = (1 << 5) +} Ecore_Ipc_Type; + +typedef struct _Ecore_Ipc_Event_Client_Add Ecore_Ipc_Event_Client_Add; +typedef struct _Ecore_Ipc_Event_Client_Del Ecore_Ipc_Event_Client_Del; +typedef struct _Ecore_Ipc_Event_Server_Add Ecore_Ipc_Event_Server_Add; +typedef struct _Ecore_Ipc_Event_Server_Del Ecore_Ipc_Event_Server_Del; +typedef struct _Ecore_Ipc_Event_Client_Data Ecore_Ipc_Event_Client_Data; +typedef struct _Ecore_Ipc_Event_Server_Data Ecore_Ipc_Event_Server_Data; + +struct _Ecore_Ipc_Event_Client_Add +{ + Ecore_Ipc_Client *client; +}; + +struct _Ecore_Ipc_Event_Client_Del +{ + Ecore_Ipc_Client *client; +}; + +struct _Ecore_Ipc_Event_Server_Add +{ + Ecore_Ipc_Server *server; +}; + +struct _Ecore_Ipc_Event_Server_Del +{ + Ecore_Ipc_Server *server; +}; + +struct _Ecore_Ipc_Event_Client_Data +{ + Ecore_Ipc_Client *client; + /* FIXME: this needs to become an ipc message */ + int major; + int minor; + int ref; + int ref_to; + int response; + void *data; + int size; +}; + +struct _Ecore_Ipc_Event_Server_Data +{ + Ecore_Ipc_Server *server; + /* FIXME: this needs to become an ipc message */ + int major; + int minor; + int ref; + int ref_to; + int response; + void *data; + int size; +}; + +EAPI extern int ECORE_IPC_EVENT_CLIENT_ADD; +EAPI extern int ECORE_IPC_EVENT_CLIENT_DEL; +EAPI extern int ECORE_IPC_EVENT_SERVER_ADD; +EAPI extern int ECORE_IPC_EVENT_SERVER_DEL; +EAPI extern int ECORE_IPC_EVENT_CLIENT_DATA; +EAPI extern int ECORE_IPC_EVENT_SERVER_DATA; + +EAPI int ecore_ipc_init(void); +EAPI int ecore_ipc_shutdown(void); + +/* FIXME: need to add protocol type parameter */ +EAPI Ecore_Ipc_Server *ecore_ipc_server_add(Ecore_Ipc_Type type, const char *name, int port, const void *data); + +/* FIXME: need to add protocol type parameter */ +EAPI Ecore_Ipc_Server *ecore_ipc_server_connect(Ecore_Ipc_Type type, char *name, int port, const void *data); +EAPI void *ecore_ipc_server_del(Ecore_Ipc_Server *svr); +EAPI void *ecore_ipc_server_data_get(Ecore_Ipc_Server *svr); +EAPI Eina_Bool ecore_ipc_server_connected_get(Ecore_Ipc_Server *svr); +EAPI Eina_List *ecore_ipc_server_clients_get(Ecore_Ipc_Server *svr); +/* FIXME: this needs to become an ipc message */ +EAPI int ecore_ipc_server_send(Ecore_Ipc_Server *svr, int major, int minor, int ref, int ref_to, int response, const void *data, int size); +EAPI void ecore_ipc_server_client_limit_set(Ecore_Ipc_Server *svr, int client_limit, char reject_excess_clients); +EAPI void ecore_ipc_server_data_size_max_set(Ecore_Ipc_Server *srv, int size); +EAPI int ecore_ipc_server_data_size_max_get(Ecore_Ipc_Server *srv); +EAPI const char *ecore_ipc_server_ip_get(Ecore_Ipc_Server *svr); +EAPI void ecore_ipc_server_flush(Ecore_Ipc_Server *svr); + +/* FIXME: this needs to become an ipc message */ +EAPI int ecore_ipc_client_send(Ecore_Ipc_Client *cl, int major, int minor, int ref, int ref_to, int response, const void *data, int size); +EAPI Ecore_Ipc_Server *ecore_ipc_client_server_get(Ecore_Ipc_Client *cl); +EAPI void *ecore_ipc_client_del(Ecore_Ipc_Client *cl); +EAPI void ecore_ipc_client_data_set(Ecore_Ipc_Client *cl, const void *data); +EAPI void *ecore_ipc_client_data_get(Ecore_Ipc_Client *cl); +EAPI void ecore_ipc_client_data_size_max_set(Ecore_Ipc_Client *cl, int size); +EAPI int ecore_ipc_client_data_size_max_get(Ecore_Ipc_Client *cl); +EAPI const char *ecore_ipc_client_ip_get(Ecore_Ipc_Client *cl); +EAPI void ecore_ipc_client_flush(Ecore_Ipc_Client *cl); + +EAPI int ecore_ipc_ssl_available_get(void); +/* FIXME: need to add a callback to "ok" large ipc messages greater than */ +/* a certain size (seurity/DOS attack safety) */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/ecore_ipc/Makefile.am b/src/lib/ecore_ipc/Makefile.am new file mode 100644 index 0000000..60e32d3 --- /dev/null +++ b/src/lib/ecore_ipc/Makefile.am @@ -0,0 +1,34 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_builddir)/src/lib/ecore \ +-I$(top_builddir)/src/lib/ecore_con \ +-I$(top_builddir)/src/lib/ecore_ipc \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore_con \ +-I$(top_srcdir)/src/lib/ecore_ipc \ +@EFL_ECORE_IPC_BUILD@ \ +@SSL_CFLAGS@ \ +@EVIL_CFLAGS@ \ +@EINA_CFLAGS@ \ +@WIN32_CPPFLAGS@ + +lib_LTLIBRARIES = libecore_ipc.la +includes_HEADERS = Ecore_Ipc.h +includesdir = $(includedir)/ecore-@VMAJ@ + +libecore_ipc_la_SOURCES = \ +ecore_ipc.c + +libecore_ipc_la_CFLAGS = @WIN32_CFLAGS@ +libecore_ipc_la_LIBADD = \ +$(top_builddir)/src/lib/ecore/libecore.la \ +$(top_builddir)/src/lib/ecore_con/libecore_con.la \ +@SSL_LIBS@ \ +@EINA_LIBS@ \ +@EVIL_LIBS@ \ +@WIN32_LIBS@ + +libecore_ipc_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@ + +EXTRA_DIST = ecore_ipc_private.h diff --git a/src/lib/ecore_ipc/ecore_ipc.c b/src/lib/ecore_ipc/ecore_ipc.c new file mode 100644 index 0000000..9e655d3 --- /dev/null +++ b/src/lib/ecore_ipc/ecore_ipc.c @@ -0,0 +1,1603 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#ifdef HAVE_NETINET_IN_H +# include +# include +#endif + +#ifdef HAVE_WINSOCK2_H +# include +#endif + +#if USE_GNUTLS_OPENSSL +# include +#elif USE_OPENSSL +# include +#endif + +#include +#include +#include + +#include "Ecore_Ipc.h" +#include "ecore_ipc_private.h" + +#define DLT_ZERO 0 +#define DLT_ONE 1 +#define DLT_SAME 2 +#define DLT_SHL 3 +#define DLT_SHR 4 +#define DLT_ADD8 5 +#define DLT_DEL8 6 +#define DLT_ADDU8 7 +#define DLT_DELU8 8 +#define DLT_ADD16 9 +#define DLT_DEL16 10 +#define DLT_ADDU16 11 +#define DLT_DELU16 12 +#define DLT_SET 13 +#define DLT_R1 14 +#define DLT_R2 15 + +int _ecore_ipc_log_dom = -1; + +EAPI unsigned short +_ecore_ipc_swap_16(unsigned short v) +{ + unsigned char *s, t; + + s = (unsigned char *)(&v); + t = s[0]; s[0] = s[1]; s[1] = t; + return v; +} + +EAPI unsigned int +_ecore_ipc_swap_32(unsigned int v) +{ + unsigned char *s, t; + + s = (unsigned char *)(&v); + t = s[0]; s[0] = s[3]; s[3] = t; + t = s[1]; s[1] = s[2]; s[2] = t; + return v; +} + +EAPI unsigned long long +_ecore_ipc_swap_64(unsigned long long v) +{ + unsigned char *s, t; + + s = (unsigned char *)(&v); + t = s[0]; s[0] = s[7]; s[7] = t; + t = s[1]; s[1] = s[6]; s[6] = t; + t = s[2]; s[2] = s[5]; s[5] = t; + t = s[3]; s[3] = s[4]; s[4] = t; + return v; +} + +static int _ecore_ipc_dlt_int(int out, int prev, int *mode); +static int _ecore_ipc_ddlt_int(int in, int prev, int mode); + +static int +_ecore_ipc_dlt_int(int out, int prev, int *mode) +{ + int dlt; + + /* 0 byte */ + if (out == 0) + { + *mode = DLT_ZERO; + return 0; + } + if (out == (int)0xffffffff) + { + *mode = DLT_ONE; + return 0; + } + if (out == prev) + { + *mode = DLT_SAME; + return 0; + } + if (out == prev << 1) + { + *mode = DLT_SHL; + return 0; + } + if (out == prev >> 1) + { + *mode = DLT_SHR; + return 0; + } + /* 1 byte */ + dlt = out - prev; + if (!(dlt & 0xffffff00)) + { + *mode = DLT_ADD8; + return dlt & 0xff; + } + dlt = prev - out; + if (!(dlt & 0xffffff00)) + { + *mode = DLT_DEL8; + return dlt & 0xff; + } + dlt = out - prev; + if (!(dlt & 0x00ffffff)) + { + *mode = DLT_ADDU8; + return (dlt >> 24) & 0xff; + } + dlt = prev - out; + if (!(dlt & 0x00ffffff)) + { + *mode = DLT_DELU8; + return (dlt >> 24) & 0xff; + } + /* 2 byte */ + dlt = out - prev; + if (!(dlt & 0xffff0000)) + { + *mode = DLT_ADD16; + return dlt & 0xffff; + } + dlt = prev - out; + if (!(dlt & 0xffff0000)) + { + *mode = DLT_DEL16; + return dlt & 0xffff; + } + dlt = out - prev; + if (!(dlt & 0x0000ffff)) + { + *mode = DLT_ADDU16; + return (dlt >> 16) & 0xffff; + } + dlt = prev - out; + if (!(dlt & 0x0000ffff)) + { + *mode = DLT_DELU16; + return (dlt >> 16) & 0xffff; + } + /* 4 byte */ + *mode = DLT_SET; + return out; +} + +static int +_ecore_ipc_ddlt_int(int in, int prev, int mode) +{ + switch (mode) + { + case DLT_ZERO: + return 0; + break; + case DLT_ONE: + return 0xffffffff; + break; + case DLT_SAME: + return prev; + break; + case DLT_SHL: + return prev << 1; + break; + case DLT_SHR: + return prev >> 1; + break; + case DLT_ADD8: + return prev + in; + break; + case DLT_DEL8: + return prev - in; + break; + case DLT_ADDU8: + return prev + (in << 24); + break; + case DLT_DELU8: + return prev - (in << 24); + break; + case DLT_ADD16: + return prev + in; + break; + case DLT_DEL16: + return prev - in; + break; + case DLT_ADDU16: + return prev + (in << 16); + break; + case DLT_DELU16: + return prev - (in << 16); + break; + case DLT_SET: + return in; + break; + case DLT_R1: + return 0; + break; + case DLT_R2: + return 0; + break; + default: + break; + } + return 0; +} + +static Eina_Bool _ecore_ipc_event_client_add(void *data, int ev_type, void *ev); +static Eina_Bool _ecore_ipc_event_client_del(void *data, int ev_type, void *ev); +static Eina_Bool _ecore_ipc_event_server_add(void *data, int ev_type, void *ev); +static Eina_Bool _ecore_ipc_event_server_del(void *data, int ev_type, void *ev); +static Eina_Bool _ecore_ipc_event_client_data(void *data, int ev_type, void *ev); +static Eina_Bool _ecore_ipc_event_server_data(void *data, int ev_type, void *ev); +static void _ecore_ipc_event_client_add_free(void *data, void *ev); +static void _ecore_ipc_event_client_del_free(void *data, void *ev); +static void _ecore_ipc_event_client_data_free(void *data, void *ev); +static void _ecore_ipc_event_server_add_free(void *data, void *ev); +static void _ecore_ipc_event_server_del_free(void *data, void *ev); +static void _ecore_ipc_event_server_data_free(void *data, void *ev); + +EAPI int ECORE_IPC_EVENT_CLIENT_ADD = 0; +EAPI int ECORE_IPC_EVENT_CLIENT_DEL = 0; +EAPI int ECORE_IPC_EVENT_SERVER_ADD = 0; +EAPI int ECORE_IPC_EVENT_SERVER_DEL = 0; +EAPI int ECORE_IPC_EVENT_CLIENT_DATA = 0; +EAPI int ECORE_IPC_EVENT_SERVER_DATA = 0; + +static int _ecore_ipc_init_count = 0; +static Eina_List *servers = NULL; +static Ecore_Event_Handler *handler[6]; + +/** + * @defgroup Ecore_IPC_Library_Group IPC Library Functions + * + * Functions that set up and shut down the Ecore IPC Library. + */ + +/** + * Initialises the Ecore IPC library. + * @return Number of times the library has been initialised without + * being shut down. + * @ingroup Ecore_IPC_Library_Group + */ +EAPI int +ecore_ipc_init(void) +{ + int i = 0; + + if (++_ecore_ipc_init_count != 1) + return _ecore_ipc_init_count; + _ecore_ipc_log_dom = eina_log_domain_register + ("ecore_ipc", ECORE_IPC_DEFAULT_LOG_COLOR); + if(_ecore_ipc_log_dom < 0) + { + EINA_LOG_ERR("Impossible to create a log domain for the Ecore IPC module."); + return --_ecore_ipc_init_count; + } + if (!ecore_con_init()) + return --_ecore_ipc_init_count; + + ECORE_IPC_EVENT_CLIENT_ADD = ecore_event_type_new(); + ECORE_IPC_EVENT_CLIENT_DEL = ecore_event_type_new(); + ECORE_IPC_EVENT_SERVER_ADD = ecore_event_type_new(); + ECORE_IPC_EVENT_SERVER_DEL = ecore_event_type_new(); + ECORE_IPC_EVENT_CLIENT_DATA = ecore_event_type_new(); + ECORE_IPC_EVENT_SERVER_DATA = ecore_event_type_new(); + + handler[i++] = ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_ADD, + _ecore_ipc_event_client_add, NULL); + handler[i++] = ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DEL, + _ecore_ipc_event_client_del, NULL); + handler[i++] = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_ADD, + _ecore_ipc_event_server_add, NULL); + handler[i++] = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DEL, + _ecore_ipc_event_server_del, NULL); + handler[i++] = ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DATA, + _ecore_ipc_event_client_data, NULL); + handler[i] = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DATA, + _ecore_ipc_event_server_data, NULL); + return _ecore_ipc_init_count; +} + +/** + * Shuts down the Ecore IPC library. + * @return Number of times the library has been initialised without being + * shut down. + * @ingroup Ecore_IPC_Library_Group + */ +EAPI int +ecore_ipc_shutdown(void) +{ + int i; + + if (--_ecore_ipc_init_count != 0) + return _ecore_ipc_init_count; + + Eina_List *l, *l2; + Ecore_Ipc_Server *svr; + EINA_LIST_FOREACH_SAFE(servers, l, l2, svr) + ecore_ipc_server_del(svr); + + for (i = 0; i < 6; i++) + ecore_event_handler_del(handler[i]); + + ecore_con_shutdown(); + eina_log_domain_unregister(_ecore_ipc_log_dom); + _ecore_ipc_log_dom = -1; + return _ecore_ipc_init_count; +} + +/** + * @defgroup Ecore_IPC_Server_Group IPC Server Functions + * + * Functions the deal with IPC server objects. + */ + +/** + * Creates an IPC server that listens for connections. + * + * For more details about the @p compl_type, @p name and @p port + * parameters, see the @ref ecore_con_server_add documentation. + * + * @param compl_type The connection type. + * @param name Name to associate with the socket used for connection. + * @param port Number to identify with socket used for connection. + * @param data Data to associate with the IPC server. + * @return New IPC server. If there is an error, @c NULL is returned. + * @ingroup Ecore_IPC_Server_Group + * @todo Need to add protocol type parameter to this function. + */ +EAPI Ecore_Ipc_Server * +ecore_ipc_server_add(Ecore_Ipc_Type compl_type, const char *name, int port, const void *data) +{ + Ecore_Ipc_Server *svr; + Ecore_Ipc_Type type; + Ecore_Con_Type extra = 0; + + svr = calloc(1, sizeof(Ecore_Ipc_Server)); + if (!svr) return NULL; + type = compl_type; + type &= ~ECORE_IPC_USE_SSL; + if (compl_type & ECORE_IPC_USE_SSL) extra = ECORE_CON_USE_SSL; + switch (type) + { + case ECORE_IPC_LOCAL_USER: + svr->server = ecore_con_server_add(ECORE_CON_LOCAL_USER | extra, name, port, svr); + break; + case ECORE_IPC_LOCAL_SYSTEM: + svr->server = ecore_con_server_add(ECORE_CON_LOCAL_SYSTEM | extra, name, port, svr); + break; + case ECORE_IPC_REMOTE_SYSTEM: + svr->server = ecore_con_server_add(ECORE_CON_REMOTE_SYSTEM | extra, name, port, svr); + break; + default: + free(svr); + return NULL; + } + if (!svr->server) + { + free(svr); + return NULL; + } + svr->max_buf_size = 32 * 1024; + svr->data = (void *)data; + servers = eina_list_append(servers, svr); + ECORE_MAGIC_SET(svr, ECORE_MAGIC_IPC_SERVER); + return svr; +} + +/** + * Creates an IPC server object to represent the IPC server listening + * on the given port. + * + * For more details about the @p compl_type, @p name and @p port + * parameters, see the @ref ecore_con_server_connect documentation. + * + * @param compl_type The IPC connection type. + * @param name Name used to determine which socket to use for the + * IPC connection. + * @param port Number used to identify the socket to use for the + * IPC connection. + * @param data Data to associate with the server. + * @return A new IPC server. @c NULL is returned on error. + * @ingroup Ecore_IPC_Server_Group + * @todo Need to add protocol type parameter. + */ +EAPI Ecore_Ipc_Server * +ecore_ipc_server_connect(Ecore_Ipc_Type compl_type, char *name, int port, const void *data) +{ + Ecore_Ipc_Server *svr; + Ecore_Ipc_Type type; + Ecore_Con_Type extra = 0; + int features; + + svr = calloc(1, sizeof(Ecore_Ipc_Server)); + if (!svr) return NULL; + type = compl_type & ECORE_IPC_TYPE; + features = compl_type & ECORE_IPC_SSL; + if ((features & ECORE_IPC_USE_SSL) == ECORE_IPC_USE_SSL) + extra |= ECORE_CON_USE_SSL; + if ((features & ECORE_IPC_NO_PROXY) == ECORE_IPC_NO_PROXY) + extra |= ECORE_CON_NO_PROXY; + switch (type) + { + case ECORE_IPC_LOCAL_USER: + svr->server = ecore_con_server_connect(ECORE_CON_LOCAL_USER | extra, name, port, svr); + break; + case ECORE_IPC_LOCAL_SYSTEM: + svr->server = ecore_con_server_connect(ECORE_CON_LOCAL_SYSTEM | extra, name, port, svr); + break; + case ECORE_IPC_REMOTE_SYSTEM: + svr->server = ecore_con_server_connect(ECORE_CON_REMOTE_SYSTEM | extra, name, port, svr); + break; + default: + free(svr); + return NULL; + } + if (!svr->server) + { + free(svr); + return NULL; + } + svr->max_buf_size = -1; + svr->data = (void *)data; + servers = eina_list_append(servers, svr); + ECORE_MAGIC_SET(svr, ECORE_MAGIC_IPC_SERVER); + return svr; +} + +/** + * Closes the connection and frees the given IPC server. + * @param svr The given IPC server. + * @return The data associated with the server when it was created. + * @ingroup Ecore_IPC_Server_Group + */ +EAPI void * +ecore_ipc_server_del(Ecore_Ipc_Server *svr) +{ + void *data; + + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, + "ecore_ipc_server_del"); + return NULL; + } + if (svr->delete_me) return NULL; + + data = svr->data; + svr->data = NULL; + svr->delete_me = 1; + if (svr->event_count == 0) + { + Ecore_Ipc_Client *cl; + + EINA_LIST_FREE(svr->clients, cl) + ecore_ipc_client_del(cl); + if (svr->server) ecore_con_server_del(svr->server); + servers = eina_list_remove(servers, svr); + + if (svr->buf) free(svr->buf); + ECORE_MAGIC_SET(svr, ECORE_MAGIC_NONE); + free(svr); + } + return data; +} + +/** + * Retrieves the data associated with the given IPC server. + * @param svr The given IPC server. + * @return The associated data. + * @ingroup Ecore_IPC_Server_Group + */ +EAPI void * +ecore_ipc_server_data_get(Ecore_Ipc_Server *svr) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, + "ecore_ipc_server_data_get"); + return NULL; + } + return svr->data; +} + +/** + * Retrieves whether the given IPC server is currently connected. + * @param svr The given IPC server. + * @return @c EINA_TRUE if the server is connected, @c EINA_FALSE otherwise. + * @ingroup Ecore_IPC_Server_Group + */ +EAPI Eina_Bool +ecore_ipc_server_connected_get(Ecore_Ipc_Server *svr) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, + "ecore_ipc_server_connected_get"); + return EINA_FALSE; + } + return ecore_con_server_connected_get(svr->server); +} + +/** + * Retrieves the list of clients for this server. + * @param svr The given IPC server. + * @return An Eina_List with the clients. + * @ingroup Ecore_IPC_Server_Group + */ +EAPI Eina_List * +ecore_ipc_server_clients_get(Ecore_Ipc_Server *svr) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, + "ecore_ipc_server_clients_get"); + return NULL; + } + return svr->clients; +} + +#define SVENC(_member) \ + d = _ecore_ipc_dlt_int(msg._member, svr->prev.o._member, &md); \ + if (md >= DLT_SET) \ + { \ + unsigned int v; \ + unsigned char *dd; \ + dd = (unsigned char *)&v; \ + v = d; \ + v = htonl(v); \ + *(dat + s + 0) = dd[0]; \ + *(dat + s + 1) = dd[1]; \ + *(dat + s + 2) = dd[2]; \ + *(dat + s + 3) = dd[3]; \ + s += 4; \ + } \ + else if (md >= DLT_ADD16) \ + { \ + unsigned short v; \ + unsigned char *dd; \ + dd = (unsigned char *)&v; \ + v = d; \ + v = htons(v); \ + *(dat + s + 0) = dd[0]; \ + *(dat + s + 1) = dd[1]; \ + s += 2; \ + } \ + else if (md >= DLT_ADD8) \ + { \ + *(dat + s + 0) = (unsigned char)d; \ + s += 1; \ + } + +/** + * Sends a message to the given IPC server. + * + * The content of the parameters, excluding the @p svr paramter, is up to + * the client. + * + * @param svr The given IPC server. + * @param major Major opcode of the message. + * @param minor Minor opcode of the message. + * @param ref Message reference number. + * @param ref_to Reference number of the message this message refers to. + * @param response Requires response. + * @param data The data to send as part of the message. + * @param size Length of the data, in bytes, to send. + * @return Number of bytes sent. @c 0 is returned if there is an error. + * @ingroup Ecore_IPC_Server_Group + * @todo This function needs to become an IPC message. + * @todo Fix up the documentation: Make sure what ref_to and response are. + */ +EAPI int +ecore_ipc_server_send(Ecore_Ipc_Server *svr, int major, int minor, int ref, int ref_to, int response, const void *data, int size) +{ + Ecore_Ipc_Msg_Head msg; + int ret; + int *head, md = 0, d, s; + unsigned char dat[sizeof(Ecore_Ipc_Msg_Head)]; + + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, + "ecore_ipc_server_send"); + return 0; + } + if (size < 0) size = 0; + msg.major = major; + msg.minor = minor; + msg.ref = ref; + msg.ref_to = ref_to; + msg.response = response; + msg.size = size; + head = (int *)dat; + s = 4; + SVENC(major); + *head = md; + SVENC(minor); + *head |= md << (4 * 1); + SVENC(ref); + *head |= md << (4 * 2); + SVENC(ref_to); + *head |= md << (4 * 3); + SVENC(response); + *head |= md << (4 * 4); + SVENC(size); + *head |= md << (4 * 5); + *head = htonl(*head); + svr->prev.o = msg; + ret = ecore_con_server_send(svr->server, dat, s); + if (size > 0) ret += ecore_con_server_send(svr->server, data, size); + return ret; +} + +/** + * Sets a limit on the number of clients that can be handled concurrently + * by the given server, and a policy on what to do if excess clients try to + * connect. + * Beware that if you set this once ecore is already running, you may + * already have pending CLIENT_ADD events in your event queue. Those + * clients have already connected and will not be affected by this call. + * Only clients subsequently trying to connect will be affected. + * @param svr The given server. + * @param client_limit The maximum number of clients to handle + * concurrently. -1 means unlimited (default). 0 + * effectively disables the server. + * @param reject_excess_clients Set to 1 to automatically disconnect + * excess clients as soon as they connect if you are + * already handling client_limit clients. Set to 0 + * (default) to just hold off on the "accept()" + * system call until the number of active clients + * drops. This causes the kernel to queue up to 4096 + * connections (or your kernel's limit, whichever is + * lower). + * @ingroup Ecore_Ipc_Server_Group + */ +EAPI void +ecore_ipc_server_client_limit_set(Ecore_Ipc_Server *svr, int client_limit, char reject_excess_clients) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, + "ecore_ipc_server_client_limit_set"); + return; + } + ecore_con_server_client_limit_set(svr->server, client_limit, reject_excess_clients); +} + +/** + * Sets the max data payload size for an Ipc message in bytes + * + * @param svr The given server. + * @param size The maximum data payload size in bytes. + * @ingroup Ecore_Ipc_Server_Group + */ +EAPI void +ecore_ipc_server_data_size_max_set(Ecore_Ipc_Server *svr, int size) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, + "ecore_ipc_server_data_size_max_set"); + return; + } + svr->max_buf_size = size; +} + +/** + * Gets the max data payload size for an Ipc message in bytes + * + * @param svr The given server. + * @return The maximum data payload in bytes. + * @ingroup Ecore_Ipc_Server_Group + */ +EAPI int +ecore_ipc_server_data_size_max_get(Ecore_Ipc_Server *svr) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, + "ecore_ipc_server_data_size_max_get"); + return -1; + } + return svr->max_buf_size; +} + +/** + * Gets the IP address of a server that has been connected to. + * + * @param svr The given server. + * @return A pointer to an internal string that contains the IP address of + * the connected server in the form "XXX.YYY.ZZZ.AAA" IP notation. + * This string should not be modified or trusted to stay valid after + * deletion for the @p svr object. If no IP is known NULL is returned. + * @ingroup Ecore_Ipc_Server_Group + */ +EAPI const char * +ecore_ipc_server_ip_get(Ecore_Ipc_Server *svr) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, + "ecore_ipc_server_ip_get"); + return NULL; + } + return ecore_con_server_ip_get(svr->server); +} + +/** + * Flushes all pending data to the given server. Will return when done. + * + * @param svr The given server. + * @ingroup Ecore_Ipc_Server_Group + */ +EAPI void +ecore_ipc_server_flush(Ecore_Ipc_Server *svr) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, + "ecore_ipc_server_server_flush"); + return; + } + ecore_con_server_flush(svr->server); +} + +#define CLENC(_member) \ + d = _ecore_ipc_dlt_int(msg._member, cl->prev.o._member, &md); \ + if (md >= DLT_SET) \ + { \ + unsigned int v; \ + unsigned char *dd; \ + dd = (unsigned char *)&v; \ + v = d; \ + v = htonl(v); \ + *(dat + s + 0) = dd[0]; \ + *(dat + s + 1) = dd[1]; \ + *(dat + s + 2) = dd[2]; \ + *(dat + s + 3) = dd[3]; \ + s += 4; \ + } \ + else if (md >= DLT_ADD16) \ + { \ + unsigned short v; \ + unsigned char *dd; \ + dd = (unsigned char *)&v; \ + v = d; \ + v = htons(v); \ + *(dat + s + 0) = dd[0]; \ + *(dat + s + 1) = dd[1]; \ + s += 2; \ + } \ + else if (md >= DLT_ADD8) \ + { \ + *(dat + s) = (unsigned char)d; \ + s += 1; \ + } + +/** + * @defgroup Ecore_IPC_Client_Group IPC Client Functions + * + * Functions that deal with IPC client objects. + */ + +/** + * Sends a message to the given IPC client. + * @param cl The given IPC client. + * @param major Major opcode of the message. + * @param minor Minor opcode of the message. + * @param ref Reference number of the message. + * @param ref_to Reference number of the message this message refers to. + * @param response Requires response. + * @param data The data to send as part of the message. + * @param size Length of the data, in bytes, to send. + * @return The number of bytes sent. @c 0 will be returned if there is + * an error. + * @ingroup Ecore_IPC_Client_Group + * @todo This function needs to become an IPC message. + * @todo Make sure ref_to and response parameters are described correctly. + */ +EAPI int +ecore_ipc_client_send(Ecore_Ipc_Client *cl, int major, int minor, int ref, int ref_to, int response, const void *data, int size) +{ + Ecore_Ipc_Msg_Head msg; + int ret; + int *head, md = 0, d, s; + unsigned char dat[sizeof(Ecore_Ipc_Msg_Head)]; + + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, + "ecore_ipc_client_send"); + return 0; + } + EINA_SAFETY_ON_TRUE_RETURN_VAL(!cl->client, 0); + EINA_SAFETY_ON_TRUE_RETURN_VAL(!ecore_con_client_connected_get(cl->client), 0); + if (size < 0) size = 0; + msg.major = major; + msg.minor = minor; + msg.ref = ref; + msg.ref_to = ref_to; + msg.response = response; + msg.size = size; + head = (int *)dat; + s = 4; + CLENC(major); + *head = md; + CLENC(minor); + *head |= md << (4 * 1); + CLENC(ref); + *head |= md << (4 * 2); + CLENC(ref_to); + *head |= md << (4 * 3); + CLENC(response); + *head |= md << (4 * 4); + CLENC(size); + *head |= md << (4 * 5); + *head = htonl(*head); + cl->prev.o = msg; + ret = ecore_con_client_send(cl->client, dat, s); + if (size > 0) ret += ecore_con_client_send(cl->client, data, size); + return ret; +} + +/** + * Retrieves the IPC server that the given IPC client is connected to. + * @param cl The given IPC client. + * @return The IPC server the IPC client is connected to. + * @ingroup Ecore_IPC_Client_Group + */ +EAPI Ecore_Ipc_Server * +ecore_ipc_client_server_get(Ecore_Ipc_Client *cl) +{ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, + "ecore_ipc_client_server_get"); + return NULL; + } + return cl->svr; +} + +/** + * Closes the connection and frees memory allocated to the given IPC + * client. + * @param cl The given client. + * @return Data associated with the client. + * @ingroup Ecore_IPC_Client_Group + */ +EAPI void * +ecore_ipc_client_del(Ecore_Ipc_Client *cl) +{ + void *data; + Ecore_Ipc_Server *svr; + + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, + "ecore_ipc_client_del"); + return NULL; + } + data = cl->data; + cl->data = NULL; + cl->delete_me = 1; + if (cl->event_count == 0) + { + svr = cl->svr; + if (cl->client) ecore_con_client_del(cl->client); + svr->clients = eina_list_remove(svr->clients, cl); + if (cl->buf) free(cl->buf); + ECORE_MAGIC_SET(cl, ECORE_MAGIC_NONE); + free(cl); + } + return data; +} + +/** + * Sets the IPC data associated with the given IPC client to @p data. + * @param cl The given IPC client. + * @param data The data to associate with the IPC client. + * @ingroup Ecore_IPC_Client_Group + */ +EAPI void +ecore_ipc_client_data_set(Ecore_Ipc_Client *cl, const void *data) +{ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, + "ecore_ipc_client_data_set"); + return; + } + cl->data = (void *)data; +} + +/** + * Retrieves the data that has been associated with the given IPC client. + * @param cl The given client. + * @return The data associated with the IPC client. + * @ingroup Ecore_IPC_Client_Group + */ +EAPI void * +ecore_ipc_client_data_get(Ecore_Ipc_Client *cl) +{ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, + "ecore_ipc_client_data_get"); + return NULL; + } + return cl->data; +} + +/** + * Sets the max data payload size for an Ipc message in bytes + * + * @param cl The given client. + * @param size The maximum data payload size in bytes. + * @ingroup Ecore_Ipc_Client_Group + */ +EAPI void +ecore_ipc_client_data_size_max_set(Ecore_Ipc_Client *cl, int size) +{ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, + "ecore_ipc_client_data_size_max_set"); + return; + } + cl->max_buf_size = size; +} + +/** + * Gets the max data payload size for an Ipc message in bytes + * + * @param cl The given client. + * @return The maximum data payload size in bytes on success, @c -1 on failure. + * @ingroup Ecore_Ipc_Client_Group + */ +EAPI int +ecore_ipc_client_data_size_max_get(Ecore_Ipc_Client *cl) +{ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, + "ecore_ipc_client_data_size_max_get"); + return -1; + } + return cl->max_buf_size; +} + +/** + * Gets the IP address of a client that has been connected to. + * + * @param cl The given client. + * @return A pointer to an internal string that contains the IP address of + * the connected server in the form "XXX.YYY.ZZZ.AAA" IP notation. + * This string should not be modified or trusted to stay valid after + * deletion for the @p cl object. If no IP is known @c NULL is + * returned. + * @ingroup Ecore_Ipc_Client_Group + */ +EAPI const char * +ecore_ipc_client_ip_get(Ecore_Ipc_Client *cl) +{ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, + "ecore_ipc_client_ip_get"); + return NULL; + } + return ecore_con_client_ip_get(cl->client); +} + +/** + * Flushes all pending data to the given client. Will return when done. + * + * @param cl The given client. + * @ingroup Ecore_Ipc_Client_Group + */ +EAPI void +ecore_ipc_client_flush(Ecore_Ipc_Client *cl) +{ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT)) + { + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, + "ecore_ipc_client_flush"); + return; + } + ecore_con_client_flush(cl->client); +} + +/** + * Returns if SSL support is available + * @return 1 if SSL is available, 0 if it is not. + * @ingroup Ecore_Con_Client_Group + */ +EAPI int +ecore_ipc_ssl_available_get(void) +{ + return ecore_con_ssl_available_get(); +} + + +static Eina_Bool +_ecore_ipc_event_client_add(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) +{ + Ecore_Con_Event_Client_Add *e; + Ecore_Ipc_Server *svr; + + e = ev; + svr = ecore_con_server_data_get(ecore_con_client_server_get(e->client)); + if (!eina_list_data_find(servers, svr)) return ECORE_CALLBACK_RENEW; + /* handling code here */ + { + Ecore_Ipc_Client *cl; + + cl = calloc(1, sizeof(Ecore_Ipc_Client)); + if (!cl) return ECORE_CALLBACK_CANCEL; + cl->svr = svr; + ECORE_MAGIC_SET(cl, ECORE_MAGIC_IPC_CLIENT); + cl->client = e->client; + cl->max_buf_size = 32 * 1024; + ecore_con_client_data_set(cl->client, (void *)cl); + svr->clients = eina_list_append(svr->clients, cl); + if (!cl->delete_me) + { + Ecore_Ipc_Event_Client_Add *e2; + + e2 = calloc(1, sizeof(Ecore_Ipc_Event_Client_Add)); + if (e2) + { + cl->event_count++; + e2->client = cl; + ecore_event_add(ECORE_IPC_EVENT_CLIENT_ADD, e2, + _ecore_ipc_event_client_add_free, NULL); + } + } + } + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool +_ecore_ipc_event_client_del(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) +{ + Ecore_Con_Event_Client_Del *e; + Ecore_Ipc_Server *svr; + + e = ev; + if (!e->client) return ECORE_CALLBACK_RENEW; + svr = ecore_con_server_data_get(ecore_con_client_server_get(e->client)); + if (!eina_list_data_find(servers, svr)) return ECORE_CALLBACK_RENEW; + /* handling code here */ + { + Ecore_Ipc_Client *cl; + + cl = ecore_con_client_data_get(e->client); + cl->client = NULL; + { + Ecore_Ipc_Event_Client_Del *e2; + + if (!cl->delete_me) + { + e2 = calloc(1, sizeof(Ecore_Ipc_Event_Client_Del)); + if (e2) + { + cl->event_count++; + e2->client = cl; + ecore_event_add(ECORE_IPC_EVENT_CLIENT_DEL, e2, + _ecore_ipc_event_client_del_free, NULL); + } + } + } + } + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool +_ecore_ipc_event_server_add(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) +{ + Ecore_Con_Event_Server_Add *e; + + e = ev; + if (!eina_list_data_find(servers, ecore_con_server_data_get(e->server))) return ECORE_CALLBACK_RENEW; + /* handling code here */ + { + Ecore_Ipc_Server *svr; + + svr = ecore_con_server_data_get(e->server); + if (!svr->delete_me) + { + Ecore_Ipc_Event_Server_Add *e2; + + e2 = calloc(1, sizeof(Ecore_Ipc_Event_Server_Add)); + if (e2) + { + svr->event_count++; + e2->server = svr; + ecore_event_add(ECORE_IPC_EVENT_SERVER_ADD, e2, + _ecore_ipc_event_server_add_free, NULL); + } + } + } + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool +_ecore_ipc_event_server_del(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) +{ + Ecore_Con_Event_Server_Del *e; + + e = ev; + if (!eina_list_data_find(servers, ecore_con_server_data_get(e->server))) return ECORE_CALLBACK_RENEW; + /* handling code here */ + { + Ecore_Ipc_Server *svr; + + svr = ecore_con_server_data_get(e->server); + svr->server = NULL; + if (!svr->delete_me) + { + Ecore_Ipc_Event_Server_Del *e2; + + e2 = calloc(1, sizeof(Ecore_Ipc_Event_Server_Del)); + if (e2) + { + svr->event_count++; + e2->server = svr; + ecore_event_add(ECORE_IPC_EVENT_SERVER_DEL, e2, + _ecore_ipc_event_server_del_free, NULL); + } + } + } + return ECORE_CALLBACK_CANCEL; +} + +#define CLSZ(_n) \ + md = ((head >> (4 * _n)) & 0xf); \ + if (md >= DLT_SET) s += 4; \ + else if (md >= DLT_ADD16) s += 2; \ + else if (md >= DLT_ADD8) s += 1; + +#define CLDEC(_n, _member) \ + md = ((head >> (4 * _n)) & 0xf); \ + if (md >= DLT_SET) \ + { \ + unsigned int v; \ + unsigned char *dv; \ + dv = (unsigned char *)&v; \ + dv[0] = *(cl->buf + offset + s + 0); \ + dv[1] = *(cl->buf + offset + s + 1); \ + dv[2] = *(cl->buf + offset + s + 2); \ + dv[3] = *(cl->buf + offset + s + 3); \ + d = (int)ntohl(v); \ + s += 4; \ + } \ + else if (md >= DLT_ADD16) \ + { \ + unsigned short v; \ + unsigned char *dv; \ + dv = (unsigned char *)&v; \ + dv[0] = *(cl->buf + offset + s + 0); \ + dv[1] = *(cl->buf + offset + s + 1); \ + d = (int)ntohs(v); \ + s += 2; \ + } \ + else if (md >= DLT_ADD8) \ + { \ + unsigned char v; \ + unsigned char *dv; \ + dv = (unsigned char *)&v; \ + dv[0] = *(cl->buf + offset + s + 0); \ + d = (int)v; \ + s += 1; \ + } \ + msg._member = _ecore_ipc_ddlt_int(d, cl->prev.i._member, md); + +static Eina_Bool +_ecore_ipc_event_client_data(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) +{ + Ecore_Con_Event_Client_Data *e; + Ecore_Ipc_Server *svr; + + e = ev; + svr = ecore_con_server_data_get(ecore_con_client_server_get(e->client)); + if (!eina_list_data_find(servers, svr)) return ECORE_CALLBACK_RENEW; + /* handling code here */ + { + Ecore_Ipc_Client *cl; + Ecore_Ipc_Msg_Head msg; + int offset = 0; + unsigned char *buf; + + cl = ecore_con_client_data_get(e->client); + + if (!cl->buf) + { + cl->buf_size = e->size; + cl->buf = e->data; + e->data = NULL; /* take it out of the old event */ + } + else + { + buf = realloc(cl->buf, cl->buf_size + e->size); + if (!buf) + { + free(cl->buf); + cl->buf = 0; + cl->buf_size = 0; + return ECORE_CALLBACK_CANCEL; + } + cl->buf = buf; + memcpy(cl->buf + cl->buf_size, e->data, e->size); + cl->buf_size += e->size; + } + /* examine header */ + redo: + if ((cl->buf_size - offset) >= (int)sizeof(int)) + { + int s, md, d = 0, head; + unsigned char *dd; + + dd = (unsigned char *)&head; + dd[0] = *(cl->buf + offset + 0); + dd[1] = *(cl->buf + offset + 1); + dd[2] = *(cl->buf + offset + 2); + dd[3] = *(cl->buf + offset + 3); + head = ntohl(head); + dd = (unsigned char *)&d; + s = 4; + CLSZ(0); + CLSZ(1); + CLSZ(2); + CLSZ(3); + CLSZ(4); + CLSZ(5); + if ((cl->buf_size - offset) < s) + { + if (offset > 0) goto scroll; + return ECORE_CALLBACK_CANCEL; + } + + s = 4; + CLDEC(0, major); + CLDEC(1, minor); + CLDEC(2, ref); + CLDEC(3, ref_to); + CLDEC(4, response); + CLDEC(5, size); + if (msg.size < 0) msg.size = 0; + /* there is enough data in the buffer for a full message */ + if ((cl->buf_size - offset) >= (s + msg.size)) + { + Ecore_Ipc_Event_Client_Data *e2; + int max, max2; + + buf = NULL; + max = svr->max_buf_size; + max2 = cl->max_buf_size; + if ((max >= 0) && (max2 >= 0)) + { + if (max2 < max) max = max2; + } + else + { + if (max < 0) max = max2; + } + if ((max < 0) || (msg.size <= max)) + { + if (msg.size > 0) + { + buf = malloc(msg.size); + if (!buf) return ECORE_CALLBACK_CANCEL; + memcpy(buf, cl->buf + offset + s, msg.size); + } + if (!cl->delete_me) + { + e2 = calloc(1, sizeof(Ecore_Ipc_Event_Client_Data)); + if (e2) + { + cl->event_count++; + e2->client = cl; + e2->major = msg.major; + e2->minor = msg.minor; + e2->ref = msg.ref; + e2->ref_to = msg.ref_to; + e2->response = msg.response; + e2->size = msg.size; + e2->data = buf; + ecore_event_add(ECORE_IPC_EVENT_CLIENT_DATA, e2, + _ecore_ipc_event_client_data_free, + NULL); + } + } + } + cl->prev.i = msg; + offset += (s + msg.size); + if (cl->buf_size == offset) + { + free(cl->buf); + cl->buf = NULL; + cl->buf_size = 0; + return ECORE_CALLBACK_CANCEL; + } + goto redo; + } + else goto scroll; + } + else + { + scroll: + buf = malloc(cl->buf_size - offset); + if (!buf) + { + free(cl->buf); + cl->buf = NULL; + cl->buf_size = 0; + return ECORE_CALLBACK_CANCEL; + } + memcpy(buf, cl->buf + offset, cl->buf_size - offset); + free(cl->buf); + cl->buf = buf; + cl->buf_size -= offset; + } + } + return ECORE_CALLBACK_CANCEL; +} + +#define SVSZ(_n) \ + md = ((head >> (4 * _n)) & 0xf); \ + if (md >= DLT_SET) s += 4; \ + else if (md >= DLT_ADD16) s += 2; \ + else if (md >= DLT_ADD8) s += 1; + +#define SVDEC(_n, _member) \ + md = ((head >> (4 * _n)) & 0xf); \ + if (md >= DLT_SET) \ + { \ + unsigned int v; \ + unsigned char *dv; \ + dv = (unsigned char *)&v; \ + dv[0] = *(svr->buf + offset + s + 0); \ + dv[1] = *(svr->buf + offset + s + 1); \ + dv[2] = *(svr->buf + offset + s + 2); \ + dv[3] = *(svr->buf + offset + s + 3); \ + d = (int)ntohl(v); \ + s += 4; \ + } \ + else if (md >= DLT_ADD16) \ + { \ + unsigned short v; \ + unsigned char *dv; \ + dv = (unsigned char *)&v; \ + dv[0] = *(svr->buf + offset + s + 0); \ + dv[1] = *(svr->buf + offset + s + 1); \ + d = (int)ntohs(v); \ + s += 2; \ + } \ + else if (md >= DLT_ADD8) \ + { \ + unsigned char v; \ + unsigned char *dv; \ + dv = (unsigned char *)&v; \ + dv[0] = *(svr->buf + offset + s + 0); \ + d = (int)v; \ + s += 1; \ + } \ + msg._member = _ecore_ipc_ddlt_int(d, svr->prev.i._member, md); + +static Eina_Bool +_ecore_ipc_event_server_data(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) +{ + Ecore_Con_Event_Server_Data *e; + + e = ev; + if (!eina_list_data_find(servers, ecore_con_server_data_get(e->server))) return ECORE_CALLBACK_RENEW; + /* handling code here */ + { + Ecore_Ipc_Server *svr; + Ecore_Ipc_Msg_Head msg; + int offset = 0; + unsigned char *buf; + + svr = ecore_con_server_data_get(e->server); + + if (!svr->buf) + { + svr->buf_size = e->size; + svr->buf = e->data; + e->data = NULL; /* take it out of the old event */ + } + else + { + buf = realloc(svr->buf, svr->buf_size + e->size); + if (!buf) + { + free(svr->buf); + svr->buf = 0; + svr->buf_size = 0; + return ECORE_CALLBACK_CANCEL; + } + svr->buf = buf; + memcpy(svr->buf + svr->buf_size, e->data, e->size); + svr->buf_size += e->size; + } + /* examine header */ + redo: + if ((svr->buf_size - offset) >= (int)sizeof(int)) + { + int s, md, d = 0, head; + unsigned char *dd; + + dd = (unsigned char *)&head; + dd[0] = *(svr->buf + offset + 0); + dd[1] = *(svr->buf + offset + 1); + dd[2] = *(svr->buf + offset + 2); + dd[3] = *(svr->buf + offset + 3); + head = ntohl(head); + dd = (unsigned char *)&d; + s = 4; + SVSZ(0); + SVSZ(1); + SVSZ(2); + SVSZ(3); + SVSZ(4); + SVSZ(5); + if ((svr->buf_size - offset) < s) + { + if (offset > 0) goto scroll; + return ECORE_CALLBACK_CANCEL; + } + + s = 4; + SVDEC(0, major); + SVDEC(1, minor); + SVDEC(2, ref); + SVDEC(3, ref_to); + SVDEC(4, response); + SVDEC(5, size); + if (msg.size < 0) msg.size = 0; + /* there is enough data in the buffer for a full message */ + if ((svr->buf_size - offset) >= (s + msg.size)) + { + Ecore_Ipc_Event_Server_Data *e2; + int max; + + buf = NULL; + max = svr->max_buf_size; + if ((max < 0) || (msg.size <= max)) + { + if (msg.size > 0) + { + buf = malloc(msg.size); + if (!buf) return ECORE_CALLBACK_CANCEL; + memcpy(buf, svr->buf + offset + s, msg.size); + } + if (!svr->delete_me) + { + e2 = calloc(1, sizeof(Ecore_Ipc_Event_Server_Data)); + if (e2) + { + svr->event_count++; + e2->server = svr; + e2->major = msg.major; + e2->minor = msg.minor; + e2->ref = msg.ref; + e2->ref_to = msg.ref_to; + e2->response = msg.response; + e2->size = msg.size; + e2->data = buf; + ecore_event_add(ECORE_IPC_EVENT_SERVER_DATA, e2, + _ecore_ipc_event_server_data_free, + NULL); + } + } + } + svr->prev.i = msg; + offset += (s + msg.size); + if (svr->buf_size == offset) + { + free(svr->buf); + svr->buf = NULL; + svr->buf_size = 0; + return ECORE_CALLBACK_CANCEL; + } + goto redo; + } + else goto scroll; + } + else + { + scroll: + buf = malloc(svr->buf_size - offset); + if (!buf) + { + free(svr->buf); + svr->buf = NULL; + svr->buf_size = 0; + return ECORE_CALLBACK_CANCEL; + } + memcpy(buf, svr->buf + offset, svr->buf_size - offset); + free(svr->buf); + svr->buf = buf; + svr->buf_size -= offset; + } + } + return ECORE_CALLBACK_CANCEL; +} + +static void +_ecore_ipc_event_client_add_free(void *data __UNUSED__, void *ev) +{ + Ecore_Ipc_Event_Client_Add *e; + + e = ev; + e->client->event_count--; + if ((e->client->event_count == 0) && (e->client->delete_me)) + ecore_ipc_client_del(e->client); + free(e); +} + +static void +_ecore_ipc_event_client_del_free(void *data __UNUSED__, void *ev) +{ + Ecore_Ipc_Event_Client_Del *e; + + e = ev; + e->client->event_count--; + if ((e->client->event_count == 0) && (e->client->delete_me)) + ecore_ipc_client_del(e->client); + free(e); +} + +static void +_ecore_ipc_event_client_data_free(void *data __UNUSED__, void *ev) +{ + Ecore_Ipc_Event_Client_Data *e; + + e = ev; + e->client->event_count--; + if (e->data) free(e->data); + if ((e->client->event_count == 0) && (e->client->delete_me)) + ecore_ipc_client_del(e->client); + free(e); +} + +static void +_ecore_ipc_event_server_add_free(void *data __UNUSED__, void *ev) +{ + Ecore_Ipc_Event_Server_Add *e; + + e = ev; + e->server->event_count--; + if ((e->server->event_count == 0) && (e->server->delete_me)) + ecore_ipc_server_del(e->server); + free(e); +} + +static void +_ecore_ipc_event_server_del_free(void *data __UNUSED__, void *ev) +{ + Ecore_Ipc_Event_Server_Add *e; + + e = ev; + e->server->event_count--; + if ((e->server->event_count == 0) && (e->server->delete_me)) + ecore_ipc_server_del(e->server); + free(e); +} + +static void +_ecore_ipc_event_server_data_free(void *data __UNUSED__, void *ev) +{ + Ecore_Ipc_Event_Server_Data *e; + + e = ev; + if (e->data) free(e->data); + e->server->event_count--; + if ((e->server->event_count == 0) && (e->server->delete_me)) + ecore_ipc_server_del(e->server); + free(e); +} diff --git a/src/lib/ecore_ipc/ecore_ipc_private.h b/src/lib/ecore_ipc/ecore_ipc_private.h new file mode 100644 index 0000000..bedaab1 --- /dev/null +++ b/src/lib/ecore_ipc/ecore_ipc_private.h @@ -0,0 +1,105 @@ +#ifndef _ECORE_IPC_PRIVATE_H +#define _ECORE_IPC_PRIVATE_H + + +extern int _ecore_ipc_log_dom; + +#ifdef ECORE_IPC_DEFAULT_LOG_COLOR +# undef ECORE_IPC_DEFAULT_LOG_COLOR +#endif +#define ECORE_IPC_DEFAULT_LOG_COLOR EINA_COLOR_BLUE + +#ifdef ERR +# undef ERR +#endif +#define ERR(...) EINA_LOG_DOM_ERR(_ecore_ipc_log_dom, __VA_ARGS__) + +#ifdef DBG +# undef DBG +#endif +#define DBG(...) EINA_LOG_DOM_DBG(_ecore_ipc_log_dom, __VA_ARGS__) + +#ifdef INF +# undef INF +#endif +#define INF(...) EINA_LOG_DOM_INFO(_ecore_ipc_log_dom, __VA_ARGS__) + +#ifdef WRN +# undef WRN +#endif +#define WRN(...) EINA_LOG_DOM_WARN(_ecore_ipc_log_dom, __VA_ARGS__) + +#ifdef CRIT +# undef CRIT +#endif +#define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_ipc_log_dom, __VA_ARGS__) + +#define ECORE_MAGIC_IPC_SERVER 0x87786556 +#define ECORE_MAGIC_IPC_CLIENT 0x78875665 + +typedef struct _Ecore_Ipc_Msg_Head Ecore_Ipc_Msg_Head; +#define ECORE_IPC_TYPE 0x0f +#define ECORE_IPC_SSL 0xf0 + +#if defined (_MSC_VER) || (defined (__SUNPRO_C) && __SUNPRO_C < 0x5100) +# pragma pack(1) +# define ECORE_IPC_STRUCT_PACKED +#elif defined (__GNUC__) || (defined (__SUNPRO_C) && __SUNPRO_C >= 0x5100) +# define ECORE_IPC_STRUCT_PACKED __attribute__((packed)) +#else +# define ECORE_IPC_STRUCT_PACKED +#endif + +#ifdef __sgi +#pragma pack 4 +#endif +struct _Ecore_Ipc_Msg_Head +{ + int major; + int minor; + int ref; + int ref_to; + int response; + int size; +} ECORE_IPC_STRUCT_PACKED; +#ifdef __sgi +#pragma pack 0 +#endif + +struct _Ecore_Ipc_Client +{ + ECORE_MAGIC; + Ecore_Con_Client *client; + Ecore_Ipc_Server *svr; + void *data; + unsigned char *buf; + int buf_size; + int max_buf_size; + + struct { + Ecore_Ipc_Msg_Head i, o; + } prev; + + int event_count; + char delete_me : 1; +}; + +struct _Ecore_Ipc_Server +{ + ECORE_MAGIC; + Ecore_Con_Server *server; + Eina_List *clients; + void *data; + unsigned char *buf; + int buf_size; + int max_buf_size; + + struct { + Ecore_Ipc_Msg_Head i, o; + } prev; + + int event_count; + char delete_me : 1; +}; + +#endif diff --git a/src/lib/ecore_psl1ght/Ecore_Psl1ght.h b/src/lib/ecore_psl1ght/Ecore_Psl1ght.h new file mode 100644 index 0000000..c6300fd --- /dev/null +++ b/src/lib/ecore_psl1ght/Ecore_Psl1ght.h @@ -0,0 +1,121 @@ +#ifndef _ECORE_PSL1GHT_H +#define _ECORE_PSL1GHT_H + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +#else +# define EAPI +#endif + +/** + * @file + * @brief Ecore PSL1GHT system functions. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +EAPI extern int ECORE_PSL1GHT_EVENT_KEY_MODIFIERS; +EAPI extern int ECORE_PSL1GHT_EVENT_GOT_FOCUS; +EAPI extern int ECORE_PSL1GHT_EVENT_LOST_FOCUS; +EAPI extern int ECORE_PSL1GHT_EVENT_EXPOSE; +EAPI extern int ECORE_PSL1GHT_EVENT_QUIT; + +typedef struct _Ecore_Psl1ght_Event_Key_Modifiers Ecore_Psl1ght_Event_Key_Modifiers; +struct _Ecore_Psl1ght_Event_Key_Modifiers /** PSL1GHT Key Modifier event */ +{ + unsigned int timestamp; + unsigned int modifiers; + int shift_changed : 1; + int shift : 1; + int alt_changed : 1; + int alt : 1; + int ctrl_changed : 1; + int ctrl : 1; + int win_changed : 1; + int win : 1; + int num_lock_changed : 1; + int num_lock : 1; + int caps_lock_changed : 1; + int caps_lock : 1; + int scroll_lock_changed : 1; + int scroll_lock : 1; +}; + +typedef struct _Ecore_Psl1ght_Event_Key_Down Ecore_Psl1ght_Event_Key_Down; +struct _Ecore_Psl1ght_Event_Key_Down /** PSL1GHT Key Down event */ +{ + const char *keyname; /**< The name of the key that was pressed */ + const char *keycompose; /**< The UTF-8 string conversion if any */ + unsigned int time; +}; + +typedef struct _Ecore_Psl1ght_Event_Key_Up Ecore_Psl1ght_Event_Key_Up; +struct _Ecore_Psl1ght_Event_Key_Up /** PSL1GHT Key Up event */ +{ + const char *keyname; /**< The name of the key that was released */ + const char *keycompose; /**< The UTF-8 string conversion if any */ + unsigned int time; +}; + +typedef struct _Ecore_Psl1ght_Event_Mouse_Button_Down Ecore_Psl1ght_Event_Mouse_Button_Down; +struct _Ecore_Psl1ght_Event_Mouse_Button_Down /** PSL1GHT Mouse Down event */ +{ + int button; /**< Mouse button that was pressed (1 - 32) */ + int x; /**< Mouse co-ordinates when mouse button was pressed */ + int y; /**< Mouse co-ordinates when mouse button was pressed */ + int double_click : 1; /**< Set if click was a double click */ + int triple_click : 1; /**< Set if click was a triple click */ + unsigned int time; +}; + +typedef struct _Ecore_Psl1ght_Event_Mouse_Button_Up Ecore_Psl1ght_Event_Mouse_Button_Up; +struct _Ecore_Psl1ght_Event_Mouse_Button_Up /** PSL1GHT Mouse Up event */ +{ + int button; /**< Mouse button that was released (1 - 32) */ + int x; /**< Mouse co-ordinates when mouse button was raised */ + int y; /**< Mouse co-ordinates when mouse button was raised */ + int double_click : 1; /**< Set if click was a double click */ + int triple_click : 1; /**< Set if click was a triple click */ + unsigned int time; +}; + +typedef struct _Ecore_Psl1ght_Event_Mouse_Move Ecore_Psl1ght_Event_Mouse_Move; +struct _Ecore_Psl1ght_Event_Mouse_Move /** PSL1GHT Mouse Move event */ +{ + int x; /**< Mouse co-ordinates where the mouse cursor moved to */ + int y; /**< Mouse co-ordinates where the mouse cursor moved to */ + unsigned int time; +}; + +typedef struct _Ecore_Psl1ght_Event_Mouse_Wheel Ecore_Psl1ght_Event_Mouse_Wheel; +struct _Ecore_Psl1ght_Event_Mouse_Wheel /** PSL1GHT Mouse Wheel event */ +{ + int x, y; + int direction; /* 0 = vertical, 1 = horizontal */ + int wheel; /* value 1 (left/up), -1 (right/down) */ + unsigned int time; +}; + +EAPI int ecore_psl1ght_init(const char *name); +EAPI int ecore_psl1ght_shutdown(void); +EAPI void ecore_psl1ght_resolution_set(int width, int height); +EAPI void ecore_psl1ght_poll_events(void); + +EAPI void ecore_psl1ght_screen_resolution_get(int *w, int *h); +EAPI void ecore_psl1ght_optimal_screen_resolution_get(int *w, int *h); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/ecore_psl1ght/Ecore_Psl1ght_Keys.h b/src/lib/ecore_psl1ght/Ecore_Psl1ght_Keys.h new file mode 100644 index 0000000..e385af8 --- /dev/null +++ b/src/lib/ecore_psl1ght/Ecore_Psl1ght_Keys.h @@ -0,0 +1,78 @@ +#ifndef ECORE_PSL1GHT_KEYS_H__ +# define ECORE_PSL1GHT_KEYS_H__ + +struct _ecore_psl1ght_keys_s +{ + int code; + const char *name; + const char *compose; +}; + +static const struct _ecore_psl1ght_keys_s keystable[] = +{ + { KB_RAWKEY_NO_EVENT, "0x00", "" }, + { KB_RAWKEY_BS, "BackSpace", "\010" }, + { KB_RAWKEY_TAB, "Tab", "\011" }, + { KB_RAWKEY_ENTER, "Return", "\015" }, + { KB_RAWKEY_PAUSE, "Pause", "Pause" }, + { KB_RAWKEY_ESCAPE, "Escape", "\033" }, + { KB_RAWKEY_SPACE, "space", " " }, + + /* Skip uppercase letters */ + { KB_RAWKEY_LEFT_BRACKET_101, "bracketleft", "[" }, + { KB_RAWKEY_BACKSLASH_101, "backslash", "\\" }, + { KB_RAWKEY_RIGHT_BRACKET_101, "bracketright", "]" }, + { KB_RAWKEY_ACCENT_CIRCONFLEX_106, "asciicircumm", "^" }, + { KB_RAWKEY_DELETE, "Delete", "\177" }, + /* End of ASCII mapped keysyms */ + + /* Numeric keypad */ + { KB_RAWKEY_KPAD_0, "KP0", "0" }, + { KB_RAWKEY_KPAD_1, "KP1", "1" }, + { KB_RAWKEY_KPAD_2, "KP2", "2" }, + { KB_RAWKEY_KPAD_3, "KP3", "3" }, + { KB_RAWKEY_KPAD_4, "KP4", "4" }, + { KB_RAWKEY_KPAD_5, "KP5", "5" }, + { KB_RAWKEY_KPAD_6, "KP6", "6" }, + { KB_RAWKEY_KPAD_7, "KP7", "7" }, + { KB_RAWKEY_KPAD_8, "KP8", "8" }, + { KB_RAWKEY_KPAD_9, "KP9", "9" }, + { KB_RAWKEY_KPAD_PERIOD, "period", "." }, + { KB_RAWKEY_KPAD_SLASH, "KP_Divide", "/" }, + { KB_RAWKEY_KPAD_ASTERISK, "KP_Multiply", "*" }, + { KB_RAWKEY_KPAD_MINUS, "KP_Minus", "-" }, + { KB_RAWKEY_KPAD_PLUS, "KP_Plus", "+" }, + { KB_RAWKEY_KPAD_ENTER, "KP_Enter", "\015" }, + + /* Arrows + Home/End pad */ + { KB_RAWKEY_UP_ARROW, "Up", "Up" }, + { KB_RAWKEY_DOWN_ARROW, "Down", "Down" }, + { KB_RAWKEY_RIGHT_ARROW, "Right", "Right" }, + { KB_RAWKEY_LEFT_ARROW, "Left", "Left" }, + { KB_RAWKEY_INSERT, "Insert", "Insert" }, + { KB_RAWKEY_HOME, "Home", "Home" }, + { KB_RAWKEY_END, "End", "End" }, + { KB_RAWKEY_PAGE_UP, "Page_Up", "Page_Up" }, + { KB_RAWKEY_PAGE_DOWN, "Page_Down", "Page_Down" }, + + /* Function keys */ + { KB_RAWKEY_F1, "F1", "F1" }, + { KB_RAWKEY_F2, "F2", "F2" }, + { KB_RAWKEY_F3, "F3", "F3" }, + { KB_RAWKEY_F4, "F4", "F4" }, + { KB_RAWKEY_F5, "F5", "F5" }, + { KB_RAWKEY_F6, "F6", "F6" }, + { KB_RAWKEY_F7, "F7", "F7" }, + { KB_RAWKEY_F8, "F8", "F8" }, + { KB_RAWKEY_F9, "F9", "F9" }, + { KB_RAWKEY_F10, "F10", "F10" }, + { KB_RAWKEY_F11, "F11", "F11" }, + { KB_RAWKEY_F12, "F12", "F12" }, + + /* Key state modifier keys */ + { KB_RAWKEY_KPAD_NUMLOCK, "Num_Lock", "Num_Lock" }, + { KB_RAWKEY_CAPS_LOCK, "Caps_Lock", "Caps_Lock" }, + { KB_RAWKEY_SCROLL_LOCK, "Scroll_Lock", "Scroll_Lock" }, +}; + +#endif /* ECORE_PSL1GHT_KEYS_H__ */ diff --git a/src/lib/ecore_psl1ght/Makefile.am b/src/lib/ecore_psl1ght/Makefile.am new file mode 100644 index 0000000..8e7328a --- /dev/null +++ b/src/lib/ecore_psl1ght/Makefile.am @@ -0,0 +1,30 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore_evas \ +-I$(top_srcdir)/src/lib/ecore_input \ +-I$(top_builddir)/src/lib/ecore \ +-I$(top_builddir)/src/lib/ecore_evas \ +-I$(top_builddir)/src/lib/ecore_input \ +@EFL_ECORE_PSL1GHT_BUILD@ \ +@EVAS_CFLAGS@ \ +@EINA_CFLAGS@ + +lib_LTLIBRARIES = libecore_psl1ght.la +includes_HEADERS = Ecore_Psl1ght.h +includesdir = $(includedir)/ecore-@VMAJ@ + +libecore_psl1ght_la_SOURCES = \ +ecore_psl1ght.c \ +moveutil.c \ +spursutil.c + +libecore_psl1ght_la_LIBADD = \ +$(top_builddir)/src/lib/ecore/libecore.la \ +$(top_builddir)/src/lib/ecore_input/libecore_input.la \ +@EINA_LIBS@ + +libecore_psl1ght_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ + +EXTRA_DIST = Ecore_Psl1ght_Keys.h ecore_psl1ght_private.h diff --git a/src/lib/ecore_psl1ght/ecore_psl1ght.c b/src/lib/ecore_psl1ght/ecore_psl1ght.c new file mode 100644 index 0000000..16487ad --- /dev/null +++ b/src/lib/ecore_psl1ght/ecore_psl1ght.c @@ -0,0 +1,859 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "moveutil.h" + +#include "Eina.h" +#include "Ecore_Psl1ght.h" +#include "Ecore_Input.h" +#include "Ecore.h" +#include "ecore_psl1ght_private.h" +#include "ecore_private.h" +#include "Ecore_Psl1ght_Keys.h" + +/* Allocate 1MB stack to avoid overflows */ +SYS_PROCESS_PARAM(1001, 0x100000); + +int _ecore_psl1ght_log_dom = -1; + +EAPI int ECORE_PSL1GHT_EVENT_KEY_MODIFIERS = 0; +EAPI int ECORE_PSL1GHT_EVENT_GOT_FOCUS = 0; +EAPI int ECORE_PSL1GHT_EVENT_LOST_FOCUS = 0; +EAPI int ECORE_PSL1GHT_EVENT_EXPOSE = 0; +EAPI int ECORE_PSL1GHT_EVENT_QUIT = 0; + +static int _ecore_psl1ght_init_count = 0; +static int window_width = 0; +static int window_height = 0; +/* Mouse support */ +static int mouse_connected = FALSE; +static u8 mouse_buttons = 0; +static int mouse_x = 0; +static int mouse_y = 0; +/* Keyboard support */ +static int keyboard_connected = FALSE; +static KbLed keyboard_leds = {{0}}; +static KbMkey keyboard_mods = {{0}}; +static u16 keyboard_old_key = 0; +/* Pad support */ +static padData pad_data; +static padData old_pad_data = {0}; +static int pad_old_x = 0; +static int pad_old_o = 0; +/* Move support */ +static int move_connected = FALSE; +static moveContext *move_context = NULL; +u16 move_buttons = 0; + +static void xmb_event_handler(u64 status, u64 param, void *user_data); + +/** + * @defgroup Ecore_Psl1ght_Library_Group PSL1GHT Library Functions + * + * Functions used to set up and shut down the Ecore_Psl1ght functions. + */ + +/** + * Sets up the Ecore_Psl1ght library. + * @param name device target name + * @return @c 0 on failure. Otherwise, the number of times the library has + * been initialised without being shut down. + * @ingroup Ecore_PSL1GHT_Library_Group + */ +EAPI int +ecore_psl1ght_init(const char *name __UNUSED__) +{ + videoState state; + videoResolution resolution; + int ret, camera_loaded, gem_loaded; + + if (++_ecore_psl1ght_init_count != 1) + return _ecore_psl1ght_init_count; + _ecore_psl1ght_log_dom = eina_log_domain_register + ("ecore_psl1ght", ECORE_PSL1GHT_DEFAULT_LOG_COLOR); + if (_ecore_psl1ght_log_dom < 0) + { + EINA_LOG_ERR("Impossible to create a log domain for the Ecore PSL1GHT module."); + return --_ecore_psl1ght_init_count; + } + if (!ecore_event_init()) + { + eina_log_domain_unregister(_ecore_psl1ght_log_dom); + _ecore_psl1ght_log_dom = -1; + return --_ecore_psl1ght_init_count; + } + + if (videoGetState (0, 0, &state) == 0 && + videoGetResolution (state.displayMode.resolution, &resolution) == 0) + { + ecore_psl1ght_resolution_set (resolution.width, resolution.height); + } + else + { + ecore_event_shutdown(); + eina_log_domain_unregister(_ecore_psl1ght_log_dom); + _ecore_psl1ght_log_dom = -1; + return --_ecore_psl1ght_init_count; + } + + /* Pad support */ + ioPadInit (7); + /* Mouse support */ + ioMouseInit(2); + mouse_buttons = 0; + mouse_x = 0; + mouse_y = 0; + + /* Keyboard support */ + ioKbInit(2); + keyboard_leds._KbLedU.leds = 0; + keyboard_mods._KbMkeyU.mkeys = 0; + + /* Initialize Move */ + move_context = NULL; + move_buttons = 0; + + camera_loaded = !sysModuleIsLoaded (SYSMODULE_CAMERA); + if (!camera_loaded) + ret = sysModuleLoad (SYSMODULE_CAMERA); + else + ret = 0; + if (ret == 0) + { + gem_loaded = !sysModuleIsLoaded (SYSMODULE_GEM); + if (!gem_loaded) + ret = sysModuleLoad (SYSMODULE_GEM); + if (ret == 0) + { + move_context = initMove (); + } + else { + if (gem_loaded) + sysModuleUnload (SYSMODULE_CAMERA); + } + } + + sysUtilRegisterCallback (SYSUTIL_EVENT_SLOT0, xmb_event_handler, NULL); + + ECORE_PSL1GHT_EVENT_GOT_FOCUS = ecore_event_type_new(); + ECORE_PSL1GHT_EVENT_LOST_FOCUS = ecore_event_type_new(); + ECORE_PSL1GHT_EVENT_EXPOSE = ecore_event_type_new(); + ECORE_PSL1GHT_EVENT_KEY_MODIFIERS = ecore_event_type_new(); + ECORE_PSL1GHT_EVENT_QUIT = ecore_event_type_new(); + + mouse_x = 0; + mouse_y = 0; + + return _ecore_psl1ght_init_count; +} + +/** + * Shuts down the Ecore_Psl1ght library. + * @return @c The number of times the system has been initialised without + * being shut down. + * @ingroup Ecore_PSL1GHT_Library_Group + */ +EAPI int +ecore_psl1ght_shutdown(void) +{ + if (--_ecore_psl1ght_init_count != 0) + return _ecore_psl1ght_init_count; + + ecore_event_shutdown(); + eina_log_domain_unregister(_ecore_psl1ght_log_dom); + _ecore_psl1ght_log_dom = -1; + + ECORE_PSL1GHT_EVENT_GOT_FOCUS = 0; + ECORE_PSL1GHT_EVENT_LOST_FOCUS = 0; + ECORE_PSL1GHT_EVENT_EXPOSE = 0; + ECORE_PSL1GHT_EVENT_KEY_MODIFIERS = 0; + ECORE_PSL1GHT_EVENT_QUIT = 0; + + ioPadEnd(); + ioMouseEnd(); + ioKbEnd(); + + if (move_context) + { + endMove (move_context); + move_context = NULL; + sysModuleUnload (SYSMODULE_CAMERA); + sysModuleUnload (SYSMODULE_GEM); + } + + sysUtilUnregisterCallback(SYSUTIL_EVENT_SLOT0); + + return _ecore_psl1ght_init_count; +} + +static unsigned int +_ecore_psl1ght_get_time(void) +{ + return (unsigned int)((unsigned long long) + (ecore_time_get() * 1000.0) & 0xffffffff); +} + +static unsigned int +_ecore_psl1ght_get_modifiers(void) +{ + unsigned int modifiers = 0; + + if (keyboard_mods._KbMkeyU._KbMkeyS.r_shift || + keyboard_mods._KbMkeyU._KbMkeyS.l_shift) + modifiers |= ECORE_EVENT_MODIFIER_SHIFT; + if (keyboard_mods._KbMkeyU._KbMkeyS.r_ctrl || + keyboard_mods._KbMkeyU._KbMkeyS.l_ctrl) + modifiers |= ECORE_EVENT_MODIFIER_CTRL; + if (keyboard_mods._KbMkeyU._KbMkeyS.r_alt || + keyboard_mods._KbMkeyU._KbMkeyS.l_alt) + modifiers |= ECORE_EVENT_MODIFIER_ALT; + if (keyboard_mods._KbMkeyU._KbMkeyS.r_win || + keyboard_mods._KbMkeyU._KbMkeyS.l_win) + modifiers |= ECORE_EVENT_MODIFIER_WIN; + + if (keyboard_leds._KbLedU._KbLedS.num_lock) + modifiers |= ECORE_EVENT_LOCK_NUM; + if (keyboard_leds._KbLedU._KbLedS.caps_lock) + modifiers |= ECORE_EVENT_LOCK_CAPS; + if (keyboard_leds._KbLedU._KbLedS.scroll_lock) + modifiers |= ECORE_EVENT_LOCK_SCROLL; + + return modifiers; +} + +static void +_ecore_psl1ght_key_modifiers(KbMkey *mods, KbLed *leds) +{ + Ecore_Psl1ght_Event_Key_Modifiers *ev; + Eina_Bool emit = EINA_FALSE; + + ev = malloc(sizeof(Ecore_Psl1ght_Event_Key_Modifiers)); + if (!ev) return; + + if (mods->_KbMkeyU._KbMkeyS.l_shift != + keyboard_mods._KbMkeyU._KbMkeyS.l_shift || + mods->_KbMkeyU._KbMkeyS.r_shift != + keyboard_mods._KbMkeyU._KbMkeyS.r_shift) + { + emit = EINA_TRUE; + ev->shift_changed = EINA_TRUE; + ev->shift = mods->_KbMkeyU._KbMkeyS.r_shift | + mods->_KbMkeyU._KbMkeyS.l_shift; + } + if (mods->_KbMkeyU._KbMkeyS.l_ctrl != + keyboard_mods._KbMkeyU._KbMkeyS.l_ctrl || + mods->_KbMkeyU._KbMkeyS.r_ctrl != + keyboard_mods._KbMkeyU._KbMkeyS.r_ctrl) + { + emit = EINA_TRUE; + ev->ctrl_changed = EINA_TRUE; + ev->ctrl = mods->_KbMkeyU._KbMkeyS.r_ctrl | + mods->_KbMkeyU._KbMkeyS.l_ctrl; + } + if (mods->_KbMkeyU._KbMkeyS.l_alt != + keyboard_mods._KbMkeyU._KbMkeyS.l_alt || + mods->_KbMkeyU._KbMkeyS.r_alt != + keyboard_mods._KbMkeyU._KbMkeyS.r_alt) + { + emit = EINA_TRUE; + ev->alt_changed = EINA_TRUE; + ev->alt = mods->_KbMkeyU._KbMkeyS.r_alt | + mods->_KbMkeyU._KbMkeyS.l_alt; + } + if (mods->_KbMkeyU._KbMkeyS.l_win != + keyboard_mods._KbMkeyU._KbMkeyS.l_win || + mods->_KbMkeyU._KbMkeyS.r_win != + keyboard_mods._KbMkeyU._KbMkeyS.r_win) + { + emit = EINA_TRUE; + ev->win_changed = EINA_TRUE; + ev->win = mods->_KbMkeyU._KbMkeyS.r_win | + mods->_KbMkeyU._KbMkeyS.l_win; + } + keyboard_mods = *mods; + + if (leds->_KbLedU._KbLedS.num_lock != + keyboard_leds._KbLedU._KbLedS.num_lock) + { + emit = EINA_TRUE; + ev->num_lock_changed = EINA_TRUE; + ev->num_lock = leds->_KbLedU._KbLedS.num_lock; + } + if (leds->_KbLedU._KbLedS.caps_lock != + keyboard_leds._KbLedU._KbLedS.caps_lock) + { + emit = EINA_TRUE; + ev->caps_lock_changed = EINA_TRUE; + ev->caps_lock = leds->_KbLedU._KbLedS.caps_lock; + } + if (leds->_KbLedU._KbLedS.scroll_lock != + keyboard_leds._KbLedU._KbLedS.scroll_lock) + { + emit = EINA_TRUE; + ev->scroll_lock_changed = EINA_TRUE; + ev->scroll_lock = leds->_KbLedU._KbLedS.scroll_lock; + } + keyboard_leds = *leds; + + if (emit) + { + ev->timestamp = _ecore_psl1ght_get_time (); + ev->modifiers = _ecore_psl1ght_get_modifiers(); + ecore_event_add(ECORE_PSL1GHT_EVENT_KEY_MODIFIERS, ev, NULL, NULL); + } + else + { + free(ev); + } +} + +static void +unicodeToUtf8(u16 w, char *utf8buf) +{ + unsigned char *utf8s = (unsigned char *)utf8buf; + + if ( w < 0x0080 ) + { + utf8s[0] = ( unsigned char )w; + utf8s[1] = 0; + } + else if ( w < 0x0800 ) + { + utf8s[0] = 0xc0 | ((w) >> 6); + utf8s[1] = 0x80 | ((w) & 0x3f); + utf8s[2] = 0; + } + else { + utf8s[0] = 0xe0 | ((w) >> 12); + utf8s[1] = 0x80 | (((w) >> 6) & 0x3f); + utf8s[2] = 0x80 | ((w) & 0x3f); + utf8s[3] = 0; + } +} + +static Ecore_Event_Key * +_ecore_psl1ght_event_key(u16 key) +{ + Ecore_Event_Key *ev; + char utf8[4]; + u16 utf16; + unsigned int i; + + ev = malloc(sizeof(Ecore_Event_Key)); + if (!ev) return NULL; + + ev->timestamp = _ecore_psl1ght_get_time (); + ev->window = 0; + ev->event_window = 0; + ev->modifiers = _ecore_psl1ght_get_modifiers(); + + key &= ~KB_KEYPAD; + for (i = 0; i < sizeof(keystable) / sizeof(struct _ecore_psl1ght_keys_s); ++i) + if (keystable[i].code == key) + { + ev->keyname = keystable[i].name; + ev->key = keystable[i].name; + ev->string = keystable[i].compose; + ev->compose = keystable[i].compose; + + return ev; + } + + utf16 = ioKbCnvRawCode (KB_MAPPING_101, keyboard_mods, keyboard_leds, key); + unicodeToUtf8(utf16, utf8); + ev->keyname = ev->key = ev->string = ev->compose = strdup (utf8); + + return ev; +} + +static void +_ecore_psl1ght_mouse_move(s32 x_axis, s32 y_axis) +{ + Ecore_Event_Mouse_Move *ev; + + ev = malloc(sizeof(Ecore_Event_Mouse_Move)); + if (!ev) return; + + mouse_x += x_axis; + mouse_y += y_axis; + if (mouse_x < 0) mouse_x = 0; + if (mouse_y < 0) mouse_y = 0; + if (mouse_x > window_width) mouse_x = window_width; + if (mouse_y > window_height) mouse_y = window_height; + + ev->window = 0; + ev->root_window = 0; + ev->event_window = 0; + ev->same_screen = 0; + ev->timestamp = _ecore_psl1ght_get_time (); + ev->modifiers = _ecore_psl1ght_get_modifiers (); + ev->x = ev->root.x = mouse_x; + ev->y = ev->root.x = mouse_y; + + ev->multi.device = 0; + ev->multi.radius = ev->multi.radius_x = ev->multi.radius_y = 0; + ev->multi.pressure = ev->multi.angle = 0; + ev->multi.x = ev->multi.y = ev->multi.root.x = ev->multi.root.y = 0; + + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, ev, NULL, NULL); +} + +static void +_ecore_psl1ght_mouse_button(int button, int pressed) +{ + Ecore_Event_Mouse_Button *ev; + static unsigned int previous_timestamp = 0; + + ev = malloc(sizeof(Ecore_Event_Mouse_Button)); + if (!ev) return; + + ev->window = 0; + ev->root_window = 0; + ev->event_window = 0; + ev->same_screen = 0; + ev->timestamp = _ecore_psl1ght_get_time (); + ev->modifiers = _ecore_psl1ght_get_modifiers (); + ev->buttons = button; + if (ev->timestamp - previous_timestamp <= 500) + ev->double_click = 1; + ev->triple_click = 0; + previous_timestamp = ev->timestamp; + + ev->x = ev->root.x = mouse_x; + ev->y = ev->root.y = mouse_y; + ev->multi.device = 0; + ev->multi.radius = ev->multi.radius_x = ev->multi.radius_y = 0; + ev->multi.pressure = ev->multi.angle = 0; + ev->multi.x = ev->multi.y = ev->multi.root.x = ev->multi.root.y = 0; + + if (pressed) + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, ev, NULL, NULL); + else + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, ev, NULL, NULL); +} + +static void +_ecore_psl1ght_mouse_wheel(s8 wheel, s8 tilt) +{ + Ecore_Event_Mouse_Wheel *ev; + + ev = malloc(sizeof(Ecore_Event_Mouse_Wheel)); + if (!ev) return; + + ev->timestamp = _ecore_psl1ght_get_time (); + ev->window = 0; + ev->event_window = 0; + ev->modifiers = _ecore_psl1ght_get_modifiers (); + ev->direction = 0; + ev->z = wheel; + + ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, ev, NULL, NULL); +} + +static void +_ecore_psl1ght_pad_button (const char *name, int pressed) +{ + Ecore_Event_Key *ev = NULL; + + ev = malloc(sizeof(Ecore_Event_Key)); + if (!ev) return; + + ev->timestamp = _ecore_psl1ght_get_time (); + ev->window = 0; + ev->event_window = 0; + ev->modifiers = 0; + + ev->keyname = name; + ev->key = name; + ev->string = ""; + ev->compose = ""; + + if (pressed) + ecore_event_add(ECORE_EVENT_KEY_DOWN, ev, NULL, NULL); + else + ecore_event_add(ECORE_EVENT_KEY_UP, ev, NULL, NULL); +} + +#define PAD_STICK_DEADZONE 0x20 + +static void +_ecore_psl1ght_poll_joypad(void) +{ + padInfo padinfo; + int i; + + /**/ + /* Check mouse events */ + ioPadGetInfo (&padinfo); + + for (i = 0; i < 4; i++) /* Ignore the move */ + { + if (padinfo.status[i]) + { + int analog_h, analog_v; + + if (ioPadGetData (i, &pad_data) != 0) + continue; + analog_h = pad_data.ANA_L_H - 0x80; + analog_v = pad_data.ANA_L_V - 0x80; + + if (analog_h > PAD_STICK_DEADZONE) + analog_h -= PAD_STICK_DEADZONE; + else if (analog_h < -PAD_STICK_DEADZONE) + analog_h += PAD_STICK_DEADZONE; + else + analog_h = 0; + analog_h /= 10; + + if (analog_v > PAD_STICK_DEADZONE) + analog_v -= PAD_STICK_DEADZONE; + else if (analog_v < -PAD_STICK_DEADZONE) + analog_v += PAD_STICK_DEADZONE; + else + analog_v = 0; + analog_v /= 10; + + if (analog_h != 0 || analog_v != 0) + _ecore_psl1ght_mouse_move (analog_h, analog_v); + + if (old_pad_data.BTN_CROSS ^ pad_data.BTN_CROSS) { + _ecore_psl1ght_pad_button ("Cross", pad_data.BTN_CROSS); + _ecore_psl1ght_mouse_button (1, pad_data.BTN_CROSS); + } + if (old_pad_data.BTN_CIRCLE ^ pad_data.BTN_CIRCLE) { + _ecore_psl1ght_pad_button ("Circle", pad_data.BTN_CIRCLE); + _ecore_psl1ght_mouse_button (3, pad_data.BTN_CIRCLE); + } + if (old_pad_data.BTN_SQUARE ^ pad_data.BTN_SQUARE) + _ecore_psl1ght_pad_button ("Square", pad_data.BTN_SQUARE); + if (old_pad_data.BTN_TRIANGLE ^ pad_data.BTN_TRIANGLE) + _ecore_psl1ght_pad_button ("Triangle", pad_data.BTN_TRIANGLE); + if (old_pad_data.BTN_UP ^ pad_data.BTN_UP) + _ecore_psl1ght_pad_button ("Up", pad_data.BTN_UP); + if (old_pad_data.BTN_DOWN ^ pad_data.BTN_DOWN) + _ecore_psl1ght_pad_button ("Down", pad_data.BTN_DOWN); + if (old_pad_data.BTN_LEFT ^ pad_data.BTN_LEFT) + _ecore_psl1ght_pad_button ("Left", pad_data.BTN_LEFT); + if (old_pad_data.BTN_RIGHT ^ pad_data.BTN_RIGHT) + _ecore_psl1ght_pad_button ("Right", pad_data.BTN_RIGHT); + if (old_pad_data.BTN_L1 ^ pad_data.BTN_L1) + _ecore_psl1ght_pad_button ("L1", pad_data.BTN_L1); + if (old_pad_data.BTN_L2 ^ pad_data.BTN_L2) + _ecore_psl1ght_pad_button ("L2", pad_data.BTN_L2); + if (old_pad_data.BTN_L3 ^ pad_data.BTN_L3) + _ecore_psl1ght_pad_button ("L3", pad_data.BTN_L3); + if (old_pad_data.BTN_R1 ^ pad_data.BTN_R1) + _ecore_psl1ght_pad_button ("R1", pad_data.BTN_R1); + if (old_pad_data.BTN_R2 ^ pad_data.BTN_R2) + _ecore_psl1ght_pad_button ("R2", pad_data.BTN_R2); + if (old_pad_data.BTN_R3 ^ pad_data.BTN_R3) + _ecore_psl1ght_pad_button ("R3", pad_data.BTN_R3); + if (old_pad_data.BTN_START ^ pad_data.BTN_START) + _ecore_psl1ght_pad_button ("Start", pad_data.BTN_START); + if (old_pad_data.BTN_SELECT ^ pad_data.BTN_SELECT) + _ecore_psl1ght_pad_button ("Select", pad_data.BTN_SELECT); + + old_pad_data = pad_data; + } + } +} + +static void +_ecore_psl1ght_poll_mouse(void) +{ + mouseInfo mouseinfo; + u32 i; + + /**/ + /* Check mouse events */ + ioMouseGetInfo(&mouseinfo); + + if (mouseinfo.status[0] == 1 && !mouse_connected) // Connected + { + mouse_connected = TRUE; + mouse_buttons = 0; + + // Old events in the queue are discarded + ioMouseClearBuf(0); + } + else if (mouseinfo.status[0] != 1 && mouse_connected) // Disconnected + { + mouse_connected = FALSE; + mouse_buttons = 0; + } + + if (mouse_connected) + { + mouseDataList datalist; + + ioMouseGetDataList(0, &datalist); + + for (i = 0; i < datalist.count; i++) + { + u8 old_left = mouse_buttons & 1; + u8 new_left = datalist.list[i].buttons & 1; + u8 old_right = mouse_buttons & 2; + u8 new_right = datalist.list[i].buttons & 2; + u8 old_middle = mouse_buttons & 4; + u8 new_middle = datalist.list[i].buttons & 4; + + if (datalist.list[i].x_axis != 0 || + datalist.list[i].y_axis != 0) + _ecore_psl1ght_mouse_move (datalist.list[i].x_axis, + datalist.list[i].y_axis); + + if (old_left != new_left) + _ecore_psl1ght_mouse_button (1, new_left); + if (old_middle != new_middle) + _ecore_psl1ght_mouse_button (2, new_middle); + if (old_right != new_right) + _ecore_psl1ght_mouse_button (3, new_right); + + if (datalist.list[i].wheel != 0) + _ecore_psl1ght_mouse_wheel (datalist.list[i].wheel, + datalist.list[i].tilt); + + mouse_buttons = datalist.list[i].buttons; + } + } +} + +static void +_ecore_psl1ght_poll_move(void) +{ + int i; + u16 new_buttons; + static int t_pressed = 0; + static int calibrated = 0; + static float prev_x = 0; + static float prev_y = 0; + static int gyro = 0; + float x, y, z; + + /* Check move events */ + processMove (move_context); + new_buttons = move_context->state.paddata.buttons & (~move_buttons); + move_buttons = move_context->state.paddata.buttons; + + moveGet3DPosition (move_context, &x, &y, &z); + //printf ("Move 3D position is : %f, %f, %f\n", x,y,z); + + switch (new_buttons) { + case 1: + gyro = !gyro; + break; + + case 4: + // Move button + //printf ("Calibrating\n"); + gemCalibrate (0); + calibrated = 1; + break; + + case 8: + // start button + _ecore_psl1ght_mouse_move ((window_width / 2) - mouse_x, (window_height / 2) - mouse_y); + break; + } + + if (calibrated) + { + float x_axis, y_axis; + + if (gyro) + { + gemInertialState gem_inert; + + gemGetInertialState (0, 0, 0, &gem_inert); + x_axis = -vec_array (gem_inert.gyro, 1) * 25; + y_axis = -vec_array (gem_inert.gyro, 0) * 25; + if (abs (x_axis) > 2 || abs (y_axis) > 2) + _ecore_psl1ght_mouse_move (x_axis, y_axis); + } + else { + x_axis = (x - prev_x) * 2.5; + y_axis = -(y - prev_y) * 2.5; + prev_x = x; + prev_y = y; + _ecore_psl1ght_mouse_move (x_axis, y_axis); + } + + if (!t_pressed && (move_buttons & 0x2)) + _ecore_psl1ght_mouse_button (1, 1); + else if (t_pressed && (move_buttons & 0x2) == 0) + _ecore_psl1ght_mouse_button (1, 0); + t_pressed = move_buttons & 0x2; + } +} + +static void +_ecore_psl1ght_poll_keyboard(void) +{ + KbInfo kbInfo; + int i; + + /* Check keyboard events */ + ioKbGetInfo(&kbInfo); + + if (kbInfo.status[0] == 1 && !keyboard_connected) + { + /* Connected */ + keyboard_connected = true; + + // Old events in the queue are discarded + ioKbClearBuf(0); + keyboard_leds._KbLedU.leds = 0; + keyboard_mods._KbMkeyU.mkeys = 0; + keyboard_old_key = 0; + + // Set raw keyboard code types to get scan codes + ioKbSetCodeType(0, KB_CODETYPE_RAW); + ioKbSetReadMode(0, KB_RMODE_INPUTCHAR); + } + else if (kbInfo.status[0] != 1 && keyboard_connected) + { + /* Disconnected keyboard */ + keyboard_connected = FALSE; + } + + if (keyboard_connected) + { + KbData Keys; + + // Read data from the keyboard buffer + if (ioKbRead(0, &Keys) == 0 && Keys.nb_keycode > 0) + { + Ecore_Event_Key *ev = NULL; + + _ecore_psl1ght_key_modifiers (&Keys.mkey, &Keys.led); + + if (Keys.nb_keycode == 0 && keyboard_old_key != 0) + { + ev = _ecore_psl1ght_event_key (keyboard_old_key); + if (ev) ecore_event_add(ECORE_EVENT_KEY_UP, ev, NULL, NULL); + } + for (i = 0; i < Keys.nb_keycode; i++) + { + if (Keys.keycode[i] != keyboard_old_key) + { + if (Keys.keycode[i] != 0) + { + ev = _ecore_psl1ght_event_key (Keys.keycode[i]); + if (ev) + ecore_event_add(ECORE_EVENT_KEY_DOWN, ev, + NULL, NULL); + } + else + { + ev = _ecore_psl1ght_event_key (keyboard_old_key); + if (ev) + ecore_event_add(ECORE_EVENT_KEY_UP, ev, + NULL, NULL); + } + keyboard_old_key = Keys.keycode[0]; + } + } + } + } +} + +static void +xmb_event_handler(u64 status, u64 param, void *user_data) +{ + //printf ("Received event %lX\n", status); + switch (status) { + case SYSUTIL_EXIT_GAME: + ecore_event_add(ECORE_PSL1GHT_EVENT_QUIT, NULL, NULL, NULL); + break; + case SYSUTIL_DRAW_BEGIN: + ecore_event_add(ECORE_PSL1GHT_EVENT_EXPOSE, NULL, NULL, NULL); + case SYSUTIL_MENU_OPEN: + ecore_event_add(ECORE_PSL1GHT_EVENT_LOST_FOCUS, NULL, NULL, NULL); + break; + case SYSUTIL_DRAW_END: + ecore_event_add(ECORE_PSL1GHT_EVENT_EXPOSE, NULL, NULL, NULL); + case SYSUTIL_MENU_CLOSE: + ecore_event_add(ECORE_PSL1GHT_EVENT_GOT_FOCUS, NULL, NULL, NULL); + break; + default: + break; + } +} + +EAPI void +ecore_psl1ght_poll_events(void) +{ + _ecore_psl1ght_poll_joypad (); + _ecore_psl1ght_poll_mouse (); + if (move_context) + _ecore_psl1ght_poll_move (); + _ecore_psl1ght_poll_keyboard (); + + sysUtilCheckCallback (); +} + +EAPI void +ecore_psl1ght_resolution_set(int width, int height) +{ + window_width = width; + window_height = height; + if (mouse_x > window_width) mouse_x = window_width; + if (mouse_y > window_height) mouse_y = window_height; +} + +EAPI void +ecore_psl1ght_screen_resolution_get(int *w, int *h) +{ + videoState state; + videoResolution resolution; + + /* Get the state of the display */ + if (videoGetState (0, 0, &state) == 0 && + videoGetResolution (state.displayMode.resolution, &resolution) == 0) + { + if (w) *w = resolution.width; + if (h) *h = resolution.height; + } + else { + if (w) *w = 0; + if (h) *h = 0; + } +} + +EAPI void +ecore_psl1ght_optimal_screen_resolution_get(int *w, int *h) +{ + videoDeviceInfo info; + videoResolution res; + int area = 720 * 480; + int mode_area; + int i; + + if (w) *w = 720; + if (h) *h = 480; + + videoGetDeviceInfo(0, 0, &info); + + for (i = 0; i < info.availableModeCount; i++) { + videoGetResolution (info.availableModes[i].resolution, &res); + mode_area = res.width * res.height; + if (mode_area > area) + { + area = mode_area; + if (w) *w = res.width; + if (h) *h = res.height; + } + } +} + diff --git a/src/lib/ecore_psl1ght/ecore_psl1ght_private.h b/src/lib/ecore_psl1ght/ecore_psl1ght_private.h new file mode 100644 index 0000000..bd5a86e --- /dev/null +++ b/src/lib/ecore_psl1ght/ecore_psl1ght_private.h @@ -0,0 +1,36 @@ +#ifndef _ECORE_PSL1GHT_PRIVATE_H +# define _ECORE_PSL1GHT_PRIVATE_H + +extern int _ecore_psl1ght_log_dom; + +# ifdef ECORE_PSL1GHT_DEFAULT_LOG_COLOR +# undef ECORE_PSL1GHT_DEFAULT_LOG_COLOR +# endif +# define ECORE_PSL1GHT_DEFAULT_LOG_COLOR EINA_COLOR_BLUE + +# ifdef ERR +# undef ERR +# endif +# define ERR(...) EINA_LOG_DOM_ERR(_ecore_psl1ght_log_dom, __VA_ARGS__) + +# ifdef DBG +# undef DBG +# endif +# define DBG(...) EINA_LOG_DOM_DBG(_ecore_psl1ght_log_dom, __VA_ARGS__) + +# ifdef INF +# undef INF +# endif +# define INF(...) EINA_LOG_DOM_INFO(_ecore_psl1ght_log_dom, __VA_ARGS__) + +# ifdef WRN +# undef WRN +# endif +# define WRN(...) EINA_LOG_DOM_WARN(_ecore_psl1ght_log_dom, __VA_ARGS__) + +# ifdef CRIT +# undef CRIT +# endif +# define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_psl1ght_log_dom, __VA_ARGS__) + +#endif diff --git a/src/lib/ecore_psl1ght/gemutil.c b/src/lib/ecore_psl1ght/gemutil.c new file mode 100644 index 0000000..9ccfc1c --- /dev/null +++ b/src/lib/ecore_psl1ght/gemutil.c @@ -0,0 +1,281 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SPURS_DEFAULT_PREFIX_NAME "gem_spurs" + +u16 oldGemPad = 0; +u16 newGemPad = 0; +u16 newGemAnalogT = 0; +extern cameraReadInfo camread; + +static inline float +vec_array(vec_float4 vec, unsigned int idx) +{ + union { + vec_float4 vec; + float array[4]; + } v; + + v.vec = vec; + + if (idx > 3) + return -1; + return v.array[idx]; +} + +int +initMove() +{ + Spurs *spurs; + gemAttribute gem_attr; + u8 gem_spu_priorities[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; + int ret; + int i; + + spurs = initSpurs (NULL); + + if (spurs == NULL) + goto error; + + printf ("preparing GemAttribute structure with spurs\n"); + + initAttributeGem (&gem_attr, 1, NULL, spurs, gem_spu_priorities); + gem_attr->version = 2; + gem_attr->max = 1; + gem_attr->spurs = spurs; + gem_attr->memory = NULL; + gem_attr->spu_priorities[0] = 1; + for (i = 1; i < 8; ++i) + gem_attr->spu_priorities[i] = 0; + + printf ("calling GemInit with GemAttribute structure version=%d max_connect=%d spurs=%X\n", + gem_attr.version, gem_attr.max, gem_attr.spurs); + ret = gemInit (&gem_attr); + printf ("return from GemInit %X \n", ret); + if (ret) + goto error; + + ret = gemPrepareCamera (128, 0.5); + printf ("GemPrepareCamera return %d exposure set to 128 and quality to 0.5\n", + ret); + if (ret) + goto error; + ret = gemReset (0); + printf ("GemReset return %X \n", ret); + if (ret) + goto error; + return ret; + +error: + if (spurs) + endSpurs (spurs); + return NULL; +} + +int +endMove() +{ + endSpurs (spurs); + gemEnd (); + return 0; +} + +int +proccessGem(int t) +{ + int ret; + + switch (t) { + case 0: + + ret = gemUpdateStart (camread.buffer, camread.timestamp); + + if (ret != 0) + { + printf ("Return from gemUpdateStart %X\n", ret); + } + break; + + case 2: + + ret = gemUpdateFinish (); + if (ret != 0) + { + printf ("Return from gemUpdateFinish %X\n", ret); + } + break; + + case 3: + ret = gemConvertVideoFinish (); + if (ret != 0) + { + printf ("Return from gemConvertVideoFinish %X\n", ret); + } + break; + + default: + ret = -1; + break; + } + return ret; +} + +void +readGemPad(int num_gem) +{ + gemState gem_state; + int ret; + unsigned int hues[] = { 4 << 24, 4 << 24, 4 << 24, 4 << 24 }; + ret = gemGetState (0, 0, -22000, &gem_state); + + newGemPad = gem_state.paddata.buttons & (~oldGemPad); + newGemAnalogT = gem_state.paddata.ANA_T; + oldGemPad = gem_state.paddata.buttons; + + switch (ret) { + case 2: + gemForceRGB (num_gem, 0.5, 0.5, 0.5); + break; + + case 5: + + gemTrackHues (hues, NULL); + break; + + default: + break; + } +} + +void +readGemAccPosition(int num_gem) +{ + vec_float4 position; + + gemGetAccelerometerPositionInDevice (num_gem, &position); + + printf (" accelerometer device coordinates [%f,%f,%f,%f]\n", + vec_array (position, 0), vec_array (position, 1), vec_array (position, 2), + vec_array (position, 3)); +} + +void +readGemInertial(int num_gem) +{ + gemInertialState gem_inertial_state; + int ret; + + ret = gemGetInertialState (num_gem, 0, -22000, &gem_inertial_state); + printf ("gemGetInertialState return %X\n", ret); + printf ("counter %d temperature %f\n", gem_inertial_state.counter, + gem_inertial_state.temperature); + + printf (" accelerometer sensor [%f,%f,%f,%f]\n", + vec_array (gem_inertial_state.accelerometer, 0), + vec_array (gem_inertial_state.accelerometer, 1), + vec_array (gem_inertial_state.accelerometer, 2), + vec_array (gem_inertial_state.accelerometer, 3)); + + printf (" accelerometer_bias sensor [%f,%f,%f,%f]\n", + vec_array (gem_inertial_state.accelerometer_bias, 0), + vec_array (gem_inertial_state.accelerometer_bias, 1), + vec_array (gem_inertial_state.accelerometer_bias, 2), + vec_array (gem_inertial_state.accelerometer_bias, 3)); + + printf (" gyro sensor [%f,%f,%f,%f]\n", vec_array (gem_inertial_state.gyro, + 0), vec_array (gem_inertial_state.gyro, 1), + vec_array (gem_inertial_state.gyro, 2), + vec_array (gem_inertial_state.gyro, 3)); + + printf (" gyro_bias sensor [%f,%f,%f,%f]\n", + vec_array (gem_inertial_state.gyro_bias, 0), + vec_array (gem_inertial_state.gyro_bias, 1), + vec_array (gem_inertial_state.gyro_bias, 2), + vec_array (gem_inertial_state.gyro_bias, 3)); +} + +void +readGem() +{ + gemState gem_state; + proccessGem (0); + + proccessGem (2); + + readGemPad (0); // This will read buttons from Move + switch (newGemPad) { + case 1: + printf ("Select pressed \n"); + break; + + case 2: + printf ("T pressed value %d\n", newGemAnalogT); + printf + ("Frame %d center of the sphere in world coordinates %f %f %f %f \n", + camread.frame, vec_array (gem_state.pos, 0), vec_array (gem_state.pos, + 1), vec_array (gem_state.pos, 2), vec_array (gem_state.pos, 3)); + break; + + case 4: + printf ("Move pressed \n"); + gemCalibrate (0); + break; + + case 8: + printf ("Start pressed \n"); + pos_x = 0; + pos_y = 0; + break; + + case 16: + printf ("Triangle pressed \n"); + getImageState (); + break; + + case 32: + printf ("Circle pressed \n"); + break; + + case 64: + printf ("Cross pressed \n"); + printf ("X,Y,Z position (mm) %f %f %f\n", vec_array (gem_state.pos, 0), + vec_array (gem_state.pos, 1), vec_array (gem_state.pos, 2)); + readGemAccPosition (0); + break; + + case 128: + printf ("Square pressed \n"); + readGemInertial (0); + break; + + default: + break; + } +} + +void +getImageState() +{ + int ret; + + gemImageState imgState; + + gemGetImageState (0, &imgState); + printf (" u [%f]\n", imgState.u); + printf (" v [%f]\n", imgState.v); + printf (" r [%f]\n", imgState.r); + printf (" projectionx [%f]\n", imgState.projectionx); + printf (" projectiony [%f]\n", imgState.projectiony); + printf (" distance [%f]\n", imgState.distance); + printf ("visible=%d r_valid=%d\n", imgState.visible, imgState.r_valid); + printf ("tiemestamp=%Ld\n", imgState.frame_time); +} + diff --git a/src/lib/ecore_psl1ght/gemutil.h b/src/lib/ecore_psl1ght/gemutil.h new file mode 100644 index 0000000..ce4b544 --- /dev/null +++ b/src/lib/ecore_psl1ght/gemutil.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) Antonio José Ramos Márquez (bigboss) + * Copyright (C) Youness Alaoui (KaKaRoTo) + */ + +#ifndef __GEMUTIL_H__ +#define __GEMUTIL_H__ + +#include +#include +#include +#include + +typedef struct +{ + Spurs *spurs; +} moveContext; + +#endif /* __GEMUTIL_H__ */ diff --git a/src/lib/ecore_psl1ght/moveutil.c b/src/lib/ecore_psl1ght/moveutil.c new file mode 100644 index 0000000..1dadfbc --- /dev/null +++ b/src/lib/ecore_psl1ght/moveutil.c @@ -0,0 +1,245 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "spursutil.h" +#include "moveutil.h" + +u16 oldGemPad = 0; +u16 newGemPad = 0; +u16 newGemAnalogT = 0; + +static void +endCamera(moveContext *context) +{ + cameraStop (0); + + cameraClose (0); + cameraEnd (); + + sysMemContainerDestroy (context->camInfo.container); +} + +static int +initCamera(moveContext *context) +{ + int ret; + + context->camInfo.container = NULL; + + ret = cameraInit (); + printf ("cameraInit() returned %d\n", ret); + if (ret == 0) + { + cameraType type = CAM_TYPE_UNKNOWN; + + ret = cameraGetType (0, &type); + if (ret == 0 && type == CAM_TYPE_PLAYSTATION_EYE) + { + context->camInfo.format = CAM_FORM_RAW8; + context->camInfo.framerate = 60; + context->camInfo.resolution = CAM_RESO_VGA; + context->camInfo.info_ver = 0x0101; + ret = sysMemContainerCreate (&context->camInfo.container, 0x200000); + printf ("sysMemContainerCreate() for camera container returned %d\n", ret); + + ret = cameraOpenEx (0, &context->camInfo); + switch (ret) { + case 0: + printf ("Found me an eye, arrr!\n"); + printf ("cameraOpenEx returned %08X\n", ret); + printf ("Video dimensions: %dx%d\n", context->camInfo.width, context->camInfo.height); + printf ("Buffer at %08X\n", context->camInfo.buffer); + printf ("pbuf0 Buffer at %08X\n", context->camInfo.pbuf[0]); + printf ("pbuf0 Buffer at %08X\n", context->camInfo.pbuf[1]); + printf ("context->camInfo.info_ver %X\n", context->camInfo.info_ver); + + context->camRead.buffer = context->camInfo.buffer; + context->camRead.version = 0x0100; + printf ("Setting CameraReadEx %08X buffer to cameraInfoex buffer \n", + context->camRead.buffer); + break; + + default: + printf ("Error %X detected opening PlayStation Eye\n", ret); + goto error; + } + } + else { + printf ("Device detected is not a PlayStation Eye and this sample need it\n"); + goto error; + } + } + else { + goto error; + } + return ret; + +error: + if (context->camInfo.container) + sysMemContainerDestroy (context->camInfo.container); + return ret; +} + +static int +readCamera(moveContext *context) +{ + int ret; + + ret = cameraReadEx (0, &context->camRead); + switch (ret) { + case CAMERA_ERRO_NEED_START: + cameraReset (0); + ret = gemPrepareCamera (128, 0.5); + printf ("GemPrepareCamera return %d exposure set to 128 and quality to 0.5 before cameraStart\n", + ret); + printf ("lets go!! It's time to look your face in Sony Bravia :P\n"); + ret = cameraStart (0); + printf ("cameraStart return %d \n", ret); + printf ("*******************************************\n"); + printf ("* Now make sure you have a Move connected\n"); + printf ("* and point it towards the camera and press\n"); + printf ("* the action button to calibrate\n"); + printf ("*******************************************\n"); + break; + + case 0: + break; + + default: + printf ("error %08X ", ret); + ret = 1; + break; + } + // printf("despues de start return %d \n",ret); + if (ret == 0 && context->camRead.readcount != 0) + { + return context->camRead.readcount; + } + else { + return 0; + } +} + +moveContext * +initMove() +{ + moveContext *context = NULL; + Spurs *spurs; + gemAttribute gem_attr; + int ret; + int i; + + spurs = initSpurs ("gem_spurs"); + + if (spurs == NULL) + goto error; + + printf ("preparing GemAttribute structure with spurs\n"); + + gem_attr.version = 2; + gem_attr.max = 1; + gem_attr.spurs = spurs; + gem_attr.memory = NULL; + gem_attr.spu_priorities[0] = 1; + for (i = 1; i < 8; ++i) + gem_attr.spu_priorities[i] = 0; + + printf ("calling GemInit with GemAttribute structure version=%d max_connect=%d spurs=%X\n", + gem_attr.version, gem_attr.max, gem_attr.spurs); + ret = gemInit (&gem_attr); + printf ("return from GemInit %X \n", ret); + if (ret) + goto error; + + ret = gemPrepareCamera (128, 0.5); + printf ("GemPrepareCamera return %d exposure set to 128 and quality to 0.5\n", + ret); + if (ret) + goto error; + ret = gemReset (0); + printf ("GemReset return %X \n", ret); + if (ret) + goto error; + + context = (moveContext *)malloc (sizeof (moveContext)); + context->spurs = spurs; + ret = initCamera (context); + + if (ret == 0) + return context; + +error: + if (spurs) + endSpurs (spurs); + if (context) + free (context); + return NULL; +} + +void +endMove(moveContext *context) +{ + /* Stop Move */ + gemEnd (); + /* Stop Camera */ + endCamera (context); + /* Stop Spurs */ + endSpurs (context->spurs); + + free (context); +} + +int +processMove(moveContext *context) +{ + const unsigned int hues[] = { 4 << 24, 4 << 24, 4 << 24, 4 << 24 }; + int ret = -1; + + if (readCamera (context) > 0) + { + ret = gemUpdateStart (context->camRead.buffer, context->camRead.timestamp); + //printf ("Return from gemUpdateStart %X\n", ret); + if (ret == 0) + { + ret = gemUpdateFinish (); + //printf ("Return from gemUpdateFinish %X\n", ret); + if (ret == 0) + { + ret = gemGetState (0, STATE_LATEST_IMAGE_TIME, 0, &context->state); + switch (ret) { + case 2: + gemForceRGB (0, 0.5, 0.5, 0.5); + break; + + case 5: + gemTrackHues (hues, NULL); + break; + + default: + break; + } + } + } + } + + return ret; +} + +void +moveGet3DPosition(moveContext *context, float *x, float *y, float *z) +{ + if (x) + *x = vec_array (context->state.pos, 0); + if (y) + *y = vec_array (context->state.pos, 1); + if (z) + *z = vec_array (context->state.pos, 2); +} + diff --git a/src/lib/ecore_psl1ght/moveutil.h b/src/lib/ecore_psl1ght/moveutil.h new file mode 100644 index 0000000..bb4b22c --- /dev/null +++ b/src/lib/ecore_psl1ght/moveutil.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) Antonio José Ramos Márquez (bigboss) + * Copyright (C) Youness Alaoui (KaKaRoTo) + */ + +#ifndef __MOVEUTIL_H__ +#define __MOVEUTIL_H__ + +#include +#include +#include +#include + +typedef struct +{ + Spurs *spurs; + cameraInfoEx camInfo; + cameraReadInfo camRead; + gemState state; +} moveContext; + +static inline float +vec_array(vec_float4 vec, unsigned int idx) +{ + union { + vec_float4 vec; + float array[4]; + } v; + + v.vec = vec; + + if (idx > 3) + return -1; + return v.array[idx]; +} + +moveContext *initMove(); +void endMove(moveContext *context); +void readGemState(moveContext *context); +int processMove(moveContext *context); +void moveGet3DPosition(moveContext *context, float *x, float *y, float *z); + +#endif /* __MOVEUTIL_H__ */ diff --git a/src/lib/ecore_psl1ght/spursutil.c b/src/lib/ecore_psl1ght/spursutil.c new file mode 100644 index 0000000..27b5c1d --- /dev/null +++ b/src/lib/ecore_psl1ght/spursutil.c @@ -0,0 +1,62 @@ +#include "spursutil.h" +#include + +#define SPURS_DEFAULT_PREFIX_NAME "spursutil" + +Spurs * +initSpurs(const char *prefix_name) +{ + Spurs *spurs = NULL; + SpursAttribute attributeSpurs; + int ret; + int i; + + ret = sysSpuInitialize (6, 0); + printf ("sysSpuInitialize return %d\n", ret); + + /* initialize spurs */ + printf ("Initializing spurs\n"); + spurs = (void *)memalign (SPURS_ALIGN, sizeof (Spurs)); + printf ("Initializing spurs attribute\n"); + + ret = spursAttributeInitialize (&attributeSpurs, 5, 250, 1000, true); + if (ret) + { + printf ("error : spursAttributeInitialize failed %x\n", ret); + goto error; + } + + printf ("Setting name prefix\n"); + if (!prefix_name) + prefix_name = SPURS_DEFAULT_PREFIX_NAME; + ret = spursAttributeSetNamePrefix (&attributeSpurs, + prefix_name, strlen (prefix_name)); + if (ret) + { + printf ("error : spursAttributeInitialize failed %x\n", ret); + goto error; + } + + printf ("Initializing with attribute\n"); + ret = spursInitializeWithAttribute (spurs, &attributeSpurs); + if (ret) + { + printf ("error: spursInitializeWithAttribute failed %x\n", ret); + goto error; + } + + return spurs; + +error: + if (spurs) + free (spurs); + return NULL; +} + +void +endSpurs(Spurs *spurs) +{ + spursFinalize (spurs); + free (spurs); +} + diff --git a/src/lib/ecore_psl1ght/spursutil.h b/src/lib/ecore_psl1ght/spursutil.h new file mode 100644 index 0000000..0b35030 --- /dev/null +++ b/src/lib/ecore_psl1ght/spursutil.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) Antonio José Ramos Márquez (bigboss) + * Copyright (C) Youness Alaoui (KaKaRoTo) + */ + +#ifndef __SPURSUTIL_H__ +#define __SPURSUTIL_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initialize spurs with a given name prefix (*/ +Spurs *initSpurs(const char *prefix_name); +void endSpurs(Spurs *spurs); + +#ifdef __cplusplus +} +#endif + +#endif /* __SPURSUTIL_H__ */ diff --git a/src/lib/ecore_sdl/Ecore_Sdl.h b/src/lib/ecore_sdl/Ecore_Sdl.h new file mode 100644 index 0000000..359e974 --- /dev/null +++ b/src/lib/ecore_sdl/Ecore_Sdl.h @@ -0,0 +1,114 @@ +#ifndef _ECORE_SDL_H +#define _ECORE_SDL_H + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_ECORE_SDL_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_ECORE_SDL_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +/** + * @file + * @brief Ecore SDL system functions. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +EAPI extern int ECORE_SDL_EVENT_GOT_FOCUS; +EAPI extern int ECORE_SDL_EVENT_LOST_FOCUS; +EAPI extern int ECORE_SDL_EVENT_RESIZE; +EAPI extern int ECORE_SDL_EVENT_EXPOSE; + +typedef struct _Ecore_Sdl_Event_Key_Down Ecore_Sdl_Event_Key_Down; +struct _Ecore_Sdl_Event_Key_Down /** SDL Key Down event */ +{ + const char *keyname; /**< The name of the key that was pressed */ + const char *keycompose; /**< The UTF-8 string conversion if any */ + unsigned int time; +}; + +typedef struct _Ecore_Sdl_Event_Key_Up Ecore_Sdl_Event_Key_Up; +struct _Ecore_Sdl_Event_Key_Up /** SDL Key Up event */ +{ + const char *keyname; /**< The name of the key that was released */ + const char *keycompose; /**< The UTF-8 string conversion if any */ + unsigned int time; +}; + +typedef struct _Ecore_Sdl_Event_Mouse_Button_Down Ecore_Sdl_Event_Mouse_Button_Down; +struct _Ecore_Sdl_Event_Mouse_Button_Down /** SDL Mouse Down event */ +{ + int button; /**< Mouse button that was pressed (1 - 32) */ + int x; /**< Mouse co-ordinates when mouse button was pressed */ + int y; /**< Mouse co-ordinates when mouse button was pressed */ + int double_click : 1; /**< Set if click was a double click */ + int triple_click : 1; /**< Set if click was a triple click */ + unsigned int time; +}; + +typedef struct _Ecore_Sdl_Event_Mouse_Button_Up Ecore_Sdl_Event_Mouse_Button_Up; +struct _Ecore_Sdl_Event_Mouse_Button_Up /** SDL Mouse Up event */ +{ + int button; /**< Mouse button that was released (1 - 32) */ + int x; /**< Mouse co-ordinates when mouse button was raised */ + int y; /**< Mouse co-ordinates when mouse button was raised */ + int double_click : 1; /**< Set if click was a double click */ + int triple_click : 1; /**< Set if click was a triple click */ + unsigned int time; +}; + +typedef struct _Ecore_Sdl_Event_Mouse_Move Ecore_Sdl_Event_Mouse_Move; +struct _Ecore_Sdl_Event_Mouse_Move /** SDL Mouse Move event */ +{ + int x; /**< Mouse co-ordinates where the mouse cursor moved to */ + int y; /**< Mouse co-ordinates where the mouse cursor moved to */ + unsigned int time; +}; + +typedef struct _Ecore_Sdl_Event_Mouse_Wheel Ecore_Sdl_Event_Mouse_Wheel; +struct _Ecore_Sdl_Event_Mouse_Wheel /** SDL Mouse Wheel event */ +{ + int x,y; + int direction; /* 0 = vertical, 1 = horizontal */ + int wheel; /* value 1 (left/up), -1 (right/down) */ + unsigned int time; +}; + +typedef struct _Ecore_Sdl_Event_Video_Resize Ecore_Sdl_Event_Video_Resize; +struct _Ecore_Sdl_Event_Video_Resize +{ + int w; + int h; +}; + +EAPI int ecore_sdl_init(const char *name); +EAPI int ecore_sdl_shutdown(void); +EAPI void ecore_sdl_feed_events(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/ecore_sdl/Ecore_Sdl_Keys.h b/src/lib/ecore_sdl/Ecore_Sdl_Keys.h new file mode 100644 index 0000000..4d0b60b --- /dev/null +++ b/src/lib/ecore_sdl/Ecore_Sdl_Keys.h @@ -0,0 +1,266 @@ +#ifndef ECORE_SDL_KEYS_H__ +# define ECORE_SDL_KEYS_H__ + +struct _ecore_sdl_keys_s +{ + int code; + const char* name; + const char* compose; +}; + +static const struct _ecore_sdl_keys_s keystable[] = +{ + { SDLK_UNKNOWN, "0x00", "" }, +#ifndef BUILD_ECORE_EVAS_SDL_130 + { SDLK_FIRST, "First", "First" }, +#endif + { SDLK_BACKSPACE, "BackSpace", "\010" }, + { SDLK_TAB, "Tab", "\011" }, + { SDLK_CLEAR, "Clear", "Clear" }, + { SDLK_RETURN, "Return", "\015" }, + { SDLK_PAUSE, "Pause", "Pause" }, + { SDLK_ESCAPE, "Escape", "\033" }, + { SDLK_SPACE, "space", " " }, + { SDLK_EXCLAIM, "exclam", "!" }, + { SDLK_QUOTEDBL, "quotedbl", "\"" }, + { SDLK_HASH, "numbersign", "#" }, + { SDLK_DOLLAR, "dollar", "$" }, + { SDLK_AMPERSAND, "ampersand", "&" }, + { SDLK_QUOTE, "apostrophe", "'" }, + { SDLK_LEFTPAREN, "parenleft", "(" }, + { SDLK_RIGHTPAREN, "parenright", ")" }, + { SDLK_ASTERISK, "asterisk", "*" }, + { SDLK_PLUS, "plus", "+" }, + { SDLK_COMMA, "comma", "," }, + { SDLK_MINUS, "minus", "-" }, + { SDLK_PERIOD, "period", "." }, + { SDLK_SLASH, "slash", "/" }, + { SDLK_0, "0", "0" }, + { SDLK_1, "1", "1" }, + { SDLK_2, "2", "2" }, + { SDLK_3, "3", "3" }, + { SDLK_4, "4", "4" }, + { SDLK_5, "5", "5" }, + { SDLK_6, "6", "6" }, + { SDLK_7, "7", "7" }, + { SDLK_8, "8", "8" }, + { SDLK_9, "9", "9" }, + { SDLK_COLON, "colon", ":" }, + { SDLK_SEMICOLON, "semicolon", ";" }, + { SDLK_LESS, "less", "<" }, + { SDLK_EQUALS, "equal", "=" }, + { SDLK_GREATER, "greater", ">" }, + { SDLK_QUESTION, "question", "?" }, + { SDLK_AT, "at", "@" }, + + /* Skip uppercase letters */ + { SDLK_LEFTBRACKET, "bracketleft", "[" }, + { SDLK_BACKSLASH, "backslash", "\\" }, + { SDLK_RIGHTBRACKET, "bracketright", "]" }, + { SDLK_CARET, "asciicircumm", "^" }, + { SDLK_UNDERSCORE, "underscore", "_" }, + { SDLK_BACKQUOTE, "asciitilde", "`" }, + { SDLK_a, "a", "a" }, + { SDLK_b, "b", "b" }, + { SDLK_c, "c", "c" }, + { SDLK_d, "d", "d" }, + { SDLK_e, "e", "e" }, + { SDLK_f, "f", "f" }, + { SDLK_g, "g", "g" }, + { SDLK_h, "h", "h" }, + { SDLK_i, "i", "i" }, + { SDLK_j, "j", "j" }, + { SDLK_k, "k", "k" }, + { SDLK_l, "l", "l" }, + { SDLK_m, "m", "m" }, + { SDLK_n, "n", "n" }, + { SDLK_o, "o", "o" }, + { SDLK_p, "p", "p" }, + { SDLK_q, "q", "q" }, + { SDLK_r, "r", "r" }, + { SDLK_s, "s", "s" }, + { SDLK_t, "t", "t" }, + { SDLK_u, "u", "u" }, + { SDLK_v, "v", "v" }, + { SDLK_w, "w", "w" }, + { SDLK_x, "x", "x" }, + { SDLK_y, "y", "y" }, + { SDLK_z, "z", "z" }, + { SDLK_DELETE, "Delete", "\177" }, + /* End of ASCII mapped keysyms */ + +#ifndef BUILD_ECORE_EVAS_SDL_130 + /* International keyboard syms */ + { SDLK_WORLD_0, "w0", "" }, /* 0xA0 */ + { SDLK_WORLD_1, "w1", "" }, + { SDLK_WORLD_2, "w2", "" }, + { SDLK_WORLD_3, "w3", "" }, + { SDLK_WORLD_4, "w4", "" }, + { SDLK_WORLD_5, "w5", "" }, + { SDLK_WORLD_6, "w6", "" }, + { SDLK_WORLD_7, "w7", "" }, + { SDLK_WORLD_8, "w8", "" }, + { SDLK_WORLD_9, "w9", "" }, + { SDLK_WORLD_10, "w10", "" }, + { SDLK_WORLD_11, "w11", "" }, + { SDLK_WORLD_12, "w12", "" }, + { SDLK_WORLD_13, "w13", "" }, + { SDLK_WORLD_14, "w14", "" }, + { SDLK_WORLD_15, "w15", "" }, + { SDLK_WORLD_16, "w16", "" }, + { SDLK_WORLD_17, "w17", "" }, + { SDLK_WORLD_18, "w18", "" }, + { SDLK_WORLD_19, "w19", "" }, + { SDLK_WORLD_20, "w20", "" }, + { SDLK_WORLD_21, "w21", "" }, + { SDLK_WORLD_22, "w22", "" }, + { SDLK_WORLD_23, "w23", "" }, + { SDLK_WORLD_24, "w24", "" }, + { SDLK_WORLD_25, "w25", "" }, + { SDLK_WORLD_26, "w26", "" }, + { SDLK_WORLD_27, "w27", "" }, + { SDLK_WORLD_28, "w28", "" }, + { SDLK_WORLD_29, "w29", "" }, + { SDLK_WORLD_30, "w30", "" }, + { SDLK_WORLD_31, "w31", "" }, + { SDLK_WORLD_32, "w32", "" }, + { SDLK_WORLD_33, "w33", "" }, + { SDLK_WORLD_34, "w34", "" }, + { SDLK_WORLD_35, "w35", "" }, + { SDLK_WORLD_36, "w36", "" }, + { SDLK_WORLD_37, "w37", "" }, + { SDLK_WORLD_38, "w38", "" }, + { SDLK_WORLD_39, "w39", "" }, + { SDLK_WORLD_40, "w40", "" }, + { SDLK_WORLD_41, "w41", "" }, + { SDLK_WORLD_42, "w42", "" }, + { SDLK_WORLD_43, "w43", "" }, + { SDLK_WORLD_44, "w44", "" }, + { SDLK_WORLD_45, "w45", "" }, + { SDLK_WORLD_46, "w46", "" }, + { SDLK_WORLD_47, "w47", "" }, + { SDLK_WORLD_48, "w48", "" }, + { SDLK_WORLD_49, "w49", "" }, + { SDLK_WORLD_50, "w50", "" }, + { SDLK_WORLD_51, "w51", "" }, + { SDLK_WORLD_52, "w52", "" }, + { SDLK_WORLD_53, "w53", "" }, + { SDLK_WORLD_54, "w54", "" }, + { SDLK_WORLD_55, "w55", "" }, + { SDLK_WORLD_56, "w56", "" }, + { SDLK_WORLD_57, "w57", "" }, + { SDLK_WORLD_58, "w58", "" }, + { SDLK_WORLD_59, "w59", "" }, + { SDLK_WORLD_60, "w60", "" }, + { SDLK_WORLD_61, "w61", "" }, + { SDLK_WORLD_62, "w62", "" }, + { SDLK_WORLD_63, "w63", "" }, + { SDLK_WORLD_64, "w64", "" }, + { SDLK_WORLD_65, "w65", "" }, + { SDLK_WORLD_66, "w66", "" }, + { SDLK_WORLD_67, "w67", "" }, + { SDLK_WORLD_68, "w68", "" }, + { SDLK_WORLD_69, "w69", "" }, + { SDLK_WORLD_70, "w70", "" }, + { SDLK_WORLD_71, "w71", "" }, + { SDLK_WORLD_72, "w72", "" }, + { SDLK_WORLD_73, "w73", "" }, + { SDLK_WORLD_74, "w74", "" }, + { SDLK_WORLD_75, "w75", "" }, + { SDLK_WORLD_76, "w76", "" }, + { SDLK_WORLD_77, "w77", "" }, + { SDLK_WORLD_78, "w78", "" }, + { SDLK_WORLD_79, "w79", "" }, + { SDLK_WORLD_80, "w80", "" }, + { SDLK_WORLD_81, "w81", "" }, + { SDLK_WORLD_82, "w82", "" }, + { SDLK_WORLD_83, "w83", "" }, + { SDLK_WORLD_84, "w84", "" }, + { SDLK_WORLD_85, "w85", "" }, + { SDLK_WORLD_86, "w86", "" }, + { SDLK_WORLD_87, "w87", "" }, + { SDLK_WORLD_88, "w88", "" }, + { SDLK_WORLD_89, "w89", "" }, + { SDLK_WORLD_90, "w90", "" }, + { SDLK_WORLD_91, "w91", "" }, + { SDLK_WORLD_92, "w92", "" }, + { SDLK_WORLD_93, "w93", "" }, + { SDLK_WORLD_94, "w94", "" }, + { SDLK_WORLD_95, "w95", "" }, +#endif + /* Numeric keypad */ + { SDLK_KP0, "KP0", "0" }, + { SDLK_KP1, "KP1", "1" }, + { SDLK_KP2, "KP2", "2" }, + { SDLK_KP3, "KP3", "3" }, + { SDLK_KP4, "KP4", "4" }, + { SDLK_KP5, "KP5", "5" }, + { SDLK_KP6, "KP6", "6" }, + { SDLK_KP7, "KP7", "7" }, + { SDLK_KP8, "KP8", "8" }, + { SDLK_KP9, "KP9", "9" }, + { SDLK_KP_PERIOD, "period", "." }, + { SDLK_KP_DIVIDE, "KP_Divide", "/" }, + { SDLK_KP_MULTIPLY, "KP_Multiply", "*" }, + { SDLK_KP_MINUS, "KP_Minus", "-" }, + { SDLK_KP_PLUS, "KP_Plus", "+" }, + { SDLK_KP_ENTER, "KP_Enter", "\015" }, + { SDLK_KP_EQUALS, "KP_Equals", "=" }, + + /* Arrows + Home/End pad */ + { SDLK_UP, "Up", "Up" }, + { SDLK_DOWN, "Down", "Down" }, + { SDLK_RIGHT, "Right", "Right" }, + { SDLK_LEFT, "Left", "Left" }, + { SDLK_INSERT, "Insert", "Insert" }, + { SDLK_HOME, "Home", "Home" }, + { SDLK_END, "End", "End" }, + { SDLK_PAGEUP, "Page_Up", "Page_Up" }, + { SDLK_PAGEDOWN, "Page_Down", "Page_Down" }, + + /* Function keys */ + { SDLK_F1, "F1", "F1" }, + { SDLK_F2, "F2", "F2" }, + { SDLK_F3, "F3", "F3" }, + { SDLK_F4, "F4", "F4" }, + { SDLK_F5, "F5", "F5" }, + { SDLK_F6, "F6", "F6" }, + { SDLK_F7, "F7", "F7" }, + { SDLK_F8, "F8", "F8" }, + { SDLK_F9, "F9", "F9" }, + { SDLK_F10, "F10", "F10" }, + { SDLK_F11, "F11", "F11" }, + { SDLK_F12, "F12", "F12" }, + { SDLK_F13, "F13", "F13" }, + { SDLK_F14, "F14", "F14" }, + { SDLK_F15, "F15", "F15" }, + + /* Key state modifier keys */ + { SDLK_NUMLOCK, "Num_Lock", "Num_Lock" }, + { SDLK_CAPSLOCK, "Caps_Lock", "Caps_Lock" }, + { SDLK_SCROLLOCK, "Scroll_Lock", "Scroll_Lock" }, + { SDLK_RSHIFT, "Shift_R", "Shift_R" }, + { SDLK_LSHIFT, "Shift_L", "Shift_L" }, + { SDLK_RCTRL, "Control_R", "Control_R" }, + { SDLK_LCTRL, "Control_L", "Control_L" }, + { SDLK_RALT, "Alt_R", "Alt_R" }, + { SDLK_LALT, "Alt_L", "Alt_L" }, + { SDLK_RMETA, "Meta_R", "Meta_R" }, + { SDLK_LMETA, "Meta_L", "Meta_L" }, + { SDLK_LSUPER, "Super_L", "Super_L" }, /* Left "Windows" key */ + { SDLK_RSUPER, "Super_R", "Super_R" }, /* Right "Windows" key */ + { SDLK_MODE, "Mode", "Mode" }, /* "Alt Gr" key */ + { SDLK_COMPOSE, "Compose", "Compose" }, /* Multi-key compose key */ + + /* Miscellaneous function keys */ + { SDLK_HELP, "Help", "Help" }, + { SDLK_PRINT, "Print", "Print" }, + { SDLK_SYSREQ, "SysReq", "SysReq" }, + { SDLK_BREAK, "Break", "Break" }, + { SDLK_MENU, "Menu", "Menu" }, + { SDLK_POWER, "Power", "Power" }, /* Power Macintosh power key */ + { SDLK_EURO, "Euro", "\200" }, /* Some european keyboards */ + { SDLK_UNDO, "Undo", "Undo" } /* Atari keyboard has Undo */ +}; + +#endif /* ECORE_SDL_KEYS_H__ */ diff --git a/src/lib/ecore_sdl/Makefile.am b/src/lib/ecore_sdl/Makefile.am new file mode 100644 index 0000000..27210bb --- /dev/null +++ b/src/lib/ecore_sdl/Makefile.am @@ -0,0 +1,29 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore_evas \ +-I$(top_srcdir)/src/lib/ecore_input \ +-I$(top_builddir)/src/lib/ecore \ +-I$(top_builddir)/src/lib/ecore_evas \ +-I$(top_builddir)/src/lib/ecore_input \ +@EFL_ECORE_SDL_BUILD@ \ +@SDL_CFLAGS@ \ +@EVAS_CFLAGS@ \ +@EINA_CFLAGS@ + +lib_LTLIBRARIES = libecore_sdl.la +includes_HEADERS = Ecore_Sdl.h +includesdir = $(includedir)/ecore-@VMAJ@ + +libecore_sdl_la_SOURCES = \ +ecore_sdl.c + +libecore_sdl_la_LIBADD = \ +$(top_builddir)/src/lib/ecore/libecore.la \ +$(top_builddir)/src/lib/ecore_input/libecore_input.la \ +@SDL_LIBS@ @EVIL_LIBS@ @EINA_LIBS@ + +libecore_sdl_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ + +EXTRA_DIST = Ecore_Sdl_Keys.h ecore_sdl_private.h diff --git a/src/lib/ecore_sdl/ecore_sdl.c b/src/lib/ecore_sdl/ecore_sdl.c new file mode 100644 index 0000000..3f28216 --- /dev/null +++ b/src/lib/ecore_sdl/ecore_sdl.c @@ -0,0 +1,335 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "Eina.h" +#include "Ecore_Sdl.h" +#include "Ecore_Input.h" +#include "Ecore.h" +#include "ecore_sdl_private.h" +#include "ecore_private.h" +#include "Ecore_Sdl_Keys.h" + +#include + +int _ecore_sdl_log_dom = -1; + +typedef struct _Ecore_SDL_Pressed Ecore_SDL_Pressed; +struct _Ecore_SDL_Pressed +{ + EINA_RBTREE; + + SDLKey key; +}; + +EAPI int ECORE_SDL_EVENT_GOT_FOCUS = 0; +EAPI int ECORE_SDL_EVENT_LOST_FOCUS = 0; +EAPI int ECORE_SDL_EVENT_RESIZE = 0; +EAPI int ECORE_SDL_EVENT_EXPOSE = 0; + +static int _ecore_sdl_init_count = 0; +static Eina_Rbtree *repeat = NULL; + +static Eina_Rbtree_Direction +_ecore_sdl_pressed_key(const Ecore_SDL_Pressed *left, + const Ecore_SDL_Pressed *right, + __UNUSED__ void *data) +{ + return left->key < right->key ? EINA_RBTREE_LEFT : EINA_RBTREE_RIGHT; +} + +static int +_ecore_sdl_pressed_node(const Ecore_SDL_Pressed *node, + const SDLKey *key, + __UNUSED__ int length, + __UNUSED__ void *data) +{ + return node->key - *key; +} + +/** + * @defgroup Ecore_Sdl_Library_Group SDL Library Functions + * + * Functions used to set up and shut down the Ecore_Sdl functions. + */ + +/** + * Sets up the Ecore_Sdl library. + * @param name device target name + * @return @c 0 on failure. Otherwise, the number of times the library has + * been initialised without being shut down. + * @ingroup Ecore_SDL_Library_Group + */ +EAPI int +ecore_sdl_init(const char *name __UNUSED__) +{ + if(++_ecore_sdl_init_count != 1) + return _ecore_sdl_init_count; + _ecore_sdl_log_dom = eina_log_domain_register + ("ecore_sdl", ECORE_SDL_DEFAULT_LOG_COLOR); + if(_ecore_sdl_log_dom < 0) + { + EINA_LOG_ERR("Impossible to create a log domain for the Ecore SDL module."); + return --_ecore_sdl_init_count; + } + if (!ecore_event_init()) + return --_ecore_sdl_init_count; + + ECORE_SDL_EVENT_GOT_FOCUS = ecore_event_type_new(); + ECORE_SDL_EVENT_LOST_FOCUS = ecore_event_type_new(); + ECORE_SDL_EVENT_RESIZE = ecore_event_type_new(); + ECORE_SDL_EVENT_EXPOSE = ecore_event_type_new(); + + SDL_EnableKeyRepeat(200, 100); + + return _ecore_sdl_init_count; +} + +/** + * Shuts down the Ecore_Sdl library. + * @return @c The number of times the system has been initialised without + * being shut down. + * @ingroup Ecore_SDL_Library_Group + */ +EAPI int +ecore_sdl_shutdown(void) +{ + if (--_ecore_sdl_init_count != 0) + return _ecore_sdl_init_count; + + ecore_event_shutdown(); + eina_log_domain_unregister(_ecore_sdl_log_dom); + _ecore_sdl_log_dom = -1; + return _ecore_sdl_init_count; +} + +static unsigned int +_ecore_sdl_event_modifiers(int mod) +{ + unsigned int modifiers = 0; + + if(mod & KMOD_LSHIFT) modifiers |= ECORE_EVENT_MODIFIER_SHIFT; + if(mod & KMOD_RSHIFT) modifiers |= ECORE_EVENT_MODIFIER_SHIFT; + if(mod & KMOD_LCTRL) modifiers |= ECORE_EVENT_MODIFIER_CTRL; + if(mod & KMOD_RCTRL) modifiers |= ECORE_EVENT_MODIFIER_CTRL; + if(mod & KMOD_LALT) modifiers |= ECORE_EVENT_MODIFIER_ALT; + if(mod & KMOD_RALT) modifiers |= ECORE_EVENT_MODIFIER_ALT; + if(mod & KMOD_NUM) modifiers |= ECORE_EVENT_LOCK_NUM; + if(mod & KMOD_CAPS) modifiers |= ECORE_EVENT_LOCK_CAPS; + + return modifiers; +} + +static Ecore_Event_Key* +_ecore_sdl_event_key(SDL_Event *event, double time) +{ + Ecore_Event_Key *ev; + unsigned int i; + + ev = malloc(sizeof(Ecore_Event_Key)); + if (!ev) return NULL; + + ev->timestamp = time; + ev->window = 0; + ev->event_window = 0; + ev->modifiers = _ecore_sdl_event_modifiers(SDL_GetModState()); + ev->key = NULL; + ev->compose = NULL; + + for (i = 0; i < sizeof(keystable) / sizeof(struct _ecore_sdl_keys_s); ++i) + if (keystable[i].code == event->key.keysym.sym) + { + ev->keyname = keystable[i].name; + ev->string = keystable[i].compose; + + return ev; + } + + free(ev); + return NULL; +} + +EAPI void +ecore_sdl_feed_events(void) +{ + SDL_Event event; + unsigned int time; + + while(SDL_PollEvent(&event)) + { + time = (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff); + switch(event.type) + { + case SDL_MOUSEMOTION: + { + Ecore_Event_Mouse_Move *ev; + + ev = malloc(sizeof(Ecore_Event_Mouse_Move)); + if (!ev) return ; + + ev->timestamp = time; + ev->window = 0; + ev->event_window = 0; + ev->modifiers = 0; /* FIXME: keep modifier around. */ + ev->x = event.motion.x; + ev->y = event.motion.y; + ev->root.x = ev->x; + ev->root.y = ev->y; + + /* Must set multi touch device to 0 or it will get ignored */ + ev->multi.device = 0; + ev->multi.radius = ev->multi.radius_x = ev->multi.radius_y = 0; + ev->multi.pressure = ev->multi.angle = 0; + ev->multi.x = ev->multi.y = ev->multi.root.x = ev->multi.root.y = 0; + + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, ev, NULL, NULL); + break; + } + case SDL_MOUSEBUTTONDOWN: + { + if (event.button.button == SDL_BUTTON_WHEELUP || + event.button.button == SDL_BUTTON_WHEELDOWN) + { + Ecore_Event_Mouse_Wheel *ev; + + ev = malloc(sizeof(Ecore_Event_Mouse_Wheel)); + if (!ev) return ; + + ev->timestamp = time; + ev->window = 0; + ev->event_window = 0; + ev->modifiers = 0; /* FIXME: keep modifier around. */ + ev->direction = 0; + ev->z = event.button.button == SDL_BUTTON_WHEELDOWN ? -1 : 1; + + ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, ev, NULL, NULL); + } + else + { + Ecore_Event_Mouse_Button *ev; + + ev = malloc(sizeof(Ecore_Event_Mouse_Button)); + if (!ev) return ; + + ev->timestamp = time; + ev->window = 0; + ev->event_window = 0; + ev->modifiers = 0; /* FIXME: keep modifier around. */ + ev->buttons = event.button.button; + ev->double_click = 0; + ev->triple_click = 0; + + /* Must set multi touch device to 0 or it will get ignored */ + ev->multi.device = 0; + ev->multi.radius = ev->multi.radius_x = ev->multi.radius_y = 0; + ev->multi.pressure = ev->multi.angle = 0; + ev->multi.x = ev->multi.y = ev->multi.root.x = ev->multi.root.y = 0; + + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, ev, NULL, NULL); + } + break; + } + case SDL_MOUSEBUTTONUP: + { + Ecore_Event_Mouse_Button *ev; + + ev = malloc(sizeof(Ecore_Event_Mouse_Button)); + if (!ev) return ; + ev->timestamp = time; + ev->window = 0; + ev->event_window = 0; + ev->modifiers = 0; /* FIXME: keep modifier around. */ + ev->buttons = event.button.button; + ev->double_click = 0; + ev->triple_click = 0; + + /* Must set multi touch device to 0 or it will get ignored */ + ev->multi.device = 0; + ev->multi.radius = ev->multi.radius_x = ev->multi.radius_y = 0; + ev->multi.pressure = ev->multi.angle = 0; + ev->multi.x = ev->multi.y = ev->multi.root.x = ev->multi.root.y = 0; + + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, ev, NULL, NULL); + break; + } + case SDL_VIDEORESIZE: + { + Ecore_Sdl_Event_Video_Resize *ev; + + ev = malloc(sizeof (Ecore_Sdl_Event_Video_Resize)); + ev->w = event.resize.w; + ev->h = event.resize.h; + + ecore_event_add(ECORE_SDL_EVENT_RESIZE, ev, NULL, NULL); + break; + } + case SDL_VIDEOEXPOSE: + ecore_event_add(ECORE_SDL_EVENT_EXPOSE, NULL, NULL, NULL); + break; + case SDL_QUIT: + ecore_main_loop_quit(); + break; + + case SDL_KEYDOWN: + { + Ecore_SDL_Pressed *entry; + Ecore_Event_Key *ev; + + entry = (Ecore_SDL_Pressed*) eina_rbtree_inline_lookup(repeat, &event.key.keysym.sym, sizeof (event.key.keysym.sym), + EINA_RBTREE_CMP_KEY_CB(_ecore_sdl_pressed_node), NULL); + if (entry) + { + ev = _ecore_sdl_event_key(&event, time); + if (ev) ecore_event_add(ECORE_EVENT_KEY_UP, ev, NULL, NULL); + } + + ev = _ecore_sdl_event_key(&event, time); + if (ev) ecore_event_add(ECORE_EVENT_KEY_DOWN, ev, NULL, NULL); + + if (!entry) + { + entry = malloc(sizeof (Ecore_SDL_Pressed)); + if (!entry) break; + + entry->key = event.key.keysym.sym; + + repeat = eina_rbtree_inline_insert(repeat, EINA_RBTREE_GET(entry), + EINA_RBTREE_CMP_NODE_CB(_ecore_sdl_pressed_key), NULL); + } + break; + } + case SDL_KEYUP: + { + Ecore_Event_Key *ev; + Ecore_SDL_Pressed *entry; + + entry = (Ecore_SDL_Pressed*) eina_rbtree_inline_lookup(repeat, &event.key.keysym.sym, sizeof (event.key.keysym.sym), + EINA_RBTREE_CMP_KEY_CB(_ecore_sdl_pressed_node), NULL); + if (entry) + { + repeat = eina_rbtree_inline_remove(repeat, EINA_RBTREE_GET(entry), + EINA_RBTREE_CMP_NODE_CB(_ecore_sdl_pressed_key), NULL); + free(entry); + } + + ev = _ecore_sdl_event_key(&event, time); + if (ev) ecore_event_add(ECORE_EVENT_KEY_UP, ev, NULL, NULL); + break; + } + case SDL_ACTIVEEVENT: + /* FIXME: Focus gain. */ + break; + case SDL_SYSWMEVENT: + case SDL_USEREVENT: + case SDL_JOYAXISMOTION: + case SDL_JOYBALLMOTION: + case SDL_JOYHATMOTION: + case SDL_JOYBUTTONDOWN: + case SDL_JOYBUTTONUP: + default: + break; + } + } +} diff --git a/src/lib/ecore_sdl/ecore_sdl_private.h b/src/lib/ecore_sdl/ecore_sdl_private.h new file mode 100644 index 0000000..37e9570 --- /dev/null +++ b/src/lib/ecore_sdl/ecore_sdl_private.h @@ -0,0 +1,36 @@ +#ifndef _ECORE_SDL_PRIVATE_H +# define _ECORE_SDL_PRIVATE_H + +extern int _ecore_sdl_log_dom; + +# ifdef ECORE_SDL_DEFAULT_LOG_COLOR +# undef ECORE_SDL_DEFAULT_LOG_COLOR +# endif +# define ECORE_SDL_DEFAULT_LOG_COLOR EINA_COLOR_BLUE + +# ifdef ERR +# undef ERR +# endif +# define ERR(...) EINA_LOG_DOM_ERR(_ecore_sdl_log_dom, __VA_ARGS__) + +# ifdef DBG +# undef DBG +# endif +# define DBG(...) EINA_LOG_DOM_DBG(_ecore_sdl_log_dom, __VA_ARGS__) + +# ifdef INF +# undef INF +# endif +# define INF(...) EINA_LOG_DOM_INFO(_ecore_sdl_log_dom, __VA_ARGS__) + +# ifdef WRN +# undef WRN +# endif +# define WRN(...) EINA_LOG_DOM_WARN(_ecore_sdl_log_dom, __VA_ARGS__) + +# ifdef CRIT +# undef CRIT +# endif +# define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_sdl_log_dom, __VA_ARGS__) + +#endif diff --git a/src/lib/ecore_wayland/Ecore_Wayland.h b/src/lib/ecore_wayland/Ecore_Wayland.h new file mode 100644 index 0000000..02f3c1a --- /dev/null +++ b/src/lib/ecore_wayland/Ecore_Wayland.h @@ -0,0 +1,389 @@ +#ifndef _ECORE_WAYLAND_H_ +# define _ECORE_WAYLAND_H_ + +/* + * Wayland supoprt is considered experimental as wayland itself is still + * unstable and liable to change core protocol. If you use this api, it is + * possible it will break in future, until this notice is removed. + */ + +# include +# include +# include +# include + +# ifdef EAPI +# undef EAPI +# endif + +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif + +typedef enum _Ecore_Wl_Window_Type Ecore_Wl_Window_Type; +typedef enum _Ecore_Wl_Window_Buffer_Type Ecore_Wl_Window_Buffer_Type; + +typedef struct _Ecore_Wl_Display Ecore_Wl_Display; +typedef struct _Ecore_Wl_Output Ecore_Wl_Output; +typedef struct _Ecore_Wl_Input Ecore_Wl_Input; +# ifndef _ECORE_WAYLAND_WINDOW_PREDEF +typedef struct _Ecore_Wl_Window Ecore_Wl_Window; +# endif +typedef struct _Ecore_Wl_Dnd Ecore_Wl_Dnd; /** @since 1.7 */ +typedef struct _Ecore_Wl_Dnd_Source Ecore_Wl_Dnd_Source; +typedef struct _Ecore_Wl_Dnd_Target Ecore_Wl_Dnd_Target; + +typedef struct _Ecore_Wl_Event_Mouse_In Ecore_Wl_Event_Mouse_In; +typedef struct _Ecore_Wl_Event_Mouse_Out Ecore_Wl_Event_Mouse_Out; +typedef struct _Ecore_Wl_Event_Focus_In Ecore_Wl_Event_Focus_In; +typedef struct _Ecore_Wl_Event_Focus_Out Ecore_Wl_Event_Focus_Out; +typedef struct _Ecore_Wl_Event_Window_Configure Ecore_Wl_Event_Window_Configure; +typedef struct _Ecore_Wl_Event_Dnd_Enter Ecore_Wl_Event_Dnd_Enter; +typedef struct _Ecore_Wl_Event_Dnd_Position Ecore_Wl_Event_Dnd_Position; +typedef struct _Ecore_Wl_Event_Dnd_Leave Ecore_Wl_Event_Dnd_Leave; +typedef struct _Ecore_Wl_Event_Dnd_Drop Ecore_Wl_Event_Dnd_Drop; +typedef struct _Ecore_Wl_Event_Data_Source_Send Ecore_Wl_Event_Data_Source_Send; /** @since 1.7 */ +typedef struct _Ecore_Wl_Event_Selection_Data_Ready Ecore_Wl_Event_Selection_Data_Ready; /** @since 1.7 */ +typedef struct _Ecore_Wl_Event_Interfaces_Bound Ecore_Wl_Event_Interfaces_Bound; + +enum _Ecore_Wl_Window_Type +{ + ECORE_WL_WINDOW_TYPE_NONE, + ECORE_WL_WINDOW_TYPE_TOPLEVEL, + ECORE_WL_WINDOW_TYPE_FULLSCREEN, + ECORE_WL_WINDOW_TYPE_MAXIMIZED, + ECORE_WL_WINDOW_TYPE_TRANSIENT, + ECORE_WL_WINDOW_TYPE_MENU, + ECORE_WL_WINDOW_TYPE_CUSTOM +}; + +enum _Ecore_Wl_Window_Buffer_Type +{ + ECORE_WL_WINDOW_BUFFER_TYPE_EGL_WINDOW, + ECORE_WL_WINDOW_BUFFER_TYPE_EGL_IMAGE, + ECORE_WL_WINDOW_BUFFER_TYPE_SHM +}; + +struct _Ecore_Wl_Display +{ + struct + { + struct wl_display *display; + struct wl_compositor *compositor; + struct wl_shell *shell; + struct wl_shell *desktop_shell; + struct wl_shm *shm; + struct wl_data_device_manager *data_device_manager; + } wl; + + int fd; + unsigned int mask; + unsigned int serial; + Ecore_Fd_Handler *fd_hdl; + + struct wl_list inputs; + struct wl_list outputs; + + struct + { + struct xkb_context *context; + } xkb; + + struct wl_cursor_theme *cursor_theme; + + Ecore_Wl_Output *output; + Ecore_Wl_Input *input; + + void (*output_configure)(Ecore_Wl_Output *output, void *data); + void *data; +}; + +struct _Ecore_Wl_Output +{ + Ecore_Wl_Display *display; + struct wl_output *output; + Eina_Rectangle allocation; + int mw, mh; + struct wl_list link; + + void (*destroy) (Ecore_Wl_Output *output, void *data); + void *data; +}; + +struct _Ecore_Wl_Input +{ + Ecore_Wl_Display *display; + struct wl_seat *seat; + struct wl_pointer *pointer; + struct wl_keyboard *keyboard; + struct wl_touch *touch; + + const char *cursor_name; + struct wl_surface *cursor_surface; + struct wl_callback *cursor_frame_cb; + + struct wl_data_device *data_device; + + Ecore_Wl_Window *pointer_focus; + Ecore_Wl_Window *keyboard_focus; + + unsigned int button; + unsigned int timestamp; + unsigned int modifiers; + unsigned int pointer_enter_serial; + int sx, sy; + + struct wl_list link; + + Ecore_Wl_Window *grab; + unsigned int grab_button; + + Ecore_Wl_Dnd_Source *drag_source; + Ecore_Wl_Dnd_Source *selection_source; + Ecore_Wl_Dnd *dnd; /** @since 1.7 */ + + struct + { + struct xkb_keymap *keymap; + struct xkb_state *state; + xkb_mod_mask_t control_mask; + xkb_mod_mask_t alt_mask; + xkb_mod_mask_t shift_mask; + } xkb; + + struct + { + Ecore_Fd_Handler *hdlr; + int timerfd; + unsigned int sym, key, time; + } repeat; +}; + +struct _Ecore_Wl_Window +{ + Ecore_Wl_Display *display; + Ecore_Wl_Window *parent; + + struct wl_surface *surface; + struct wl_shell_surface *shell_surface; + + struct + { + struct wl_region *input, *opaque; + } region; + + int id; + int x, y; + int edges; + + Eina_Rectangle allocation, pending_allocation; + Eina_Rectangle saved_allocation, server_allocation; + + /* Eina_Bool redraw_scheduled : 1; */ + /* Eina_Bool resize_scheduled : 1; */ + Eina_Bool alpha : 1; + Eina_Bool transparent : 1; + Eina_Bool moving : 1; + Eina_Bool resizing : 1; + + Ecore_Wl_Window_Type type; + Ecore_Wl_Window_Buffer_Type buffer_type; + + Ecore_Wl_Input *pointer_device; + Ecore_Wl_Input *keyboard_device; + + /* FIXME: Ideally we should record the cursor name for this window + * so we can compare and avoid unnecessary cursor set calls to wayland */ + + void *data; +}; + +struct _Ecore_Wl_Event_Mouse_In +{ + int modifiers; + int x, y; + struct + { + int x, y; + } root; + unsigned int window; + unsigned int event_window; + unsigned int root_window; + unsigned int timestamp; +}; + +struct _Ecore_Wl_Event_Mouse_Out +{ + int modifiers; + int x, y; + struct + { + int x, y; + } root; + unsigned int window; + unsigned int event_window; + unsigned int root_window; + unsigned int timestamp; +}; + +struct _Ecore_Wl_Event_Focus_In +{ + unsigned int win; + unsigned int timestamp; +}; + +struct _Ecore_Wl_Event_Focus_Out +{ + unsigned int win; + unsigned int timestamp; +}; + +struct _Ecore_Wl_Event_Window_Configure +{ + unsigned int win; + unsigned int event_win; + int x, y, w, h; +}; + +struct _Ecore_Wl_Event_Dnd_Enter +{ + unsigned int win, source; + char **types; + int num_types; + struct + { + int x, y; + } position; +}; + +struct _Ecore_Wl_Event_Dnd_Position +{ + unsigned int win, source; + struct + { + int x, y; + } position; +}; + +struct _Ecore_Wl_Event_Dnd_Leave +{ + unsigned int win, source; +}; + +struct _Ecore_Wl_Event_Dnd_Drop +{ + unsigned int win, source; + struct + { + int x, y; + } position; +}; + +/** @since 1.7 */ +struct _Ecore_Wl_Event_Data_Source_Send +{ + char *type; + int fd; +}; + +/** @since 1.7 */ +struct _Ecore_Wl_Event_Selection_Data_Ready +{ + char *data; + int len; + Eina_Bool done; +}; + +struct _Ecore_Wl_Event_Interfaces_Bound +{ + Eina_Bool compositor : 1; + Eina_Bool shm : 1; + Eina_Bool shell : 1; +}; + +/** + * @file + * @brief Ecore functions for dealing with the Wayland window system + * + * Ecore_Wl provides a wrapper and convenience functions for using the + * Wayland window system. Function groups for this part of the library + * include the following: + * + * @li @ref Ecore_Wl_Init_Group + * @li @ref Ecore_Wl_Display_Group + * @li @ref Ecore_Wl_Flush_Group + * @li @ref Ecore_Wl_Window_Group + */ + +EAPI extern int ECORE_WL_EVENT_MOUSE_IN; +EAPI extern int ECORE_WL_EVENT_MOUSE_OUT; +EAPI extern int ECORE_WL_EVENT_FOCUS_IN; +EAPI extern int ECORE_WL_EVENT_FOCUS_OUT; +EAPI extern int ECORE_WL_EVENT_WINDOW_CONFIGURE; +EAPI extern int ECORE_WL_EVENT_DND_ENTER; +EAPI extern int ECORE_WL_EVENT_DND_POSITION; +EAPI extern int ECORE_WL_EVENT_DND_LEAVE; +EAPI extern int ECORE_WL_EVENT_DND_DROP; +EAPI extern int ECORE_WL_EVENT_DATA_SOURCE_TARGET; /** @since 1.7 */ +EAPI extern int ECORE_WL_EVENT_DATA_SOURCE_SEND; /** @since 1.7 */ +EAPI extern int ECORE_WL_EVENT_DATA_SOURCE_CANCELLED; /** @since 1.7 */ +EAPI extern int ECORE_WL_EVENT_SELECTION_DATA_READY; /** @since 1.7 */ +EAPI extern int ECORE_WL_EVENT_INTERFACES_BOUND; + +EAPI int ecore_wl_init(const char *name); +EAPI int ecore_wl_shutdown(void); +EAPI void ecore_wl_flush(void); +EAPI void ecore_wl_sync(void); +EAPI struct wl_shm *ecore_wl_shm_get(void); +EAPI struct wl_display *ecore_wl_display_get(void); +EAPI void ecore_wl_screen_size_get(int *w, int *h); +EAPI void ecore_wl_pointer_xy_get(int *x, int *y); +EAPI int ecore_wl_dpi_get(void); +EAPI void ecore_wl_display_iterate(void); +EAPI struct wl_cursor *ecore_wl_cursor_get(const char *cursor_name); + +EAPI void ecore_wl_input_grab(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int button); +EAPI void ecore_wl_input_ungrab(Ecore_Wl_Input *input); +EAPI void ecore_wl_input_pointer_set(Ecore_Wl_Input *input, struct wl_surface *surface, int hot_x, int hot_y); +EAPI void ecore_wl_input_cursor_from_name_set(Ecore_Wl_Input *input, const char *cursor_name); +EAPI void ecore_wl_input_cursor_default_restore(Ecore_Wl_Input *input); + +EAPI struct wl_list ecore_wl_outputs_get(void); + +EAPI Ecore_Wl_Window *ecore_wl_window_new(Ecore_Wl_Window *parent, int x, int y, int w, int h, int buffer_type); +EAPI void ecore_wl_window_free(Ecore_Wl_Window *win); +EAPI void ecore_wl_window_move(Ecore_Wl_Window *win, int x, int y); +EAPI void ecore_wl_window_resize(Ecore_Wl_Window *win, int w, int h, int location); +EAPI void ecore_wl_window_damage(Ecore_Wl_Window *win, int x, int y, int w, int h); +EAPI void ecore_wl_window_buffer_attach(Ecore_Wl_Window *win, struct wl_buffer *buffer, int x, int y); +EAPI void ecore_wl_window_show(Ecore_Wl_Window *win); +EAPI void ecore_wl_window_hide(Ecore_Wl_Window *win); +EAPI void ecore_wl_window_raise(Ecore_Wl_Window *win); +EAPI void ecore_wl_window_maximized_set(Ecore_Wl_Window *win, Eina_Bool maximized); +EAPI void ecore_wl_window_fullscreen_set(Ecore_Wl_Window *win, Eina_Bool fullscreen); +EAPI void ecore_wl_window_transparent_set(Ecore_Wl_Window *win, Eina_Bool transparent); +EAPI void ecore_wl_window_update_size(Ecore_Wl_Window *win, int w, int h); +EAPI void ecore_wl_window_update_location(Ecore_Wl_Window *win, int x, int y); +EAPI struct wl_surface *ecore_wl_window_surface_get(Ecore_Wl_Window *win); +EAPI struct wl_shell_surface *ecore_wl_window_shell_surface_get(Ecore_Wl_Window *win); +EAPI Ecore_Wl_Window *ecore_wl_window_find(unsigned int id); +EAPI void ecore_wl_window_type_set(Ecore_Wl_Window *win, Ecore_Wl_Window_Type type); +EAPI void ecore_wl_window_pointer_set(Ecore_Wl_Window *win, struct wl_surface *surface, int hot_x, int hot_y); +EAPI void ecore_wl_window_cursor_from_name_set(Ecore_Wl_Window *win, const char *cursor_name); +EAPI void ecore_wl_window_cursor_default_restore(Ecore_Wl_Window *win); +EAPI void ecore_wl_window_parent_set(Ecore_Wl_Window *win, Ecore_Wl_Window *parent); + +/** @since 1.7 */ +EAPI Eina_Bool ecore_wl_dnd_set_selection(Ecore_Wl_Dnd *dnd, const char **types_offered); +EAPI Eina_Bool ecore_wl_dnd_get_selection(Ecore_Wl_Dnd *dnd, const char *type); +EAPI Ecore_Wl_Dnd *ecore_wl_dnd_get(); +EAPI Eina_Bool ecore_wl_dnd_start_drag(); +EAPI Eina_Bool ecore_wl_dnd_selection_has_owner(Ecore_Wl_Dnd *dnd); + +#endif diff --git a/src/lib/ecore_wayland/Makefile.am b/src/lib/ecore_wayland/Makefile.am new file mode 100644 index 0000000..f6b801d --- /dev/null +++ b/src/lib/ecore_wayland/Makefile.am @@ -0,0 +1,33 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore_input \ +-I$(top_builddir)/src/lib/ecore \ +-I$(top_builddir)/src/lib/ecore_input \ +@WAYLAND_CFLAGS@ \ +@EVAS_CFLAGS@ \ +@EINA_CFLAGS@ + +lib_LTLIBRARIES = libecore_wayland.la +includes_HEADERS = Ecore_Wayland.h +includesdir = $(includedir)/ecore-@VMAJ@ + +libecore_wayland_la_SOURCES = \ +ecore_wl.c \ +ecore_wl_output.c \ +ecore_wl_input.c \ +ecore_wl_window.c \ +ecore_wl_dnd.c + +libecore_wayland_la_LIBADD = \ +$(top_builddir)/src/lib/ecore/libecore.la \ +$(top_builddir)/src/lib/ecore_input/libecore_input.la \ +@WAYLAND_LIBS@ \ +@EVAS_LIBS@ \ +@EINA_LIBS@ + +libecore_wayland_la_LDFLAGS = -version-info @version_info@ @release_info@ +libecore_wayland_la_DEPENDENCIES = $(top_builddir)/src/lib/ecore/libecore.la + +EXTRA_DIST = ecore_wl_private.h diff --git a/src/lib/ecore_wayland/ecore_wl.c b/src/lib/ecore_wayland/ecore_wl.c new file mode 100644 index 0000000..3bb05e7 --- /dev/null +++ b/src/lib/ecore_wayland/ecore_wl.c @@ -0,0 +1,498 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "ecore_wl_private.h" + +/* local function prototypes */ +static Eina_Bool _ecore_wl_shutdown(Eina_Bool close); +static int _ecore_wl_cb_event_mask_update(unsigned int mask, void *data); +static Eina_Bool _ecore_wl_cb_handle_data(void *data, Ecore_Fd_Handler *hdl __UNUSED__); +static void _ecore_wl_cb_handle_global(struct wl_display *disp, unsigned int id, const char *interface, unsigned int version __UNUSED__, void *data); +static Eina_Bool _ecore_wl_xkb_init(Ecore_Wl_Display *ewd); +static Eina_Bool _ecore_wl_xkb_shutdown(Ecore_Wl_Display *ewd); + +/* local variables */ +static int _ecore_wl_init_count = 0; + +/* external variables */ +int _ecore_wl_log_dom = -1; +Ecore_Wl_Display *_ecore_wl_disp = NULL; + +EAPI int ECORE_WL_EVENT_MOUSE_IN = 0; +EAPI int ECORE_WL_EVENT_MOUSE_OUT = 0; +EAPI int ECORE_WL_EVENT_FOCUS_IN = 0; +EAPI int ECORE_WL_EVENT_FOCUS_OUT = 0; +EAPI int ECORE_WL_EVENT_WINDOW_CONFIGURE = 0; +EAPI int ECORE_WL_EVENT_DND_ENTER = 0; +EAPI int ECORE_WL_EVENT_DND_POSITION = 0; +EAPI int ECORE_WL_EVENT_DND_LEAVE = 0; +EAPI int ECORE_WL_EVENT_DND_DROP = 0; +EAPI int ECORE_WL_EVENT_DATA_SOURCE_TARGET = 0; +EAPI int ECORE_WL_EVENT_DATA_SOURCE_SEND = 0; +EAPI int ECORE_WL_EVENT_SELECTION_DATA_READY = 0; +EAPI int ECORE_WL_EVENT_DATA_SOURCE_CANCELLED = 0; +EAPI int ECORE_WL_EVENT_INTERFACES_BOUND = 0; + +/** + * @defgroup Ecore_Wl_Init_Group Wayland Library Init and Shutdown Functions + * + * Functions that start and shutdown the Ecore Wayland Library. + */ + +/** + * Initialize the Wayland display connection to the given display. + * + * @param name Display target name. if @c NULL, the default display is + * assumed. + * @return The number of times the library has been initialized without being + * shut down. 0 is returned if an error occurs. + * + * @ingroup Ecore_Wl_Init_Group + */ +EAPI int +ecore_wl_init(const char *name) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (++_ecore_wl_init_count != 1) return _ecore_wl_init_count; + + if (!eina_init()) return --_ecore_wl_init_count; + + _ecore_wl_log_dom = + eina_log_domain_register("ecore_wl", ECORE_WL_DEFAULT_LOG_COLOR); + if (_ecore_wl_log_dom < 0) + { + EINA_LOG_ERR("Cannot create a log domain for Ecore Wayland"); + eina_shutdown(); + return --_ecore_wl_init_count; + } + + if (!ecore_init()) + { + ERR("Could not initialize ecore"); + eina_log_domain_unregister(_ecore_wl_log_dom); + _ecore_wl_log_dom = -1; + eina_shutdown(); + return --_ecore_wl_init_count; + } + + if (!ecore_event_init()) + { + ERR("Could not initialize ecore_event"); + eina_log_domain_unregister(_ecore_wl_log_dom); + _ecore_wl_log_dom = -1; + ecore_shutdown(); + eina_shutdown(); + return --_ecore_wl_init_count; + } + + if (!ECORE_WL_EVENT_MOUSE_IN) + { + ECORE_WL_EVENT_MOUSE_IN = ecore_event_type_new(); + ECORE_WL_EVENT_MOUSE_OUT = ecore_event_type_new(); + ECORE_WL_EVENT_FOCUS_IN = ecore_event_type_new(); + ECORE_WL_EVENT_FOCUS_OUT = ecore_event_type_new(); + ECORE_WL_EVENT_WINDOW_CONFIGURE = ecore_event_type_new(); + ECORE_WL_EVENT_DND_ENTER = ecore_event_type_new(); + ECORE_WL_EVENT_DND_POSITION = ecore_event_type_new(); + ECORE_WL_EVENT_DND_LEAVE = ecore_event_type_new(); + ECORE_WL_EVENT_DND_DROP = ecore_event_type_new(); + ECORE_WL_EVENT_DATA_SOURCE_TARGET = ecore_event_type_new(); + ECORE_WL_EVENT_DATA_SOURCE_SEND = ecore_event_type_new(); + ECORE_WL_EVENT_SELECTION_DATA_READY = ecore_event_type_new(); + ECORE_WL_EVENT_DATA_SOURCE_CANCELLED = ecore_event_type_new(); + ECORE_WL_EVENT_INTERFACES_BOUND = ecore_event_type_new(); + } + + if (!(_ecore_wl_disp = malloc(sizeof(Ecore_Wl_Display)))) + { + ERR("Could not allocate memory for Ecore_Wl_Display structure"); + eina_log_domain_unregister(_ecore_wl_log_dom); + _ecore_wl_log_dom = -1; + ecore_event_shutdown(); + ecore_shutdown(); + eina_shutdown(); + return --_ecore_wl_init_count; + } + + memset(_ecore_wl_disp, 0, sizeof(Ecore_Wl_Display)); + + if (!(_ecore_wl_disp->wl.display = wl_display_connect(name))) + { + ERR("Could not connect to Wayland display"); + eina_log_domain_unregister(_ecore_wl_log_dom); + _ecore_wl_log_dom = -1; + ecore_event_shutdown(); + ecore_shutdown(); + eina_shutdown(); + return --_ecore_wl_init_count; + } + + _ecore_wl_disp->fd = + wl_display_get_fd(_ecore_wl_disp->wl.display, + _ecore_wl_cb_event_mask_update, _ecore_wl_disp); + + _ecore_wl_disp->fd_hdl = + ecore_main_fd_handler_add(_ecore_wl_disp->fd, ECORE_FD_READ, + _ecore_wl_cb_handle_data, _ecore_wl_disp, + NULL, NULL); + + wl_list_init(&_ecore_wl_disp->inputs); + wl_list_init(&_ecore_wl_disp->outputs); + + wl_display_add_global_listener(_ecore_wl_disp->wl.display, + _ecore_wl_cb_handle_global, _ecore_wl_disp); + + /* Init egl */ + + /* FIXME: Process connection events ?? */ + /* wl_display_iterate(_ecore_wl_disp->wl.display, WL_DISPLAY_READABLE); */ + + /* TODO: create pointer surfaces */ + + if (!_ecore_wl_xkb_init(_ecore_wl_disp)) + { + ERR("Could not initialize XKB"); + free(_ecore_wl_disp); + eina_log_domain_unregister(_ecore_wl_log_dom); + _ecore_wl_log_dom = -1; + ecore_event_shutdown(); + ecore_shutdown(); + eina_shutdown(); + return --_ecore_wl_init_count; + } + + _ecore_wl_window_init(); + + return _ecore_wl_init_count; +} + +/** + * Shuts down the Ecore Wayland Library + * + * In shutting down the library, the Wayland display connection is terminated + * and any event handlers for it are removed. + * + * @return The number of times the library has been initialized without + * being shut down. + * + * @ingroup Ecore_Wl_Init_Group + */ +EAPI int +ecore_wl_shutdown(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _ecore_wl_shutdown(EINA_TRUE); +} + +/** + * @defgroup Ecore_Wl_Flush_Group Wayland Synchronization Functions + * + * Functions that ensure that all commands which have been issued by the + * Ecore Wayland library have been sent to the server. + */ + +/** + * Sends all Wayland commands to the Wayland Display. + * + * @ingroup Ecore_Wl_Flush_Group + * @since 1.2 + */ +EAPI void +ecore_wl_flush(void) +{ +// LOGFN(__FILE__, __LINE__, __FUNCTION__); + + while (_ecore_wl_disp->mask & WL_DISPLAY_WRITABLE) + wl_display_iterate(_ecore_wl_disp->wl.display, WL_DISPLAY_WRITABLE); +} + +/** + * Flushes the command buffer and waits until all requests have been + * processed by the server. + * + * @ingroup Ecore_Wl_Flush_Group + * @since 1.2 + */ +EAPI void +ecore_wl_sync(void) +{ +// LOGFN(__FILE__, __LINE__, __FUNCTION__); + + wl_display_sync(_ecore_wl_disp->wl.display); +} + +/** + * @defgroup Ecore_Wl_Display_Group Wayland Display Functions + * + * Functions that set and retrieve various information about the Wayland Display. + */ + +/** + * Retrieves the Wayland Shm Interface used for the current Wayland connection. + * + * @return The current wayland shm interface + * + * @ingroup Ecore_Wl_Display_Group + * @since 1.2 + */ +EAPI struct wl_shm * +ecore_wl_shm_get(void) +{ + return _ecore_wl_disp->wl.shm; +} + +/** + * Retrieves the Wayland Display Interface used for the current Wayland connection. + * + * @return The current wayland display interface + * + * @ingroup Ecore_Wl_Display_Group + * @since 1.2 + */ +EAPI struct wl_display * +ecore_wl_display_get(void) +{ + return _ecore_wl_disp->wl.display; +} + +/** + * Retrieves the size of the current screen. + * + * @param w where to return the width. May be NULL. Returns 0 on error. + * @param h where to return the height. May be NULL. Returns 0 on error. + * + * @ingroup Ecore_Wl_Display_Group + * @since 1.2 + */ +EAPI void +ecore_wl_screen_size_get(int *w, int *h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (w) *w = 0; + if (h) *h = 0; + + if (!_ecore_wl_disp->output) return; + + if (w) *w = _ecore_wl_disp->output->allocation.w; + if (h) *h = _ecore_wl_disp->output->allocation.h; +} + +/* @since 1.2 */ +EAPI void +ecore_wl_pointer_xy_get(int *x, int *y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_wl_input_pointer_xy_get(x, y); +} + +/** + * Return the screen DPI + * + * This is a simplistic call to get DPI. It does not account for differing + * DPI in the x and y axes nor does it account for multihead or xinerama and + * xrandr where different parts of the screen may have different DPI etc. + * + * @return the general screen DPI (dots/pixels per inch). + * + * @since 1.2 + */ +EAPI int +ecore_wl_dpi_get(void) +{ + int w, mw; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!_ecore_wl_disp->output) return 75; + + mw = _ecore_wl_disp->output->mw; + if (mw <= 0) return 75; + + w = _ecore_wl_disp->output->allocation.w; + /* FIXME: NB: Hrrrmmm, need to verify this. xorg code is using a different + * formula to calc this */ + return (((w * 254) / mw) + 5) / 10; +} + +EAPI void +ecore_wl_display_iterate(void) +{ + wl_display_iterate(_ecore_wl_disp->wl.display, WL_DISPLAY_READABLE); +} + +/** + * Retrieves the requested cursor from the cursor theme + * + * @param cursor_name The desired cursor name to be looked up in the theme + * @return the cursor or NULL if the cursor cannot be found + * + * @since 1.2 + */ +EAPI struct wl_cursor * +ecore_wl_cursor_get(const char *cursor_name) +{ + if ((!_ecore_wl_disp) || (!_ecore_wl_disp->cursor_theme)) + return NULL; + + return wl_cursor_theme_get_cursor(_ecore_wl_disp->cursor_theme, + cursor_name); +} + +/* local functions */ +static Eina_Bool +_ecore_wl_shutdown(Eina_Bool close) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (--_ecore_wl_init_count != 0) return _ecore_wl_init_count; + if (!_ecore_wl_disp) return _ecore_wl_init_count; + + _ecore_wl_window_shutdown(); + + if (_ecore_wl_disp->fd_hdl) + ecore_main_fd_handler_del(_ecore_wl_disp->fd_hdl); + + if (close) + { + Ecore_Wl_Output *out, *tout; + Ecore_Wl_Input *in, *tin; + + wl_list_for_each_safe(out, tout, &_ecore_wl_disp->outputs, link) + _ecore_wl_output_del(out); + + wl_list_for_each_safe(in, tin, &_ecore_wl_disp->inputs, link) + _ecore_wl_input_del(in); + + _ecore_wl_xkb_shutdown(_ecore_wl_disp); + + if (_ecore_wl_disp->wl.shell) + wl_shell_destroy(_ecore_wl_disp->wl.shell); + if (_ecore_wl_disp->wl.shm) wl_shm_destroy(_ecore_wl_disp->wl.shm); + if (_ecore_wl_disp->wl.data_device_manager) + wl_data_device_manager_destroy(_ecore_wl_disp->wl.data_device_manager); + if (_ecore_wl_disp->wl.compositor) + wl_compositor_destroy(_ecore_wl_disp->wl.compositor); + if (_ecore_wl_disp->wl.display) + { + wl_display_flush(_ecore_wl_disp->wl.display); + wl_display_disconnect(_ecore_wl_disp->wl.display); + } + free(_ecore_wl_disp); + } + + ecore_event_shutdown(); + ecore_shutdown(); + + eina_log_domain_unregister(_ecore_wl_log_dom); + _ecore_wl_log_dom = -1; + eina_shutdown(); + + return _ecore_wl_init_count; +} + +static int +_ecore_wl_cb_event_mask_update(unsigned int mask, void *data) +{ + Ecore_Wl_Display *ewd; + +// LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ewd = data; + ewd->mask = mask; + return 0; +} + +static Eina_Bool +_ecore_wl_cb_handle_data(void *data, Ecore_Fd_Handler *hdl __UNUSED__) +{ + Ecore_Wl_Display *ewd; + + /* LOGFN(__FILE__, __LINE__, __FUNCTION__); */ + + if (!(ewd = data)) return ECORE_CALLBACK_RENEW; + wl_display_iterate(ewd->wl.display, ewd->mask); + return ECORE_CALLBACK_RENEW; +} + +static void +_ecore_wl_cb_handle_global(struct wl_display *disp, unsigned int id, const char *interface, unsigned int version __UNUSED__, void *data) +{ + Ecore_Wl_Display *ewd; + +// LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ewd = data; + + /* TODO: Add listener for wl_display so we can catch fatal errors !! */ + + if (!strcmp(interface, "wl_compositor")) + ewd->wl.compositor = wl_display_bind(disp, id, &wl_compositor_interface); + else if (!strcmp(interface, "wl_output")) + _ecore_wl_output_add(ewd, id); + else if (!strcmp(interface, "wl_seat")) + _ecore_wl_input_add(ewd, id); + else if (!strcmp(interface, "wl_shell")) + ewd->wl.shell = wl_display_bind(disp, id, &wl_shell_interface); + /* else if (!strcmp(interface, "desktop_shell")) */ + /* ewd->wl.desktop_shell = wl_display_bind(disp, id, &wl_shell_interface); */ + else if (!strcmp(interface, "wl_shm")) + { + ewd->wl.shm = wl_display_bind(disp, id, &wl_shm_interface); + + /* FIXME: We should not hard-code a cursor size here, and we should + * also import the theme name from a config or env variable */ + ewd->cursor_theme = wl_cursor_theme_load(NULL, 32, ewd->wl.shm); + } + else if (!strcmp(interface, "wl_data_device_manager")) + { + ewd->wl.data_device_manager = + wl_display_bind(disp, id, &wl_data_device_manager_interface); + } + + if ((ewd->wl.compositor) && (ewd->wl.shm) && (ewd->wl.shell)) + { + Ecore_Wl_Event_Interfaces_Bound *ev; + + if (!(ev = calloc(1, sizeof(Ecore_Wl_Event_Interfaces_Bound)))) + return; + + ev->compositor = (ewd->wl.compositor != NULL); + ev->shm = (ewd->wl.shm != NULL); + ev->shell = (ewd->wl.shell != NULL); + + ecore_event_add(ECORE_WL_EVENT_INTERFACES_BOUND, ev, NULL, NULL); + } +} + +static Eina_Bool +_ecore_wl_xkb_init(Ecore_Wl_Display *ewd) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(ewd->xkb.context = xkb_context_new(0))) + return EINA_FALSE; + + return EINA_TRUE; +} + +static Eina_Bool +_ecore_wl_xkb_shutdown(Ecore_Wl_Display *ewd) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + xkb_context_unref(ewd->xkb.context); + + return EINA_TRUE; +} + +struct wl_data_source * +_ecore_wl_create_data_source(Ecore_Wl_Display *ewd) +{ + return wl_data_device_manager_create_data_source(ewd->wl.data_device_manager); +} diff --git a/src/lib/ecore_wayland/ecore_wl_dnd.c b/src/lib/ecore_wayland/ecore_wl_dnd.c new file mode 100644 index 0000000..e7c8f86 --- /dev/null +++ b/src/lib/ecore_wayland/ecore_wl_dnd.c @@ -0,0 +1,485 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "ecore_wl_private.h" + +struct _dnd_task +{ + void *data; + Ecore_Fd_Cb cb; +}; + +struct _dnd_read_ctx +{ + int epoll_fd; + struct epoll_event *ep; +}; + +/* local function prototypes */ +static void _ecore_wl_dnd_offer(void *data, struct wl_data_offer *wl_data_offer __UNUSED__, const char *type); +static void _ecore_wl_dnd_cb_enter_free(void *data __UNUSED__, void *event); + +static void _ecore_wl_dnd_data_source_target(void *data, struct wl_data_source *source, const char *mime_type); +static void _ecore_wl_dnd_data_source_send(void *data, struct wl_data_source *source, const char *mime_type, int32_t fd); +static void _ecore_wl_dnd_data_source_cancelled(void *data, struct wl_data_source *source); +static void _ecore_wl_dnd_source_receive_data(Ecore_Wl_Dnd_Source *source, const char *type); + +/* wayland listeners */ +static const struct wl_data_offer_listener _ecore_wl_data_offer_listener = +{ + _ecore_wl_dnd_offer, +}; + +static const struct wl_data_source_listener _ecore_wl_data_source_listener = +{ + _ecore_wl_dnd_data_source_target, + _ecore_wl_dnd_data_source_send, + _ecore_wl_dnd_data_source_cancelled +}; + +extern Ecore_Wl_Dnd *glb_dnd; + +EAPI Ecore_Wl_Dnd * +ecore_wl_dnd_get() +{ + return glb_dnd; +} + +EAPI Eina_Bool +ecore_wl_dnd_start_drag(Ecore_Wl_Dnd *dnd __UNUSED__) +{ + //TODO: + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_wl_dnd_set_selection(Ecore_Wl_Dnd *dnd, const char **types_offered) +{ + char **p; + const char **type; + + dnd->data_source = _ecore_wl_create_data_source(dnd->ewd); + + /* free old types */ + if (dnd->types_offered.data) + { + wl_array_for_each(p, &dnd->types_offered) + free(*p); + wl_array_release(&dnd->types_offered); + wl_array_init(&dnd->types_offered); + } + + for (type = types_offered; *type; type++) + { + p = wl_array_add(&dnd->types_offered, sizeof(*p)); + *p = strdup(*type); + wl_data_source_offer(dnd->data_source, *p); + } + + wl_data_source_add_listener(dnd->data_source, &_ecore_wl_data_source_listener, dnd); + + _ecore_wl_input_set_selection(dnd->input, dnd->data_source); + + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_wl_dnd_get_selection(Ecore_Wl_Dnd *dnd, const char *type) +{ + char **p; + Ecore_Wl_Input *input; + + input = dnd->input; + + if (!input->selection_source) return EINA_FALSE; + + wl_array_for_each(p, &input->selection_source->types) + if (strcmp(type, *p) == 0) break; + + if (!*p) return EINA_FALSE; + + _ecore_wl_dnd_source_receive_data(input->selection_source, type); + + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_wl_dnd_selection_has_owner(Ecore_Wl_Dnd *dnd) +{ + Ecore_Wl_Input *input; + + input = dnd->input; + return (input->selection_source != NULL); +} + +/* local functions */ +static void +_ecore_wl_dnd_data_source_target(void *data __UNUSED__, struct wl_data_source *source __UNUSED__, const char *mime_type __UNUSED__) +{ + //TODO: +} + +static void +_ecore_wl_dnd_cb_data_source_send_free(void *data __UNUSED__, void *event) +{ + Ecore_Wl_Event_Data_Source_Send *ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(ev = event)) return; + + free(ev->type); + free(ev); +} + +static void +_ecore_wl_dnd_data_source_send(void *data, struct wl_data_source *source __UNUSED__, const char *mime_type, int32_t fd) +{ + Ecore_Wl_Event_Data_Source_Send *event; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!data) return; + + if (!(event = calloc(1, sizeof(Ecore_Wl_Event_Data_Source_Send)))) return; + + event->type = strdup(mime_type); + event->fd = fd; + + ecore_event_add(ECORE_WL_EVENT_DATA_SOURCE_SEND, event, _ecore_wl_dnd_cb_data_source_send_free, NULL); +} + +static void +_ecore_wl_dnd_data_source_cancelled(void *data __UNUSED__, struct wl_data_source *source) +{ + wl_data_source_destroy(source); +} + +void +_ecore_wl_dnd_add(Ecore_Wl_Input *input, struct wl_data_device *data_device __UNUSED__, struct wl_data_offer *offer) +{ + Ecore_Wl_Dnd_Source *source; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(source = malloc(sizeof(Ecore_Wl_Dnd_Source)))) return; + wl_array_init(&source->types); + source->refcount = 1; + source->input = input; + source->offer = offer; + wl_data_offer_add_listener(source->offer, + &_ecore_wl_data_offer_listener, source); +} + +void +_ecore_wl_dnd_enter(void *data, struct wl_data_device *data_device __UNUSED__, unsigned int timestamp __UNUSED__, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *offer) +{ + Ecore_Wl_Event_Dnd_Enter *event; + Ecore_Wl_Input *input; + Ecore_Wl_Window *win; + char **p; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if ((!(input = data)) || (!offer)) return; + + if (!(input->drag_source = wl_data_offer_get_user_data(offer))) + return; + + win = wl_surface_get_user_data(surface); +// input->pointer_focus = win; + + p = wl_array_add(&input->drag_source->types, sizeof(*p)); + *p = NULL; + + if (!(event = calloc(1, sizeof(Ecore_Wl_Event_Dnd_Enter)))) return; + + event->win = win->id; + if (input->drag_source->input) + { + if (input->drag_source->input->keyboard_focus) + event->source = input->drag_source->input->keyboard_focus->id; + } + + event->position.x = wl_fixed_to_int(x); + event->position.y = wl_fixed_to_int(y); + event->num_types = input->drag_source->types.size; + event->types = input->drag_source->types.data; + + ecore_event_add(ECORE_WL_EVENT_DND_ENTER, event, + _ecore_wl_dnd_cb_enter_free, NULL); +} + +void +_ecore_wl_dnd_leave(void *data, struct wl_data_device *data_device __UNUSED__) +{ + Ecore_Wl_Input *input; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(input = data)) return; + /* FIXME: NB: This MAY need to raise a wl_event_dnd_leave for the + * source window */ + _ecore_wl_dnd_del(input->drag_source); + input->drag_source = NULL; +} + +void +_ecore_wl_dnd_motion(void *data, struct wl_data_device *data_device __UNUSED__, unsigned int timestamp __UNUSED__, wl_fixed_t x, wl_fixed_t y) +{ + Ecore_Wl_Event_Dnd_Position *event; + Ecore_Wl_Input *input; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(input = data)) return; + + input->sx = wl_fixed_to_int(x); + input->sy = wl_fixed_to_int(y); + + if (!(event = calloc(1, sizeof(Ecore_Wl_Event_Dnd_Position)))) return; + + if (input->drag_source) + { + if (input->drag_source->input) + { + if (input->drag_source->input->pointer_focus) + event->win = input->drag_source->input->pointer_focus->id; + if (input->drag_source->input->keyboard_focus) + event->source = input->drag_source->input->keyboard_focus->id; + } + } + + event->position.x = input->sx; + event->position.y = input->sy; + + ecore_event_add(ECORE_WL_EVENT_DND_POSITION, event, NULL, NULL); +} + +void +_ecore_wl_dnd_drop(void *data, struct wl_data_device *data_device __UNUSED__) +{ + Ecore_Wl_Event_Dnd_Drop *event; + Ecore_Wl_Input *input; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(input = data)) return; + + if (!(event = calloc(1, sizeof(Ecore_Wl_Event_Dnd_Drop)))) return; + + if (input->drag_source) + { + if (input->drag_source->input) + { + if (input->drag_source->input->pointer_focus) + event->win = input->drag_source->input->pointer_focus->id; + if (input->drag_source->input->keyboard_focus) + event->source = input->drag_source->input->keyboard_focus->id; + } + } + + event->position.x = input->sx; + event->position.y = input->sy; + + ecore_event_add(ECORE_WL_EVENT_DND_DROP, event, NULL, NULL); +} + +void +_ecore_wl_dnd_selection(void *data, struct wl_data_device *data_device __UNUSED__, struct wl_data_offer *offer) +{ + Ecore_Wl_Input *input; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(input = data)) return; + if (input->selection_source) _ecore_wl_dnd_del(input->selection_source); + input->selection_source = NULL; + if (offer) + { + char **p; + + input->selection_source = wl_data_offer_get_user_data(offer); + p = wl_array_add(&input->selection_source->types, sizeof(*p)); + *p = NULL; + } +} + +void +_ecore_wl_dnd_del(Ecore_Wl_Dnd_Source *source) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!source) return; + source->refcount--; + if (source->refcount == 0) + { + char **p; + + wl_data_offer_destroy(source->offer); + for (p = source->types.data; *p; p++) + free(*p); + wl_array_release(&source->types); + free(source); + } +} + +/* local functions */ +static void +_ecore_wl_dnd_offer(void *data, struct wl_data_offer *wl_data_offer __UNUSED__, const char *type) +{ + Ecore_Wl_Dnd_Source *source; + char **p; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(source = data)) return; + p = wl_array_add(&source->types, sizeof(*p)); + *p = strdup(type); +} + +static void +_ecore_wl_dnd_cb_enter_free(void *data __UNUSED__, void *event) +{ + Ecore_Wl_Event_Dnd_Enter *ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(ev = event)) return; + free(ev); +} + +static void +_ecore_wl_dnd_cb_selection_data_ready_free(void *data __UNUSED__, void *event) +{ + Ecore_Wl_Event_Selection_Data_Ready *ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(ev = event)) return; + + free(ev->data); + free(ev); +} + +static Eina_Bool +_ecore_wl_dnd_read_data(void *data, Ecore_Fd_Handler *fd_handler __UNUSED__) +{ + int len; + char buffer[4096]; + Ecore_Wl_Dnd_Source *source; + Ecore_Wl_Event_Selection_Data_Ready *event; + Eina_Bool ret; + + source = data; + + len = read(source->fd, buffer, sizeof buffer); + + if (!(event = calloc(1, sizeof(Ecore_Wl_Event_Selection_Data_Ready)))) + return ECORE_CALLBACK_CANCEL; + + if (len <= 0) + { + close(source->fd); + _ecore_wl_dnd_del(source); + event->done = EINA_TRUE; + event->data = NULL; + event->len = 0; + ret = ECORE_CALLBACK_CANCEL; + } + else + { + event->data = malloc(len + 1); + if (!event->data) return ECORE_CALLBACK_CANCEL; + strncpy(event->data, buffer, len); + event->data[len] = '\0'; + event->len = len; + event->done = EINA_FALSE; + ret = ECORE_CALLBACK_RENEW; + } + + ecore_event_add(ECORE_WL_EVENT_SELECTION_DATA_READY, event, + _ecore_wl_dnd_cb_selection_data_ready_free, NULL); + return ret; +} + + +static Eina_Bool +_ecore_wl_dnd_idler_cb(void *data) +{ + struct _dnd_read_ctx *ctx; + struct _dnd_task *task; + int count, i; + + ctx = data; + count = epoll_wait(ctx->epoll_fd, ctx->ep, 1, 0); + for (i = 0; i < count; i++) + { + task = ctx->ep->data.ptr; + if (task->cb(task->data, NULL) == ECORE_CALLBACK_CANCEL) + { + free(ctx->ep); + free(task); + free(ctx); + return ECORE_CALLBACK_CANCEL; + } + } + return ECORE_CALLBACK_RENEW; +} + +static void +_ecore_wl_dnd_source_receive_data(Ecore_Wl_Dnd_Source *source, const char *type) +{ + int epoll_fd; + struct epoll_event *ep = NULL; + struct _dnd_task *task = NULL; + struct _dnd_read_ctx *read_ctx = NULL; + int p[2]; + + if (pipe2(p, O_CLOEXEC) == -1) + return; + + wl_data_offer_receive(source->offer, type, p[1]); + close(p[1]); + + /* Due to http://trac.enlightenment.org/e/ticket/1208, + * use epoll and idle handler instead of ecore_main_fd_handler_add() */ + + ep = calloc(1, sizeof(struct epoll_event)); + if (!ep) goto err; + + task = calloc(1, sizeof(struct _dnd_task)); + if (!task) goto err; + + read_ctx = calloc(1, sizeof(struct _dnd_read_ctx)); + if (!read_ctx) goto err; + + epoll_fd = epoll_create1(0); + if (epoll_fd < 0) goto err; + + task->data = source; + task->cb = _ecore_wl_dnd_read_data; + ep->events = EPOLLIN; + ep->data.ptr = task; + + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, p[0], ep) < 0) goto err; + + read_ctx->epoll_fd = epoll_fd; + read_ctx->ep = ep; + + if (!ecore_idler_add(_ecore_wl_dnd_idler_cb, read_ctx)) goto err; + + source->refcount++; + source->fd = p[0]; + return; + +err: + if (ep) free(ep); + if (task) free(task); + if (read_ctx) free(read_ctx); + close(p[0]); + return; +} diff --git a/src/lib/ecore_wayland/ecore_wl_input.c b/src/lib/ecore_wayland/ecore_wl_input.c new file mode 100644 index 0000000..ccb4e5b --- /dev/null +++ b/src/lib/ecore_wayland/ecore_wl_input.c @@ -0,0 +1,1210 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +/** + * NB: Events that receive a 'serial' instead of timestamp + * + * input_device_attach (for pointer image) + * input_device_button_event (button press/release) + * input_device_key_press + * input_device_pointer_enter + * input_device_pointer_leave + * input_device_keyboard_enter + * input_device_keyboard_leave + * input_device_touch_down + * input_device_touch_up + * + **/ + +#include "ecore_wl_private.h" +#include +#include + +/* FIXME: This gives BTN_LEFT/RIGHT/MIDDLE for linux systems ... + * What about other OSs ?? */ +#ifdef __linux__ +# include +#else +# define BTN_LEFT 0x110 +# define BTN_RIGHT 0x111 +# define BTN_MIDDLE 0x112 +# define BTN_SIDE 0x113 +# define BTN_EXTRA 0x114 +# define BTN_FORWARD 0x115 +# define BTN_BACK 0x116 +#endif + +#define MOD_SHIFT_MASK 0x01 +#define MOD_ALT_MASK 0x02 +#define MOD_CONTROL_MASK 0x04 + +Ecore_Wl_Dnd *glb_dnd = NULL; + +/* local function prototypes */ +static void _ecore_wl_input_seat_handle_capabilities(void *data, struct wl_seat *seat, enum wl_seat_capability caps); + +static void _ecore_wl_input_cb_pointer_enter(void *data, struct wl_pointer *pointer __UNUSED__, unsigned int serial, struct wl_surface *surface, wl_fixed_t sx, wl_fixed_t sy); +static void _ecore_wl_input_cb_pointer_leave(void *data, struct wl_pointer *pointer __UNUSED__, unsigned int serial, struct wl_surface *surface); +static void _ecore_wl_input_cb_pointer_motion(void *data, struct wl_pointer *pointer __UNUSED__, unsigned int timestamp, wl_fixed_t sx, wl_fixed_t sy); +static void _ecore_wl_input_cb_pointer_button(void *data, struct wl_pointer *pointer __UNUSED__, unsigned int serial, unsigned int timestamp, unsigned int button, unsigned int state); +static void _ecore_wl_input_cb_pointer_axis(void *data, struct wl_pointer *pointer __UNUSED__, unsigned int timestamp, unsigned int axis, wl_fixed_t value); +static void _ecore_wl_input_cb_pointer_frame(void *data, struct wl_callback *callback, unsigned int timestamp __UNUSED__); +static void _ecore_wl_input_cb_keyboard_keymap(void *data, struct wl_keyboard *keyboard __UNUSED__, unsigned int format, int fd, unsigned int size); +static void _ecore_wl_input_cb_keyboard_enter(void *data, struct wl_keyboard *keyboard __UNUSED__, unsigned int serial, struct wl_surface *surface, struct wl_array *keys __UNUSED__); +static void _ecore_wl_input_cb_keyboard_leave(void *data, struct wl_keyboard *keyboard __UNUSED__, unsigned int serial, struct wl_surface *surface); +static void _ecore_wl_input_cb_keyboard_key(void *data, struct wl_keyboard *keyboard __UNUSED__, unsigned int serial, unsigned int timestamp, unsigned int key, unsigned int state); +static void _ecore_wl_input_cb_keyboard_modifiers(void *data, struct wl_keyboard *keyboard __UNUSED__, unsigned int serial __UNUSED__, unsigned int depressed, unsigned int latched, unsigned int locked, unsigned int group); +static Eina_Bool _ecore_wl_input_cb_keyboard_repeat(void *data, Ecore_Fd_Handler *handler __UNUSED__); +static void _ecore_wl_input_cb_touch_down(void *data, struct wl_touch *touch __UNUSED__, unsigned int serial, unsigned int timestamp, struct wl_surface *surface __UNUSED__, int id __UNUSED__, wl_fixed_t x, wl_fixed_t y); +static void _ecore_wl_input_cb_touch_up(void *data, struct wl_touch *touch __UNUSED__, unsigned int serial, unsigned int timestamp, int id __UNUSED__); +static void _ecore_wl_input_cb_touch_motion(void *data, struct wl_touch *touch __UNUSED__, unsigned int timestamp, int id __UNUSED__, wl_fixed_t x, wl_fixed_t y); +static void _ecore_wl_input_cb_touch_frame(void *data __UNUSED__, struct wl_touch *touch __UNUSED__); +static void _ecore_wl_input_cb_touch_cancel(void *data __UNUSED__, struct wl_touch *touch __UNUSED__); +static void _ecore_wl_input_cb_data_offer(void *data, struct wl_data_device *data_device, struct wl_data_offer *offer); +static void _ecore_wl_input_cb_data_enter(void *data, struct wl_data_device *data_device, unsigned int timestamp, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *offer); +static void _ecore_wl_input_cb_data_leave(void *data, struct wl_data_device *data_device); +static void _ecore_wl_input_cb_data_motion(void *data, struct wl_data_device *data_device, unsigned int timestamp, wl_fixed_t x, wl_fixed_t y); +static void _ecore_wl_input_cb_data_drop(void *data, struct wl_data_device *data_device); +static void _ecore_wl_input_cb_data_selection(void *data, struct wl_data_device *data_device, struct wl_data_offer *offer); + +static void _ecore_wl_input_mouse_move_send(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int timestamp); +static void _ecore_wl_input_mouse_in_send(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int timestamp); +static void _ecore_wl_input_mouse_out_send(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int timestamp); +static void _ecore_wl_input_focus_in_send(Ecore_Wl_Input *input __UNUSED__, Ecore_Wl_Window *win, unsigned int timestamp); +static void _ecore_wl_input_focus_out_send(Ecore_Wl_Input *input __UNUSED__, Ecore_Wl_Window *win, unsigned int timestamp); +static void _ecore_wl_input_mouse_down_send(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int timestamp); +static void _ecore_wl_input_mouse_up_send(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int timestamp); +static void _ecore_wl_input_mouse_wheel_send(Ecore_Wl_Input *input, unsigned int axis, int value, unsigned int timestamp); + +/* static int _ecore_wl_input_keysym_to_string(unsigned int symbol, char *buffer, int len); */ + +/* wayland interfaces */ +static const struct wl_pointer_listener pointer_listener = +{ + _ecore_wl_input_cb_pointer_enter, + _ecore_wl_input_cb_pointer_leave, + _ecore_wl_input_cb_pointer_motion, + _ecore_wl_input_cb_pointer_button, + _ecore_wl_input_cb_pointer_axis, +}; + +static const struct wl_keyboard_listener keyboard_listener = +{ + _ecore_wl_input_cb_keyboard_keymap, + _ecore_wl_input_cb_keyboard_enter, + _ecore_wl_input_cb_keyboard_leave, + _ecore_wl_input_cb_keyboard_key, + _ecore_wl_input_cb_keyboard_modifiers, +}; + +static const struct wl_touch_listener touch_listener = +{ + _ecore_wl_input_cb_touch_down, + _ecore_wl_input_cb_touch_up, + _ecore_wl_input_cb_touch_motion, + _ecore_wl_input_cb_touch_frame, + _ecore_wl_input_cb_touch_cancel +}; + +static const struct wl_seat_listener _ecore_wl_seat_listener = +{ + _ecore_wl_input_seat_handle_capabilities, +}; + +static const struct wl_data_device_listener _ecore_wl_data_listener = +{ + _ecore_wl_input_cb_data_offer, + _ecore_wl_input_cb_data_enter, + _ecore_wl_input_cb_data_leave, + _ecore_wl_input_cb_data_motion, + _ecore_wl_input_cb_data_drop, + _ecore_wl_input_cb_data_selection +}; + +static const struct wl_callback_listener _ecore_wl_pointer_surface_listener = +{ + _ecore_wl_input_cb_pointer_frame +}; + +/* local variables */ +static int _pointer_x, _pointer_y; + +EAPI void +ecore_wl_input_grab(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int button) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!input) return; + input->grab = win; + input->grab_button = button; +} + +EAPI void +ecore_wl_input_ungrab(Ecore_Wl_Input *input) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!input) return; + input->grab = NULL; + input->grab_button = 0; +} + +EAPI void +ecore_wl_input_pointer_set(Ecore_Wl_Input *input, struct wl_surface *surface, int hot_x, int hot_y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (input) + wl_pointer_set_cursor(input->pointer, input->pointer_enter_serial, + surface, hot_x, hot_y); +} + +EAPI void +ecore_wl_input_cursor_from_name_set(Ecore_Wl_Input *input, const char *cursor_name) +{ + struct wl_cursor_image *cursor_image; + struct wl_buffer *buffer; + struct wl_cursor *cursor; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!input) return; + + eina_stringshare_replace(&input->cursor_name, cursor_name); + + /* No cursor. Set to default Left Pointer */ + if (!cursor_name) + eina_stringshare_replace(&input->cursor_name, "left_ptr"); + + /* try to get this cursor from the theme */ + if (!(cursor = ecore_wl_cursor_get(input->cursor_name))) + { + /* if the theme does not have this cursor, default to left pointer */ + if (!(cursor = ecore_wl_cursor_get("left_ptr"))) + return; + } + + if ((!cursor->images) || (!cursor->images[0])) + { + ecore_wl_input_pointer_set(input, NULL, 0, 0); + return; + } + + cursor_image = cursor->images[0]; + if ((buffer = wl_cursor_image_get_buffer(cursor_image))) + { + ecore_wl_input_pointer_set(input, input->cursor_surface, + cursor_image->hotspot_x, + cursor_image->hotspot_y); + wl_surface_attach(input->cursor_surface, buffer, 0, 0); + wl_surface_damage(input->cursor_surface, 0, 0, + cursor_image->width, cursor_image->height); + + if (!input->cursor_frame_cb) + _ecore_wl_input_cb_pointer_frame(input, NULL, 0); + } +} + +EAPI void +ecore_wl_input_cursor_default_restore(Ecore_Wl_Input *input) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!input) return; + + /* Restore to default wayland cursor */ + ecore_wl_input_cursor_from_name_set(input, "left_ptr"); +} + +/* local functions */ +void +_ecore_wl_input_add(Ecore_Wl_Display *ewd, unsigned int id) +{ + Ecore_Wl_Input *input; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(input = malloc(sizeof(Ecore_Wl_Input)))) return; + + memset(input, 0, sizeof(Ecore_Wl_Input)); + + input->display = ewd; + input->pointer_focus = NULL; + input->keyboard_focus = NULL; + + input->seat = + wl_display_bind(ewd->wl.display, id, &wl_seat_interface); + wl_list_insert(ewd->inputs.prev, &input->link); + wl_seat_add_listener(input->seat, + &_ecore_wl_seat_listener, input); + wl_seat_set_user_data(input->seat, input); + + input->data_device = + wl_data_device_manager_get_data_device(ewd->wl.data_device_manager, + input->seat); + wl_data_device_add_listener(input->data_device, + &_ecore_wl_data_listener, input); + input->cursor_surface = + wl_compositor_create_surface(_ecore_wl_disp->wl.compositor); + + input->repeat.timerfd = + timerfd_create(CLOCK_MONOTONIC, (TFD_CLOEXEC | TFD_NONBLOCK)); + + input->repeat.hdlr = + ecore_main_fd_handler_add(input->repeat.timerfd, ECORE_FD_READ, + _ecore_wl_input_cb_keyboard_repeat, input, + NULL, NULL); + + ewd->input = input; + + /* create Ecore_Wl_Dnd */ + if (!glb_dnd) + if (!(glb_dnd = calloc(1, sizeof(Ecore_Wl_Dnd)))) return; + glb_dnd->ewd = ewd; + glb_dnd->input = input; + input->dnd = glb_dnd; + wl_array_init(&glb_dnd->types_offered); +} + +void +_ecore_wl_input_del(Ecore_Wl_Input *input) +{ + if (!input) return; + + if (input->cursor_name) eina_stringshare_del(input->cursor_name); + input->cursor_name = NULL; + + if (input->keyboard_focus) + { + Ecore_Wl_Window *win = NULL; + + if ((win = input->keyboard_focus)) + win->keyboard_device = NULL; + + input->keyboard_focus = NULL; + } + + if (input->drag_source) _ecore_wl_dnd_del(input->drag_source); + input->drag_source = NULL; + + if (input->selection_source) _ecore_wl_dnd_del(input->selection_source); + input->selection_source = NULL; + + if (input->data_device) wl_data_device_destroy(input->data_device); + + if (input->xkb.state) + xkb_state_unref(input->xkb.state); + if (input->xkb.keymap) + xkb_map_unref(input->xkb.keymap); + + if (input->cursor_surface) + wl_surface_destroy(input->cursor_surface); + + wl_list_remove(&input->link); + if (input->seat) wl_seat_destroy(input->seat); + + if (input->repeat.hdlr) ecore_main_fd_handler_del(input->repeat.hdlr); + input->repeat.hdlr = NULL; + + if (input->repeat.timerfd) close(input->repeat.timerfd); + input->repeat.timerfd = 0; + + free(input); +} + +void +_ecore_wl_input_pointer_xy_get(int *x, int *y) +{ + if (x) *x = _pointer_x; + if (y) *y = _pointer_y; +} + +static void +_ecore_wl_input_seat_handle_capabilities(void *data, struct wl_seat *seat, enum wl_seat_capability caps) +{ + Ecore_Wl_Input *input; + + if (!(input = data)) return; + if ((caps & WL_SEAT_CAPABILITY_POINTER) && (!input->pointer)) + { + input->pointer = wl_seat_get_pointer(seat); + wl_pointer_set_user_data(input->pointer, input); + wl_pointer_add_listener(input->pointer, &pointer_listener, input); + } + else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && (input->pointer)) + { + wl_pointer_destroy(input->pointer); + input->pointer = NULL; + } + + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && (!input->keyboard)) + { + input->keyboard = wl_seat_get_keyboard(seat); + wl_keyboard_set_user_data(input->keyboard, input); + wl_keyboard_add_listener(input->keyboard, &keyboard_listener, input); + } + else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && (input->keyboard)) + { + wl_keyboard_destroy(input->keyboard); + input->keyboard = NULL; + } + + if ((caps & WL_SEAT_CAPABILITY_TOUCH) && (!input->touch)) + { + input->touch = wl_seat_get_touch(seat); + wl_touch_set_user_data(input->touch, input); + wl_touch_add_listener(input->touch, &touch_listener, input); + } + else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && (input->touch)) + { + wl_touch_destroy(input->touch); + input->touch = NULL; + } +} + + +static void +_ecore_wl_input_cb_pointer_motion(void *data, struct wl_pointer *pointer __UNUSED__, unsigned int timestamp, wl_fixed_t sx, wl_fixed_t sy) +{ + Ecore_Wl_Input *input; + + /* LOGFN(__FILE__, __LINE__, __FUNCTION__); */ + + if (!(input = data)) return; + + _pointer_x = input->sx = wl_fixed_to_int(sx); + _pointer_y = input->sy = wl_fixed_to_int(sy); + + input->timestamp = timestamp; + + if (input->pointer_focus) + _ecore_wl_input_mouse_move_send(input, input->pointer_focus, timestamp); + + ecore_wl_input_cursor_from_name_set(input, input->cursor_name); +} + +static void +_ecore_wl_input_cb_pointer_button(void *data, struct wl_pointer *pointer __UNUSED__, unsigned int serial, unsigned int timestamp, unsigned int button, unsigned int state) +{ + Ecore_Wl_Input *input; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(input = data)) return; + + input->timestamp = timestamp; + input->display->serial = serial; + +// _ecore_wl_input_mouse_move_send(input, input->pointer_focus, timestamp); + + if (state) + { + if ((input->pointer_focus) && (!input->grab) && (state)) + ecore_wl_input_grab(input, input->pointer_focus, button); + + input->button = button; + _ecore_wl_input_mouse_down_send(input, input->pointer_focus, + timestamp); + } + else + { + _ecore_wl_input_mouse_up_send(input, input->pointer_focus, + timestamp); + input->button = 0; + + if ((input->grab) && (input->grab_button == button) && (!state)) + ecore_wl_input_ungrab(input); + } + +// _ecore_wl_input_mouse_move_send(input, timestamp); +} + +static void +_ecore_wl_input_cb_pointer_axis(void *data, struct wl_pointer *pointer __UNUSED__, unsigned int timestamp, unsigned int axis, wl_fixed_t value) +{ + Ecore_Wl_Input *input; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(input = data)) return; + _ecore_wl_input_mouse_wheel_send(input, axis, wl_fixed_to_int(value), + timestamp); +} + +static void +_ecore_wl_input_cb_pointer_frame(void *data, struct wl_callback *callback, unsigned int timestamp __UNUSED__) +{ + Ecore_Wl_Input *input; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(input = data)) return; + + if (callback) + { + if (callback != input->cursor_frame_cb) return; + wl_callback_destroy(callback); + input->cursor_frame_cb = NULL; + } + + if (!input->cursor_name) + { + ecore_wl_input_pointer_set(input, NULL, 0, 0); + return; + } + + if (!input->cursor_frame_cb) + { + input->cursor_frame_cb = wl_surface_frame(input->cursor_surface); + wl_callback_add_listener(input->cursor_frame_cb, + &_ecore_wl_pointer_surface_listener, input); + } +} + +static void +_ecore_wl_input_cb_keyboard_keymap(void *data, struct wl_keyboard *keyboard __UNUSED__, unsigned int format, int fd, unsigned int size) +{ + Ecore_Wl_Input *input; + char *map = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(input = data)) + { + close(fd); + return; + } + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) + { + close(fd); + return; + } + + map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (map == MAP_FAILED) + { + close(fd); + return; + } + + input->xkb.keymap = + xkb_map_new_from_string(input->display->xkb.context, map, + XKB_KEYMAP_FORMAT_TEXT_V1, 0); + + munmap(map, size); + close(fd); + + if (!(input->xkb.keymap)) return; + if (!(input->xkb.state = xkb_state_new(input->xkb.keymap))) + { + xkb_map_unref(input->xkb.keymap); + input->xkb.keymap = NULL; + return; + } + + input->xkb.control_mask = + 1 << xkb_map_mod_get_index(input->xkb.keymap, "Control"); + input->xkb.alt_mask = + 1 << xkb_map_mod_get_index(input->xkb.keymap, "Mod1"); + input->xkb.shift_mask = + 1 << xkb_map_mod_get_index(input->xkb.keymap, "Shift"); +} + +static void +_ecore_wl_input_cb_keyboard_key(void *data, struct wl_keyboard *keyboard __UNUSED__, unsigned int serial, unsigned int timestamp, unsigned int keycode, unsigned int state) +{ + Ecore_Wl_Input *input; + Ecore_Wl_Window *win; + unsigned int code, num; + const xkb_keysym_t *syms; + xkb_keysym_t sym = XKB_KEY_NoSymbol; + xkb_mod_mask_t mask; + char string[32], key[32], keyname[32];// compose[32]; + Ecore_Event_Key *e; + struct itimerspec ts; + int len = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(input = data)) return; + input->display->serial = serial; + + /* xkb rules reflect X broken keycodes, so offset by 8 */ + code = keycode + 8; + + win = input->keyboard_focus; + if ((!win) || (win->keyboard_device != input) || (!input->xkb.state)) + return; + + mask = xkb_state_serialize_mods(input->xkb.state, + XKB_STATE_DEPRESSED | XKB_STATE_LATCHED); + + input->modifiers = 0; + + /* The Ecore_Event_Modifiers don't quite match the X mask bits */ + if (mask & input->xkb.control_mask) + input->modifiers |= MOD_CONTROL_MASK; + if (mask & input->xkb.alt_mask) + input->modifiers |= MOD_ALT_MASK; + if (mask & input->xkb.shift_mask) + input->modifiers |= MOD_SHIFT_MASK; + + num = xkb_key_get_syms(input->xkb.state, code, &syms); + if (num == 1) sym = syms[0]; + + memset(key, 0, sizeof(key)); + xkb_keysym_get_name(sym, key, sizeof(key)); + + memset(keyname, 0, sizeof(keyname)); + xkb_keysym_get_name(sym, keyname, sizeof(keyname)); + if (keyname[0] == '\0') + snprintf(keyname, sizeof(keyname), "Keycode-%i", code); + + memset(string, 0, sizeof(string)); + if (xkb_keysym_to_utf8(sym, string, 32) <= 0) + { + /* FIXME: NB: We may need to add more checks here for other + * non-printable characters */ + if ((sym == XKB_KEY_Tab) || (sym == XKB_KEY_ISO_Left_Tab)) + string[len++] = '\t'; + } + + /* FIXME: NB: Start hacking on compose key support */ + /* memset(compose, 0, sizeof(compose)); */ + /* if (sym == XKB_KEY_Multi_key) */ + /* { */ + /* if (xkb_keysym_to_utf8(sym, compose, 32) <= 0) */ + /* compose[0] = '\0'; */ + /* } */ + + e = malloc(sizeof(Ecore_Event_Key) + strlen(key) + strlen(keyname) + + ((string[0] != '\0') ? strlen(string) : 0) + 3); + if (!e) return; + + e->keyname = (char *)(e + 1); + e->key = e->keyname + strlen(keyname) + 1; + e->string = strlen(string) ? e->key + strlen(key) + 1 : NULL; + e->compose = e->string; + + strcpy((char *)e->keyname, keyname); + strcpy((char *)e->key, key); + if (strlen(string)) strcpy((char *)e->string, string); + + e->window = win->id; + e->event_window = win->id; + e->timestamp = timestamp; + e->modifiers = input->modifiers; + + if (state) + ecore_event_add(ECORE_EVENT_KEY_DOWN, e, NULL, NULL); + else + ecore_event_add(ECORE_EVENT_KEY_UP, e, NULL, NULL); + + if ((!state) && (keycode == input->repeat.key)) + { + input->repeat.sym = 0; + input->repeat.key = 0; + input->repeat.time = 0; + + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 0; + ts.it_value.tv_sec = 0; + ts.it_value.tv_nsec = 0; + + timerfd_settime(input->repeat.timerfd, 0, &ts, NULL); + } + else if ((state) && + ((!input->repeat.key) || + ((keycode) && (keycode != input->repeat.key)))) + { + input->repeat.sym = sym; + input->repeat.key = keycode; + input->repeat.time = timestamp; + + /* interval after expires */ + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 35 * 1000 * 1000; + + /* initial expiration */ + ts.it_value.tv_sec = 0; + ts.it_value.tv_nsec = 500 * 1000 * 1000; + + timerfd_settime(input->repeat.timerfd, 0, &ts, NULL); + } +} + +static void +_ecore_wl_input_cb_keyboard_modifiers(void *data, struct wl_keyboard *keyboard __UNUSED__, unsigned int serial __UNUSED__, unsigned int depressed, unsigned int latched, unsigned int locked, unsigned int group) +{ + Ecore_Wl_Input *input; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(input = data)) return; + xkb_state_update_mask(input->xkb.state, depressed, latched, + locked, 0, 0, group); +} + +static Eina_Bool +_ecore_wl_input_cb_keyboard_repeat(void *data, Ecore_Fd_Handler *handler __UNUSED__) +{ + Ecore_Wl_Input *input; + Ecore_Wl_Window *win = NULL; + unsigned long long int xp; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(input = data)) return ECORE_CALLBACK_RENEW; + + /* Trap for EAGAIN */ + if (read(input->repeat.timerfd, &xp, sizeof(xp)) != sizeof(xp)) + return ECORE_CALLBACK_RENEW; + + if ((win = input->keyboard_focus)) + _ecore_wl_input_cb_keyboard_key(input, NULL, input->display->serial, + input->repeat.time, + input->repeat.key, EINA_TRUE); + + return ECORE_CALLBACK_RENEW; +} + +static void +_ecore_wl_input_cb_pointer_enter(void *data, struct wl_pointer *pointer __UNUSED__, unsigned int serial, struct wl_surface *surface, wl_fixed_t sx, wl_fixed_t sy) +{ + Ecore_Wl_Input *input; + Ecore_Wl_Window *win = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!surface) return; + if (!(input = data)) return; + + if (!input->timestamp) + { + struct timeval tv; + + gettimeofday(&tv, NULL); + input->timestamp = (tv.tv_sec * 1000 + tv.tv_usec / 1000); + } + + input->sx = wl_fixed_to_double(sx); + input->sy = wl_fixed_to_double(sy); + input->display->serial = serial; + input->pointer_enter_serial = serial; + + if (!(win = wl_surface_get_user_data(surface))) return; + + win->pointer_device = input; + input->pointer_focus = win; + + /* _ecore_wl_input_mouse_move_send(input, win, input->timestamp); */ + _ecore_wl_input_mouse_in_send(input, win, input->timestamp); + + /* The cursor on the surface is undefined until we set it */ + ecore_wl_input_cursor_from_name_set(input, "left_ptr"); + + /* NB: This whole 'if' below is a major HACK due to wayland's stupidness + * of not sending a mouse_up (or any notification at all for that matter) + * when a move or resize grab is finished */ + if (input->grab) + { + /* NB: This COULD mean a move has finished, or it could mean that + * a 'drag' is being done to a different surface */ + + if ((input->grab == win) && (win->moving)) + { + /* NB: 'Fake' a mouse_up for move finished */ + win->moving = EINA_FALSE; + _ecore_wl_input_mouse_up_send(input, win, input->timestamp); + + input->button = 0; + + if ((input->grab) && (input->grab_button == BTN_LEFT)) + ecore_wl_input_ungrab(input); + } + else if ((input->grab == win) && (win->resizing)) + { + /* NB: 'Fake' a mouse_up for resize finished */ + win->resizing = EINA_FALSE; + _ecore_wl_input_mouse_up_send(input, win, input->timestamp); + + input->button = 0; + + if ((input->grab) && (input->grab_button == BTN_LEFT)) + ecore_wl_input_ungrab(input); + } + /* FIXME: Test d-n-d and potentially add needed case here */ + } +} + +static void +_ecore_wl_input_cb_pointer_leave(void *data, struct wl_pointer *pointer __UNUSED__, unsigned int serial, struct wl_surface *surface) +{ + Ecore_Wl_Input *input; + Ecore_Wl_Window *win; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!surface) return; + if (!(input = data)) return; + + input->display->serial = serial; + + if (!surface) return; + if (!(win = wl_surface_get_user_data(surface))) return; + + win->pointer_device = NULL; + input->pointer_focus = NULL; + + /* _ecore_wl_input_mouse_move_send(input, win, input->timestamp); */ + _ecore_wl_input_mouse_out_send(input, win, input->timestamp); + + if (input->grab) + { + /* move or resize started */ + + /* printf("Pointer Leave WITH a Grab\n"); */ + } +} + +static void +_ecore_wl_input_cb_keyboard_enter(void *data, struct wl_keyboard *keyboard __UNUSED__, unsigned int serial, struct wl_surface *surface, struct wl_array *keys __UNUSED__) +{ + Ecore_Wl_Input *input; + Ecore_Wl_Window *win = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!surface) return; + if (!(input = data)) return; + + if (!input->timestamp) + { + struct timeval tv; + + gettimeofday(&tv, NULL); + input->timestamp = (tv.tv_sec * 1000 + tv.tv_usec / 1000); + } + + input->display->serial = serial; + + if (!(win = wl_surface_get_user_data(surface))) return; + + win->keyboard_device = input; + input->keyboard_focus = win; + + _ecore_wl_input_focus_in_send(input, win, input->timestamp); +} + +static void +_ecore_wl_input_cb_keyboard_leave(void *data, struct wl_keyboard *keyboard __UNUSED__, unsigned int serial, struct wl_surface *surface) +{ + Ecore_Wl_Input *input; + Ecore_Wl_Window *win; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!surface) return; + if (!(input = data)) return; + + if (input->repeat.timerfd) + { + struct itimerspec ts; + + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 0; + ts.it_value.tv_sec = 0; + ts.it_value.tv_nsec = 0; + + timerfd_settime(input->repeat.timerfd, 0, &ts, NULL); + } + + if (!input->timestamp) + { + struct timeval tv; + + gettimeofday(&tv, NULL); + input->timestamp = (tv.tv_sec * 1000 + tv.tv_usec / 1000); + } + + input->display->serial = serial; + + if (!surface) return; + if (!(win = wl_surface_get_user_data(surface))) return; + + win->keyboard_device = NULL; + _ecore_wl_input_focus_out_send(input, win, input->timestamp); + + input->keyboard_focus = NULL; +} + +static void +_ecore_wl_input_cb_touch_down(void *data, struct wl_touch *touch __UNUSED__, unsigned int serial, unsigned int timestamp, struct wl_surface *surface __UNUSED__, int id __UNUSED__, wl_fixed_t x, wl_fixed_t y) +{ + Ecore_Wl_Input *input; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!surface) return; + if (!(input = data)) return; + + /* FIXME: NB: Not sure yet if input->timestamp should be set here. + * This needs to be tested with an actual touch device */ + /* input->timestamp = timestamp; */ + input->display->serial = serial; + input->button = BTN_LEFT; + input->sx = wl_fixed_to_int(x); + input->sy = wl_fixed_to_int(y); + _ecore_wl_input_cb_pointer_enter(data, NULL, serial, surface, x, y); + _ecore_wl_input_mouse_down_send(input, input->pointer_focus, timestamp); +} + +static void +_ecore_wl_input_cb_touch_up(void *data, struct wl_touch *touch __UNUSED__, unsigned int serial, unsigned int timestamp, int id __UNUSED__) +{ + Ecore_Wl_Input *input; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(input = data)) return; + + /* FIXME: NB: Not sure yet if input->timestamp should be set here. + * This needs to be tested with an actual touch device */ + /* input->timestamp = timestamp; */ + input->button = BTN_LEFT; + input->display->serial = serial; + _ecore_wl_input_mouse_up_send(input, input->pointer_focus, timestamp); + input->button = 0; +} + +static void +_ecore_wl_input_cb_touch_motion(void *data, struct wl_touch *touch __UNUSED__, unsigned int timestamp, int id __UNUSED__, wl_fixed_t x, wl_fixed_t y) +{ + Ecore_Wl_Input *input; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(input = data)) return; + + /* FIXME: NB: Not sure yet if input->timestamp should be set here. + * This needs to be tested with an actual touch device */ + /* input->timestamp = timestamp; */ + input->sx = wl_fixed_to_int(x); + input->sy = wl_fixed_to_int(y); + + _ecore_wl_input_mouse_move_send(input, input->pointer_focus, timestamp); +} + +static void +_ecore_wl_input_cb_touch_frame(void *data __UNUSED__, struct wl_touch *touch __UNUSED__) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); +} + +static void +_ecore_wl_input_cb_touch_cancel(void *data __UNUSED__, struct wl_touch *touch __UNUSED__) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); +} + +static void +_ecore_wl_input_cb_data_offer(void *data, struct wl_data_device *data_device, struct wl_data_offer *offer) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_wl_dnd_add(data, data_device, offer); +} + +static void +_ecore_wl_input_cb_data_enter(void *data, struct wl_data_device *data_device, unsigned int timestamp, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *offer) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!surface) return; + + _ecore_wl_dnd_enter(data, data_device, timestamp, surface, x, y, offer); +} + +static void +_ecore_wl_input_cb_data_leave(void *data, struct wl_data_device *data_device) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_wl_dnd_leave(data, data_device); +} + +static void +_ecore_wl_input_cb_data_motion(void *data, struct wl_data_device *data_device, unsigned int timestamp, wl_fixed_t x, wl_fixed_t y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_wl_dnd_motion(data, data_device, timestamp, x, y); +} + +static void +_ecore_wl_input_cb_data_drop(void *data, struct wl_data_device *data_device) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_wl_dnd_drop(data, data_device); +} + +static void +_ecore_wl_input_cb_data_selection(void *data, struct wl_data_device *data_device, struct wl_data_offer *offer) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_wl_dnd_selection(data, data_device, offer); +} + +static void +_ecore_wl_input_mouse_move_send(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int timestamp) +{ + Ecore_Event_Mouse_Move *ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(ev = malloc(sizeof(Ecore_Event_Mouse_Move)))) return; + + ev->timestamp = timestamp; + ev->x = input->sx; + ev->y = input->sy; + /* ev->root.x = input->sx; */ + /* ev->root.y = input->sy; */ + ev->modifiers = input->modifiers; + ev->multi.device = 0; + ev->multi.radius = 1; + ev->multi.radius_x = 1; + ev->multi.radius_y = 1; + ev->multi.pressure = 1.0; + ev->multi.angle = 0.0; + ev->multi.x = input->sx; + ev->multi.y = input->sy; + + if (win) + { + ev->window = win->id; + ev->event_window = win->id; + } + + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, ev, NULL, NULL); +} + +static void +_ecore_wl_input_mouse_in_send(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int timestamp) +{ + Ecore_Wl_Event_Mouse_In *ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(ev = calloc(1, sizeof(Ecore_Wl_Event_Mouse_In)))) return; + + ev->x = input->sx; + ev->y = input->sy; + /* ev->root.x = input->sx; */ + /* ev->root.y = input->sy; */ + ev->modifiers = input->modifiers; + ev->timestamp = timestamp; + + if (win) + { + ev->window = win->id; + ev->event_window = win->id; + } + + ecore_event_add(ECORE_WL_EVENT_MOUSE_IN, ev, NULL, NULL); +} + +static void +_ecore_wl_input_mouse_out_send(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int timestamp) +{ + Ecore_Wl_Event_Mouse_Out *ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(ev = calloc(1, sizeof(Ecore_Wl_Event_Mouse_Out)))) return; + + ev->x = input->sx; + ev->y = input->sy; + /* ev->root.x = input->sx; */ + /* ev->root.y = input->sy; */ + ev->modifiers = input->modifiers; + ev->timestamp = timestamp; + + if (win) + { + ev->window = win->id; + ev->event_window = win->id; + } + + ecore_event_add(ECORE_WL_EVENT_MOUSE_OUT, ev, NULL, NULL); +} + +static void +_ecore_wl_input_focus_in_send(Ecore_Wl_Input *input __UNUSED__, Ecore_Wl_Window *win, unsigned int timestamp) +{ + Ecore_Wl_Event_Focus_In *ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(ev = calloc(1, sizeof(Ecore_Wl_Event_Focus_In)))) return; + ev->timestamp = timestamp; + if (win) ev->win = win->id; + ecore_event_add(ECORE_WL_EVENT_FOCUS_IN, ev, NULL, NULL); +} + +static void +_ecore_wl_input_focus_out_send(Ecore_Wl_Input *input __UNUSED__, Ecore_Wl_Window *win, unsigned int timestamp) +{ + Ecore_Wl_Event_Focus_Out *ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(ev = calloc(1, sizeof(Ecore_Wl_Event_Focus_Out)))) return; + ev->timestamp = timestamp; + if (win) ev->win = win->id; + ecore_event_add(ECORE_WL_EVENT_FOCUS_OUT, ev, NULL, NULL); +} + +static void +_ecore_wl_input_mouse_down_send(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int timestamp) +{ + Ecore_Event_Mouse_Button *ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(ev = malloc(sizeof(Ecore_Event_Mouse_Button)))) return; + + if (input->button == BTN_LEFT) + ev->buttons = 1; + else if (input->button == BTN_MIDDLE) + ev->buttons = 2; + else if (input->button == BTN_RIGHT) + ev->buttons = 3; + else + ev->buttons = input->button; + + ev->timestamp = timestamp; + ev->x = input->sx; + ev->y = input->sy; + /* ev->root.x = input->sx; */ + /* ev->root.y = input->sy; */ + ev->modifiers = input->modifiers; + + /* FIXME: Need to get these from wayland somehow */ + ev->double_click = 0; + ev->triple_click = 0; + + ev->multi.device = 0; + ev->multi.radius = 1; + ev->multi.radius_x = 1; + ev->multi.radius_y = 1; + ev->multi.pressure = 1.0; + ev->multi.angle = 0.0; + ev->multi.x = input->sx; + ev->multi.y = input->sy; + + if (win) + { + ev->window = win->id; + ev->event_window = win->id; + } + + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, ev, NULL, NULL); +} + +static void +_ecore_wl_input_mouse_up_send(Ecore_Wl_Input *input, Ecore_Wl_Window *win, unsigned int timestamp) +{ + Ecore_Event_Mouse_Button *ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(ev = malloc(sizeof(Ecore_Event_Mouse_Button)))) return; + + if (input->button == BTN_LEFT) + ev->buttons = 1; + else if (input->button == BTN_MIDDLE) + ev->buttons = 2; + else if (input->button == BTN_RIGHT) + ev->buttons = 3; + else + ev->buttons = input->button; + + ev->timestamp = timestamp; + ev->x = input->sx; + ev->y = input->sy; + /* ev->root.x = input->sx; */ + /* ev->root.y = input->sy; */ + ev->modifiers = input->modifiers; + + /* FIXME: Need to get these from wayland somehow */ + ev->double_click = 0; + ev->triple_click = 0; + + ev->multi.device = 0; + ev->multi.radius = 1; + ev->multi.radius_x = 1; + ev->multi.radius_y = 1; + ev->multi.pressure = 1.0; + ev->multi.angle = 0.0; + ev->multi.x = input->sx; + ev->multi.y = input->sy; + + if (win) + { + ev->window = win->id; + ev->event_window = win->id; + } + + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, ev, NULL, NULL); +} + +static void +_ecore_wl_input_mouse_wheel_send(Ecore_Wl_Input *input, unsigned int axis, int value, unsigned int timestamp) +{ + Ecore_Event_Mouse_Wheel *ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(ev = malloc(sizeof(Ecore_Event_Mouse_Wheel)))) return; + + ev->timestamp = timestamp; + ev->modifiers = input->modifiers; + ev->x = input->sx; + ev->y = input->sy; + /* ev->root.x = input->sx; */ + /* ev->root.y = input->sy; */ + + if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) + { + ev->direction = 0; + ev->z = -value; + } + else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) + { + ev->direction = 1; + ev->z = -value; + } + + if (input->grab) + { + ev->window = input->grab->id; + ev->event_window = input->grab->id; + } + else if (input->pointer_focus) + { + ev->window = input->pointer_focus->id; + ev->event_window = input->pointer_focus->id; + } + + ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, ev, NULL, NULL); +} + +void +_ecore_wl_input_set_selection(Ecore_Wl_Input *input, struct wl_data_source *source) +{ + wl_data_device_set_selection(input->data_device, source, input->display->serial); +} diff --git a/src/lib/ecore_wayland/ecore_wl_output.c b/src/lib/ecore_wayland/ecore_wl_output.c new file mode 100644 index 0000000..5e6c38d --- /dev/null +++ b/src/lib/ecore_wayland/ecore_wl_output.c @@ -0,0 +1,85 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "ecore_wl_private.h" + +/* local function prototypes */ +static void _ecore_wl_output_cb_geometry(void *data, struct wl_output *wl_output __UNUSED__, int x, int y, int w, int h, int subpixel __UNUSED__, const char *make __UNUSED__, const char *model __UNUSED__, int transform __UNUSED__); +static void _ecore_wl_output_cb_mode(void *data, struct wl_output *wl_output __UNUSED__, unsigned int flags, int w, int h, int refresh __UNUSED__); + +/* wayland listeners */ +static const struct wl_output_listener _ecore_wl_output_listener = +{ + _ecore_wl_output_cb_geometry, + _ecore_wl_output_cb_mode +}; + +/* @since 1.2 */ +EAPI struct wl_list +ecore_wl_outputs_get(void) +{ + return _ecore_wl_disp->outputs; +} + +void +_ecore_wl_output_add(Ecore_Wl_Display *ewd, unsigned int id) +{ + Ecore_Wl_Output *output; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(output = malloc(sizeof(Ecore_Wl_Output)))) return; + + memset(output, 0, sizeof(Ecore_Wl_Output)); + + output->display = ewd; + + output->output = wl_display_bind(ewd->wl.display, id, &wl_output_interface); + wl_list_insert(ewd->outputs.prev, &output->link); + wl_output_add_listener(output->output, &_ecore_wl_output_listener, output); +} + +void +_ecore_wl_output_del(Ecore_Wl_Output *output) +{ + if (!output) return; + if (output->destroy) (*output->destroy)(output, output->data); + if (output->output) wl_output_destroy(output->output); + wl_list_remove(&output->link); + free(output); +} + +/* local functions */ +static void +_ecore_wl_output_cb_geometry(void *data, struct wl_output *wl_output __UNUSED__, int x, int y, int w, int h, int subpixel __UNUSED__, const char *make __UNUSED__, const char *model __UNUSED__, int transform __UNUSED__) +{ + Ecore_Wl_Output *output; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + output = data; + output->allocation.x = x; + output->allocation.y = y; + output->mw = w; + output->mh = h; +} + +static void +_ecore_wl_output_cb_mode(void *data, struct wl_output *wl_output __UNUSED__, unsigned int flags, int w, int h, int refresh __UNUSED__) +{ + Ecore_Wl_Output *output; + Ecore_Wl_Display *ewd; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + output = data; + ewd = output->display; + if (flags & WL_OUTPUT_MODE_CURRENT) + { + output->allocation.w = w; + output->allocation.h = h; + _ecore_wl_disp->output = output; + if (ewd->output_configure) (*ewd->output_configure)(output, ewd->data); + } +} diff --git a/src/lib/ecore_wayland/ecore_wl_private.h b/src/lib/ecore_wayland/ecore_wl_private.h new file mode 100644 index 0000000..7f59ae9 --- /dev/null +++ b/src/lib/ecore_wayland/ecore_wl_private.h @@ -0,0 +1,103 @@ +#ifndef _ECORE_WAYLAND_PRIVATE_H +# define _ECORE_WAYLAND_PRIVATE_H + +# include +# include + +# include "Ecore.h" +# include "Ecore_Input.h" +# include "Ecore_Wayland.h" + +//# define LOGFNS 1 + +# ifdef LOGFNS +# include +# define LOGFN(fl, ln, fn) printf("-ECORE-WL: %25s: %5i - %s\n", fl, ln, fn); +# else +# define LOGFN(fl, ln, fn) +# endif + +extern int _ecore_wl_log_dom; +extern Ecore_Wl_Display *_ecore_wl_disp; + +# ifdef ECORE_WL_DEFAULT_LOG_COLOR +# undef ECORE_WL_DEFAULT_LOG_COLOR +# endif +# define ECORE_WL_DEFAULT_LOG_COLOR EINA_COLOR_BLUE + +# ifdef ERR +# undef ERR +# endif +# define ERR(...) EINA_LOG_DOM_ERR(_ecore_wl_log_dom, __VA_ARGS__) + +# ifdef DBG +# undef DBG +# endif +# define DBG(...) EINA_LOG_DOM_DBG(_ecore_wl_log_dom, __VA_ARGS__) + +# ifdef INF +# undef INF +# endif +# define INF(...) EINA_LOG_DOM_INFO(_ecore_wl_log_dom, __VA_ARGS__) + +# ifdef WRN +# undef WRN +# endif +# define WRN(...) EINA_LOG_DOM_WARN(_ecore_wl_log_dom, __VA_ARGS__) + +# ifdef CRIT +# undef CRIT +# endif +# define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_wl_log_dom, __VA_ARGS__) + +struct _Ecore_Wl_Dnd +{ + Ecore_Wl_Display *ewd; + Ecore_Wl_Input *input; + + /* As provider */ + struct wl_data_source *data_source; + struct wl_array types_offered; + + /* TODO: dnd specific fields */ +}; + +struct _Ecore_Wl_Dnd_Source +{ + struct wl_data_offer *offer; + Ecore_Wl_Input *input; + struct wl_array types; + int refcount; + int fd; + int x, y; + + /* TODO: task & data_func */ + void *data; +}; + +struct _Ecore_Wl_Dnd_Target +{ + Ecore_Wl_Dnd_Source *source; +}; + +void _ecore_wl_window_init(void); +void _ecore_wl_window_shutdown(void); + +void _ecore_wl_output_add(Ecore_Wl_Display *ewd, unsigned int id); +void _ecore_wl_output_del(Ecore_Wl_Output *output); + +void _ecore_wl_input_add(Ecore_Wl_Display *ewd, unsigned int id); +void _ecore_wl_input_del(Ecore_Wl_Input *input); +void _ecore_wl_input_pointer_xy_get(int *x, int *y); +void _ecore_wl_input_set_selection(Ecore_Wl_Input *input, struct wl_data_source *source); + +void _ecore_wl_dnd_add(Ecore_Wl_Input *input, struct wl_data_device *data_device, struct wl_data_offer *offer); +void _ecore_wl_dnd_enter(void *data, struct wl_data_device *data_device __UNUSED__, unsigned int timestamp __UNUSED__, struct wl_surface *surface, int x, int y, struct wl_data_offer *offer); +void _ecore_wl_dnd_leave(void *data, struct wl_data_device *data_device __UNUSED__); +void _ecore_wl_dnd_motion(void *data, struct wl_data_device *data_device __UNUSED__, unsigned int timestamp __UNUSED__, int x, int y); +void _ecore_wl_dnd_drop(void *data, struct wl_data_device *data_device __UNUSED__); +void _ecore_wl_dnd_selection(void *data, struct wl_data_device *data_device __UNUSED__, struct wl_data_offer *offer); +void _ecore_wl_dnd_del(Ecore_Wl_Dnd_Source *source); + +struct wl_data_source *_ecore_wl_create_data_source(Ecore_Wl_Display *ewd); +#endif diff --git a/src/lib/ecore_wayland/ecore_wl_window.c b/src/lib/ecore_wayland/ecore_wl_window.c new file mode 100644 index 0000000..76524ac --- /dev/null +++ b/src/lib/ecore_wayland/ecore_wl_window.c @@ -0,0 +1,703 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "ecore_wl_private.h" + +/* local function prototypes */ +static void _ecore_wl_window_cb_ping(void *data __UNUSED__, struct wl_shell_surface *shell_surface, unsigned int serial); +static void _ecore_wl_window_cb_configure(void *data, struct wl_shell_surface *shell_surface __UNUSED__, unsigned int edges, int w, int h); +static void _ecore_wl_window_cb_popup_done(void *data, struct wl_shell_surface *shell_surface __UNUSED__); +static void _ecore_wl_window_cb_surface_enter(void *data, struct wl_surface *surface, struct wl_output *output __UNUSED__); +static void _ecore_wl_window_cb_surface_leave(void *data, struct wl_surface *surface, struct wl_output *output __UNUSED__); +static void _ecore_wl_window_configure_send(Ecore_Wl_Window *win, int w, int h); +static char *_ecore_wl_window_id_str_get(unsigned int win_id); + +/* local variables */ +static Eina_Hash *_windows = NULL; + +/* wayland listeners */ +static const struct wl_surface_listener _ecore_wl_surface_listener = +{ + _ecore_wl_window_cb_surface_enter, + _ecore_wl_window_cb_surface_leave +}; + +static const struct wl_shell_surface_listener _ecore_wl_shell_surface_listener = +{ + _ecore_wl_window_cb_ping, + _ecore_wl_window_cb_configure, + _ecore_wl_window_cb_popup_done +}; + +/* internal functions */ +void +_ecore_wl_window_init(void) +{ + if (!_windows) + _windows = eina_hash_string_superfast_new(NULL); +} + +void +_ecore_wl_window_shutdown(void) +{ + eina_hash_free(_windows); + _windows = NULL; +} + +/** + * @defgroup Ecore_Wl_Window_Group Wayland Library Init and Shutdown Functions + * + * Functions that can be used to create a Wayland window. + */ + +/** + * Creates a new window + * + * @param parent The parent window to use. If @p parent is @c 0, the root window + * of the default display is used. + * @param x X Position + * @param y Y position + * @param w Width + * @param h Height + * @param buffer_type The type of the buffer to be used to create a new Ecore_Wl_Window. + * + * @return The new window + * + * @ingroup Ecore_Wl_Window_Group + * @since 1.2 + */ +EAPI Ecore_Wl_Window * +ecore_wl_window_new(Ecore_Wl_Window *parent, int x, int y, int w, int h, int buffer_type) +{ + Ecore_Wl_Window *win; + static int _win_id = 1; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(win = malloc(sizeof(Ecore_Wl_Window)))) + { + ERR("Failed to allocate an Ecore Wayland Window"); + return NULL; + } + + memset(win, 0, sizeof(Ecore_Wl_Window)); + + win->display = _ecore_wl_disp; + win->parent = parent; + win->allocation.x = x; + win->allocation.y = y; + win->allocation.w = w; + win->allocation.h = h; + win->saved_allocation = win->allocation; + win->transparent = EINA_FALSE; + /* win->type = ECORE_WL_WINDOW_TYPE_TOPLEVEL; */ + win->type = ECORE_WL_WINDOW_TYPE_NONE; + win->buffer_type = buffer_type; + win->id = _win_id++; + + eina_hash_add(_windows, _ecore_wl_window_id_str_get(win->id), win); + return win; +} + +/** + * Deletes the given window + * + * @param win The given window + * + * @ingroup Ecore_Wl_Window_Group + * @since 1.2 + */ +EAPI void +ecore_wl_window_free(Ecore_Wl_Window *win) +{ + Ecore_Wl_Input *input; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!win) return; + + eina_hash_del(_windows, _ecore_wl_window_id_str_get(win->id), win); + + wl_list_for_each(input, &_ecore_wl_disp->inputs, link) + { + if ((input->pointer_focus) && (input->pointer_focus == win)) + input->pointer_focus = NULL; + if ((input->keyboard_focus) && (input->keyboard_focus == win)) + input->keyboard_focus = NULL; + } + + if (win->region.input) wl_region_destroy(win->region.input); + win->region.input = NULL; + if (win->region.opaque) wl_region_destroy(win->region.opaque); + win->region.opaque = NULL; + if (win->shell_surface) wl_shell_surface_destroy(win->shell_surface); + win->shell_surface = NULL; + + if (win->surface) wl_surface_destroy(win->surface); + win->surface = NULL; + + /* HMMM, why was this disabled ? */ + free(win); +} + +/** + * Signals for Wayland to initiate a window move. + * + * The position requested (@p x, @p y) is not honored by Wayland because + * Wayland does not allow specific window placement to be set. + * + * @param win The window to move. + * @param x X Position + * @param y Y Position + * + * @ingroup Ecore_Wl_Window_Group + * @since 1.2 + */ +EAPI void +ecore_wl_window_move(Ecore_Wl_Window *win, int x, int y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!win) return; + + win->allocation.x = x; + win->allocation.y = y; + + if (win->shell_surface) + { + Ecore_Wl_Input *input; + + if (!(input = win->keyboard_device)) + { + if (win->parent) + { + if (!(input = win->parent->keyboard_device)) + input = win->parent->pointer_device; + } + } + + if ((!input) || (!input->seat)) return; + + wl_shell_surface_move(win->shell_surface, input->seat, + input->display->serial); + } +} + +/** + * Signals for Wayland to initiate a window resize. + * + * The size requested (@p w, @p h) is not honored by Wayland because + * Wayland does not allow specific window sizes to be set. + * + * @param win The window to resize. + * @param w Width + * @param h Height + * @param location The edge of the window from where the resize should start. + * + * @ingroup Ecore_Wl_Window_Group + * @since 1.2 + */ +EAPI void +ecore_wl_window_resize(Ecore_Wl_Window *win, int w, int h, int location) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!win) return; + + if (win->type != ECORE_WL_WINDOW_TYPE_FULLSCREEN) + { + win->allocation.w = w; + win->allocation.h = h; + + win->region.input = + wl_compositor_create_region(_ecore_wl_disp->wl.compositor); + wl_region_add(win->region.input, win->allocation.x, win->allocation.y, + win->allocation.w, win->allocation.h); + } + + if (!win->transparent) + { + win->region.opaque = + wl_compositor_create_region(_ecore_wl_disp->wl.compositor); + wl_region_add(win->region.opaque, win->allocation.x, win->allocation.y, + win->allocation.w, win->allocation.h); + } + + if (win->shell_surface) + { + Ecore_Wl_Input *input; + + if (!(input = win->keyboard_device)) + { + if (win->parent) + { + if (!(input = win->parent->keyboard_device)) + input = win->parent->pointer_device; + } + } + + if ((!input) || (!input->seat)) return; + + wl_shell_surface_resize(win->shell_surface, input->seat, + input->display->serial, location); + } +} + +EAPI void +ecore_wl_window_damage(Ecore_Wl_Window *win, int x, int y, int w, int h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!win) return; + if (win->surface) + wl_surface_damage(win->surface, x, y, w, h); +} + +EAPI void +ecore_wl_window_buffer_attach(Ecore_Wl_Window *win, struct wl_buffer *buffer, int x, int y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!win) return; + + switch (win->buffer_type) + { + case ECORE_WL_WINDOW_BUFFER_TYPE_EGL_WINDOW: + win->server_allocation = win->allocation; + break; + case ECORE_WL_WINDOW_BUFFER_TYPE_EGL_IMAGE: + case ECORE_WL_WINDOW_BUFFER_TYPE_SHM: + if (win->surface) + { + if (win->edges & 4) // resizing from the left + x = win->server_allocation.w - win->allocation.w; + else + x = 0; + + if (win->edges & 1) // resizing from the top + y = win->server_allocation.h - win->allocation.h; + else + y = 0; + + win->edges = 0; + + /* if (buffer) */ + wl_surface_attach(win->surface, buffer, x, y); + wl_surface_damage(win->surface, 0, 0, + win->allocation.w, win->allocation.h); + + win->server_allocation = win->allocation; + } + break; + default: + return; + } + + if (win->region.input) + { + wl_surface_set_input_region(win->surface, win->region.input); + wl_region_destroy(win->region.input); + win->region.input = NULL; + } + + if (win->region.opaque) + { + wl_surface_set_opaque_region(win->surface, win->region.opaque); + wl_region_destroy(win->region.opaque); + win->region.opaque = NULL; + } +} + +/** + * Shows a window + * + * Synonymous to "mapping" a window in Wayland System terminology. + * + * @param win The window to show. + * + * @ingroup Ecore_Wl_Window_Group + * @since 1.2 + */ +EAPI void +ecore_wl_window_show(Ecore_Wl_Window *win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!win) return; + if (win->surface) return; + + win->surface = wl_compositor_create_surface(_ecore_wl_disp->wl.compositor); + wl_surface_set_user_data(win->surface, win); + /* wl_surface_add_listener(win->surface, &_ecore_wl_surface_listener, win); */ + + win->shell_surface = + wl_shell_get_shell_surface(_ecore_wl_disp->wl.shell, win->surface); + wl_shell_surface_add_listener(win->shell_surface, + &_ecore_wl_shell_surface_listener, win); + + switch (win->type) + { + case ECORE_WL_WINDOW_TYPE_FULLSCREEN: + wl_shell_surface_set_fullscreen(win->shell_surface, + WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, + 0, NULL); + break; + case ECORE_WL_WINDOW_TYPE_MAXIMIZED: + wl_shell_surface_set_maximized(win->shell_surface, NULL); + break; + case ECORE_WL_WINDOW_TYPE_TRANSIENT: + wl_shell_surface_set_transient(win->shell_surface, + win->parent->surface, + win->allocation.x, win->allocation.y, 0); + break; + case ECORE_WL_WINDOW_TYPE_MENU: + wl_shell_surface_set_popup(win->shell_surface, + _ecore_wl_disp->input->seat, + _ecore_wl_disp->serial, + win->parent->surface, + win->allocation.x, win->allocation.y, 0); + break; + case ECORE_WL_WINDOW_TYPE_NONE: + win->type = ECORE_WL_WINDOW_TYPE_TOPLEVEL; + /* fallthrough */ + case ECORE_WL_WINDOW_TYPE_TOPLEVEL: + wl_shell_surface_set_toplevel(win->shell_surface); + break; + default: + break; + } + + /* if (win->type != ECORE_WL_WINDOW_TYPE_FULLSCREEN) */ + /* { */ + /* win->region.input = */ + /* wl_compositor_create_region(_ecore_wl_disp->wl.compositor); */ + /* wl_region_add(win->region.input, win->allocation.x, win->allocation.y, */ + /* win->allocation.w, win->allocation.h); */ + /* } */ + + /* if (!win->transparent) */ + /* { */ + /* win->region.opaque = */ + /* wl_compositor_create_region(_ecore_wl_disp->wl.compositor); */ + /* wl_region_add(win->region.opaque, win->allocation.x, win->allocation.y, */ + /* win->allocation.w, win->allocation.h); */ + /* } */ +} + +/** + * Hides a window + * + * Synonymous to "unmapping" a window in Wayland System terminology. + * + * @param win The window to hide. + * + * @ingroup Ecore_Wl_Window_Group + * @since 1.2 + */ +EAPI void +ecore_wl_window_hide(Ecore_Wl_Window *win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!win) return; + if (win->shell_surface) wl_shell_surface_destroy(win->shell_surface); + win->shell_surface = NULL; + if (win->surface) wl_surface_destroy(win->surface); + win->surface = NULL; +} + +/** + * Raises a window + * + * @param win The window to raise. + * + * @ingroup Ecore_Wl_Window_Group + * @since 1.2 + */ +EAPI void +ecore_wl_window_raise(Ecore_Wl_Window *win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!win) return; + if (win->shell_surface) + wl_shell_surface_set_toplevel(win->shell_surface); +} + +EAPI void +ecore_wl_window_maximized_set(Ecore_Wl_Window *win, Eina_Bool maximized) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!win) return; + + if ((win->type == ECORE_WL_WINDOW_TYPE_MAXIMIZED) == maximized) return; + if (win->type == ECORE_WL_WINDOW_TYPE_TOPLEVEL) + { + win->saved_allocation = win->allocation; + if (win->shell_surface) + wl_shell_surface_set_maximized(win->shell_surface, NULL); + win->type = ECORE_WL_WINDOW_TYPE_MAXIMIZED; + } + else if (win->type == ECORE_WL_WINDOW_TYPE_MAXIMIZED) + { + if (win->shell_surface) + wl_shell_surface_set_toplevel(win->shell_surface); + win->type = ECORE_WL_WINDOW_TYPE_TOPLEVEL; + _ecore_wl_window_configure_send(win, win->saved_allocation.w, + win->saved_allocation.h); + } +} + +EAPI void +ecore_wl_window_fullscreen_set(Ecore_Wl_Window *win, Eina_Bool fullscreen) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!win) return; + if ((win->type == ECORE_WL_WINDOW_TYPE_FULLSCREEN) == fullscreen) return; + if (fullscreen) + { + win->type = ECORE_WL_WINDOW_TYPE_FULLSCREEN; + win->saved_allocation = win->allocation; + if (win->shell_surface) + wl_shell_surface_set_fullscreen(win->shell_surface, + WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, + 0, NULL); + } + else + { + if (win->shell_surface) + wl_shell_surface_set_toplevel(win->shell_surface); + win->type = ECORE_WL_WINDOW_TYPE_TOPLEVEL; + _ecore_wl_window_configure_send(win, win->saved_allocation.w, + win->saved_allocation.h); + } +} + +EAPI void +ecore_wl_window_transparent_set(Ecore_Wl_Window *win, Eina_Bool transparent) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!win) return; + win->transparent = transparent; + if (win->region.opaque) wl_region_destroy(win->region.opaque); + win->region.opaque = NULL; + if (!win->transparent) + { + win->region.opaque = + wl_compositor_create_region(_ecore_wl_disp->wl.compositor); + wl_region_add(win->region.opaque, win->allocation.x, win->allocation.y, + win->allocation.w, win->allocation.h); + } +} + +EAPI void +ecore_wl_window_update_size(Ecore_Wl_Window *win, int w, int h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!win) return; + win->allocation.w = w; + win->allocation.h = h; +} + +EAPI void +ecore_wl_window_update_location(Ecore_Wl_Window *win, int x, int y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!win) return; + win->allocation.x = x; + win->allocation.y = y; +} + +EAPI struct wl_surface * +ecore_wl_window_surface_get(Ecore_Wl_Window *win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!win) return NULL; + return win->surface; +} + +/* @since 1.2 */ +EAPI struct wl_shell_surface * +ecore_wl_window_shell_surface_get(Ecore_Wl_Window *win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!win) return NULL; + return win->shell_surface; +} + +EAPI Ecore_Wl_Window * +ecore_wl_window_find(unsigned int id) +{ + Ecore_Wl_Window *win = NULL; + + win = eina_hash_find(_windows, _ecore_wl_window_id_str_get(id)); + return win; +} + +EAPI void +ecore_wl_window_type_set(Ecore_Wl_Window *win, Ecore_Wl_Window_Type type) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!win) return; + win->type = type; +} + +EAPI void +ecore_wl_window_pointer_set(Ecore_Wl_Window *win, struct wl_surface *surface, int hot_x, int hot_y) +{ + Ecore_Wl_Input *input; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!win) return; + + if ((input = win->pointer_device)) + ecore_wl_input_pointer_set(input, surface, hot_x, hot_y); +} + +EAPI void +ecore_wl_window_cursor_from_name_set(Ecore_Wl_Window *win, const char *cursor_name) +{ + Ecore_Wl_Input *input; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!win) return; + + if ((input = win->pointer_device)) + ecore_wl_input_cursor_from_name_set(input, cursor_name); +} + +EAPI void +ecore_wl_window_cursor_default_restore(Ecore_Wl_Window *win) +{ + Ecore_Wl_Input *input; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!win) return; + + if ((input = win->pointer_device)) + ecore_wl_input_cursor_default_restore(input); +} + +/* @since 1.2 */ +EAPI void +ecore_wl_window_parent_set(Ecore_Wl_Window *win, Ecore_Wl_Window *parent) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + win->parent = parent; +} + +/* local functions */ +static void +_ecore_wl_window_cb_ping(void *data __UNUSED__, struct wl_shell_surface *shell_surface, unsigned int serial) +{ + if (!shell_surface) return; + wl_shell_surface_pong(shell_surface, serial); +} + +static void +_ecore_wl_window_cb_configure(void *data, struct wl_shell_surface *shell_surface __UNUSED__, unsigned int edges, int w, int h) +{ + Ecore_Wl_Window *win; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(win = data)) return; + + if ((w <= 0) || (h <= 0)) return; + + if ((win->allocation.w != w) || (win->allocation.h != h)) + { + win->edges = edges; + if (win->region.input) wl_region_destroy(win->region.input); + win->region.input = NULL; + if (win->region.opaque) wl_region_destroy(win->region.opaque); + win->region.opaque = NULL; + + _ecore_wl_window_configure_send(win, w, h); + } +} + +static void +_ecore_wl_window_cb_popup_done(void *data, struct wl_shell_surface *shell_surface __UNUSED__) +{ + Ecore_Wl_Window *win; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!shell_surface) return; + if (!(win = data)) return; + ecore_wl_input_ungrab(win->pointer_device); +} + +static void +_ecore_wl_window_cb_surface_enter(void *data, struct wl_surface *surface, struct wl_output *output __UNUSED__) +{ + Ecore_Wl_Window *win; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!surface) return; + if (!(win = data)) return; +} + +static void +_ecore_wl_window_cb_surface_leave(void *data, struct wl_surface *surface, struct wl_output *output __UNUSED__) +{ + Ecore_Wl_Window *win; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!surface) return; + if (!(win = data)) return; +} + +static void +_ecore_wl_window_configure_send(Ecore_Wl_Window *win, int w, int h) +{ + Ecore_Wl_Event_Window_Configure *ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(ev = calloc(1, sizeof(Ecore_Wl_Event_Window_Configure)))) return; + ev->win = win->id; + ev->event_win = win->id; + ev->x = win->allocation.x; + ev->y = win->allocation.y; + ev->w = w; + ev->h = h; + ecore_event_add(ECORE_WL_EVENT_WINDOW_CONFIGURE, ev, NULL, NULL); +} + +static char * +_ecore_wl_window_id_str_get(unsigned int win_id) +{ + const char *vals = "qWeRtYuIoP5$&<~"; + static char id[9]; + unsigned int val; + + val = win_id; + id[0] = vals[(val >> 28) & 0xf]; + id[1] = vals[(val >> 24) & 0xf]; + id[2] = vals[(val >> 20) & 0xf]; + id[3] = vals[(val >> 16) & 0xf]; + id[4] = vals[(val >> 12) & 0xf]; + id[5] = vals[(val >> 8) & 0xf]; + id[6] = vals[(val >> 4) & 0xf]; + id[7] = vals[(val) & 0xf]; + id[8] = 0; + + return id; +} diff --git a/src/lib/ecore_win32/Ecore_Win32.h b/src/lib/ecore_win32/Ecore_Win32.h new file mode 100644 index 0000000..ae1bd4e --- /dev/null +++ b/src/lib/ecore_win32/Ecore_Win32.h @@ -0,0 +1,526 @@ +#ifndef __ECORE_WIN32_H__ +#define __ECORE_WIN32_H__ + +/* + * DO NOT USE THIS HEADER. IT IS WORK IN PROGRESS. IT IS NOT FINAL AND + * THE API MAY CHANGE. + */ + +#ifndef ECORE_WIN32_WIP_POZEFLKSD +# ifdef _MSC_VER +# pragma message ("You are using a work in progress API. This API is not stable") +# pragma message ("and is subject to change. You use this at your own risk.") +# else +# warning "You are using a work in progress API. This API is not stable" +# warning "and is subject to change. You use this at your own risk." +# endif +#endif + +#include + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_ECORE_WIN32_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_ECORE_WIN32_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup Ecore_Win32_Group Ecore_Win32 library + * + * @{ + */ + +/** + * @typedef Ecore_Win32_Window_State + * State of a window. + */ +typedef enum +{ + ECORE_WIN32_WINDOW_STATE_ICONIFIED, /**< iconified window */ + ECORE_WIN32_WINDOW_STATE_MODAL, /**< modal dialog box */ + ECORE_WIN32_WINDOW_STATE_STICKY, /**< sticky window */ + ECORE_WIN32_WINDOW_STATE_MAXIMIZED_VERT, /**< maximum vertical sized window */ + ECORE_WIN32_WINDOW_STATE_MAXIMIZED_HORZ, /**< maximum horizontal sized window */ + ECORE_WIN32_WINDOW_STATE_MAXIMIZED, /**< maximum sized window */ + ECORE_WIN32_WINDOW_STATE_SHADED, /**< shaded window */ + ECORE_WIN32_WINDOW_STATE_HIDDEN, /**< hidden (minimized or iconified) window */ + ECORE_WIN32_WINDOW_STATE_FULLSCREEN, /**< fullscreen window */ + ECORE_WIN32_WINDOW_STATE_ABOVE, /**< above window */ + ECORE_WIN32_WINDOW_STATE_BELOW, /**< below window */ + ECORE_WIN32_WINDOW_STATE_DEMANDS_ATTENTION, /**< To document */ + ECORE_WIN32_WINDOW_STATE_UNKNOWN /**< Unknown state */ +} Ecore_Win32_Window_State; + +/** + * @typedef Ecore_Win32_Window_Type + * Type of a window. + */ +typedef enum +{ + ECORE_WIN32_WINDOW_TYPE_DESKTOP, /**< Desktop feature */ + ECORE_WIN32_WINDOW_TYPE_DOCK, /**< Dock window (should be on top of other windows) */ + ECORE_WIN32_WINDOW_TYPE_TOOLBAR, /**< Toolbar window */ + ECORE_WIN32_WINDOW_TYPE_MENU, /**< Menu window */ + ECORE_WIN32_WINDOW_TYPE_UTILITY, /**< Small persistent utility window, such as a palette or toolbox */ + ECORE_WIN32_WINDOW_TYPE_SPLASH, /**< Splash screen window displayed as an application is starting up */ + ECORE_WIN32_WINDOW_TYPE_DIALOG, /**< Dialog window */ + ECORE_WIN32_WINDOW_TYPE_NORMAL, /**< Normal top-level window */ + ECORE_WIN32_WINDOW_TYPE_UNKNOWN /**< Unknown type */ +} Ecore_Win32_Window_Type; + +/** + * @typedef Ecore_Win32_Cursor_Shape + * Shape of a cursor. + */ +typedef enum +{ + ECORE_WIN32_CURSOR_SHAPE_APP_STARTING, /**< Standard arrow and small hourglass */ + ECORE_WIN32_CURSOR_SHAPE_ARROW, /**< Standard arrow */ + ECORE_WIN32_CURSOR_SHAPE_CROSS, /**< Crosshair */ + ECORE_WIN32_CURSOR_SHAPE_HAND, /**< Hand */ + ECORE_WIN32_CURSOR_SHAPE_HELP, /**< Arrow and question mark */ + ECORE_WIN32_CURSOR_SHAPE_I_BEAM, /**< I-beam */ + ECORE_WIN32_CURSOR_SHAPE_NO, /**< Slashed circle */ + ECORE_WIN32_CURSOR_SHAPE_SIZE_ALL, /**< Four-pointed arrow pointing north, south, east, and west */ + ECORE_WIN32_CURSOR_SHAPE_SIZE_NESW, /**< Double-pointed arrow pointing northeast and southwest */ + ECORE_WIN32_CURSOR_SHAPE_SIZE_NS, /**< Double-pointed arrow pointing north and south */ + ECORE_WIN32_CURSOR_SHAPE_SIZE_NWSE, /**< Double-pointed arrow pointing northwest and southeast */ + ECORE_WIN32_CURSOR_SHAPE_SIZE_WE, /**< Double-pointed arrow pointing west and east */ + ECORE_WIN32_CURSOR_SHAPE_UP_ARROW, /**< Vertical arrow */ + ECORE_WIN32_CURSOR_SHAPE_WAIT /**< Hourglass */ +} Ecore_Win32_Cursor_Shape; + +/** + * @typedef Ecore_Win32_DnD_State + * State of a DnD operation. + */ +typedef enum +{ + ECORE_WIN32_DND_EVENT_DRAG_ENTER = 1, /**< Drag enter */ + ECORE_WIN32_DND_EVENT_DRAG_OVER = 2, /**< Drag over */ + ECORE_WIN32_DND_EVENT_DRAG_LEAVE = 3, /**< Drag leave */ + ECORE_WIN32_DND_EVENT_DROP = 4 /**< Drop */ +} Ecore_Win32_DnD_State; + +/** + * @typedef Ecore_Win32_Window + * Abstract type for a window. + */ +typedef struct _Ecore_Win32_Window Ecore_Win32_Window; + +/** + * @typedef Ecore_Win32_Cursor + * Abstract type for a cursor. + */ +typedef void Ecore_Win32_Cursor; + + +/** + * @typedef Ecore_Win32_Event_Mouse_In + * Event sent when the mouse enters the window. + */ +typedef struct _Ecore_Win32_Event_Mouse_In Ecore_Win32_Event_Mouse_In; + +/** + * @typedef Ecore_Win32_Event_Mouse_Out + * Event sent when the mouse leaves the window. + */ +typedef struct _Ecore_Win32_Event_Mouse_Out Ecore_Win32_Event_Mouse_Out; + +/** + * @typedef Ecore_Win32_Event_Window_Focus_In + * Event sent when the window gets the focus. + */ +typedef struct _Ecore_Win32_Event_Window_Focus_In Ecore_Win32_Event_Window_Focus_In; + +/** + * @typedef Ecore_Win32_Event_Window_Focus_Out + * Event sent when the window looses the focus. + */ +typedef struct _Ecore_Win32_Event_Window_Focus_Out Ecore_Win32_Event_Window_Focus_Out; + +/** + * @typedef Ecore_Win32_Event_Window_Damage + * Event sent when the window is damaged. + */ +typedef struct _Ecore_Win32_Event_Window_Damage Ecore_Win32_Event_Window_Damage; + +/** + * @typedef Ecore_Win32_Event_Window_Create + * Event sent when the window is created. + */ +typedef struct _Ecore_Win32_Event_Window_Create Ecore_Win32_Event_Window_Create; + +/** + * @typedef Ecore_Win32_Event_Window_Destroy + * Event sent when the window is destroyed. + */ +typedef struct _Ecore_Win32_Event_Window_Destroy Ecore_Win32_Event_Window_Destroy; + +/** + * @typedef Ecore_Win32_Event_Window_Hide + * Event sent when the window is hidden. + */ +typedef struct _Ecore_Win32_Event_Window_Hide Ecore_Win32_Event_Window_Hide; + +/** + * @typedef Ecore_Win32_Event_Window_Show + * Event sent when the window is shown. + */ +typedef struct _Ecore_Win32_Event_Window_Show Ecore_Win32_Event_Window_Show; + +/** + * @typedef Ecore_Win32_Event_Window_Configure + * Event sent when the window is configured. + */ +typedef struct _Ecore_Win32_Event_Window_Configure Ecore_Win32_Event_Window_Configure; + +/** + * @typedef Ecore_Win32_Event_Window_Resize + * Event sent when the window is resized. + */ +typedef struct _Ecore_Win32_Event_Window_Resize Ecore_Win32_Event_Window_Resize; + +/** + * @typedef Ecore_Win32_Event_Window_Delete_Request + * Event sent when the window is deleted. + */ +typedef struct _Ecore_Win32_Event_Window_Delete_Request Ecore_Win32_Event_Window_Delete_Request; + +/** + * @struct _Ecore_Win32_Event_Mouse_In + * Event sent when the mouse enters the window. + */ +struct _Ecore_Win32_Event_Mouse_In +{ + Ecore_Win32_Window *window; /**< The window that received the event */ + int x; /**< The x coordinate where the mouse leaved */ + int y; /**< The y coordinate where the mouse entered */ + unsigned long timestamp; /**< The time the event occurred */ +}; + +/** + * @struct _Ecore_Win32_Event_Mouse_Out + * Event sent when the mouse leaves the window. + */ +struct _Ecore_Win32_Event_Mouse_Out +{ + Ecore_Win32_Window *window; /**< The window that received the event */ + int x; /**< The x coordinate where the mouse leaved */ + int y; /**< The y coordinate where the mouse leaved */ + unsigned long timestamp; /**< The time the event occurred */ +}; + +/** + * @struct _Ecore_Win32_Event_Window_Focus_In + * Event sent when the window gets the focus. + */ +struct _Ecore_Win32_Event_Window_Focus_In +{ + Ecore_Win32_Window *window; /**< The window that received the event */ + unsigned long timestamp; /**< The time the event occurred */ +}; + +/** + * @struct _Ecore_Win32_Event_Window_Focus_Out + * Event sent when the window looses the focus. + */ +struct _Ecore_Win32_Event_Window_Focus_Out +{ + Ecore_Win32_Window *window; /**< The window that received the event */ + unsigned long timestamp; /**< The time the event occurred */ +}; + +/** + * @struct _Ecore_Win32_Event_Window_Damage + * Event sent when the window is damaged. + */ +struct _Ecore_Win32_Event_Window_Damage +{ + Ecore_Win32_Window *window; /**< The window that received the event */ + int x; /**< The x coordinate of the top left corner of the damaged region */ + int y; /**< The y coordinate of the top left corner of the damaged region */ + int width; /**< The width of the damaged region */ + int height; /**< The time the event occurred */ + unsigned long timestamp; /**< The time the event occurred */ +}; + +/** + * @struct _Ecore_Win32_Event_Window_Create + * Event sent when the window is created. + */ +struct _Ecore_Win32_Event_Window_Create +{ + Ecore_Win32_Window *window; /**< The window that received the event */ + unsigned long timestamp; /**< The time the event occurred */ +}; + +/** + * @struct _Ecore_Win32_Event_Window_Destroy + * Event sent when the window is destroyed. + */ +struct _Ecore_Win32_Event_Window_Destroy +{ + Ecore_Win32_Window *window; /**< The window that received the event */ + unsigned long timestamp; /**< The time the event occurred */ +}; + +/** + * @struct _Ecore_Win32_Event_Window_Hide + * Event sent when the window is hidden. + */ +struct _Ecore_Win32_Event_Window_Hide +{ + Ecore_Win32_Window *window; /**< The window that received the event */ + unsigned long timestamp; /**< The time the event occurred */ +}; + +/** + * @struct _Ecore_Win32_Event_Window_Show + * Event sent when the window is shown. + */ +struct _Ecore_Win32_Event_Window_Show +{ + Ecore_Win32_Window *window; /**< The window that received the event */ + unsigned long timestamp; /**< The time the event occurred */ +}; + +/** + * @struct _Ecore_Win32_Event_Window_Configure + * Event sent when the window is configured. + */ +struct _Ecore_Win32_Event_Window_Configure +{ + Ecore_Win32_Window *window; /**< The window that received the event */ + Ecore_Win32_Window *abovewin; + int x; /**< The new x coordinate of the top left corner */ + int y; /**< The new y coordinate of the top left corner */ + int width; /**< The new width */ + int height; /**< The new height */ + unsigned long timestamp; /**< The time the event occurred */ +}; + +/** + * @struct _Ecore_Win32_Event_Window_Resize + * Event sent when the window is resized. + */ +struct _Ecore_Win32_Event_Window_Resize +{ + Ecore_Win32_Window *window; /**< The window that received the event */ + int width; /**< The new width */ + int height; /**< The new height */ + unsigned long timestamp; /**< The time the event occurred */ +}; + +/** + * @struct _Ecore_Win32_Event_Window_Delete_Request + * Event sent when the window is deleted. + */ +struct _Ecore_Win32_Event_Window_Delete_Request +{ + Ecore_Win32_Window *window; /**< The window that received the event */ + unsigned long timestamp; /**< The time the event occurred */ +}; + +/** + * @typedef Ecore_Win32_Dnd_DropTarget_Callback + * Callback type for Drop operations. See ecore_win32_dnd_register_drop_target(). + */ +typedef int (*Ecore_Win32_Dnd_DropTarget_Callback)(void *window, int event, int pt_x, int pt_y, void *data, int size); + +EAPI extern int ECORE_WIN32_EVENT_MOUSE_IN; /**< Ecore_Event for the #Ecore_Win32_Event_Mouse_In event */ +EAPI extern int ECORE_WIN32_EVENT_MOUSE_OUT; /**< Ecore_Event for the #Ecore_Win32_Event_Mouse_Out event */ +EAPI extern int ECORE_WIN32_EVENT_WINDOW_FOCUS_IN; /**< Ecore_Event for the #Ecore_Win32_Event_Window_Focus_In event */ +EAPI extern int ECORE_WIN32_EVENT_WINDOW_FOCUS_OUT; /**< Ecore_Event for the #Ecore_Win32_Event_Window_Focus_Out event */ +EAPI extern int ECORE_WIN32_EVENT_WINDOW_DAMAGE; /**< Ecore_Event for the Ecore_Win32_Event_Damage event */ +EAPI extern int ECORE_WIN32_EVENT_WINDOW_CREATE; /**< Ecore_Event for the Ecore_Win32_Event_Create event */ +EAPI extern int ECORE_WIN32_EVENT_WINDOW_DESTROY; /**< Ecore_Event for the Ecore_Win32_Event_Destroy event */ +EAPI extern int ECORE_WIN32_EVENT_WINDOW_HIDE; /**< Ecore_Event for the Ecore_Win32_Event_Hide event */ +EAPI extern int ECORE_WIN32_EVENT_WINDOW_SHOW; /**< Ecore_Event for the Ecore_Win32_Event_Show event */ +EAPI extern int ECORE_WIN32_EVENT_WINDOW_CONFIGURE; /**< Ecore_Event for the Ecore_Win32_Event_Configure event */ +EAPI extern int ECORE_WIN32_EVENT_WINDOW_RESIZE; /**< Ecore_Event for the Ecore_Win32_Event_Resize event */ +EAPI extern int ECORE_WIN32_EVENT_WINDOW_DELETE_REQUEST; /**< Ecore_Event for the #Ecore_Win32_Event_Window_Delete_Request event */ + + +/* Core */ + +EAPI int ecore_win32_init(); +EAPI int ecore_win32_shutdown(); +EAPI int ecore_win32_screen_depth_get(); +EAPI void ecore_win32_double_click_time_set(double t); +EAPI double ecore_win32_double_click_time_get(void); +EAPI unsigned long ecore_win32_current_time_get(void); + +/* Window */ + +EAPI Ecore_Win32_Window *ecore_win32_window_new(Ecore_Win32_Window *parent, + int x, + int y, + int width, + int height); +EAPI Ecore_Win32_Window *ecore_win32_window_override_new(Ecore_Win32_Window *parent, + int x, + int y, + int width, + int height); + +EAPI void ecore_win32_window_free(Ecore_Win32_Window *window); + +EAPI void *ecore_win32_window_hwnd_get(Ecore_Win32_Window *window); + +EAPI void ecore_win32_window_move(Ecore_Win32_Window *window, + int x, + int y); + +EAPI void ecore_win32_window_resize(Ecore_Win32_Window *window, + int width, + int height); + +EAPI void ecore_win32_window_move_resize(Ecore_Win32_Window *window, + int x, + int y, + int width, + int height); + +EAPI void ecore_win32_window_geometry_get(Ecore_Win32_Window *window, + int *x, + int *y, + int *width, + int *height); + +EAPI void ecore_win32_window_size_get(Ecore_Win32_Window *window, + int *width, + int *height); + +EAPI void ecore_win32_window_size_min_set(Ecore_Win32_Window *window, + unsigned int min_width, + unsigned int min_height); + +EAPI void ecore_win32_window_size_min_get(Ecore_Win32_Window *window, + unsigned int *min_width, + unsigned int *min_height); + +EAPI void ecore_win32_window_size_max_set(Ecore_Win32_Window *window, + unsigned int max_width, + unsigned int max_height); + +EAPI void ecore_win32_window_size_max_get(Ecore_Win32_Window *window, + unsigned int *max_width, + unsigned int *max_height); + +EAPI void ecore_win32_window_size_base_set(Ecore_Win32_Window *window, + unsigned int base_width, + unsigned int base_height); + +EAPI void ecore_win32_window_size_base_get(Ecore_Win32_Window *window, + unsigned int *base_width, + unsigned int *base_height); + +EAPI void ecore_win32_window_size_step_set(Ecore_Win32_Window *window, + unsigned int step_width, + unsigned int step_height); + +EAPI void ecore_win32_window_size_step_get(Ecore_Win32_Window *window, + unsigned int *step_width, + unsigned int *step_height); + +EAPI void ecore_win32_window_show(Ecore_Win32_Window *window); + +EAPI void ecore_win32_window_hide(Ecore_Win32_Window *window); + +EAPI void ecore_win32_window_raise(Ecore_Win32_Window *window); + +EAPI void ecore_win32_window_lower(Ecore_Win32_Window *window); + +EAPI void ecore_win32_window_title_set(Ecore_Win32_Window *window, + const char *title); + +EAPI void ecore_win32_window_focus(Ecore_Win32_Window *window); + +EAPI void *ecore_win32_window_focus_get(void); + +EAPI void ecore_win32_window_iconified_set(Ecore_Win32_Window *window, + Eina_Bool on); + +EAPI void ecore_win32_window_borderless_set(Ecore_Win32_Window *window, + Eina_Bool on); + +EAPI void ecore_win32_window_fullscreen_set(Ecore_Win32_Window *window, + Eina_Bool on); + +EAPI void ecore_win32_window_cursor_set(Ecore_Win32_Window *window, + Ecore_Win32_Cursor *cursor); + +EAPI void ecore_win32_window_state_set(Ecore_Win32_Window *window, + Ecore_Win32_Window_State *state, + unsigned int num); + +EAPI void ecore_win32_window_state_request_send(Ecore_Win32_Window *window, + Ecore_Win32_Window_State state, + unsigned int set); + +EAPI void ecore_win32_window_type_set(Ecore_Win32_Window *window, + Ecore_Win32_Window_Type type); + +/* Cursor */ + +EAPI Ecore_Win32_Cursor *ecore_win32_cursor_new(const void *pixels_and, + const void *pixels_xor, + int width, + int height, + int hot_x, + int hot_y); + +EAPI void ecore_win32_cursor_free(Ecore_Win32_Cursor *cursor); + +EAPI Ecore_Win32_Cursor *ecore_win32_cursor_shaped_new(Ecore_Win32_Cursor_Shape shape); + +EAPI void ecore_win32_cursor_size_get(int *width, int *height); + + + +/* Drag and drop */ +EAPI int ecore_win32_dnd_init(); +EAPI int ecore_win32_dnd_shutdown(); +EAPI Eina_Bool ecore_win32_dnd_begin(const char *data, + int size); +EAPI Eina_Bool ecore_win32_dnd_register_drop_target(Ecore_Win32_Window *window, + Ecore_Win32_Dnd_DropTarget_Callback callback); +EAPI void ecore_win32_dnd_unregister_drop_target(Ecore_Win32_Window *window); + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + + +#endif /* __ECORE_WIN32_H__ */ diff --git a/src/lib/ecore_win32/Makefile.am b/src/lib/ecore_win32/Makefile.am new file mode 100644 index 0000000..7031fa5 --- /dev/null +++ b/src/lib/ecore_win32/Makefile.am @@ -0,0 +1,44 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore_input \ +-I$(top_builddir)/src/lib/ecore \ +-I$(top_builddir)/src/lib/ecore_input \ +@EFL_ECORE_WIN32_BUILD@ \ +@EVIL_CFLAGS@ \ +@EINA_CFLAGS@ \ +@WIN32_CPPFLAGS@ + +lib_LTLIBRARIES = libecore_win32.la + +includes_HEADERS = Ecore_Win32.h +includesdir = $(includedir)/ecore-@VMAJ@ + +libecore_win32_la_SOURCES = \ +ecore_win32.c \ +ecore_win32_cursor.c \ +ecore_win32_dnd.c \ +ecore_win32_dnd_enumformatetc.cpp \ +ecore_win32_dnd_data_object.cpp \ +ecore_win32_dnd_drop_source.cpp \ +ecore_win32_dnd_drop_target.cpp \ +ecore_win32_event.c \ +ecore_win32_window.c + +libecore_win32_la_LIBADD = \ +@ecore_win32_libs@ \ +@WIN32_LIBS@ \ +$(top_builddir)/src/lib/ecore/libecore.la \ +$(top_builddir)/src/lib/ecore_input/libecore_input.la \ +@EINA_LIBS@ \ +@EVIL_LIBS@ + +libecore_win32_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ + +EXTRA_DIST = \ +ecore_win32_private.h \ +ecore_win32_dnd_enumformatetc.h \ +ecore_win32_dnd_data_object.h \ +ecore_win32_dnd_drop_source.h \ +ecore_win32_dnd_drop_target.h diff --git a/src/lib/ecore_win32/ecore_win32.c b/src/lib/ecore_win32/ecore_win32.c new file mode 100644 index 0000000..b571d74 --- /dev/null +++ b/src/lib/ecore_win32/ecore_win32.c @@ -0,0 +1,841 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN +#include + +#include +#include +#include + +#include "Ecore_Win32.h" +#include "ecore_win32_private.h" + +/*============================================================================* + * Local * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +/* OLE IID for Drag'n Drop */ + +# define INITGUID +# include +DEFINE_OLEGUID(IID_IEnumFORMATETC, 0x00000103L, 0, 0); +DEFINE_OLEGUID(IID_IDataObject, 0x0000010EL, 0, 0); +DEFINE_OLEGUID(IID_IDropSource, 0x00000121L, 0, 0); +DEFINE_OLEGUID(IID_IDropTarget, 0x00000122L, 0, 0); +DEFINE_OLEGUID(IID_IUnknown, 0x00000000L, 0, 0); + +#define IDI_ICON 101 + +static int _ecore_win32_init_count = 0; + +static void +_ecore_win32_size_check(Ecore_Win32_Window *win, int w, int h, int *dx, int *dy) +{ + int minimal_width; + int minimal_height; + + minimal_width = GetSystemMetrics(SM_CXMIN); + minimal_height = GetSystemMetrics(SM_CYMIN); + if ((w) < MAX(minimal_width, (int)win->min_width)) + *dx = 0; + if ((w) > (int)win->max_width) + *dx = 0; + if ((h) < MAX(minimal_height, (int)win->min_height)) + *dy = 0; + if ((h) > (int)win->max_height) + *dy = 0; +} + +LRESULT CALLBACK +_ecore_win32_window_procedure(HWND window, + UINT message, + WPARAM window_param, + LPARAM data_param) +{ + Ecore_Win32_Callback_Data *data; + POINTS point; + DWORD coord; + + data = (Ecore_Win32_Callback_Data *)malloc(sizeof(Ecore_Win32_Callback_Data)); + if (!data) return DefWindowProc(window, message, window_param, data_param); + + data->window = window; + data->message = message; + data->window_param = window_param; + data->data_param = data_param; + data->timestamp = GetMessageTime(); + coord = GetMessagePos(); + point = MAKEPOINTS(coord); + data->x = point.x; + data->y = point.y; + data->discard_ctrl = EINA_FALSE; + + switch (data->message) + { + /* Keyboard input notifications */ + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + if ((data->message == WM_KEYDOWN) && + (data->window_param == VK_CONTROL) && + ((HIWORD(data->data_param) & KF_EXTENDED) == 0)) + { + /* Ctrl left key is pressed */ + BOOL res; + MSG next_msg; + + /* + * we check if the next message + * - is a WM_KEYDOWN + * - has the same timestamp than the Ctrl one + * - is the key press of the right Alt key + */ + res = PeekMessage(&next_msg, data->window, + WM_KEYDOWN, WM_KEYDOWN, + PM_NOREMOVE); + if (res && + (next_msg.wParam == VK_MENU) && + (next_msg.time == data->timestamp) && + (HIWORD(next_msg.lParam) & KF_EXTENDED)) + { + INF("discard left Ctrl key press (sent by AltGr key press)"); + data->discard_ctrl = EINA_TRUE; + } + } + _ecore_win32_event_handle_key_press(data, 1); + return 0; + case WM_CHAR: + case WM_SYSCHAR: + INF("char message"); + _ecore_win32_event_handle_key_press(data, 0); + return 0; + case WM_KEYUP: + case WM_SYSKEYUP: + INF("keyup message"); + if ((data->window_param == VK_CONTROL) && + ((HIWORD(data->data_param) & KF_EXTENDED) == 0)) + { + /* Ctrl left key is pressed */ + BOOL res; + MSG next_msg; + + /* + * we check if the next message + * - is a WM_KEYUP or WM_SYSKEYUP + * - has the same timestamp than the Ctrl one + * - is the key release of the right Alt key + */ + res = PeekMessage(&next_msg, data->window, + WM_KEYUP, WM_SYSKEYUP, + PM_NOREMOVE); + if (res && + ((next_msg.message == WM_KEYUP) || + (next_msg.message == WM_SYSKEYUP)) && + (next_msg.wParam == VK_MENU) && + (next_msg.time == data->timestamp) && + (HIWORD(next_msg.lParam) & KF_EXTENDED)) + { + INF("discard left Ctrl key release (sent by AltGr key release)"); + data->discard_ctrl = EINA_TRUE; + } + } + _ecore_win32_event_handle_key_release(data); + return 0; + case WM_SETFOCUS: + INF("setfocus message"); + _ecore_win32_event_handle_focus_in(data); + return 0; + case WM_KILLFOCUS: + INF("kill focus message"); + _ecore_win32_event_handle_focus_out(data); + return 0; + /* Mouse input notifications */ + case WM_LBUTTONDOWN: + INF("left button down message"); + SetCapture(window); + _ecore_win32_event_handle_button_press(data, 1); + return 0; + case WM_MBUTTONDOWN: + INF("middle button down message"); + _ecore_win32_event_handle_button_press(data, 2); + return 0; + case WM_RBUTTONDOWN: + INF("right button down message"); + _ecore_win32_event_handle_button_press(data, 3); + return 0; + case WM_LBUTTONUP: + { + Ecore_Win32_Window *w = NULL; + + INF("left button up message"); + + ReleaseCapture(); + w = (Ecore_Win32_Window *)GetWindowLongPtr(window, GWLP_USERDATA); + if (w->drag.dragging) + { + w->drag.dragging = 0; + return 0; + } + + _ecore_win32_event_handle_button_release(data, 1); + return 0; + } + case WM_MBUTTONUP: + INF("middle button up message"); + _ecore_win32_event_handle_button_release(data, 2); + return 0; + case WM_RBUTTONUP: + INF("right button up message"); + _ecore_win32_event_handle_button_release(data, 3); + return 0; + case WM_MOUSEMOVE: + { + RECT rect; + Ecore_Win32_Window *w = NULL; + + INF("moue move message"); + + w = (Ecore_Win32_Window *)GetWindowLongPtr(window, GWLP_USERDATA); + + if (w->drag.dragging) + { + POINT pt; + + pt.x = GET_X_LPARAM(data_param); + pt.y = GET_Y_LPARAM(data_param); + if (ClientToScreen(window, &pt)) + { + if (w->drag.type == HTCAPTION) + { + int dx; + int dy; + + dx = pt.x - w->drag.px; + dy = pt.y - w->drag.py; + ecore_win32_window_move(w, w->drag.x + dx, w->drag.y + dy); + w->drag.x += dx; + w->drag.y += dy; + w->drag.px = pt.x; + w->drag.py = pt.y; + return 0; + } + if (w->drag.type == HTLEFT) + { + int dw; + + dw = pt.x - w->drag.px; + ecore_win32_window_move_resize(w, w->drag.x + dw, w->drag.y, w->drag.w - dw, w->drag.h); + w->drag.x += dw; + w->drag.w -= dw; + w->drag.px = pt.x; + w->drag.py = pt.y; + return 0; + } + if (w->drag.type == HTRIGHT) + { + int dw; + + dw = pt.x - w->drag.px; + ecore_win32_window_resize(w, w->drag.w + dw, w->drag.h); + w->drag.w += dw; + w->drag.px = pt.x; + w->drag.py = pt.y; + return 0; + } + if (w->drag.type == HTTOP) + { + int dh; + + dh = pt.y - w->drag.py; + ecore_win32_window_move_resize(w, w->drag.x, w->drag.y + dh, w->drag.w, w->drag.h - dh); + w->drag.y += dh; + w->drag.h -= dh; + w->drag.px = pt.x; + w->drag.py = pt.y; + return 0; + } + if (w->drag.type == HTBOTTOM) + { + int dh; + + dh = pt.y - w->drag.py; + ecore_win32_window_resize(w, w->drag.w, w->drag.h + dh); + w->drag.h += dh; + w->drag.px = pt.x; + w->drag.py = pt.y; + return 0; + } + if (w->drag.type == HTTOPLEFT) + { + int dx; + int dy; + int dh; + int dw; + + dw = pt.x - w->drag.px; + dh = pt.y - w->drag.py; + dx = dw; + dy = dh; + _ecore_win32_size_check(w, + w->drag.w - dw, w->drag.h - dh, + &dx, &dy); + + ecore_win32_window_move_resize(w, w->drag.x + dx, w->drag.y + dy, w->drag.w - dw, w->drag.h - dh); + w->drag.x += dx; + w->drag.y += dy; + w->drag.w -= dw; + w->drag.h -= dh; + w->drag.px = pt.x; + w->drag.py = pt.y; + return 0; + } + if (w->drag.type == HTTOPRIGHT) + { + int dx; + int dy; + int dh; + int dw; + + dw = pt.x - w->drag.px; + dh = pt.y - w->drag.py; + dx = dw; + dy = dh; + _ecore_win32_size_check(w, + w->drag.w, w->drag.h - dh, + &dx, &dy); + ecore_win32_window_move_resize(w, w->drag.x, w->drag.y + dy, w->drag.w, w->drag.h - dh); + w->drag.y += dy; + w->drag.w += dw; + w->drag.h -= dh; + w->drag.px = pt.x; + w->drag.py = pt.y; + return 0; + } + if (w->drag.type == HTBOTTOMLEFT) + { + int dx; + int dy; + int dh; + int dw; + + dw = pt.x - w->drag.px; + dh = pt.y - w->drag.py; + dx = dw; + dy = dh; + _ecore_win32_size_check(w, + w->drag.w - dw, w->drag.h + dh, + &dx, &dy); + ecore_win32_window_move_resize(w, w->drag.x + dx, w->drag.y, w->drag.w - dw, w->drag.h + dh); + w->drag.x += dx; + w->drag.w -= dw; + w->drag.h += dh; + w->drag.px = pt.x; + w->drag.py = pt.y; + return 0; + } + if (w->drag.type == HTBOTTOMRIGHT) + { + int dh; + int dw; + + dw = pt.x - w->drag.px; + dh = pt.y - w->drag.py; + ecore_win32_window_resize(w, w->drag.w + dw, w->drag.h + dh); + w->drag.w += dw; + w->drag.h += dh; + w->drag.px = pt.x; + w->drag.py = pt.y; + return 0; + } + } + } + + if (GetClientRect(window, &rect)) + { + POINT pt; + + INF("mouse in window"); + + pt.x = GET_X_LPARAM(data_param); + pt.y = GET_Y_LPARAM(data_param); + if (!PtInRect(&rect, pt)) + { + if (w->pointer_is_in) + { + w->pointer_is_in = 0; + _ecore_win32_event_handle_leave_notify(data); + } + } + else + { + if (!w->pointer_is_in) + { + w->pointer_is_in = 1; + _ecore_win32_event_handle_enter_notify(data); + } + } + } + else + { + ERR("GetClientRect() failed"); + } + _ecore_win32_event_handle_motion_notify(data); + + return 0; + } + case WM_MOUSEWHEEL: + INF("mouse wheel message"); + _ecore_win32_event_handle_button_press(data, 4); + return 0; + /* Window notifications */ + case WM_CREATE: + INF("create window message"); + _ecore_win32_event_handle_create_notify(data); + return 0; + case WM_DESTROY: + INF("destroy window message"); + _ecore_win32_event_handle_destroy_notify(data); + return 0; + case WM_SHOWWINDOW: + INF("show window message"); + if ((data->data_param == SW_OTHERUNZOOM) || + (data->data_param == SW_OTHERZOOM)) + return 0; + + if (data->window_param) + _ecore_win32_event_handle_map_notify(data); + else + _ecore_win32_event_handle_unmap_notify(data); + + return 0; + case WM_CLOSE: + INF("close window message"); + _ecore_win32_event_handle_delete_request(data); + return 0; + case WM_GETMINMAXINFO: + INF("get min max info window message"); + return TRUE; + case WM_MOVING: + INF("moving window message"); + _ecore_win32_event_handle_configure_notify(data); + return TRUE; + case WM_MOVE: + INF("move window message"); + return 0; + case WM_SIZING: + INF("sizing window message"); + _ecore_win32_event_handle_resize(data); + _ecore_win32_event_handle_configure_notify(data); + return TRUE; + case WM_SIZE: + INF("size window message"); + return 0; +/* case WM_WINDOWPOSCHANGING: */ +/* { */ +/* RECT rect; */ +/* GetClientRect(window, &rect); */ +/* printf (" *** ecore message : WINDOWPOSCHANGING %ld %ld\n", */ +/* rect.right - rect.left, rect.bottom - rect.top); */ +/* } */ +/* _ecore_win32_event_handle_configure_notify(data); */ +/* return 0; */ + case WM_WINDOWPOSCHANGED: + INF("position changed window message"); + _ecore_win32_event_handle_configure_notify(data); + _ecore_win32_event_handle_expose(data); + return 0; + case WM_ENTERSIZEMOVE: + INF("enter size move window message"); + return 0; + case WM_EXITSIZEMOVE: + INF("exit size move window message"); + return 0; + case WM_NCLBUTTONDOWN: + INF("non client left button down window message"); + + if (((DWORD)window_param == HTCAPTION) || + ((DWORD)window_param == HTBOTTOM) || + ((DWORD)window_param == HTBOTTOMLEFT) || + ((DWORD)window_param == HTBOTTOMRIGHT) || + ((DWORD)window_param == HTLEFT) || + ((DWORD)window_param == HTRIGHT) || + ((DWORD)window_param == HTTOP) || + ((DWORD)window_param == HTTOPLEFT) || + ((DWORD)window_param == HTTOPRIGHT)) + { + Ecore_Win32_Window *w; + + w = (Ecore_Win32_Window *)GetWindowLongPtr(window, GWLP_USERDATA); + ecore_win32_window_geometry_get(w, + NULL, NULL, + &w->drag.w, &w->drag.h); + SetCapture(window); + w->drag.type = (DWORD)window_param; + w->drag.px = GET_X_LPARAM(data_param); + w->drag.py = GET_Y_LPARAM(data_param); + w->drag.dragging = 1; + return 0; + } + return DefWindowProc(window, message, window_param, data_param); + case WM_SYSCOMMAND: + INF("sys command window message %d", (int)window_param); + + if ((((DWORD)window_param & 0xfff0) == SC_MOVE) || + (((DWORD)window_param & 0xfff0) == SC_SIZE)) + { + Ecore_Win32_Window *w; + + INF("sys command MOVE or SIZE window message : %dx%d", GET_X_LPARAM(data_param), GET_Y_LPARAM(data_param)); + + w = (Ecore_Win32_Window *)GetWindowLongPtr(window, GWLP_USERDATA); + w->drag.dragging = 1; + return 0; + } + return DefWindowProc(window, message, window_param, data_param); + /* GDI notifications */ + case WM_ERASEBKGND: + return 1; + case WM_PAINT: + { + RECT rect; + + INF("paint message"); + + if (GetUpdateRect(window, &rect, FALSE)) + { + PAINTSTRUCT ps; + HDC hdc; + + hdc = BeginPaint(window, &ps); + data->update = rect; + _ecore_win32_event_handle_expose(data); + EndPaint(window, &ps); + } + return 0; + } + case WM_SETREDRAW: + INF("set redraw message"); + return 0; + case WM_SYNCPAINT: + INF("sync paint message"); + return 0; + default: + return DefWindowProc(window, message, window_param, data_param); + } +} + +/** + * @endcond + */ + + +/*============================================================================* + * Global * + *============================================================================*/ + + +HINSTANCE _ecore_win32_instance = NULL; +double _ecore_win32_double_click_time = 0.25; +unsigned long _ecore_win32_event_last_time = 0; +Ecore_Win32_Window *_ecore_win32_event_last_window = NULL; +int _ecore_win32_log_dom_global = -1; + +int ECORE_WIN32_EVENT_MOUSE_IN = 0; +int ECORE_WIN32_EVENT_MOUSE_OUT = 0; +int ECORE_WIN32_EVENT_WINDOW_FOCUS_IN = 0; +int ECORE_WIN32_EVENT_WINDOW_FOCUS_OUT = 0; +int ECORE_WIN32_EVENT_WINDOW_DAMAGE = 0; +int ECORE_WIN32_EVENT_WINDOW_CREATE = 0; +int ECORE_WIN32_EVENT_WINDOW_DESTROY = 0; +int ECORE_WIN32_EVENT_WINDOW_SHOW = 0; +int ECORE_WIN32_EVENT_WINDOW_HIDE = 0; +int ECORE_WIN32_EVENT_WINDOW_CONFIGURE = 0; +int ECORE_WIN32_EVENT_WINDOW_RESIZE = 0; +int ECORE_WIN32_EVENT_WINDOW_DELETE_REQUEST = 0; + +/*============================================================================* + * API * + *============================================================================*/ + +/** + * @addtogroup Ecore_Win32_Group Ecore_Win32 library + * + * Ecore_Win32 is a library that wraps Windows graphic functions + * and integrate them nicely into the Ecore main loop. + * + * @section Ecore_Win32_Sec_Init Initialisation / Shutdown + * + * To fill... + * + * @section Ecore_Win32_Sec_Icons How to set icons to an application + * + * It is possible to also sets the icon of the application easily: + * + * @li Create an icon with your favorite image creator. The Gimp is a + * good choice. Create several images of size 16, 32 and 48. You can + * also create images of size 24, 64, 128 and 256. Paste all of them + * in the image of size 16 as a layer. Save the image of size 16 with + * the name my_icon.ico. Put it where the source code of the + * application is located. + * @li Create my_icon_rc.rc file with your code editor and add in it: + * @code + * 101 ICON DISCARDABLE "my_icon.ico" + * @endcode + * @li With Visual Studio, put that file in the 'Resource file' part + * of the project. + * @li With MinGW, you have to compile it with windres: + * @code + * windres my_icon_rc.rc my_icon_rc.o + * @endcode + * and add my_icon_rc.o to the object files of the application. + * + * @note The value 101 must not be changed, it's the ID used + * internally by Ecore_Win32 to get the icons. + * + * @{ + */ + +/** + * @brief Initialize the Ecore_Win32 library. + * + * @return 1 or greater on success, 0 on error. + * + * This function sets up the Windows graphic system. It returns 0 on + * failure, otherwise it returns the number of times it has already been + * called. + * + * When Ecore_Win32 is not used anymore, call ecore_win32_shutdown() + * to shut down the Ecore_Win32 library. + */ +EAPI int +ecore_win32_init() +{ + WNDCLASSEX wc; + HICON icon; + HICON icon_sm; + + if (++_ecore_win32_init_count != 1) + return _ecore_win32_init_count; + + if (!eina_init()) + return --_ecore_win32_init_count; + + _ecore_win32_log_dom_global = eina_log_domain_register + ("ecore_win32", ECORE_WIN32_DEFAULT_LOG_COLOR); + if (_ecore_win32_log_dom_global < 0) + { + EINA_LOG_ERR("Ecore_Win32: Could not register log domain"); + goto shutdown_eina; + } + + if (!ecore_event_init()) + { + ERR("Ecore_Win32: Could not init ecore_event"); + goto unregister_log_domain; + } + + _ecore_win32_instance = GetModuleHandle(NULL); + if (!_ecore_win32_instance) + { + ERR("GetModuleHandle() failed"); + goto shutdown_ecore_event; + } + + icon = LoadImage(_ecore_win32_instance, + MAKEINTRESOURCE(IDI_ICON), + IMAGE_ICON, + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON), + LR_DEFAULTCOLOR); + icon_sm = LoadImage(_ecore_win32_instance, + MAKEINTRESOURCE(IDI_ICON), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + LR_DEFAULTCOLOR); + if (!icon) + icon = LoadIcon (NULL, IDI_APPLICATION); + if (!icon_sm) + icon_sm = LoadIcon (NULL, IDI_APPLICATION); + + memset (&wc, 0, sizeof (WNDCLASSEX)); + wc.cbSize = sizeof (WNDCLASSEX); + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = _ecore_win32_window_procedure; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = _ecore_win32_instance; + wc.hIcon = icon; + wc.hCursor = LoadCursor (NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(1 + COLOR_BTNFACE); + wc.lpszMenuName = NULL; + wc.lpszClassName = ECORE_WIN32_WINDOW_CLASS; + wc.hIconSm = icon_sm; + + if(!RegisterClassEx(&wc)) + { + ERR("RegisterClass() failed"); + goto free_library; + } + + if (!ecore_win32_dnd_init()) + { + ERR("ecore_win32_dnd_init() failed"); + goto unregister_class; + } + + if (!ECORE_WIN32_EVENT_MOUSE_IN) + { + ECORE_WIN32_EVENT_MOUSE_IN = ecore_event_type_new(); + ECORE_WIN32_EVENT_MOUSE_OUT = ecore_event_type_new(); + ECORE_WIN32_EVENT_WINDOW_FOCUS_IN = ecore_event_type_new(); + ECORE_WIN32_EVENT_WINDOW_FOCUS_OUT = ecore_event_type_new(); + ECORE_WIN32_EVENT_WINDOW_DAMAGE = ecore_event_type_new(); + ECORE_WIN32_EVENT_WINDOW_CREATE = ecore_event_type_new(); + ECORE_WIN32_EVENT_WINDOW_DESTROY = ecore_event_type_new(); + ECORE_WIN32_EVENT_WINDOW_SHOW = ecore_event_type_new(); + ECORE_WIN32_EVENT_WINDOW_HIDE = ecore_event_type_new(); + ECORE_WIN32_EVENT_WINDOW_CONFIGURE = ecore_event_type_new(); + ECORE_WIN32_EVENT_WINDOW_RESIZE = ecore_event_type_new(); + ECORE_WIN32_EVENT_WINDOW_DELETE_REQUEST = ecore_event_type_new(); + } + + return _ecore_win32_init_count; + + unregister_class: + UnregisterClass(ECORE_WIN32_WINDOW_CLASS, _ecore_win32_instance); + free_library: + FreeLibrary(_ecore_win32_instance); + shutdown_ecore_event: + ecore_event_shutdown(); + unregister_log_domain: + eina_log_domain_unregister(_ecore_win32_log_dom_global); + shutdown_eina: + eina_shutdown(); + + return --_ecore_win32_init_count; +} + +/** + * @brief Shut down the Ecore_Win32 library. + * + * @return 0 when the library is completely shut down, 1 or + * greater otherwise. + * + * This function shuts down the Ecore_Win32 library. It returns 0 when it has + * been called the same number of times than ecore_win32_init(). In that case + * it shuts down all the Windows graphic system. + */ +EAPI int +ecore_win32_shutdown() +{ + if (--_ecore_win32_init_count != 0) + return _ecore_win32_init_count; + + ecore_win32_dnd_shutdown(); + + if (!UnregisterClass(ECORE_WIN32_WINDOW_CLASS, _ecore_win32_instance)) + INF("UnregisterClass() failed"); + + if (!FreeLibrary(_ecore_win32_instance)) + INF("FreeLibrary() failed"); + + _ecore_win32_instance = NULL; + + ecore_event_shutdown(); + eina_log_domain_unregister(_ecore_win32_log_dom_global); + _ecore_win32_log_dom_global = -1; + eina_shutdown(); + + return _ecore_win32_init_count; +} + +/** + * @brief Retrieve the depth of the screen. + * + * @return The depth of the screen. + * + * This function returns the depth of the screen. If an error occurs, + * it returns 0. + */ +EAPI int +ecore_win32_screen_depth_get() +{ + HDC dc; + int depth; + + INF("getting screen depth"); + + dc = GetDC(NULL); + if (!dc) + { + ERR("GetDC() failed"); + return 0; + } + + depth = GetDeviceCaps(dc, BITSPIXEL); + if (!ReleaseDC(NULL, dc)) + { + ERR("ReleaseDC() failed (device context not released)"); + } + + return depth; +} + +/** + * @brief Sets the timeout for a double and triple clicks to be flagged. + * + * @param t The time in seconds. + * + * This function sets the time @p t between clicks before the + * double_click flag is set in a button down event. If 3 clicks occur + * within double this time, the triple_click flag is also set. + */ +EAPI void +ecore_win32_double_click_time_set(double t) +{ + if (t < 0.0) t = 0.0; + _ecore_win32_double_click_time = t; +} + +/** + * @brief Retrieve the double and triple click flag timeout. + * + * @return The timeout for double clicks in seconds. + * + * This function returns the double clicks in seconds. If + * ecore_win32_double_click_time_set() has not been called, the + * default value is returned. See ecore_win32_double_click_time_set() + * for more informations. + */ +EAPI double +ecore_win32_double_click_time_get(void) +{ + return _ecore_win32_double_click_time; +} + +/** + * @brief Return the last event time. + * + * @return The last envent time. + * + * This function returns the last event time. + */ +EAPI unsigned long +ecore_win32_current_time_get(void) +{ + return _ecore_win32_event_last_time; +} + +/** + * @} + */ diff --git a/src/lib/ecore_win32/ecore_win32_cursor.c b/src/lib/ecore_win32/ecore_win32_cursor.c new file mode 100644 index 0000000..9b58c95 --- /dev/null +++ b/src/lib/ecore_win32/ecore_win32_cursor.c @@ -0,0 +1,305 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN + +#include + +#include "Ecore_Win32.h" +#include "ecore_win32_private.h" + +/*============================================================================* + * Local * + *============================================================================*/ + + +/*============================================================================* + * Global * + *============================================================================*/ + + +/*============================================================================* + * API * + *============================================================================*/ + +/** + * @addtogroup Ecore_Win32_Group Ecore_Win32 library + * + * @{ + */ + +/** + * @brief Create a new cursor. + * + * @param pixels_and The array of bytes containing the bit values for + * the AND mask of the cursor. + * @param pixels_xor The array of bytes containing the bit values for + * the XOR mask of the cursor. + * @param width The width of the cursor. + * @param height The height of the cursor. + * @param hot_x The horizontal position of the cursor's hot spot. + * @param hot_y The vertical position of the cursor's hot spot. + * @return A newly user-defined cursor. + * + * This function creates a new cursor of size @p width and @p + * height. They must be valid size. To determine the valid size of a + * cursor, use ecore_win32_cursor_size_get(). @p pixels_and is an array + * of bytes (unsigned char) containing the bits of the cursor that + * will be visible. @p pixels_xor is similar but will allow the cursor + * to have a shape. Here is the truth table for the masks: + * + * + * + * + * + * + * + *
AND maskXOR maskDisplay
0 0 Black
0 1 White
1 0 Screen
1 1 Reverse screen
+ * + * @p hot_x and @p hot_y are the position of the hot spot of the + * cursor. If @p pixels_and or @p pixels_xor are @c NULL, the function + * returns NULL. If @p width or @p height does not match the valid + * size of a cursor, the function returns @c NULL. On success, the + * function creates a user-defined cursor, otherwise it returns + * @c NULL. + * + * Once the cursor is not used anymore, use ecore_win32_cursor_free() + * to free the ressources. + * + * Example of use: + * + * @code + * unsigned char pixels_and[] ={ + * 0xFF, 0xFC, 0x3F, 0xFF, // line 1 + * 0xFF, 0xC0, 0x1F, 0xFF, // line 2 + * 0xFF, 0x00, 0x3F, 0xFF, // line 3 + * 0xFE, 0x00, 0xFF, 0xFF, // line 4 + * + * 0xF7, 0x01, 0xFF, 0xFF, // line 5 + * 0xF0, 0x03, 0xFF, 0xFF, // line 6 + * 0xF0, 0x03, 0xFF, 0xFF, // line 7 + * 0xE0, 0x07, 0xFF, 0xFF, // line 8 + * + * 0xC0, 0x07, 0xFF, 0xFF, // line 9 + * 0xC0, 0x0F, 0xFF, 0xFF, // line 10 + * 0x80, 0x0F, 0xFF, 0xFF, // line 11 + * 0x80, 0x0F, 0xFF, 0xFF, // line 12 + * + * 0x80, 0x07, 0xFF, 0xFF, // line 13 + * 0x00, 0x07, 0xFF, 0xFF, // line 14 + * 0x00, 0x03, 0xFF, 0xFF, // line 15 + * 0x00, 0x00, 0xFF, 0xFF, // line 16 + * + * 0x00, 0x00, 0x7F, 0xFF, // line 17 + * 0x00, 0x00, 0x1F, 0xFF, // line 18 + * 0x00, 0x00, 0x0F, 0xFF, // line 19 + * 0x80, 0x00, 0x0F, 0xFF, // line 20 + * + * 0x80, 0x00, 0x07, 0xFF, // line 21 + * 0x80, 0x00, 0x07, 0xFF, // line 22 + * 0xC0, 0x00, 0x07, 0xFF, // line 23 + * 0xC0, 0x00, 0x0F, 0xFF, // line 24 + * + * 0xE0, 0x00, 0x0F, 0xFF, // line 25 + * 0xF0, 0x00, 0x1F, 0xFF, // line 26 + * 0xF0, 0x00, 0x1F, 0xFF, // line 27 + * 0xF8, 0x00, 0x3F, 0xFF, // line 28 + * + * 0xFE, 0x00, 0x7F, 0xFF, // line 29 + * 0xFF, 0x00, 0xFF, 0xFF, // line 30 + * 0xFF, 0xC3, 0xFF, 0xFF, // line 31 + * 0xFF, 0xFF, 0xFF, 0xFF // line 32 + * }; + * + * unsigned char pixels_xor[] = { + * 0x00, 0x00, 0x00, 0x00, // line 1 + * 0x00, 0x03, 0xC0, 0x00, // line 2 + * 0x00, 0x3F, 0x00, 0x00, // line 3 + * 0x00, 0xFE, 0x00, 0x00, // line 4 + * + * 0x0E, 0xFC, 0x00, 0x00, // line 5 + * 0x07, 0xF8, 0x00, 0x00, // line 6 + * 0x07, 0xF8, 0x00, 0x00, // line 7 + * 0x0F, 0xF0, 0x00, 0x00, // line 8 + * + * 0x1F, 0xF0, 0x00, 0x00, // line 9 + * 0x1F, 0xE0, 0x00, 0x00, // line 10 + * 0x3F, 0xE0, 0x00, 0x00, // line 11 + * 0x3F, 0xE0, 0x00, 0x00, // line 12 + * + * 0x3F, 0xF0, 0x00, 0x00, // line 13 + * 0x7F, 0xF0, 0x00, 0x00, // line 14 + * 0x7F, 0xF8, 0x00, 0x00, // line 15 + * 0x7F, 0xFC, 0x00, 0x00, // line 16 + * + * 0x7F, 0xFF, 0x00, 0x00, // line 17 + * 0x7F, 0xFF, 0x80, 0x00, // line 18 + * 0x7F, 0xFF, 0xE0, 0x00, // line 19 + * 0x3F, 0xFF, 0xE0, 0x00, // line 20 + * + * 0x3F, 0xC7, 0xF0, 0x00, // line 21 + * 0x3F, 0x83, 0xF0, 0x00, // line 22 + * 0x1F, 0x83, 0xF0, 0x00, // line 23 + * 0x1F, 0x83, 0xE0, 0x00, // line 24 + * + * 0x0F, 0xC7, 0xE0, 0x00, // line 25 + * 0x07, 0xFF, 0xC0, 0x00, // line 26 + * 0x07, 0xFF, 0xC0, 0x00, // line 27 + * 0x01, 0xFF, 0x80, 0x00, // line 28 + * + * 0x00, 0xFF, 0x00, 0x00, // line 29 + * 0x00, 0x3C, 0x00, 0x00, // line 30 + * 0x00, 0x00, 0x00, 0x00, // line 31 + * 0x00, 0x00, 0x00, 0x00 // line 32 + * }; + * + * Ecore_Win32_Cursor *cursor = ecore_win32_cursor_new(pixels_and, pixels_xor, 32, 32, 19, 2); + * @endcode + */ +EAPI Ecore_Win32_Cursor * +ecore_win32_cursor_new(const void *pixels_and, + const void *pixels_xor, + int width, + int height, + int hot_x, + int hot_y) +{ + Ecore_Win32_Cursor *cursor = NULL; + int cursor_width; + int cursor_height; + + INF("creating cursor"); + + if (!pixels_and || !pixels_xor) + return NULL; + + cursor_width = GetSystemMetrics(SM_CXCURSOR); + cursor_height = GetSystemMetrics(SM_CYCURSOR); + + if ((cursor_width != width) || + (cursor_height != height)) + return NULL; + + if (!(cursor = CreateCursor(_ecore_win32_instance, + hot_x, hot_y, + width, height, + pixels_and, + pixels_xor))) + return NULL; + + return cursor; +} + +/** + * @brief Free the given cursor. + * + * @param cursor The cursor to free. + * + * This function free @p cursor. @p cursor must have been obtained + * with ecore_win32_cursor_new(). + */ +EAPI void +ecore_win32_cursor_free(Ecore_Win32_Cursor *cursor) +{ + INF("destroying cursor"); + + DestroyCursor(cursor); +} + +/** + * @brief Create a cursor from a Windows ressource. + * + * @param shape The pre-defined shape of the cursor. + * @return The new cursor. + * + * This function returns a pre-defined cursor with a specified + * @p shape. This cursor does not need to be freed, as it is loaded + * from an existing resource. + */ +EAPI Ecore_Win32_Cursor * +ecore_win32_cursor_shaped_new(Ecore_Win32_Cursor_Shape shape) +{ + Ecore_Win32_Cursor *cursor = NULL; + const char *cursor_name; + + INF("geting shape cursor"); + + switch (shape) + { + case ECORE_WIN32_CURSOR_SHAPE_APP_STARTING: + cursor_name = IDC_APPSTARTING; + break; + case ECORE_WIN32_CURSOR_SHAPE_ARROW: + cursor_name = IDC_ARROW; + break; + case ECORE_WIN32_CURSOR_SHAPE_CROSS: + cursor_name = IDC_CROSS; + break; + case ECORE_WIN32_CURSOR_SHAPE_HAND: + cursor_name = IDC_HAND; + break; + case ECORE_WIN32_CURSOR_SHAPE_HELP: + cursor_name = IDC_HELP; + break; + case ECORE_WIN32_CURSOR_SHAPE_I_BEAM: + cursor_name = IDC_IBEAM; + break; + case ECORE_WIN32_CURSOR_SHAPE_NO: + cursor_name = IDC_NO; + break; + case ECORE_WIN32_CURSOR_SHAPE_SIZE_ALL: + cursor_name = IDC_SIZEALL; + break; + case ECORE_WIN32_CURSOR_SHAPE_SIZE_NESW: + cursor_name = IDC_SIZENESW; + break; + case ECORE_WIN32_CURSOR_SHAPE_SIZE_NS: + cursor_name = IDC_SIZENS; + break; + case ECORE_WIN32_CURSOR_SHAPE_SIZE_NWSE: + cursor_name = IDC_SIZENWSE; + break; + case ECORE_WIN32_CURSOR_SHAPE_SIZE_WE: + cursor_name = IDC_SIZEWE; + break; + case ECORE_WIN32_CURSOR_SHAPE_UP_ARROW: + cursor_name = IDC_UPARROW; + break; + case ECORE_WIN32_CURSOR_SHAPE_WAIT: + cursor_name = IDC_WAIT; + break; + default: + return NULL; + } + + if (!(cursor = LoadCursor(NULL, cursor_name))) + return NULL; + + return cursor; +} + +/** + * @brief Retrieve the size of a valid cursor. + * + * @param width The width of a valid cursor. + * @param height The height of a valid cursor. + * + * This function returns the size of a cursor that must be passed to + * ecore_win32_cursor_new(). @p width and @p height are buffers that + * will be filled with the correct size. They can be @c NULL. + */ +EAPI void +ecore_win32_cursor_size_get(int *width, int *height) +{ + INF("geting size cursor"); + + if (*width) *width = GetSystemMetrics(SM_CXCURSOR); + if (*height) *height = GetSystemMetrics(SM_CYCURSOR); +} + +/** + * @} + */ diff --git a/src/lib/ecore_win32/ecore_win32_dnd.c b/src/lib/ecore_win32/ecore_win32_dnd.c new file mode 100755 index 0000000..6c5253a --- /dev/null +++ b/src/lib/ecore_win32/ecore_win32_dnd.c @@ -0,0 +1,221 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "Ecore_Win32.h" +#include "ecore_win32_private.h" + +/*============================================================================* + * Local * + *============================================================================*/ + +/** + * @cond LOCAL + */ + + +static int _ecore_win32_dnd_init_count = 0; + +static HANDLE DataToHandle(const char *data, int size) +{ + char *ptr; + ptr = (char *)GlobalAlloc(GMEM_FIXED, size); + memcpy(ptr, data, size); + return ptr; +} + +/** + * @endcond + */ + + +/*============================================================================* + * Global * + *============================================================================*/ + + +/*============================================================================* + * API * + *============================================================================*/ + +/** + * @addtogroup Ecore_Win32_Group Ecore_Win32 library + * + * @{ + */ + +/** + * @brief Initialize the Ecore_Win32 Drag and Drop module. + * + * @return 1 or greater on success, 0 on error. + * + * This function initialize the Drag and Drop module. It returns 0 on + * failure, otherwise it returns the number of times it has already + * been called. + * + * When the Drag and Drop module is not used anymore, call + * ecore_win32_dnd_shutdown() to shut down the module. + */ +EAPI int +ecore_win32_dnd_init() +{ + if (_ecore_win32_dnd_init_count > 0) + { + _ecore_win32_dnd_init_count++; + return _ecore_win32_dnd_init_count; + } + + if (OleInitialize(NULL) != S_OK) + return 0; + + _ecore_win32_dnd_init_count++; + + return _ecore_win32_dnd_init_count; +} + +/** + * @brief Shut down the Ecore_Win32 Drag and Drop module. + * + * @return 0 when the module is completely shut down, 1 or + * greater otherwise. + * + * This function shuts down the Drag and Drop module. It returns 0 when it has + * been called the same number of times than ecore_win32_dnd_init(). In that case + * it shut down the module. + */ +EAPI int +ecore_win32_dnd_shutdown() +{ + _ecore_win32_dnd_init_count--; + if (_ecore_win32_dnd_init_count > 0) return _ecore_win32_dnd_init_count; + + OleUninitialize(); + + if (_ecore_win32_dnd_init_count < 0) _ecore_win32_dnd_init_count = 0; + + return _ecore_win32_dnd_init_count; +} + +/** + * @brief Begin a DnD operation. + * + * @param data The name pf the Drag operation. + * @param size The size of the name. + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * This function start a Drag operation with the name @p data. If + * @p data is @c NULL, @c EINA_FALSE is returned. if @p size is less than + * @c 0, it is set to the length (as strlen()) of @p data. On success the + * function returns @c EINA_TRUE, otherwise it returns @c EINA_FALSE. + */ +EAPI Eina_Bool +ecore_win32_dnd_begin(const char *data, + int size) +{ + IDataObject *pDataObject = NULL; + IDropSource *pDropSource = NULL; + FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + STGMEDIUM stgmed = { TYMED_HGLOBAL, { 0 }, 0 }; + Eina_Bool res = EINA_FALSE; + + if (!data) + return EINA_FALSE; + + if (size < 0) + size = strlen(data) + 1; + + stgmed.hGlobal = DataToHandle(data, size); + + // create the data object + pDataObject = (IDataObject *)_ecore_win32_dnd_data_object_new((void *)&fmtetc, + (void *)&stgmed, + 1); + pDropSource = (IDropSource *)_ecore_win32_dnd_drop_source_new(); + + if (pDataObject && pDropSource) + { + DWORD dwResult; + DWORD dwEffect = DROPEFFECT_COPY; + + // do the drag-drop! + dwResult = DoDragDrop(pDataObject, pDropSource, DROPEFFECT_COPY, &dwEffect); + + // finished. Check the return values to see if we need to do anything else + if (dwResult == DRAGDROP_S_DROP) + { + //printf(">>> \"%s\" Dropped <<<\n", str); + if(dwEffect == DROPEFFECT_MOVE) + { + // remove the data we just dropped from active document + } + } + //else if (dwResult == DRAGDROP_S_CANCEL) + // printf("DND cancelled\n"); + //else + // printf("DND error\n"); + + res = EINA_TRUE; + } + + _ecore_win32_dnd_data_object_free(pDataObject); + _ecore_win32_dnd_drop_source_free(pDropSource); + + // cleanup + ReleaseStgMedium(&stgmed); + + return res; +} + +/** + * @brief Register a Drop operation. + * + * @param window The destination of the Drop operation. + * @param callback The callback called when the Drop operation + * finishes. + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * This function register a Drop operation on @p window. Once the Drop + * operation finishes, @p callback is called. If @p window is @c NULL, + * the function returns @c EINA_FALSE. On success, it returns @c EINA_TRUE, + * otherwise it returns @c EINA_FALSE. + */ +EAPI Eina_Bool +ecore_win32_dnd_register_drop_target(Ecore_Win32_Window *window, + Ecore_Win32_Dnd_DropTarget_Callback callback) +{ + Ecore_Win32_Window *wnd = (Ecore_Win32_Window *)window; + + if (!window) + return EINA_FALSE; + + wnd->dnd_drop_target = _ecore_win32_dnd_register_drop_window(wnd->window, + callback, + (void *)wnd); + return wnd->dnd_drop_target ? EINA_TRUE : EINA_FALSE; +} + +/** + * @brief Unregister a Drop operation. + * + * @param window The destination of the Drop operation. + * + * This function unregister a Drop operation on @p window. If + * @p window is @c NULL, the function does nothing. + */ +EAPI void +ecore_win32_dnd_unregister_drop_target(Ecore_Win32_Window *window) +{ + Ecore_Win32_Window *wnd = (Ecore_Win32_Window *)window; + + if (!window) + return; + + if (wnd->dnd_drop_target) + _ecore_win32_dnd_unregister_drop_window(wnd->window, wnd->dnd_drop_target); +} + +/** + * @} + */ diff --git a/src/lib/ecore_win32/ecore_win32_dnd_data_object.cpp b/src/lib/ecore_win32/ecore_win32_dnd_data_object.cpp new file mode 100644 index 0000000..75e26f5 --- /dev/null +++ b/src/lib/ecore_win32/ecore_win32_dnd_data_object.cpp @@ -0,0 +1,209 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN +#include + +#include "Ecore_Win32.h" +#include "ecore_win32_private.h" + +#include "ecore_win32_dnd_enumformatetc.h" +#include "ecore_win32_dnd_data_object.h" + + +static HGLOBAL DupGlobalMem(HGLOBAL hMem) +{ + DWORD len = (DWORD)GlobalSize(hMem); + PVOID source = GlobalLock(hMem); + PVOID dest = GlobalAlloc(GMEM_FIXED, len); + memcpy(dest, source, len); + GlobalUnlock(hMem); + return dest; +} + +// structors + +DataObject::DataObject(FORMATETC *fmtetc, STGMEDIUM *stgmed, int count) +{ + assert(fmtetc != NULL); + assert(stgmed != NULL); + assert(count > 0); + + // reference count must ALWAYS start at 1 + ref_count_ = 1; + formats_num_ = count; + + format_etc_ = new FORMATETC[count]; + stg_medium_ = new STGMEDIUM[count]; + + for(int i = 0; i < count; i++) + { + format_etc_[i] = fmtetc[i]; + stg_medium_[i] = stgmed[i]; + } +} + +DataObject::~DataObject() +{ + delete[] format_etc_; + delete[] stg_medium_; +} + + +// IUnknown + +HRESULT DataObject::QueryInterface(REFIID iid, void **ppvObject) +{ + // check to see what interface has been requested + if ((iid == IID_IDataObject) || (iid == IID_IUnknown)) + { + AddRef(); + *ppvObject = this; + return S_OK; + } + *ppvObject = 0; + return E_NOINTERFACE; +} + +ULONG DataObject::AddRef() +{ + return InterlockedIncrement(&ref_count_); +} + +ULONG DataObject::Release() +{ + LONG count = InterlockedDecrement(&ref_count_); + if(count == 0) + { + delete this; + return 0; + } + return count; +} + +// IDataObject + +HRESULT DataObject::GetData(FORMATETC *pFormatEtc, STGMEDIUM *pMedium) +{ + assert(pMedium != NULL); + int idx; + + // try to match the specified FORMATETC with one of our supported formats + if((idx = lookup_format_etc(pFormatEtc)) == -1) + return DV_E_FORMATETC; + + // found a match - transfer data into supplied storage medium + pMedium->tymed = format_etc_[idx].tymed; + pMedium->pUnkForRelease = 0; + + // copy the data into the caller's storage medium + switch(format_etc_[idx].tymed) + { + case TYMED_HGLOBAL: + pMedium->hGlobal = DupGlobalMem(stg_medium_[idx].hGlobal); + break; + + default: + return DV_E_FORMATETC; + } + + return S_OK; +} + +HRESULT DataObject::GetDataHere(FORMATETC *pFormatEtc __UNUSED__, STGMEDIUM *pmedium __UNUSED__) +{ + return DATA_E_FORMATETC; +} + +HRESULT DataObject::QueryGetData(FORMATETC *pFormatEtc) +{ + return (lookup_format_etc(pFormatEtc) == -1) ? DV_E_FORMATETC : S_OK; +} + +HRESULT DataObject::GetCanonicalFormatEtc(FORMATETC *pFormatEct __UNUSED__, FORMATETC *pFormatEtcOut) +{ + // Apparently we have to set this field to NULL even though we don't do anything else + pFormatEtcOut->ptd = NULL; + return E_NOTIMPL; +} + +HRESULT DataObject::SetData(FORMATETC *pFormatEtc __UNUSED__, STGMEDIUM *pMedium __UNUSED__, BOOL fRelease __UNUSED__) +{ + return E_NOTIMPL; +} + +HRESULT DataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc) +{ + // only the get direction is supported for OLE + if(dwDirection == DATADIR_GET) + { + // for Win2k+ you can use the SHCreateStdEnumFmtEtc API call, however + // to support all Windows platforms we need to implement IEnumFormatEtc ourselves. + return CreateEnumFormatEtc(formats_num_, format_etc_, ppEnumFormatEtc); + } + else + { + // the direction specified is not supported for drag+drop + return E_NOTIMPL; + } +} + +HRESULT DataObject::DAdvise(FORMATETC *pFormatEtc __UNUSED__, DWORD advf __UNUSED__, IAdviseSink *, DWORD *) +{ + return OLE_E_ADVISENOTSUPPORTED; +} + +HRESULT DataObject::DUnadvise(DWORD dwConnection __UNUSED__) +{ + return OLE_E_ADVISENOTSUPPORTED; +} + +HRESULT DataObject::EnumDAdvise(IEnumSTATDATA **ppEnumAdvise __UNUSED__) +{ + return OLE_E_ADVISENOTSUPPORTED; +} + +// internal helper function + +int DataObject::lookup_format_etc(FORMATETC *pFormatEtc) +{ + // check each of our formats in turn to see if one matches + for(int i = 0; i < formats_num_; i++) + { + if((format_etc_[i].tymed & pFormatEtc->tymed) && + (format_etc_[i].cfFormat == pFormatEtc->cfFormat) && + (format_etc_[i].dwAspect == pFormatEtc->dwAspect)) + { + // return index of stored format + return i; + } + } + + // error, format not found + return -1; +} + +void *_ecore_win32_dnd_data_object_new(void *fmtetc, void *stgmeds, int count) +{ + IDataObject *object = new DataObject((FORMATETC *)fmtetc, (STGMEDIUM *)stgmeds, (UINT)count); + assert(object != NULL); + return object; +} + +void _ecore_win32_dnd_data_object_free(void *data_object) +{ + if (!data_object) + return; + + IDataObject *object = (IDataObject *)data_object; + object->Release(); +} diff --git a/src/lib/ecore_win32/ecore_win32_dnd_data_object.h b/src/lib/ecore_win32/ecore_win32_dnd_data_object.h new file mode 100644 index 0000000..3d289cf --- /dev/null +++ b/src/lib/ecore_win32/ecore_win32_dnd_data_object.h @@ -0,0 +1,49 @@ +#ifndef __ECORE_WIN32_DND_DATA_OBJECT_H__ +#define __ECORE_WIN32_DND_DATA_OBJECT_H__ + + +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN +#include + + +class DataObject : public IDataObject +{ + private: + + LONG ref_count_; + int formats_num_; + FORMATETC *format_etc_; + STGMEDIUM *stg_medium_; + + private: // internal helper function + + int lookup_format_etc(FORMATETC *format_etc); + + public: // structors + + DataObject(FORMATETC *fmtetc, STGMEDIUM *stgmed, int count); + ~DataObject(); + + public: // IUnknown + + HRESULT __stdcall QueryInterface(REFIID iid, void **ppvObject); + ULONG __stdcall AddRef(); + ULONG __stdcall Release(); + + public: // IDataObject + + HRESULT __stdcall GetData(FORMATETC *pFormatEtc, STGMEDIUM *pmedium); + HRESULT __stdcall GetDataHere(FORMATETC *pFormatEtc, STGMEDIUM *pmedium); + HRESULT __stdcall QueryGetData(FORMATETC *pFormatEtc); + HRESULT __stdcall GetCanonicalFormatEtc(FORMATETC *pFormatEct, FORMATETC *pFormatEtcOut); + HRESULT __stdcall SetData(FORMATETC *pFormatEtc, STGMEDIUM *pMedium, BOOL fRelease); + HRESULT __stdcall EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc); + HRESULT __stdcall DAdvise(FORMATETC *pFormatEtc, DWORD advf, IAdviseSink *, DWORD *); + HRESULT __stdcall DUnadvise(DWORD dwConnection); + HRESULT __stdcall EnumDAdvise(IEnumSTATDATA **ppEnumAdvise); +}; + + +#endif /* __ECORE_WIN32_DND_DATA_OBJECT_H__ */ diff --git a/src/lib/ecore_win32/ecore_win32_dnd_drop_source.cpp b/src/lib/ecore_win32/ecore_win32_dnd_drop_source.cpp new file mode 100644 index 0000000..bea7736 --- /dev/null +++ b/src/lib/ecore_win32/ecore_win32_dnd_drop_source.cpp @@ -0,0 +1,92 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "ecore_win32_dnd_drop_source.h" + +#include "ecore_win32_private.h" + +// structors + +// reference count must ALWAYS start at 1 +DropSource::DropSource() : ref_count_(1) +{ } + + +// IUnknown + +HRESULT DropSource::QueryInterface(REFIID iid, void **ppvObject) +{ + // check to see what interface has been requested + if (iid == IID_IDropSource || iid == IID_IUnknown) + { + AddRef(); + *ppvObject = this; + return S_OK; + } + *ppvObject = 0; + return E_NOINTERFACE; +} + +ULONG DropSource::AddRef() +{ + return InterlockedIncrement(&ref_count_); +} + +ULONG DropSource::Release() +{ + LONG count = InterlockedDecrement(&ref_count_); + if(count == 0) + { + delete this; + return 0; + } + return count; +} + + +// IDropSource + +HRESULT DropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) +{ + // if the Escape key has been pressed since the last call, cancel the drop + if(fEscapePressed == TRUE) + return DRAGDROP_S_CANCEL; + + // if the LeftMouse button has been released, then do the drop! + if((grfKeyState & MK_LBUTTON) == 0) + return DRAGDROP_S_DROP; + + // continue with the drag-drop + return S_OK; +} + +HRESULT DropSource::GiveFeedback(DWORD dwEffect __UNUSED__) +{ + return DRAGDROP_S_USEDEFAULTCURSORS; +} + + +// ecore_win32 private functions + +void *_ecore_win32_dnd_drop_source_new() +{ + IDropSource *object = new DropSource(); + assert(object != NULL); + return object; +} + +void _ecore_win32_dnd_drop_source_free(void *drop_source) +{ + if (!drop_source) + return; + + IDropSource *object = (IDropSource *)drop_source; + object->Release(); +} diff --git a/src/lib/ecore_win32/ecore_win32_dnd_drop_source.h b/src/lib/ecore_win32/ecore_win32_dnd_drop_source.h new file mode 100644 index 0000000..9081f46 --- /dev/null +++ b/src/lib/ecore_win32/ecore_win32_dnd_drop_source.h @@ -0,0 +1,36 @@ +#ifndef __ECORE_WIN32_DND_DROP_SOURCE_H__ +#define __ECORE_WIN32_DND_DROP_SOURCE_H__ + + +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN +#include + +#include "Ecore_Win32.h" + + +class DropSource : public IDropSource +{ + private: + + LONG ref_count_; + + public: // structors + + DropSource(); + + public: // IUnknown + + HRESULT __stdcall QueryInterface(REFIID iid, void ** ppvObject); + ULONG __stdcall AddRef(); + ULONG __stdcall Release(); + + public: // IDropSource + + HRESULT __stdcall QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState); + HRESULT __stdcall GiveFeedback(DWORD dwEffect); +}; + + +#endif /* __ECORE_WIN32_DND_DROP_SOURCE_H__ */ diff --git a/src/lib/ecore_win32/ecore_win32_dnd_drop_target.cpp b/src/lib/ecore_win32/ecore_win32_dnd_drop_target.cpp new file mode 100644 index 0000000..e19fb5d --- /dev/null +++ b/src/lib/ecore_win32/ecore_win32_dnd_drop_target.cpp @@ -0,0 +1,232 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "ecore_win32_dnd_drop_target.h" + +#include "ecore_win32_private.h" + + +// structors + +DropTarget::DropTarget(HWND window, Ecore_Win32_Dnd_DropTarget_Callback callback, void *window_obj_ptr) + : ref_count_(1) + , window_(window) + , allow_drop_(false) + , drop_callback_(callback) + ,drop_callback_ptr_(window_obj_ptr) +{ } + + +// IUnknown + +HRESULT DropTarget::QueryInterface(REFIID iid, void **ppvObject) +{ + // check to see what interface has been requested + if (iid == IID_IDropTarget || iid == IID_IUnknown) + { + AddRef(); + *ppvObject = this; + return S_OK; + } + *ppvObject = 0; + + return E_NOINTERFACE; +} + +ULONG DropTarget::AddRef() +{ + return InterlockedIncrement(&ref_count_); +} + +ULONG DropTarget::Release() +{ + LONG count = InterlockedDecrement(&ref_count_); + if (count == 0) + { + delete this; + return 0; + } + + return count; +} + + +// IDropTarget + +HRESULT DropTarget::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) +{ + // does the dataobject contain data we want? + allow_drop_ = QueryDataObject(pDataObject) && + (drop_callback_ == NULL || + (drop_callback_(drop_callback_ptr_, ECORE_WIN32_DND_EVENT_DRAG_ENTER, pt.x, pt.y, NULL, 0) != 0)); + + if (allow_drop_) + { + // get the dropeffect based on keyboard state + *pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect); + SetFocus(window_); + //PositionCursor(_hwnd, pt); + } + else + *pdwEffect = DROPEFFECT_NONE; + return S_OK; +} + +HRESULT DropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD * pdwEffect) +{ + allow_drop_ = + (drop_callback_ == NULL) || + (drop_callback_(drop_callback_ptr_, ECORE_WIN32_DND_EVENT_DRAG_OVER, pt.x, pt.y, NULL, 0) != 0); + + if (allow_drop_) + { + *pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect); + //PositionCursor(m_hWnd, pt); + } + else + { + *pdwEffect = DROPEFFECT_NONE; + } + + return S_OK; +} + +HRESULT DropTarget::DragLeave() +{ + POINT pt; + + GetCursorPos(&pt); + if (drop_callback_ != NULL) + drop_callback_(drop_callback_ptr_, ECORE_WIN32_DND_EVENT_DRAG_LEAVE, pt.x, pt.y, NULL, 0); + + return S_OK; +} + +HRESULT DropTarget::Drop(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) +{ + if (allow_drop_) + { + // construct a FORMATETC object + FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + STGMEDIUM stgmed; + + // See if the dataobject contains any TEXT stored as a HGLOBAL + if (pDataObject->QueryGetData(&fmtetc) == S_OK) + { + // Yippie! the data is there, so go get it! + if (pDataObject->GetData(&fmtetc, &stgmed) == S_OK) + { + // we asked for the data as a HGLOBAL, so access it appropriately + PVOID data = GlobalLock(stgmed.hGlobal); + UINT size = GlobalSize(stgmed.hGlobal); + + if (drop_callback_ != NULL) + { + drop_callback_(drop_callback_ptr_, + ECORE_WIN32_DND_EVENT_DROP, + pt.x, pt.y, + data, size); + } + + GlobalUnlock(stgmed.hGlobal); + + // release the data using the COM API + ReleaseStgMedium(&stgmed); + } + } + *pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect); + } + else + { + *pdwEffect = DROPEFFECT_NONE; + } + + return S_OK; +} + + +// internal helper function + +DWORD DropTarget::DropEffect(DWORD grfKeyState, POINTL pt __UNUSED__, DWORD dwAllowed) +{ + DWORD dwEffect = 0; + + // 1. check "pt" -> do we allow a drop at the specified coordinates? + + // 2. work out that the drop-effect should be based on grfKeyState + if (grfKeyState & MK_CONTROL) + { + dwEffect = dwAllowed & DROPEFFECT_COPY; + } + else if (grfKeyState & MK_SHIFT) + { + dwEffect = dwAllowed & DROPEFFECT_MOVE; + } + + // 3. no key-modifiers were specified (or drop effect not allowed), so + // base the effect on those allowed by the dropsource + if (dwEffect == 0) + { + if (dwAllowed & DROPEFFECT_COPY) dwEffect = DROPEFFECT_COPY; + if (dwAllowed & DROPEFFECT_MOVE) dwEffect = DROPEFFECT_MOVE; + } + + return dwEffect; +} + +bool DropTarget::QueryDataObject(IDataObject *pDataObject) +{ + FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + + // does the data object support CF_TEXT using a HGLOBAL? + return pDataObject->QueryGetData(&fmtetc) == S_OK; +} + + +// ecore_win32 private functions + +void *_ecore_win32_dnd_register_drop_window(HWND hwnd, Ecore_Win32_Dnd_DropTarget_Callback callback, void *ptr) +{ + DropTarget *pDropTarget = new DropTarget(hwnd, callback, ptr); + + if (pDropTarget == NULL) + return NULL; + + // acquire a strong lock + if (FAILED(CoLockObjectExternal(pDropTarget, TRUE, FALSE))) + { + delete pDropTarget; + return NULL; + } + + // tell OLE that the window is a drop target + if (FAILED(RegisterDragDrop(hwnd, pDropTarget))) + { + delete pDropTarget; + return NULL; + } + + return pDropTarget; +} + +void _ecore_win32_dnd_unregister_drop_window(HWND hwnd, void *drop_target) +{ + IDropTarget *pDropTarget = (IDropTarget *)drop_target; + + if (drop_target == NULL) + return; + + // remove drag+drop + RevokeDragDrop(hwnd); + + // remove the strong lock + CoLockObjectExternal(pDropTarget, FALSE, TRUE); + + // release our own reference + pDropTarget->Release(); +} diff --git a/src/lib/ecore_win32/ecore_win32_dnd_drop_target.h b/src/lib/ecore_win32/ecore_win32_dnd_drop_target.h new file mode 100644 index 0000000..24c3de3 --- /dev/null +++ b/src/lib/ecore_win32/ecore_win32_dnd_drop_target.h @@ -0,0 +1,47 @@ +#ifndef __ECORE_WIN32_DND_DROP_TARGET_H__ +#define __ECORE_WIN32_DND_DROP_TARGET_H__ + + +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN +#include + +#include "Ecore_Win32.h" + + +class DropTarget : public IDropTarget +{ + private: + + LONG ref_count_; + HWND window_; + bool allow_drop_; + Ecore_Win32_Dnd_DropTarget_Callback drop_callback_; + void *drop_callback_ptr_; + + private: // internal helper function + + DWORD DropEffect(DWORD grfKeyState, POINTL pt, DWORD dwAllowed); + bool QueryDataObject(IDataObject *pDataObject); + + public: // structors + + DropTarget(HWND hwnd, Ecore_Win32_Dnd_DropTarget_Callback callback, void *window_obj_ptr); + +public: // IUnknown + + HRESULT __stdcall QueryInterface(REFIID iid, void ** ppvObject); + ULONG __stdcall AddRef(); + ULONG __stdcall Release(); + + public: // IDropTarget + + HRESULT __stdcall DragEnter(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect); + HRESULT __stdcall DragOver(DWORD grfKeyState, POINTL pt, DWORD * pdwEffect); + HRESULT __stdcall DragLeave(); + HRESULT __stdcall Drop(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect); +}; + + +#endif /* __ECORE_WIN32_DND_DROP_TARGET_H__ */ diff --git a/src/lib/ecore_win32/ecore_win32_dnd_enumformatetc.cpp b/src/lib/ecore_win32/ecore_win32_dnd_enumformatetc.cpp new file mode 100644 index 0000000..a3858bc --- /dev/null +++ b/src/lib/ecore_win32/ecore_win32_dnd_enumformatetc.cpp @@ -0,0 +1,157 @@ + +#include + +#include "ecore_win32_dnd_enumformatetc.h" + + +// structors + +CEnumFormatEtc::CEnumFormatEtc(FORMATETC *format_etc, int formats_num) + : ref_count_(1) + , index_(0) + , formats_num_(formats_num) + , format_etc_(new FORMATETC[formats_num]) +{ + // make a new copy of each FORMATETC structure + for (unsigned int i = 0; i < formats_num_; i++) + { + DeepCopyFormatEtc(&format_etc_[i], &format_etc[i]); + } +} + +CEnumFormatEtc::~CEnumFormatEtc() +{ + if (format_etc_) + { + // first free any DVTARGETDEVICE structures + for (ULONG i = 0; i < formats_num_; i++) + { + if (format_etc_[i].ptd) + CoTaskMemFree(format_etc_[i].ptd); + } + + // now free the main array + delete[] format_etc_; + } +} + +// IUnknown + +ULONG __stdcall CEnumFormatEtc::AddRef(void) +{ + // increment object reference count + return InterlockedIncrement(&ref_count_); +} + +ULONG __stdcall CEnumFormatEtc::Release(void) +{ + // decrement object reference count + LONG count = InterlockedDecrement(&ref_count_); + + if (count == 0) + { + delete this; + return 0; + } + else + { + return count; + } +} + +HRESULT __stdcall CEnumFormatEtc::QueryInterface(REFIID iid, void **ppvObject) +{ + // check to see what interface has been requested + if ((iid == IID_IEnumFORMATETC) || (iid == IID_IUnknown)) + { + AddRef(); + *ppvObject = this; + return S_OK; + } + else + { + *ppvObject = 0; + return E_NOINTERFACE; + } +} + +// IEnumFormatEtc + +HRESULT CEnumFormatEtc::Reset(void) +{ + index_ = 0; + return S_OK; +} + +HRESULT CEnumFormatEtc::Skip(ULONG celt) +{ + index_ += celt; + return (index_ <= formats_num_) ? S_OK : S_FALSE; +} + +HRESULT CEnumFormatEtc::Clone(IEnumFORMATETC **ppEnumFormatEtc) +{ + HRESULT hResult; + + // make a duplicate enumerator + hResult = CreateEnumFormatEtc(formats_num_, format_etc_, ppEnumFormatEtc); + + if (hResult == S_OK) + { + // manually set the index state + ((CEnumFormatEtc *)*ppEnumFormatEtc)->index_ = index_; + } + + return hResult; +} + +HRESULT CEnumFormatEtc::Next(ULONG celt, FORMATETC *pFormatEtc, ULONG *pceltFetched) +{ + ULONG copied = 0; + + // validate arguments + if ((celt == 0) || (pFormatEtc == 0)) + return E_INVALIDARG; + + // copy the FORMATETC structures into the caller's buffer + while (index_ < formats_num_ && copied < celt) + { + DeepCopyFormatEtc(&pFormatEtc[copied], &format_etc_[index_]); + copied++; + index_++; + } + + // store result + if (pceltFetched != 0) + *pceltFetched = copied; + + // did we copy all that was requested? + return (copied == celt) ? S_OK : S_FALSE; +} + +// external functions + +void DeepCopyFormatEtc(FORMATETC *dest, FORMATETC *source) +{ + // copy the source FORMATETC into dest + *dest = *source; + + if (source->ptd) + { + // allocate memory for the DVTARGETDEVICE if necessary + dest->ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE)); + + // copy the contents of the source DVTARGETDEVICE into dest->ptd + *(dest->ptd) = *(source->ptd); + } +} + +HRESULT CreateEnumFormatEtc(UINT cfmt, FORMATETC *afmt, IEnumFORMATETC **ppEnumFormatEtc) +{ + if((cfmt == 0) || (afmt == 0) || (ppEnumFormatEtc == 0)) + return E_INVALIDARG; + + *ppEnumFormatEtc = new CEnumFormatEtc(afmt, cfmt); + + return (*ppEnumFormatEtc) ? S_OK : E_OUTOFMEMORY; +} diff --git a/src/lib/ecore_win32/ecore_win32_dnd_enumformatetc.h b/src/lib/ecore_win32/ecore_win32_dnd_enumformatetc.h new file mode 100644 index 0000000..9f17f56 --- /dev/null +++ b/src/lib/ecore_win32/ecore_win32_dnd_enumformatetc.h @@ -0,0 +1,50 @@ +#ifndef __ECORE_WIN32_DND_ENUMFORMATETC_H__ +#define __ECORE_WIN32_DND_ENUMFORMATETC_H__ + + +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN +#include + + +class CEnumFormatEtc : public IEnumFORMATETC +{ + private: + + LONG ref_count_; // Reference count for this COM interface + ULONG index_; // current enumerator index + ULONG formats_num_; // number of FORMATETC members + FORMATETC *format_etc_; // array of FORMATETC objects + + public: // structors + + CEnumFormatEtc(FORMATETC *pFormatEtc, int nNumFormats); + + ~CEnumFormatEtc(); + + public: // IUnknown + + HRESULT __stdcall QueryInterface (REFIID iid, void ** ppvObject); + + ULONG __stdcall AddRef (void); + + ULONG __stdcall Release (void); + + public: // IEnumFormatEtc + + HRESULT __stdcall Next (ULONG celt, FORMATETC * rgelt, ULONG * pceltFetched); + + HRESULT __stdcall Skip (ULONG celt); + + HRESULT __stdcall Reset (void); + + HRESULT __stdcall Clone (IEnumFORMATETC ** ppEnumFormatEtc); +}; + +void DeepCopyFormatEtc(FORMATETC *dest, FORMATETC *source); + +HRESULT CreateEnumFormatEtc(UINT cfmt, FORMATETC *afmt, IEnumFORMATETC **ppEnumFormatEtc); + + +#endif /* __ECORE_WIN32_DND_ENUMFORMATETC_H__ */ diff --git a/src/lib/ecore_win32/ecore_win32_event.c b/src/lib/ecore_win32/ecore_win32_event.c new file mode 100644 index 0000000..4476b2b --- /dev/null +++ b/src/lib/ecore_win32/ecore_win32_event.c @@ -0,0 +1,1307 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include /* for printf */ + +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN +#include + +#include +#include +#include + +#include "Ecore_Win32.h" +#include "ecore_win32_private.h" + + +typedef enum +{ + ECORE_WIN32_KEY_MASK_LSHIFT = 1 << 0, + ECORE_WIN32_KEY_MASK_RSHIFT = 1 << 1, + ECORE_WIN32_KEY_MASK_LCONTROL = 1 << 2, + ECORE_WIN32_KEY_MASK_RCONTROL = 1 << 3, + ECORE_WIN32_KEY_MASK_LMENU = 1 << 4, + ECORE_WIN32_KEY_MASK_RMENU = 1 << 5 +} Ecore_Win32_Key_Mask; + +/***** Private declarations *****/ + + +static Ecore_Win32_Window *_ecore_win32_mouse_down_last_window = NULL; +static Ecore_Win32_Window *_ecore_win32_mouse_down_last_last_window = NULL; +static long _ecore_win32_mouse_down_last_time = 0 ; +static long _ecore_win32_mouse_down_last_last_time = 0 ; +static int _ecore_win32_mouse_down_did_triple = 0; +static int _ecore_win32_mouse_up_count = 0; +static Ecore_Win32_Key_Mask _ecore_win32_key_mask = 0; + +static void _ecore_win32_event_free_key_down(void *data, + void *ev); + +static void _ecore_win32_event_free_key_up(void *data, + void *ev); + +static int _ecore_win32_event_keystroke_get(Ecore_Win32_Callback_Data *msg, + Eina_Bool is_down, + char **keyname, + char **keysymbol, + char **keycompose, + unsigned int *modifiers); + +static int _ecore_win32_event_char_get(int key, + char **keyname, + char **keysymbol, + char **keycompose, + unsigned int *modifiers); + + +/***** Global functions definitions *****/ + +void +_ecore_win32_event_handle_key_press(Ecore_Win32_Callback_Data *msg, + int is_keystroke) +{ + Ecore_Event_Key *e; + + INF("key pressed"); + + e = (Ecore_Event_Key *)calloc(1, sizeof(Ecore_Event_Key)); + if (!e) return; + + if (is_keystroke) + { + if (!_ecore_win32_event_keystroke_get(msg, + EINA_TRUE, + (char **)&e->keyname, + (char **)&e->key, + (char **)&e->string, + &e->modifiers)) + { + free(e); + return; + } + } + else + { + if (!_ecore_win32_event_char_get(LOWORD(msg->window_param), + (char **)&e->keyname, + (char **)&e->key, + (char **)&e->string, + &e->modifiers)) + { + free(e); + return; + } + } + + e->window = (Ecore_Window)GetWindowLongPtr(msg->window, GWLP_USERDATA); + if (!e->window) + { + free(e); + return; + } + e->event_window = e->window; + e->timestamp = msg->timestamp; + + _ecore_win32_event_last_time = e->timestamp; + + ecore_event_add(ECORE_EVENT_KEY_DOWN, e, _ecore_win32_event_free_key_down, NULL); +} + +void +_ecore_win32_event_handle_key_release(Ecore_Win32_Callback_Data *msg) +{ + Ecore_Event_Key *e; + + INF("key released"); + + e = (Ecore_Event_Key *)calloc(1, sizeof(Ecore_Event_Key)); + if (!e) return; + + if (!_ecore_win32_event_keystroke_get(msg, + EINA_FALSE, + (char **)&e->keyname, + (char **)&e->key, + (char **)&e->string, + &e->modifiers)) + { + if (msg->discard_ctrl || + !_ecore_win32_event_char_get(LOWORD(msg->window_param), + (char **)&e->keyname, + (char **)&e->key, + (char **)&e->string, + &e->modifiers)) + { + free(e); + return; + } + } + + e->window = (Ecore_Window)GetWindowLongPtr(msg->window, GWLP_USERDATA); + if (!e->window) + { + free(e); + return; + } + e->event_window = e->window; + e->timestamp = msg->timestamp; + + _ecore_win32_event_last_time = e->timestamp; + + ecore_event_add(ECORE_EVENT_KEY_UP, e, _ecore_win32_event_free_key_up, NULL); +} + +void +_ecore_win32_event_handle_button_press(Ecore_Win32_Callback_Data *msg, + int button) +{ + Ecore_Win32_Window *window; + + INF("mouse button pressed"); + + window = (Ecore_Win32_Window *)GetWindowLongPtr(msg->window, GWLP_USERDATA); + + if (button > 3) + { + Ecore_Event_Mouse_Wheel *e; + + e = (Ecore_Event_Mouse_Wheel *)calloc(1, sizeof(Ecore_Event_Mouse_Wheel)); + if (!e) return; + + e->window = (Ecore_Window)window; + e->event_window = e->window; + e->direction = 0; + /* wheel delta is positive or negative, never 0 */ + e->z = GET_WHEEL_DELTA_WPARAM(msg->window_param) > 0 ? -1 : 1; + e->x = GET_X_LPARAM(msg->data_param); + e->y = GET_Y_LPARAM(msg->data_param); + e->timestamp = msg->timestamp; + + _ecore_win32_event_last_time = e->timestamp; + _ecore_win32_event_last_window = (Ecore_Win32_Window *)e->window; + + ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, e, NULL, NULL); + } + else + { + { + Ecore_Event_Mouse_Move *e; + + e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move)); + if (!e) return; + + e->window = (Ecore_Window)window; + e->event_window = e->window; + e->x = GET_X_LPARAM(msg->data_param); + e->y = GET_Y_LPARAM(msg->data_param); + e->timestamp = msg->timestamp; + + _ecore_win32_event_last_time = e->timestamp; + _ecore_win32_event_last_window = (Ecore_Win32_Window *)e->window; + + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL); + } + + { + Ecore_Event_Mouse_Button *e; + + if (_ecore_win32_mouse_down_did_triple) + { + _ecore_win32_mouse_down_last_window = NULL; + _ecore_win32_mouse_down_last_last_window = NULL; + _ecore_win32_mouse_down_last_time = 0; + _ecore_win32_mouse_down_last_last_time = 0; + } + + e = (Ecore_Event_Mouse_Button *)calloc(1, sizeof(Ecore_Event_Mouse_Button)); + if (!e) return; + + e->window = (Ecore_Window)window; + e->event_window = e->window; + e->buttons = button; + e->x = GET_X_LPARAM(msg->data_param); + e->y = GET_Y_LPARAM(msg->data_param); + e->timestamp = msg->timestamp; + + if (((e->timestamp - _ecore_win32_mouse_down_last_time) <= (unsigned long)(1000 * _ecore_win32_double_click_time)) && + (e->window == (Ecore_Window)_ecore_win32_mouse_down_last_window)) + e->double_click = 1; + + if (((e->timestamp - _ecore_win32_mouse_down_last_last_time) <= (unsigned long)(2 * 1000 * _ecore_win32_double_click_time)) && + (e->window == (Ecore_Window)_ecore_win32_mouse_down_last_window) && + (e->window == (Ecore_Window)_ecore_win32_mouse_down_last_last_window)) + { + e->triple_click = 1; + _ecore_win32_mouse_down_did_triple = 1; + } + else + _ecore_win32_mouse_down_did_triple = 0; + + if (!e->double_click && !e->triple_click) + _ecore_win32_mouse_up_count = 0; + + _ecore_win32_event_last_time = e->timestamp; + _ecore_win32_event_last_window = (Ecore_Win32_Window *)e->window; + + if (!_ecore_win32_mouse_down_did_triple) + { + _ecore_win32_mouse_down_last_last_window = _ecore_win32_mouse_down_last_window; + _ecore_win32_mouse_down_last_window = (Ecore_Win32_Window *)e->window; + _ecore_win32_mouse_down_last_last_time = _ecore_win32_mouse_down_last_time; + _ecore_win32_mouse_down_last_time = e->timestamp; + } + + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, e, NULL, NULL); + } + } +} + +void +_ecore_win32_event_handle_button_release(Ecore_Win32_Callback_Data *msg, + int button) +{ + Ecore_Win32_Window *window; + + INF("mouse button released"); + + window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); + + { + Ecore_Event_Mouse_Move *e; + + e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move)); + if (!e) return; + + e->window = (Ecore_Window)window; + e->event_window = e->window; + e->x = GET_X_LPARAM(msg->data_param); + e->y = GET_Y_LPARAM(msg->data_param); + e->timestamp = msg->timestamp; + + _ecore_win32_event_last_time = e->timestamp; + _ecore_win32_event_last_window = (Ecore_Win32_Window *)e->window; + + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL); + } + + { + Ecore_Event_Mouse_Button *e; + + e = (Ecore_Event_Mouse_Button *)calloc(1, sizeof(Ecore_Event_Mouse_Button)); + if (!e) return; + + e->window = (Ecore_Window)window; + e->event_window = e->window; + e->buttons = button; + e->x = GET_X_LPARAM(msg->data_param); + e->y = GET_Y_LPARAM(msg->data_param); + e->timestamp = msg->timestamp; + + _ecore_win32_mouse_up_count++; + + if ((_ecore_win32_mouse_up_count >= 2) && + ((e->timestamp - _ecore_win32_mouse_down_last_time) <= (unsigned long)(1000 * _ecore_win32_double_click_time)) && + (e->window == (Ecore_Window)_ecore_win32_mouse_down_last_window)) + e->double_click = 1; + + if ((_ecore_win32_mouse_up_count >= 3) && + ((e->timestamp - _ecore_win32_mouse_down_last_last_time) <= (unsigned long)(2 * 1000 * _ecore_win32_double_click_time)) && + (e->window == (Ecore_Window)_ecore_win32_mouse_down_last_window) && + (e->window == (Ecore_Window)_ecore_win32_mouse_down_last_last_window)) + e->triple_click = 1; + + _ecore_win32_event_last_time = e->timestamp; + _ecore_win32_event_last_window = (Ecore_Win32_Window *)e->window; + + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, e, NULL, NULL); + } +} + +void +_ecore_win32_event_handle_motion_notify(Ecore_Win32_Callback_Data *msg) +{ + Ecore_Event_Mouse_Move *e; + + INF("mouse moved"); + + e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move)); + if (!e) return; + + e->window = (Ecore_Window)GetWindowLongPtr(msg->window, GWLP_USERDATA); + e->event_window = e->window; + e->x = GET_X_LPARAM(msg->data_param); + e->y = GET_Y_LPARAM(msg->data_param); + e->timestamp = msg->timestamp; + + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL); +} + +void +_ecore_win32_event_handle_enter_notify(Ecore_Win32_Callback_Data *msg) +{ + { + Ecore_Event_Mouse_Move *e; + + INF("mouse in"); + + e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move)); + if (!e) return; + + e->window = (Ecore_Window)GetWindowLongPtr(msg->window, GWLP_USERDATA); + e->event_window = e->window; + e->x = msg->x; + e->y = msg->y; + e->timestamp = msg->timestamp; + + _ecore_win32_event_last_time = e->timestamp; + _ecore_win32_event_last_window = (Ecore_Win32_Window *)e->window; + + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL); + } + + { + Ecore_Win32_Event_Mouse_In *e; + + e = (Ecore_Win32_Event_Mouse_In *)calloc(1, sizeof(Ecore_Win32_Event_Mouse_In)); + if (!e) return; + + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); + e->x = msg->x; + e->y = msg->y; + e->timestamp = msg->timestamp ; + + _ecore_win32_event_last_time = e->timestamp; + + ecore_event_add(ECORE_WIN32_EVENT_MOUSE_IN, e, NULL, NULL); + } +} + +void +_ecore_win32_event_handle_leave_notify(Ecore_Win32_Callback_Data *msg) +{ + { + Ecore_Event_Mouse_Move *e; + + INF("mouse out"); + + e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move)); + if (!e) return; + + e->window = (Ecore_Window)GetWindowLongPtr(msg->window, GWLP_USERDATA); + e->event_window = e->window; + e->x = msg->x; + e->y = msg->y; + e->timestamp = msg->timestamp; + + _ecore_win32_event_last_time = e->timestamp; + _ecore_win32_event_last_window = (Ecore_Win32_Window *)e->window; + + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL); + } + + { + Ecore_Win32_Event_Mouse_Out *e; + + e = (Ecore_Win32_Event_Mouse_Out *)calloc(1, sizeof(Ecore_Win32_Event_Mouse_Out)); + if (!e) return; + + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); + e->x = msg->x; + e->y = msg->y; + e->timestamp = msg->timestamp; + + _ecore_win32_event_last_time = e->timestamp; + + ecore_event_add(ECORE_WIN32_EVENT_MOUSE_OUT, e, NULL, NULL); + } +} + +void +_ecore_win32_event_handle_focus_in(Ecore_Win32_Callback_Data *msg) +{ + Ecore_Win32_Event_Window_Focus_In *e; + + INF("focus in"); + + e = (Ecore_Win32_Event_Window_Focus_In *)calloc(1, sizeof(Ecore_Win32_Event_Window_Focus_In)); + if (!e) return; + + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); + + e->timestamp = _ecore_win32_event_last_time; + _ecore_win32_event_last_time = e->timestamp; + + ecore_event_add(ECORE_WIN32_EVENT_WINDOW_FOCUS_IN, e, NULL, NULL); +} + +void +_ecore_win32_event_handle_focus_out(Ecore_Win32_Callback_Data *msg) +{ + Ecore_Win32_Event_Window_Focus_Out *e; + + INF("focus out"); + + e = (Ecore_Win32_Event_Window_Focus_Out *)calloc(1, sizeof(Ecore_Win32_Event_Window_Focus_Out)); + if (!e) return; + + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); + + e->timestamp = _ecore_win32_event_last_time; + _ecore_win32_event_last_time = e->timestamp; + + ecore_event_add(ECORE_WIN32_EVENT_WINDOW_FOCUS_OUT, e, NULL, NULL); +} + +void +_ecore_win32_event_handle_expose(Ecore_Win32_Callback_Data *msg) +{ + Ecore_Win32_Event_Window_Damage *e; + + INF("window expose"); + + e = (Ecore_Win32_Event_Window_Damage *)calloc(1, sizeof(Ecore_Win32_Event_Window_Damage)); + if (!e) return; + + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); + + e->x = msg->update.left; + e->y = msg->update.top; + e->width = msg->update.right - msg->update.left; + e->height = msg->update.bottom - msg->update.top; + + e->timestamp = _ecore_win32_event_last_time; + + ecore_event_add(ECORE_WIN32_EVENT_WINDOW_DAMAGE, e, NULL, NULL); +} + +void +_ecore_win32_event_handle_create_notify(Ecore_Win32_Callback_Data *msg) +{ + Ecore_Win32_Event_Window_Create *e; + + INF("window create notify"); + + e = calloc(1, sizeof(Ecore_Win32_Event_Window_Create)); + if (!e) return; + + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); + + e->timestamp = _ecore_win32_event_last_time; + + ecore_event_add(ECORE_WIN32_EVENT_WINDOW_CREATE, e, NULL, NULL); +} + +void +_ecore_win32_event_handle_destroy_notify(Ecore_Win32_Callback_Data *msg) +{ + Ecore_Win32_Event_Window_Destroy *e; + + INF("window destroy notify"); + + e = calloc(1, sizeof(Ecore_Win32_Event_Window_Destroy)); + if (!e) return; + + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); + + e->timestamp = _ecore_win32_event_last_time; + if (e->window == _ecore_win32_event_last_window) _ecore_win32_event_last_window = NULL; + + ecore_event_add(ECORE_WIN32_EVENT_WINDOW_DESTROY, e, NULL, NULL); +} + +void +_ecore_win32_event_handle_map_notify(Ecore_Win32_Callback_Data *msg) +{ + Ecore_Win32_Event_Window_Show *e; + + INF("window map notify"); + + e = calloc(1, sizeof(Ecore_Win32_Event_Window_Show)); + if (!e) return; + + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); + + e->timestamp = _ecore_win32_event_last_time; + + ecore_event_add(ECORE_WIN32_EVENT_WINDOW_SHOW, e, NULL, NULL); +} + +void +_ecore_win32_event_handle_unmap_notify(Ecore_Win32_Callback_Data *msg) +{ + Ecore_Win32_Event_Window_Hide *e; + + INF("window unmap notify"); + + e = calloc(1, sizeof(Ecore_Win32_Event_Window_Hide)); + if (!e) return; + + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); + + e->timestamp = _ecore_win32_event_last_time; + + ecore_event_add(ECORE_WIN32_EVENT_WINDOW_HIDE, e, NULL, NULL); +} + +void +_ecore_win32_event_handle_configure_notify(Ecore_Win32_Callback_Data *msg) +{ + WINDOWINFO wi; + Ecore_Win32_Event_Window_Configure *e; + WINDOWPOS *window_pos; + + INF("window configure notify"); + + e = calloc(1, sizeof(Ecore_Win32_Event_Window_Configure)); + if (!e) return; + + window_pos = (WINDOWPOS *)msg->data_param; + wi.cbSize = sizeof(WINDOWINFO); + if (!GetWindowInfo(window_pos->hwnd, &wi)) + { + free(e); + return; + } + + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); + e->abovewin = (void *)GetWindowLongPtr(window_pos->hwndInsertAfter, GWLP_USERDATA); + e->x = wi.rcClient.left; + e->y = wi.rcClient.top; + e->width = wi.rcClient.right - wi.rcClient.left; + e->height = wi.rcClient.bottom - wi.rcClient.top; + e->timestamp = _ecore_win32_event_last_time; + + ecore_event_add(ECORE_WIN32_EVENT_WINDOW_CONFIGURE, e, NULL, NULL); +} + +void +_ecore_win32_event_handle_resize(Ecore_Win32_Callback_Data *msg) +{ + RECT rect; + Ecore_Win32_Event_Window_Resize *e; + + INF("window resize"); + + if (!GetClientRect(msg->window, &rect)) + return; + + e = calloc(1, sizeof(Ecore_Win32_Event_Window_Resize)); + if (!e) return; + + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); + e->width = rect.right - rect.left; + e->height = rect.bottom - rect.top; + e->timestamp = _ecore_win32_event_last_time; + + ecore_event_add(ECORE_WIN32_EVENT_WINDOW_RESIZE, e, NULL, NULL); +} + +void +_ecore_win32_event_handle_delete_request(Ecore_Win32_Callback_Data *msg) +{ + Ecore_Win32_Event_Window_Delete_Request *e; + + INF("window delete request"); + + e = calloc(1, sizeof(Ecore_Win32_Event_Window_Delete_Request)); + if (!e) return; + + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); + e->timestamp = _ecore_win32_event_last_time; + + ecore_event_add(ECORE_WIN32_EVENT_WINDOW_DELETE_REQUEST, e, NULL, NULL); +} + + +/***** Private functions definitions *****/ + +static void +_ecore_win32_event_free_key_down(void *data __UNUSED__, + void *ev) +{ + Ecore_Event_Key *e; + + e = ev; + if (e->keyname) free((char *)e->keyname); + if (e->key) free((char *)e->key); + if (e->string) free((char *)e->string); + free(e); +} + +static void +_ecore_win32_event_free_key_up(void *data __UNUSED__, + void *ev) +{ + Ecore_Event_Key *e; + + e = ev; + if (e->keyname) free((char *)e->keyname); + if (e->key) free((char *)e->key); + if (e->string) free((char *)e->string); + free(e); +} + +static int +_ecore_win32_event_keystroke_get(Ecore_Win32_Callback_Data *msg, + Eina_Bool is_down, + char **keyname, + char **keysymbol, + char **keycompose, + unsigned int *modifiers) +{ + WCHAR buf[3]; + char delete_string[2] = { 0x7f, 0 }; + char *kn = NULL; + char *ks = NULL; + char *kc = NULL; + int key; + int is_extended; + int previous_key_state; + + key = msg->window_param; + is_extended = msg->data_param & 0x01000000; + previous_key_state = msg->data_param & 0x40000000; + + *keyname = NULL; + *keysymbol = NULL; + *keycompose = NULL; + + switch (key) + { + /* Keystroke */ + case VK_PRIOR: + if (is_extended) + { + kn = "Prior"; + ks = "Prior"; + kc = NULL; + } + else + { + kn = "KP_Prior"; + ks = "KP_9"; + kc = "KP_Prior"; + } + break; + case VK_NEXT: + if (is_extended) + { + kn = "Next"; + ks = "Next"; + kc = NULL; + } + else + { + kn = "KP_Next"; + ks = "KP_3"; + kc = "KP_Next"; + } + break; + case VK_END: + if (is_extended) + { + kn = "End"; + ks = "End"; + kc = NULL; + } + else + { + kn = "KP_End"; + ks = "KP_1"; + kc = "KP_End"; + } + break; + case VK_HOME: + if (is_extended) + { + kn = "Home"; + ks = "Home"; + kc = NULL; + } + else + { + kn = "KP_Home"; + ks = "KP_7"; + kc = "KP_Home"; + } + break; + case VK_LEFT: + if (is_extended) + { + kn = "Left"; + ks = "Left"; + kc = NULL; + } + else + { + kn = "KP_Left"; + ks = "KP_4"; + kc = "KP_Left"; + } + break; + case VK_UP: + if (is_extended) + { + kn = "Up"; + ks = "Up"; + kc = NULL; + } + else + { + kn = "KP_Up"; + ks = "KP_8"; + kc = "KP_Up"; + } + break; + case VK_RIGHT: + if (is_extended) + { + kn = "Right"; + ks = "Right"; + kc = NULL; + } + else + { + kn = "KP_Right"; + ks = "KP_6"; + kc = "KP_Right"; + } + break; + case VK_DOWN: + if (is_extended) + { + kn = "Down"; + ks = "Down"; + kc = NULL; + } + else + { + kn = "KP_Down"; + ks = "KP_2"; + kc = "KP_Down"; + } + break; + case VK_INSERT: + if (is_extended) + { + kn = "Insert"; + ks = "Insert"; + kc = NULL; + } + else + { + kn = "KP_Insert"; + ks = "KP_0"; + kc = "KP_Insert"; + } + break; + case VK_DELETE: + if (is_extended) + { + kn = "Delete"; + ks = "Delete"; + kc = delete_string; + } + else + { + kn = "KP_Delete"; + ks = "KP_Decimal"; + kc = "KP_Delete"; + } + break; + case VK_SHIFT: + { + SHORT res; + + if (is_down) + { + if (previous_key_state) return 0; + res = GetKeyState(VK_LSHIFT); + if (res & 0x8000) + { + _ecore_win32_key_mask |= ECORE_WIN32_KEY_MASK_LSHIFT; + kn = "Shift_L"; + ks = "Shift_L"; + kc = ""; + } + res = GetKeyState(VK_RSHIFT); + if (res & 0x8000) + { + _ecore_win32_key_mask |= ECORE_WIN32_KEY_MASK_RSHIFT; + kn = "Shift_R"; + ks = "Shift_R"; + kc = ""; + } + *modifiers &= ~ECORE_EVENT_MODIFIER_SHIFT; + } + else /* is_up */ + { + res = GetKeyState(VK_LSHIFT); + if (!(res & 0x8000) && + (_ecore_win32_key_mask & ECORE_WIN32_KEY_MASK_LSHIFT)) + { + kn = "Shift_L"; + ks = "Shift_L"; + kc = ""; + _ecore_win32_key_mask &= ~ECORE_WIN32_KEY_MASK_LSHIFT; + } + res = GetKeyState(VK_RSHIFT); + if (!(res & 0x8000) && + (_ecore_win32_key_mask & ECORE_WIN32_KEY_MASK_RSHIFT)) + { + kn = "Shift_R"; + ks = "Shift_R"; + kc = ""; + _ecore_win32_key_mask &= ~ECORE_WIN32_KEY_MASK_RSHIFT; + } + *modifiers |= ECORE_EVENT_MODIFIER_SHIFT; + } + break; + } + case VK_CONTROL: + { + SHORT res; + + if (msg->discard_ctrl) + return 0; + + if (is_down) + { + if (previous_key_state) return 0; + res = GetKeyState(VK_LCONTROL); + if (res & 0x8000) + { + _ecore_win32_key_mask |= ECORE_WIN32_KEY_MASK_LCONTROL; + kn = "Control_L"; + ks = "Control_L"; + kc = ""; + break; + } + res = GetKeyState(VK_RCONTROL); + if (res & 0x8000) + { + _ecore_win32_key_mask |= ECORE_WIN32_KEY_MASK_RCONTROL; + kn = "Control_R"; + ks = "Control_R"; + kc = ""; + break; + } + *modifiers |= ECORE_EVENT_MODIFIER_CTRL; + } + else /* is_up */ + { + res = GetKeyState(VK_LCONTROL); + if (!(res & 0x8000) && + (_ecore_win32_key_mask & ECORE_WIN32_KEY_MASK_LCONTROL)) + { + kn = "Control_L"; + ks = "Control_L"; + kc = ""; + _ecore_win32_key_mask &= ~ECORE_WIN32_KEY_MASK_LCONTROL; + break; + } + res = GetKeyState(VK_RCONTROL); + if (!(res & 0x8000) && + (_ecore_win32_key_mask & ECORE_WIN32_KEY_MASK_RCONTROL)) + { + kn = "Control_R"; + ks = "Control_R"; + kc = ""; + _ecore_win32_key_mask &= ~ECORE_WIN32_KEY_MASK_RCONTROL; + break; + } + *modifiers &= ~ECORE_EVENT_MODIFIER_CTRL; + } + break; + } + case VK_MENU: + { + SHORT res; + + if (is_down) + { + if (previous_key_state) return 0; + res = GetKeyState(VK_LMENU); + if (res & 0x8000) + { + _ecore_win32_key_mask |= ECORE_WIN32_KEY_MASK_LMENU; + kn = "Alt_L"; + ks = "Alt_L"; + kc = ""; + } + res = GetKeyState(VK_RMENU); + if (res & 0x8000) + { + _ecore_win32_key_mask |= ECORE_WIN32_KEY_MASK_RMENU; + kn = "Alt_R"; + ks = "Alt_R"; + kc = ""; + } + *modifiers |= ECORE_EVENT_MODIFIER_ALT; + } + else /* is_up */ + { + res = GetKeyState(VK_LMENU); + if (!(res & 0x8000) && + (_ecore_win32_key_mask & ECORE_WIN32_KEY_MASK_LMENU)) + { + kn = "Alt_L"; + ks = "Alt_L"; + kc = ""; + _ecore_win32_key_mask &= ~ECORE_WIN32_KEY_MASK_LMENU; + } + res = GetKeyState(VK_RMENU); + if (!(res & 0x8000) && + (_ecore_win32_key_mask & ECORE_WIN32_KEY_MASK_RMENU)) + { + kn = "Alt_R"; + ks = "Alt_R"; + kc = ""; + _ecore_win32_key_mask &= ~ECORE_WIN32_KEY_MASK_RMENU; + } + *modifiers &= ~ECORE_EVENT_MODIFIER_ALT; + } + break; + } + case VK_LWIN: + { + if (is_down) + { + if (previous_key_state) return 0; + kn = "Super_L"; + ks = "Super_L"; + kc = ""; + *modifiers |= ECORE_EVENT_MODIFIER_WIN; + } + else /* is_up */ + { + kn = "Super_L"; + ks = "Super_L"; + kc = ""; + *modifiers &= ~ECORE_EVENT_MODIFIER_WIN; + } + break; + } + case VK_RWIN: + { + if (is_down) + { + if (previous_key_state) return 0; + kn = "Super_R"; + ks = "Super_R"; + kc = ""; + *modifiers |= ECORE_EVENT_MODIFIER_WIN; + } + else /* is_up */ + { + kn = "Super_R"; + ks = "Super_R"; + kc = ""; + *modifiers &= ~ECORE_EVENT_MODIFIER_WIN; + } + break; + } + case VK_F1: + kn = "F1"; + ks = "F1"; + kc = ""; + break; + case VK_F2: + kn = "F2"; + ks = "F2"; + kc = ""; + break; + case VK_F3: + kn = "F3"; + ks = "F3"; + kc = ""; + break; + case VK_F4: + kn = "F4"; + ks = "F4"; + kc = ""; + break; + case VK_F5: + kn = "F5"; + ks = "F5"; + kc = ""; + break; + case VK_F6: + kn = "F6"; + ks = "F6"; + kc = ""; + break; + case VK_F7: + kn = "F7"; + ks = "F7"; + kc = ""; + break; + case VK_F8: + kn = "F8"; + ks = "F8"; + kc = ""; + break; + case VK_F9: + kn = "F9"; + ks = "F9"; + kc = ""; + break; + case VK_F10: + kn = "F10"; + ks = "F10"; + kc = ""; + break; + case VK_F11: + kn = "F11"; + ks = "F11"; + kc = ""; + break; + case VK_F12: + kn = "F12"; + ks = "F12"; + kc = ""; + break; + case VK_F13: + kn = "F13"; + ks = "F13"; + kc = ""; + break; + case VK_F14: + kn = "F14"; + ks = "F14"; + kc = ""; + break; + case VK_F15: + kn = "F15"; + ks = "F15"; + kc = ""; + break; + case VK_F16: + kn = "F16"; + ks = "F16"; + kc = ""; + break; + case VK_F17: + kn = "F17"; + ks = "F17"; + kc = ""; + break; + case VK_F18: + kn = "F18"; + ks = "F18"; + kc = ""; + break; + case VK_F19: + kn = "F19"; + ks = "F19"; + kc = ""; + break; + case VK_F20: + kn = "F20"; + ks = "F20"; + kc = ""; + break; + case VK_F21: + kn = "F21"; + ks = "F21"; + kc = ""; + break; + case VK_F22: + kn = "F22"; + ks = "F22"; + kc = ""; + break; + case VK_F23: + kn = "F23"; + ks = "F23"; + kc = ""; + break; + case VK_F24: + kn = "F24"; + ks = "F24"; + kc = ""; + break; + default: + { + /* other non keystroke characters */ + BYTE kbd_state[256]; + int res; + + if (is_down) + return 0; + + if (!GetKeyboardState(kbd_state)) + return 0; + + res = ToUnicode(msg->window_param, + MapVirtualKey(msg->window_param, 2), + kbd_state, buf, 3, 0); + if (res == 1) + { + /* FIXME: might be troublesome for non european languages */ + /* in that case, UNICODE should be used, I guess */ + buf[1] = '\0'; + kn = (char *)buf; + ks = (char *)buf; + kc = (char *)buf; + + res = GetAsyncKeyState(VK_SHIFT); + if (res & 0x8000) + *modifiers |= ECORE_EVENT_MODIFIER_SHIFT; + else + *modifiers &= ~ECORE_EVENT_MODIFIER_SHIFT; + + res = GetKeyState(VK_CONTROL); + if (res & 0x8000) + *modifiers |= ECORE_EVENT_MODIFIER_CTRL; + else + *modifiers &= ~ECORE_EVENT_MODIFIER_CTRL; + + res = GetKeyState(VK_MENU); + if (res & 0x8000) + *modifiers |= ECORE_EVENT_MODIFIER_ALT; + else + *modifiers &= ~ECORE_EVENT_MODIFIER_ALT; + + break; + } + return 0; + } + } + + *keyname = strdup(kn); + if (!*keyname) return 0; + *keysymbol = strdup(ks); + if (!*keysymbol) + { + free(*keyname); + *keyname = NULL; + return 0; + } + if (!kc) + *keycompose = NULL; + else + { + *keycompose = strdup(kc); + if (!*keycompose) + { + free(*keyname); + free(*keysymbol); + *keyname = NULL; + *keysymbol = NULL; + return 0; + } + } + + return 1; +} + +static int +_ecore_win32_event_char_get(int key, + char **keyname, + char **keysymbol, + char **keycompose, + unsigned int *modifiers) +{ + char *kn = NULL; + char *ks = NULL; + char *kc = NULL; + char buf[2]; + SHORT res; + + *keyname = NULL; + *keysymbol = NULL; + *keycompose = NULL; + + /* check control charaters such as ^a(key:1), ^z(key:26) */ + if ((key > 0) && (key < 27) && + ((GetKeyState(VK_CONTROL) & 0x8000) || + (GetKeyState(VK_CONTROL) & 0x8000))) key += 96; + + switch (key) + { + case VK_PROCESSKEY: + break; + case VK_BACK: + kn = "BackSpace"; + ks = "BackSpace"; + kc = "\b"; + break; + case VK_TAB: + kn = "Tab"; + ks = "Tab"; + kc = "\t"; + break; + case 0x0a: + /* Line feed (Shift + Enter) */ + kn = "LineFeed"; + ks = "LineFeed"; + kc = "LineFeed"; + break; + case VK_RETURN: + kn = "Return"; + ks = "Return"; + kc = "\n"; + break; + case VK_ESCAPE: + kn = "Escape"; + ks = "Escape"; + kc = "\e"; + break; + case VK_SPACE: + kn = "space"; + ks = "space"; + kc = " "; + break; + default: + /* displayable characters */ + buf[0] = key; + buf[1] = '\0'; + kn = buf; + ks = buf; + kc = buf; + break; + } + *keyname = strdup(kn); + if (!*keyname) return 0; + *keysymbol = strdup(ks); + if (!*keysymbol) + { + free(*keyname); + *keyname = NULL; + return 0; + } + *keycompose = strdup(kc); + if (!*keycompose) + { + free(*keyname); + free(*keysymbol); + *keyname = NULL; + *keysymbol = NULL; + return 0; + } + + res = GetAsyncKeyState(VK_SHIFT); + if (res & 0x8000) + *modifiers |= ECORE_EVENT_MODIFIER_SHIFT; + else + *modifiers &= ~ECORE_EVENT_MODIFIER_SHIFT; + + res = GetKeyState(VK_CONTROL); + if (res & 0x8000) + *modifiers |= ECORE_EVENT_MODIFIER_CTRL; + else + *modifiers &= ~ECORE_EVENT_MODIFIER_CTRL; + + res = GetKeyState(VK_MENU); + if (res & 0x8000) + *modifiers |= ECORE_EVENT_MODIFIER_ALT; + else + *modifiers &= ~ECORE_EVENT_MODIFIER_ALT; + + return 1; +} diff --git a/src/lib/ecore_win32/ecore_win32_private.h b/src/lib/ecore_win32/ecore_win32_private.h new file mode 100644 index 0000000..e3e4426 --- /dev/null +++ b/src/lib/ecore_win32/ecore_win32_private.h @@ -0,0 +1,170 @@ +#ifndef __ECORE_WIN32_PRIVATE_H__ +#define __ECORE_WIN32_PRIVATE_H__ + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef MIN +# undef MIN +#endif +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +#ifdef MAX +# undef MAX +#endif +#define MAX(a,b) (((a) < (b)) ? (b) : (a)) + +/* logging messages macros */ +extern int _ecore_win32_log_dom_global; + +#ifdef ECORE_WIN32_DEFAULT_LOG_COLOR +# undef ECORE_WIN32_DEFAULT_LOG_COLOR +#endif +#define ECORE_WIN32_DEFAULT_LOG_COLOR EINA_COLOR_LIGHTBLUE + +#ifdef ERR +# undef ERR +#endif +#define ERR(...) EINA_LOG_DOM_ERR(_ecore_win32_log_dom_global , __VA_ARGS__) +#ifdef DBG +#undef DBG +#endif +#define DBG(...) EINA_LOG_DOM_DBG(_ecore_win32_log_dom_global , __VA_ARGS__) + +#ifdef INF +#undef INF +#endif +#define INF(...) EINA_LOG_DOM_INFO(_ecore_win32_log_dom_global , __VA_ARGS__) + +#ifdef WRN +# undef WRN +#endif +#define WRN(...) EINA_LOG_DOM_WARN(_ecore_win32_log_dom_global, __VA_ARGS__) + +#define ECORE_WIN32_WINDOW_CLASS "Ecore_Win32_Window_Class" + +typedef struct _Ecore_Win32_Callback_Data Ecore_Win32_Callback_Data; + +struct _Ecore_Win32_Callback_Data +{ + RECT update; + HWND window; + unsigned int message; + WPARAM window_param; + LPARAM data_param; + unsigned long timestamp; + int x; + int y; + Eina_Bool discard_ctrl; +}; + +struct _Ecore_Win32_Window +{ + HWND window; + + DWORD style; /* used to go fullscreen to normal */ + RECT rect; /* used to go fullscreen to normal */ + + unsigned int min_width; + unsigned int min_height; + unsigned int max_width; + unsigned int max_height; + int base_width; + int base_height; + unsigned int step_width; + unsigned int step_height; + + struct { + unsigned int iconified : 1; + unsigned int modal : 1; + unsigned int sticky : 1; + unsigned int maximized_vert : 1; + unsigned int maximized_horz : 1; + unsigned int shaded : 1; + unsigned int hidden : 1; + unsigned int fullscreen : 1; + unsigned int above : 1; + unsigned int below : 1; + unsigned int demands_attention : 1; + } state; + + struct { + unsigned int desktop : 1; + unsigned int dock : 1; + unsigned int toolbar : 1; + unsigned int menu : 1; + unsigned int utility : 1; + unsigned int splash : 1; + unsigned int dialog : 1; + unsigned int normal : 1; + } type; + + unsigned int pointer_is_in : 1; + unsigned int borderless : 1; + unsigned int iconified : 1; + unsigned int fullscreen : 1; + + struct { + unsigned short width; + unsigned short height; + unsigned char *mask; + unsigned int enabled : 1; + unsigned int layered : 1; + } shape; + + struct { + DWORD type; + int x; + int y; + int w; + int h; + int px; + int py; + unsigned int dragging : 1; + } drag; + + void *dnd_drop_target; +}; + + +extern HINSTANCE _ecore_win32_instance; +extern double _ecore_win32_double_click_time; +extern unsigned long _ecore_win32_event_last_time; +extern Ecore_Win32_Window *_ecore_win32_event_last_window; + + +void _ecore_win32_event_handle_key_press(Ecore_Win32_Callback_Data *msg, int is_keystroke); +void _ecore_win32_event_handle_key_release(Ecore_Win32_Callback_Data *msg); +void _ecore_win32_event_handle_button_press(Ecore_Win32_Callback_Data *msg, int button); +void _ecore_win32_event_handle_button_release(Ecore_Win32_Callback_Data *msg, int button); +void _ecore_win32_event_handle_motion_notify(Ecore_Win32_Callback_Data *msg); +void _ecore_win32_event_handle_enter_notify(Ecore_Win32_Callback_Data *msg); +void _ecore_win32_event_handle_leave_notify(Ecore_Win32_Callback_Data *msg); +void _ecore_win32_event_handle_focus_in(Ecore_Win32_Callback_Data *msg); +void _ecore_win32_event_handle_focus_out(Ecore_Win32_Callback_Data *msg); +void _ecore_win32_event_handle_expose(Ecore_Win32_Callback_Data *msg); +void _ecore_win32_event_handle_create_notify(Ecore_Win32_Callback_Data *msg); +void _ecore_win32_event_handle_destroy_notify(Ecore_Win32_Callback_Data *msg); +void _ecore_win32_event_handle_map_notify(Ecore_Win32_Callback_Data *msg); +void _ecore_win32_event_handle_unmap_notify(Ecore_Win32_Callback_Data *msg); +void _ecore_win32_event_handle_configure_notify(Ecore_Win32_Callback_Data *msg); +void _ecore_win32_event_handle_resize(Ecore_Win32_Callback_Data *msg); +void _ecore_win32_event_handle_delete_request(Ecore_Win32_Callback_Data *msg); + +void *_ecore_win32_dnd_data_object_new(void *fmtetc, void *stgmeds, int count); +void _ecore_win32_dnd_data_object_free(void *data_object); +void *_ecore_win32_dnd_drop_source_new(); +void _ecore_win32_dnd_drop_source_free(void *drop_source); +void *_ecore_win32_dnd_register_drop_window(HWND hwnd, + Ecore_Win32_Dnd_DropTarget_Callback callback, void *ptr); +void _ecore_win32_dnd_unregister_drop_window(HWND hwnd, void *drop_target); + + +#ifdef __cplusplus +} +#endif + + +#endif /* __ECORE_WIN32_PRIVATE_H__ */ diff --git a/src/lib/ecore_win32/ecore_win32_window.c b/src/lib/ecore_win32/ecore_win32_window.c new file mode 100644 index 0000000..36f8a86 --- /dev/null +++ b/src/lib/ecore_win32/ecore_win32_window.c @@ -0,0 +1,1418 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include /* for printf */ + +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN + +#include + +#include "Ecore_Win32.h" +#include "ecore_win32_private.h" + +/*============================================================================* + * Local * + *============================================================================*/ + +/** + * @cond LOCAL + */ + + +typedef enum _Ecore_Win32_Window_Z_Order Ecore_Win32_Window_Z_Order; +enum _Ecore_Win32_Window_Z_Order +{ + ECORE_WIN32_WINDOW_Z_ORDER_BOTTOM, + ECORE_WIN32_WINDOW_Z_ORDER_NOTOPMOST, + ECORE_WIN32_WINDOW_Z_ORDER_TOP, + ECORE_WIN32_WINDOW_Z_ORDER_TOPMOST +}; + +static Ecore_Win32_Window * +ecore_win32_window_internal_new(Ecore_Win32_Window *parent, + int x, + int y, + int width, + int height, + DWORD style) +{ + RECT rect; + Ecore_Win32_Window *w; + int minimal_width; + int minimal_height; + + w = (Ecore_Win32_Window *)calloc(1, sizeof(Ecore_Win32_Window)); + if (!w) + { + ERR("malloc() failed"); + return NULL; + } + + rect.left = 0; + rect.top = 0; + rect.right = width; + rect.bottom = height; + if (!AdjustWindowRectEx(&rect, style, FALSE, 0)) + { + ERR("AdjustWindowRect() failed"); + free(w); + return NULL; + } + + minimal_width = GetSystemMetrics(SM_CXMIN); + minimal_height = GetSystemMetrics(SM_CYMIN); +/* if (((rect.right - rect.left) < minimal_width) || */ +/* ((rect.bottom - rect.top) < minimal_height)) */ +/* { */ +/* fprintf (stderr, "[Ecore] [Win32] ERROR !!\n"); */ +/* fprintf (stderr, " Wrong size %ld\n", rect.right - rect.left); */ +/* free(w); */ +/* return NULL; */ +/* } */ + if ((rect.right - rect.left) < minimal_width) + { + rect.right = rect.left + minimal_width; + } + + w->window = CreateWindowEx(0, + ECORE_WIN32_WINDOW_CLASS, "", + style, + x, y, + rect.right - rect.left, + rect.bottom - rect.top, + parent ? parent->window : NULL, + NULL, _ecore_win32_instance, NULL); + if (!w->window) + { + ERR("CreateWindowEx() failed"); + free(w); + return NULL; + } + + SetLastError(0); + if (!SetWindowLongPtr(w->window, GWLP_USERDATA, (LONG_PTR)w) && + (GetLastError() != 0)) + { + ERR("SetWindowLongPtr() failed"); + DestroyWindow(w->window); + free(w); + return NULL; + } + + w->min_width = 0; + w->min_height = 0; + w->max_width = 32767; + w->max_height = 32767; + w->base_width = -1; + w->base_height = -1; + w->step_width = 1; + w->step_height = 1; + + w->state.iconified = 0; + w->state.modal = 0; + w->state.sticky = 0; + w->state.maximized_vert = 0; + w->state.maximized_horz = 0; + w->state.shaded = 0; + w->state.hidden = 0; + w->state.fullscreen = 0; + w->state.above = 0; + w->state.below = 0; + w->state.demands_attention = 0; + + w->type.desktop = 0; + w->type.dock = 0; + w->type.toolbar = 0; + w->type.menu = 0; + w->type.utility = 0; + w->type.splash = 0; + w->type.dialog = 0; + w->type.normal = 0; + + w->pointer_is_in = 0; + w->borderless = 0; + w->iconified = 0; + w->fullscreen = 0; + + return w; +} + +/** + * @endcond + */ + + +/*============================================================================* + * Global * + *============================================================================*/ + +/*============================================================================* + * API * + *============================================================================*/ + +/** + * @addtogroup Ecore_Win32_Group Ecore_Win32 library + * + * @{ + */ + +/** + * @brief Creates a new window. + * + * @param parent The parent window. + * @param x The x coordinate of the top-left corner of the window. + * @param y The y coordinate of the top-left corner of the window. + * @param width The width of the window. + * @param height The height of hte window. + * @return A newly allocated window. + * + * This function creates a new window which parent is @p parent. @p width and + * @p height are the size of the window content (the client part), + * without the border and title bar. @p x and @p y are the system + * coordinates of the top left cerner of the window (that is, of the + * title bar). This function returns a newly created window on + * success, and @c NULL on failure. + */ +EAPI Ecore_Win32_Window * +ecore_win32_window_new(Ecore_Win32_Window *parent, + int x, + int y, + int width, + int height) +{ + INF("creating window with border"); + + return ecore_win32_window_internal_new(parent, + x, y, + width, height, + WS_OVERLAPPEDWINDOW | WS_SIZEBOX); +} + +/** + * @brief Creates a new borderless window. + * + * @param parent The parent window. + * @param x The x coordinate of the top-left corner of the window. + * @param y The y coordinate of the top-left corner of the window. + * @param width The width of the window. + * @param height The height of hte window. + * @return A newly allocated window. + * + * This function is the same than ecore_win32_window_override_new() + * but the returned window is borderless. + */ +EAPI Ecore_Win32_Window * +ecore_win32_window_override_new(Ecore_Win32_Window *parent, + int x, + int y, + int width, + int height) +{ + INF("creating window without border"); + + return ecore_win32_window_internal_new(parent, + x, y, + width, height, + WS_POPUP & ~(WS_CAPTION | WS_THICKFRAME)); +} + +/** + * @brief Free the given window. + * + * @param window The window to free. + * + * This function frees @p window. If @p window is @c NULL, this + * function does nothing. + */ +EAPI void +ecore_win32_window_free(Ecore_Win32_Window *window) +{ + if (!window) return; + + INF("destroying window"); + + if (window->shape.mask) + free(window->shape.mask); + + DestroyWindow(window->window); + free(window); +} + +/** + * @brief Return the window HANDLE associated to the given window. + * + * @param window The window to retrieve the HANDLE from. + * + * This function returns the window HANDLE associated to @p window. If + * @p window is @c NULL, this function returns @c NULL. + * + * @note The returned value is of type HWND. + */ +EAPI void * +ecore_win32_window_hwnd_get(Ecore_Win32_Window *window) +{ + if (!window) return NULL; + + return window->window; +} + +/* +void +ecore_win32_window_configure(Ecore_Win32_Window *window, + Ecore_Win32_Window_Z_Order order, + int x, + int y, + int width, + int height) +{ + HWND w; + + switch (order) + { + case ECORE_WIN32_WINDOW_Z_ORDER_BOTTOM: + w = HWND_BOTTOM; + break; + case ECORE_WIN32_WINDOW_Z_ORDER_NOTOPMOST: + w = HWND_NOTOPMOST; + break; + case ECORE_WIN32_WINDOW_Z_ORDER_TOP: + w = HWND_TOP; + break; + case ECORE_WIN32_WINDOW_Z_ORDER_TOPMOST: + w = HWND_TOPMOST; + break; + default: + return; + } + SetWindowPos((Ecore_Win32_Window *)window->window, w, x, y, width, height, ???); +} +*/ + +/** + * @brief Move the given window to a given position. + * + * @param window The window to move. + * @param x The x coordinate of the destination position. + * @param y The y coordinate of the destination position. + * + * This function move @p window to the new position of coordinates @p x + * and @p y. If @p window is @c NULL, or if it is fullscreen, or on + * error, this function does nothing. + */ +EAPI void +ecore_win32_window_move(Ecore_Win32_Window *window, + int x, + int y) +{ + RECT rect; + + /* FIXME: on fullscreen, should not move it */ + if (!window) return; + + INF("moving window (%dx%d)", x, y); + + if (!GetWindowRect(window->window, &rect)) + { + ERR("GetWindowRect() failed"); + return; + } + + if (!MoveWindow(window->window, x, y, + rect.right - rect.left, + rect.bottom - rect.top, + TRUE)) + { + ERR("MoveWindow() failed"); + } +} + +/** + * @brief Resize the given window to a given size. + * + * @param window The window to resize. + * @param width The new width. + * @param height The new height. + * + * This function resize @p window to the new @p width and @p height. + * If @p window is @c NULL, or if it is fullscreen, or on error, this + * function does nothing. + */ +EAPI void +ecore_win32_window_resize(Ecore_Win32_Window *window, + int width, + int height) +{ + RECT rect; + DWORD style; + int x; + int y; + int minimal_width; + int minimal_height; + + /* FIXME: on fullscreen, should not resize it */ + if (!window) return; + + INF("resizing window (%dx%d)", width, height); + + minimal_width = MAX(GetSystemMetrics(SM_CXMIN), (int)window->min_width); + minimal_height = MAX(GetSystemMetrics(SM_CYMIN), (int)window->min_height); + + if (!GetWindowRect(window->window, &rect)) + { + ERR("GetWindowRect() failed"); + return; + } + + x = rect.left; + y = rect.top; + rect.left = 0; + rect.top = 0; + if (width < minimal_width) width = minimal_width; + if (width > (int)window->max_width) width = window->max_width; + if (height < minimal_height) height = minimal_height; + if (height > (int)window->max_height) height = window->max_height; + rect.right = width; + rect.bottom = height; + if (!(style = GetWindowLong(window->window, GWL_STYLE))) + { + ERR("GetWindowLong() failed"); + return; + } + if (!AdjustWindowRect(&rect, style, FALSE)) + { + ERR("AdjustWindowRect() failed"); + return; + } + + if (!MoveWindow(window->window, x, y, + rect.right - rect.left, + rect.bottom - rect.top, + TRUE)) + { + ERR("MoveWindow() failed"); + } +} + +/** + * @brief Move and resize the given window to a given position and size. + * + * @param window The window to move and resize. + * @param x The x coordinate of the destination position. + * @param y The x coordinate of the destination position. + * @param width The new width. + * @param height The new height. + * + * This function resize @p window to the new position of coordinates @p x + * and @p y and the new @p width and @p height. If @p window is @c NULL, + * or if it is fullscreen, or on error, this function does nothing. + */ +EAPI void +ecore_win32_window_move_resize(Ecore_Win32_Window *window, + int x, + int y, + int width, + int height) +{ + RECT rect; + DWORD style; + int minimal_width; + int minimal_height; + + /* FIXME: on fullscreen, should not move/resize it */ + if (!window) return; + + INF("moving and resizing window (%dx%d %dx%d)", x, y, width, height); + + minimal_width = MAX(GetSystemMetrics(SM_CXMIN), (int)window->min_width); + minimal_height = MAX(GetSystemMetrics(SM_CYMIN), (int)window->min_height); + + rect.left = 0; + rect.top = 0; + if (width < minimal_width) width = minimal_width; + if (width > (int)window->max_width) width = window->max_width; + if (height < minimal_height) height = minimal_height; + if (height > (int)window->max_height) height = window->max_height; + rect.right = width; + rect.bottom = height; + if (!(style = GetWindowLong(window->window, GWL_STYLE))) + { + ERR("GetWindowLong() failed"); + return; + } + if (!AdjustWindowRect(&rect, style, FALSE)) + { + ERR("AdjustWindowRect() failed"); + return; + } + + if (!MoveWindow(window->window, x, y, + rect.right - rect.left, + rect.bottom - rect.top, + TRUE)) + { + ERR("MoveWindow() failed"); + } +} + +/** + * @brief Get the geometry of the given window. + * + * @param window The window to retrieve the geometry from. + * @param x The x coordinate of the position. + * @param y The x coordinate of the position. + * @param width The width. + * @param height The height. + * + * This function retrieves the position and size of @p window. @p x, + * @p y, @p width and @p height can be buffers that will be filled with + * the corresponding values. If one of them is @c NULL, nothing will + * be done for that parameter. If @p window is @c NULL, and if the + * buffers are not @c NULL, they will be filled with respectively 0, + * 0, the size of the screen and the height of the screen. + */ +EAPI void +ecore_win32_window_geometry_get(Ecore_Win32_Window *window, + int *x, + int *y, + int *width, + int *height) +{ + RECT rect; + int w; + int h; + + INF("getting window geometry"); + + if (!window) + { + if (x) *x = 0; + if (y) *y = 0; + if (width) *width = GetSystemMetrics(SM_CXSCREEN); + if (height) *height = GetSystemMetrics(SM_CYSCREEN); + + return; + } + + if (!GetClientRect(window->window, &rect)) + { + ERR("GetClientRect() failed"); + + if (x) *x = 0; + if (y) *y = 0; + if (width) *width = 0; + if (height) *height = 0; + + return; + } + + w = rect.right - rect.left; + h = rect.bottom - rect.top; + + if (!GetWindowRect(window->window, &rect)) + { + ERR("GetWindowRect() failed"); + + if (x) *x = 0; + if (y) *y = 0; + if (width) *width = 0; + if (height) *height = 0; + + return; + } + + if (x) *x = rect.left; + if (y) *y = rect.top; + if (width) *width = w; + if (height) *height = h; +} + +/** + * @brief Get the size of the given window. + * + * @param window The window to retrieve the size from. + * @param width The width. + * @param height The height. + * + * This function retrieves the size of @p window. @p width and + * @p height can be buffers that will be filled with the corresponding + * values. If one of them is @c NULL, nothing will be done for that + * parameter. If @p window is @c NULL, and if the buffers are not + * @c NULL, they will be filled with respectively the size of the screen + * and the height of the screen. + */ +EAPI void +ecore_win32_window_size_get(Ecore_Win32_Window *window, + int *width, + int *height) +{ + RECT rect; + + INF("getting window size"); + + if (!window) + { + if (width) *width = GetSystemMetrics(SM_CXSCREEN); + if (height) *height = GetSystemMetrics(SM_CYSCREEN); + + return; + } + + if (!GetClientRect(window->window, &rect)) + { + ERR("GetClientRect() failed"); + + if (width) *width = 0; + if (height) *height = 0; + } + + if (width) *width = rect.right - rect.left; + if (height) *height = rect.bottom - rect.top; +} + +/** + * @brief Set the minimum size of the given window. + * + * @param window The window. + * @param min_width The minimal width. + * @param min_height The minimal height. + * + * This function sets the minimum size of @p window to @p min_width + * and *p min_height. If @p window is @c NULL, this functions does + * nothing. + */ +EAPI void +ecore_win32_window_size_min_set(Ecore_Win32_Window *window, + unsigned int min_width, + unsigned int min_height) +{ + if (!window) return; + + printf ("ecore_win32_window_size_min_set : %p %d %d\n", window, min_width, min_height); + window->min_width = min_width; + window->min_height = min_height; +} + +/** + * @brief Get the minimum size of the given window. + * + * @param window The window. + * @param min_width The minimal width. + * @param min_height The minimal height. + * + * This function fills the minimum size of @p window in the buffers + * @p min_width and *p min_height. They both can be @c NULL. If + * @p window is @c NULL, this functions does nothing. + */ +EAPI void +ecore_win32_window_size_min_get(Ecore_Win32_Window *window, + unsigned int *min_width, + unsigned int *min_height) +{ + if (!window) return; + + printf ("ecore_win32_window_size_min_get : %p %d %d\n", window, window->min_width, window->min_height); + if (min_width) *min_width = window->min_width; + if (min_height) *min_height = window->min_height; +} + +/** + * @brief Set the maximum size of the given window. + * + * @param window The window. + * @param max_width The maximal width. + * @param max_height The maximal height. + * + * This function sets the maximum size of @p window to @p max_width + * and *p max_height. If @p window is @c NULL, this functions does + * nothing. + */ +EAPI void +ecore_win32_window_size_max_set(Ecore_Win32_Window *window, + unsigned int max_width, + unsigned int max_height) +{ + if (!window) return; + + printf ("ecore_win32_window_size_max_set : %p %d %d\n", window, max_width, max_height); + window->max_width = max_width; + window->max_height = max_height; +} + +/** + * @brief Get the maximum size of the given window. + * + * @param window The window. + * @param max_width The maximal width. + * @param max_height The maximal height. + * + * This function fills the maximum size of @p window in the buffers + * @p max_width and *p max_height. They both can be @c NULL. If + * @p window is @c NULL, this functions does nothing. + */ +EAPI void +ecore_win32_window_size_max_get(Ecore_Win32_Window *window, + unsigned int *max_width, + unsigned int *max_height) +{ + if (!window) return; + + printf ("ecore_win32_window_size_max_get : %p %d %d\n", window, window->max_width, window->max_height); + if (max_width) *max_width = window->max_width; + if (max_height) *max_height = window->max_height; +} + +/** + * @brief Set the base size of the given window. + * + * @param window The window. + * @param base_width The base width. + * @param base_height The base height. + * + * This function sets the base size of @p window to @p base_width + * and *p base_height. If @p window is @c NULL, this functions does + * nothing. + */ +EAPI void +ecore_win32_window_size_base_set(Ecore_Win32_Window *window, + unsigned int base_width, + unsigned int base_height) +{ + printf ("ecore_win32_window_size_base_set : %p %d %d\n", window, base_width, base_height); + if (!window) return; + + window->base_width = base_width; + window->base_height = base_height; +} + +/** + * @brief Get the base size of the given window. + * + * @param window The window. + * @param base_width The base width. + * @param base_height The bas height. + * + * This function fills the base size of @p window in the buffers + * @p base_width and *p base_height. They both can be @c NULL. If + * @p window is @c NULL, this functions does nothing. + */ +EAPI void +ecore_win32_window_size_base_get(Ecore_Win32_Window *window, + unsigned int *base_width, + unsigned int *base_height) +{ + if (!window) return; + + printf ("ecore_win32_window_size_base_get : %p %d %d\n", window, window->base_width, window->base_height); + if (base_width) *base_width = window->base_width; + if (base_height) *base_height = window->base_height; +} + +/** + * @brief Set the step size of the given window. + * + * @param window The window. + * @param step_width The step width. + * @param step_height The step height. + * + * This function sets the step size of @p window to @p step_width + * and *p step_height. If @p window is @c NULL, this functions does + * nothing. + */ +EAPI void +ecore_win32_window_size_step_set(Ecore_Win32_Window *window, + unsigned int step_width, + unsigned int step_height) +{ + printf ("ecore_win32_window_size_step_set : %p %d %d\n", window, step_width, step_height); + if (!window) return; + + window->step_width = step_width; + window->step_height = step_height; +} + +/** + * @brief Get the step size of the given window. + * + * @param window The window. + * @param step_width The step width. + * @param step_height The bas height. + * + * This function fills the step size of @p window in the buffers + * @p step_width and *p step_height. They both can be @c NULL. If + * @p window is @c NULL, this functions does nothing. + */ +EAPI void +ecore_win32_window_size_step_get(Ecore_Win32_Window *window, + unsigned int *step_width, + unsigned int *step_height) +{ + if (!window) return; + + printf ("ecore_win32_window_size_step_get : %p %d %d\n", window, window->step_width, window->step_height); + if (step_width) *step_width = window->step_width; + if (step_height) *step_height = window->step_height; +} + +/** + * @brief Show the given window. + * + * @param window The window to show. + * + * This function shows @p window. If @p window is @c NULL, or on + * error, this function does nothing. + */ +EAPI void +ecore_win32_window_show(Ecore_Win32_Window *window) +{ + if (!window) return; + + INF("showing window"); + + ShowWindow(window->window, SW_SHOWNORMAL); + if (!UpdateWindow(window->window)) + { + ERR("UpdateWindow() failed"); + } +} + +/* FIXME: seems to block the taskbar */ +/** + * @brief Hide the given window. + * + * @param window The window to show. + * + * This function hides @p window. If @p window is @c NULL, or on + * error, this function does nothing. + */ +EAPI void +ecore_win32_window_hide(Ecore_Win32_Window *window) +{ + if (!window) return; + + INF("hiding window"); + + ShowWindow(window->window, SW_HIDE); +} + +/** + * @brief Place the given window at the top of the Z order. + * + * @param window The window to place at the top. + * + * This function places @p window at the top of the Z order. If + * @p window is @c NULL, this function does nothing. + */ +EAPI void +ecore_win32_window_raise(Ecore_Win32_Window *window) +{ + if (!window) return; + + INF("raising window"); + + if (!SetWindowPos(window->window, + HWND_TOP, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE)) + { + ERR("SetWindowPos() failed"); + } +} + +/** + * @brief Place the given window at the bottom of the Z order. + * + * @param window The window to place at the bottom. + * + * This function places @p window at the bottom of the Z order. If + * @p window is @c NULL, this function does nothing. + */ +EAPI void +ecore_win32_window_lower(Ecore_Win32_Window *window) +{ + if (!window) return; + + INF("lowering window"); + + if (!SetWindowPos(window->window, + HWND_BOTTOM, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE)) + { + ERR("SetWindowPos() failed"); + } +} + +/** + * @brief Set the title of the given window. + * + * @param window The window to set the title. + * @param title The new title. + * + * This function sets the title of @p window to @p title. If @p window + * is @c NULL, or if @p title is @c NULL or empty, or on error, this + * function does nothing. + */ +EAPI void +ecore_win32_window_title_set(Ecore_Win32_Window *window, + const char *title) +{ + if (!window) return; + + if (!title || !title[0]) return; + + INF("setting window title"); + + if (!SetWindowText(window->window, title)) + { + ERR("SetWindowText() failed"); + } +} + +/** + * @brief Set the focus to the given window. + * + * @param window The window to give focus to. + * + * This function gives the focus to @p window. If @p window is + * @c NULL, this function does nothing. + */ +EAPI void +ecore_win32_window_focus(Ecore_Win32_Window *window) +{ + if (!window) return; + + INF("focusing window"); + + if (!SetFocus(window->window)) + { + ERR("SetFocus() failed"); + } +} + +/** + * @brief Get the current focused window. + * + * @return The window that has focus. + * + * This function returns the window that has focus. If the calling + * thread's message queue does not have an associated window with the + * keyboard focus, the return value is @c NULL. + * + * @note Even if the returned value is @c NULL, another thread's queue + * may be associated with a window that has the keyboard focus. + * + * @note The returned value is of type HWND. + */ +EAPI void * +ecore_win32_window_focus_get(void) +{ + HWND focused; + + INF("getting focused window"); + + focused = GetFocus(); + if (!focused) + { + ERR("GetFocus() failed"); + return NULL; + } + + return focused; +} + +/** + * @brief Iconify or restore the given window. + * + * @param window The window. + * @param on @c EINA_TRUE to iconify the window, @c EINA_FALSE to restore it. + * + * This function iconify or restore @p window. If @p on is set to @c EINA_TRUE, + * the window will be iconified, if it is set to @c EINA_FALSE, it will be + * restored. If @p window is @c NULL or if the state does not change (like + * iconifying the window while it is already iconified), this function does + * nothing. + */ +EAPI void +ecore_win32_window_iconified_set(Ecore_Win32_Window *window, + Eina_Bool on) +{ + if (!window) return; + + if (((window->iconified) && (on)) || + ((!window->iconified) && (!on))) + return; + + INF("iconifying window: %s", on ? "yes" : "no"); + + ShowWindow(window->window, on ? SW_MINIMIZE : SW_RESTORE); + window->iconified = on; +} + +/** + * @brief Remove or restore the border of the given window. + * + * @param window The window. + * @param on @c EINA_TRUE to remove the border, @c EINA_FALSE to restore it. + * + * This function remove or restore the border of @p window. If @p on is set to + * @c EINA_TRUE, the window will have no border, if it is set to @c EINA_FALSE, + * it will have a border. If @p window is @c NULL or if the state does not + * change (like setting to borderless while the window has no border), this + * function does nothing. + */ +EAPI void +ecore_win32_window_borderless_set(Ecore_Win32_Window *window, + Eina_Bool on) +{ + RECT rect; + DWORD style; + + if (!window) return; + + if (((window->borderless) && (on)) || + ((!window->borderless) && (!on))) + return; + + INF("setting window without border: %s", on ? "yes" : "no"); + + style = GetWindowLong(window->window, GWL_STYLE); + if (on) + { + if (!GetClientRect(window->window, &rect)) + { + ERR("GetClientRect() failed"); + return; + } + SetLastError(0); + if (!SetWindowLongPtr(window->window, GWL_STYLE, style & ~(WS_CAPTION | WS_THICKFRAME)) && + (GetLastError() != 0)) + { + ERR("SetWindowLongPtr() failed"); + return; + } + } + else + { + if (!GetWindowRect(window->window, &rect)) + { + ERR("GetWindowRect() failed"); + return; + } + style |= WS_CAPTION | WS_THICKFRAME; + if (!AdjustWindowRect (&rect, style, FALSE)) + { + ERR("AdjustWindowRect() failed"); + return; + } + SetLastError(0); + if (!SetWindowLongPtr(window->window, GWL_STYLE, style) && + (GetLastError() != 0)) + { + ERR("SetWindowLongPtr() failed"); + return; + } + } + if (!SetWindowPos(window->window, HWND_TOPMOST, + rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_NOMOVE | SWP_FRAMECHANGED)) + { + ERR("SetWindowPos() failed"); + return; + } + + window->borderless = on; +} + +/** + * @brief Set the given window to fullscreen. + * + * @param window The window. + * @param on @c EINA_TRUE for fullscreen mode, @c EINA_FALSE for windowed mode. + * + * This function set @p window to fullscreen or windowed mode. If @p on is set + * to @c EINA_TRUE, the window will be fullscreen, if it is set to + * @c EINA_FALSE, it will be windowed. If @p window is @c NULL or if the state + * does not change (like setting to fullscreen while the window is already + * fullscreen), this function does nothing. + */ +EAPI void +ecore_win32_window_fullscreen_set(Ecore_Win32_Window *window, + Eina_Bool on) +{ + if (!window) return; + + if (((window->fullscreen) && (on)) || + ((!window->fullscreen) && (!on))) + return; + + INF("setting fullscreen: %s", on ? "yes" : "no"); + + window->fullscreen = !!on; + + if (on) + { + DWORD style; + + if (!GetWindowRect(window->window, &window->rect)) + { + ERR("GetWindowRect() failed"); + return; + } + if (!(window->style = GetWindowLong(window->window, GWL_STYLE))) + { + ERR("GetWindowLong() failed"); + return; + } + style = window->style & ~WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX; + style |= WS_VISIBLE | WS_POPUP; + SetLastError(0); + if (!SetWindowLongPtr(window->window, GWL_STYLE, style) && + (GetLastError() != 0)) + { + ERR("SetWindowLongPtr() failed"); + return; + } + SetLastError(0); + if (!SetWindowLongPtr(window->window, GWL_EXSTYLE, WS_EX_TOPMOST) && + (GetLastError() != 0)) + { + ERR("SetWindowLongPtr() failed"); + return; + } + if (!SetWindowPos(window->window, HWND_TOPMOST, 0, 0, + GetSystemMetrics (SM_CXSCREEN), + GetSystemMetrics (SM_CYSCREEN), + SWP_NOCOPYBITS | SWP_SHOWWINDOW)) + { + ERR("SetWindowPos() failed"); + return; + } + } + else + { + SetLastError(0); + if (!SetWindowLongPtr(window->window, GWL_STYLE, window->style) && + (GetLastError() != 0)) + { + ERR("SetWindowLongPtr() failed"); + return; + } + SetLastError(0); + if (!SetWindowLongPtr(window->window, GWL_EXSTYLE, 0) && + (GetLastError() != 0)) + { + ERR("SetWindowLongPtr() failed"); + return; + } + if (!SetWindowPos(window->window, HWND_NOTOPMOST, + window->rect.left, + window->rect.top, + window->rect.right - window->rect.left, + window->rect.bottom - window->rect.top, + SWP_NOCOPYBITS | SWP_SHOWWINDOW)) + { + ERR("SetWindowPos() failed"); + return; + } + } +} + +/** + * @brief Set the given cursor to the given window. + * + * @param window The window to modify the cursor. + * @param cursor The new cursor. + * + * This function sets @p cursor to @p window. @p cursor must have been + * obtained by ecore_win32_cursor_new() or + * ecore_win32_cursor_shaped_new(). If @p window or @p cursor is + * @c NULL, the function does nothing. + */ +EAPI void +ecore_win32_window_cursor_set(Ecore_Win32_Window *window, + Ecore_Win32_Cursor *cursor) +{ + INF("setting cursor"); + + if (!window || !cursor) + return; + + if (!SetClassLongPtr(window->window, + GCLP_HCURSOR, (LONG_PTR)cursor)) + { + ERR("SetClassLong() failed"); + } +} + +/** + * @brief Set the state of the given window. + * + * @param window The window to modify the state. + * @param state An array of the new states. + * @param num The number of states in the array. + * + * This function set the state of @p window. @p state is an array of + * states of size @p num. If @p window or @p state are @c NULL, or if + * @p num is less or equal than 0, the function does nothing. + */ +EAPI void +ecore_win32_window_state_set(Ecore_Win32_Window *window, + Ecore_Win32_Window_State *state, + unsigned int num) +{ + unsigned int i; + + if (!window || !state || (num <= 0)) + return; + + INF("setting cursor state"); + + for (i = 0; i < num; i++) + { + switch (state[i]) + { + case ECORE_WIN32_WINDOW_STATE_ICONIFIED: + window->state.iconified = 1; + break; + case ECORE_WIN32_WINDOW_STATE_MODAL: + window->state.modal = 1; + break; + case ECORE_WIN32_WINDOW_STATE_STICKY: + window->state.sticky = 1; + break; + case ECORE_WIN32_WINDOW_STATE_MAXIMIZED_VERT: + window->state.maximized_vert = 1; + break; + case ECORE_WIN32_WINDOW_STATE_MAXIMIZED_HORZ: + window->state.maximized_horz = 1; + break; + case ECORE_WIN32_WINDOW_STATE_MAXIMIZED: + window->state.maximized_horz = 1; + window->state.maximized_vert = 1; + break; + case ECORE_WIN32_WINDOW_STATE_SHADED: + window->state.shaded = 1; + break; + case ECORE_WIN32_WINDOW_STATE_HIDDEN: + window->state.hidden = 1; + break; + case ECORE_WIN32_WINDOW_STATE_FULLSCREEN: + window->state.fullscreen = 1; + break; + case ECORE_WIN32_WINDOW_STATE_ABOVE: + window->state.above = 1; + break; + case ECORE_WIN32_WINDOW_STATE_BELOW: + window->state.below = 1; + break; + case ECORE_WIN32_WINDOW_STATE_DEMANDS_ATTENTION: + window->state.demands_attention = 1; + break; + case ECORE_WIN32_WINDOW_STATE_UNKNOWN: + /* nothing to be done */ + break; + } + } +} + +/** + * @brief Apply the modification of the state to the given window. + * + * @param window The window. + * @param state The state to apply changes. + * @param set The value of the state change. + * + * This function applies the modification of the state @p state of + * @p window. @p set is used only for + * #ECORE_WIN32_WINDOW_STATE_ICONIFIED and + * #ECORE_WIN32_WINDOW_STATE_FULLSCREEN. If @p window is @c NULL, the + * function does nothing. + */ +EAPI void +ecore_win32_window_state_request_send(Ecore_Win32_Window *window, + Ecore_Win32_Window_State state, + unsigned int set) +{ + if (!window) return; + + INF("sending cursor state"); + + switch (state) + { + case ECORE_WIN32_WINDOW_STATE_ICONIFIED: + if (window->state.iconified) + ecore_win32_window_iconified_set(window, set); + break; + case ECORE_WIN32_WINDOW_STATE_MODAL: + window->state.modal = 1; + break; + case ECORE_WIN32_WINDOW_STATE_STICKY: + window->state.sticky = 1; + break; + case ECORE_WIN32_WINDOW_STATE_MAXIMIZED_VERT: + if (window->state.maximized_vert) + { + RECT rect; + int y; + int height; + + if (!SystemParametersInfo(SPI_GETWORKAREA, 0, + &rect, 0)) + { + ERR("SystemParametersInfo() failed"); + break; + } + y = rect.top; + height = rect.bottom - rect.top; + + if (!GetClientRect(window->window, &rect)) + { + ERR("GetClientRect() failed"); + break; + } + + if (!MoveWindow(window->window, rect.left, y, + rect.right - rect.left, + height, + TRUE)) + { + ERR("MoveWindow() failed"); + } + } + break; + case ECORE_WIN32_WINDOW_STATE_MAXIMIZED_HORZ: + if (window->state.maximized_horz) + { + RECT rect; + + if (!GetClientRect(window->window, &rect)) + { + ERR("GetClientRect() failed"); + break; + } + + if (!MoveWindow(window->window, 0, rect.top, + GetSystemMetrics(SM_CXSCREEN), + rect.bottom - rect.top, + TRUE)) + { + ERR("MoveWindow() failed"); + } + } + break; + case ECORE_WIN32_WINDOW_STATE_MAXIMIZED: + if (window->state.maximized_vert && window->state.maximized_horz) + { + RECT rect; + + if (!SystemParametersInfo(SPI_GETWORKAREA, 0, + &rect, 0)) + { + ERR("SystemParametersInfo() failed"); + break; + } + + if (!MoveWindow(window->window, 0, 0, + GetSystemMetrics(SM_CXSCREEN), + rect.bottom - rect.top, + TRUE)) + { + ERR("MoveWindow() failed"); + } + } + break; + case ECORE_WIN32_WINDOW_STATE_SHADED: + window->state.shaded = 1; + break; + case ECORE_WIN32_WINDOW_STATE_HIDDEN: + window->state.hidden = 1; + break; + case ECORE_WIN32_WINDOW_STATE_FULLSCREEN: + if (window->state.fullscreen) + ecore_win32_window_fullscreen_set(window, set); + break; + case ECORE_WIN32_WINDOW_STATE_ABOVE: + if (window->state.above) + if (!SetWindowPos(window->window, HWND_TOP, + 0, 0, + 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW)) + { + ERR("SetWindowPos() failed"); + } + break; + case ECORE_WIN32_WINDOW_STATE_BELOW: + if (window->state.below) + if (!SetWindowPos(window->window, HWND_BOTTOM, + 0, 0, + 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW)) + { + ERR("SetWindowPos() failed"); + } + break; + case ECORE_WIN32_WINDOW_STATE_DEMANDS_ATTENTION: + window->state.demands_attention = 1; + break; + case ECORE_WIN32_WINDOW_STATE_UNKNOWN: + /* nothing to be done */ + break; + } +} + +/** + * @brief Set the type of the given window. + * + * @param window The window to modify the type. + * @param type The nwindow types. + * + * This function set the type of @p window to @p type. If + * @p window is @c NULL, the function does nothing. + */ +EAPI void +ecore_win32_window_type_set(Ecore_Win32_Window *window, + Ecore_Win32_Window_Type type) +{ + if (!window) + return; + + INF("setting window type"); + + switch (type) + { + case ECORE_WIN32_WINDOW_TYPE_DESKTOP: + window->type.desktop = 1; + break; + case ECORE_WIN32_WINDOW_TYPE_DOCK: + window->type.dock = 1; + break; + case ECORE_WIN32_WINDOW_TYPE_TOOLBAR: + window->type.toolbar = 1; + break; + case ECORE_WIN32_WINDOW_TYPE_MENU: + window->type.menu = 1; + break; + case ECORE_WIN32_WINDOW_TYPE_UTILITY: + window->type.utility = 1; + break; + case ECORE_WIN32_WINDOW_TYPE_SPLASH: + window->type.splash = 1; + break; + case ECORE_WIN32_WINDOW_TYPE_DIALOG: + window->type.dialog = 1; + break; + case ECORE_WIN32_WINDOW_TYPE_NORMAL: + window->type.normal = 1; + break; + case ECORE_WIN32_WINDOW_TYPE_UNKNOWN: + window->type.normal = 1; + break; + } +} + +/** + * @} + */ diff --git a/src/lib/ecore_wince/Ecore_WinCE.h b/src/lib/ecore_wince/Ecore_WinCE.h new file mode 100644 index 0000000..20c1975 --- /dev/null +++ b/src/lib/ecore_wince/Ecore_WinCE.h @@ -0,0 +1,314 @@ +#ifndef __ECORE_WINCE_H__ +#define __ECORE_WINCE_H__ + +/* + * DO NOT USE THIS HEADER. IT IS WORK IN PROGRESS. IT IS NOT FINAL AND + * THE API MAY CHANGE. + */ + +#ifndef ECORE_WINCE_WIP_OSXCKQSD +# warning "You are using a work in progress API. This API is not stable" +# warning "and is subject to change. You use this at your own risk." +#endif + +#include + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_ECORE_WINCE_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_ECORE_WINCE_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WINCE */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup Ecore_WinCE_Group Ecore_WinCE library + * + * @{ + */ + + +/** + * @typedef Ecore_WinCE_Window + * Abstract type for a window. + */ +typedef struct _Ecore_WinCE_Window Ecore_WinCE_Window; + + +/** + * @typedef Ecore_WinCE_Event_Mouse_In + * Event sent when the mouse enters the window. + */ +typedef struct _Ecore_WinCE_Event_Mouse_In Ecore_WinCE_Event_Mouse_In; + +/** + * @typedef Ecore_WinCE_Event_Mouse_Out + * Event sent when the mouse leaves the window. + */ +typedef struct _Ecore_WinCE_Event_Mouse_Out Ecore_WinCE_Event_Mouse_Out; + +/** + * @typedef Ecore_WinCE_Event_Window_Focus_In + * Event sent when the window gets the focus. + */ +typedef struct _Ecore_WinCE_Event_Window_Focus_In Ecore_WinCE_Event_Window_Focus_In; + +/** + * @typedef Ecore_WinCE_Event_Window_Focus_Out + * Event sent when the window looses the focus. + */ +typedef struct _Ecore_WinCE_Event_Window_Focus_Out Ecore_WinCE_Event_Window_Focus_Out; + +/** + * @typedef Ecore_WinCE_Event_Window_Damage + * Event sent when the window is damaged. + */ +typedef struct _Ecore_WinCE_Event_Window_Damage Ecore_WinCE_Event_Window_Damage; + +/** + * @typedef Ecore_WinCE_Event_Window_Create + * Event sent when the window is created. + */ +typedef struct _Ecore_WinCE_Event_Window_Create Ecore_WinCE_Event_Window_Create; + +/** + * @typedef Ecore_WinCE_Event_Window_Destroy + * Event sent when the window is destroyed. + */ +typedef struct _Ecore_WinCE_Event_Window_Destroy Ecore_WinCE_Event_Window_Destroy; + +/** + * @typedef Ecore_WinCE_Event_Window_Hide + * Event sent when the window is hidden. + */ +typedef struct _Ecore_WinCE_Event_Window_Hide Ecore_WinCE_Event_Window_Hide; + +/** + * @typedef Ecore_WinCE_Event_Window_Show + * Event sent when the window is shown. + */ +typedef struct _Ecore_WinCE_Event_Window_Show Ecore_WinCE_Event_Window_Show; + +/** + * @typedef Ecore_WinCE_Event_Window_Delete_Request + * Event sent when the window is deleted. + */ +typedef struct _Ecore_WinCE_Event_Window_Delete_Request Ecore_WinCE_Event_Window_Delete_Request; + + +/** + * @struct _Ecore_WinCE_Event_Mouse_In + * Event sent when the mouse enters the window. + */ +struct _Ecore_WinCE_Event_Mouse_In +{ + Ecore_WinCE_Window *window; /**< The window that received the event */ + int x; /**< The x coordinate where the mouse entered */ + int y; /**< The y coordinate where the mouse entered */ + long time; /**< The time the event occurred */ +}; + +/** + * @struct _Ecore_WinCE_Event_Mouse_Out + * Event sent when the mouse leaves the window. + */ +struct _Ecore_WinCE_Event_Mouse_Out +{ + Ecore_WinCE_Window *window; /**< The window that received the event */ + int x; /**< The x coordinate where the mouse leaved */ + int y; /**< The y coordinate where the mouse leaved */ + long time; /**< The time the event occurred */ +}; + +/** + * @struct _Ecore_WinCE_Event_Window_Focus_In + * Event sent when the window gets the focus. + */ +struct _Ecore_WinCE_Event_Window_Focus_In +{ + Ecore_WinCE_Window *window; /**< The window that received the event */ + long time; /**< The time the event occurred */ +}; + +/** + * @struct _Ecore_WinCE_Event_Window_Focus_Out + * Event sent when the window looses the focus. + */ +struct _Ecore_WinCE_Event_Window_Focus_Out +{ + Ecore_WinCE_Window *window; /**< The window that received the event */ + long time; /**< The time the event occurred */ +}; + +/** + * @struct _Ecore_WinCE_Event_Window_Damage + * Event sent when the window is damaged. + */ +struct _Ecore_WinCE_Event_Window_Damage +{ + Ecore_WinCE_Window *window; /**< The window that received the event */ + int x; /**< The x coordinate of the top left corner of the damaged region */ + int y; /**< The y coordinate of the top left corner of the damaged region */ + int width; /**< The width of the damaged region */ + int height; /**< The height of the damaged region */ + long time; /**< The time the event occurred */ +}; + +/** + * @struct _Ecore_WinCE_Event_Window_Create + * Event sent when the window is created. + */ +struct _Ecore_WinCE_Event_Window_Create +{ + Ecore_WinCE_Window *window; /**< The window that received the event */ + long time; /**< The time the event occurred */ +}; + +/** + * @struct _Ecore_WinCE_Event_Window_Destroy + * Event sent when the window is destroyed. + */ +struct _Ecore_WinCE_Event_Window_Destroy +{ + Ecore_WinCE_Window *window; /**< The window that received the event */ + long time; /**< The time the event occurred */ +}; + +/** + * @struct _Ecore_WinCE_Event_Window_Hide + * Event sent when the window is hidden. + */ +struct _Ecore_WinCE_Event_Window_Hide +{ + Ecore_WinCE_Window *window; /**< The window that received the event */ + long time; /**< The time the event occurred */ +}; + +/** + * @struct _Ecore_WinCE_Event_Window_Show + * Event sent when the window is shown. + */ +struct _Ecore_WinCE_Event_Window_Show +{ + Ecore_WinCE_Window *window; /**< The window that received the event */ + long time; /**< The time the event occurred */ +}; + +/** + * @struct _Ecore_WinCE_Event_Window_Delete_Request + * Event sent when the window is deleted. + */ +struct _Ecore_WinCE_Event_Window_Delete_Request +{ + Ecore_WinCE_Window *window; /**< The window that received the event */ + long time; /**< The time the event occurred */ +}; + + +EAPI extern int ECORE_WINCE_EVENT_MOUSE_IN; /**< Ecore_Event for the #Ecore_WinCE_Event_Mouse_In event */ +EAPI extern int ECORE_WINCE_EVENT_MOUSE_OUT; /**< Ecore_Event for the #Ecore_WinCE_Event_Mouse_Out event */ +EAPI extern int ECORE_WINCE_EVENT_WINDOW_FOCUS_IN; /**< Ecore_Event for the #Ecore_WinCE_Event_Window_Focus_In event */ +EAPI extern int ECORE_WINCE_EVENT_WINDOW_FOCUS_OUT; /**< Ecore_Event for the #Ecore_WinCE_Event_Window_Focus_Out event */ +EAPI extern int ECORE_WINCE_EVENT_WINDOW_DAMAGE; /**< Ecore_Event for the Ecore_WinCE_Event_Damage event */ +EAPI extern int ECORE_WINCE_EVENT_WINDOW_CREATE; /**< Ecore_Event for the Ecore_WinCE_Event_Create event */ +EAPI extern int ECORE_WINCE_EVENT_WINDOW_DESTROY; /**< Ecore_Event for the Ecore_WinCE_Event_Destroy event */ +EAPI extern int ECORE_WINCE_EVENT_WINDOW_HIDE; /**< Ecore_Event for the Ecore_WinCE_Event_Hide event */ +EAPI extern int ECORE_WINCE_EVENT_WINDOW_SHOW; /**< Ecore_Event for the Ecore_WinCE_Event_Show event */ +EAPI extern int ECORE_WINCE_EVENT_WINDOW_DELETE_REQUEST; /**< Ecore_Event for the #Ecore_WinCE_Event_Window_Delete_Request event */ + + +/* Core */ + +EAPI int ecore_wince_init(); +EAPI int ecore_wince_shutdown(); +EAPI void ecore_wince_double_click_time_set(double t); +EAPI double ecore_wince_double_click_time_get(void); +EAPI long ecore_wince_current_time_get(void); + +/* Window */ + +EAPI Ecore_WinCE_Window *ecore_wince_window_new(Ecore_WinCE_Window *parent, + int x, + int y, + int width, + int height); + +EAPI void ecore_wince_window_free(Ecore_WinCE_Window *window); + +EAPI void *ecore_wince_window_hwnd_get(Ecore_WinCE_Window *window); + +EAPI void ecore_wince_window_move(Ecore_WinCE_Window *window, + int x, + int y); + +EAPI void ecore_wince_window_resize(Ecore_WinCE_Window *window, + int width, + int height); + +EAPI void ecore_wince_window_move_resize(Ecore_WinCE_Window *window, + int x, + int y, + int width, + int height); + +EAPI void ecore_wince_window_show(Ecore_WinCE_Window *window); + +EAPI void ecore_wince_window_hide(Ecore_WinCE_Window *window); + +EAPI void ecore_wince_window_title_set(Ecore_WinCE_Window *window, + const char *title); + +EAPI void ecore_wince_window_focus(Ecore_WinCE_Window *window); + +EAPI void *ecore_wince_window_focus_get(void); + +EAPI void ecore_wince_window_backend_set(Ecore_WinCE_Window *window, int backend); + +EAPI void ecore_wince_window_suspend_cb_set(Ecore_WinCE_Window *window, int (*suspend_cb)(int)); + +EAPI void ecore_wince_window_resume_cb_set(Ecore_WinCE_Window *window, int (*resume_cb)(int)); + +EAPI void ecore_wince_window_geometry_get(Ecore_WinCE_Window *window, + int *x, + int *y, + int *width, + int *height); + +EAPI void ecore_wince_window_size_get(Ecore_WinCE_Window *window, + int *width, + int *height); + +EAPI void ecore_wince_window_fullscreen_set(Ecore_WinCE_Window *window, + Eina_Bool on); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ECORE_WINCE_H__ */ diff --git a/src/lib/ecore_wince/Makefile.am b/src/lib/ecore_wince/Makefile.am new file mode 100644 index 0000000..a264ffb --- /dev/null +++ b/src/lib/ecore_wince/Makefile.am @@ -0,0 +1,35 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore_input \ +-I$(top_builddir)/src/lib/ecore \ +-I$(top_builddir)/src/lib/ecore_input \ +@EFL_ECORE_WINCE_BUILD@ \ +@EVAS_CFLAGS@ \ +@EINA_CFLAGS@ \ +@WIN32_CPPFLAGS@ + +AM_CFLAGS = @WIN32_CFLAGS@ + +lib_LTLIBRARIES = libecore_wince.la + +includes_HEADERS = Ecore_WinCE.h +includesdir = $(includedir)/ecore-@VMAJ@ + +libecore_wince_la_SOURCES = \ +ecore_wince.c \ +ecore_wince_event.c \ +ecore_wince_window.c + +libecore_wince_la_LIBADD = \ +@WIN32_LIBS@ \ +$(top_builddir)/src/lib/ecore_input/libecore_input.la \ +$(top_builddir)/src/lib/ecore/libecore.la \ +@EVAS_LIBS@ \ +@EINA_LIBS@ \ +@EVIL_LIBS@ + +libecore_wince_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ + +EXTRA_DIST = ecore_wince_private.h diff --git a/src/lib/ecore_wince/ecore_wince.c b/src/lib/ecore_wince/ecore_wince.c new file mode 100644 index 0000000..5638ad3 --- /dev/null +++ b/src/lib/ecore_wince/ecore_wince.c @@ -0,0 +1,400 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include /* for printf */ + +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN + +#include +#include +#include + +#include "Ecore_WinCE.h" +#include "ecore_wince_private.h" + +/*============================================================================* + * Local * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +static int _ecore_wince_init_count = 0; + +LRESULT CALLBACK +_ecore_wince_window_procedure(HWND window, + UINT message, + WPARAM window_param, + LPARAM data_param) +{ + Ecore_WinCE_Callback_Data *data; + POINTS pt; + DWORD coord; + + data = (Ecore_WinCE_Callback_Data *)malloc(sizeof(Ecore_WinCE_Callback_Data)); + if (!data) return DefWindowProc(window, message, window_param, data_param); + + data->window = window; + data->message = message; + data->window_param = window_param; + data->data_param = data_param; + data->time = GetTickCount(); + coord = GetMessagePos(); + pt = MAKEPOINTS(coord); + data->x = pt.x; + data->y = pt.y; + + switch (data->message) + { + /* Keyboard input notifications */ + case WM_CHAR: + _ecore_wince_event_handle_key_press(data, 0); + break; + case WM_HOTKEY: + _ecore_wince_event_handle_key_press(data, 1); + break; + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + _ecore_wince_event_handle_key_press(data, 1); + break; + case WM_KEYUP: + case WM_SYSKEYUP: + _ecore_wince_event_handle_key_release(data, 1); + break; + case WM_SETFOCUS: + _ecore_wince_event_handle_focus_in(data); + break; + case WM_KILLFOCUS: + _ecore_wince_event_handle_focus_out(data); + break; + /* Mouse input notifications */ + case WM_LBUTTONDOWN: + _ecore_wince_event_handle_button_press(data, 1); + break; + case WM_LBUTTONUP: + _ecore_wince_event_handle_button_release(data, 1); + break; + case WM_MOUSEMOVE: + { + RECT rect; + Ecore_WinCE_Window *w = NULL; + + w = (Ecore_WinCE_Window *)GetWindowLong(window, GWL_USERDATA); + + if (GetClientRect(window, &rect)) + { + POINT pt; + + INF("mouse in window"); + + pt.x = LOWORD(data_param); + pt.y = HIWORD(data_param); + if (!PtInRect(&rect, pt)) + { + if (w->pointer_is_in) + { + w->pointer_is_in = 0; + _ecore_wince_event_handle_leave_notify(data); + } + } + else + { + if (!w->pointer_is_in) + { + w->pointer_is_in = 1; + _ecore_wince_event_handle_enter_notify(data); + } + } + } + else + { + ERR("GetClientRect() failed"); + } + _ecore_wince_event_handle_motion_notify(data); + + break; + } + /* Window notifications */ + case WM_CREATE: + _ecore_wince_event_handle_create_notify(data); + break; + case WM_DESTROY: + _ecore_wince_event_handle_destroy_notify(data); + break; + case WM_SHOWWINDOW: + if ((data->data_param == SW_OTHERUNZOOM) || + (data->data_param == SW_OTHERZOOM)) + break; + + if (data->window_param) + _ecore_wince_event_handle_map_notify(data); + else + _ecore_wince_event_handle_unmap_notify(data); + + break; + case WM_CLOSE: + _ecore_wince_event_handle_delete_request(data); + break; + /* GDI notifications */ + case WM_ERASEBKGND: + return 1; + case WM_PAINT: + { + PAINTSTRUCT paint; + + if (BeginPaint(window, &paint)) + { + data->update = paint.rcPaint; + _ecore_wince_event_handle_expose(data); + EndPaint(window, &paint); + } + break; + } + default: + return DefWindowProc(window, message, window_param, data_param); + } + + return 0; +} + +static void +_ecore_wince_error_print_cb(const Eina_Log_Domain *d __UNUSED__, + Eina_Log_Level level __UNUSED__, + const char *file __UNUSED__, + const char *fnc, + int line, + const char *fmt, + void *data __UNUSED__, + va_list args) +{ + fprintf(stderr, "[%s:%d] ", fnc, line); + vfprintf(stderr, fmt, args); +} + +/** + * @endcond + */ + + +/*============================================================================* + * Global * + *============================================================================*/ + + +double _ecore_wince_double_click_time = 0.25; +long _ecore_wince_event_last_time = 0; +Ecore_WinCE_Window *_ecore_wince_event_last_window = NULL; +HINSTANCE _ecore_wince_instance = NULL; +int _ecore_wince_log_dom_global = -1; + +int ECORE_WINCE_EVENT_MOUSE_IN = 0; +int ECORE_WINCE_EVENT_MOUSE_OUT = 0; +int ECORE_WINCE_EVENT_WINDOW_FOCUS_IN = 0; +int ECORE_WINCE_EVENT_WINDOW_FOCUS_OUT = 0; +int ECORE_WINCE_EVENT_WINDOW_DAMAGE = 0; +int ECORE_WINCE_EVENT_WINDOW_CREATE = 0; +int ECORE_WINCE_EVENT_WINDOW_DESTROY = 0; +int ECORE_WINCE_EVENT_WINDOW_SHOW = 0; +int ECORE_WINCE_EVENT_WINDOW_HIDE = 0; +int ECORE_WINCE_EVENT_WINDOW_DELETE_REQUEST = 0; + +/*============================================================================* + * API * + *============================================================================*/ + +/** + * @addtogroup Ecore_WinCE_Group Ecore_WinCE library + * + * Ecore_WinCE is a library that wraps Windows CE graphic functions + * and integrate them nicely into the Ecore main loop. + * + * @{ + */ + +/** + * @brief Initialize the Ecore_WinCE library. + * + * @return 1 or greater on success, 0 on error. + * + * This function sets up the Windows CE graphic system. It returns 0 on + * failure, otherwise it returns the number of times it has already been + * called. + * + * When Ecore_WinCE is not used anymore, call ecore_wince_shutdown() + * to shut down the Ecore_WinCE library. + */ +EAPI int +ecore_wince_init() +{ + WNDCLASS wc; + + if (++_ecore_wince_init_count != 1) + return _ecore_wince_init_count; + + if (!eina_init()) + return --_ecore_wince_init_count; + + eina_log_print_cb_set(_ecore_wince_error_print_cb, NULL); + _ecore_wince_log_dom_global = eina_log_domain_register + ("ecore_wince", ECORE_WINCE_DEFAULT_LOG_COLOR); + if (_ecore_wince_log_dom_global < 0) + { + EINA_LOG_ERR("Ecore_WinCE: Could not register log domain"); + goto shutdown_eina; + } + + if (!ecore_event_init()) + { + ERR("Ecore_WinCE: Could not init ecore_event"); + goto unregister_log_domain; + } + + _ecore_wince_instance = GetModuleHandle(NULL); + if (!_ecore_wince_instance) + { + ERR("GetModuleHandle() failed"); + goto shutdown_ecore_event; + } + + memset (&wc, 0, sizeof (wc)); + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = _ecore_wince_window_procedure; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = _ecore_wince_instance; + wc.hIcon = NULL; + wc.hCursor = LoadCursor (NULL, IDC_ARROW); + wc.hbrBackground = GetSysColorBrush(COLOR_BTNFACE); + wc.lpszMenuName = NULL; + wc.lpszClassName = ECORE_WINCE_WINDOW_CLASS; + + if(!RegisterClass(&wc)) + { + ERR("RegisterClass() failed"); + goto free_library; + } + + if (!ECORE_WINCE_EVENT_MOUSE_IN) + { + ECORE_WINCE_EVENT_MOUSE_IN = ecore_event_type_new(); + ECORE_WINCE_EVENT_MOUSE_OUT = ecore_event_type_new(); + ECORE_WINCE_EVENT_WINDOW_FOCUS_IN = ecore_event_type_new(); + ECORE_WINCE_EVENT_WINDOW_FOCUS_OUT = ecore_event_type_new(); + ECORE_WINCE_EVENT_WINDOW_DAMAGE = ecore_event_type_new(); + ECORE_WINCE_EVENT_WINDOW_CREATE = ecore_event_type_new(); + ECORE_WINCE_EVENT_WINDOW_DESTROY = ecore_event_type_new(); + ECORE_WINCE_EVENT_WINDOW_SHOW = ecore_event_type_new(); + ECORE_WINCE_EVENT_WINDOW_HIDE = ecore_event_type_new(); + ECORE_WINCE_EVENT_WINDOW_DELETE_REQUEST = ecore_event_type_new(); + } + + return _ecore_wince_init_count; + + free_library: + FreeLibrary(_ecore_wince_instance); + shutdown_ecore_event: + ecore_event_shutdown(); + unregister_log_domain: + eina_log_domain_unregister(_ecore_wince_log_dom_global); + shutdown_eina: + eina_shutdown(); + + return --_ecore_wince_init_count; +} + +/** + * @brief Shut down the Ecore_WinCE library. + * + * @return 0 when the library is completely shut down, 1 or + * greater otherwise. + * + * This function shuts down the Ecore_WinCE library. It returns 0 when it has + * been called the same number of times than ecore_wince_init(). In that case + * it shuts down all the Windows CE graphic system. + */ +EAPI int +ecore_wince_shutdown() +{ + HWND task_bar; + + if (--_ecore_wince_init_count != 0) + return _ecore_wince_init_count; + + /* force task bar to be shown (in case the application exits */ + /* while being fullscreen) */ + task_bar = FindWindow(L"HHTaskBar", NULL); + if (task_bar) + { + ShowWindow(task_bar, SW_SHOW); + EnableWindow(task_bar, TRUE); + } + + if (!UnregisterClass(ECORE_WINCE_WINDOW_CLASS, _ecore_wince_instance)) + ERR("UnregisterClass() failed"); + + if (!FreeLibrary(_ecore_wince_instance)) + ERR("FreeLibrary() failed"); + + _ecore_wince_instance = NULL; + + ecore_event_shutdown(); + eina_log_domain_unregister(_ecore_wince_log_dom_global); + _ecore_wince_log_dom_global = -1; + eina_shutdown(); + + return _ecore_wince_init_count; +} + +/** + * @brief Set the timeout for a double and triple clicks to be flagged. + * + * @param t The time in seconds. + * + * This function sets the time @p t between clicks before the + * double_click flag is set in a button down event. If 3 clicks occur + * within double this time, the triple_click flag is also set. + */ +EAPI void +ecore_wince_double_click_time_set(double t) +{ + if (t < 0.0) t = 0.0; + _ecore_wince_double_click_time = t; +} + +/** + * @brief Retrieve the double and triple click flag timeout. + * + * @return The timeout for double clicks in seconds. + * + * This function returns the double clicks in seconds. If + * ecore_wince_double_click_time_set() has not been called, the + * default value is returned. See ecore_wince_double_click_time_set() + * for more informations. + */ +EAPI double +ecore_wince_double_click_time_get(void) +{ + return _ecore_wince_double_click_time; +} + +/** + * @brief Return the last event time. + * + * @return The last envent time. + * + * This function returns the last event time. + */ +EAPI long +ecore_wince_current_time_get(void) +{ + return _ecore_wince_event_last_time; +} + +/** + * @} + */ diff --git a/src/lib/ecore_wince/ecore_wince_event.c b/src/lib/ecore_wince/ecore_wince_event.c new file mode 100644 index 0000000..9afc062 --- /dev/null +++ b/src/lib/ecore_wince/ecore_wince_event.c @@ -0,0 +1,1123 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN + +#include +#include +#include + +#include "Ecore_WinCE.h" +#include "ecore_wince_private.h" + +/*============================================================================* + * Local * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +typedef enum +{ + ECORE_WINCE_KEY_MASK_LSHIFT = 1 << 0, + ECORE_WINCE_KEY_MASK_RSHIFT = 1 << 1, + ECORE_WINCE_KEY_MASK_LCONTROL = 1 << 2, + ECORE_WINCE_KEY_MASK_RCONTROL = 1 << 3, + ECORE_WINCE_KEY_MASK_LMENU = 1 << 4, + ECORE_WINCE_KEY_MASK_RMENU = 1 << 5 +} Ecore_Wince_Key_Mask; + +static Ecore_WinCE_Window *_ecore_wince_mouse_down_last_window = NULL; +static Ecore_WinCE_Window *_ecore_wince_mouse_down_last_last_window = NULL; +static long _ecore_wince_mouse_down_last_time = 0; +static long _ecore_wince_mouse_down_last_last_time = 0; +static int _ecore_wince_mouse_down_did_triple = 0; +static int _ecore_wince_mouse_up_count = 0; +static Ecore_Wince_Key_Mask _ecore_wince_key_mask = 0; + +static void +_ecore_wince_event_free_key_down(void *data __UNUSED__, + void *ev) +{ + Ecore_Event_Key *e; + + e = ev; + if (e->keyname) free((char *)e->keyname); + if (e->key) free((char *)e->key); + if (e->string) free((char *)e->string); + free(e); +} + +static void +_ecore_wince_event_free_key_up(void *data __UNUSED__, + void *ev) +{ + Ecore_Event_Key *e; + + e = ev; + if (e->keyname) free((char *)e->keyname); + if (e->key) free((char *)e->key); + if (e->string) free((char *)e->string); + free(e); +} + +static int +_ecore_wince_event_keystroke_get(int key, + Eina_Bool is_down, + char **keyname, + char **keysymbol, + char **keycompose) +{ + char *kn; + char *ks; + char *kc; + int previous_key_state; + + previous_key_state = msg->data_param & 0x40000000; + + *keyname = NULL; + *keysymbol = NULL; + *keycompose = NULL; + + switch (key) + { + /* Keystroke */ + case VK_PRIOR: + kn = "Prior"; + ks = "Prior"; + kc = "Prior"; + break; + case VK_NEXT: + kn = "Next"; + ks = "Next"; + kc = "Next"; + break; + case VK_END: + kn = "End"; + ks = "End"; + kc = "End"; + break; + case VK_HOME: + kn = "Home"; + ks = "Home"; + kc = "Home"; + break; + case VK_LEFT: + kn = "Left"; + ks = "Left"; + kc = "Left"; + break; + case VK_UP: + kn = "Up"; + ks = "Up"; + kc = "Up"; + break; + case VK_RIGHT: + kn = "Right"; + ks = "Right"; + kc = "Right"; + break; + case VK_DOWN: + kn = "Down"; + ks = "Down"; + kc = "Down"; + break; + case VK_INSERT: + kn = "Insert"; + ks = "Insert"; + kc = "Insert"; + break; + case VK_DELETE: + kn = "Delete"; + ks = "Delete"; + kc = "Delete"; + break; + case VK_F1: + kn = "F1"; + ks = "F1"; + kc = ""; + break; + case VK_F2: + kn = "F2"; + ks = "F2"; + kc = ""; + break; + case VK_F3: + kn = "F3"; + ks = "F3"; + kc = ""; + break; + case VK_F4: + kn = "F4"; + ks = "F4"; + kc = ""; + break; + case VK_F5: + kn = "F5"; + ks = "F5"; + kc = ""; + break; + case VK_F6: + kn = "F6"; + ks = "F6"; + kc = ""; + break; + case VK_F7: + kn = "F7"; + ks = "F7"; + kc = ""; + break; + case VK_F8: + kn = "F8"; + ks = "F8"; + kc = ""; + break; + case VK_F9: + kn = "F9"; + ks = "F9"; + kc = ""; + break; + case VK_F10: + kn = "F10"; + ks = "F10"; + kc = ""; + break; + case VK_F11: + kn = "F11"; + ks = "F11"; + kc = ""; + break; + case VK_F12: + kn = "F12"; + ks = "F12"; + kc = ""; + break; + case VK_F13: + kn = "F13"; + ks = "F13"; + kc = ""; + break; + case VK_F14: + kn = "F14"; + ks = "F14"; + kc = ""; + break; + case VK_F15: + kn = "F15"; + ks = "F15"; + kc = ""; + break; + case VK_F16: + kn = "F16"; + ks = "F16"; + kc = ""; + break; + case VK_F17: + kn = "F17"; + ks = "F17"; + kc = ""; + break; + case VK_F18: + kn = "F18"; + ks = "F18"; + kc = ""; + break; + case VK_F19: + kn = "F19"; + ks = "F19"; + kc = ""; + break; + case VK_F20: + /* + * VK_F20 indicates that an arrow key came from a rocker. + * This can safely be ignored. + */ + return 0; + case VK_F21: + /* + * VK_F21 indicates that an arrow key came from a directional + * pad. This can safely be ignored. + */ + return 0; + case VK_F22: + kn = "F22"; + ks = "F22"; + kc = ""; + break; + case VK_F23: + /* + * Sent with VK_RETURN when doing an action (usually the middle + * button on a directional pad. This can safely be ignored. + */ + return 0; + case VK_F24: + kn = "F24"; + ks = "F24"; + kc = ""; + break; + case VK_APPS: + kn = "Application"; + ks = "Application"; + kc = ""; + break; + case VK_SHIFT: + { + SHORT res; + + if (is_down) + { + if (previous_key_state) return 0; + res = GetKeyState(VK_LSHIFT); + if (res & 0x8000) + { + _ecore_wince_key_mask |= ECORE_WINCE_KEY_MASK_LSHIFT; + kn = "Shift_L"; + ks = "Shift_L"; + kc = ""; + } + res = GetKeyState(VK_RSHIFT); + if (res & 0x8000) + { + _ecore_wince_key_mask |= ECORE_WINCE_KEY_MASK_RSHIFT; + kn = "Shift_R"; + ks = "Shift_R"; + kc = ""; + } + } + else /* is_up */ + { + res = GetKeyState(VK_LSHIFT); + if (!(res & 0x8000) && + (_ecore_wince_key_mask & ECORE_WINCE_KEY_MASK_LSHIFT)) + { + kn = "Shift_L"; + ks = "Shift_L"; + kc = ""; + _ecore_wince_key_mask &= ~ECORE_WINCE_KEY_MASK_LSHIFT; + } + res = GetKeyState(VK_RSHIFT); + if (!(res & 0x8000) && + (_ecore_wince_key_mask & ECORE_WINCE_KEY_MASK_RSHIFT)) + { + kn = "Shift_R"; + ks = "Shift_R"; + kc = ""; + _ecore_wince_key_mask &= ~ECORE_WINCE_KEY_MASK_RSHIFT; + } + } + break; + } + case VK_CONTROL: + { + SHORT res; + + if (is_down) + { + if (previous_key_state) return 0; + res = GetKeyState(VK_LCONTROL); + if (res & 0x8000) + { + _ecore_wince_key_mask |= ECORE_WINCE_KEY_MASK_LCONTROL; + kn = "Control_L"; + ks = "Control_L"; + kc = ""; + break; + } + res = GetKeyState(VK_RCONTROL); + if (res & 0x8000) + { + _ecore_wince_key_mask |= ECORE_WINCE_KEY_MASK_RCONTROL; + kn = "Control_R"; + ks = "Control_R"; + kc = ""; + break; + } + } + else /* is_up */ + { + res = GetKeyState(VK_LCONTROL); + if (!(res & 0x8000) && + (_ecore_wince_key_mask & ECORE_WINCE_KEY_MASK_LCONTROL)) + { + kn = "Control_L"; + ks = "Control_L"; + kc = ""; + _ecore_wince_key_mask &= ~ECORE_WINCE_KEY_MASK_LCONTROL; + break; + } + res = GetKeyState(VK_RCONTROL); + if (!(res & 0x8000) && + (_ecore_wince_key_mask & ECORE_WINCE_KEY_MASK_RCONTROL)) + { + kn = "Control_R"; + ks = "Control_R"; + kc = ""; + _ecore_wince_key_mask &= ~ECORE_WINCE_KEY_MASK_RCONTROL; + break; + } + } + break; + } + case VK_MENU: + { + SHORT res; + + if (is_down) + { + if (previous_key_state) return 0; + res = GetKeyState(VK_LMENU); + if (res & 0x8000) + { + _ecore_wince_key_mask |= ECORE_WINCE_KEY_MASK_LMENU; + kn = "Alt_L"; + ks = "Alt_L"; + kc = ""; + } + res = GetKeyState(VK_RMENU); + if (res & 0x8000) + { + _ecore_wince_key_mask |= ECORE_WINCE_KEY_MASK_RMENU; + kn = "Alt_R"; + ks = "Alt_R"; + kc = ""; + } + } + else /* is_up */ + { + res = GetKeyState(VK_LMENU); + if (!(res & 0x8000) && + (_ecore_wince_key_mask & ECORE_WINCE_KEY_MASK_LMENU)) + { + kn = "Alt_L"; + ks = "Alt_L"; + kc = ""; + _ecore_wince_key_mask &= ~ECORE_WINCE_KEY_MASK_LMENU; + } + res = GetKeyState(VK_RMENU); + if (!(res & 0x8000) && + (_ecore_wince_key_mask & ECORE_WINCE_KEY_MASK_RMENU)) + { + kn = "Alt_R"; + ks = "Alt_R"; + kc = ""; + _ecore_wince_key_mask &= ~ECORE_WINCE_KEY_MASK_RMENU; + } + } + break; + } + case VK_LWIN: + { + if (is_down) + { + if (previous_key_state) return 0; + kn = "Super_L"; + ks = "Super_L"; + kc = ""; + *modifiers |= ECORE_EVENT_MODIFIER_WIN; + } + else /* is_up */ + { + kn = "Super_L"; + ks = "Super_L"; + kc = ""; + *modifiers &= ~ECORE_EVENT_MODIFIER_WIN; + } + break; + } + case VK_RWIN: + { + if (is_down) + { + if (previous_key_state) return 0; + kn = "Super_R"; + ks = "Super_R"; + kc = ""; + *modifiers |= ECORE_EVENT_MODIFIER_WIN; + } + else /* is_up */ + { + kn = "Super_R"; + ks = "Super_R"; + kc = ""; + *modifiers &= ~ECORE_EVENT_MODIFIER_WIN; + } + break; + } + default: + /* other non keystroke characters */ + return 0; + } + *keyname = strdup(kn); + if (!*keyname) return 0; + *keysymbol = strdup(ks); + if (!*keysymbol) + { + free(*keyname); + *keyname = NULL; + return 0; + } + *keycompose = strdup(kc); + if (!*keycompose) + { + free(*keyname); + free(*keysymbol); + *keyname = NULL; + *keysymbol = NULL; + return 0; + } + + return 1; +} + +static int +_ecore_wince_event_char_get(int key, + char **keyname, + char **keysymbol, + char **keycompose) +{ + char kn[32]; + char ks[32]; + char kc[32]; + + *keyname = NULL; + *keysymbol = NULL; + *keycompose = NULL; + + /* check control charaters such as ^a(key:1), ^z(key:26) */ + if ((key > 0) && (key < 27) && + ((GetKeyState(VK_CONTROL) & 0x8000) || + (GetKeyState(VK_CONTROL) & 0x8000))) key += 96; + + switch (key) + { + case VK_APP3: + case VK_BACK: + strncpy(kn, "BackSpace", 32); + strncpy(ks, "BackSpace", 32); + strncpy(kc, "BackSpace", 32); + break; + case VK_APP4: + case VK_TAB: + strncpy(kn, "Tab", 32); + strncpy(ks, "Tab", 32); + strncpy(kc, "Tab", 32); + break; + case VK_APP5: + case 0x0a: + /* Line feed (Shift + Enter) */ + strncpy(kn, "LineFeed", 32); + strncpy(ks, "LineFeed", 32); + strncpy(kc, "LineFeed", 32); + break; + case VK_APP2: + case VK_RETURN: + strncpy(kn, "Return", 32); + strncpy(ks, "Return", 32); + strncpy(kc, "Return", 32); + break; + case VK_APP1: + case VK_ESCAPE: + strncpy(kn, "Escape", 32); + strncpy(ks, "Escape", 32); + strncpy(kc, "Escape", 32); + break; + case VK_SPACE: + strncpy(kn, "space", 32); + strncpy(ks, "space", 32); + strncpy(kc, " ", 32); + break; + default: + /* displayable characters */ + printf (" * key : %d\n", key); + kn[0] = (TCHAR)key; + kn[1] = '\0'; + ks[0] = (TCHAR)key; + ks[1] = '\0'; + kc[0] = (TCHAR)key; + kc[1] = '\0'; + break; + } + *keyname = strdup(kn); + if (!*keyname) return 0; + *keysymbol = strdup(ks); + if (!*keysymbol) + { + free(*keyname); + *keyname = NULL; + return 0; + } + *keycompose = strdup(kc); + if (!*keycompose) + { + free(*keyname); + free(*keysymbol); + *keyname = NULL; + *keysymbol = NULL; + return 0; + } + + return 1; +} + +/** + * @endcond + */ + + +/*============================================================================* + * Global * + *============================================================================*/ + +void +_ecore_wince_event_handle_key_press(Ecore_WinCE_Callback_Data *msg, + int is_keystroke) +{ + Ecore_Event_Key *e; + + INF("key pressed"); + + e = (Ecore_Event_Key *)malloc(sizeof(Ecore_Event_Key)); + if (!e) return; + + if (is_keystroke) + { + if (!_ecore_wince_event_keystroke_get(LOWORD(msg->window_param), + EINA_TRUE, + (char **)&e->keyname, + (char **)&e->key, + (char **)&e->string)) + { + free(e); + return; + } + } + else + { + if (!_ecore_wince_event_char_get(LOWORD(msg->window_param), + (char **)&e->keyname, + (char **)&e->key, + (char **)&e->string)) + { + free(e); + return; + } + } + + e->window = (Ecore_Window)GetWindowLong(msg->window, GWL_USERDATA); + e->event_window = e->window; + if (!e->window) + { + free(e); + return; + } + e->timestamp = msg->time; + + _ecore_wince_event_last_time = e->timestamp; + + ecore_event_add(ECORE_EVENT_KEY_DOWN, e, _ecore_wince_event_free_key_down, NULL); +} + +void +_ecore_wince_event_handle_key_release(Ecore_WinCE_Callback_Data *msg, + int is_keystroke) +{ + Ecore_Event_Key *e; + + INF("key released"); + + e = (Ecore_Event_Key *)calloc(1, sizeof(Ecore_Event_Key)); + if (!e) return; + + if (is_keystroke) + { + if (!_ecore_wince_event_keystroke_get(LOWORD(msg->window_param), + EINA_FALSE, + (char **)&e->keyname, + (char **)&e->key, + (char **)&e->string)) + { + free(e); + return; + } + } + else + { + if (!_ecore_wince_event_char_get(LOWORD(msg->window_param), + (char **)&e->keyname, + (char **)&e->key, + (char **)&e->string)) + { + free(e); + return; + } + } + + e->window = (Ecore_Window)GetWindowLong(msg->window, GWL_USERDATA); + e->event_window = e->window; + if (!e->window) + { + free(e); + return; + } + e->timestamp = msg->time; + + _ecore_wince_event_last_time = e->timestamp; + + ecore_event_add(ECORE_EVENT_KEY_UP, e, _ecore_wince_event_free_key_up, NULL); +} + +void +_ecore_wince_event_handle_button_press(Ecore_WinCE_Callback_Data *msg, + int button) +{ + Ecore_WinCE_Window *window; + + INF("mouse button pressed"); + + window = (Ecore_WinCE_Window *)GetWindowLong(msg->window, GWL_USERDATA); + + { + Ecore_Event_Mouse_Move *e; + + e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move)); + if (!e) return; + + e->window = (Ecore_Window)window; + e->event_window = e->window; + e->x = LOWORD(msg->data_param); + e->y = HIWORD(msg->data_param); + e->timestamp = msg->time; + + _ecore_wince_event_last_time = e->timestamp; + _ecore_wince_event_last_window = (Ecore_WinCE_Window *)e->window; + + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL); + } + + { + Ecore_Event_Mouse_Button *e; + + if (_ecore_wince_mouse_down_did_triple) + { + _ecore_wince_mouse_down_last_window = NULL; + _ecore_wince_mouse_down_last_last_window = NULL; + _ecore_wince_mouse_down_last_time = 0; + _ecore_wince_mouse_down_last_last_time = 0; + } + + e = (Ecore_Event_Mouse_Button *)calloc(1, sizeof(Ecore_Event_Mouse_Button)); + if (!e) return; + + e->window = (Ecore_Window)window; + e->event_window = e->window; + e->buttons = button; + e->x = LOWORD(msg->data_param); + e->y = HIWORD(msg->data_param); + e->timestamp = msg->time; + + if (((e->timestamp - _ecore_wince_mouse_down_last_time) <= (long)(1000 * _ecore_wince_double_click_time)) && + (e->window == (Ecore_Window)_ecore_wince_mouse_down_last_window)) + e->double_click = 1; + + if (((e->timestamp - _ecore_wince_mouse_down_last_last_time) <= (long)(2 * 1000 * _ecore_wince_double_click_time)) && + (e->window == (Ecore_Window)_ecore_wince_mouse_down_last_window) && + (e->window == (Ecore_Window)_ecore_wince_mouse_down_last_last_window)) + { + e->triple_click = 1; + _ecore_wince_mouse_down_did_triple = 1; + } + else + _ecore_wince_mouse_down_did_triple = 0; + + if (!e->double_click && !e->triple_click) + _ecore_wince_mouse_up_count = 0; + + _ecore_wince_event_last_time = e->timestamp; + _ecore_wince_event_last_window = (Ecore_WinCE_Window *)e->window; + + if (!_ecore_wince_mouse_down_did_triple) + { + _ecore_wince_mouse_down_last_last_window = _ecore_wince_mouse_down_last_window; + _ecore_wince_mouse_down_last_window = (Ecore_WinCE_Window *)e->window; + _ecore_wince_mouse_down_last_last_time = _ecore_wince_mouse_down_last_time; + _ecore_wince_mouse_down_last_time = e->timestamp; + } + + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, e, NULL, NULL); + } +} + +void +_ecore_wince_event_handle_button_release(Ecore_WinCE_Callback_Data *msg, + int button) +{ + Ecore_WinCE_Window *window; + + INF("mouse button released"); + + window = (void *)GetWindowLong(msg->window, GWL_USERDATA); + + { + Ecore_Event_Mouse_Move *e; + + e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move)); + if (!e) return; + + e->window = (Ecore_Window)window; + e->event_window = e->window; + e->x = LOWORD(msg->data_param); + e->y = HIWORD(msg->data_param); + e->timestamp = msg->time; + + _ecore_wince_event_last_time = e->timestamp; + _ecore_wince_event_last_window = (Ecore_WinCE_Window *)e->window; + + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL); + } + + { + Ecore_Event_Mouse_Button *e; + + e = (Ecore_Event_Mouse_Button *)calloc(1, sizeof(Ecore_Event_Mouse_Button)); + if (!e) return; + + e->window = (Ecore_Window)window; + e->event_window = e->window; + e->buttons = button; + e->x = LOWORD(msg->data_param); + e->y = HIWORD(msg->data_param); + e->timestamp = msg->time; + + _ecore_wince_mouse_up_count++; + + if ((_ecore_wince_mouse_up_count >= 2) && + ((e->timestamp - _ecore_wince_mouse_down_last_time) <= (long)(1000 * _ecore_wince_double_click_time)) && + (e->window == (Ecore_Window)_ecore_wince_mouse_down_last_window)) + e->double_click = 1; + + if ((_ecore_wince_mouse_up_count >= 3) && + ((e->timestamp - _ecore_wince_mouse_down_last_last_time) <= (long)(2 * 1000 * _ecore_wince_double_click_time)) && + (e->window == (Ecore_Window)_ecore_wince_mouse_down_last_window) && + (e->window == (Ecore_Window)_ecore_wince_mouse_down_last_last_window)) + e->triple_click = 1; + + _ecore_wince_event_last_time = e->timestamp; + _ecore_wince_event_last_window = (Ecore_WinCE_Window *)e->window; + + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, e, NULL, NULL); + } +} + +void +_ecore_wince_event_handle_motion_notify(Ecore_WinCE_Callback_Data *msg) +{ + Ecore_Event_Mouse_Move *e; + + INF("mouse moved"); + + e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move)); + if (!e) return; + + e->window = (Ecore_Window)GetWindowLong(msg->window, GWL_USERDATA); + e->event_window = e->window; + e->x = LOWORD(msg->data_param); + e->y = HIWORD(msg->data_param); + e->timestamp = msg->time; + + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL); +} + +void +_ecore_wince_event_handle_enter_notify(Ecore_WinCE_Callback_Data *msg) +{ + Ecore_WinCE_Window *window; + + INF("mouse in"); + + window = (void *)GetWindowLong(msg->window, GWL_USERDATA); + + { + Ecore_Event_Mouse_Move *e; + + e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move)); + if (!e) return; + + e->window = (Ecore_Window)window; + e->event_window = e->window; + e->x = msg->x; + e->y = msg->y; + e->timestamp = msg->time; + + _ecore_wince_event_last_time = e->timestamp; + _ecore_wince_event_last_window = (Ecore_WinCE_Window *)e->window; + + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL); + } + + { + Ecore_WinCE_Event_Mouse_In *e; + + e = (Ecore_WinCE_Event_Mouse_In *)calloc(1, sizeof(Ecore_WinCE_Event_Mouse_In)); + if (!e) return; + + e->window = window; + e->x = msg->x; + e->y = msg->y; + e->time = msg->time; + + _ecore_wince_event_last_time = e->time; + + ecore_event_add(ECORE_WINCE_EVENT_MOUSE_IN, e, NULL, NULL); + } +} + +void +_ecore_wince_event_handle_leave_notify(Ecore_WinCE_Callback_Data *msg) +{ + Ecore_WinCE_Window *window; + + INF("mouse out"); + + window = (void *)GetWindowLong(msg->window, GWL_USERDATA); + + { + Ecore_Event_Mouse_Move *e; + + e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move)); + if (!e) return; + + e->window = (Ecore_Window)window; + e->event_window = e->window; + e->x = msg->x; + e->y = msg->y; + e->timestamp = msg->time; + + _ecore_wince_event_last_time = e->timestamp; + _ecore_wince_event_last_window = (Ecore_WinCE_Window *)e->window; + + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL); + } + + { + Ecore_WinCE_Event_Mouse_Out *e; + + e = (Ecore_WinCE_Event_Mouse_Out *)calloc(1, sizeof(Ecore_WinCE_Event_Mouse_Out)); + if (!e) return; + + e->window = window; + e->x = msg->x; + e->y = msg->y; + e->time = msg->time; + + _ecore_wince_event_last_time = e->time; + + ecore_event_add(ECORE_WINCE_EVENT_MOUSE_OUT, e, NULL, NULL); + } +} + +void +_ecore_wince_event_handle_focus_in(Ecore_WinCE_Callback_Data *msg) +{ + Ecore_WinCE_Event_Window_Focus_In *e; + Ecore_WinCE_Window *window; + + INF("focus in"); + + e = (Ecore_WinCE_Event_Window_Focus_In *)calloc(1, sizeof(Ecore_WinCE_Event_Window_Focus_In)); + if (!e) return; + + window = (void *)GetWindowLong(msg->window, GWL_USERDATA); + if (!e->window) + { + free(e); + return; + } + + if (window->resume_cb) + window->resume_cb(window->backend); + + e->window = window; + + e->time = _ecore_wince_event_last_time; + _ecore_wince_event_last_time = e->time; + + ecore_event_add(ECORE_WINCE_EVENT_WINDOW_FOCUS_IN, e, NULL, NULL); +} + +void +_ecore_wince_event_handle_focus_out(Ecore_WinCE_Callback_Data *msg) +{ + Ecore_WinCE_Event_Window_Focus_Out *e; + Ecore_WinCE_Window *window; + + INF("focus out"); + + e = (Ecore_WinCE_Event_Window_Focus_Out *)calloc(1, sizeof(Ecore_WinCE_Event_Window_Focus_Out)); + if (!e) return; + + window = (void *)GetWindowLong(msg->window, GWL_USERDATA); + if (!e->window) + { + free(e); + return; + } + if (window->suspend_cb) + window->suspend_cb(window->backend); + + e->window = window; + + e->time = _ecore_wince_event_last_time; + _ecore_wince_event_last_time = e->time; + + ecore_event_add(ECORE_WINCE_EVENT_WINDOW_FOCUS_OUT, e, NULL, NULL); +} + +void +_ecore_wince_event_handle_expose(Ecore_WinCE_Callback_Data *msg) +{ + Ecore_WinCE_Event_Window_Damage *e; + + INF("window expose"); + + e = (Ecore_WinCE_Event_Window_Damage *)calloc(1, sizeof(Ecore_WinCE_Event_Window_Damage)); + if (!e) return; + + e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA); + if (!e->window) + { + free(e); + return; + } + + e->x = msg->update.left; + e->y = msg->update.top; + e->width = msg->update.right - msg->update.left; + e->height = msg->update.bottom - msg->update.top; + INF("window expose size: %dx%d", e->width, e->height); + + e->time = _ecore_wince_event_last_time; + + ecore_event_add(ECORE_WINCE_EVENT_WINDOW_DAMAGE, e, NULL, NULL); +} + +void +_ecore_wince_event_handle_create_notify(Ecore_WinCE_Callback_Data *msg) +{ + Ecore_WinCE_Event_Window_Create *e; + + INF("window create notify"); + + e = calloc(1, sizeof(Ecore_WinCE_Event_Window_Create)); + if (!e) return; + + e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA); + if (!e->window) + { + free(e); + return; + } + + e->time = _ecore_wince_event_last_time; + + ecore_event_add(ECORE_WINCE_EVENT_WINDOW_CREATE, e, NULL, NULL); +} + +void +_ecore_wince_event_handle_destroy_notify(Ecore_WinCE_Callback_Data *msg) +{ + Ecore_WinCE_Event_Window_Destroy *e; + + INF("window destroy notify"); + + e = calloc(1, sizeof(Ecore_WinCE_Event_Window_Destroy)); + if (!e) return; + + e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA); + if (!e->window) + { + free(e); + return; + } + + e->time = _ecore_wince_event_last_time; +/* if (e->window == _ecore_wince_event_last_window) _ecore_wince_event_last_window = NULL; */ + + ecore_event_add(ECORE_WINCE_EVENT_WINDOW_DESTROY, e, NULL, NULL); +} + +void +_ecore_wince_event_handle_map_notify(Ecore_WinCE_Callback_Data *msg) +{ + Ecore_WinCE_Event_Window_Show *e; + + INF("window map notify"); + + e = calloc(1, sizeof(Ecore_WinCE_Event_Window_Show)); + if (!e) return; + + e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA); + if (!e->window) + { + free(e); + return; + } + + e->time = _ecore_wince_event_last_time; + + ecore_event_add(ECORE_WINCE_EVENT_WINDOW_SHOW, e, NULL, NULL); +} + +void +_ecore_wince_event_handle_unmap_notify(Ecore_WinCE_Callback_Data *msg) +{ + Ecore_WinCE_Event_Window_Hide *e; + + INF("window unmap notify"); + + e = calloc(1, sizeof(Ecore_WinCE_Event_Window_Hide)); + if (!e) return; + + e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA); + if (!e->window) + { + free(e); + return; + } + + e->time = _ecore_wince_event_last_time; + + ecore_event_add(ECORE_WINCE_EVENT_WINDOW_HIDE, e, NULL, NULL); +} + +void +_ecore_wince_event_handle_delete_request(Ecore_WinCE_Callback_Data *msg) +{ + Ecore_WinCE_Event_Window_Delete_Request *e; + + INF("window delete request"); + + e = calloc(1, sizeof(Ecore_WinCE_Event_Window_Delete_Request)); + if (!e) return; + + e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA); + if (!e->window) + { + free(e); + return; + } + + e->time = _ecore_wince_event_last_time; + + ecore_event_add(ECORE_WINCE_EVENT_WINDOW_DELETE_REQUEST, e, NULL, NULL); +} + +/*============================================================================* + * API * + *============================================================================*/ + diff --git a/src/lib/ecore_wince/ecore_wince_private.h b/src/lib/ecore_wince/ecore_wince_private.h new file mode 100644 index 0000000..b506312 --- /dev/null +++ b/src/lib/ecore_wince/ecore_wince_private.h @@ -0,0 +1,85 @@ +#ifndef __ECORE_WINCE_PRIVATE_H__ +#define __ECORE_WINCE_PRIVATE_H__ + + +/* logging messages macros */ +extern int _ecore_wince_log_dom_global; + +#ifdef ECORE_WINCE_DEFAULT_LOG_COLOR +#undef ECORE_WINCE_DEFAULT_LOG_COLOR +#endif +#define ECORE_WINCE_DEFAULT_LOG_COLOR EINA_COLOR_LIGHTBLUE + +#ifdef ERR +# undef ERR +#endif +#define ERR(...) EINA_LOG_DOM_ERR(_ecore_wince_log_dom_global , __VA_ARGS__) +#ifdef DBG +# undef DBG +#endif +#define DBG(...) EINA_LOG_DOM_DBG(_ecore_wince_log_dom_global , __VA_ARGS__) +#ifdef INF +# undef INF +#endif +#define INF(...) EINA_LOG_DOM_INFO(_ecore_wince_log_dom_global , __VA_ARGS__) + +#define ECORE_WINCE_WINDOW_CLASS L"Ecore_WinCE_Window_Class" + + +typedef struct _Ecore_WinCE_Callback_Data Ecore_WinCE_Callback_Data; + +struct _Ecore_WinCE_Callback_Data +{ + RECT update; + HWND window; + unsigned int message; + WPARAM window_param; + LPARAM data_param; + long time; + int x; + int y; +}; + + +typedef int (*ecore_wince_suspend_cb) (int); +typedef int (*ecore_wince_resume_cb) (int); + + +struct _Ecore_WinCE_Window +{ + HWND window; + + int backend; + ecore_wince_suspend_cb suspend_cb; + ecore_wince_resume_cb resume_cb; + + RECT rect; /* used to go fullscreen to normal */ + + unsigned int pointer_is_in : 1; + unsigned int fullscreen : 1; +}; + +extern HINSTANCE _ecore_wince_instance; +extern double _ecore_wince_double_click_time; +extern long _ecore_wince_event_last_time; +extern Ecore_WinCE_Window *_ecore_wince_event_last_window; + + +void _ecore_wince_event_handle_key_press(Ecore_WinCE_Callback_Data *msg, int is_keystroke); +void _ecore_wince_event_handle_key_release(Ecore_WinCE_Callback_Data *msg, int is_keystroke); +void _ecore_wince_event_handle_button_press(Ecore_WinCE_Callback_Data *msg, int button); +void _ecore_wince_event_handle_button_release(Ecore_WinCE_Callback_Data *msg, int button); +void _ecore_wince_event_handle_motion_notify(Ecore_WinCE_Callback_Data *msg); +void _ecore_wince_event_handle_enter_notify(Ecore_WinCE_Callback_Data *msg); +void _ecore_wince_event_handle_leave_notify(Ecore_WinCE_Callback_Data *msg); +void _ecore_wince_event_handle_focus_in(Ecore_WinCE_Callback_Data *msg); +void _ecore_wince_event_handle_focus_out(Ecore_WinCE_Callback_Data *msg); +void _ecore_wince_event_handle_expose(Ecore_WinCE_Callback_Data *msg); +void _ecore_wince_event_handle_create_notify(Ecore_WinCE_Callback_Data *msg); +void _ecore_wince_event_handle_destroy_notify(Ecore_WinCE_Callback_Data *msg); +void _ecore_wince_event_handle_map_notify(Ecore_WinCE_Callback_Data *msg); +void _ecore_wince_event_handle_unmap_notify(Ecore_WinCE_Callback_Data *msg); +void _ecore_wince_event_handle_delete_request(Ecore_WinCE_Callback_Data *msg); + + +#endif /* __ECORE_WINCE_PRIVATE_H__ */ diff --git a/src/lib/ecore_wince/ecore_wince_window.c b/src/lib/ecore_wince/ecore_wince_window.c new file mode 100644 index 0000000..49a6312 --- /dev/null +++ b/src/lib/ecore_wince/ecore_wince_window.c @@ -0,0 +1,827 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN + +#include +#include + +#include "Ecore_WinCE.h" +#include "ecore_wince_private.h" + +/*============================================================================* + * Local * + *============================================================================*/ + +/** + * @cond LOCAL + */ + + +typedef BOOL (__stdcall *UnregisterFunc1Proc)(UINT, UINT); + +static int +_ecore_wince_hardware_keys_register(HWND window) +{ + HINSTANCE core_dll; + UnregisterFunc1Proc unregister_fct; + int i; + + core_dll = LoadLibrary(L"coredll.dll"); + if (!core_dll) + { + ERR("LoadLibrary() failed"); + return 0; + } + + unregister_fct = (UnregisterFunc1Proc)GetProcAddress(core_dll, L"UnregisterFunc1"); + if (!unregister_fct) + { + ERR("GetProcAddress() failed"); + FreeLibrary(core_dll); + return 0; + } + + for (i = 0xc1; i <= 0xcf; i++) + { + unregister_fct(MOD_WIN, i); + RegisterHotKey(window, i, MOD_WIN, i); + } + + FreeLibrary(core_dll); + + return 1; +} + +/** + * @endcond + */ + + +/*============================================================================* + * Global * + *============================================================================*/ + +/*============================================================================* + * API * + *============================================================================*/ + +/** + * @addtogroup Ecore_WinCE_Group Ecore_WinCE library + * + * @{ + */ + +/** + * @brief Creates a new window. + * + * @param parent The parent window. + * @param x The x coordinate of the top-left corner of the window. + * @param y The y coordinate of the top-left corner of the window. + * @param width The width of the window. + * @param height The height of hte window. + * @return A newly allocated window. + * + * This function creates a new window which parent is @p parent. @p width and + * @p height are the size of the window content (the client part), + * without the border and title bar. @p x and @p y are the system + * coordinates of the top left cerner of the window (that is, of the + * title bar). This function returns a newly created window on + * success, and @c NULL on failure. + */ +EAPI Ecore_WinCE_Window * +ecore_wince_window_new(Ecore_WinCE_Window *parent, + int x, + int y, + int width, + int height) +{ + Ecore_WinCE_Window *w; + HWND window; + RECT rect; + + INF("creating window"); + + w = (Ecore_WinCE_Window *)calloc(1, sizeof(Ecore_WinCE_Window)); + if (!w) + { + ERR("malloc() failed"); + return NULL; + } + + rect.left = 0; + rect.top = 0; + rect.right = width; + rect.bottom = height; + if (!AdjustWindowRectEx(&rect, WS_CAPTION | WS_SYSMENU | WS_VISIBLE, FALSE, WS_EX_TOPMOST)) + { + ERR("AdjustWindowRectEx() failed"); + free(w); + return NULL; + } + + window = CreateWindowEx(WS_EX_TOPMOST, + ECORE_WINCE_WINDOW_CLASS, + L"", + WS_CAPTION | WS_SYSMENU | WS_VISIBLE, + x, y, + rect.right - rect.left, rect.bottom - rect.top, + parent ? ((Ecore_WinCE_Window *)parent)->window : NULL, + NULL, _ecore_wince_instance, NULL); + if (!window) + { + ERR("CreateWindowEx() failed"); + free(w); + return NULL; + } + + if (!_ecore_wince_hardware_keys_register(window)) + { + ERR("_ecore_wince_hardware_keys_register() failed"); + DestroyWindow(window); + free(w); + return NULL; + } + + w->window = window; + + SetLastError(0); + if (!SetWindowLong(window, GWL_USERDATA, (LONG)w) && (GetLastError() != 0)) + { + ERR("SetWindowLong() failed"); + DestroyWindow(window); + free(w); + return NULL; + } + + w->pointer_is_in = 0; + + return w; +} + +/** + * @brief Free the given window. + * + * @param window The window to free. + * + * This function frees @p window. If @p window is @c NULL, this + * function does nothing. + */ +EAPI void +ecore_wince_window_free(Ecore_WinCE_Window *window) +{ + if (!window) return; + + INF("destroying window"); + + DestroyWindow(window->window); + free(window); +} + +/** + * @brief Return the window HANDLE associated to the given window. + * + * @param window The window to retrieve the HANDLE from. + * + * This function returns the window HANDLE associated to @p window. If + * @p window is @c NULL, this function returns @c NULL. + */ +EAPI void * +ecore_wince_window_hwnd_get(Ecore_WinCE_Window *window) +{ + if (!window) + return NULL; + + return window->window; +} + +/** + * @brief Move the given window to a given position. + * + * @param window The window to move. + * @param x The x coordinate of the destination position. + * @param y The y coordinate of the destination position. + * + * This function move @p window to the new position of coordinates @p x + * and @p y. If @p window is @c NULL, or if it is fullscreen, or on + * error, this function does nothing. + */ +EAPI void +ecore_wince_window_move(Ecore_WinCE_Window *window, + int x, + int y) +{ + RECT rect; + + if (!window || window->fullscreen) + return; + + INF("moving window (%dx%d)", x, y); + + if (!GetWindowRect(window->window, &rect)) + { + ERR("GetWindowRect() failed"); + return; + } + + if (!MoveWindow(window->window, x, y, + rect.right - rect.left, + rect.bottom - rect.top, + TRUE)) + { + ERR("MoveWindow() failed"); + } +} + +/** + * @brief Resize the given window to a given size. + * + * @param window The window to resize. + * @param width The new width. + * @param height The new height. + * + * This function resize @p window to the new @p width and @p height. + * If @p window is @c NULL, or if it is fullscreen, or on error, this + * function does nothing. + */ +EAPI void +ecore_wince_window_resize(Ecore_WinCE_Window *window, + int width, + int height) +{ + RECT rect; + DWORD style; + DWORD exstyle; + int x; + int y; + + if (!window || window->fullscreen) + return; + + INF("resizing window (%dx%d)", width, height); + + if (!GetWindowRect(window->window, &rect)) + { + ERR("GetWindowRect() failed"); + return; + } + + x = rect.left; + y = rect.top; + rect.left = 0; + rect.top = 0; + rect.right = width; + rect.bottom = height; + if (!(style = GetWindowLong(window->window, GWL_STYLE))) + { + ERR("GetWindowLong() failed"); + return; + } + if (!(exstyle = GetWindowLong(window->window, GWL_EXSTYLE))) + { + ERR("GetWindowLong() failed"); + return; + } + if (!AdjustWindowRectEx(&rect, style, FALSE, exstyle)) + { + ERR("AdjustWindowRectEx() failed"); + return; + } + + if (!MoveWindow(window->window, x, y, + rect.right - rect.left, + rect.bottom - rect.top, + FALSE)) + { + ERR("MoveWindow() failed"); + } +} + +/** + * @brief Move and resize the given window to a given position and size. + * + * @param window The window to move and resize. + * @param x The x coordinate of the destination position. + * @param y The x coordinate of the destination position. + * @param width The new width. + * @param height The new height. + * + * This function resize @p window to the new position of coordinates @p x + * and @p y and the new @p width and @p height. If @p window is @c NULL, + * or if it is fullscreen, or on error, this function does nothing. + */ +EAPI void +ecore_wince_window_move_resize(Ecore_WinCE_Window *window, + int x, + int y, + int width, + int height) +{ + RECT rect; + DWORD style; + DWORD exstyle; + + if (!window || window->fullscreen) + return; + + INF("moving and resizing window (%dx%d %dx%d)", x, y, width, height); + + rect.left = 0; + rect.top = 0; + rect.right = width; + rect.bottom = height; + if (!(style = GetWindowLong(window->window, GWL_STYLE))) + { + ERR("GetWindowLong() failed"); + return; + } + if (!(exstyle = GetWindowLong(window->window, GWL_EXSTYLE))) + { + ERR("GetWindowLong() failed"); + return; + } + if (!AdjustWindowRectEx(&rect, style, FALSE, exstyle)) + { + ERR("AdjustWindowRectEx() failed"); + return; + } + + if (!MoveWindow(window->window, x, y, + rect.right - rect.left, + rect.bottom - rect.top, + TRUE)) + { + ERR("MoveWindow() failed"); + } +} + +/** + * @brief Show the given window. + * + * @param window The window to show. + * + * This function shows @p window. If @p window is @c NULL, or on + * error, this function does nothing. + */ +EAPI void +ecore_wince_window_show(Ecore_WinCE_Window *window) +{ + if (!window) return; + + INF("showing window"); + + if (!ShowWindow(window->window, SW_SHOWNORMAL)) + { + ERR("ShowWindow() failed"); + return; + } + if (!UpdateWindow(window->window)) + { + ERR("UpdateWindow() failed"); + } + if (!SendMessage(window->window, WM_SHOWWINDOW, 1, 0)) + { + ERR("SendMessage() failed"); + } +} + +/** + * @brief Hide the given window. + * + * @param window The window to show. + * + * This function hides @p window. If @p window is @c NULL, or on + * error, this function does nothing. + */ +EAPI void +ecore_wince_window_hide(Ecore_WinCE_Window *window) +{ + if (!window) return; + + INF("hiding window"); + + if (!ShowWindow(window->window, SW_HIDE)) + { + ERR("ShowWindow() failed"); + return; + } + if (!SendMessage(window->window, WM_SHOWWINDOW, 0, 0)) + { + ERR("SendMessage() failed"); + } +} + +/** + * @brief Set the title of the given window. + * + * @param window The window to set the title. + * @param title The new title. + * + * This function sets the title of @p window to @p title. If @p window + * is @c NULL, or if @p title is @c NULL or empty, or on error, this + * function does nothing. + */ +EAPI void +ecore_wince_window_title_set(Ecore_WinCE_Window *window, + const char *title) +{ + wchar_t *wtitle; + + if (!window) return; + + if (!title || !title[0]) return; + + INF("setting window title"); + + wtitle = evil_char_to_wchar(title); + if (!wtitle) return; + + if (!SetWindowText(window->window, wtitle)) + { + ERR("SetWindowText() failed"); + } + free(wtitle); +} + +/** + * @brief Set the focus to the given window. + * + * @param window The window to give focus to. + * + * This function gives the focus to @p window. If @p window is + * @c NULL, this function does nothing. + */ +EAPI void +ecore_wince_window_focus(Ecore_WinCE_Window *window) +{ + if (!window) return; + + INF("focusing window"); + + if (!SetFocus(window->window)) + { + ERR("SetFocus() failed"); + } +} + +/** + * @brief Get the current focused window. + * + * @return The window that has focus. + * + * This function returns the window that has focus. If the calling + * thread's message queue does not have an associated window with the + * keyboard focus, the return value is @c NULL. + * + * @note Even if the returned value is @c NULL, another thread's queue + * may be associated with a window that has the keyboard focus. + * + * @note The returned value is of type HWND. + */ +EAPI void * +ecore_wince_window_focus_get(void) +{ + HWND focused; + + INF("getting focused window"); + + focused = GetFocus(); + if (!focused) + { + ERR("GetFocus() failed"); + return NULL; + } + + return focused; +} + +/** + * @brief Set the graphic backend used for the given window. + * + * @param window The window. + * @param backend The backend. + * + * This function sets the graphic backend to use with @p window to + * @p backend. If @p window if @c NULL, this function does nothing. + * + * The valid values for @p backend are + * + * @li 0: automatic choice of the backend. + * @li 1: the framebuffer (fast but could be not well suported). + * @li 2: GAPI (less fast but almost always supported). + * @li 3: DirectDraw (less fast than GAPI but almost always + * supported). + * @li 4: GDI (the slowest but always supported). + * + * The @p backend is used only in Evas and Ecore_Evas. So this + * function should not be called if Ecore_Evas is used. + */ +EAPI void +ecore_wince_window_backend_set(Ecore_WinCE_Window *window, + int backend) +{ + if (!window) + return; + + INF("setting backend"); + + window->backend = backend; +} + +/** + * @brief Set the suspend callback used for the given window. + * + * @param window The window. + * @param suspend_cb The suspend callback. + * + * This function sets the suspend callback to use with @p window to + * @p suspend_cb. If @p window if @c NULL, this function does nothing. + * + * The @p suspend_cb is used only in Evas and Ecore_Evas. So this + * function should not be called if Ecore_Evas is used. + */ +EAPI void +ecore_wince_window_suspend_cb_set(Ecore_WinCE_Window *window, int (*suspend_cb)(int)) +{ + if (!window) + return; + + INF("setting suspend callback"); + + window->suspend_cb = suspend_cb; +} + +/** + * @brief Set the resume callback used for the given window. + * + * @param window The window. + * @param resume_cb The resume callback. + * + * This function sets the resume callback to use with @p window to + * @p resume_cb. If @p window if @c NULL, this function does nothing. + * + * The @p resume_cb is used only in Evas and Ecore_Evas. So this + * function should not be called if Ecore_Evas is used. + */ +EAPI void +ecore_wince_window_resume_cb_set(Ecore_WinCE_Window *window, int (*resume_cb)(int)) +{ + if (!window) + return; + + INF("setting resume callback"); + + window->resume_cb = resume_cb; +} + +/** + * @brief Get the geometry of the given window. + * + * @param window The window to retrieve the geometry from. + * @param x The x coordinate of the position. + * @param y The x coordinate of the position. + * @param width The width. + * @param height The height. + * + * This function retrieves the position and size of @p window. @p x, + * @p y, @p width and @p height can be buffers that will be filled with + * the corresponding values. If one of them is @c NULL, nothing will + * be done for that parameter. If @p window is @c NULL, and if the + * buffers are not @c NULL, they will be filled with respectively 0, + * 0, the size of the screen and the height of the screen. + */ +EAPI void +ecore_wince_window_geometry_get(Ecore_WinCE_Window *window, + int *x, + int *y, + int *width, + int *height) +{ + RECT rect; + int w; + int h; + + INF("getting window geometry"); + + if (!window) + { + if (x) *x = 0; + if (y) *y = 0; + if (width) *width = GetSystemMetrics(SM_CXSCREEN); + if (height) *height = GetSystemMetrics(SM_CYSCREEN); + + return; + } + + if (!GetClientRect(window->window, &rect)) + { + ERR("GetClientRect() failed"); + + if (x) *x = 0; + if (y) *y = 0; + if (width) *width = 0; + if (height) *height = 0; + + return; + } + + w = rect.right - rect.left; + h = rect.bottom - rect.top; + + if (!GetWindowRect(window->window, &rect)) + { + ERR("GetWindowRect() failed"); + + if (x) *x = 0; + if (y) *y = 0; + if (width) *width = 0; + if (height) *height = 0; + + return; + } + + if (x) *x = rect.left; + if (y) *y = rect.top; + if (width) *width = w; + if (height) *height = h; +} + +/** + * @brief Get the size of the given window. + * + * @param window The window to retrieve the size from. + * @param width The width. + * @param height The height. + * + * This function retrieves the size of @p window. @p width and + * @p height can be buffers that will be filled with the corresponding + * values. If one of them is @c NULL, nothing will be done for that + * parameter. If @p window is @c NULL, and if the buffers are not + * @c NULL, they will be filled with respectively the size of the screen + * and the height of the screen. + */ +EAPI void +ecore_wince_window_size_get(Ecore_WinCE_Window *window, + int *width, + int *height) +{ + RECT rect; + + INF("getting window size"); + + if (!window) + { + if (width) *width = GetSystemMetrics(SM_CXSCREEN); + if (height) *height = GetSystemMetrics(SM_CYSCREEN); + + return; + } + + if (!GetClientRect(window->window, &rect)) + { + ERR("GetClientRect() failed"); + + if (width) *width = 0; + if (height) *height = 0; + } + + if (width) *width = rect.right - rect.left; + if (height) *height = rect.bottom - rect.top; +} + +/** + * @brief Set the given window to fullscreen. + * + * @param window The window. + * @param on @c EINA_TRUE for fullscreen mode, @c EINA_FALSE for windowed mode. + * + * This function set @p window to fullscreen or windowed mode. If @p on is set + * to @c EINA_TRUE, the window will be fullscreen, if it is set to + * @c EINA_FALSE, it will be windowed. If @p window is @c NULL or if the state + * does not change (like setting to fullscreen while the window is already + * fullscreen), this function does nothing. + */ +EAPI void +ecore_wince_window_fullscreen_set(Ecore_WinCE_Window *window, + Eina_Bool on) +{ + HWND task_bar; + + if (!window) return; + + if (((window->fullscreen) && (on)) || + ((!window->fullscreen) && (!on))) + return; + + INF("setting fullscreen: %s", on ? "yes" : "no"); + + window->fullscreen = !!on; + + if (on) + { + /* save the position and size of the window */ + if (!GetWindowRect(window->window, &window->rect)) + { + ERR("GetWindowRect() failed"); + return; + } + + /* hide task bar */ + task_bar = FindWindow(L"HHTaskBar", NULL); + if (!task_bar) + { + INF("FindWindow(): can not find task bar"); + } + if (!ShowWindow(task_bar, SW_HIDE)) + { + INF("ShowWindow(): task bar already hidden"); + } + if (!EnableWindow(task_bar, FALSE)) + { + INF("EnableWindow(): input already disabled"); + } + + /* style: visible + popup */ + if (!SetWindowLong(window->window, GWL_STYLE, WS_POPUP | WS_VISIBLE)) + { + INF("SetWindowLong() failed"); + } + + /* resize window to fit the entire screen */ + if (!SetWindowPos(window->window, HWND_TOPMOST, + 0, 0, + GetSystemMetrics(SM_CXSCREEN), + GetSystemMetrics(SM_CYSCREEN), + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED)) + { + INF("SetWindowPos() failed"); + } + /* + * It seems that SetWindowPos is not sufficient. + * Call MoveWindow with the correct size and force painting. + * Note that UpdateWindow (forcing repainting) is not sufficient + */ + if (!MoveWindow(window->window, + 0, 0, + GetSystemMetrics(SM_CXSCREEN), + GetSystemMetrics(SM_CYSCREEN), + TRUE)) + { + INF("MoveWindow() failed"); + } + } + else + { + /* show task bar */ + task_bar = FindWindow(L"HHTaskBar", NULL); + if (!task_bar) + { + INF("FindWindow(): can not find task bar"); + } + if (!ShowWindow(task_bar, SW_SHOW)) + { + INF("ShowWindow(): task bar already visible"); + } + if (!EnableWindow(task_bar, TRUE)) + { + INF("EnableWindow(): input already enabled"); + } + + /* style: visible + caption + sysmenu */ + if (!SetWindowLong(window->window, GWL_STYLE, WS_CAPTION | WS_SYSMENU | WS_VISIBLE)) + { + INF("SetWindowLong() failed"); + } + /* restaure the position and size of the window */ + if (!SetWindowPos(window->window, HWND_TOPMOST, + window->rect.left, + window->rect.top, + window->rect.right - window->rect.left, + window->rect.bottom - window->rect.top, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED)) + { + INF("SetWindowLong() failed"); + } + /* + * It seems that SetWindowPos is not sufficient. + * Call MoveWindow with the correct size and force painting. + * Note that UpdateWindow (forcing repainting) is not sufficient + */ + if (!MoveWindow(window->window, + window->rect.left, + window->rect.top, + window->rect.right - window->rect.left, + window->rect.bottom - window->rect.top, + TRUE)) + { + INF("MoveWindow() failed"); + } + } +} + +/** + * @} + */ diff --git a/src/lib/ecore_x/Ecore_X.h b/src/lib/ecore_x/Ecore_X.h new file mode 100644 index 0000000..17cc0f4 --- /dev/null +++ b/src/lib/ecore_x/Ecore_X.h @@ -0,0 +1,2399 @@ +#ifndef _ECORE_X_H +#define _ECORE_X_H + +#include + +#ifdef EAPI +# undef EAPI +#endif // ifdef EAPI + +#ifdef _MSC_VER +# ifdef BUILDING_DLL +# define EAPI __declspec(dllexport) +# else // ifdef BUILDING_DLL +# define EAPI __declspec(dllimport) +# endif // ifdef BUILDING_DLL +#else // ifdef _MSC_VER +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else // if __GNUC__ >= 4 +# define EAPI +# endif // if __GNUC__ >= 4 +# else // ifdef __GNUC__ +# define EAPI +# endif // ifdef __GNUC__ +#endif // ifdef _MSC_VER + +#include + +/** + * @file + * @brief Ecore functions for dealing with the X Windows System + * + * Ecore_X provides a wrapper and convenience functions for using the + * X Windows System. Function groups for this part of the library + * include the following: + * @li @ref Ecore_X_Init_Group + * @li @ref Ecore_X_Display_Attr_Group + * @li @ref Ecore_X_Flush_Group + */ + +typedef unsigned int Ecore_X_ID; +#ifndef _ECORE_X_WINDOW_PREDEF +typedef Ecore_X_ID Ecore_X_Window; +#endif // ifndef _ECORE_X_WINDOW_PREDEF +typedef void *Ecore_X_Visual; +typedef Ecore_X_ID Ecore_X_Pixmap; +typedef Ecore_X_ID Ecore_X_Drawable; +#ifdef HAVE_ECORE_X_XCB +typedef Ecore_X_ID Ecore_X_GC; +#else // ifdef HAVE_ECORE_X_XCB +typedef void *Ecore_X_GC; +#endif /* HAVE_ECORE_X_XCB */ +typedef Ecore_X_ID Ecore_X_Atom; +typedef Ecore_X_ID Ecore_X_Colormap; +typedef Ecore_X_ID Ecore_X_Time; +typedef Ecore_X_ID Ecore_X_Cursor; +typedef void Ecore_X_Display; +typedef void Ecore_X_Connection; +typedef void Ecore_X_Screen; +typedef Ecore_X_ID Ecore_X_Sync_Counter; +typedef Ecore_X_ID Ecore_X_Sync_Alarm; +typedef void Ecore_X_XRegion; + +typedef Ecore_X_ID Ecore_X_Randr_Output; +typedef Ecore_X_ID Ecore_X_Randr_Crtc; +typedef Ecore_X_ID Ecore_X_Randr_Mode; +typedef unsigned short Ecore_X_Randr_Size_ID; +typedef int Ecore_X_Randr_Screen; + +typedef Ecore_X_ID Ecore_X_Device; + +#ifdef __cplusplus +extern "C" { +#endif // ifdef __cplusplus + +typedef struct _Ecore_X_Rectangle +{ + int x, y; + unsigned int width, height; +} Ecore_X_Rectangle; + +typedef struct _Ecore_X_Icon +{ + unsigned int width, height; + unsigned int *data; +} Ecore_X_Icon; + +typedef enum _Ecore_X_GC_Value_Mask +{ + ECORE_X_GC_VALUE_MASK_FUNCTION = (1L << 0), + ECORE_X_GC_VALUE_MASK_PLANE_MASK = (1L << 1), + ECORE_X_GC_VALUE_MASK_FOREGROUND = (1L << 2), + ECORE_X_GC_VALUE_MASK_BACKGROUND = (1L << 3), + ECORE_X_GC_VALUE_MASK_LINE_WIDTH = (1L << 4), + ECORE_X_GC_VALUE_MASK_LINE_STYLE = (1L << 5), + ECORE_X_GC_VALUE_MASK_CAP_STYLE = (1L << 6), + ECORE_X_GC_VALUE_MASK_JOIN_STYLE = (1L << 7), + ECORE_X_GC_VALUE_MASK_FILL_STYLE = (1L << 8), + ECORE_X_GC_VALUE_MASK_FILL_RULE = (1L << 9), + ECORE_X_GC_VALUE_MASK_TILE = (1L << 10), + ECORE_X_GC_VALUE_MASK_STIPPLE = (1L << 11), + ECORE_X_GC_VALUE_MASK_TILE_STIPPLE_ORIGIN_X = (1L << 12), + ECORE_X_GC_VALUE_MASK_TILE_STIPPLE_ORIGIN_Y = (1L << 13), + ECORE_X_GC_VALUE_MASK_FONT = (1L << 14), + ECORE_X_GC_VALUE_MASK_SUBWINDOW_MODE = (1L << 15), + ECORE_X_GC_VALUE_MASK_GRAPHICS_EXPOSURES = (1L << 16), + ECORE_X_GC_VALUE_MASK_CLIP_ORIGIN_X = (1L << 17), + ECORE_X_GC_VALUE_MASK_CLIP_ORIGIN_Y = (1L << 18), + ECORE_X_GC_VALUE_MASK_CLIP_MASK = (1L << 19), + ECORE_X_GC_VALUE_MASK_DASH_OFFSET = (1L << 20), + ECORE_X_GC_VALUE_MASK_DASH_LIST = (1L << 21), + ECORE_X_GC_VALUE_MASK_ARC_MODE = (1L << 22) +} Ecore_X_GC_Value_Mask; + +typedef enum _Ecore_X_Composite_Update_Type +{ + ECORE_X_COMPOSITE_UPDATE_AUTOMATIC, + ECORE_X_COMPOSITE_UPDATE_MANUAL +} Ecore_X_Composite_Update_Type; + +/** + * @typedef _Ecore_X_Window_State + * Defines the different states of the window of Ecore_X. + */ +typedef enum _Ecore_X_Window_State +{ + ECORE_X_WINDOW_STATE_UNKNOWN = 0, + ECORE_X_WINDOW_STATE_ICONIFIED, /** The window is iconified. */ + ECORE_X_WINDOW_STATE_MODAL, /** The window is a modal dialog box. */ + ECORE_X_WINDOW_STATE_STICKY, /** The window manager should keep the window's position fixed + * even if the virtual desktop scrolls. */ + ECORE_X_WINDOW_STATE_MAXIMIZED_VERT, /** The window has the maximum vertical size. */ + ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ, /** The window has the maximum horizontal size. */ + ECORE_X_WINDOW_STATE_SHADED, /** The window is shaded. */ + ECORE_X_WINDOW_STATE_SKIP_TASKBAR, /** The window should not be included in the taskbar. */ + ECORE_X_WINDOW_STATE_SKIP_PAGER, /** The window should not be included in the pager. */ + ECORE_X_WINDOW_STATE_HIDDEN, /** The window is invisible (i.e. minimized/iconified) */ + ECORE_X_WINDOW_STATE_FULLSCREEN, /** The window should fill the entire screen and have no + * window border/decorations */ + ECORE_X_WINDOW_STATE_ABOVE, + ECORE_X_WINDOW_STATE_BELOW, + ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION +} Ecore_X_Window_State; + +typedef enum _Ecore_X_Window_State_Action +{ + ECORE_X_WINDOW_STATE_ACTION_REMOVE, + ECORE_X_WINDOW_STATE_ACTION_ADD, + ECORE_X_WINDOW_STATE_ACTION_TOGGLE +} Ecore_X_Window_State_Action; + +typedef enum _Ecore_X_Window_Stack_Mode +{ + ECORE_X_WINDOW_STACK_ABOVE = 0, + ECORE_X_WINDOW_STACK_BELOW = 1, + ECORE_X_WINDOW_STACK_TOP_IF = 2, + ECORE_X_WINDOW_STACK_BOTTOM_IF = 3, + ECORE_X_WINDOW_STACK_OPPOSITE = 4 +} Ecore_X_Window_Stack_Mode; + +typedef enum _Ecore_X_Randr_Orientation +{ + ECORE_X_RANDR_ORIENTATION_ROT_0 = (1 << 0), + ECORE_X_RANDR_ORIENTATION_ROT_90 = (1 << 1), + ECORE_X_RANDR_ORIENTATION_ROT_180 = (1 << 2), + ECORE_X_RANDR_ORIENTATION_ROT_270 = (1 << 3), + ECORE_X_RANDR_ORIENTATION_FLIP_X = (1 << 4), + ECORE_X_RANDR_ORIENTATION_FLIP_Y = (1 << 5) +} Ecore_X_Randr_Orientation; + +typedef enum _Ecore_X_Randr_Connection_Status +{ + ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED = 0, + ECORE_X_RANDR_CONNECTION_STATUS_DISCONNECTED = 1, + ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN = 2 +} Ecore_X_Randr_Connection_Status; + +typedef enum _Ecore_X_Randr_Output_Policy +{ + ECORE_X_RANDR_OUTPUT_POLICY_ABOVE = 1, + ECORE_X_RANDR_OUTPUT_POLICY_RIGHT = 2, + ECORE_X_RANDR_OUTPUT_POLICY_BELOW = 3, + ECORE_X_RANDR_OUTPUT_POLICY_LEFT = 4, + ECORE_X_RANDR_OUTPUT_POLICY_CLONE = 5, + ECORE_X_RANDR_OUTPUT_POLICY_NONE = 6, + ECORE_X_RANDR_OUTPUT_POLICY_ASK = 7 +} Ecore_X_Randr_Output_Policy; + +typedef enum _Ecore_X_Randr_Relative_Alignment +{ + ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE = 0, + ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL = 1, + ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR = 2 +} Ecore_X_Randr_Relative_Alignment; + +typedef enum _Ecore_X_Render_Subpixel_Order +{ + ECORE_X_RENDER_SUBPIXEL_ORDER_UNKNOWN = 0, + ECORE_X_RENDER_SUBPIXEL_ORDER_HORIZONTAL_RGB = 1, + ECORE_X_RENDER_SUBPIXEL_ORDER_HORIZONTAL_BGR = 2, + ECORE_X_RENDER_SUBPIXEL_ORDER_VERTICAL_RGB = 3, + ECORE_X_RENDER_SUBPIXEL_ORDER_VERTICAL_BGR = 4, + ECORE_X_RENDER_SUBPIXEL_ORDER_NONE = 5 +} Ecore_X_Render_Subpixel_Order; + +typedef enum _Ecore_X_Randr_Edid_Display_Interface_Type +{ + ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_UNDEFINED, + ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_DVI, + ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_HDMI_A, + ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_HDMI_B, + ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_MDDI, + ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_DISPLAY_PORT +} Ecore_X_Randr_Edid_Display_Interface_Type; + +typedef enum _Ecore_X_Randr_Edid_Display_Colorscheme +{ + ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_MONOCHROME_GRAYSCALE = 0x00, + ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB = 0x08, + ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_NON_RGB = 0x10, + ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_UNDEFINED = 0x18, + ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_4_4_4 = 0x444000, + ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_YCRCB_4_4_4 = 0x444, + ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_YCRCB_4_2_2 = 0x422 +} Ecore_X_Randr_Edid_Display_Colorscheme; + +typedef enum _Ecore_X_Randr_Edid_Aspect_Ratio +{ + ECORE_X_RANDR_EDID_ASPECT_RATIO_4_3 = 0x0, + ECORE_X_RANDR_EDID_ASPECT_RATIO_16_9 = 0x1, + ECORE_X_RANDR_EDID_ASPECT_RATIO_16_10 = 0x2, + ECORE_X_RANDR_EDID_ASPECT_RATIO_5_4 = 0x4, + ECORE_X_RANDR_EDID_ASPECT_RATIO_15_9 = 0x8 +} Ecore_X_Randr_Edid_Aspect_Ratio; + +#define ECORE_X_RANDR_EDID_UNKNOWN_VALUE -1 + +#define ECORE_X_SELECTION_TARGET_TARGETS "TARGETS" +#define ECORE_X_SELECTION_TARGET_TEXT "TEXT" +#define ECORE_X_SELECTION_TARGET_COMPOUND_TEXT "COMPOUND_TEXT" +#define ECORE_X_SELECTION_TARGET_STRING "STRING" +#define ECORE_X_SELECTION_TARGET_UTF8_STRING "UTF8_STRING" +#define ECORE_X_SELECTION_TARGET_FILENAME "FILENAME" + +#define ECORE_X_DND_VERSION 5 + +typedef enum _Ecore_X_Selection +{ + ECORE_X_SELECTION_PRIMARY, + ECORE_X_SELECTION_SECONDARY, + ECORE_X_SELECTION_XDND, + ECORE_X_SELECTION_CLIPBOARD, + ECORE_X_SELECTION_OTHER +} Ecore_X_Selection; + +typedef enum _Ecore_X_Event_Mode +{ + ECORE_X_EVENT_MODE_NORMAL, + ECORE_X_EVENT_MODE_WHILE_GRABBED, + ECORE_X_EVENT_MODE_GRAB, + ECORE_X_EVENT_MODE_UNGRAB +} Ecore_X_Event_Mode; + +typedef enum _Ecore_X_Event_Detail +{ + ECORE_X_EVENT_DETAIL_ANCESTOR, + ECORE_X_EVENT_DETAIL_VIRTUAL, + ECORE_X_EVENT_DETAIL_INFERIOR, + ECORE_X_EVENT_DETAIL_NON_LINEAR, + ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL, + ECORE_X_EVENT_DETAIL_POINTER, + ECORE_X_EVENT_DETAIL_POINTER_ROOT, + ECORE_X_EVENT_DETAIL_DETAIL_NONE +} Ecore_X_Event_Detail; + +typedef enum _Ecore_X_Event_Mask +{ + ECORE_X_EVENT_MASK_NONE = 0L, + ECORE_X_EVENT_MASK_KEY_DOWN = (1L << 0), + ECORE_X_EVENT_MASK_KEY_UP = (1L << 1), + ECORE_X_EVENT_MASK_MOUSE_DOWN = (1L << 2), + ECORE_X_EVENT_MASK_MOUSE_UP = (1L << 3), + ECORE_X_EVENT_MASK_MOUSE_IN = (1L << 4), + ECORE_X_EVENT_MASK_MOUSE_OUT = (1L << 5), + ECORE_X_EVENT_MASK_MOUSE_MOVE = (1L << 6), + ECORE_X_EVENT_MASK_WINDOW_DAMAGE = (1L << 15), + ECORE_X_EVENT_MASK_WINDOW_VISIBILITY = (1L << 16), + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE = (1L << 17), + ECORE_X_EVENT_MASK_WINDOW_RESIZE_MANAGE = (1L << 18), + ECORE_X_EVENT_MASK_WINDOW_MANAGE = (1L << 19), + ECORE_X_EVENT_MASK_WINDOW_CHILD_CONFIGURE = (1L << 20), + ECORE_X_EVENT_MASK_WINDOW_FOCUS_CHANGE = (1L << 21), + ECORE_X_EVENT_MASK_WINDOW_PROPERTY = (1L << 22), + ECORE_X_EVENT_MASK_WINDOW_COLORMAP = (1L << 23), + ECORE_X_EVENT_MASK_WINDOW_GRAB = (1L << 24), + ECORE_X_EVENT_MASK_MOUSE_WHEEL = (1L << 29), + ECORE_X_EVENT_MASK_WINDOW_FOCUS_IN = (1L << 30), + ECORE_X_EVENT_MASK_WINDOW_FOCUS_OUT = (1L << 31) +} Ecore_X_Event_Mask; + +typedef enum _Ecore_X_Gravity +{ + ECORE_X_GRAVITY_FORGET = 0, + ECORE_X_GRAVITY_UNMAP = 0, + ECORE_X_GRAVITY_NW = 1, + ECORE_X_GRAVITY_N = 2, + ECORE_X_GRAVITY_NE = 3, + ECORE_X_GRAVITY_W = 4, + ECORE_X_GRAVITY_CENTER = 5, + ECORE_X_GRAVITY_E = 6, + ECORE_X_GRAVITY_SW = 7, + ECORE_X_GRAVITY_S = 8, + ECORE_X_GRAVITY_SE = 9, + ECORE_X_GRAVITY_STATIC = 10 +} Ecore_X_Gravity; + +/* Needed for ecore_x_region_window_shape_set */ +typedef enum _Ecore_X_Shape_Type +{ + ECORE_X_SHAPE_BOUNDING, + ECORE_X_SHAPE_CLIP, + ECORE_X_SHAPE_INPUT +} Ecore_X_Shape_Type; + +typedef enum _Ecore_X_Mapping_Type +{ + ECORE_X_MAPPING_MODIFIER, + ECORE_X_MAPPING_KEYBOARD, + ECORE_X_MAPPING_MOUSE +} Ecore_X_Mapping_Type; + +typedef enum _Ecore_X_Randr_Property_Change +{ + ECORE_X_RANDR_PROPERTY_CHANGE_ADD, + ECORE_X_RANDR_PROPERTY_CHANGE_DEL +} Ecore_X_Randr_Property_Change; + +typedef enum _Ecore_X_Netwm_Direction +{ + ECORE_X_NETWM_DIRECTION_SIZE_TL = 0, + ECORE_X_NETWM_DIRECTION_SIZE_T = 1, + ECORE_X_NETWM_DIRECTION_SIZE_TR = 2, + ECORE_X_NETWM_DIRECTION_SIZE_R = 3, + ECORE_X_NETWM_DIRECTION_SIZE_BR = 4, + ECORE_X_NETWM_DIRECTION_SIZE_B = 5, + ECORE_X_NETWM_DIRECTION_SIZE_BL = 6, + ECORE_X_NETWM_DIRECTION_SIZE_L = 7, + ECORE_X_NETWM_DIRECTION_MOVE = 8, + ECORE_X_NETWM_DIRECTION_CANCEL = 11, +} Ecore_X_Netwm_Direction; + +/** + * @typedef _Ecore_X_Error_Code + * Defines the error codes of Ecore_X which wraps the X Window Systems + * protocol's errors. + * + * @since 1.7.0 + */ +typedef enum _Ecore_X_Error_Code +{ + /** Everything is okay. */ + ECORE_X_ERROR_CODE_SUCCESS = 0, /** Bad request code */ + ECORE_X_ERROR_CODE_BAD_REQUEST = 1, /** Int parameter out of range */ + ECORE_X_ERROR_CODE_BAD_VALUE = 2, /** Parameter not a Window */ + ECORE_X_ERROR_CODE_BAD_WINDOW = 3, /** Parameter not a Pixmap */ + ECORE_X_ERROR_CODE_BAD_PIXMAP = 4, /** Parameter not an Atom */ + ECORE_X_ERROR_CODE_BAD_ATOM = 5, /** Parameter not a Cursor */ + ECORE_X_ERROR_CODE_BAD_CURSOR = 6, /** Parameter not a Font */ + ECORE_X_ERROR_CODE_BAD_FONT = 7, /** Parameter mismatch */ + ECORE_X_ERROR_CODE_BAD_MATCH = 8, /** Parameter not a Pixmap or Window */ + ECORE_X_ERROR_CODE_BAD_DRAWABLE = 9, /** Bad access */ + ECORE_X_ERROR_CODE_BAD_ACCESS = 10, /** Insufficient resources */ + ECORE_X_ERROR_CODE_BAD_ALLOC = 11, /** No such colormap */ + ECORE_X_ERROR_CODE_BAD_COLOR = 12, /** Parameter not a GC */ + ECORE_X_ERROR_CODE_BAD_GC = 13, /** Choice not in range or already used */ + ECORE_X_ERROR_CODE_BAD_ID_CHOICE = 14, /** Font or color name doesn't exist */ + ECORE_X_ERROR_CODE_BAD_NAME = 15, /** Request length incorrect */ + ECORE_X_ERROR_CODE_BAD_LENGTH = 16, /** Server is defective */ + ECORE_X_ERROR_CODE_BAD_IMPLEMENTATION = 17, +} Ecore_X_Error_Code; + +typedef struct _Ecore_X_Event_Mouse_In Ecore_X_Event_Mouse_In; +typedef struct _Ecore_X_Event_Mouse_Out Ecore_X_Event_Mouse_Out; +typedef struct _Ecore_X_Event_Window_Focus_In Ecore_X_Event_Window_Focus_In; +typedef struct _Ecore_X_Event_Window_Focus_Out Ecore_X_Event_Window_Focus_Out; +typedef struct _Ecore_X_Event_Window_Keymap Ecore_X_Event_Window_Keymap; +typedef struct _Ecore_X_Event_Window_Damage Ecore_X_Event_Window_Damage; +typedef struct _Ecore_X_Event_Window_Visibility_Change Ecore_X_Event_Window_Visibility_Change; +typedef struct _Ecore_X_Event_Window_Create Ecore_X_Event_Window_Create; +typedef struct _Ecore_X_Event_Window_Destroy Ecore_X_Event_Window_Destroy; +typedef struct _Ecore_X_Event_Window_Hide Ecore_X_Event_Window_Hide; +typedef struct _Ecore_X_Event_Window_Show Ecore_X_Event_Window_Show; +typedef struct _Ecore_X_Event_Window_Show_Request Ecore_X_Event_Window_Show_Request; +typedef struct _Ecore_X_Event_Window_Reparent Ecore_X_Event_Window_Reparent; +typedef struct _Ecore_X_Event_Window_Configure Ecore_X_Event_Window_Configure; +typedef struct _Ecore_X_Event_Window_Configure_Request Ecore_X_Event_Window_Configure_Request; +typedef struct _Ecore_X_Event_Window_Gravity Ecore_X_Event_Window_Gravity; +typedef struct _Ecore_X_Event_Window_Resize_Request Ecore_X_Event_Window_Resize_Request; +typedef struct _Ecore_X_Event_Window_Stack Ecore_X_Event_Window_Stack; +typedef struct _Ecore_X_Event_Window_Stack_Request Ecore_X_Event_Window_Stack_Request; +typedef struct _Ecore_X_Event_Window_Property Ecore_X_Event_Window_Property; +typedef struct _Ecore_X_Event_Window_Colormap Ecore_X_Event_Window_Colormap; +typedef struct _Ecore_X_Event_Mapping_Change Ecore_X_Event_Mapping_Change; +typedef struct _Ecore_X_Event_Window_Mapping Ecore_X_Event_Window_Mapping; +typedef struct _Ecore_X_Event_Selection_Clear Ecore_X_Event_Selection_Clear; +typedef struct _Ecore_X_Event_Selection_Request Ecore_X_Event_Selection_Request; +typedef struct _Ecore_X_Event_Selection_Notify Ecore_X_Event_Selection_Notify; +typedef struct _Ecore_X_Event_Fixes_Selection_Notify Ecore_X_Event_Fixes_Selection_Notify; +typedef struct _Ecore_X_Selection_Data Ecore_X_Selection_Data; +typedef struct _Ecore_X_Selection_Data_Files Ecore_X_Selection_Data_Files; +typedef struct _Ecore_X_Selection_Data_Text Ecore_X_Selection_Data_Text; +typedef struct _Ecore_X_Selection_Data_Targets Ecore_X_Selection_Data_Targets; +typedef struct _Ecore_X_Event_Xdnd_Enter Ecore_X_Event_Xdnd_Enter; +typedef struct _Ecore_X_Event_Xdnd_Position Ecore_X_Event_Xdnd_Position; +typedef struct _Ecore_X_Event_Xdnd_Status Ecore_X_Event_Xdnd_Status; +typedef struct _Ecore_X_Event_Xdnd_Leave Ecore_X_Event_Xdnd_Leave; +typedef struct _Ecore_X_Event_Xdnd_Drop Ecore_X_Event_Xdnd_Drop; +typedef struct _Ecore_X_Event_Xdnd_Finished Ecore_X_Event_Xdnd_Finished; +typedef struct _Ecore_X_Event_Client_Message Ecore_X_Event_Client_Message; +typedef struct _Ecore_X_Event_Window_Shape Ecore_X_Event_Window_Shape; +typedef struct _Ecore_X_Event_Screensaver_Notify Ecore_X_Event_Screensaver_Notify; +typedef struct _Ecore_X_Event_Gesture_Notify_Flick Ecore_X_Event_Gesture_Notify_Flick; +typedef struct _Ecore_X_Event_Gesture_Notify_Pan Ecore_X_Event_Gesture_Notify_Pan; +typedef struct _Ecore_X_Event_Gesture_Notify_PinchRotation Ecore_X_Event_Gesture_Notify_PinchRotation; +typedef struct _Ecore_X_Event_Gesture_Notify_Tap Ecore_X_Event_Gesture_Notify_Tap; +typedef struct _Ecore_X_Event_Gesture_Notify_TapNHold Ecore_X_Event_Gesture_Notify_TapNHold; +typedef struct _Ecore_X_Event_Gesture_Notify_Hold Ecore_X_Event_Gesture_Notify_Hold; +typedef struct _Ecore_X_Event_Gesture_Notify_Group Ecore_X_Event_Gesture_Notify_Group; +typedef struct _Ecore_X_Event_Sync_Counter Ecore_X_Event_Sync_Counter; +typedef struct _Ecore_X_Event_Sync_Alarm Ecore_X_Event_Sync_Alarm; +typedef struct _Ecore_X_Event_Screen_Change Ecore_X_Event_Screen_Change; +typedef struct _Ecore_X_Event_Randr_Crtc_Change Ecore_X_Event_Randr_Crtc_Change; +typedef struct _Ecore_X_Event_Randr_Output_Change Ecore_X_Event_Randr_Output_Change; +typedef struct _Ecore_X_Event_Randr_Output_Property_Notify Ecore_X_Event_Randr_Output_Property_Notify; + +typedef struct _Ecore_X_Event_Window_Delete_Request Ecore_X_Event_Window_Delete_Request; +typedef struct _Ecore_X_Event_Window_Move_Resize_Request Ecore_X_Event_Window_Move_Resize_Request; +typedef struct _Ecore_X_Event_Window_State_Request Ecore_X_Event_Window_State_Request; +typedef struct _Ecore_X_Event_Frame_Extents_Request Ecore_X_Event_Frame_Extents_Request; +typedef struct _Ecore_X_Event_Ping Ecore_X_Event_Ping; +typedef struct _Ecore_X_Event_Desktop_Change Ecore_X_Event_Desktop_Change; + +typedef struct _Ecore_X_Event_Startup_Sequence Ecore_X_Event_Startup_Sequence; + +typedef struct _Ecore_X_Event_Generic Ecore_X_Event_Generic; + +typedef struct _Ecore_X_Randr_Screen_Size Ecore_X_Randr_Screen_Size; +typedef struct _Ecore_X_Randr_Screen_Size_MM Ecore_X_Randr_Screen_Size_MM; + +typedef struct _Ecore_X_Xdnd_Position Ecore_X_Xdnd_Position; + +struct _Ecore_X_Event_Mouse_In +{ + int modifiers; + int x, y; + Eina_Bool same_screen : 1; + struct + { + int x, y; + } root; + Ecore_X_Window win; + Ecore_X_Window event_win; + Ecore_X_Window root_win; + Ecore_X_Event_Mode mode; + Ecore_X_Event_Detail detail; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Mouse_Out +{ + int modifiers; + int x, y; + int same_screen; + struct + { + int x, y; + } root; + Ecore_X_Window win; + Ecore_X_Window event_win; + Ecore_X_Window root_win; + Ecore_X_Event_Mode mode; + Ecore_X_Event_Detail detail; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Focus_In +{ + Ecore_X_Window win; + Ecore_X_Event_Mode mode; + Ecore_X_Event_Detail detail; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Focus_Out +{ + Ecore_X_Window win; + Ecore_X_Event_Mode mode; + Ecore_X_Event_Detail detail; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Keymap +{ + Ecore_X_Window win; +}; + +struct _Ecore_X_Event_Window_Damage +{ + Ecore_X_Window win; + int x, y, w, h; + int count; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Visibility_Change +{ + Ecore_X_Window win; + int fully_obscured; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Create +{ + Ecore_X_Window win; + Ecore_X_Window parent; + int override; + int x, y, w, h; + int border; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Destroy +{ + Ecore_X_Window win; + Ecore_X_Window event_win; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Hide +{ + Ecore_X_Window win; + Ecore_X_Window event_win; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Show +{ + Ecore_X_Window win; + Ecore_X_Window event_win; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Show_Request +{ + Ecore_X_Window win; + Ecore_X_Window parent; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Reparent +{ + Ecore_X_Window win; + Ecore_X_Window event_win; + Ecore_X_Window parent; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Configure +{ + Ecore_X_Window win; + Ecore_X_Window event_win; + Ecore_X_Window abovewin; + int x, y, w, h; + int border; + Eina_Bool override : 1; + Eina_Bool from_wm : 1; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Configure_Request +{ + Ecore_X_Window win; + Ecore_X_Window parent_win; + Ecore_X_Window abovewin; + int x, y, w, h; + int border; + Ecore_X_Window_Stack_Mode detail; + unsigned long value_mask; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Gravity +{ + Ecore_X_Window win; + Ecore_X_Window event_win; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Resize_Request +{ + Ecore_X_Window win; + int w, h; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Stack +{ + Ecore_X_Window win; + Ecore_X_Window event_win; + Ecore_X_Window_Stack_Mode detail; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Stack_Request +{ + Ecore_X_Window win; + Ecore_X_Window parent; + Ecore_X_Window_Stack_Mode detail; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Property +{ + Ecore_X_Window win; + Ecore_X_Atom atom; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Colormap +{ + Ecore_X_Window win; + Ecore_X_Colormap cmap; + Eina_Bool installed : 1; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Mapping_Change +{ + Ecore_X_Mapping_Type type; + int keycode; + int num; +}; + +struct _Ecore_X_Event_Selection_Clear +{ + Ecore_X_Window win; + Ecore_X_Selection selection; + Ecore_X_Atom atom; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Selection_Request +{ + Ecore_X_Window owner; + Ecore_X_Window requestor; + Ecore_X_Time time; + Ecore_X_Atom selection; + Ecore_X_Atom target; + Ecore_X_Atom property; +}; + +typedef enum +{ + ECORE_X_OWNER_CHANGE_REASON_NEW_OWNER, + ECORE_X_OWNER_CHANGE_REASON_DESTROY, + ECORE_X_OWNER_CHANGE_REASON_CLOSE +} Ecore_X_Owner_Change_Reason; + +struct _Ecore_X_Event_Fixes_Selection_Notify +{ + Ecore_X_Window win; + Ecore_X_Window owner; + Ecore_X_Time time; + Ecore_X_Time selection_time; + Ecore_X_Selection selection; + Ecore_X_Atom atom; + Ecore_X_Owner_Change_Reason reason; +}; + +struct _Ecore_X_Event_Selection_Notify +{ + Ecore_X_Window win; + Ecore_X_Time time; + Ecore_X_Selection selection; + Ecore_X_Atom atom; + char *target; + void *data; +}; + +struct _Ecore_X_Selection_Data +{ + enum + { + ECORE_X_SELECTION_CONTENT_NONE, + ECORE_X_SELECTION_CONTENT_TEXT, + ECORE_X_SELECTION_CONTENT_FILES, + ECORE_X_SELECTION_CONTENT_TARGETS, + ECORE_X_SELECTION_CONTENT_CUSTOM + } content; + unsigned char *data; + int length; + int format; + int (*free)(void *data); +}; + +struct _Ecore_X_Selection_Data_Files +{ + Ecore_X_Selection_Data data; + char **files; + int num_files; +}; + +struct _Ecore_X_Selection_Data_Text +{ + Ecore_X_Selection_Data data; + char *text; +}; + +struct _Ecore_X_Selection_Data_Targets +{ + Ecore_X_Selection_Data data; + char **targets; + int num_targets; +}; + +struct _Ecore_X_Event_Xdnd_Enter +{ + Ecore_X_Window win, source; + + char **types; + int num_types; +}; + +struct _Ecore_X_Event_Xdnd_Position +{ + Ecore_X_Window win, source; + struct + { + int x, y; + } position; + Ecore_X_Atom action; +}; + +struct _Ecore_X_Xdnd_Position +{ + Ecore_X_Window win, prev; + struct + { + int x, y; + } position; +}; + +struct _Ecore_X_Event_Xdnd_Status +{ + Ecore_X_Window win, target; + Eina_Bool will_accept : 1; + Ecore_X_Rectangle rectangle; + Ecore_X_Atom action; +}; + +struct _Ecore_X_Event_Xdnd_Leave +{ + Ecore_X_Window win, source; +}; + +struct _Ecore_X_Event_Xdnd_Drop +{ + Ecore_X_Window win, source; + Ecore_X_Atom action; + struct + { + int x, y; + } position; +}; + +struct _Ecore_X_Event_Xdnd_Finished +{ + Ecore_X_Window win, target; + Eina_Bool completed : 1; + Ecore_X_Atom action; +}; + +struct _Ecore_X_Event_Client_Message +{ + Ecore_X_Window win; + Ecore_X_Atom message_type; + int format; + union + { + char b[20]; + short s[10]; + long l[5]; + } data; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Shape +{ + Ecore_X_Window win; + Ecore_X_Time time; + Ecore_X_Shape_Type type; + int x, y, w, h; + Eina_Bool shaped : 1; +}; + +struct _Ecore_X_Event_Screensaver_Notify +{ + Ecore_X_Window win; + Eina_Bool on : 1; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Sync_Counter +{ + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Sync_Alarm +{ + Ecore_X_Time time; + Ecore_X_Sync_Alarm alarm; +}; + +struct _Ecore_X_Randr_Screen_Size +{ + int width, height; +}; + +struct _Ecore_X_Randr_Screen_Size_MM +{ + int width, height, width_mm, height_mm; +}; + +struct _Ecore_X_Event_Screen_Change +{ + Ecore_X_Window win; + Ecore_X_Window root; + Ecore_X_Randr_Screen_Size_MM size; /* in pixel and millimeters */ + Ecore_X_Time time; + Ecore_X_Time config_time; + Ecore_X_Randr_Orientation orientation; + Ecore_X_Render_Subpixel_Order subpixel_order; + Ecore_X_Randr_Size_ID size_id; +}; + +struct _Ecore_X_Event_Randr_Crtc_Change +{ + Ecore_X_Window win; + Ecore_X_Randr_Crtc crtc; + Ecore_X_Randr_Mode mode; + Ecore_X_Randr_Orientation orientation; + Eina_Rectangle geo; +}; + +struct _Ecore_X_Event_Randr_Output_Change +{ + Ecore_X_Window win; + Ecore_X_Randr_Output output; + Ecore_X_Randr_Crtc crtc; + Ecore_X_Randr_Mode mode; + Ecore_X_Randr_Orientation orientation; + Ecore_X_Randr_Connection_Status connection; + Ecore_X_Render_Subpixel_Order subpixel_order; +}; + +struct _Ecore_X_Event_Randr_Output_Property_Notify +{ + Ecore_X_Window win; + Ecore_X_Randr_Output output; + Ecore_X_Atom property; + Ecore_X_Time time; + Ecore_X_Randr_Property_Change state; +}; + +struct _Ecore_X_Event_Window_Delete_Request +{ + Ecore_X_Window win; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Prop_Title_Change +{ + Ecore_X_Window win; + char *title; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Prop_Visible_Title_Change +{ + Ecore_X_Window win; + char *title; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Prop_Icon_Name_Change +{ + Ecore_X_Window win; + char *name; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Prop_Visible_Icon_Name_Change +{ + Ecore_X_Window win; + char *name; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Prop_Client_Machine_Change +{ + Ecore_X_Window win; + char *name; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Prop_Name_Class_Change +{ + Ecore_X_Window win; + char *name; + char *clas; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Prop_Pid_Change +{ + Ecore_X_Window win; + pid_t pid; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Window_Prop_Desktop_Change +{ + Ecore_X_Window win; + long desktop; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Startup_Sequence +{ + Ecore_X_Window win; +}; + +struct _Ecore_X_Event_Window_Move_Resize_Request +{ + Ecore_X_Window win; + int x, y; + int direction; + int button; + int source; +}; + +struct _Ecore_X_Event_Window_State_Request +{ + Ecore_X_Window win; + Ecore_X_Window_State_Action action; + Ecore_X_Window_State state[2]; + int source; +}; + +struct _Ecore_X_Event_Frame_Extents_Request +{ + Ecore_X_Window win; +}; + +struct _Ecore_X_Event_Ping +{ + Ecore_X_Window win; + Ecore_X_Window event_win; + Ecore_X_Time time; +}; + +struct _Ecore_X_Event_Desktop_Change +{ + Ecore_X_Window win; + unsigned int desk; + int source; +}; + +struct _Ecore_X_Event_Generic +{ + int extension; + int evtype; + unsigned int cookie; + void *data; +}; + +EAPI extern int ECORE_X_EVENT_ANY; /**< low level event dependent on + backend in use, if Xlib will be XEvent, if XCB will be xcb_generic_event_t. + @warning avoid using it. + */ +EAPI extern int ECORE_X_EVENT_MOUSE_IN; +EAPI extern int ECORE_X_EVENT_MOUSE_OUT; +EAPI extern int ECORE_X_EVENT_WINDOW_FOCUS_IN; +EAPI extern int ECORE_X_EVENT_WINDOW_FOCUS_OUT; +EAPI extern int ECORE_X_EVENT_WINDOW_KEYMAP; +EAPI extern int ECORE_X_EVENT_WINDOW_DAMAGE; +EAPI extern int ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE; +EAPI extern int ECORE_X_EVENT_WINDOW_CREATE; +EAPI extern int ECORE_X_EVENT_WINDOW_DESTROY; +EAPI extern int ECORE_X_EVENT_WINDOW_HIDE; +EAPI extern int ECORE_X_EVENT_WINDOW_SHOW; +EAPI extern int ECORE_X_EVENT_WINDOW_SHOW_REQUEST; +EAPI extern int ECORE_X_EVENT_WINDOW_REPARENT; +EAPI extern int ECORE_X_EVENT_WINDOW_CONFIGURE; +EAPI extern int ECORE_X_EVENT_WINDOW_CONFIGURE_REQUEST; +EAPI extern int ECORE_X_EVENT_WINDOW_GRAVITY; +EAPI extern int ECORE_X_EVENT_WINDOW_RESIZE_REQUEST; +EAPI extern int ECORE_X_EVENT_WINDOW_STACK; +EAPI extern int ECORE_X_EVENT_WINDOW_STACK_REQUEST; +EAPI extern int ECORE_X_EVENT_WINDOW_PROPERTY; +EAPI extern int ECORE_X_EVENT_WINDOW_COLORMAP; +EAPI extern int ECORE_X_EVENT_WINDOW_MAPPING; +EAPI extern int ECORE_X_EVENT_MAPPING_CHANGE; +EAPI extern int ECORE_X_EVENT_SELECTION_CLEAR; +EAPI extern int ECORE_X_EVENT_SELECTION_REQUEST; +EAPI extern int ECORE_X_EVENT_SELECTION_NOTIFY; +EAPI extern int ECORE_X_EVENT_FIXES_SELECTION_NOTIFY; +EAPI extern int ECORE_X_EVENT_CLIENT_MESSAGE; +EAPI extern int ECORE_X_EVENT_WINDOW_SHAPE; +EAPI extern int ECORE_X_EVENT_SCREENSAVER_NOTIFY; +EAPI extern int ECORE_X_EVENT_GESTURE_NOTIFY_FLICK; +EAPI extern int ECORE_X_EVENT_GESTURE_NOTIFY_PAN; +EAPI extern int ECORE_X_EVENT_GESTURE_NOTIFY_PINCHROTATION; +EAPI extern int ECORE_X_EVENT_GESTURE_NOTIFY_TAP; +EAPI extern int ECORE_X_EVENT_GESTURE_NOTIFY_TAPNHOLD; +EAPI extern int ECORE_X_EVENT_GESTURE_NOTIFY_HOLD; +EAPI extern int ECORE_X_EVENT_GESTURE_NOTIFY_GROUP; +EAPI extern int ECORE_X_EVENT_SYNC_COUNTER; +EAPI extern int ECORE_X_EVENT_SYNC_ALARM; +EAPI extern int ECORE_X_EVENT_SCREEN_CHANGE; +EAPI extern int ECORE_X_EVENT_RANDR_CRTC_CHANGE; +EAPI extern int ECORE_X_EVENT_RANDR_OUTPUT_CHANGE; +EAPI extern int ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY; +EAPI extern int ECORE_X_EVENT_DAMAGE_NOTIFY; + +EAPI extern int ECORE_X_EVENT_WINDOW_DELETE_REQUEST; + +EAPI extern int ECORE_X_EVENT_WINDOW_MOVE_RESIZE_REQUEST; +EAPI extern int ECORE_X_EVENT_WINDOW_STATE_REQUEST; +EAPI extern int ECORE_X_EVENT_FRAME_EXTENTS_REQUEST; +EAPI extern int ECORE_X_EVENT_PING; +EAPI extern int ECORE_X_EVENT_DESKTOP_CHANGE; + +EAPI extern int ECORE_X_EVENT_STARTUP_SEQUENCE_NEW; +EAPI extern int ECORE_X_EVENT_STARTUP_SEQUENCE_CHANGE; +EAPI extern int ECORE_X_EVENT_STARTUP_SEQUENCE_REMOVE; +EAPI extern int ECORE_X_EVENT_XKB_STATE_NOTIFY; /** @since 1.7 */ +EAPI extern int ECORE_X_EVENT_XKB_NEWKBD_NOTIFY; /** @since 1.7 */ + +EAPI extern int ECORE_X_EVENT_GENERIC; + +EAPI extern int ECORE_X_EVENT_XDND_ENTER; +EAPI extern int ECORE_X_EVENT_XDND_POSITION; +EAPI extern int ECORE_X_EVENT_XDND_STATUS; +EAPI extern int ECORE_X_EVENT_XDND_LEAVE; +EAPI extern int ECORE_X_EVENT_XDND_DROP; +EAPI extern int ECORE_X_EVENT_XDND_FINISHED; + +EAPI extern int ECORE_X_MODIFIER_SHIFT; /**< @since 1.7 */ +EAPI extern int ECORE_X_MODIFIER_CTRL; /**< @since 1.7 */ +EAPI extern int ECORE_X_MODIFIER_ALT; /**< @since 1.7 */ +EAPI extern int ECORE_X_MODIFIER_WIN; /**< @since 1.7 */ +EAPI extern int ECORE_X_MODIFIER_ALTGR; /**< @since 1.7 */ + +EAPI extern int ECORE_X_LOCK_SCROLL; +EAPI extern int ECORE_X_LOCK_NUM; +EAPI extern int ECORE_X_LOCK_CAPS; +EAPI extern int ECORE_X_LOCK_SHIFT; + +typedef enum _Ecore_X_WM_Protocol +{ + /** If enabled the window manager will be asked to send a + * delete message instead of just closing (destroying) the window. */ + ECORE_X_WM_PROTOCOL_DELETE_REQUEST, + + /** If enabled the window manager will be told that the window + * explicitly sets input focus. */ + ECORE_X_WM_PROTOCOL_TAKE_FOCUS, + + /** If enabled the window manager can ping the window to check + * if it is alive. */ + ECORE_X_NET_WM_PROTOCOL_PING, + + /** If enabled the window manager can sync updating with the + * window (?) */ + ECORE_X_NET_WM_PROTOCOL_SYNC_REQUEST, + + /** Number of defined items */ + ECORE_X_WM_PROTOCOL_NUM +} Ecore_X_WM_Protocol; + +typedef enum _Ecore_X_Window_Input_Mode +{ + /** The window can never be focused */ + ECORE_X_WINDOW_INPUT_MODE_NONE, + + /** The window can be focused by the WM but doesn't focus itself */ + ECORE_X_WINDOW_INPUT_MODE_PASSIVE, + + /** The window sets the focus itself if one of its sub-windows + * already is focused */ + ECORE_X_WINDOW_INPUT_MODE_ACTIVE_LOCAL, + + /** The window sets the focus itself even if another window + * is currently focused */ + ECORE_X_WINDOW_INPUT_MODE_ACTIVE_GLOBAL +} Ecore_X_Window_Input_Mode; + +/** + * @typedef _Ecore_X_Window_State_Hint + * Defines the different state hint of the window of Ecore_X. + */ +typedef enum _Ecore_X_Window_State_Hint +{ + /** Do not provide any state hint to the window manager */ + ECORE_X_WINDOW_STATE_HINT_NONE = -1, + + /** The window wants to remain hidden and NOT iconified */ + ECORE_X_WINDOW_STATE_HINT_WITHDRAWN, + + /** The window wants to be mapped normally */ + ECORE_X_WINDOW_STATE_HINT_NORMAL, + + /** The window wants to start in an iconified state */ + ECORE_X_WINDOW_STATE_HINT_ICONIC +} Ecore_X_Window_State_Hint; + +typedef enum _Ecore_X_Window_Type +{ + ECORE_X_WINDOW_TYPE_UNKNOWN = 0, + ECORE_X_WINDOW_TYPE_DESKTOP, + ECORE_X_WINDOW_TYPE_DOCK, + ECORE_X_WINDOW_TYPE_TOOLBAR, + ECORE_X_WINDOW_TYPE_MENU, + ECORE_X_WINDOW_TYPE_UTILITY, + ECORE_X_WINDOW_TYPE_SPLASH, + ECORE_X_WINDOW_TYPE_DIALOG, + ECORE_X_WINDOW_TYPE_NORMAL, + ECORE_X_WINDOW_TYPE_DROPDOWN_MENU, + ECORE_X_WINDOW_TYPE_POPUP_MENU, + ECORE_X_WINDOW_TYPE_TOOLTIP, + ECORE_X_WINDOW_TYPE_NOTIFICATION, + ECORE_X_WINDOW_TYPE_COMBO, + ECORE_X_WINDOW_TYPE_DND +} Ecore_X_Window_Type; + +typedef enum _Ecore_X_Action +{ + ECORE_X_ACTION_MOVE, + ECORE_X_ACTION_RESIZE, + ECORE_X_ACTION_MINIMIZE, + ECORE_X_ACTION_SHADE, + ECORE_X_ACTION_STICK, + ECORE_X_ACTION_MAXIMIZE_HORZ, + ECORE_X_ACTION_MAXIMIZE_VERT, + ECORE_X_ACTION_FULLSCREEN, + ECORE_X_ACTION_CHANGE_DESKTOP, + ECORE_X_ACTION_CLOSE, + ECORE_X_ACTION_ABOVE, + ECORE_X_ACTION_BELOW +} Ecore_X_Action; + +typedef enum _Ecore_X_Window_Configure_Mask +{ + ECORE_X_WINDOW_CONFIGURE_MASK_X = (1 << 0), + ECORE_X_WINDOW_CONFIGURE_MASK_Y = (1 << 1), + ECORE_X_WINDOW_CONFIGURE_MASK_W = (1 << 2), + ECORE_X_WINDOW_CONFIGURE_MASK_H = (1 << 3), + ECORE_X_WINDOW_CONFIGURE_MASK_BORDER_WIDTH = (1 << 4), + ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING = (1 << 5), + ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE = (1 << 6) +} Ecore_X_Window_Configure_Mask; + +typedef enum _Ecore_X_Virtual_Keyboard_State +{ + ECORE_X_VIRTUAL_KEYBOARD_STATE_UNKNOWN = 0, + ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF, + ECORE_X_VIRTUAL_KEYBOARD_STATE_ON, + ECORE_X_VIRTUAL_KEYBOARD_STATE_ALPHA, + ECORE_X_VIRTUAL_KEYBOARD_STATE_NUMERIC, + ECORE_X_VIRTUAL_KEYBOARD_STATE_PIN, + ECORE_X_VIRTUAL_KEYBOARD_STATE_PHONE_NUMBER, + ECORE_X_VIRTUAL_KEYBOARD_STATE_HEX, + ECORE_X_VIRTUAL_KEYBOARD_STATE_TERMINAL, + ECORE_X_VIRTUAL_KEYBOARD_STATE_PASSWORD, + ECORE_X_VIRTUAL_KEYBOARD_STATE_IP, + ECORE_X_VIRTUAL_KEYBOARD_STATE_HOST, + ECORE_X_VIRTUAL_KEYBOARD_STATE_FILE, + ECORE_X_VIRTUAL_KEYBOARD_STATE_URL, + ECORE_X_VIRTUAL_KEYBOARD_STATE_KEYPAD, + ECORE_X_VIRTUAL_KEYBOARD_STATE_J2ME +} Ecore_X_Virtual_Keyboard_State; + +typedef enum _Ecore_X_Illume_Mode +{ + ECORE_X_ILLUME_MODE_UNKNOWN = 0, + ECORE_X_ILLUME_MODE_SINGLE, + ECORE_X_ILLUME_MODE_DUAL_TOP, + ECORE_X_ILLUME_MODE_DUAL_LEFT +} Ecore_X_Illume_Mode; + +typedef enum _Ecore_X_Illume_Quickpanel_State +{ + ECORE_X_ILLUME_QUICKPANEL_STATE_UNKNOWN = 0, + ECORE_X_ILLUME_QUICKPANEL_STATE_OFF, + ECORE_X_ILLUME_QUICKPANEL_STATE_ON +} Ecore_X_Illume_Quickpanel_State; + +typedef enum _Ecore_X_Illume_Indicator_State +{ + ECORE_X_ILLUME_INDICATOR_STATE_UNKNOWN = 0, + ECORE_X_ILLUME_INDICATOR_STATE_OFF, + ECORE_X_ILLUME_INDICATOR_STATE_ON +} Ecore_X_Illume_Indicator_State; + +typedef enum _Ecore_X_Illume_Clipboard_State +{ + ECORE_X_ILLUME_CLIPBOARD_STATE_UNKNOWN = 0, + ECORE_X_ILLUME_CLIPBOARD_STATE_OFF, + ECORE_X_ILLUME_CLIPBOARD_STATE_ON +} Ecore_X_Illume_Clipboard_State; + +typedef enum _Ecore_X_Illume_Indicator_Opacity_Mode +{ + ECORE_X_ILLUME_INDICATOR_OPACITY_UNKNOWN = 0, + ECORE_X_ILLUME_INDICATOR_OPAQUE, + ECORE_X_ILLUME_INDICATOR_TRANSLUCENT, + ECORE_X_ILLUME_INDICATOR_TRANSPARENT +} Ecore_X_Illume_Indicator_Opacity_Mode; + +typedef enum _Ecore_X_Illume_Window_State +{ + ECORE_X_ILLUME_WINDOW_STATE_NORMAL = 0, + ECORE_X_ILLUME_WINDOW_STATE_FLOATING +} Ecore_X_Illume_Window_State; + +/* Window layer constants */ +#define ECORE_X_WINDOW_LAYER_BELOW 2 +#define ECORE_X_WINDOW_LAYER_NORMAL 4 +#define ECORE_X_WINDOW_LAYER_ABOVE 6 + +/* Property list operations */ +#define ECORE_X_PROP_LIST_REMOVE 0 +#define ECORE_X_PROP_LIST_ADD 1 +#define ECORE_X_PROP_LIST_TOGGLE 2 + +EAPI int ecore_x_init(const char *name); +EAPI int ecore_x_shutdown(void); +EAPI int ecore_x_disconnect(void); +EAPI Ecore_X_Display *ecore_x_display_get(void); +EAPI Ecore_X_Connection *ecore_x_connection_get(void); +EAPI int ecore_x_fd_get(void); +EAPI Ecore_X_Screen *ecore_x_default_screen_get(void); +EAPI void ecore_x_screen_size_get(const Ecore_X_Screen *screen, int *w, int *h); +EAPI int ecore_x_screen_count_get(void); +EAPI int ecore_x_screen_index_get(const Ecore_X_Screen *screen); +EAPI Ecore_X_Screen *ecore_x_screen_get(int index); + +EAPI void ecore_x_double_click_time_set(double t); +EAPI double ecore_x_double_click_time_get(void); +EAPI void ecore_x_flush(void); +EAPI void ecore_x_sync(void); +EAPI void ecore_x_killall(Ecore_X_Window root); +EAPI void ecore_x_kill(Ecore_X_Window win); +EAPI int ecore_x_dpi_get(void); +EAPI Eina_Bool ecore_x_bell(int percent); +EAPI unsigned int ecore_x_visual_id_get(Ecore_X_Visual visual); + +EAPI Ecore_X_Visual ecore_x_default_visual_get(Ecore_X_Display *disp, Ecore_X_Screen *screen); +EAPI Ecore_X_Colormap ecore_x_default_colormap_get(Ecore_X_Display *disp, Ecore_X_Screen *screen); +EAPI int ecore_x_default_depth_get(Ecore_X_Display *disp, Ecore_X_Screen *screen); + +EAPI Ecore_X_Time ecore_x_current_time_get(void); + +EAPI void ecore_x_error_handler_set(void (*func)(void *data), const void *data); +EAPI void ecore_x_io_error_handler_set(void (*func)(void *data), const void *data); +EAPI int ecore_x_error_request_get(void); +EAPI int ecore_x_error_code_get(void); +EAPI Ecore_X_ID ecore_x_error_resource_id_get(void); + +EAPI void ecore_x_event_mask_set(Ecore_X_Window w, Ecore_X_Event_Mask mask); +EAPI void ecore_x_event_mask_unset(Ecore_X_Window w, Ecore_X_Event_Mask mask); + +EAPI Eina_Bool ecore_x_selection_notify_send(Ecore_X_Window requestor, Ecore_X_Atom selection, Ecore_X_Atom target, Ecore_X_Atom property, Ecore_X_Time time); +EAPI Eina_Bool ecore_x_selection_primary_set(Ecore_X_Window w, const void *data, int size); +EAPI Eina_Bool ecore_x_selection_primary_clear(void); +EAPI Eina_Bool ecore_x_selection_secondary_set(Ecore_X_Window w, const void *data, int size); +EAPI Eina_Bool ecore_x_selection_secondary_clear(void); +EAPI Eina_Bool ecore_x_selection_xdnd_set(Ecore_X_Window w, const void *data, int size); +EAPI Eina_Bool ecore_x_selection_xdnd_clear(void); +EAPI Eina_Bool ecore_x_selection_clipboard_set(Ecore_X_Window w, const void *data, int size); +EAPI Eina_Bool ecore_x_selection_clipboard_clear(void); +EAPI void ecore_x_selection_primary_request(Ecore_X_Window w, const char *target); +EAPI void ecore_x_selection_secondary_request(Ecore_X_Window w, const char *target); +EAPI void ecore_x_selection_xdnd_request(Ecore_X_Window w, const char *target); +EAPI void ecore_x_selection_clipboard_request(Ecore_X_Window w, const char *target); +EAPI Eina_Bool ecore_x_selection_convert(Ecore_X_Atom selection, Ecore_X_Atom target, void **data_ret, int *len, Ecore_X_Atom *targprop, int *targsize); +EAPI void ecore_x_selection_converter_add(char *target, Eina_Bool (*func)(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *, int *)); +EAPI void ecore_x_selection_converter_atom_add(Ecore_X_Atom target, Eina_Bool (*func)(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *tprop, int *tsize)); +EAPI void ecore_x_selection_converter_del(char *target); +EAPI void ecore_x_selection_converter_atom_del(Ecore_X_Atom target); +EAPI void ecore_x_selection_parser_add(const char *target, void *(*func)(const char *target, void *data, int size, int format)); +EAPI void ecore_x_selection_parser_del(const char *target); +EAPI void ecore_x_selection_owner_set(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Time tm); +EAPI Ecore_X_Window ecore_x_selection_owner_get(Ecore_X_Atom atom); + +EAPI void ecore_x_dnd_aware_set(Ecore_X_Window win, Eina_Bool on); +EAPI int ecore_x_dnd_version_get(Ecore_X_Window win); +EAPI Eina_Bool ecore_x_dnd_type_isset(Ecore_X_Window win, const char *type); +EAPI void ecore_x_dnd_type_set(Ecore_X_Window win, const char *type, Eina_Bool on); +EAPI void ecore_x_dnd_types_set(Ecore_X_Window win, const char **types, unsigned int num_types); +EAPI void ecore_x_dnd_actions_set(Ecore_X_Window win, Ecore_X_Atom *actions, unsigned int num_actions); +EAPI Eina_Bool ecore_x_dnd_begin(Ecore_X_Window source, unsigned char *data, int size); +EAPI Eina_Bool ecore_x_dnd_drop(void); +EAPI void ecore_x_dnd_send_status(Eina_Bool will_accept, Eina_Bool suppress, Ecore_X_Rectangle rectangle, Ecore_X_Atom action); +EAPI void ecore_x_dnd_send_finished(void); +EAPI void ecore_x_dnd_source_action_set(Ecore_X_Atom action); +EAPI Ecore_X_Atom ecore_x_dnd_source_action_get(void); +EAPI void ecore_x_dnd_callback_pos_update_set(void (*cb)(void *, Ecore_X_Xdnd_Position *data), const void *data); + +EAPI Ecore_X_Window ecore_x_window_new(Ecore_X_Window parent, int x, int y, int w, int h); +EAPI Ecore_X_Window ecore_x_window_override_new(Ecore_X_Window parent, int x, int y, int w, int h); +EAPI int ecore_x_window_argb_get(Ecore_X_Window win); +EAPI Ecore_X_Window ecore_x_window_manager_argb_new(Ecore_X_Window parent, int x, int y, int w, int h); +EAPI Ecore_X_Window ecore_x_window_argb_new(Ecore_X_Window parent, int x, int y, int w, int h); +EAPI Ecore_X_Window ecore_x_window_override_argb_new(Ecore_X_Window parent, int x, int y, int w, int h); +EAPI Ecore_X_Window ecore_x_window_input_new(Ecore_X_Window parent, int x, int y, int w, int h); +EAPI void ecore_x_window_configure(Ecore_X_Window win, Ecore_X_Window_Configure_Mask mask, int x, int y, int w, int h, int border_width, Ecore_X_Window sibling, int stack_mode); +EAPI void ecore_x_window_cursor_set(Ecore_X_Window win, Ecore_X_Cursor c); +EAPI void ecore_x_window_free(Ecore_X_Window win); +EAPI void ecore_x_window_ignore_set(Ecore_X_Window win, int ignore); +EAPI Ecore_X_Window *ecore_x_window_ignore_list(int *num); + +EAPI void ecore_x_window_delete_request_send(Ecore_X_Window win); +EAPI void ecore_x_window_show(Ecore_X_Window win); +EAPI void ecore_x_window_hide(Ecore_X_Window win); +EAPI void ecore_x_window_move(Ecore_X_Window win, int x, int y); +EAPI void ecore_x_window_resize(Ecore_X_Window win, int w, int h); +EAPI void ecore_x_window_move_resize(Ecore_X_Window win, int x, int y, int w, int h); +EAPI void ecore_x_window_focus(Ecore_X_Window win); +EAPI void ecore_x_window_focus_at_time(Ecore_X_Window win, Ecore_X_Time t); +EAPI Ecore_X_Window ecore_x_window_focus_get(void); +EAPI void ecore_x_window_raise(Ecore_X_Window win); +EAPI void ecore_x_window_lower(Ecore_X_Window win); +EAPI void ecore_x_window_reparent(Ecore_X_Window win, Ecore_X_Window new_parent, int x, int y); +EAPI void ecore_x_window_size_get(Ecore_X_Window win, int *w, int *h); +EAPI void ecore_x_window_geometry_get(Ecore_X_Window win, int *x, int *y, int *w, int *h); +EAPI int ecore_x_window_border_width_get(Ecore_X_Window win); +EAPI void ecore_x_window_border_width_set(Ecore_X_Window win, int width); +EAPI int ecore_x_window_depth_get(Ecore_X_Window win); +EAPI void ecore_x_window_cursor_show(Ecore_X_Window win, Eina_Bool show); +EAPI void ecore_x_window_defaults_set(Ecore_X_Window win); +EAPI int ecore_x_window_visible_get(Ecore_X_Window win); +EAPI Ecore_X_Window ecore_x_window_shadow_tree_at_xy_with_skip_get(Ecore_X_Window base, int x, int y, Ecore_X_Window *skip, int skip_num); +EAPI Ecore_X_Window ecore_x_window_shadow_parent_get(Ecore_X_Window root, Ecore_X_Window win); +EAPI void ecore_x_window_shadow_tree_flush(void); +EAPI Ecore_X_Window ecore_x_window_root_get(Ecore_X_Window win); +EAPI Ecore_X_Window ecore_x_window_at_xy_get(int x, int y); +EAPI Ecore_X_Window ecore_x_window_at_xy_with_skip_get(int x, int y, Ecore_X_Window *skip, int skip_num); +EAPI Ecore_X_Window ecore_x_window_at_xy_begin_get(Ecore_X_Window begin, int x, int y); +EAPI Ecore_X_Window ecore_x_window_parent_get(Ecore_X_Window win); + +EAPI void ecore_x_window_background_color_set(Ecore_X_Window win, unsigned short r, unsigned short g, unsigned short b); +EAPI void ecore_x_window_gravity_set(Ecore_X_Window win, Ecore_X_Gravity grav); +EAPI void ecore_x_window_pixel_gravity_set(Ecore_X_Window win, Ecore_X_Gravity grav); +EAPI void ecore_x_window_pixmap_set(Ecore_X_Window win, Ecore_X_Pixmap pmap); +EAPI void ecore_x_window_area_clear(Ecore_X_Window win, int x, int y, int w, int h); +EAPI void ecore_x_window_area_expose(Ecore_X_Window win, int x, int y, int w, int h); +EAPI void ecore_x_window_override_set(Ecore_X_Window win, Eina_Bool override); + +EAPI void ecore_x_window_prop_card32_set(Ecore_X_Window win, Ecore_X_Atom atom, unsigned int *val, unsigned int num); +EAPI int ecore_x_window_prop_card32_get(Ecore_X_Window win, Ecore_X_Atom atom, unsigned int *val, unsigned int len); +EAPI int ecore_x_window_prop_card32_list_get(Ecore_X_Window win, Ecore_X_Atom atom, unsigned int **plst); + +EAPI void ecore_x_window_prop_xid_set(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Atom type, Ecore_X_ID *lst, unsigned int num); +EAPI int ecore_x_window_prop_xid_get(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Atom type, Ecore_X_ID *lst, unsigned int len); +EAPI int ecore_x_window_prop_xid_list_get(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Atom type, Ecore_X_ID **plst); +EAPI void ecore_x_window_prop_xid_list_change(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Atom type, Ecore_X_ID item, int op); +EAPI void ecore_x_window_prop_atom_set(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Atom *val, unsigned int num); +EAPI int ecore_x_window_prop_atom_get(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Atom *val, unsigned int len); +EAPI int ecore_x_window_prop_atom_list_get(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Atom **plst); +EAPI void ecore_x_window_prop_atom_list_change(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Atom item, int op); +EAPI void ecore_x_window_prop_window_set(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Window *val, unsigned int num); +EAPI int ecore_x_window_prop_window_get(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Window *val, unsigned int len); +EAPI int ecore_x_window_prop_window_list_get(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Window **plst); + +EAPI Ecore_X_Atom ecore_x_window_prop_any_type(void); +EAPI void ecore_x_window_prop_property_set(Ecore_X_Window win, Ecore_X_Atom type, Ecore_X_Atom format, int size, void *data, int number); +EAPI int ecore_x_window_prop_property_get(Ecore_X_Window win, Ecore_X_Atom property, Ecore_X_Atom type, int size, unsigned char **data, int *num); +EAPI void ecore_x_window_prop_property_del(Ecore_X_Window win, Ecore_X_Atom property); +EAPI Ecore_X_Atom *ecore_x_window_prop_list(Ecore_X_Window win, int *num_ret); +EAPI void ecore_x_window_prop_string_set(Ecore_X_Window win, Ecore_X_Atom type, const char *str); +EAPI char *ecore_x_window_prop_string_get(Ecore_X_Window win, Ecore_X_Atom type); +EAPI Eina_Bool ecore_x_window_prop_protocol_isset(Ecore_X_Window win, Ecore_X_WM_Protocol protocol); +EAPI Ecore_X_WM_Protocol *ecore_x_window_prop_protocol_list_get(Ecore_X_Window win, int *num_ret); + +EAPI void ecore_x_window_shape_mask_set(Ecore_X_Window win, Ecore_X_Pixmap mask); +EAPI void ecore_x_window_shape_window_set(Ecore_X_Window win, Ecore_X_Window shape_win); +EAPI void ecore_x_window_shape_window_set_xy(Ecore_X_Window win, Ecore_X_Window shape_win, int x, int y); +EAPI void ecore_x_window_shape_rectangle_set(Ecore_X_Window win, int x, int y, int w, int h); +EAPI void ecore_x_window_shape_rectangles_set(Ecore_X_Window win, Ecore_X_Rectangle *rects, int num); +EAPI void ecore_x_window_shape_input_rectangle_set(Ecore_X_Window win, int x, int y, int w, int h); +EAPI void ecore_x_window_shape_input_rectangles_set(Ecore_X_Window win, Ecore_X_Rectangle *rects, int num); +EAPI void ecore_x_window_shape_input_rectangle_add(Ecore_X_Window win, int x, int y, int w, int h); +EAPI void ecore_x_window_shape_rectangle_subtract(Ecore_X_Window win, int x, int y, int w, int h); +EAPI void ecore_x_window_shape_input_rectangle_subtract(Ecore_X_Window win, int x, int y, int w, int h); +EAPI void ecore_x_window_shape_input_window_set_xy(Ecore_X_Window win, Ecore_X_Window shape_win, int x, int y); +EAPI void ecore_x_window_shape_input_window_set(Ecore_X_Window win, Ecore_X_Window shape_win); +EAPI void ecore_x_window_shape_window_add(Ecore_X_Window win, Ecore_X_Window shape_win); +EAPI void ecore_x_window_shape_window_add_xy(Ecore_X_Window win, Ecore_X_Window shape_win, int x, int y); +EAPI void ecore_x_window_shape_input_window_add_xy(Ecore_X_Window win, Ecore_X_Window shape_win, int x, int y); +EAPI void ecore_x_window_shape_rectangle_add(Ecore_X_Window win, int x, int y, int w, int h); +EAPI void ecore_x_window_shape_rectangle_clip(Ecore_X_Window win, int x, int y, int w, int h); +EAPI void ecore_x_window_shape_input_rectangle_clip(Ecore_X_Window win, int x, int y, int w, int h); +EAPI void ecore_x_window_shape_rectangles_add(Ecore_X_Window win, Ecore_X_Rectangle *rects, int num); +EAPI void ecore_x_window_shape_input_rectangles_add(Ecore_X_Window win, Ecore_X_Rectangle *rects, int num); +EAPI Ecore_X_Rectangle *ecore_x_window_shape_rectangles_get(Ecore_X_Window win, int *num_ret); +EAPI Ecore_X_Rectangle *ecore_x_window_shape_input_rectangles_get(Ecore_X_Window win, int *num_ret); +EAPI void ecore_x_window_shape_events_select(Ecore_X_Window win, Eina_Bool on); +EAPI void ecore_x_window_shape_input_mask_set(Ecore_X_Window win, Ecore_X_Pixmap mask); + +EAPI Ecore_X_Pixmap ecore_x_pixmap_new(Ecore_X_Window win, int w, int h, int dep); +EAPI void ecore_x_pixmap_free(Ecore_X_Pixmap pmap); +EAPI void ecore_x_pixmap_paste(Ecore_X_Pixmap pmap, Ecore_X_Drawable dest, Ecore_X_GC gc, int sx, int sy, int w, int h, int dx, int dy); +EAPI void ecore_x_pixmap_geometry_get(Ecore_X_Pixmap pmap, int *x, int *y, int *w, int *h); +EAPI int ecore_x_pixmap_depth_get(Ecore_X_Pixmap pmap); + +EAPI Ecore_X_GC ecore_x_gc_new(Ecore_X_Drawable draw, Ecore_X_GC_Value_Mask value_mask, const unsigned int *value_list); +EAPI void ecore_x_gc_free(Ecore_X_GC gc); +EAPI void ecore_x_gc_foreground_set(Ecore_X_GC gc, unsigned long foreground); +EAPI void ecore_x_gc_background_set(Ecore_X_GC gc, unsigned long background); + +EAPI Eina_Bool ecore_x_client_message32_send(Ecore_X_Window win, Ecore_X_Atom type, Ecore_X_Event_Mask mask, long d0, long d1, long d2, long d3, long d4); +EAPI Eina_Bool ecore_x_client_message8_send(Ecore_X_Window win, Ecore_X_Atom type, const void *data, int len); +EAPI Eina_Bool ecore_x_mouse_move_send(Ecore_X_Window win, int x, int y); +EAPI Eina_Bool ecore_x_mouse_down_send(Ecore_X_Window win, int x, int y, int b); +EAPI Eina_Bool ecore_x_mouse_up_send(Ecore_X_Window win, int x, int y, int b); +EAPI Eina_Bool ecore_x_mouse_in_send(Ecore_X_Window win, int x, int y); +EAPI Eina_Bool ecore_x_mouse_out_send(Ecore_X_Window win, int x, int y); + +EAPI void ecore_x_drawable_geometry_get(Ecore_X_Drawable d, int *x, int *y, int *w, int *h); +EAPI int ecore_x_drawable_border_width_get(Ecore_X_Drawable d); +EAPI int ecore_x_drawable_depth_get(Ecore_X_Drawable d); +EAPI void ecore_x_drawable_rectangle_fill(Ecore_X_Drawable d, Ecore_X_GC gc, int x, int y, int width, int height); + +EAPI Eina_Bool ecore_x_cursor_color_supported_get(void); +EAPI Ecore_X_Cursor ecore_x_cursor_new(Ecore_X_Window win, int *pixels, int w, int h, int hot_x, int hot_y); +EAPI void ecore_x_cursor_free(Ecore_X_Cursor c); +EAPI Ecore_X_Cursor ecore_x_cursor_shape_get(int shape); +EAPI void ecore_x_cursor_size_set(int size); +EAPI int ecore_x_cursor_size_get(void); + +/* FIXME: these funcs need categorising */ +EAPI Ecore_X_Window *ecore_x_window_root_list(int *num_ret); +EAPI Ecore_X_Window ecore_x_window_root_first_get(void); +EAPI Eina_Bool ecore_x_window_manage(Ecore_X_Window win); +EAPI void ecore_x_window_container_manage(Ecore_X_Window win); +EAPI void ecore_x_window_client_manage(Ecore_X_Window win); +EAPI void ecore_x_window_sniff(Ecore_X_Window win); +EAPI void ecore_x_window_client_sniff(Ecore_X_Window win); + +EAPI Ecore_X_Atom ecore_x_atom_get(const char *name); +EAPI void ecore_x_atoms_get(const char **names, int num, Ecore_X_Atom *atoms); +EAPI char *ecore_x_atom_name_get(Ecore_X_Atom atom); + +EAPI void ecore_x_icccm_init(void); +EAPI void ecore_x_icccm_state_set(Ecore_X_Window win, Ecore_X_Window_State_Hint state); +EAPI Ecore_X_Window_State_Hint ecore_x_icccm_state_get(Ecore_X_Window win); +EAPI void ecore_x_icccm_delete_window_send(Ecore_X_Window win, Ecore_X_Time t); +EAPI void ecore_x_icccm_take_focus_send(Ecore_X_Window win, Ecore_X_Time t); +EAPI void ecore_x_icccm_save_yourself_send(Ecore_X_Window win, Ecore_X_Time t); +EAPI void ecore_x_icccm_move_resize_send(Ecore_X_Window win, int x, int y, int w, int h); +EAPI void ecore_x_icccm_hints_set(Ecore_X_Window win, Eina_Bool accepts_focus, Ecore_X_Window_State_Hint initial_state, Ecore_X_Pixmap icon_pixmap, Ecore_X_Pixmap icon_mask, Ecore_X_Window icon_window, Ecore_X_Window window_group, Eina_Bool is_urgent); +EAPI Eina_Bool ecore_x_icccm_hints_get(Ecore_X_Window win, Eina_Bool *accepts_focus, Ecore_X_Window_State_Hint *initial_state, Ecore_X_Pixmap *icon_pixmap, Ecore_X_Pixmap *icon_mask, Ecore_X_Window *icon_window, Ecore_X_Window *window_group, Eina_Bool *is_urgent); +EAPI void ecore_x_icccm_size_pos_hints_set(Ecore_X_Window win, Eina_Bool request_pos, Ecore_X_Gravity gravity, int min_w, int min_h, int max_w, int max_h, int base_w, int base_h, int step_x, int step_y, double min_aspect, double max_aspect); +EAPI Eina_Bool ecore_x_icccm_size_pos_hints_get(Ecore_X_Window win, Eina_Bool *request_pos, Ecore_X_Gravity *gravity, int *min_w, int *min_h, int *max_w, int *max_h, int *base_w, int *base_h, int *step_x, int *step_y, double *min_aspect, double *max_aspect); +EAPI void ecore_x_icccm_title_set(Ecore_X_Window win, const char *t); +EAPI char *ecore_x_icccm_title_get(Ecore_X_Window win); +EAPI void ecore_x_icccm_protocol_atoms_set(Ecore_X_Window win, Ecore_X_Atom *protos, int num); +EAPI void ecore_x_icccm_protocol_set(Ecore_X_Window win, Ecore_X_WM_Protocol protocol, Eina_Bool on); +EAPI Eina_Bool ecore_x_icccm_protocol_isset(Ecore_X_Window win, Ecore_X_WM_Protocol protocol); +EAPI void ecore_x_icccm_name_class_set(Ecore_X_Window win, const char *n, const char *c); +EAPI void ecore_x_icccm_name_class_get(Ecore_X_Window win, char **n, char **c); +EAPI char *ecore_x_icccm_client_machine_get(Ecore_X_Window win); +EAPI void ecore_x_icccm_command_set(Ecore_X_Window win, int argc, char **argv); +EAPI void ecore_x_icccm_command_get(Ecore_X_Window win, int *argc, char ***argv); +EAPI char *ecore_x_icccm_icon_name_get(Ecore_X_Window win); +EAPI void ecore_x_icccm_icon_name_set(Ecore_X_Window win, const char *t); +EAPI void ecore_x_icccm_colormap_window_set(Ecore_X_Window win, Ecore_X_Window subwin); +EAPI void ecore_x_icccm_colormap_window_unset(Ecore_X_Window win, Ecore_X_Window subwin); +EAPI void ecore_x_icccm_transient_for_set(Ecore_X_Window win, Ecore_X_Window forwin); +EAPI void ecore_x_icccm_transient_for_unset(Ecore_X_Window win); +EAPI Ecore_X_Window ecore_x_icccm_transient_for_get(Ecore_X_Window win); +EAPI void ecore_x_icccm_window_role_set(Ecore_X_Window win, const char *role); +EAPI char *ecore_x_icccm_window_role_get(Ecore_X_Window win); +EAPI void ecore_x_icccm_client_leader_set(Ecore_X_Window win, Ecore_X_Window l); +EAPI Ecore_X_Window ecore_x_icccm_client_leader_get(Ecore_X_Window win); +EAPI void ecore_x_icccm_iconic_request_send(Ecore_X_Window win, Ecore_X_Window root); + +typedef enum _Ecore_X_MWM_Hint_Func +{ + ECORE_X_MWM_HINT_FUNC_ALL = (1 << 0), + ECORE_X_MWM_HINT_FUNC_RESIZE = (1 << 1), + ECORE_X_MWM_HINT_FUNC_MOVE = (1 << 2), + ECORE_X_MWM_HINT_FUNC_MINIMIZE = (1 << 3), + ECORE_X_MWM_HINT_FUNC_MAXIMIZE = (1 << 4), + ECORE_X_MWM_HINT_FUNC_CLOSE = (1 << 5) +} Ecore_X_MWM_Hint_Func; + +typedef enum _Ecore_X_MWM_Hint_Decor +{ + ECORE_X_MWM_HINT_DECOR_ALL = (1 << 0), + ECORE_X_MWM_HINT_DECOR_BORDER = (1 << 1), + ECORE_X_MWM_HINT_DECOR_RESIZEH = (1 << 2), + ECORE_X_MWM_HINT_DECOR_TITLE = (1 << 3), + ECORE_X_MWM_HINT_DECOR_MENU = (1 << 4), + ECORE_X_MWM_HINT_DECOR_MINIMIZE = (1 << 5), + ECORE_X_MWM_HINT_DECOR_MAXIMIZE = (1 << 6) +} Ecore_X_MWM_Hint_Decor; + +typedef enum _Ecore_X_MWM_Hint_Input +{ + ECORE_X_MWM_HINT_INPUT_MODELESS = 0, + ECORE_X_MWM_HINT_INPUT_PRIMARY_APPLICATION_MODAL = 1, + ECORE_X_MWM_HINT_INPUT_SYSTEM_MODAL = 2, + ECORE_X_MWM_HINT_INPUT_FULL_APPLICATION_MODAL = 3 +} Ecore_X_MWM_Hint_Input; + +EAPI Eina_Bool ecore_x_mwm_hints_get(Ecore_X_Window win, Ecore_X_MWM_Hint_Func *fhint, Ecore_X_MWM_Hint_Decor *dhint, Ecore_X_MWM_Hint_Input *ihint); +EAPI void ecore_x_mwm_borderless_set(Ecore_X_Window win, Eina_Bool borderless); + +/* netwm */ +EAPI void ecore_x_netwm_init(void); +EAPI void ecore_x_netwm_shutdown(void); +EAPI void ecore_x_netwm_wm_identify(Ecore_X_Window root, Ecore_X_Window check, const char *wm_name); +EAPI void ecore_x_netwm_supported_set(Ecore_X_Window root, Ecore_X_Atom *supported, int num); +EAPI Eina_Bool ecore_x_netwm_supported_get(Ecore_X_Window root, Ecore_X_Atom **supported, int *num); +EAPI void ecore_x_netwm_desk_count_set(Ecore_X_Window root, unsigned int n_desks); +EAPI void ecore_x_netwm_desk_roots_set(Ecore_X_Window root, Ecore_X_Window *vroots, unsigned int n_desks); +EAPI void ecore_x_netwm_desk_names_set(Ecore_X_Window root, const char **names, unsigned int n_desks); +EAPI void ecore_x_netwm_desk_size_set(Ecore_X_Window root, unsigned int width, unsigned int height); +EAPI void ecore_x_netwm_desk_workareas_set(Ecore_X_Window root, unsigned int *areas, unsigned int n_desks); +EAPI unsigned int *ecore_x_netwm_desk_workareas_get(Ecore_X_Window root, unsigned int *n_desks); +EAPI void ecore_x_netwm_desk_current_set(Ecore_X_Window root, unsigned int desk); +EAPI void ecore_x_netwm_desk_viewports_set(Ecore_X_Window root, unsigned int *origins, unsigned int n_desks); +EAPI void ecore_x_netwm_desk_layout_set(Ecore_X_Window root, int orientation, int columns, int rows, int starting_corner); +EAPI void ecore_x_netwm_showing_desktop_set(Ecore_X_Window root, Eina_Bool on); +EAPI void ecore_x_netwm_client_list_set(Ecore_X_Window root, Ecore_X_Window *p_clients, unsigned int n_clients); +EAPI void ecore_x_netwm_client_list_stacking_set(Ecore_X_Window root, Ecore_X_Window *p_clients, unsigned int n_clients); +EAPI void ecore_x_netwm_client_active_set(Ecore_X_Window root, Ecore_X_Window win); +EAPI void ecore_x_netwm_client_active_request(Ecore_X_Window root, Ecore_X_Window win, int type, Ecore_X_Window current_win); +EAPI void ecore_x_netwm_name_set(Ecore_X_Window win, const char *name); +EAPI int ecore_x_netwm_name_get(Ecore_X_Window win, char **name); +EAPI void ecore_x_netwm_startup_id_set(Ecore_X_Window win, const char *id); +EAPI int ecore_x_netwm_startup_id_get(Ecore_X_Window win, char **id); +EAPI void ecore_x_netwm_visible_name_set(Ecore_X_Window win, const char *name); +EAPI int ecore_x_netwm_visible_name_get(Ecore_X_Window win, char **name); +EAPI void ecore_x_netwm_icon_name_set(Ecore_X_Window win, const char *name); +EAPI int ecore_x_netwm_icon_name_get(Ecore_X_Window win, char **name); +EAPI void ecore_x_netwm_visible_icon_name_set(Ecore_X_Window win, const char *name); +EAPI int ecore_x_netwm_visible_icon_name_get(Ecore_X_Window win, char **name); +EAPI void ecore_x_netwm_desktop_set(Ecore_X_Window win, unsigned int desk); +EAPI Eina_Bool ecore_x_netwm_desktop_get(Ecore_X_Window win, unsigned int *desk); +EAPI void ecore_x_netwm_strut_set(Ecore_X_Window win, int left, int right, int top, int bottom); +EAPI Eina_Bool ecore_x_netwm_strut_get(Ecore_X_Window win, int *left, int *right, int *top, int *bottom); +EAPI void ecore_x_netwm_strut_partial_set(Ecore_X_Window win, int left, int right, int top, int bottom, int left_start_y, int left_end_y, int right_start_y, int right_end_y, int top_start_x, int top_end_x, int bottom_start_x, int bottom_end_x); +EAPI Eina_Bool ecore_x_netwm_strut_partial_get(Ecore_X_Window win, int *left, int *right, int *top, int *bottom, int *left_start_y, int *left_end_y, int *right_start_y, int *right_end_y, int *top_start_x, int *top_end_x, int *bottom_start_x, int *bottom_end_x); + +EAPI void ecore_x_netwm_icons_set(Ecore_X_Window win, Ecore_X_Icon *icon, int num); + +EAPI Eina_Bool ecore_x_netwm_icons_get(Ecore_X_Window win, Ecore_X_Icon **icon, int *num); +EAPI void ecore_x_netwm_icon_geometry_set(Ecore_X_Window win, int x, int y, int width, int height); +EAPI Eina_Bool ecore_x_netwm_icon_geometry_get(Ecore_X_Window win, int *x, int *y, int *width, int *height); +EAPI void ecore_x_netwm_pid_set(Ecore_X_Window win, int pid); +EAPI Eina_Bool ecore_x_netwm_pid_get(Ecore_X_Window win, int *pid); +EAPI void ecore_x_netwm_handled_icons_set(Ecore_X_Window win); +EAPI Eina_Bool ecore_x_netwm_handled_icons_get(Ecore_X_Window win); +EAPI void ecore_x_netwm_user_time_set(Ecore_X_Window win, unsigned int time); +EAPI Eina_Bool ecore_x_netwm_user_time_get(Ecore_X_Window win, unsigned int *time); +EAPI void ecore_x_netwm_window_state_set(Ecore_X_Window win, Ecore_X_Window_State *state, unsigned int num); +EAPI Eina_Bool ecore_x_netwm_window_state_get(Ecore_X_Window win, Ecore_X_Window_State **state, unsigned int *num); +EAPI void ecore_x_netwm_window_type_set(Ecore_X_Window win, Ecore_X_Window_Type type); +EAPI Eina_Bool ecore_x_netwm_window_type_get(Ecore_X_Window win, Ecore_X_Window_Type *type); +EAPI int ecore_x_netwm_window_types_get(Ecore_X_Window win, Ecore_X_Window_Type **types); +EAPI Eina_Bool ecore_x_netwm_allowed_action_isset(Ecore_X_Window win, Ecore_X_Action action); +EAPI void ecore_x_netwm_allowed_action_set(Ecore_X_Window win, Ecore_X_Action *action, unsigned int num); +EAPI Eina_Bool ecore_x_netwm_allowed_action_get(Ecore_X_Window win, Ecore_X_Action **action, unsigned int *num); +EAPI void ecore_x_netwm_opacity_set(Ecore_X_Window win, unsigned int opacity); +EAPI Eina_Bool ecore_x_netwm_opacity_get(Ecore_X_Window win, unsigned int *opacity); +EAPI void ecore_x_netwm_frame_size_set(Ecore_X_Window win, int fl, int fr, int ft, int fb); +EAPI Eina_Bool ecore_x_netwm_frame_size_get(Ecore_X_Window win, int *fl, int *fr, int *ft, int *fb); +EAPI Eina_Bool ecore_x_netwm_sync_counter_get(Ecore_X_Window win, Ecore_X_Sync_Counter *counter); +EAPI void ecore_x_netwm_ping_send(Ecore_X_Window win); +EAPI void ecore_x_netwm_sync_request_send(Ecore_X_Window win, unsigned int serial); +EAPI void ecore_x_netwm_state_request_send(Ecore_X_Window win, Ecore_X_Window root, Ecore_X_Window_State s1, Ecore_X_Window_State s2, Eina_Bool set); +EAPI void ecore_x_netwm_desktop_request_send(Ecore_X_Window win, Ecore_X_Window root, unsigned int desktop); +EAPI void ecore_x_netwm_moveresize_request_send(Ecore_X_Window win, int x, int y, Ecore_X_Netwm_Direction direction, unsigned int button); + +EAPI void ecore_x_e_init(void); +EAPI void ecore_x_e_frame_size_set(Ecore_X_Window win, int fl, int fr, int ft, int fb); +EAPI void ecore_x_e_virtual_keyboard_set(Ecore_X_Window win, unsigned int is_keyboard); +EAPI Eina_Bool ecore_x_e_virtual_keyboard_get(Ecore_X_Window win); +EAPI void ecore_x_e_virtual_keyboard_state_set(Ecore_X_Window win, Ecore_X_Virtual_Keyboard_State state); +EAPI Ecore_X_Virtual_Keyboard_State ecore_x_e_virtual_keyboard_state_get(Ecore_X_Window win); +EAPI void ecore_x_e_virtual_keyboard_state_send(Ecore_X_Window win, Ecore_X_Virtual_Keyboard_State state); + +/* Illume functions */ +EAPI void ecore_x_e_illume_zone_set(Ecore_X_Window win, Ecore_X_Window zone); +EAPI Ecore_X_Window ecore_x_e_illume_zone_get(Ecore_X_Window win); +EAPI void ecore_x_e_illume_zone_list_set(Ecore_X_Window win, Ecore_X_Window *zones, unsigned int n_zones); +EAPI void ecore_x_e_illume_conformant_set(Ecore_X_Window win, unsigned int is_conformant); +EAPI Eina_Bool ecore_x_e_illume_conformant_get(Ecore_X_Window win); +EAPI void ecore_x_e_illume_mode_set(Ecore_X_Window win, Ecore_X_Illume_Mode mode); +EAPI Ecore_X_Illume_Mode ecore_x_e_illume_mode_get(Ecore_X_Window win); +EAPI void ecore_x_e_illume_mode_send(Ecore_X_Window win, Ecore_X_Illume_Mode mode); +EAPI void ecore_x_e_illume_focus_back_send(Ecore_X_Window win); +EAPI void ecore_x_e_illume_focus_forward_send(Ecore_X_Window win); +EAPI void ecore_x_e_illume_focus_home_send(Ecore_X_Window win); +EAPI void ecore_x_e_illume_close_send(Ecore_X_Window win); +EAPI void ecore_x_e_illume_home_new_send(Ecore_X_Window win); +EAPI void ecore_x_e_illume_home_del_send(Ecore_X_Window win); +EAPI void ecore_x_e_illume_access_action_next_send(Ecore_X_Window win); +EAPI void ecore_x_e_illume_access_action_prev_send(Ecore_X_Window win); +EAPI void ecore_x_e_illume_access_action_activate_send(Ecore_X_Window win); +EAPI void ecore_x_e_illume_access_action_read_send(Ecore_X_Window win); +EAPI void ecore_x_e_illume_access_action_read_next_send(Ecore_X_Window win); +EAPI void ecore_x_e_illume_access_action_read_prev_send(Ecore_X_Window win); + +EAPI void ecore_x_e_illume_drag_set(Ecore_X_Window win, unsigned int drag); +EAPI Eina_Bool ecore_x_e_illume_drag_get(Ecore_X_Window win); +EAPI void ecore_x_e_illume_drag_locked_set(Ecore_X_Window win, unsigned int is_locked); +EAPI Eina_Bool ecore_x_e_illume_drag_locked_get(Ecore_X_Window win); +EAPI void ecore_x_e_illume_drag_start_send(Ecore_X_Window win); +EAPI void ecore_x_e_illume_drag_end_send(Ecore_X_Window win); +EAPI void ecore_x_e_illume_indicator_geometry_set(Ecore_X_Window win, int x, int y, int w, int h); +EAPI Eina_Bool ecore_x_e_illume_indicator_geometry_get(Ecore_X_Window win, int *x, int *y, int *w, int *h); +EAPI void ecore_x_e_illume_softkey_geometry_set(Ecore_X_Window win, int x, int y, int w, int h); +EAPI Eina_Bool ecore_x_e_illume_softkey_geometry_get(Ecore_X_Window win, int *x, int *y, int *w, int *h); +EAPI void ecore_x_e_illume_keyboard_geometry_set(Ecore_X_Window win, int x, int y, int w, int h); +EAPI Eina_Bool ecore_x_e_illume_keyboard_geometry_get(Ecore_X_Window win, int *x, int *y, int *w, int *h); +EAPI void ecore_x_e_illume_quickpanel_set(Ecore_X_Window win, unsigned int is_quickpanel); +EAPI Eina_Bool ecore_x_e_illume_quickpanel_get(Ecore_X_Window win); +EAPI void ecore_x_e_illume_quickpanel_state_set(Ecore_X_Window win, Ecore_X_Illume_Quickpanel_State state); +EAPI Ecore_X_Illume_Quickpanel_State ecore_x_e_illume_quickpanel_state_get(Ecore_X_Window win); +EAPI void ecore_x_e_illume_quickpanel_state_send(Ecore_X_Window win, Ecore_X_Illume_Quickpanel_State state); +EAPI void ecore_x_e_illume_quickpanel_state_toggle(Ecore_X_Window win); +EAPI void ecore_x_e_illume_quickpanel_priority_major_set(Ecore_X_Window win, unsigned int priority); +EAPI int ecore_x_e_illume_quickpanel_priority_major_get(Ecore_X_Window win); +EAPI void ecore_x_e_illume_quickpanel_priority_minor_set(Ecore_X_Window win, unsigned int priority); +EAPI int ecore_x_e_illume_quickpanel_priority_minor_get(Ecore_X_Window win); +EAPI void ecore_x_e_illume_quickpanel_zone_set(Ecore_X_Window win, unsigned int zone); +EAPI int ecore_x_e_illume_quickpanel_zone_get(Ecore_X_Window win); +EAPI void ecore_x_e_illume_quickpanel_zone_request_send(Ecore_X_Window win); +EAPI void ecore_x_e_illume_quickpanel_position_update_send(Ecore_X_Window win); + +EAPI void ecore_x_e_illume_clipboard_state_set(Ecore_X_Window win, Ecore_X_Illume_Clipboard_State state); + +EAPI Ecore_X_Illume_Clipboard_State ecore_x_e_illume_clipboard_state_get(Ecore_X_Window win); + +EAPI void ecore_x_e_illume_clipboard_geometry_set(Ecore_X_Window win, int x, int y, int w, int h); +EAPI Eina_Bool ecore_x_e_illume_clipboard_geometry_get(Ecore_X_Window win, int *x, int *y, int *w, int *h); +EAPI void ecore_x_e_comp_sync_counter_set(Ecore_X_Window win, Ecore_X_Sync_Counter counter); +EAPI Ecore_X_Sync_Counter ecore_x_e_comp_sync_counter_get(Ecore_X_Window win); +EAPI void ecore_x_e_comp_sync_draw_done_send(Ecore_X_Window root, Ecore_X_Window win); +EAPI void ecore_x_e_comp_sync_draw_size_done_send(Ecore_X_Window root, Ecore_X_Window win, int w, int h); +EAPI void ecore_x_e_comp_sync_supported_set(Ecore_X_Window root, Eina_Bool enabled); +EAPI Eina_Bool ecore_x_e_comp_sync_supported_get(Ecore_X_Window root); +EAPI void ecore_x_e_comp_sync_begin_send(Ecore_X_Window win); +EAPI void ecore_x_e_comp_sync_end_send(Ecore_X_Window win); +EAPI void ecore_x_e_comp_sync_cancel_send(Ecore_X_Window win); + +EAPI void ecore_x_e_comp_flush_send(Ecore_X_Window win); +EAPI void ecore_x_e_comp_dump_send(Ecore_X_Window win); +EAPI void ecore_x_e_comp_pixmap_set(Ecore_X_Window win, Ecore_X_Pixmap pixmap); +EAPI Ecore_X_Pixmap ecore_x_e_comp_pixmap_get(Ecore_X_Window win); + +EAPI char *ecore_x_e_window_profile_get(Ecore_X_Window win); +EAPI void ecore_x_e_window_profile_set(Ecore_X_Window win, const char *profile); +EAPI void ecore_x_e_window_profile_list_set(Ecore_X_Window win, const char **profiles, unsigned int num_profiles); +EAPI Eina_Bool ecore_x_e_window_profile_list_get(Ecore_X_Window win, const char ***profiles, int *ret_num); + +EAPI Ecore_X_Sync_Alarm ecore_x_sync_alarm_new(Ecore_X_Sync_Counter counter); +EAPI Eina_Bool ecore_x_sync_alarm_free(Ecore_X_Sync_Alarm alarm); +EAPI Eina_Bool ecore_x_sync_counter_query(Ecore_X_Sync_Counter counter, unsigned int *val); +EAPI Ecore_X_Sync_Counter ecore_x_sync_counter_new(int val); +EAPI void ecore_x_sync_counter_free(Ecore_X_Sync_Counter counter); +EAPI void ecore_x_sync_counter_inc(Ecore_X_Sync_Counter counter, int by); +EAPI void ecore_x_sync_counter_val_wait(Ecore_X_Sync_Counter counter, int val); + +EAPI void ecore_x_sync_counter_set(Ecore_X_Sync_Counter counter, int val); +EAPI void ecore_x_sync_counter_2_set(Ecore_X_Sync_Counter counter, int val_hi, unsigned int val_lo); +EAPI Eina_Bool ecore_x_sync_counter_2_query(Ecore_X_Sync_Counter counter, int *val_hi, unsigned int *val_lo); + +EAPI int ecore_x_xinerama_screen_count_get(void); +EAPI Eina_Bool ecore_x_xinerama_screen_geometry_get(int screen, int *x, int *y, int *w, int *h); + +EAPI Eina_Bool ecore_x_screensaver_event_available_get(void); +EAPI int ecore_x_screensaver_idle_time_get(void); +EAPI void ecore_x_screensaver_set(int timeout, int interval, int prefer_blanking, int allow_exposures); +EAPI void ecore_x_screensaver_timeout_set(int timeout); +EAPI int ecore_x_screensaver_timeout_get(void); +EAPI void ecore_x_screensaver_blank_set(int timeout); +EAPI int ecore_x_screensaver_blank_get(void); +EAPI void ecore_x_screensaver_expose_set(int timeout); +EAPI int ecore_x_screensaver_expose_get(void); +EAPI void ecore_x_screensaver_interval_set(int timeout); +EAPI int ecore_x_screensaver_interval_get(void); +EAPI void ecore_x_screensaver_event_listen_set(Eina_Bool on); +EAPI Eina_Bool ecore_x_screensaver_custom_blanking_enable(void); /** @since 1.7 */ +EAPI Eina_Bool ecore_x_screensaver_custom_blanking_disable(void); /** @since 1.7 */ + +/* FIXME: these funcs need categorising */ + +typedef struct _Ecore_X_Window_Attributes +{ + Ecore_X_Window root; + int x, y, w, h; + int border; + int depth; + Eina_Bool visible : 1; + Eina_Bool viewable : 1; + Eina_Bool override : 1; + Eina_Bool input_only : 1; + Eina_Bool save_under : 1; + struct + { + Ecore_X_Event_Mask mine; + Ecore_X_Event_Mask all; + Ecore_X_Event_Mask no_propagate; + } event_mask; + Ecore_X_Gravity window_gravity; + Ecore_X_Gravity pixel_gravity; + Ecore_X_Colormap colormap; + Ecore_X_Visual visual; + /* FIXME: missing + * int map_installed; + * Screen *screen; + */ +} Ecore_X_Window_Attributes; + +EAPI Eina_Bool ecore_x_window_attributes_get(Ecore_X_Window win, Ecore_X_Window_Attributes *att_ret); +EAPI void ecore_x_window_save_set_add(Ecore_X_Window win); +EAPI void ecore_x_window_save_set_del(Ecore_X_Window win); +EAPI Ecore_X_Window *ecore_x_window_children_get(Ecore_X_Window win, int *num); + +EAPI Eina_Bool ecore_x_pointer_control_set(int accel_num, int accel_denom, int threshold); +EAPI Eina_Bool ecore_x_pointer_control_get(int *accel_num, int *accel_denom, int *threshold); +EAPI Eina_Bool ecore_x_pointer_mapping_set(unsigned char *map, int nmap); +EAPI Eina_Bool ecore_x_pointer_mapping_get(unsigned char *map, int nmap); +EAPI Eina_Bool ecore_x_pointer_grab(Ecore_X_Window win); +EAPI Eina_Bool ecore_x_pointer_confine_grab(Ecore_X_Window win); +EAPI void ecore_x_pointer_ungrab(void); +EAPI Eina_Bool ecore_x_pointer_warp(Ecore_X_Window win, int x, int y); +EAPI Eina_Bool ecore_x_keyboard_grab(Ecore_X_Window win); +EAPI void ecore_x_keyboard_ungrab(void); +EAPI void ecore_x_grab(void); +EAPI void ecore_x_ungrab(void); +EAPI void ecore_x_passive_grab_replay_func_set(Eina_Bool (*func)(void *data, int event_type, void *event), void *data); +EAPI void ecore_x_window_button_grab(Ecore_X_Window win, int button, Ecore_X_Event_Mask event_mask, int mod, int any_mod); +EAPI void ecore_x_window_button_ungrab(Ecore_X_Window win, int button, int mod, int any_mod); +EAPI void ecore_x_window_key_grab(Ecore_X_Window win, const char *key, int mod, int any_mod); +EAPI void ecore_x_window_key_ungrab(Ecore_X_Window win, const char *key, int mod, int any_mod); + +EAPI void ecore_x_focus_reset(void); +EAPI void ecore_x_events_allow_all(void); +EAPI void ecore_x_pointer_last_xy_get(int *x, int *y); +EAPI void ecore_x_pointer_xy_get(Ecore_X_Window win, int *x, int *y); + +/* ecore_x_region.c */ +EAPI Ecore_X_XRegion *ecore_x_xregion_new(void); +EAPI void ecore_x_xregion_free(Ecore_X_XRegion *region); +EAPI Eina_Bool ecore_x_xregion_set(Ecore_X_XRegion *region, Ecore_X_GC gc); +EAPI void ecore_x_xregion_translate(Ecore_X_XRegion *region, int x, int y); +EAPI Eina_Bool ecore_x_xregion_intersect(Ecore_X_XRegion *dst, Ecore_X_XRegion *r1, Ecore_X_XRegion *r2); +EAPI Eina_Bool ecore_x_xregion_union(Ecore_X_XRegion *dst, Ecore_X_XRegion *r1, Ecore_X_XRegion *r2); +EAPI Eina_Bool ecore_x_xregion_union_rect(Ecore_X_XRegion *dst, Ecore_X_XRegion *src, Ecore_X_Rectangle *rect); +EAPI Eina_Bool ecore_x_xregion_subtract(Ecore_X_XRegion *dst, Ecore_X_XRegion *r1, Ecore_X_XRegion *r2); +EAPI Eina_Bool ecore_x_xregion_is_empty(Ecore_X_XRegion *region); +EAPI Eina_Bool ecore_x_xregion_is_equal(Ecore_X_XRegion *r1, Ecore_X_XRegion *r2); +EAPI Eina_Bool ecore_x_xregion_point_contain(Ecore_X_XRegion *region, int x, int y); +EAPI Eina_Bool ecore_x_xregion_rect_contain(Ecore_X_XRegion *region, Ecore_X_Rectangle *rect); + +/* ecore_x_randr.c */ + +/* The usage of 'Ecore_X_Randr_None' or 'Ecore_X_Randr_Unset' + * depends on the context. In most cases 'Ecore_X_Randr_Unset' + * can be used, but in some cases -1 is a special value to + * functions, thus 'Ecore_X_Randr_None' (=0) must be used. + */ + +typedef short Ecore_X_Randr_Refresh_Rate; +typedef int Ecore_X_Randr_Crtc_Gamma; +typedef int Ecore_X_Randr_Signal_Format; +typedef int Ecore_X_Randr_Signal_Property; +typedef int Ecore_X_Randr_Connector_Type; + +typedef struct _Ecore_X_Randr_Mode_Info +{ + Ecore_X_ID xid; + unsigned int width; + unsigned int height; + unsigned long dotClock; + unsigned int hSyncStart; + unsigned int hSyncEnd; + unsigned int hTotal; + unsigned int hSkew; + unsigned int vSyncStart; + unsigned int vSyncEnd; + unsigned int vTotal; + char *name; + unsigned int nameLength; + unsigned long modeFlags; +} Ecore_X_Randr_Mode_Info; + +EAPI int ecore_x_randr_version_get(void); +EAPI Eina_Bool ecore_x_randr_query(void); + +/* ecore_x_randr_11.c */ +EAPI Ecore_X_Randr_Orientation ecore_x_randr_screen_primary_output_orientations_get(Ecore_X_Window root); +EAPI Ecore_X_Randr_Orientation ecore_x_randr_screen_primary_output_orientation_get(Ecore_X_Window root); +EAPI Eina_Bool ecore_x_randr_screen_primary_output_orientation_set(Ecore_X_Window root, Ecore_X_Randr_Orientation orientation); +EAPI Ecore_X_Randr_Screen_Size_MM *ecore_x_randr_screen_primary_output_sizes_get(Ecore_X_Window root, int *num); + +/** + * @brief get the current set size of a given screen's primary output + * @param root window which's primary output will be queried + * @param w the current size's width + * @param h the current size's height + * @param w_mm the current size's width in mm + * @param h_mm the current size's height in mm + * @param size_index of current set size to be used with ecore_x_randr_primary_output_size_set() + */ +EAPI void ecore_x_randr_screen_primary_output_current_size_get(Ecore_X_Window root, int *w, int *h, int *w_mm, int *h_mm, int *size_index); +EAPI Eina_Bool ecore_x_randr_screen_primary_output_size_set(Ecore_X_Window root, int size_index); +EAPI Ecore_X_Randr_Refresh_Rate ecore_x_randr_screen_primary_output_current_refresh_rate_get(Ecore_X_Window root); +EAPI Ecore_X_Randr_Refresh_Rate *ecore_x_randr_screen_primary_output_refresh_rates_get(Ecore_X_Window root, int size_index, int *num); +EAPI Eina_Bool ecore_x_randr_screen_primary_output_refresh_rate_set(Ecore_X_Window root, int size_index, Ecore_X_Randr_Refresh_Rate rate); + +/* ecore_x_randr_12.c */ +EAPI void ecore_x_randr_events_select(Ecore_X_Window win, Eina_Bool on); + +EAPI void ecore_x_randr_screen_current_size_get(Ecore_X_Window root, int *w, int *h, int *w_mm, int *h_mm); +EAPI void ecore_x_randr_screen_size_range_get(Ecore_X_Window root, int *wmin, int *hmin, int *wmax, int *hmax); +EAPI void ecore_x_randr_screen_reset(Ecore_X_Window root); +EAPI Eina_Bool ecore_x_randr_screen_current_size_set(Ecore_X_Window root, int w, int h, int w_mm, int h_mm); +EAPI Ecore_X_Randr_Mode_Info **ecore_x_randr_modes_info_get(Ecore_X_Window root, int *num); +EAPI Ecore_X_Randr_Mode ecore_x_randr_mode_info_add(Ecore_X_Window root, Ecore_X_Randr_Mode_Info *mode_info); +EAPI void ecore_x_randr_mode_del(Ecore_X_Randr_Mode mode); +EAPI Ecore_X_Randr_Mode_Info *ecore_x_randr_mode_info_get(Ecore_X_Window root, Ecore_X_Randr_Mode mode); +EAPI void ecore_x_randr_mode_info_free(Ecore_X_Randr_Mode_Info *mode_info); +EAPI Ecore_X_Randr_Crtc *ecore_x_randr_crtcs_get(Ecore_X_Window root, int *num); +EAPI Ecore_X_Randr_Output *ecore_x_randr_outputs_get(Ecore_X_Window root, int *num); +EAPI Ecore_X_Randr_Output *ecore_x_randr_window_outputs_get(Ecore_X_Window window, int *num); +EAPI Ecore_X_Randr_Output *ecore_x_randr_current_output_get(Ecore_X_Window window, int *num); +EAPI Ecore_X_Randr_Crtc *ecore_x_randr_window_crtcs_get(Ecore_X_Window window, int *num); +EAPI Ecore_X_Randr_Crtc *ecore_x_randr_current_crtc_get(Ecore_X_Window window, int *num); +EAPI Ecore_X_Randr_Output *ecore_x_randr_crtc_outputs_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *num); +EAPI Ecore_X_Randr_Output *ecore_x_randr_crtc_possible_outputs_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *num); +EAPI void ecore_x_randr_crtc_geometry_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *x, int *y, int *w, int *h); +EAPI void ecore_x_randr_crtc_pos_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *x, int *y); +EAPI Eina_Bool ecore_x_randr_crtc_pos_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int x, int y); +EAPI Ecore_X_Randr_Mode ecore_x_randr_crtc_mode_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc); +EAPI Eina_Bool ecore_x_randr_crtc_mode_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, Ecore_X_Randr_Output *outputs, int noutputs, Ecore_X_Randr_Mode mode); +EAPI void ecore_x_randr_crtc_size_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *w, int *h); +EAPI Ecore_X_Randr_Refresh_Rate ecore_x_randr_crtc_refresh_rate_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, Ecore_X_Randr_Mode mode); +EAPI Ecore_X_Randr_Orientation ecore_x_randr_crtc_orientations_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc); +EAPI Ecore_X_Randr_Orientation ecore_x_randr_crtc_orientation_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc); +EAPI Eina_Bool ecore_x_randr_crtc_orientation_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, const Ecore_X_Randr_Orientation orientation); +EAPI Eina_Bool ecore_x_randr_crtc_clone_set(Ecore_X_Window root, Ecore_X_Randr_Crtc original, Ecore_X_Randr_Crtc clone); +EAPI Eina_Bool ecore_x_randr_crtc_settings_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, Ecore_X_Randr_Output *outputs, int noutputs, int x, int y, Ecore_X_Randr_Mode mode, Ecore_X_Randr_Orientation orientation); +EAPI Eina_Bool ecore_x_randr_crtc_pos_relative_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc_r1, Ecore_X_Randr_Crtc crtc_r2, Ecore_X_Randr_Output_Policy policy, Ecore_X_Randr_Relative_Alignment alignment); +EAPI Eina_Bool ecore_x_randr_output_mode_add(Ecore_X_Randr_Output output, Ecore_X_Randr_Mode mode); +EAPI void ecore_x_randr_output_mode_del(Ecore_X_Randr_Output output, Ecore_X_Randr_Mode mode); +EAPI Ecore_X_Randr_Mode *ecore_x_randr_output_modes_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num, int *npreferred); +EAPI Ecore_X_Randr_Output *ecore_x_randr_output_clones_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num); +EAPI Ecore_X_Randr_Crtc *ecore_x_randr_output_possible_crtcs_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num); +EAPI Ecore_X_Randr_Crtc ecore_x_randr_output_crtc_get(Ecore_X_Window root, Ecore_X_Randr_Output output); +EAPI char *ecore_x_randr_output_name_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *len); +EAPI int ecore_x_randr_crtc_gamma_ramp_size_get(Ecore_X_Randr_Crtc crtc); +EAPI Ecore_X_Randr_Crtc_Gamma **ecore_x_randr_crtc_gamma_ramps_get(Ecore_X_Randr_Crtc crtc); +EAPI Eina_Bool ecore_x_randr_crtc_gamma_ramps_set(Ecore_X_Randr_Crtc crtc, const Ecore_X_Randr_Crtc_Gamma *red, const Ecore_X_Randr_Crtc_Gamma *green, const Ecore_X_Randr_Crtc_Gamma *blue); +EAPI Eina_Bool ecore_x_randr_move_all_crtcs_but(Ecore_X_Window root, const Ecore_X_Randr_Crtc *not_moved, int nnot_moved, int dx, int dy); +EAPI Eina_Bool ecore_x_randr_move_crtcs(Ecore_X_Window root, const Ecore_X_Randr_Crtc *crtcs, int ncrtc, int dx, int dy); +EAPI void ecore_x_randr_mode_size_get(Ecore_X_Window root, Ecore_X_Randr_Mode mode, int *w, int *h); +EAPI Ecore_X_Randr_Connection_Status ecore_x_randr_output_connection_status_get(Ecore_X_Window root, Ecore_X_Randr_Output output); +EAPI void ecore_x_randr_output_size_mm_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *w, int *h); +EAPI Eina_Bool ecore_x_randr_output_crtc_set(Ecore_X_Window root, Ecore_X_Randr_Output output, const Ecore_X_Randr_Crtc crtc); + +/* ecore_x_randr_12_edid.c */ + +/** + * @brief Validates the header from raw EDID data. + * + * @param edid The edid structure. + * @param edid_length Length of the edid structure. + * @return @c EINA_TRUE, if the header is valid, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool ecore_x_randr_edid_has_valid_header(unsigned char *edid, unsigned long edid_length); + +/** + * @brief Checks whether a display's EDID has a valid checksum. + * + * @param edid The edid structure. + * @param edid_length Length of the edid structure. + * @return @c EINA_TRUE, if the checksum is valid, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool ecore_x_randr_edid_info_has_valid_checksum(unsigned char *edid, unsigned long edid_length); + +/** + * @brief Get the encoded version from raw EDID data. + * + * The return value has the minor version in the lowest 8 bits, and the major + * version in all the rest of the bits. i.e. + * + * minor = (version & 0x000000ff); + * major = (version & 0xffffff00) >> 8; + * + * @param edid the edid structure + * @param edid_length length of the edid structure + * @return The encoded major and minor version encasuplated an int. + */ +EAPI int ecore_x_randr_edid_version_get(unsigned char *edid, unsigned long edid_length); + +/** + * @brief Get the encoded manufacturer from raw EDID data. + * + * @param edid the edid structure + * @param edid_length length of the edid structure + * @return The encoded manufacturer identifier. + */ +EAPI char *ecore_x_randr_edid_manufacturer_name_get(unsigned char *edid, unsigned long edid_length); + +/** + * @brief Get the encoded name from raw EDID data. + * + * @param edid the edid structure + * @param edid_length length of the edid structure + * @return The encoded manufacturer identifier. + */ +EAPI char *ecore_x_randr_edid_display_name_get(unsigned char *edid, unsigned long edid_length); + +/** + * @brief Get the encoded ASCII from raw EDID data. + * + * @param edid the edid structure + * @param edid_length length of the edid structure + * @return The encoded ASCII display identifier. + */ +EAPI char *ecore_x_randr_edid_display_ascii_get(unsigned char *edid, unsigned long edid_length); + +/** + * @brief Get the encoded serial identifier from raw EDID data. + * + * @param edid the edid structure + * @param edid_length length of the edid structure + * @return The encoded serial identifier. + */ +EAPI char *ecore_x_randr_edid_display_serial_get(unsigned char *edid, unsigned long edid_length); + +/** + * @brief Get the encoded model number from raw EDID data. + * + * The manufacturer ID table is necessary for a useful description. + * + * @param edid the edid structure + * @param edid_length length of the edid structure + * @return The encoded model number. + */ +EAPI int ecore_x_randr_edid_model_get(unsigned char *edid, unsigned long edid_length); + +/** + * @brief Get the manufacturer serial number from raw EDID data. + * + * @param edid the edid structure + * @param edid_length length of the edid structure + * @return The encoded serial manufacturer serial number. + */ +EAPI int ecore_x_randr_edid_manufacturer_serial_number_get(unsigned char *edid, unsigned long edid_length); + +/** + * @brief Get the manufacturer model number from raw EDID data. + * + * @param edid the edid structure + * @param edid_length length of the edid structure + * @return The manufacturer's model number. + */ +EAPI int ecore_x_randr_edid_manufacturer_model_get(unsigned char *edid, unsigned long edid_length); + +/** + * @brief Looks up the DPMS support from raw EDID data. + * + * @param edid The edid structure. + * @param edid_length Length of the edid structure. + * @return @c EINA_TRUE, if DPMS is supported in some way, @c EINA_FALSE + * otherwise. + */ +EAPI Eina_Bool ecore_x_randr_edid_dpms_available_get(unsigned char *edid, unsigned long edid_length); + +/** + * @brief Looks up the DPMS Standby support from raw EDID data. + * + * @param edid The edid structure. + * @param edid_length Length of the edid structure. + * @return @c EINA_TRUE, if DPMS Standby is supported, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool ecore_x_randr_edid_dpms_standby_available_get(unsigned char *edid, unsigned long edid_length); + +/** + * @brief Looks up the DPMS Suspend support from raw EDID data. + * + * @param edid The edid structure. + * @param edid_length Length of the edid structure. + * @return @c EINA_TRUE, if DPMS Suspend is supported, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool ecore_x_randr_edid_dpms_suspend_available_get(unsigned char *edid, unsigned long edid_length); + +/** + * @brief Looks up the DPMS Off support from raw EDID data. + * + * @param edid The edid structure. + * @param edid_length Length of the edid structure. + * @return @c EINA_TRUE, if DPMS Off is supported, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool ecore_x_randr_edid_dpms_off_available_get(unsigned char *edid, unsigned long edid_length); + +/** + * @brief Get the preferred aspect ratio from raw EDID data. + * + * @param edid the edid structure + * @param edid_length length of the edid structure + * @return The preferred aspect ratio. + */ +EAPI Ecore_X_Randr_Edid_Aspect_Ratio ecore_x_randr_edid_display_aspect_ratio_preferred_get(unsigned char *edid, unsigned long edid_length); + +/** + * @brief Get the supported aspect ratios from raw EDID data. + * + * @param edid the edid structure + * @param edid_length length of the edid structure + * @return The supported aspect ratios. + */ +EAPI Ecore_X_Randr_Edid_Aspect_Ratio ecore_x_randr_edid_display_aspect_ratios_get(unsigned char *edid, unsigned long edid_length); + +/** + * @brief Get the supported colorschemes from raw EDID data. + * + * @param edid the edid structure + * @param edid_length length of the edid structure + * @return The supported colorschemes. + */ +EAPI Ecore_X_Randr_Edid_Display_Colorscheme ecore_x_randr_edid_display_colorscheme_get(unsigned char *edid, unsigned long edid_length); + +/** + * @brief Get the display type from raw EDID data. + * + * @param edid The edid structure. + * @param edid_length Length of the edid structure. + * @return @c EINA_TRUE, if the display is a digital one, @c EINA_FALSE + * otherwise. + */ +EAPI Eina_Bool ecore_x_randr_edid_display_type_digital_get(unsigned char *edid, unsigned long edid_length); + +/** + * @brief Get the display interface type from raw EDID data. + * + * @param edid the edid structure + * @param edid_length length of the edid structure + * @return The interface type. + */ +EAPI Ecore_X_Randr_Edid_Display_Interface_Type ecore_x_randr_edid_display_interface_type_get(unsigned char *edid, unsigned long edid_length); + +/* ecore_x_randr_12.c */ + +EAPI Eina_Bool ecore_x_randr_output_backlight_available(void); +EAPI void ecore_x_randr_screen_backlight_level_set(Ecore_X_Window root, double level); +EAPI double ecore_x_randr_output_backlight_level_get(Ecore_X_Window root, Ecore_X_Randr_Output output); +EAPI Eina_Bool ecore_x_randr_output_backlight_level_set(Ecore_X_Window root, Ecore_X_Randr_Output output, double level); +EAPI Ecore_X_Randr_Output ecore_x_randr_primary_output_get(Ecore_X_Window root); +EAPI void ecore_x_randr_primary_output_set(Ecore_X_Window root, Ecore_X_Randr_Output output); +EAPI Ecore_X_Render_Subpixel_Order ecore_x_randr_output_subpixel_order_get(Ecore_X_Window root, Ecore_X_Randr_Output output); +EAPI unsigned char *ecore_x_randr_output_edid_get(Ecore_X_Window root, Ecore_X_Randr_Output output, unsigned long *length); +EAPI Ecore_X_Randr_Output *ecore_x_randr_output_wired_clones_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num); +EAPI Ecore_X_Randr_Output **ecore_x_randr_output_compatibility_list_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num); +EAPI Ecore_X_Randr_Signal_Format *ecore_x_randr_output_signal_formats_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num); +EAPI Eina_Bool ecore_x_randr_output_signal_format_set(Ecore_X_Window root, Ecore_X_Randr_Output output, Ecore_X_Randr_Signal_Format *signal); +EAPI Ecore_X_Randr_Signal_Property *ecore_x_randr_output_signal_properties_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *num); +EAPI int ecore_x_randr_output_connector_number_get(Ecore_X_Window root, Ecore_X_Randr_Output output); +EAPI Ecore_X_Randr_Connector_Type ecore_x_randr_output_connector_type_get(Ecore_X_Window root, Ecore_X_Randr_Output output); +/* WTF - these dont exist in ecore-x!!!! +EAPI Eina_Rectangle *ecore_x_randr_crtc_panning_area_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *x, int *y, int *w, int *h); +EAPI Eina_Bool ecore_x_randr_crtc_panning_area_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int x, const int y, const int w, const int h); +EAPI Eina_Rectangle *ecore_x_randr_crtc_tracking_area_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int *x, int *y, int *w, int *h); +EAPI Eina_Bool ecore_x_randr_crtc_tracking_area_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int x, const int y, const int w, const int h); +EAPI Eina_Rectangle *ecore_x_randr_crtc_border_area_get(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc); +EAPI Eina_Bool ecore_x_randr_crtc_border_area_set(Ecore_X_Window root, Ecore_X_Randr_Crtc crtc, int left, const int top, const int right, const int bottom); +*/ + +/* XRender Support (horrendously incomplete) */ +typedef Ecore_X_ID Ecore_X_Picture; + +/* XFixes Extension Support */ +typedef Ecore_X_ID Ecore_X_Region; + +typedef enum _Ecore_X_Region_Type +{ + ECORE_X_REGION_BOUNDING, + ECORE_X_REGION_CLIP +} Ecore_X_Region_Type; + +EAPI Ecore_X_Region ecore_x_region_new(Ecore_X_Rectangle *rects, int num); +EAPI Ecore_X_Region ecore_x_region_new_from_bitmap(Ecore_X_Pixmap bitmap); +EAPI Ecore_X_Region ecore_x_region_new_from_window(Ecore_X_Window win, Ecore_X_Region_Type type); +EAPI Ecore_X_Region ecore_x_region_new_from_gc(Ecore_X_GC gc); +EAPI Ecore_X_Region ecore_x_region_new_from_picture(Ecore_X_Picture picture); +EAPI void ecore_x_region_free(Ecore_X_Region region); +EAPI void ecore_x_region_set(Ecore_X_Region region, Ecore_X_Rectangle *rects, int num); +EAPI void ecore_x_region_copy(Ecore_X_Region dest, Ecore_X_Region source); +EAPI void ecore_x_region_combine(Ecore_X_Region dest, Ecore_X_Region source1, Ecore_X_Region source2); +EAPI void ecore_x_region_intersect(Ecore_X_Region dest, Ecore_X_Region source1, Ecore_X_Region source2); +EAPI void ecore_x_region_subtract(Ecore_X_Region dest, Ecore_X_Region source1, Ecore_X_Region source2); +EAPI void ecore_x_region_invert(Ecore_X_Region dest, Ecore_X_Rectangle *bounds, Ecore_X_Region source); +EAPI void ecore_x_region_translate(Ecore_X_Region region, int dx, int dy); +EAPI void ecore_x_region_extents(Ecore_X_Region dest, Ecore_X_Region source); +EAPI Ecore_X_Rectangle *ecore_x_region_fetch(Ecore_X_Region region, int *num, Ecore_X_Rectangle *bounds); +EAPI void ecore_x_region_expand(Ecore_X_Region dest, Ecore_X_Region source, unsigned int left, unsigned int right, unsigned int top, unsigned int bottom); +EAPI void ecore_x_region_gc_clip_set(Ecore_X_Region region, Ecore_X_GC gc, int x_origin, int y_origin); +EAPI void ecore_x_region_window_shape_set(Ecore_X_Region region, Ecore_X_Window win, Ecore_X_Shape_Type type, int x_offset, int y_offset); +EAPI void ecore_x_region_picture_clip_set(Ecore_X_Region region, Ecore_X_Picture picture, int x_origin, int y_origin); + +/** + * xfixes selection notification request. + * + * This lets you choose which selections you want to get notifications for. + * @param selection The selection atom. + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * @since 1.1.0 + */ +EAPI Eina_Bool ecore_x_fixes_selection_notification_request(Ecore_X_Atom selection); + +/* XComposite Extension Support */ +EAPI Eina_Bool ecore_x_composite_query(void); +EAPI void ecore_x_composite_redirect_window(Ecore_X_Window win, Ecore_X_Composite_Update_Type type); +EAPI void ecore_x_composite_redirect_subwindows(Ecore_X_Window win, Ecore_X_Composite_Update_Type type); +EAPI void ecore_x_composite_unredirect_window(Ecore_X_Window win, Ecore_X_Composite_Update_Type type); +EAPI void ecore_x_composite_unredirect_subwindows(Ecore_X_Window win, Ecore_X_Composite_Update_Type type); +EAPI Ecore_X_Pixmap ecore_x_composite_name_window_pixmap_get(Ecore_X_Window win); +EAPI void ecore_x_composite_window_events_disable(Ecore_X_Window win); +EAPI void ecore_x_composite_window_events_enable(Ecore_X_Window win); +EAPI Ecore_X_Window ecore_x_composite_render_window_enable(Ecore_X_Window root); +EAPI void ecore_x_composite_render_window_disable(Ecore_X_Window root); + +/* XDamage Extension Support */ +typedef Ecore_X_ID Ecore_X_Damage; + +typedef enum _Ecore_X_Damage_Report_Level +{ + ECORE_X_DAMAGE_REPORT_RAW_RECTANGLES, + ECORE_X_DAMAGE_REPORT_DELTA_RECTANGLES, + ECORE_X_DAMAGE_REPORT_BOUNDING_BOX, + ECORE_X_DAMAGE_REPORT_NON_EMPTY +} Ecore_X_Damage_Report_Level; + +struct _Ecore_X_Event_Damage +{ + Ecore_X_Damage_Report_Level level; + Ecore_X_Drawable drawable; + Ecore_X_Damage damage; + int more; + Ecore_X_Time time; + Ecore_X_Rectangle area; + Ecore_X_Rectangle geometry; +}; + +typedef struct _Ecore_X_Event_Damage Ecore_X_Event_Damage; + +struct _Ecore_X_Event_Xkb +{ + int group; +}; +typedef struct _Ecore_X_Event_Xkb Ecore_X_Event_Xkb; /** @since 1.7 */ + +EAPI Eina_Bool ecore_x_damage_query(void); +EAPI Ecore_X_Damage ecore_x_damage_new(Ecore_X_Drawable d, Ecore_X_Damage_Report_Level level); +EAPI void ecore_x_damage_free(Ecore_X_Damage damage); +EAPI void ecore_x_damage_subtract(Ecore_X_Damage damage, Ecore_X_Region repair, Ecore_X_Region parts); + +EAPI Eina_Bool ecore_x_screen_is_composited(int screen); +EAPI void ecore_x_screen_is_composited_set(int screen, Ecore_X_Window win); + +EAPI Eina_Bool ecore_x_dpms_query(void); +EAPI Eina_Bool ecore_x_dpms_capable_get(void); +EAPI Eina_Bool ecore_x_dpms_enabled_get(void); +EAPI void ecore_x_dpms_enabled_set(int enabled); +EAPI void ecore_x_dpms_timeouts_get(unsigned int *standby, unsigned int *suspend, unsigned int *off); +EAPI Eina_Bool ecore_x_dpms_timeouts_set(unsigned int standby, unsigned int suspend, unsigned int off); +EAPI unsigned int ecore_x_dpms_timeout_standby_get(void); +EAPI unsigned int ecore_x_dpms_timeout_suspend_get(void); +EAPI unsigned int ecore_x_dpms_timeout_off_get(void); +EAPI void ecore_x_dpms_timeout_standby_set(unsigned int new_timeout); +EAPI void ecore_x_dpms_timeout_suspend_set(unsigned int new_timeout); +EAPI void ecore_x_dpms_timeout_off_set(unsigned int new_timeout); + +EAPI Eina_Bool ecore_x_test_fake_key_down(const char *key); +EAPI Eina_Bool ecore_x_test_fake_key_up(const char *key); +EAPI Eina_Bool ecore_x_test_fake_key_press(const char *key); +EAPI const char *ecore_x_keysym_string_get(int keysym); + +/** + * Given a keyname, return the keycode representing that key + * @param keyname The key from which to get the keycode. + * @return The keycode of the key. + * + * @since 1.2.0 + */ +EAPI int ecore_x_keysym_keycode_get(const char *keyname); + +typedef struct _Ecore_X_Image Ecore_X_Image; + +EAPI Ecore_X_Image *ecore_x_image_new(int w, int h, Ecore_X_Visual vis, int depth); +EAPI void ecore_x_image_free(Ecore_X_Image *im); +EAPI Eina_Bool ecore_x_image_get(Ecore_X_Image *im, Ecore_X_Drawable draw, int x, int y, int sx, int sy, int w, int h); +EAPI void ecore_x_image_put(Ecore_X_Image *im, Ecore_X_Drawable draw, Ecore_X_GC gc, int x, int y, int sx, int sy, int w, int h); +EAPI void *ecore_x_image_data_get(Ecore_X_Image *im, int *bpl, int *rows, int *bpp); +EAPI Eina_Bool ecore_x_image_is_argb32_get(Ecore_X_Image *im); + +EAPI Eina_Bool ecore_x_image_to_argb_convert(void *src, int sbpp, int sbpl, Ecore_X_Colormap c, Ecore_X_Visual v, int x, int y, int w, int h, unsigned int *dst, int dbpl, int dx, int dy); + +EAPI Eina_Bool ecore_x_input_multi_select(Ecore_X_Window win); + +EAPI Eina_Bool ecore_x_vsync_animator_tick_source_set(Ecore_X_Window win); + +typedef enum _Ecore_X_Gesture_Event_Mask +{ + ECORE_X_GESTURE_EVENT_MASK_NONE = 0L, + ECORE_X_GESTURE_EVENT_MASK_FLICK = (1L << 0), + ECORE_X_GESTURE_EVENT_MASK_PAN = (1L << 1), + ECORE_X_GESTURE_EVENT_MASK_PINCHROTATION = (1L << 2), + ECORE_X_GESTURE_EVENT_MASK_TAP = (1L << 3), + ECORE_X_GESTURE_EVENT_MASK_TAPNHOLD = (1L << 4), + ECORE_X_GESTURE_EVENT_MASK_HOLD = (1L << 5), + ECORE_X_GESTURE_EVENT_MASK_GROUP = (1L << 6) +} Ecore_X_Gesture_Event_Mask; + +typedef enum _Ecore_X_Gesture_Event_Type +{ + ECORE_X_GESTURE_EVENT_FLICK, + ECORE_X_GESTURE_EVENT_PAN, + ECORE_X_GESTURE_EVENT_PINCHROTATION, + ECORE_X_GESTURE_EVENT_TAP, + ECORE_X_GESTURE_EVENT_TAPNHOLD, + ECORE_X_GESTURE_EVENT_HOLD, + ECORE_X_GESTURE_EVENT_GROUP +} Ecore_X_Gesture_Event_Type; + +typedef enum _Ecore_X_Gesture_Event_Subtype +{ + ECORE_X_GESTURE_END, + ECORE_X_GESTURE_BEGIN, + ECORE_X_GESTURE_UPDATE, + ECORE_X_GESTURE_DONE +} Ecore_X_Gesture_Event_Subtype; + +typedef enum _Ecore_X_Gesture_Group_Subtype +{ + ECORE_X_GESTURE_GROUP_REMOVED, + ECORE_X_GESTURE_GROUP_ADDED, + ECORE_X_GESTURE_GROUP_CURRENT +} Ecore_X_Gesture_Group_Subtype; + +typedef enum _Ecore_X_Gesture_Direction +{ + ECORE_X_GESTURE_NORTHWARD, + ECORE_X_GESTURE_NORTHEASTWARD, + ECORE_X_GESTURE_EASTWARD, + ECORE_X_GESTURE_SOUTHEASTWARD, + ECORE_X_GESTURE_SOUTHWARD, + ECORE_X_GESTURE_SOUTHWESTWARD, + ECORE_X_GESTURE_WESTWARD, + ECORE_X_GESTURE_NORTHWESTWARD +} Ecore_X_Gesture_Direction; + +struct _Ecore_X_Event_Gesture_Notify_Flick +{ + Ecore_X_Window win; + Ecore_X_Time time; + Ecore_X_Gesture_Event_Subtype subtype; + int num_fingers; + int distance; + Ecore_X_Time duration; + Ecore_X_Gesture_Direction direction; + double angle; +}; + +struct _Ecore_X_Event_Gesture_Notify_Pan +{ + Ecore_X_Window win; + Ecore_X_Time time; + Ecore_X_Gesture_Event_Subtype subtype; + int num_fingers; + int dx; + int dy; + int distance; + Ecore_X_Time duration; + Ecore_X_Gesture_Direction direction; +}; + +struct _Ecore_X_Event_Gesture_Notify_PinchRotation +{ + Ecore_X_Window win; + Ecore_X_Time time; + Ecore_X_Gesture_Event_Subtype subtype; + int num_fingers; + int distance; + int cx; + int cy; + double zoom; + double angle; +}; + +struct _Ecore_X_Event_Gesture_Notify_Tap +{ + Ecore_X_Window win; + Ecore_X_Time time; + Ecore_X_Gesture_Event_Subtype subtype; + int num_fingers; + int cx; + int cy; + int tap_repeat; + Ecore_X_Time interval; +}; + +struct _Ecore_X_Event_Gesture_Notify_TapNHold +{ + Ecore_X_Window win; + Ecore_X_Time time; + Ecore_X_Gesture_Event_Subtype subtype; + int num_fingers; + int cx; + int cy; + Ecore_X_Time interval; + Ecore_X_Time hold_time; +}; + +struct _Ecore_X_Event_Gesture_Notify_Hold +{ + Ecore_X_Window win; + Ecore_X_Time time; + Ecore_X_Gesture_Event_Subtype subtype; + int num_fingers; + int cx; + int cy; + Ecore_X_Time hold_time; +}; + +struct _Ecore_X_Event_Gesture_Notify_Group +{ + Ecore_X_Window win; + Ecore_X_Time time; + Ecore_X_Gesture_Group_Subtype subtype; + int num_groups; + int group_id; +}; + +EAPI Eina_Bool ecore_x_gesture_supported(void); + +EAPI Eina_Bool ecore_x_gesture_events_select(Ecore_X_Window win, Ecore_X_Gesture_Event_Mask mask); + +EAPI Ecore_X_Gesture_Event_Mask ecore_x_gesture_events_selected_get(Ecore_X_Window win); + +EAPI Eina_Bool ecore_x_gesture_event_grab(Ecore_X_Window win, Ecore_X_Gesture_Event_Type type, int num_fingers); + +EAPI Eina_Bool ecore_x_gesture_event_ungrab(Ecore_X_Window win, Ecore_X_Gesture_Event_Type type, int num_fingers); + +EAPI void ecore_x_e_illume_indicator_state_set(Ecore_X_Window win, Ecore_X_Illume_Indicator_State state); +EAPI Ecore_X_Illume_Indicator_State ecore_x_e_illume_indicator_state_get(Ecore_X_Window win); +EAPI void ecore_x_e_illume_indicator_state_send(Ecore_X_Window win, Ecore_X_Illume_Indicator_State state); + +EAPI void ecore_x_e_illume_indicator_opacity_set(Ecore_X_Window win, Ecore_X_Illume_Indicator_Opacity_Mode mode); + +EAPI Ecore_X_Illume_Indicator_Opacity_Mode ecore_x_e_illume_indicator_opacity_get(Ecore_X_Window win); + +EAPI void ecore_x_e_illume_indicator_opacity_send(Ecore_X_Window win, Ecore_X_Illume_Indicator_Opacity_Mode mode); + +EAPI void +ecore_x_e_illume_window_state_set(Ecore_X_Window win, + Ecore_X_Illume_Window_State state); + +EAPI Ecore_X_Illume_Window_State ecore_x_e_illume_window_state_get(Ecore_X_Window win); +EAPI void ecore_x_xkb_select_group(int group); /* @since 1.7 */ + +#ifdef __cplusplus +} +#endif // ifdef __cplusplus + +#include +#include + +#endif // ifndef _ECORE_X_H diff --git a/src/lib/ecore_x/Ecore_X_Atoms.h b/src/lib/ecore_x/Ecore_X_Atoms.h new file mode 100644 index 0000000..c9af5bf --- /dev/null +++ b/src/lib/ecore_x/Ecore_X_Atoms.h @@ -0,0 +1,290 @@ +#ifndef _ECORE_X_ATOMS_H +#define _ECORE_X_ATOMS_H + +/** + * @file + * @brief Ecore X atoms + */ + +/* generic atoms */ +EAPI extern Ecore_X_Atom ECORE_X_ATOM_ATOM; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_CARDINAL; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_COMPOUND_TEXT; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_FILE_NAME; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_STRING; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_TEXT; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_UTF8_STRING; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_WINDOW; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_PIXMAP; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_VISUALID; + +/* dnd atoms */ +EAPI extern Ecore_X_Atom ECORE_X_ATOM_SELECTION_XDND; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_SELECTION_PROP_XDND; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_AWARE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_ENTER; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_TYPE_LIST; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_POSITION; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_COPY; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_MOVE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_PRIVATE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_ASK; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_LIST; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_LINK; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_DESCRIPTION; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_PROXY; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_STATUS; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_LEAVE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_DROP; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_XDND_FINISHED; + +/* dnd atoms that need to be exposed to the application interface */ +EAPI extern Ecore_X_Atom ECORE_X_DND_ACTION_COPY; +EAPI extern Ecore_X_Atom ECORE_X_DND_ACTION_MOVE; +EAPI extern Ecore_X_Atom ECORE_X_DND_ACTION_LINK; +EAPI extern Ecore_X_Atom ECORE_X_DND_ACTION_ASK; +EAPI extern Ecore_X_Atom ECORE_X_DND_ACTION_PRIVATE; + +/* old E atom */ +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_FRAME_SIZE; + +/* old Gnome atom */ +EAPI extern Ecore_X_Atom ECORE_X_ATOM_WIN_LAYER; + +/* ICCCM: client properties */ +EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_NAME; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_ICON_NAME; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_NORMAL_HINTS; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_SIZE_HINTS; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_HINTS; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_CLASS; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_TRANSIENT_FOR; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_PROTOCOLS; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_COLORMAP_WINDOWS; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_COMMAND; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_CLIENT_MACHINE; + +/* ICCCM: window manager properties */ +EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_STATE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_ICON_SIZE; + +/* ICCCM: WM_STATEproperty */ +EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_CHANGE_STATE; + +/* ICCCM: WM_PROTOCOLS properties */ +EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_TAKE_FOCUS; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_SAVE_YOURSELF; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_DELETE_WINDOW; + +/* ICCCM: WM_COLORMAP properties */ +EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_COLORMAP_NOTIFY; + +/* ICCCM: session management properties */ +EAPI extern Ecore_X_Atom ECORE_X_ATOM_SM_CLIENT_ID; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_CLIENT_LEADER; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_WM_WINDOW_ROLE; + +/* Motif WM atom */ +EAPI extern Ecore_X_Atom ECORE_X_ATOM_MOTIF_WM_HINTS; + +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_SUPPORTED; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_CLIENT_LIST; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_CLIENT_LIST_STACKING; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_NUMBER_OF_DESKTOPS; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_DESKTOP_GEOMETRY; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_DESKTOP_VIEWPORT; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_CURRENT_DESKTOP; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_DESKTOP_NAMES; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_ACTIVE_WINDOW; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WORKAREA; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_VIRTUAL_ROOTS; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_DESKTOP_LAYOUT; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_SHOWING_DESKTOP; + +/* pager */ +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_CLOSE_WINDOW; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_MOVERESIZE_WINDOW; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_MOVERESIZE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_RESTACK_WINDOW; + +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_REQUEST_FRAME_EXTENTS; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_NAME; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_VISIBLE_NAME; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ICON_NAME; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_DESKTOP; + +/* window type */ +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DESKTOP; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DOCK; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_MENU; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_UTILITY; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_SPLASH; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DIALOG; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NORMAL; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DROPDOWN_MENU; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_POPUP_MENU; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLTIP; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_COMBO; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DND; + +/* state */ +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_MODAL; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_STICKY; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_SHADED; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_SKIP_TASKBAR; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_SKIP_PAGER; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_HIDDEN; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_ABOVE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_BELOW; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_DEMANDS_ATTENTION; + +/* allowed actions */ +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_MOVE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_RESIZE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_MINIMIZE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_SHADE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_STICK; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_HORZ; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_VERT; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_FULLSCREEN; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_CHANGE_DESKTOP; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_CLOSE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_ABOVE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_BELOW; + +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STRUT; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_STRUT_PARTIAL; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ICON_GEOMETRY; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_ICON; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_PID; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_HANDLED_ICONS; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_USER_TIME; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_STARTUP_ID; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_FRAME_EXTENTS; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_PING; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_SYNC_REQUEST; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_OPACITY; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_SHADOW; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_SHADE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_STARTUP_INFO_BEGIN; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_NET_STARTUP_INFO; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_SELECTION_TARGETS; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_SELECTION_PRIMARY; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_SELECTION_SECONDARY; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_SELECTION_CLIPBOARD; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_SELECTION_PROP_PRIMARY; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_SELECTION_PROP_SECONDARY; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_SELECTION_PROP_CLIPBOARD; + +/* currently E specific virtual keyboard extension, aim to submit to netwm spec + * later */ + +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ALPHA; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_NUMERIC; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PIN; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PHONE_NUMBER; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HEX; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_TERMINAL; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PASSWORD; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_IP; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HOST; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_FILE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_URL; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_KEYPAD; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_J2ME; + +/* Illume specific atoms */ +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ZONE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ZONE_LIST; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CONFORMANT; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_MODE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_MODE_SINGLE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_MODE_DUAL_TOP; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_MODE_DUAL_LEFT; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_FOCUS_BACK; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_FOCUS_FORWARD; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_FOCUS_HOME; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_HOME_NEW; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_HOME_DEL; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CLOSE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_DRAG; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_DRAG_LOCKED; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_DRAG_START; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_DRAG_END; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_GEOMETRY; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_SOFTKEY_GEOMETRY; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_KEYBOARD_GEOMETRY; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE_TOGGLE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ON; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_OFF; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MINOR; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ZONE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_POSITION_UPDATE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_STATE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_ON; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_OFF; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_OPACITY_MODE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_OPAQUE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSLUCENT; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSPARENT; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_AVAILABLE_ANGLE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ROTATE_ROOT_ANGLE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CLIPBOARD_STATE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CLIPBOARD_ON; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CLIPBOARD_OFF; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CLIPBOARD_GEOMETRY; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_WINDOW_STATE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_NORMAL; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_FLOATING; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_NEXT; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_PREV; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_ACTIVATE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_NEXT; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_PREV; + +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_COUNTER; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_DRAW_DONE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_BEGIN; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_END; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_CANCEL; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_COMP_FLUSH; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_COMP_DUMP; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_COMP_PIXMAP; + +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIDEO_PARENT; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIDEO_POSITION; + +/* currently elementary and E specific extension */ +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_PROFILE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_PROFILE_LIST; + +/* for sliding window */ +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_SLIDING_WIN_STATE; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_SLIDING_WIN_GEOMETRY; + +/* for SDB(Samsung Debug Bridge) */ +EAPI extern Ecore_X_Atom ECORE_X_ATOM_SDB_SERVER_CONNECT; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_SDB_SERVER_DISCONNECT; +#endif /* _ECORE_X_ATOMS_H */ diff --git a/src/lib/ecore_x/Ecore_X_Cursor.h b/src/lib/ecore_x/Ecore_X_Cursor.h new file mode 100644 index 0000000..807541e --- /dev/null +++ b/src/lib/ecore_x/Ecore_X_Cursor.h @@ -0,0 +1,87 @@ +#ifndef _ECORE_X_CURSOR_H +#define _ECORE_X_CURSOR_H + +/** + * @file + * @brief Defines the various cursor types for the X Windows system. + */ + +#define ECORE_X_CURSOR_X 0 +#define ECORE_X_CURSOR_ARROW 2 +#define ECORE_X_CURSOR_BASED_ARROW_DOWN 4 +#define ECORE_X_CURSOR_UP 6 +#define ECORE_X_CURSOR_BOAT 8 +#define ECORE_X_CURSOR_BOGOSITY 10 +#define ECORE_X_CURSOR_BOTTOM_LEFT_CORNER 12 +#define ECORE_X_CURSOR_BOTTOM_RIGHT_CORNER 14 +#define ECORE_X_CURSOR_BOTTOM_SIDE 16 +#define ECORE_X_CURSOR_BOTTOM_TEE 18 +#define ECORE_X_CURSOR_BOX_SPIRAL 20 +#define ECORE_X_CURSOR_CENTER_PTR 22 +#define ECORE_X_CURSOR_CIRCLE 24 +#define ECORE_X_CURSOR_CLOCK 26 +#define ECORE_X_CURSOR_COFFEE_MUG 28 +#define ECORE_X_CURSOR_CROSS 30 +#define ECORE_X_CURSOR_CROSS_REVERSE 32 +#define ECORE_X_CURSOR_CROSSHAIR 34 +#define ECORE_X_CURSOR_DIAMOND_CROSS 36 +#define ECORE_X_CURSOR_DOT 38 +#define ECORE_X_CURSOR_DOT_BOX_MASK 40 +#define ECORE_X_CURSOR_DOUBLE_ARROW 42 +#define ECORE_X_CURSOR_DRAFT_LARGE 44 +#define ECORE_X_CURSOR_DRAFT_SMALL 46 +#define ECORE_X_CURSOR_DRAPED_BOX 48 +#define ECORE_X_CURSOR_EXCHANGE 50 +#define ECORE_X_CURSOR_FLEUR 52 +#define ECORE_X_CURSOR_GOBBLER 54 +#define ECORE_X_CURSOR_GUMBY 56 +#define ECORE_X_CURSOR_HAND1 58 +#define ECORE_X_CURSOR_HAND2 60 +#define ECORE_X_CURSOR_HEART 62 +#define ECORE_X_CURSOR_ICON 64 +#define ECORE_X_CURSOR_IRON_CROSS 66 +#define ECORE_X_CURSOR_LEFT_PTR 68 +#define ECORE_X_CURSOR_LEFT_SIDE 70 +#define ECORE_X_CURSOR_LEFT_TEE 72 +#define ECORE_X_CURSOR_LEFTBUTTON 74 +#define ECORE_X_CURSOR_LL_ANGLE 76 +#define ECORE_X_CURSOR_LR_ANGLE 78 +#define ECORE_X_CURSOR_MAN 80 +#define ECORE_X_CURSOR_MIDDLEBUTTON 82 +#define ECORE_X_CURSOR_MOUSE 84 +#define ECORE_X_CURSOR_PENCIL 86 +#define ECORE_X_CURSOR_PIRATE 88 +#define ECORE_X_CURSOR_PLUS 90 +#define ECORE_X_CURSOR_QUESTION_ARROW 92 +#define ECORE_X_CURSOR_RIGHT_PTR 94 +#define ECORE_X_CURSOR_RIGHT_SIDE 96 +#define ECORE_X_CURSOR_RIGHT_TEE 98 +#define ECORE_X_CURSOR_RIGHTBUTTON 100 +#define ECORE_X_CURSOR_RTL_LOGO 102 +#define ECORE_X_CURSOR_SAILBOAT 104 +#define ECORE_X_CURSOR_SB_DOWN_ARROW 106 +#define ECORE_X_CURSOR_SB_H_DOUBLE_ARROW 108 +#define ECORE_X_CURSOR_SB_LEFT_ARROW 110 +#define ECORE_X_CURSOR_SB_RIGHT_ARROW 112 +#define ECORE_X_CURSOR_SB_UP_ARROW 114 +#define ECORE_X_CURSOR_SB_V_DOUBLE_ARROW 116 +#define ECORE_X_CURSOR_SHUTTLE 118 +#define ECORE_X_CURSOR_SIZING 120 +#define ECORE_X_CURSOR_SPIDER 122 +#define ECORE_X_CURSOR_SPRAYCAN 124 +#define ECORE_X_CURSOR_STAR 126 +#define ECORE_X_CURSOR_TARGET 128 +#define ECORE_X_CURSOR_TCROSS 130 +#define ECORE_X_CURSOR_TOP_LEFT_ARROW 132 +#define ECORE_X_CURSOR_TOP_LEFT_CORNER 134 +#define ECORE_X_CURSOR_TOP_RIGHT_CORNER 136 +#define ECORE_X_CURSOR_TOP_SIDE 138 +#define ECORE_X_CURSOR_TOP_TEE 140 +#define ECORE_X_CURSOR_TREK 142 +#define ECORE_X_CURSOR_UL_ANGLE 144 +#define ECORE_X_CURSOR_UMBRELLA 146 +#define ECORE_X_CURSOR_UR_ANGLE 148 +#define ECORE_X_CURSOR_WATCH 150 +#define ECORE_X_CURSOR_XTERM 152 + +#endif // ifndef _ECORE_X_CURSOR_H diff --git a/src/lib/ecore_x/Makefile.am b/src/lib/ecore_x/Makefile.am new file mode 100644 index 0000000..b14fc7d --- /dev/null +++ b/src/lib/ecore_x/Makefile.am @@ -0,0 +1,30 @@ +MAINTAINERCLEANFILES = Makefile.in + +SUBDIRS = xlib xcb + +if BUILD_ECORE_X_XCB +DEP = xcb/libecore_x_xcb.la +else +DEP = xlib/libecore_x_xlib.la +endif + +AM_CPPFLAGS = \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_builddir)/src/lib/ecore \ +@EINA_CFLAGS@ + +lib_LTLIBRARIES = libecore_x.la + +libecore_x_la_SOURCES = + +libecore_x_la_LIBADD = $(DEP) @EINA_LIBS@ +libecore_x_la_LDFLAGS = -version-info @version_info@ @release_info@ +libecore_x_la_DEPENDENCIES = $(DEP) + +includes_HEADERS = \ +Ecore_X.h \ +Ecore_X_Atoms.h \ +Ecore_X_Cursor.h +includesdir = $(includedir)/ecore-@VMAJ@ + +EXTRA_DIST = ecore_x_atoms_decl.h diff --git a/src/lib/ecore_x/ecore_x_atoms_decl.h b/src/lib/ecore_x/ecore_x_atoms_decl.h new file mode 100644 index 0000000..706fccd --- /dev/null +++ b/src/lib/ecore_x/ecore_x_atoms_decl.h @@ -0,0 +1,595 @@ +/* generic atoms */ +EAPI Ecore_X_Atom ECORE_X_ATOM_ATOM = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_CARDINAL = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_COMPOUND_TEXT = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_FILE_NAME = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_STRING = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_TEXT = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_UTF8_STRING = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_WINDOW = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_PIXMAP = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_VISUALID = 0; + +/* dnd atoms */ +EAPI Ecore_X_Atom ECORE_X_ATOM_SELECTION_PROP_XDND = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_SELECTION_XDND = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_AWARE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_ENTER = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_TYPE_LIST = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_POSITION = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_COPY = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_MOVE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_PRIVATE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_ASK = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_LIST = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_LINK = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_ACTION_DESCRIPTION = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_PROXY = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_STATUS = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_LEAVE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_DROP = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_XDND_FINISHED = 0; + +/* dnd atoms that need to be exposed to the application interface */ +EAPI Ecore_X_Atom ECORE_X_DND_ACTION_COPY = 0; +EAPI Ecore_X_Atom ECORE_X_DND_ACTION_MOVE = 0; +EAPI Ecore_X_Atom ECORE_X_DND_ACTION_LINK = 0; +EAPI Ecore_X_Atom ECORE_X_DND_ACTION_ASK = 0; +EAPI Ecore_X_Atom ECORE_X_DND_ACTION_PRIVATE = 0; + +/* old E atom */ +EAPI Ecore_X_Atom ECORE_X_ATOM_E_FRAME_SIZE = 0; + +/* old Gnome atom */ +EAPI Ecore_X_Atom ECORE_X_ATOM_WIN_LAYER = 0; + +/* ICCCM atoms */ + +/* ICCCM: client properties */ +EAPI Ecore_X_Atom ECORE_X_ATOM_WM_NAME = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_WM_ICON_NAME = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_WM_NORMAL_HINTS = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_WM_SIZE_HINTS = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_WM_HINTS = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_WM_CLASS = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_WM_TRANSIENT_FOR = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_WM_PROTOCOLS = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_WM_COLORMAP_WINDOWS = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_WM_COMMAND = 0; /* obsolete */ +EAPI Ecore_X_Atom ECORE_X_ATOM_WM_CLIENT_MACHINE = 0; /* obsolete */ + +/* ICCCM: window manager properties */ +EAPI Ecore_X_Atom ECORE_X_ATOM_WM_STATE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_WM_ICON_SIZE = 0; + +/* ICCCM: WM_STATE property */ +EAPI Ecore_X_Atom ECORE_X_ATOM_WM_CHANGE_STATE = 0; + +/* ICCCM: WM_PROTOCOLS properties */ +EAPI Ecore_X_Atom ECORE_X_ATOM_WM_TAKE_FOCUS = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_WM_SAVE_YOURSELF = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_WM_DELETE_WINDOW = 0; + +/* ICCCM: WM_COLORMAP properties */ +EAPI Ecore_X_Atom ECORE_X_ATOM_WM_COLORMAP_NOTIFY = 0; + +/* ICCCM: session management properties */ +EAPI Ecore_X_Atom ECORE_X_ATOM_SM_CLIENT_ID = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_WM_CLIENT_LEADER = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_WM_WINDOW_ROLE = 0; + +/* Motif WM atom */ +EAPI Ecore_X_Atom ECORE_X_ATOM_MOTIF_WM_HINTS = 0; + +/* NetWM 1.3 atoms (http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html) */ + +/* + * NetWM: Root Window Properties and related messages (complete) + */ + +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_SUPPORTED = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_CLIENT_LIST = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_CLIENT_LIST_STACKING = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_NUMBER_OF_DESKTOPS = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_DESKTOP_GEOMETRY = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_DESKTOP_VIEWPORT = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_CURRENT_DESKTOP = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_DESKTOP_NAMES = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_ACTIVE_WINDOW = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WORKAREA = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_VIRTUAL_ROOTS = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_DESKTOP_LAYOUT = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_SHOWING_DESKTOP = 0; + +/* + * NetWM: Other Root Window Messages (complete) + */ + +/* pager */ +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_CLOSE_WINDOW = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_MOVERESIZE_WINDOW = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_MOVERESIZE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_RESTACK_WINDOW = 0; + +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_REQUEST_FRAME_EXTENTS = 0; + +/* + * NetWM: Application Window Properties (complete) + */ + +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_NAME = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_VISIBLE_NAME = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ICON_NAME = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_DESKTOP = 0; + +/* window type */ +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DESKTOP = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DOCK = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_MENU = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_UTILITY = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_SPLASH = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DIALOG = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NORMAL = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DROPDOWN_MENU = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_POPUP_MENU = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLTIP = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_COMBO = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DND = 0; + +/* state */ +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_MODAL = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_STICKY = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_SHADED = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_SKIP_TASKBAR = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_SKIP_PAGER = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_HIDDEN = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_ABOVE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_BELOW = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STATE_DEMANDS_ATTENTION = 0; + +/* allowed actions */ +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_MOVE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_RESIZE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_MINIMIZE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_SHADE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_STICK = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_HORZ = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_VERT = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_FULLSCREEN = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_CHANGE_DESKTOP = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_CLOSE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_ABOVE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ACTION_BELOW = 0; + +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STRUT = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_STRUT_PARTIAL = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ICON_GEOMETRY = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_ICON = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_PID = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_HANDLED_ICONS = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_USER_TIME = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_STARTUP_ID = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_FRAME_EXTENTS = 0; + +/* + * NetWM: Window Manager Protocols (complete) + */ + +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_PING = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_SYNC_REQUEST = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER = 0; + +/* + * NetWM: Not in the spec + */ + +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_OPACITY = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_SHADOW = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_WM_WINDOW_SHADE = 0; + +/* + * Startup Notification (http://standards.freedesktop.org/startup-notification-spec/startup-notification-0.1.txt) + */ + +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_STARTUP_INFO_BEGIN = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_NET_STARTUP_INFO = 0; + +/* selection atoms */ +EAPI Ecore_X_Atom ECORE_X_ATOM_SELECTION_TARGETS = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_SELECTION_PRIMARY = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_SELECTION_SECONDARY = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_SELECTION_CLIPBOARD = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_SELECTION_PROP_PRIMARY = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_SELECTION_PROP_SECONDARY = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_SELECTION_PROP_CLIPBOARD = 0; + +/* currently E specific virtual keyboard extension, aim to submit to netwm spec + * later */ + +EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ALPHA = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_NUMERIC = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PIN = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PHONE_NUMBER = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HEX = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_TERMINAL = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PASSWORD = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_IP = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HOST = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_FILE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_URL = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_KEYPAD = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_J2ME = 0; + +/* currently E specific illume extension */ +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ZONE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ZONE_LIST = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CONFORMANT = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_MODE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_MODE_SINGLE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_MODE_DUAL_TOP = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_MODE_DUAL_LEFT = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_FOCUS_BACK = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_FOCUS_FORWARD = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_FOCUS_HOME = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CLOSE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_HOME_NEW = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_HOME_DEL = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_DRAG = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_DRAG_LOCKED = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_DRAG_START = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_DRAG_END = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_GEOMETRY = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_SOFTKEY_GEOMETRY = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_KEYBOARD_GEOMETRY = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE_TOGGLE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ON = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_OFF = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MINOR = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ZONE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_QUICKPANEL_POSITION_UPDATE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_STATE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_ON = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_OFF = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_OPACITY_MODE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_OPAQUE= 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSLUCENT = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSPARENT = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_AVAILABLE_ANGLE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ROTATE_ROOT_ANGLE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CLIPBOARD_STATE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CLIPBOARD_GEOMETRY = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CLIPBOARD_ON = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_CLIPBOARD_OFF = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_WINDOW_STATE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_NORMAL = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_FLOATING = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_NEXT = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_PREV = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_ACTIVATE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_NEXT = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_PREV = 0; + +EAPI Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_COUNTER = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_DRAW_DONE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_BEGIN = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_END = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_COMP_SYNC_CANCEL = 0; + +EAPI Ecore_X_Atom ECORE_X_ATOM_E_COMP_FLUSH = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_COMP_DUMP = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_COMP_PIXMAP = 0; + +/* currently Emotion and E17 specific extension */ +EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIDEO_PARENT = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIDEO_POSITION = 0; + +/* for sliding window */ +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_SLIDING_WIN_STATE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_SLIDING_WIN_GEOMETRY = 0; + +/* for SDB(Samsung Debug Bridge) */ +EAPI Ecore_X_Atom ECORE_X_ATOM_SDB_SERVER_CONNECT = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_SDB_SERVER_DISCONNECT = 0; + +/* currently elementary and E specific extension */ +EAPI Ecore_X_Atom ECORE_X_ATOM_E_PROFILE = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_PROFILE_LIST = 0; + +typedef struct _Atom_Item Atom_Item; + +struct _Atom_Item +{ + const char *name; + Ecore_X_Atom *atom; +}; + +const Atom_Item atom_items[] = +{ + { "ATOM", &ECORE_X_ATOM_ATOM }, + { "CARDINAL", &ECORE_X_ATOM_CARDINAL }, + { "COMPOUND_TEXT", &ECORE_X_ATOM_COMPOUND_TEXT }, + { "FILE_NAME", &ECORE_X_ATOM_FILE_NAME }, + { "STRING", &ECORE_X_ATOM_STRING }, + { "TEXT", &ECORE_X_ATOM_TEXT }, + { "UTF8_STRING", &ECORE_X_ATOM_UTF8_STRING }, + { "WINDOW", &ECORE_X_ATOM_WINDOW }, + { "PIXMAP", &ECORE_X_ATOM_PIXMAP }, + { "VISUALID", &ECORE_X_ATOM_VISUALID }, + + { "JXSelectionWindowProperty", &ECORE_X_ATOM_SELECTION_PROP_XDND }, + { "XdndSelection", &ECORE_X_ATOM_SELECTION_XDND }, + { "XdndAware", &ECORE_X_ATOM_XDND_AWARE }, + { "XdndEnter", &ECORE_X_ATOM_XDND_ENTER }, + { "XdndTypeList", &ECORE_X_ATOM_XDND_TYPE_LIST }, + { "XdndPosition", &ECORE_X_ATOM_XDND_POSITION }, + { "XdndActionCopy", &ECORE_X_ATOM_XDND_ACTION_COPY }, + { "XdndActionMove", &ECORE_X_ATOM_XDND_ACTION_MOVE }, + { "XdndActionPrivate", &ECORE_X_ATOM_XDND_ACTION_PRIVATE }, + { "XdndActionAsk", &ECORE_X_ATOM_XDND_ACTION_ASK }, + { "XdndActionList", &ECORE_X_ATOM_XDND_ACTION_LIST }, + { "XdndActionLink", &ECORE_X_ATOM_XDND_ACTION_LINK }, + { "XdndActionDescription", &ECORE_X_ATOM_XDND_ACTION_DESCRIPTION }, + { "XdndProxy", &ECORE_X_ATOM_XDND_PROXY }, + { "XdndStatus", &ECORE_X_ATOM_XDND_STATUS }, + { "XdndLeave", &ECORE_X_ATOM_XDND_LEAVE }, + { "XdndDrop", &ECORE_X_ATOM_XDND_DROP }, + { "XdndFinished", &ECORE_X_ATOM_XDND_FINISHED }, + + { "XdndActionCopy", &ECORE_X_DND_ACTION_COPY }, + { "XdndActionMove", &ECORE_X_DND_ACTION_MOVE }, + { "XdndActionLink", &ECORE_X_DND_ACTION_LINK }, + { "XdndActionAsk", &ECORE_X_DND_ACTION_ASK }, + { "XdndActionPrivate", &ECORE_X_DND_ACTION_PRIVATE }, + + { "_E_FRAME_SIZE", &ECORE_X_ATOM_E_FRAME_SIZE }, + + { "_WIN_LAYER", &ECORE_X_ATOM_WIN_LAYER }, + + { "WM_NAME", &ECORE_X_ATOM_WM_NAME }, + { "WM_ICON_NAME", &ECORE_X_ATOM_WM_ICON_NAME }, + { "WM_NORMAL_HINTS", &ECORE_X_ATOM_WM_NORMAL_HINTS }, + { "WM_SIZE_HINTS", &ECORE_X_ATOM_WM_SIZE_HINTS }, + { "WM_HINTS", &ECORE_X_ATOM_WM_HINTS }, + { "WM_CLASS", &ECORE_X_ATOM_WM_CLASS }, + { "WM_TRANSIENT_FOR", &ECORE_X_ATOM_WM_TRANSIENT_FOR }, + { "WM_PROTOCOLS", &ECORE_X_ATOM_WM_PROTOCOLS }, + { "WM_COLORMAP_WINDOWS", &ECORE_X_ATOM_WM_COLORMAP_WINDOWS }, + { "WM_COMMAND", &ECORE_X_ATOM_WM_COMMAND }, + { "WM_CLIENT_MACHINE", &ECORE_X_ATOM_WM_CLIENT_MACHINE }, + + { "WM_STATE", &ECORE_X_ATOM_WM_STATE }, + { "WM_ICON_SIZE", &ECORE_X_ATOM_WM_ICON_SIZE }, + + { "WM_CHANGE_STATE", &ECORE_X_ATOM_WM_CHANGE_STATE }, + + { "WM_TAKE_FOCUS", &ECORE_X_ATOM_WM_TAKE_FOCUS }, + { "WM_SAVE_YOURSELF", &ECORE_X_ATOM_WM_SAVE_YOURSELF }, + { "WM_DELETE_WINDOW", &ECORE_X_ATOM_WM_DELETE_WINDOW }, + + { "WM_COLORMAP_NOTIFY", &ECORE_X_ATOM_WM_COLORMAP_NOTIFY }, + + { "SM_CLIENT_ID", &ECORE_X_ATOM_SM_CLIENT_ID }, + { "WM_CLIENT_LEADER", &ECORE_X_ATOM_WM_CLIENT_LEADER }, + { "WM_WINDOW_ROLE", &ECORE_X_ATOM_WM_WINDOW_ROLE }, + + { "_MOTIF_WM_HINTS", &ECORE_X_ATOM_MOTIF_WM_HINTS }, + + { "_NET_SUPPORTED", &ECORE_X_ATOM_NET_SUPPORTED }, + { "_NET_CLIENT_LIST", &ECORE_X_ATOM_NET_CLIENT_LIST }, + { "_NET_CLIENT_LIST_STACKING", &ECORE_X_ATOM_NET_CLIENT_LIST_STACKING }, + { "_NET_NUMBER_OF_DESKTOPS", &ECORE_X_ATOM_NET_NUMBER_OF_DESKTOPS }, + { "_NET_DESKTOP_GEOMETRY", &ECORE_X_ATOM_NET_DESKTOP_GEOMETRY }, + { "_NET_DESKTOP_VIEWPORT", &ECORE_X_ATOM_NET_DESKTOP_VIEWPORT }, + { "_NET_CURRENT_DESKTOP", &ECORE_X_ATOM_NET_CURRENT_DESKTOP }, + { "_NET_DESKTOP_NAMES", &ECORE_X_ATOM_NET_DESKTOP_NAMES }, + { "_NET_ACTIVE_WINDOW", &ECORE_X_ATOM_NET_ACTIVE_WINDOW }, + { "_NET_WORKAREA", &ECORE_X_ATOM_NET_WORKAREA }, + { "_NET_SUPPORTING_WM_CHECK", &ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK }, + { "_NET_VIRTUAL_ROOTS", &ECORE_X_ATOM_NET_VIRTUAL_ROOTS }, + { "_NET_DESKTOP_LAYOUT", &ECORE_X_ATOM_NET_DESKTOP_LAYOUT }, + { "_NET_SHOWING_DESKTOP", &ECORE_X_ATOM_NET_SHOWING_DESKTOP }, + + { "_NET_CLOSE_WINDOW", &ECORE_X_ATOM_NET_CLOSE_WINDOW }, + { "_NET_MOVERESIZE_WINDOW", &ECORE_X_ATOM_NET_MOVERESIZE_WINDOW }, + { "_NET_WM_MOVERESIZE", &ECORE_X_ATOM_NET_WM_MOVERESIZE }, + { "_NET_RESTACK_WINDOW", &ECORE_X_ATOM_NET_RESTACK_WINDOW }, + + { "_NET_REQUEST_FRAME_EXTENTS", &ECORE_X_ATOM_NET_REQUEST_FRAME_EXTENTS }, + + { "_NET_WM_NAME", &ECORE_X_ATOM_NET_WM_NAME }, + { "_NET_WM_VISIBLE_NAME", &ECORE_X_ATOM_NET_WM_VISIBLE_NAME }, + { "_NET_WM_ICON_NAME", &ECORE_X_ATOM_NET_WM_ICON_NAME }, + { "_NET_WM_VISIBLE_ICON_NAME", &ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME }, + { "_NET_WM_DESKTOP", &ECORE_X_ATOM_NET_WM_DESKTOP }, + + { "_NET_WM_WINDOW_TYPE", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE }, + { "_NET_WM_WINDOW_TYPE_DESKTOP", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DESKTOP }, + { "_NET_WM_WINDOW_TYPE_DOCK", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DOCK }, + { "_NET_WM_WINDOW_TYPE_TOOLBAR", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR }, + { "_NET_WM_WINDOW_TYPE_MENU", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_MENU }, + { "_NET_WM_WINDOW_TYPE_UTILITY", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_UTILITY }, + { "_NET_WM_WINDOW_TYPE_SPLASH", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_SPLASH }, + { "_NET_WM_WINDOW_TYPE_DIALOG", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DIALOG }, + { "_NET_WM_WINDOW_TYPE_NORMAL", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NORMAL }, + { "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", + &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DROPDOWN_MENU }, + { "_NET_WM_WINDOW_TYPE_POPUP_MENU", + &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_POPUP_MENU }, + { "_NET_WM_WINDOW_TYPE_TOOLTIP", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLTIP }, + { "_NET_WM_WINDOW_TYPE_NOTIFICATION", + &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION }, + { "_NET_WM_WINDOW_TYPE_COMBO", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_COMBO }, + { "_NET_WM_WINDOW_TYPE_DND", &ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DND }, + + { "_NET_WM_STATE", &ECORE_X_ATOM_NET_WM_STATE }, + { "_NET_WM_STATE_MODAL", &ECORE_X_ATOM_NET_WM_STATE_MODAL }, + { "_NET_WM_STATE_STICKY", &ECORE_X_ATOM_NET_WM_STATE_STICKY }, + { "_NET_WM_STATE_MAXIMIZED_VERT", + &ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT }, + { "_NET_WM_STATE_MAXIMIZED_HORZ", + &ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ }, + { "_NET_WM_STATE_SHADED", &ECORE_X_ATOM_NET_WM_STATE_SHADED }, + { "_NET_WM_STATE_SKIP_TASKBAR", &ECORE_X_ATOM_NET_WM_STATE_SKIP_TASKBAR }, + { "_NET_WM_STATE_SKIP_PAGER", &ECORE_X_ATOM_NET_WM_STATE_SKIP_PAGER }, + { "_NET_WM_STATE_HIDDEN", &ECORE_X_ATOM_NET_WM_STATE_HIDDEN }, + { "_NET_WM_STATE_FULLSCREEN", &ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN }, + { "_NET_WM_STATE_ABOVE", &ECORE_X_ATOM_NET_WM_STATE_ABOVE }, + { "_NET_WM_STATE_BELOW", &ECORE_X_ATOM_NET_WM_STATE_BELOW }, + { "_NET_WM_STATE_DEMANDS_ATTENTION", + &ECORE_X_ATOM_NET_WM_STATE_DEMANDS_ATTENTION }, + + { "_NET_WM_ALLOWED_ACTIONS", &ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS }, + { "_NET_WM_ACTION_MOVE", &ECORE_X_ATOM_NET_WM_ACTION_MOVE }, + { "_NET_WM_ACTION_RESIZE", &ECORE_X_ATOM_NET_WM_ACTION_RESIZE }, + { "_NET_WM_ACTION_MINIMIZE", &ECORE_X_ATOM_NET_WM_ACTION_MINIMIZE }, + { "_NET_WM_ACTION_SHADE", &ECORE_X_ATOM_NET_WM_ACTION_SHADE }, + { "_NET_WM_ACTION_STICK", &ECORE_X_ATOM_NET_WM_ACTION_STICK }, + { "_NET_WM_ACTION_MAXIMIZE_HORZ", + &ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_HORZ }, + { "_NET_WM_ACTION_MAXIMIZE_VERT", + &ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_VERT }, + { "_NET_WM_ACTION_FULLSCREEN", &ECORE_X_ATOM_NET_WM_ACTION_FULLSCREEN }, + { "_NET_WM_ACTION_CHANGE_DESKTOP", + &ECORE_X_ATOM_NET_WM_ACTION_CHANGE_DESKTOP }, + { "_NET_WM_ACTION_CLOSE", &ECORE_X_ATOM_NET_WM_ACTION_CLOSE }, + { "_NET_WM_ACTION_ABOVE", &ECORE_X_ATOM_NET_WM_ACTION_ABOVE }, + { "_NET_WM_ACTION_BELOW", &ECORE_X_ATOM_NET_WM_ACTION_BELOW }, + + { "_NET_WM_STRUT", &ECORE_X_ATOM_NET_WM_STRUT }, + { "_NET_WM_STRUT_PARTIAL", &ECORE_X_ATOM_NET_WM_STRUT_PARTIAL }, + { "_NET_WM_ICON_GEOMETRY", &ECORE_X_ATOM_NET_WM_ICON_GEOMETRY }, + { "_NET_WM_ICON", &ECORE_X_ATOM_NET_WM_ICON }, + { "_NET_WM_PID", &ECORE_X_ATOM_NET_WM_PID }, + { "_NET_WM_HANDLED_ICONS", &ECORE_X_ATOM_NET_WM_HANDLED_ICONS }, + { "_NET_WM_USER_TIME", &ECORE_X_ATOM_NET_WM_USER_TIME }, + { "_NET_STARTUP_ID", &ECORE_X_ATOM_NET_STARTUP_ID }, + { "_NET_FRAME_EXTENTS", &ECORE_X_ATOM_NET_FRAME_EXTENTS }, + + { "_NET_WM_PING", &ECORE_X_ATOM_NET_WM_PING }, + { "_NET_WM_SYNC_REQUEST", &ECORE_X_ATOM_NET_WM_SYNC_REQUEST }, + { "_NET_WM_SYNC_REQUEST_COUNTER", + &ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER }, + + { "_NET_WM_WINDOW_OPACITY", &ECORE_X_ATOM_NET_WM_WINDOW_OPACITY }, + { "_NET_WM_WINDOW_SHADOW", &ECORE_X_ATOM_NET_WM_WINDOW_SHADOW }, + { "_NET_WM_WINDOW_SHADE", &ECORE_X_ATOM_NET_WM_WINDOW_SHADE }, + + { "TARGETS", &ECORE_X_ATOM_SELECTION_TARGETS }, + { "CLIPBOARD", &ECORE_X_ATOM_SELECTION_CLIPBOARD }, + { "PRIMARY", &ECORE_X_ATOM_SELECTION_PRIMARY }, + { "SECONDARY", &ECORE_X_ATOM_SELECTION_SECONDARY }, + { "_ECORE_SELECTION_PRIMARY", &ECORE_X_ATOM_SELECTION_PROP_PRIMARY }, + { "_ECORE_SELECTION_SECONDARY", &ECORE_X_ATOM_SELECTION_PROP_SECONDARY }, + { "_ECORE_SELECTION_CLIPBOARD", &ECORE_X_ATOM_SELECTION_PROP_CLIPBOARD }, + + { "_E_VIRTUAL_KEYBOARD", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD }, + { "_E_VIRTUAL_KEYBOARD_STATE", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE }, + { "_E_VIRTUAL_KEYBOARD_ON", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON }, + { "_E_VIRTUAL_KEYBOARD_OFF", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF }, + { "_E_VIRTUAL_KEYBOARD_ALPHA", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ALPHA }, + { "_E_VIRTUAL_KEYBOARD_NUMERIC", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_NUMERIC }, + { "_E_VIRTUAL_KEYBOARD_PIN", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PIN }, + { "_E_VIRTUAL_KEYBOARD_PHONE_NUMBER", + &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PHONE_NUMBER }, + { "_E_VIRTUAL_KEYBOARD_HEX", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HEX }, + { "_E_VIRTUAL_KEYBOARD_TERMINAL", + &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_TERMINAL }, + { "_E_VIRTUAL_KEYBOARD_PASSWORD", + &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PASSWORD }, + { "_E_VIRTUAL_KEYBOARD_IP", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_IP }, + { "_E_VIRTUAL_KEYBOARD_HOST", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HOST }, + { "_E_VIRTUAL_KEYBOARD_FILE", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_FILE }, + { "_E_VIRTUAL_KEYBOARD_URL", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_URL }, + { "_E_VIRTUAL_KEYBOARD_KEYPAD", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_KEYPAD }, + { "_E_VIRTUAL_KEYBOARD_J2ME", &ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_J2ME }, + + { "_E_ILLUME_ZONE", &ECORE_X_ATOM_E_ILLUME_ZONE }, + { "_E_ILLUME_ZONE_LIST", &ECORE_X_ATOM_E_ILLUME_ZONE_LIST }, + { "_E_ILLUME_CONFORMANT", &ECORE_X_ATOM_E_ILLUME_CONFORMANT }, + { "_E_ILLUME_MODE", &ECORE_X_ATOM_E_ILLUME_MODE }, + { "_E_ILLUME_MODE_SINGLE", &ECORE_X_ATOM_E_ILLUME_MODE_SINGLE }, + { "_E_ILLUME_MODE_DUAL_TOP", &ECORE_X_ATOM_E_ILLUME_MODE_DUAL_TOP }, + { "_E_ILLUME_MODE_DUAL_LEFT", &ECORE_X_ATOM_E_ILLUME_MODE_DUAL_LEFT }, + { "_E_ILLUME_FOCUS_BACK", &ECORE_X_ATOM_E_ILLUME_FOCUS_BACK }, + { "_E_ILLUME_FOCUS_FORWARD", &ECORE_X_ATOM_E_ILLUME_FOCUS_FORWARD }, + { "_E_ILLUME_FOCUS_HOME", &ECORE_X_ATOM_E_ILLUME_FOCUS_HOME }, + { "_E_ILLUME_CLOSE", &ECORE_X_ATOM_E_ILLUME_CLOSE }, + { "_E_ILLUME_HOME_NEW", &ECORE_X_ATOM_E_ILLUME_HOME_NEW }, + { "_E_ILLUME_HOME_DEL", &ECORE_X_ATOM_E_ILLUME_HOME_DEL }, + { "_E_ILLUME_DRAG", &ECORE_X_ATOM_E_ILLUME_DRAG }, + { "_E_ILLUME_DRAG_LOCKED", &ECORE_X_ATOM_E_ILLUME_DRAG_LOCKED }, + { "_E_ILLUME_DRAG_START", &ECORE_X_ATOM_E_ILLUME_DRAG_START }, + { "_E_ILLUME_DRAG_END", &ECORE_X_ATOM_E_ILLUME_DRAG_END }, + { "_E_ILLUME_INDICATOR_GEOMETRY", + &ECORE_X_ATOM_E_ILLUME_INDICATOR_GEOMETRY }, + { "_E_ILLUME_SOFTKEY_GEOMETRY", &ECORE_X_ATOM_E_ILLUME_SOFTKEY_GEOMETRY }, + { "_E_ILLUME_KEYBOARD_GEOMETRY", &ECORE_X_ATOM_E_ILLUME_KEYBOARD_GEOMETRY }, + { "_E_ILLUME_QUICKPANEL", &ECORE_X_ATOM_E_ILLUME_QUICKPANEL }, + { "_E_ILLUME_QUICKPANEL_STATE", &ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE }, + { "_E_ILLUME_QUICKPANEL_STATE_TOGGLE", + &ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE_TOGGLE }, + { "_E_ILLUME_QUICKPANEL_ON", &ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ON }, + { "_E_ILLUME_QUICKPANEL_OFF", &ECORE_X_ATOM_E_ILLUME_QUICKPANEL_OFF }, + { "_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR", + &ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR }, + { "_E_ILLUME_QUICKPANEL_PRIORITY_MINOR", + &ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MINOR }, + { "_E_ILLUME_QUICKPANEL_ZONE", &ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ZONE }, + { "_E_ILLUME_QUICKPANEL_POSITION_UPDATE", + &ECORE_X_ATOM_E_ILLUME_QUICKPANEL_POSITION_UPDATE }, + { "_E_ILLUME_INDICATOR_STATE", &ECORE_X_ATOM_E_ILLUME_INDICATOR_STATE }, + { "_E_ILLUME_INDICATOR_ON", &ECORE_X_ATOM_E_ILLUME_INDICATOR_ON }, + { "_E_ILLUME_INDICATOR_OFF", &ECORE_X_ATOM_E_ILLUME_INDICATOR_OFF }, + { "_E_ILLUME_INDICATOR_OPACITY_MODE", &ECORE_X_ATOM_E_ILLUME_INDICATOR_OPACITY_MODE }, + { "_E_ILLUME_INDICATOR_OPAQUE", &ECORE_X_ATOM_E_ILLUME_INDICATOR_OPAQUE }, + { "_E_ILLUME_INDICATOR_TRANSLUCENT", &ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSLUCENT }, + { "_E_ILLUME_INDICATOR_TRANSPARENT", &ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSPARENT }, + { "_E_ILLUME_ROTATE_WINDOW_AVAILABLE_ANGLES", &ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_AVAILABLE_ANGLE }, + { "_E_ILLUME_ROTATE_WINDOW_ANGLE", &ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE }, + { "_E_ILLUME_ROTATE_ROOT_ANGLE", &ECORE_X_ATOM_E_ILLUME_ROTATE_ROOT_ANGLE }, + { "_E_ILLUME_CLIPBOARD_STATE", &ECORE_X_ATOM_E_ILLUME_CLIPBOARD_STATE }, + { "_E_ILLUME_CLIPBOARD_ON", &ECORE_X_ATOM_E_ILLUME_CLIPBOARD_ON }, + { "_E_ILLUME_CLIPBOARD_OFF", &ECORE_X_ATOM_E_ILLUME_CLIPBOARD_OFF }, + { "_E_ILLUME_CLIPBOARD_GEOMETRY", &ECORE_X_ATOM_E_ILLUME_CLIPBOARD_GEOMETRY }, + { "_E_ILLUME_ACCESS_CONTROL", &ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL }, + { "_E_ILLUME_ACCESS_ACTION_NEXT", &ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_NEXT }, + { "_E_ILLUME_ACCESS_ACTION_PREV", &ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_PREV }, + { "_E_ILLUME_ACCESS_ACTION_ACTIVATE", &ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_ACTIVATE }, + { "_E_ILLUME_ACCESS_ACTION_READ", &ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ }, + { "_E_ILLUME_ACCESS_ACTION_READ_NEXT", &ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_NEXT }, + { "_E_ILLUME_ACCESS_ACTION_READ_PREV", &ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_PREV }, + { "_E_COMP_SYNC_COUNTER", &ECORE_X_ATOM_E_COMP_SYNC_COUNTER }, + { "_E_COMP_SYNC_DRAW_DONE", &ECORE_X_ATOM_E_COMP_SYNC_DRAW_DONE }, + { "_E_COMP_SYNC_SUPPORTED", &ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED }, + { "_E_COMP_SYNC_BEGIN", &ECORE_X_ATOM_E_COMP_SYNC_BEGIN }, + { "_E_COMP_SYNC_END", &ECORE_X_ATOM_E_COMP_SYNC_END }, + { "_E_COMP_SYNC_CANCEL", &ECORE_X_ATOM_E_COMP_SYNC_CANCEL }, + + { "_E_COMP_FLUSH", &ECORE_X_ATOM_E_COMP_FLUSH }, + { "_E_COMP_DUMP", &ECORE_X_ATOM_E_COMP_DUMP }, + { "_E_COMP_PIXMAP", &ECORE_X_ATOM_E_COMP_PIXMAP }, + { "_E_VIDEO_PARENT", &ECORE_X_ATOM_E_VIDEO_PARENT }, + { "_E_VIDEO_POSITION", &ECORE_X_ATOM_E_VIDEO_POSITION } +}; + diff --git a/src/lib/ecore_x/xcb/Makefile.am b/src/lib/ecore_x/xcb/Makefile.am new file mode 100644 index 0000000..366ebfd --- /dev/null +++ b/src/lib/ecore_x/xcb/Makefile.am @@ -0,0 +1,99 @@ + +MAINTAINERCLEANFILES = Makefile.in ecore_xcb_keysym_table.h + +if BUILD_ECORE_X_XCB + +AM_CPPFLAGS = \ + @XCB_DAMAGE_CFLAGS@ \ + @XCB_COMPOSITE_CFLAGS@ \ + @XCB_DPMS_CFLAGS@ \ + @XCB_RANDR_CFLAGS@ \ + @XCB_RENDER_CFLAGS@ \ + @XCB_SCREENSAVER_CFLAGS@ \ + @XCB_SHAPE_CFLAGS@ \ + @XCB_SYNC_CFLAGS@ \ + @XCB_XFIXES_CFLAGS@ \ + @XCB_XINERAMA_CFLAGS@ \ + @XCB_XPRINT_CFLAGS@ \ + @XCB_XTEST_CFLAGS@ \ + @XCB_XINPUT_CFLAGS@ \ + @XCB_XGESTURE_CFLAGS@ \ + @XCB_CURSOR_CFLAGS@ \ + @ECORE_XCB_CFLAGS@ \ + @PIXMAN_CFLAGS@ \ + -I$(top_srcdir)/src/lib/ecore \ + -I$(top_srcdir)/src/lib/ecore_x \ + -I$(top_srcdir)/src/lib/ecore_input \ + -I$(top_builddir)/src/lib/ecore \ + -I$(top_builddir)/src/lib/ecore_x \ + -I$(top_builddir)/src/lib/ecore_input \ + @EINA_CFLAGS@ + +noinst_LTLIBRARIES = libecore_x_xcb.la + +libecore_x_xcb_la_SOURCES = \ + ecore_xcb.c \ + ecore_xcb_atoms.c \ + ecore_xcb_extensions.c \ + ecore_xcb_shape.c \ + ecore_xcb_screensaver.c \ + ecore_xcb_sync.c \ + ecore_xcb_render.c \ + ecore_xcb_randr.c \ + ecore_xcb_xfixes.c \ + ecore_xcb_composite.c \ + ecore_xcb_cursor.c \ + ecore_xcb_damage.c \ + ecore_xcb_dnd.c \ + ecore_xcb_dpms.c \ + ecore_xcb_drawable.c \ + ecore_xcb_e.c \ + ecore_xcb_gc.c \ + ecore_xcb_image.c \ + ecore_xcb_input.c \ + ecore_xcb_gesture.c \ + ecore_xcb_mwm.c \ + ecore_xcb_pixmap.c \ + ecore_xcb_region.c \ + ecore_xcb_selection.c \ + ecore_xcb_textlist.c \ + ecore_xcb_events.c \ + ecore_xcb_keymap.c \ + ecore_xcb_netwm.c \ + ecore_xcb_icccm.c \ + ecore_xcb_window.c \ + ecore_xcb_window_prop.c \ + ecore_xcb_window_shape.c \ + ecore_xcb_window_shadow.c \ + ecore_xcb_xinerama.c \ + ecore_xcb_error.c \ + ecore_xcb_xtest.c \ + ecore_xcb_vsync.c \ + ecore_xcb_xdefaults.c + +libecore_x_xcb_la_LIBADD = \ + @XCB_DAMAGE_LIBS@ \ + @XCB_COMPOSITE_LIBS@ \ + @XCB_DPMS_LIBS@ \ + @XCB_RANDR_LIBS@ \ + @XCB_RENDER_LIBS@ \ + @XCB_SCREENSAVER_LIBS@ \ + @XCB_SHAPE_LIBS@ \ + @XCB_SYNC_LIBS@ \ + @XCB_XFIXES_LIBS@ \ + @XCB_XINERAMA_LIBS@ \ + @XCB_XPRINT_LIBS@ \ + @XCB_XTEST_LIBS@ \ + @XCB_XINPUT_LIBS@ \ + @XCB_XGESTURE_LIBS@ \ + @XCB_CURSOR_LIBS@ \ + @ECORE_XCB_LIBS@ \ + @PIXMAN_LIBS@ \ + $(top_builddir)/src/lib/ecore/libecore.la \ + $(top_builddir)/src/lib/ecore_input/libecore_input.la \ + @EINA_LIBS@ \ + @dlopen_libs@ + +endif + +EXTRA_DIST = ecore_xcb_private.h diff --git a/src/lib/ecore_x/xcb/ecore_xcb.c b/src/lib/ecore_x/xcb/ecore_xcb.c new file mode 100644 index 0000000..0ca779e --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb.c @@ -0,0 +1,1583 @@ +#include "ecore_xcb_private.h" +#include +#include + +/* local function prototypes */ +static int _ecore_xcb_shutdown(Eina_Bool close_display); +static Eina_Bool _ecore_xcb_fd_handle(void *data, Ecore_Fd_Handler *hdlr __UNUSED__); +static Eina_Bool _ecore_xcb_fd_handle_buff(void *data, Ecore_Fd_Handler *hdlr __UNUSED__); +static Eina_Bool _ecore_xcb_idle_enter(void *data __UNUSED__); + +/* local variables */ +static int _ecore_xcb_init_count = 0; +static int _ecore_xcb_grab_count = 0; +static Ecore_Fd_Handler *_ecore_xcb_fd_handler = NULL; +static xcb_generic_event_t *_ecore_xcb_event_buffered = NULL; +static Ecore_Idle_Enterer *_ecore_xcb_idle_enterer = NULL; + +/* external variables */ +int _ecore_xcb_log_dom = -1; +Ecore_X_Display *_ecore_xcb_display = NULL; +Ecore_X_Connection *_ecore_xcb_conn = NULL; +Ecore_X_Screen *_ecore_xcb_screen = NULL; +Ecore_X_Atom _ecore_xcb_atoms_wm_protocol[ECORE_X_WM_PROTOCOL_NUM]; +double _ecore_xcb_double_click_time = 0.25; + +/** + * @defgroup Ecore_X_Init_Group X Library Init and Shutdown Functions + * + * Functions that start and shut down the Ecore X Library. + */ + +/** + * Initialize the X display connection to the given display. + * + * @param name Display target name. If @c NULL, the default display is + * assumed. + * @return The number of times the library has been initialized without + * being shut down. 0 is returned if an error occurs. + * @ingroup Ecore_X_Init_Group + */ +EAPI int +ecore_x_init(const char *name) +{ + char *gl = NULL; + uint32_t mask, list[1]; + + /* check if we have initialized already */ + if (++_ecore_xcb_init_count != 1) + return _ecore_xcb_init_count; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + /* try to initialize eina */ + if (!eina_init()) return --_ecore_xcb_init_count; + + /* setup ecore_xcb log domain */ + _ecore_xcb_log_dom = + eina_log_domain_register("ecore_x", ECORE_XCB_DEFAULT_LOG_COLOR); + if (_ecore_xcb_log_dom < 0) + { + EINA_LOG_ERR("Cannot create Ecore Xcb log domain"); + eina_shutdown(); + return --_ecore_xcb_init_count; + } + + /* try to initialize ecore */ + if (!ecore_init()) + { + /* unregister log domain */ + eina_log_domain_unregister(_ecore_xcb_log_dom); + _ecore_xcb_log_dom = -1; + eina_shutdown(); + return --_ecore_xcb_init_count; + } + + /* try to initialize ecore_event */ + if (!ecore_event_init()) + { + /* unregister log domain */ + eina_log_domain_unregister(_ecore_xcb_log_dom); + _ecore_xcb_log_dom = -1; + ecore_shutdown(); + eina_shutdown(); + return --_ecore_xcb_init_count; + } + + /* NB: XLib has XInitThreads */ + + /* check for env var which says we are not going to use GL @ all + * + * NB: This is done because if someone wants a 'pure' xcb implementation + * of ecore_x, all they need do is export this variable in the environment + * and ecore_x will not use xlib stuff at all. + * + * The upside is you can get pure xcb-based ecore_x (w/ all the speed), but + * there is a down-side here in that you cannot get OpenGL without XLib :( + */ + if ((gl = getenv("ECORE_X_NO_XLIB"))) + { + /* we found the env var that says 'Yes, we are not ever gonna try + * OpenGL so it is safe to not use XLib at all' */ + + /* try to connect to the display server */ + _ecore_xcb_conn = xcb_connect(name, NULL); + } + else + { + /* env var was not specified, so we will assume that the user + * may want opengl @ some point. connect this way for opengl to work */ + void *libxcb, *libxlib; + Display *(*_real_display)(const char *display); + xcb_connection_t *(*_real_connection)(Display * dpy); + void (*_real_queue)(Display *dpy, enum XEventQueueOwner owner); + int (*_real_close)(Display *dpy); +#ifdef EVAS_FRAME_QUEUING + Status (*_real_threads)(void); +#endif + + /* want to dlopen here to avoid actual library linkage */ + libxlib = dlopen("libX11.so", (RTLD_LAZY | RTLD_GLOBAL)); + if (!libxlib) + libxlib = dlopen("libX11.so.6", (RTLD_LAZY | RTLD_GLOBAL)); + if (!libxlib) + libxlib = dlopen("libX11.so.6.3.0", (RTLD_LAZY | RTLD_GLOBAL)); + if (!libxlib) + { + ERR("Could not dlsym to libX11"); + /* unregister log domain */ + eina_log_domain_unregister(_ecore_xcb_log_dom); + _ecore_xcb_log_dom = -1; + ecore_event_shutdown(); + ecore_shutdown(); + eina_shutdown(); + return --_ecore_xcb_init_count; + } + + libxcb = dlopen("libX11-xcb.so", (RTLD_LAZY | RTLD_GLOBAL)); + if (!libxcb) + libxcb = dlopen("libX11-xcb.so.1", (RTLD_LAZY | RTLD_GLOBAL)); + if (!libxcb) + libxcb = dlopen("libX11-xcb.so.1.0.0", (RTLD_LAZY | RTLD_GLOBAL)); + if (!libxcb) + { + ERR("Could not dlsym to libX11-xcb"); + /* unregister log domain */ + eina_log_domain_unregister(_ecore_xcb_log_dom); + _ecore_xcb_log_dom = -1; + ecore_event_shutdown(); + ecore_shutdown(); + eina_shutdown(); + return --_ecore_xcb_init_count; + } + + _real_display = dlsym(libxlib, "XOpenDisplay"); + _real_close = dlsym(libxlib, "XCloseDisplay"); + _real_connection = dlsym(libxcb, "XGetXCBConnection"); + _real_queue = dlsym(libxcb, "XSetEventQueueOwner"); +#ifdef EVAS_FRAME_QUEUING + _real_threads = dlsym(libxlib, "XInitThreads"); +#endif + + if (_real_display) + { +#ifdef EVAS_FRAME_QUEUING + if (_real_threads) _real_threads(); +#endif + _ecore_xcb_display = _real_display(name); + if (!_ecore_xcb_display) + { + ERR("Could not open Display via XLib"); + /* unregister log domain */ + eina_log_domain_unregister(_ecore_xcb_log_dom); + _ecore_xcb_log_dom = -1; + ecore_event_shutdown(); + ecore_shutdown(); + eina_shutdown(); + return --_ecore_xcb_init_count; + } + if (_real_connection) + _ecore_xcb_conn = _real_connection(_ecore_xcb_display); + if (!_ecore_xcb_conn) + { + ERR("Could not get XCB Connection from XLib"); + + if (_real_close) _real_close(_ecore_xcb_display); + + /* unregister log domain */ + eina_log_domain_unregister(_ecore_xcb_log_dom); + _ecore_xcb_log_dom = -1; + ecore_event_shutdown(); + ecore_shutdown(); + eina_shutdown(); + return --_ecore_xcb_init_count; + } + if (_real_queue) + _real_queue(_ecore_xcb_display, XCBOwnsEventQueue); + } + } + + if (xcb_connection_has_error(_ecore_xcb_conn)) + { + CRIT("XCB Connection has error"); + eina_log_domain_unregister(_ecore_xcb_log_dom); + _ecore_xcb_log_dom = -1; + ecore_event_shutdown(); + ecore_shutdown(); + eina_shutdown(); + return --_ecore_xcb_init_count; + } + + /* grab the default screen */ + _ecore_xcb_screen = + xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)).data; + + /* NB: This method of init/finalize extensions first, then atoms + * Does end up being 2 round trips to X, BUT if we do extensions init then + * atoms init first, and call the 'finalize' functions later, we end up + * being slower, so it's a trade-off. This current method clocks in + * around 0.003 for fetching atoms VS 0.010 for init both then finalize */ + + /* prefetch extension data */ + _ecore_xcb_extensions_init(); + + /* finalize extensions */ + _ecore_xcb_extensions_finalize(); + + /* set keyboard autorepeat */ + mask = XCB_KB_AUTO_REPEAT_MODE; + list[0] = XCB_AUTO_REPEAT_MODE_ON; + xcb_change_keyboard_control(_ecore_xcb_conn, mask, list); + + /* setup xcb events */ + _ecore_xcb_events_init(); + + /* setup xcb keymasks */ + _ecore_xcb_keymap_init(); + + /* finalize xcb keymasks */ + _ecore_xcb_keymap_finalize(); + + /* setup ecore fd handler */ + _ecore_xcb_fd_handler = + ecore_main_fd_handler_add(xcb_get_file_descriptor(_ecore_xcb_conn), + ECORE_FD_READ, _ecore_xcb_fd_handle, + _ecore_xcb_conn, _ecore_xcb_fd_handle_buff, + _ecore_xcb_conn); + + if (!_ecore_xcb_fd_handler) + return _ecore_xcb_shutdown(EINA_TRUE); + + /* prefetch atoms */ + _ecore_xcb_atoms_init(); + + /* finalize atoms */ + _ecore_xcb_atoms_finalize(); + + /* icccm_init: dummy function */ + ecore_x_icccm_init(); + + /* setup netwm */ + ecore_x_netwm_init(); + + /* old e hints init: dummy function */ + ecore_x_e_init(); + + _ecore_xcb_atoms_wm_protocol[ECORE_X_WM_PROTOCOL_DELETE_REQUEST] = + ECORE_X_ATOM_WM_DELETE_WINDOW; + _ecore_xcb_atoms_wm_protocol[ECORE_X_WM_PROTOCOL_TAKE_FOCUS] = + ECORE_X_ATOM_WM_TAKE_FOCUS; + _ecore_xcb_atoms_wm_protocol[ECORE_X_NET_WM_PROTOCOL_PING] = + ECORE_X_ATOM_NET_WM_PING; + _ecore_xcb_atoms_wm_protocol[ECORE_X_NET_WM_PROTOCOL_SYNC_REQUEST] = + ECORE_X_ATOM_NET_WM_SYNC_REQUEST; + + /* setup selection */ + _ecore_xcb_selection_init(); + + /* setup dnd */ + _ecore_xcb_dnd_init(); + + _ecore_xcb_idle_enterer = + ecore_idle_enterer_add(_ecore_xcb_idle_enter, NULL); + + return _ecore_xcb_init_count; +} + +/** + * Shuts down the Ecore X library. + * + * In shutting down the library, the X display connection is terminated + * and any event handlers for it are removed. + * + * @return The number of times the library has been initialized without + * being shut down. + * @ingroup Ecore_X_Init_Group + */ +EAPI int +ecore_x_shutdown(void) +{ + return _ecore_xcb_shutdown(EINA_TRUE); +} + +/** + * Shuts down the Ecore X library. + * + * As ecore_x_shutdown, except do not close Display, only connection. + * + * @return The number of times the library has been initialized without + * being shut down. 0 is returned if an error occurs. + * @ingroup Ecore_X_Init_Group + */ +EAPI int +ecore_x_disconnect(void) +{ + return _ecore_xcb_shutdown(EINA_FALSE); +} + +/** + * @defgroup Ecore_X_Flush_Group X Synchronization Functions + * + * Functions that ensure that all commands that have been issued by the + * Ecore X library have been sent to the server. + */ + +/** + * Sends all X commands in the X Display buffer. + * @ingroup Ecore_X_Flush_Group + */ +EAPI void +ecore_x_flush(void) +{ +// LOGFN(__FILE__, __LINE__, __FUNCTION__); + + CHECK_XCB_CONN; + xcb_flush(_ecore_xcb_conn); +} + +/** + * Retrieves the Ecore_X_Screen handle used for the current X connection. + * @return The current default screen. + * @ingroup Ecore_X_Display_Attr_Group + */ +EAPI Ecore_X_Screen * +ecore_x_default_screen_get(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return (Ecore_X_Screen *)_ecore_xcb_screen; +} + +EAPI Ecore_X_Connection * +ecore_x_connection_get(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + CHECK_XCB_CONN; + return (Ecore_X_Connection *)_ecore_xcb_conn; +} + +/** + * Return the last event time + */ +EAPI Ecore_X_Time +ecore_x_current_time_get(void) +{ + return _ecore_xcb_events_last_time_get(); +} + +/** + * Flushes the command buffer and waits until all requests have been + * processed by the server. + * @ingroup Ecore_X_Flush_Group + */ +EAPI void +ecore_x_sync(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + CHECK_XCB_CONN; + free(xcb_get_input_focus_reply(_ecore_xcb_conn, + xcb_get_input_focus_unchecked(_ecore_xcb_conn), + NULL)); +} + +EAPI void +ecore_x_grab(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + CHECK_XCB_CONN; + _ecore_xcb_grab_count++; + if (_ecore_xcb_grab_count == 1) + xcb_grab_server(_ecore_xcb_conn); +} + +EAPI void +ecore_x_ungrab(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + CHECK_XCB_CONN; + _ecore_xcb_grab_count--; + if (_ecore_xcb_grab_count < 0) _ecore_xcb_grab_count = 0; + if (_ecore_xcb_grab_count == 0) + xcb_ungrab_server(_ecore_xcb_conn); +} + +/** + * Send client message with given type and format 32. + * + * @param win The window the message is sent to. + * @param type The client message type. + * @param mask The mask of the message to be sent. + * @param d0 The client message data item 1 + * @param d1 The client message data item 2 + * @param d2 The client message data item 3 + * @param d3 The client message data item 4 + * @param d4 The client message data item 5 + * + * @return @c EINA_TRUE on success @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_x_client_message32_send(Ecore_X_Window win, Ecore_X_Atom type, + Ecore_X_Event_Mask mask, + long d0, long d1, long d2, long d3, long d4) +{ + xcb_client_message_event_t ev; + xcb_void_cookie_t cookie; + xcb_generic_error_t *err; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 32; + ev.window = win; + ev.type = type; + ev.data.data32[0] = (uint32_t)d0; + ev.data.data32[1] = (uint32_t)d1; + ev.data.data32[2] = (uint32_t)d2; + ev.data.data32[3] = (uint32_t)d3; + ev.data.data32[4] = (uint32_t)d4; + + cookie = xcb_send_event(_ecore_xcb_conn, 0, win, mask, (const char *)&ev); + + err = xcb_request_check(_ecore_xcb_conn, cookie); + if (err) + { + DBG("Problem Sending Event"); + DBG("\tType: %d", type); + DBG("\tWin: %d", win); + _ecore_xcb_error_handle(err); + free(err); + return EINA_FALSE; + } + + return EINA_TRUE; +} + +/** + * Send client message with given type and format 8. + * + * @param win The window the message is sent to. + * @param type The client message type. + * @param data Data to be sent. + * @param len Number of data bytes, max @c 20. + * + * @return @c EINA_TRUE on success @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_x_client_message8_send(Ecore_X_Window win, Ecore_X_Atom type, + const void *data, int len) +{ + xcb_client_message_event_t ev; + xcb_void_cookie_t cookie; + xcb_generic_error_t *err; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 8; + ev.window = win; + ev.type = type; + if (len > 20) len = 20; + memcpy(ev.data.data8, data, len); + memset(ev.data.data8 + len, 0, 20 - len); + + cookie = xcb_send_event(_ecore_xcb_conn, 0, win, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); + + err = xcb_request_check(_ecore_xcb_conn, cookie); + if (err) + { + DBG("Problem Sending Event"); + DBG("\tType: %d", type); + DBG("\tWin: %d", win); + _ecore_xcb_error_handle(err); + free(err); + return EINA_FALSE; + } + + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_x_mouse_down_send(Ecore_X_Window win, int x, int y, int b) +{ + xcb_translate_coordinates_cookie_t cookie; + xcb_translate_coordinates_reply_t *reply; + xcb_button_press_event_t ev; + xcb_void_cookie_t vcookie; + xcb_generic_error_t *err; + Ecore_X_Window root = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + root = ecore_x_window_root_get(win); + cookie = xcb_translate_coordinates(_ecore_xcb_conn, win, root, x, y); + reply = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return EINA_FALSE; + + memset(&ev, 0, sizeof(xcb_button_press_event_t)); + + ev.response_type = XCB_BUTTON_PRESS; + ev.event = win; + ev.child = win; + ev.root = root; + ev.event_x = x; + ev.event_y = y; + ev.same_screen = 1; + ev.state = 1 << b; + ev.detail = b; // xcb uses detail for button + ev.root_x = reply->dst_x; + ev.root_y = reply->dst_y; + ev.time = ecore_x_current_time_get(); + free(reply); + + vcookie = xcb_send_event(_ecore_xcb_conn, 1, win, + XCB_EVENT_MASK_BUTTON_PRESS, (const char *)&ev); + + err = xcb_request_check(_ecore_xcb_conn, vcookie); + if (err) + { + _ecore_xcb_error_handle(err); + free(err); + return EINA_FALSE; + } + + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_x_mouse_up_send(Ecore_X_Window win, int x, int y, int b) +{ + xcb_translate_coordinates_cookie_t cookie; + xcb_translate_coordinates_reply_t *reply; + xcb_button_release_event_t ev; + xcb_void_cookie_t vcookie; + xcb_generic_error_t *err; + Ecore_X_Window root = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + root = ecore_x_window_root_get(win); + cookie = xcb_translate_coordinates(_ecore_xcb_conn, win, root, x, y); + reply = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return EINA_FALSE; + + memset(&ev, 0, sizeof(xcb_button_release_event_t)); + + ev.response_type = XCB_BUTTON_RELEASE; + ev.event = win; + ev.child = win; + ev.root = root; + ev.event_x = x; + ev.event_y = y; + ev.same_screen = 1; + ev.state = 0; + ev.root_x = reply->dst_x; + ev.root_y = reply->dst_y; + ev.detail = b; // xcb uses detail for button + ev.time = ecore_x_current_time_get(); + free(reply); + + vcookie = xcb_send_event(_ecore_xcb_conn, 1, win, + XCB_EVENT_MASK_BUTTON_RELEASE, (const char *)&ev); + + err = xcb_request_check(_ecore_xcb_conn, vcookie); + if (err) + { + _ecore_xcb_error_handle(err); + free(err); + return EINA_FALSE; + } + + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_x_mouse_move_send(Ecore_X_Window win, int x, int y) +{ + xcb_translate_coordinates_cookie_t cookie; + xcb_translate_coordinates_reply_t *reply; + xcb_motion_notify_event_t ev; + xcb_void_cookie_t vcookie; + xcb_generic_error_t *err; + Ecore_X_Window root = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + root = ecore_x_window_root_get(win); + cookie = xcb_translate_coordinates(_ecore_xcb_conn, win, root, x, y); + reply = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return EINA_FALSE; + + memset(&ev, 0, sizeof(xcb_motion_notify_event_t)); + + ev.response_type = XCB_MOTION_NOTIFY; + ev.event = win; + ev.child = win; + ev.root = root; + ev.event_x = x; + ev.event_y = y; + ev.same_screen = 1; + ev.state = 0; + ev.detail = 0; // xcb uses 'detail' for is_hint + ev.root_x = reply->dst_x; + ev.root_y = reply->dst_y; + ev.time = ecore_x_current_time_get(); + free(reply); + + vcookie = xcb_send_event(_ecore_xcb_conn, 1, win, + XCB_EVENT_MASK_POINTER_MOTION, (const char *)&ev); + + err = xcb_request_check(_ecore_xcb_conn, vcookie); + if (err) + { + _ecore_xcb_error_handle(err); + free(err); + return EINA_FALSE; + } + + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_x_mouse_in_send(Ecore_X_Window win, int x, int y) +{ + xcb_translate_coordinates_cookie_t cookie; + xcb_translate_coordinates_reply_t *reply; + xcb_enter_notify_event_t ev; + xcb_void_cookie_t vcookie; + xcb_generic_error_t *err; + Ecore_X_Window root = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + root = ecore_x_window_root_get(win); + cookie = xcb_translate_coordinates(_ecore_xcb_conn, win, root, x, y); + reply = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return EINA_FALSE; + + memset(&ev, 0, sizeof(xcb_enter_notify_event_t)); + + ev.response_type = XCB_ENTER_NOTIFY; + ev.event = win; + ev.child = win; + ev.root = root; + ev.event_x = x; + ev.event_y = y; + ev.same_screen_focus = 1; + ev.mode = XCB_NOTIFY_MODE_NORMAL; + ev.detail = XCB_NOTIFY_DETAIL_NONLINEAR; + /* ev.focus = 0; */ + ev.state = 0; + ev.root_x = reply->dst_x; + ev.root_y = reply->dst_y; + ev.time = ecore_x_current_time_get(); + free(reply); + + vcookie = xcb_send_event(_ecore_xcb_conn, 1, win, + XCB_EVENT_MASK_ENTER_WINDOW, (const char *)&ev); + + err = xcb_request_check(_ecore_xcb_conn, vcookie); + if (err) + { + _ecore_xcb_error_handle(err); + free(err); + return EINA_FALSE; + } + + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_x_mouse_out_send(Ecore_X_Window win, int x, int y) +{ + xcb_translate_coordinates_cookie_t cookie; + xcb_translate_coordinates_reply_t *reply; + xcb_leave_notify_event_t ev; + xcb_void_cookie_t vcookie; + xcb_generic_error_t *err; + Ecore_X_Window root = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + root = ecore_x_window_root_get(win); + cookie = xcb_translate_coordinates(_ecore_xcb_conn, win, root, x, y); + reply = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return EINA_FALSE; + + memset(&ev, 0, sizeof(xcb_leave_notify_event_t)); + + ev.response_type = XCB_LEAVE_NOTIFY; + ev.event = win; + ev.child = win; + ev.root = root; + ev.event_x = x; + ev.event_y = y; + ev.same_screen_focus = 1; + ev.mode = XCB_NOTIFY_MODE_NORMAL; + ev.detail = XCB_NOTIFY_DETAIL_NONLINEAR; + /* ev.focus = 0; */ + ev.state = 0; + ev.root_x = reply->dst_x; + ev.root_y = reply->dst_y; + ev.time = ecore_x_current_time_get(); + free(reply); + + vcookie = xcb_send_event(_ecore_xcb_conn, 1, win, + XCB_EVENT_MASK_LEAVE_WINDOW, (const char *)&ev); + + err = xcb_request_check(_ecore_xcb_conn, vcookie); + if (err) + { + _ecore_xcb_error_handle(err); + free(err); + return EINA_FALSE; + } + + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_x_keyboard_grab(Ecore_X_Window win) +{ + xcb_grab_keyboard_cookie_t cookie; + xcb_grab_keyboard_reply_t *reply; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + cookie = + xcb_grab_keyboard_unchecked(_ecore_xcb_conn, 0, win, XCB_CURRENT_TIME, + XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); + reply = xcb_grab_keyboard_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return EINA_FALSE; + free(reply); + return EINA_TRUE; +} + +EAPI void +ecore_x_keyboard_ungrab(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_ungrab_keyboard(_ecore_xcb_conn, XCB_CURRENT_TIME); +} + +EAPI void +ecore_x_pointer_xy_get(Ecore_X_Window win, int *x, int *y) +{ + xcb_query_pointer_cookie_t cookie; + xcb_query_pointer_reply_t *reply; + +// LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +// if (!win) win = ((xcb_screen_t *)_ecore_xcb_screen)->root; + + if (x) *x = -1; + if (y) *y = -1; + + cookie = xcb_query_pointer_unchecked(_ecore_xcb_conn, win); + reply = xcb_query_pointer_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return; + if (x) *x = reply->win_x; + if (y) *y = reply->win_y; + free(reply); +} + +EAPI Eina_Bool +ecore_x_pointer_control_set(int accel_num, int accel_denom, int threshold) +{ + xcb_void_cookie_t vcookie; + xcb_generic_error_t *err; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + vcookie = + xcb_change_pointer_control_checked(_ecore_xcb_conn, + accel_num, accel_denom, threshold, + 1, 1); + err = xcb_request_check(_ecore_xcb_conn, vcookie); + if (err) + { + _ecore_xcb_error_handle(err); + free(err); + return EINA_FALSE; + } + + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_x_pointer_control_get(int *accel_num, int *accel_denom, int *threshold) +{ + xcb_get_pointer_control_cookie_t cookie; + xcb_get_pointer_control_reply_t *reply; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (accel_num) *accel_num = 0; + if (accel_denom) *accel_denom = 0; + if (threshold) *threshold = 0; + + cookie = xcb_get_pointer_control_unchecked(_ecore_xcb_conn); + reply = xcb_get_pointer_control_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return EINA_FALSE; + + if (accel_num) *accel_num = reply->acceleration_numerator; + if (accel_denom) *accel_denom = reply->acceleration_denominator; + if (threshold) *threshold = reply->threshold; + free(reply); + + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_x_pointer_mapping_set(unsigned char *map, int nmap) +{ + xcb_set_pointer_mapping_cookie_t cookie; + xcb_set_pointer_mapping_reply_t *reply; + Eina_Bool ret = EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + cookie = xcb_set_pointer_mapping_unchecked(_ecore_xcb_conn, nmap, map); + reply = xcb_set_pointer_mapping_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return EINA_FALSE; + + if (reply->status == XCB_MAPPING_STATUS_SUCCESS) + ret = EINA_TRUE; + + free(reply); + return ret; +} + +EAPI Eina_Bool +ecore_x_pointer_mapping_get(unsigned char *map, int nmap) +{ + xcb_get_pointer_mapping_cookie_t cookie; + xcb_get_pointer_mapping_reply_t *reply; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (map) *map = 0; + nmap = 0; + + cookie = xcb_get_pointer_mapping_unchecked(_ecore_xcb_conn); + reply = xcb_get_pointer_mapping_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return EINA_FALSE; + + nmap = xcb_get_pointer_mapping_map_length(reply); + if (nmap <= 0) + { + free(reply); + return EINA_FALSE; + } + + if (map) + { + uint8_t *tmp; + int i = 0; + + tmp = xcb_get_pointer_mapping_map(reply); + for (i = 0; i < nmap; i++) + map[i] = tmp[i]; + } + + free(reply); + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_x_pointer_grab(Ecore_X_Window win) +{ + xcb_grab_pointer_cookie_t cookie; + xcb_grab_pointer_reply_t *reply; + uint16_t mask; + Eina_Bool ret = EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + mask = (XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | + XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | + XCB_EVENT_MASK_POINTER_MOTION); + + cookie = xcb_grab_pointer_unchecked(_ecore_xcb_conn, 0, win, mask, + XCB_GRAB_MODE_ASYNC, + XCB_GRAB_MODE_ASYNC, + XCB_NONE, XCB_NONE, XCB_CURRENT_TIME); + reply = xcb_grab_pointer_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return EINA_FALSE; + + ret = (reply->status == XCB_GRAB_STATUS_SUCCESS) ? EINA_TRUE : EINA_FALSE; + + free(reply); + return ret; +} + +EAPI Eina_Bool +ecore_x_pointer_confine_grab(Ecore_X_Window win) +{ + xcb_grab_pointer_cookie_t cookie; + xcb_grab_pointer_reply_t *reply; + uint16_t mask; + Eina_Bool ret = EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + mask = (XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | + XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | + XCB_EVENT_MASK_POINTER_MOTION); + + cookie = xcb_grab_pointer_unchecked(_ecore_xcb_conn, 0, win, mask, + XCB_GRAB_MODE_ASYNC, + XCB_GRAB_MODE_ASYNC, + win, XCB_NONE, XCB_CURRENT_TIME); + reply = xcb_grab_pointer_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return EINA_FALSE; + + ret = (reply->status == XCB_GRAB_STATUS_SUCCESS) ? EINA_TRUE : EINA_FALSE; + + free(reply); + return ret; +} + +EAPI void +ecore_x_pointer_ungrab(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_ungrab_pointer(_ecore_xcb_conn, XCB_CURRENT_TIME); +} + +EAPI Eina_Bool +ecore_x_pointer_warp(Ecore_X_Window win, int x, int y) +{ + xcb_void_cookie_t vcookie; + xcb_generic_error_t *err; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + vcookie = + xcb_warp_pointer_checked(_ecore_xcb_conn, XCB_NONE, win, 0, 0, 0, 0, x, y); + err = xcb_request_check(_ecore_xcb_conn, vcookie); + if (err) + { + _ecore_xcb_error_handle(err); + free(err); + return EINA_FALSE; + } + + return EINA_TRUE; +} + +/** + * Invoke the standard system beep to alert users + * + * @param percent The volume at which the bell rings. Must be in the range + * [-100,+100]. If percent >= 0, the final volume will be: + * base - [(base * percent) / 100] + percent + * Otherwise, it's calculated as: + * base + [(base * percent) / 100] + * where @c base is the bell's base volume as set by XChangeKeyboardControl(3). + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_x_bell(int percent) +{ + xcb_void_cookie_t cookie; + xcb_generic_error_t *err; + + CHECK_XCB_CONN; + + // FIXME: Use unchecked version after development is ironed out + cookie = xcb_bell_checked(_ecore_xcb_conn, percent); + err = xcb_request_check(_ecore_xcb_conn, cookie); + if (err) + { + _ecore_xcb_error_handle(err); + free(err); + return EINA_FALSE; + } + + return EINA_TRUE; +} + +EAPI void +ecore_x_display_size_get(Ecore_X_Display *dsp __UNUSED__, int *w, int *h) +{ + xcb_screen_t *screen; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + /* grab the default screen */ + screen = xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)).data; + if (w) *w = screen->width_in_pixels; + if (h) *h = screen->height_in_pixels; +} + +EAPI unsigned long +ecore_x_display_black_pixel_get(Ecore_X_Display *dsp __UNUSED__) +{ + xcb_screen_t *screen; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + /* grab the default screen */ + screen = xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)).data; + return screen->black_pixel; +} + +EAPI unsigned long +ecore_x_display_white_pixel_get(Ecore_X_Display *dsp __UNUSED__) +{ + xcb_screen_t *screen; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + /* grab the default screen */ + screen = xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)).data; + return screen->white_pixel; +} + +EAPI void +ecore_x_pointer_last_xy_get(int *x, int *y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (x) *x = _ecore_xcb_event_last_root_x; + if (y) *y = _ecore_xcb_event_last_root_y; +} + +EAPI void +ecore_x_focus_reset(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_set_input_focus(_ecore_xcb_conn, XCB_INPUT_FOCUS_POINTER_ROOT, + ((xcb_screen_t *)_ecore_xcb_screen)->root, + XCB_CURRENT_TIME); +// ecore_x_flush(); +} + +EAPI void +ecore_x_events_allow_all(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_allow_events(_ecore_xcb_conn, XCB_ALLOW_ASYNC_BOTH, XCB_CURRENT_TIME); +// ecore_x_flush(); +} + +/** + * Kill a specific client + * + * You can kill a specific client owning window @p win + * + * @param win Window of the client to be killed + */ +EAPI void +ecore_x_kill(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_kill_client(_ecore_xcb_conn, win); +// ecore_x_flush(); +} + +/** + * Kill all clients with subwindows under a given window. + * + * You can kill all clients connected to the X server by using + * @ref ecore_x_window_root_list to get a list of root windows, and + * then passing each root window to this function. + * + * @param root The window whose children will be killed. + */ +EAPI void +ecore_x_killall(Ecore_X_Window root) +{ + int screens = 0, i = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + ecore_x_grab(); + + screens = xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)).rem; + + /* Traverse window tree starting from root, and drag each + * before the firing squad */ + for (i = 0; i < screens; ++i) + { + xcb_query_tree_cookie_t cookie; + xcb_query_tree_reply_t *reply; + + cookie = xcb_query_tree_unchecked(_ecore_xcb_conn, root); + reply = xcb_query_tree_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + xcb_window_t *wins = NULL; + int tree_c_len, j = 0; + + wins = xcb_query_tree_children(reply); + tree_c_len = xcb_query_tree_children_length(reply); + for (j = 0; j < tree_c_len; j++) + xcb_kill_client(_ecore_xcb_conn, wins[j]); + free(reply); + } + } + + ecore_x_ungrab(); + ecore_x_sync(); // needed +} + +/** + * Return the screen DPI + * + * This is a simplistic call to get DPI. It does not account for differing + * DPI in the x amd y axes nor does it account for multihead or xinerama and + * xrander where different parts of the screen may have differen DPI etc. + * + * @return the general screen DPI (dots/pixels per inch). + */ +EAPI int +ecore_x_dpi_get(void) +{ + uint16_t mw = 0, w = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + mw = ((xcb_screen_t *)_ecore_xcb_screen)->width_in_millimeters; + if (mw <= 0) return 75; + w = ((xcb_screen_t *)_ecore_xcb_screen)->width_in_pixels; + return (((w * 254) / mw) + 5) / 10; +} + +/** + * @defgroup Ecore_X_Display_Attr_Group X Display Attributes + * + * Functions that set and retrieve X display attributes. + */ + +/** + * Retrieves the Ecore_X_Display handle used for the current X connection. + * @return The current X display. + * @ingroup Ecore_X_Display_Attr_Group + */ +EAPI Ecore_X_Display * +ecore_x_display_get(void) +{ + char *gl = NULL; + + CHECK_XCB_CONN; + + /* if we have the 'dont use xlib' env var, then we are not using + * XLib and thus cannot return a real XDisplay. + * + * NB: This may break EFL in some places and needs lots of testing !!! */ + if ((gl = getenv("ECORE_X_NO_XLIB"))) + return (Ecore_X_Display *)_ecore_xcb_conn; + else /* we can safely return an XDisplay var */ + return (Ecore_X_Display *)_ecore_xcb_display; +} + +/** + * Retrieves the X display file descriptor. + * @return The current X display file descriptor. + * @ingroup Ecore_X_Display_Attr_Group + */ +EAPI int +ecore_x_fd_get(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + return xcb_get_file_descriptor(_ecore_xcb_conn); +} + +EAPI void +ecore_x_passive_grab_replay_func_set(Eina_Bool (*func)(void *data, int type, void *event), + void *data) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_xcb_window_grab_replay_func = func; + _ecore_xcb_window_grab_replay_data = data; +} + +/** + * Retrieves the size of an Ecore_X_Screen. + * @param screen the handle to the screen to query. + * @param w where to return the width. May be NULL. Returns 0 on errors. + * @param h where to return the height. May be NULL. Returns 0 on errors. + * @ingroup Ecore_X_Display_Attr_Group + * @see ecore_x_default_screen_get() + * + * @since 1.1 + */ +EAPI void +ecore_x_screen_size_get(const Ecore_X_Screen *screen, int *w, int *h) +{ + xcb_screen_t *s; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (w) *w = 0; + if (h) *h = 0; + if (!(s = (xcb_screen_t *)screen)) return; + if (w) *w = s->width_in_pixels; + if (h) *h = s->height_in_pixels; +} + +/** + * Retrieves the count of screens. + * + * @return The count of screens. + * @ingroup Ecore_X_Display_Attr_Group + * + * @since 1.1 + */ +EAPI int +ecore_x_screen_count_get(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + return xcb_setup_roots_length(xcb_get_setup(_ecore_xcb_conn)); +} + +/** + * Retrieves the index number of the given screen. + * + * @param screen The screen for which index will be gotten. + * @return The index number of the screen. + * @ingroup Ecore_X_Display_Attr_Group + * + * @since 1.1 + */ +EAPI int +ecore_x_screen_index_get(const Ecore_X_Screen *screen) +{ + xcb_screen_iterator_t iter; + int i = 0; + + CHECK_XCB_CONN; + + iter = + xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)); + for (; iter.rem; xcb_screen_next(&iter)) + { + if (iter.data == (xcb_screen_t *)screen) + return i; + i++; + } + + return 0; +} + +/** + * Retrieves the screen based on index number. + * + * @param idx The index that will be used to retrieve the screen. + * @return The Ecore_X_Screen at this index. + * @ingroup Ecore_X_Display_Attr_Group + * + * @since 1.1 + */ +EAPI Ecore_X_Screen * +ecore_x_screen_get(int idx) +{ + xcb_screen_iterator_t iter; + int i = 0; + + CHECK_XCB_CONN; + + iter = + xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)); + for (i = 0; iter.rem; xcb_screen_next(&iter), i++) + if (i == idx) return iter.data; + + return NULL; +} + +EAPI unsigned int +ecore_x_visual_id_get(Ecore_X_Visual visual) +{ + return ((xcb_visualtype_t *)visual)->visual_id; +} + +/** + * Retrieve the default Visual. + * + * @param disp The Display to get the Default Visual from + * @param screen The Screen. + * + * @return The default visual. + * @since 1.1.0 + */ +EAPI Ecore_X_Visual +ecore_x_default_visual_get(Ecore_X_Display *disp __UNUSED__, Ecore_X_Screen *screen) +{ + xcb_screen_t *s; + xcb_depth_iterator_t diter; + xcb_visualtype_iterator_t viter; + + CHECK_XCB_CONN; + + s = (xcb_screen_t *)screen; + diter = xcb_screen_allowed_depths_iterator(s); + for (; diter.rem; xcb_depth_next(&diter)) + { + viter = xcb_depth_visuals_iterator(diter.data); + for (; viter.rem; xcb_visualtype_next(&viter)) + { + if (viter.data->visual_id == s->root_visual) + return viter.data; + } + } + return 0; +} + +/** + * Retrieve the default Colormap. + * + * @param disp The Display to get the Default Colormap from + * @param screen The Screen. + * + * @return The default colormap. + * @since 1.1.0 + */ +EAPI Ecore_X_Colormap +ecore_x_default_colormap_get(Ecore_X_Display *disp __UNUSED__, Ecore_X_Screen *screen) +{ + xcb_screen_t *s; + + s = (xcb_screen_t *)screen; + return s->default_colormap; +} + +/** + * Retrieve the default depth. + * + * @param disp The Display to get the Default Depth from + * @param screen The Screen. + * + * @return The default depth. + * @since 1.1.0 + */ +EAPI int +ecore_x_default_depth_get(Ecore_X_Display *disp __UNUSED__, Ecore_X_Screen *screen) +{ + xcb_screen_t *s; + + s = (xcb_screen_t *)screen; + return s->root_depth; +} + +EAPI void +ecore_x_xkb_select_group(int group) +{ + // XXX: implement me */ +} + +/** + * Sets the timeout for a double and triple clicks to be flagged. + * + * This sets the time between clicks before the double_click flag is + * set in a button down event. If 3 clicks occur within double this + * time, the triple_click flag is also set. + * + * @param t The time in seconds + * @ingroup Ecore_X_Display_Attr_Group + */ +EAPI void +ecore_x_double_click_time_set(double t) +{ + if (t < 0.0) t = 0.0; + _ecore_xcb_double_click_time = t; +} + +/** + * Retrieves the double and triple click flag timeout. + * + * See @ref ecore_x_double_click_time_set for more information. + * + * @return The timeout for double clicks in seconds. + * @ingroup Ecore_X_Display_Attr_Group + */ +EAPI double +ecore_x_double_click_time_get(void) +{ + return _ecore_xcb_double_click_time; +} + +/* local function prototypes */ +static int +_ecore_xcb_shutdown(Eina_Bool close_display) +{ + if (--_ecore_xcb_init_count != 0) + return _ecore_xcb_init_count; + + if (!_ecore_xcb_conn) + return _ecore_xcb_init_count; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + ecore_idle_enterer_del(_ecore_xcb_idle_enterer); + _ecore_xcb_idle_enterer = NULL; + + if (_ecore_xcb_fd_handler) + ecore_main_fd_handler_del(_ecore_xcb_fd_handler); + + /* disconnect from display server */ + if (close_display) + xcb_disconnect(_ecore_xcb_conn); + else + { + close(xcb_get_file_descriptor(_ecore_xcb_conn)); + _ecore_xcb_conn = NULL; + } + + /* shutdown events */ + _ecore_xcb_events_shutdown(); + + /* shutdown input extension */ + _ecore_xcb_input_shutdown(); + + /* shutdown gesture extension */ + _ecore_xcb_gesture_shutdown(); + + /* shutdown selection */ + _ecore_xcb_selection_shutdown(); + + /* shutdown dnd */ + _ecore_xcb_dnd_shutdown(); + + /* shutdown netwm */ + ecore_x_netwm_shutdown(); + + /* shutdown keymap */ + _ecore_xcb_keymap_shutdown(); + + /* shutdown ecore_event */ + ecore_event_shutdown(); + + /* shutdown ecore */ + ecore_shutdown(); + + /* unregister log domain */ + eina_log_domain_unregister(_ecore_xcb_log_dom); + _ecore_xcb_log_dom = -1; + + /* shutdown eina */ + eina_shutdown(); + + return _ecore_xcb_init_count; +} + +static Eina_Bool +_ecore_xcb_fd_handle(void *data, Ecore_Fd_Handler *hdlr __UNUSED__) +{ + xcb_connection_t *conn; + xcb_generic_event_t *ev = NULL; + + conn = (xcb_connection_t *)data; + + if (_ecore_xcb_event_buffered) + { + _ecore_xcb_events_handle(_ecore_xcb_event_buffered); + free(_ecore_xcb_event_buffered); + _ecore_xcb_event_buffered = NULL; + } + +// xcb_flush(conn); + + while ((ev = xcb_poll_for_event(conn))) + { + /* NB: Ecore Xlib uses filterevent for xim, but xcb does not support + * xim, so no need for it here */ + + /* check for errors first */ + if (xcb_connection_has_error(conn)) + { + xcb_generic_error_t *err; + + err = (xcb_generic_error_t *)ev; + _ecore_xcb_io_error_handle(err); + } + else + { + /* FIXME: Filter event for XIM */ + _ecore_xcb_events_handle(ev); + free(ev); + } + } + + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +_ecore_xcb_fd_handle_buff(void *data, Ecore_Fd_Handler *hdlr __UNUSED__) +{ + xcb_connection_t *conn; + xcb_generic_event_t *ev = NULL; + + conn = (xcb_connection_t *)data; + ev = xcb_poll_for_event(conn); + if (ev) + { + /* check for errors first */ + if (xcb_connection_has_error(conn)) + { + xcb_generic_error_t *err; + + err = (xcb_generic_error_t *)ev; + _ecore_xcb_io_error_handle(err); + return ECORE_CALLBACK_CANCEL; + } + _ecore_xcb_event_buffered = ev; + return ECORE_CALLBACK_RENEW; + } + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool +_ecore_xcb_idle_enter(void *data __UNUSED__) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_flush(_ecore_xcb_conn); + return ECORE_CALLBACK_RENEW; +} diff --git a/src/lib/ecore_x/xcb/ecore_xcb_atoms.c b/src/lib/ecore_x/xcb/ecore_xcb_atoms.c new file mode 100644 index 0000000..b01898f --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_atoms.c @@ -0,0 +1,153 @@ +#include "ecore_xcb_private.h" +#include "ecore_x_atoms_decl.h" + +/* NB: Increment if you add new atoms */ +#define ECORE_X_ATOMS_COUNT 199 + +/* local function prototypes */ + +/* local variables */ +static xcb_intern_atom_cookie_t cookies[ECORE_X_ATOMS_COUNT]; + +void +_ecore_xcb_atoms_init(void) +{ + int i = 0, num = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + num = (sizeof(atom_items) / sizeof(Atom_Item)); + for (i = 0; i < num; i++) + { + cookies[i] = + xcb_intern_atom_unchecked(_ecore_xcb_conn, 0, + strlen(atom_items[i].name), atom_items[i].name); + } +} + +void +_ecore_xcb_atoms_finalize(void) +{ + int i = 0, num = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + num = (sizeof(atom_items) / sizeof(Atom_Item)); + for (i = 0; i < num; i++) + { + xcb_intern_atom_reply_t *reply = NULL; + + if (!(reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookies[i], 0))) + continue; + *(atom_items[i].atom) = reply->atom; + free(reply); + } +} + +/** + * @defgroup Ecore_X_Atom_Group XCB Atom Functions + * + * Functions that operate on atoms + */ + +/** + * Retrieves the atom value associated to a name. + * + * @param name Unused. + * @return Associated atom value. + * + * Retrieves the atom value associated to a name. The reply is the + * returned value of the function ecore_xcb_intern_atom_reply(). If + * @p reply is @c NULL, the NULL atom is returned. Otherwise, the atom + * associated to the name is returned. + * + * To use this function, you must call before, and in order, + * ecore_x_atom_get_prefetch(), which sends the InternAtom request, + * then ecore_x_atom_get_fetch(), which gets the reply. + * + * @ingroup Ecore_X_Atom_Group + */ +EAPI Ecore_X_Atom +ecore_x_atom_get(const char *name) +{ + xcb_intern_atom_cookie_t cookie; + xcb_intern_atom_reply_t *reply; + Ecore_X_Atom a; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + cookie = xcb_intern_atom_unchecked(_ecore_xcb_conn, 0, strlen(name), name); + reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return XCB_ATOM_NONE; + a = reply->atom; + free(reply); + return a; +} + +/** + * Retrieves the name of the given atom. + * + * @param atom + * @return The name of the atom. + * + * @ingroup Ecore_X_Atom_Group + */ +EAPI char * +ecore_x_atom_name_get(Ecore_X_Atom atom) +{ + xcb_get_atom_name_cookie_t cookie; + xcb_get_atom_name_reply_t *reply; + char *name; + int len = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + cookie = xcb_get_atom_name_unchecked(_ecore_xcb_conn, atom); + reply = xcb_get_atom_name_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return NULL; + len = xcb_get_atom_name_name_length(reply); + name = (char *)malloc(sizeof(char) * (len + 1)); + if (!name) + { + free(reply); + return NULL; + } + memcpy(name, xcb_get_atom_name_name(reply), len); + name[len] = '\0'; + + free(reply); + return name; +} + +EAPI void +ecore_x_atoms_get(const char **names, + int num, + Ecore_X_Atom *atoms) +{ + xcb_intern_atom_cookie_t cookies[num]; + int i = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + for (i = 0; i < num; i++) + { + cookies[i] = + xcb_intern_atom_unchecked(_ecore_xcb_conn, 0, + strlen(names[i]), names[i]); + } + for (i = 0; i < num; i++) + { + xcb_intern_atom_reply_t *reply = NULL; + + if (!(reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookies[i], 0))) + continue; + atoms[i] = reply->atom; + free(reply); + } +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_composite.c b/src/lib/ecore_x/xcb/ecore_xcb_composite.c new file mode 100644 index 0000000..0d3b44e --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_composite.c @@ -0,0 +1,290 @@ +#include "ecore_xcb_private.h" +#ifdef ECORE_XCB_COMPOSITE +# include +#endif + +/* local variables */ +static Eina_Bool _composite_avail = EINA_FALSE; + +void +_ecore_xcb_composite_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_COMPOSITE + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_composite_id); +#endif +} + +void +_ecore_xcb_composite_finalize(void) +{ +#ifdef ECORE_XCB_COMPOSITE + const xcb_query_extension_reply_t *ext_reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_COMPOSITE + ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_composite_id); + if ((ext_reply) && (ext_reply->present)) + { + xcb_composite_query_version_cookie_t cookie; + xcb_composite_query_version_reply_t *reply; + + cookie = + xcb_composite_query_version_unchecked(_ecore_xcb_conn, + XCB_COMPOSITE_MAJOR_VERSION, + XCB_COMPOSITE_MINOR_VERSION); + reply = + xcb_composite_query_version_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { +// if ((reply->major_version >= XCB_COMPOSITE_MAJOR_VERSION) && + if (reply->minor_version >= XCB_COMPOSITE_MINOR_VERSION) + { +# ifdef ECORE_XCB_RENDER + if (_ecore_xcb_render_avail_get()) + { +# ifdef ECORE_XCB_XFIXES + if (_ecore_xcb_xfixes_avail_get()) + _composite_avail = EINA_TRUE; +# endif + } +# endif + } + + free(reply); + } + } +#endif +} + +/** + * @defgroup Ecore_X_Composite_Group X Composite Extension Functions + * + * Functions related to the X Composite Extension + */ + +/** + * Return whether the Composite Extension is available + * + * @return @c EINA_TRUE is the Composite Extension is available, @c EINA_FALSE + * if not. + * + * @ingroup Ecore_X_Composite_Group + */ +EAPI Eina_Bool +ecore_x_composite_query(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return _composite_avail; +} + +EAPI void +ecore_x_composite_redirect_window(Ecore_X_Window win, + Ecore_X_Composite_Update_Type type) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_composite_avail) return; + +#ifdef ECORE_XCB_COMPOSITE + uint8_t update = XCB_COMPOSITE_REDIRECT_AUTOMATIC; + + switch (type) + { + case ECORE_X_COMPOSITE_UPDATE_AUTOMATIC: + update = XCB_COMPOSITE_REDIRECT_AUTOMATIC; + break; + + case ECORE_X_COMPOSITE_UPDATE_MANUAL: + update = XCB_COMPOSITE_REDIRECT_MANUAL; + break; + } + xcb_composite_redirect_window(_ecore_xcb_conn, win, update); +// ecore_x_flush(); +#endif +} + +EAPI void +ecore_x_composite_redirect_subwindows(Ecore_X_Window win, + Ecore_X_Composite_Update_Type type) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_composite_avail) return; + +#ifdef ECORE_XCB_COMPOSITE + uint8_t update = XCB_COMPOSITE_REDIRECT_AUTOMATIC; + + switch (type) + { + case ECORE_X_COMPOSITE_UPDATE_AUTOMATIC: + update = XCB_COMPOSITE_REDIRECT_AUTOMATIC; + break; + + case ECORE_X_COMPOSITE_UPDATE_MANUAL: + update = XCB_COMPOSITE_REDIRECT_MANUAL; + break; + } + xcb_composite_redirect_subwindows(_ecore_xcb_conn, win, update); +// ecore_x_flush(); +#endif +} + +EAPI void +ecore_x_composite_unredirect_window(Ecore_X_Window win, + Ecore_X_Composite_Update_Type type) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_composite_avail) return; + +#ifdef ECORE_XCB_COMPOSITE + uint8_t update = XCB_COMPOSITE_REDIRECT_AUTOMATIC; + + switch (type) + { + case ECORE_X_COMPOSITE_UPDATE_AUTOMATIC: + update = XCB_COMPOSITE_REDIRECT_AUTOMATIC; + break; + + case ECORE_X_COMPOSITE_UPDATE_MANUAL: + update = XCB_COMPOSITE_REDIRECT_MANUAL; + break; + } + xcb_composite_unredirect_window(_ecore_xcb_conn, win, update); +// ecore_x_flush(); +#endif +} + +EAPI void +ecore_x_composite_unredirect_subwindows(Ecore_X_Window win, + Ecore_X_Composite_Update_Type type) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_composite_avail) return; + +#ifdef ECORE_XCB_COMPOSITE + uint8_t update = XCB_COMPOSITE_REDIRECT_AUTOMATIC; + + switch (type) + { + case ECORE_X_COMPOSITE_UPDATE_AUTOMATIC: + update = XCB_COMPOSITE_REDIRECT_AUTOMATIC; + break; + + case ECORE_X_COMPOSITE_UPDATE_MANUAL: + update = XCB_COMPOSITE_REDIRECT_MANUAL; + break; + } + xcb_composite_unredirect_subwindows(_ecore_xcb_conn, win, update); +// ecore_x_flush(); +#endif +} + +EAPI Ecore_X_Pixmap +ecore_x_composite_name_window_pixmap_get(Ecore_X_Window win) +{ +#ifdef ECORE_XCB_COMPOSITE + Ecore_X_Pixmap pmap = XCB_NONE; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_composite_avail) return XCB_NONE; + +#ifdef ECORE_XCB_COMPOSITE + pmap = xcb_generate_id(_ecore_xcb_conn); + xcb_composite_name_window_pixmap(_ecore_xcb_conn, win, pmap); +// ecore_x_flush(); +#endif + + return pmap; +} + +EAPI void +ecore_x_composite_window_events_disable(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_composite_avail) return; + +#ifdef ECORE_XCB_SHAPE + ecore_x_window_shape_input_rectangle_set(win, -1, -1, 1, 1); +// ecore_x_flush(); +#else + return; + win = 0; +#endif +} + +EAPI void +ecore_x_composite_window_events_enable(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_composite_avail) return; + +#ifdef ECORE_XCB_SHAPE + ecore_x_window_shape_input_rectangle_set(win, 0, 0, 65535, 65535); +// ecore_x_flush(); +#else + return; + win = 0; +#endif +} + +EAPI Ecore_X_Window +ecore_x_composite_render_window_enable(Ecore_X_Window root) +{ + Ecore_X_Window win = 0; +#ifdef ECORE_XCB_COMPOSITE + xcb_composite_get_overlay_window_cookie_t cookie; + xcb_composite_get_overlay_window_reply_t *reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_composite_avail) return 0; + +#ifdef ECORE_XCB_COMPOSITE + cookie = xcb_composite_get_overlay_window_unchecked(_ecore_xcb_conn, root); + reply = + xcb_composite_get_overlay_window_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return win; + + win = reply->overlay_win; + free(reply); + + ecore_x_composite_window_events_disable(win); +// ecore_x_flush(); +#endif + + return win; +} + +EAPI void +ecore_x_composite_render_window_disable(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_composite_avail) return; + +#ifdef ECORE_XCB_COMPOSITE + xcb_composite_release_overlay_window(_ecore_xcb_conn, win); +// ecore_x_flush(); +#endif +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_cursor.c b/src/lib/ecore_x/xcb/ecore_xcb_cursor.c new file mode 100644 index 0000000..755df04 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_cursor.c @@ -0,0 +1,400 @@ +#include "ecore_xcb_private.h" +#ifdef ECORE_XCB_CURSOR +# include +# include +#endif + +/* local function prototypes */ +#ifdef ECORE_XCB_CURSOR +static xcb_render_pictforminfo_t *_ecore_xcb_cursor_format_get(void); +#endif +static void _ecore_xcb_cursor_default_size_get(void); +static void _ecore_xcb_cursor_dpi_size_get(void); +static void _ecore_xcb_cursor_guess_size(void); +#ifdef ECORE_XCB_CURSOR +static Ecore_X_Cursor _ecore_xcb_cursor_image_load_cursor(xcb_image_t *img, + int hot_x, + int hot_y); +#endif +static void _ecore_xcb_cursor_image_destroy(xcb_image_t *img); + +/* local variables */ +static int _ecore_xcb_cursor_size = 0; +static Eina_Bool _ecore_xcb_cursor = EINA_FALSE; +#ifdef ECORE_XCB_CURSOR +static uint32_t _ecore_xcb_cursor_format_id = 0; +// static xcb_render_pictforminfo_t *_ecore_xcb_cursor_format = NULL; +#endif + +void +_ecore_xcb_cursor_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + /* NB: No-op */ +} + +void +_ecore_xcb_cursor_finalize(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_CURSOR + _ecore_xcb_cursor = _ecore_xcb_render_argb_get(); + + /* find render pict format */ + if (_ecore_xcb_cursor_format_id <= 0) + _ecore_xcb_cursor_format_id = _ecore_xcb_cursor_format_get()->id; +#endif + + /* try to grab cursor size from XDefaults */ + _ecore_xcb_cursor_default_size_get(); + + /* if that failed, try to get it from Xft Dpi setting */ + if (_ecore_xcb_cursor_size == 0) + _ecore_xcb_cursor_dpi_size_get(); + + /* if that failed, try to guess from display size */ + if (_ecore_xcb_cursor_size == 0) + _ecore_xcb_cursor_guess_size(); + + /* NB: Would normally add theme stuff here, but E cursor does not support + * xcursor themes. Delay parsing that stuff out until such time if/when the + * user selects to use X Cursor, rather than E cursor */ +} + +EAPI Eina_Bool +ecore_x_cursor_color_supported_get(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _ecore_xcb_cursor; +} + +EAPI Ecore_X_Cursor +ecore_x_cursor_new(Ecore_X_Window win, + int *pixels, + int w, + int h, + int hot_x, + int hot_y) +{ + Ecore_X_Cursor cursor = 0; + xcb_image_t *img; + +// LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_CURSOR + if (_ecore_xcb_cursor) + { + img = _ecore_xcb_image_create_native(w, h, XCB_IMAGE_FORMAT_Z_PIXMAP, + 32, NULL, (w * h * sizeof(int)), + (uint8_t *)pixels); + cursor = _ecore_xcb_cursor_image_load_cursor(img, hot_x, hot_y); + _ecore_xcb_cursor_image_destroy(img); + return cursor; + } + else +#endif + { + Ecore_X_GC gc; + xcb_pixmap_t pmap, mask; + uint32_t *pix; + uint8_t fr = 0x00, fg = 0x00, fb = 0x00; + uint8_t br = 0xff, bg = 0xff, bb = 0xff; + uint32_t brightest = 0, darkest = 255 * 3; + uint16_t x, y; + const uint32_t dither[2][2] = + { + {0, 2}, + {3, 1} + }; + + img = _ecore_xcb_image_create_native(w, h, XCB_IMAGE_FORMAT_Z_PIXMAP, + 1, NULL, ~0, NULL); + if (img->data) free(img->data); + img->data = malloc(img->size); + + pmap = xcb_generate_id(_ecore_xcb_conn); + xcb_create_pixmap(_ecore_xcb_conn, 1, pmap, win, w, h); + mask = xcb_generate_id(_ecore_xcb_conn); + xcb_create_pixmap(_ecore_xcb_conn, 1, mask, win, w, h); + + pix = (uint32_t *)pixels; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + uint8_t r, g, b, a; + + a = (pix[0] >> 24) & 0xff; + r = (pix[0] >> 16) & 0xff; + g = (pix[0] >> 8) & 0xff; + b = (pix[0]) & 0xff; + if (a > 0) + { + if ((uint32_t)(r + g + b) > brightest) + { + brightest = r + g + b; + br = r; + bg = g; + bb = b; + } + + if ((uint32_t)(r + g + b) < darkest) + { + darkest = r + g + b; + fr = r; + fg = g; + fb = b; + } + } + pix++; + } + } + + pix = (uint32_t *)pixels; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + uint32_t v; + uint8_t r, g, b; + int32_t d1, d2; + + r = (pix[0] >> 16) & 0xff; + g = (pix[0] >> 8) & 0xff; + b = (pix[0]) & 0xff; + d1 = + ((r - fr) * (r - fr)) + + ((g - fg) * (g - fg)) + + ((b - fb) * (b - fb)); + d2 = + ((r - br) * (r - br)) + + ((g - bg) * (g - bg)) + + ((b - bb) * (b - bb)); + if (d1 + d2) + { + v = (((d2 * 255) / (d1 + d2)) * 5) / 256; + if (v > dither[x & 0x1][y & 0x1]) + v = 1; + else + v = 0; + } + else + v = 0; + + xcb_image_put_pixel(img, x, y, v); + pix++; + } + } + + gc = ecore_x_gc_new(pmap, 0, NULL); + xcb_put_image(_ecore_xcb_conn, img->format, pmap, gc, w, h, + 0, 0, 0, img->depth, img->size, img->data); + ecore_x_gc_free(gc); + + pix = (uint32_t *)pixels; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + uint32_t v; + + v = (((pix[0] >> 24) & 0xff) * 5) / 256; + if (v > dither[x & 0x1][y & 0x1]) + v = 1; + else + v = 0; + + xcb_image_put_pixel(img, x, y, v); + pix++; + } + } + + gc = ecore_x_gc_new(mask, 0, NULL); + xcb_put_image(_ecore_xcb_conn, img->format, mask, gc, w, h, + 0, 0, 0, img->depth, img->size, img->data); + ecore_x_gc_free(gc); + + if (img->data) free(img->data); + _ecore_xcb_cursor_image_destroy(img); + + cursor = xcb_generate_id(_ecore_xcb_conn); + xcb_create_cursor(_ecore_xcb_conn, cursor, pmap, mask, + fr << 8 | fr, fg << 8 | fg, fb << 8 | fb, + br << 8 | br, bg << 8 | bg, bb << 8 | bb, + hot_x, hot_y); + + xcb_free_pixmap(_ecore_xcb_conn, pmap); + xcb_free_pixmap(_ecore_xcb_conn, mask); + + return cursor; + } + + return 0; +} + +EAPI void +ecore_x_cursor_free(Ecore_X_Cursor c) +{ +// LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_free_cursor(_ecore_xcb_conn, c); +} + +/* + * Returns the cursor for the given shape. + * Note that the return value must not be freed with + * ecore_x_cursor_free()! + */ +EAPI Ecore_X_Cursor +ecore_x_cursor_shape_get(int shape) +{ + Ecore_X_Cursor cursor = 0; + xcb_font_t font; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + font = xcb_generate_id(_ecore_xcb_conn); + xcb_open_font(_ecore_xcb_conn, font, strlen("cursor"), "cursor"); + + cursor = xcb_generate_id(_ecore_xcb_conn); + /* FIXME: Add request check ?? */ + xcb_create_glyph_cursor(_ecore_xcb_conn, cursor, font, font, + shape, shape + 1, 0, 0, 0, 65535, 65535, 65535); + + xcb_close_font(_ecore_xcb_conn, font); + return cursor; +} + +EAPI void +ecore_x_cursor_size_set(int size) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_xcb_cursor_size = size; + /* NB: May need to adjust size of current cursors here */ +} + +EAPI int +ecore_x_cursor_size_get(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _ecore_xcb_cursor_size; +} + +/* local functions */ +#ifdef ECORE_XCB_CURSOR +static xcb_render_pictforminfo_t * +_ecore_xcb_cursor_format_get(void) +{ + const xcb_render_query_pict_formats_reply_t *reply; + xcb_render_pictforminfo_t *ret = NULL; + + CHECK_XCB_CONN; + + reply = xcb_render_util_query_formats(_ecore_xcb_conn); + if (reply) + ret = xcb_render_util_find_standard_format(reply, + XCB_PICT_STANDARD_ARGB_32); + + return ret; +} + +#endif + +static void +_ecore_xcb_cursor_default_size_get(void) +{ + char *s = NULL; + int v = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + s = getenv("XCURSOR_SIZE"); + if (!s) + { + _ecore_xcb_xdefaults_init(); + v = _ecore_xcb_xdefaults_int_get("Xcursor", "size"); + _ecore_xcb_xdefaults_shutdown(); + } + else + v = atoi(s); + if (v) _ecore_xcb_cursor_size = ((v * 16) / 72); +} + +static void +_ecore_xcb_cursor_dpi_size_get(void) +{ + int v = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_xcb_xdefaults_init(); + v = _ecore_xcb_xdefaults_int_get("Xft", "dpi"); + if (v) _ecore_xcb_cursor_size = ((v * 16) / 72); + _ecore_xcb_xdefaults_shutdown(); +} + +static void +_ecore_xcb_cursor_guess_size(void) +{ + int w = 0, h = 0, s = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_screen_size_get(_ecore_xcb_screen, &w, &h); + if (h < w) s = h; + else s = w; + _ecore_xcb_cursor_size = (s / 48); +} + +#ifdef ECORE_XCB_CURSOR +static Ecore_X_Cursor +_ecore_xcb_cursor_image_load_cursor(xcb_image_t *img, + int hot_x, + int hot_y) +{ + Ecore_X_Cursor cursor = 0; + Ecore_X_GC gc; + xcb_pixmap_t pmap; + xcb_render_picture_t pict; + + CHECK_XCB_CONN; + + pmap = xcb_generate_id(_ecore_xcb_conn); + xcb_create_pixmap(_ecore_xcb_conn, img->depth, pmap, + ((xcb_screen_t *)_ecore_xcb_screen)->root, + img->width, img->height); + + gc = ecore_x_gc_new(pmap, 0, NULL); + xcb_put_image(_ecore_xcb_conn, img->format, pmap, gc, + img->width, img->height, 0, 0, 0, img->depth, + img->size, img->data); + ecore_x_gc_free(gc); + + pict = xcb_generate_id(_ecore_xcb_conn); + xcb_render_create_picture(_ecore_xcb_conn, pict, pmap, + _ecore_xcb_cursor_format_id, 0, NULL); + xcb_free_pixmap(_ecore_xcb_conn, pmap); + + cursor = xcb_generate_id(_ecore_xcb_conn); + xcb_render_create_cursor(_ecore_xcb_conn, cursor, pict, hot_x, hot_y); + xcb_render_free_picture(_ecore_xcb_conn, pict); + + return cursor; +} + +#endif + +static void +_ecore_xcb_cursor_image_destroy(xcb_image_t *img) +{ + CHECK_XCB_CONN; + if (img) xcb_image_destroy(img); +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_damage.c b/src/lib/ecore_x/xcb/ecore_xcb_damage.c new file mode 100644 index 0000000..deb3b9c --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_damage.c @@ -0,0 +1,155 @@ +#include "ecore_xcb_private.h" +# ifdef ECORE_XCB_DAMAGE +# include +# endif + +/* local variables */ +static Eina_Bool _damage_avail = EINA_FALSE; + +/* external variables */ +int _ecore_xcb_event_damage = -1; + +void +_ecore_xcb_damage_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_DAMAGE + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_damage_id); +#endif +} + +void +_ecore_xcb_damage_finalize(void) +{ +#ifdef ECORE_XCB_DAMAGE + const xcb_query_extension_reply_t *ext_reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_DAMAGE + ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_damage_id); + if ((ext_reply) && (ext_reply->present)) + { + xcb_damage_query_version_cookie_t cookie; + xcb_damage_query_version_reply_t *reply; + + cookie = + xcb_damage_query_version_unchecked(_ecore_xcb_conn, + XCB_DAMAGE_MAJOR_VERSION, + XCB_DAMAGE_MINOR_VERSION); + reply = xcb_damage_query_version_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + _damage_avail = EINA_TRUE; + free(reply); + } + + if (_damage_avail) + _ecore_xcb_event_damage = ext_reply->first_event; + } +#endif +} + +/** + * @defgroup Ecore_X_Damage_Group X Damage Extension Functions + * + * Functions related to the X Damage Extension. + */ + +EAPI Eina_Bool +ecore_x_damage_query(void) +{ + return _damage_avail; +} + +/** + * Create a damage object + * + * @param drawable The drawable to monitor + * @param level The level of the damage report + * @return The damage object + * + * Creates a damage object to monitor changes to @p drawable, + * with the level @p level. + * + * @ingroup Ecore_X_Damage_Group + */ +EAPI Ecore_X_Damage +ecore_x_damage_new(Ecore_X_Drawable drawable, + Ecore_X_Damage_Report_Level level) +{ + Ecore_X_Damage damage = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_damage_avail) return 0; + +#ifdef ECORE_XCB_DAMAGE + damage = xcb_generate_id(_ecore_xcb_conn); + xcb_damage_create(_ecore_xcb_conn, damage, drawable, level); +// ecore_x_flush(); +#endif + + return damage; +} + +/** + * Destroy a damage object + * + * @param damage The damage object to destroy + * + * Destroys the damage object @p damage + * + * @ingroup Ecore_X_Damage_Group + */ +EAPI void +ecore_x_damage_free(Ecore_X_Damage damage) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_damage_avail) return; + +#ifdef ECORE_XCB_DAMAGE + xcb_damage_destroy(_ecore_xcb_conn, damage); +// ecore_x_flush(); +#endif +} + +/** + * Synchronously modifies the region + * + * @param damage The damage object to destroy + * @param repair The repair region + * @param parts The parts region + * + * Synchronously modifies the regions in the following manner: + * If @p repair is @c XCB_NONE: + * 1) parts = damage + * 2) damage = \ + * Otherwise: + * 1) parts = damage INTERSECT repair + * 2) damage = damage - parts + * 3) Generate DamageNotify for remaining damage areas + * + * @ingroup Ecore_X_Damage_Group + */ +EAPI void +ecore_x_damage_subtract(Ecore_X_Damage damage, + Ecore_X_Region repair, + Ecore_X_Region parts) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_damage_avail) return; + +#ifdef ECORE_XCB_DAMAGE + xcb_damage_subtract(_ecore_xcb_conn, damage, repair, parts); +// ecore_x_flush(); +#endif +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_dnd.c b/src/lib/ecore_x/xcb/ecore_xcb_dnd.c new file mode 100644 index 0000000..177e61d --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_dnd.c @@ -0,0 +1,688 @@ +#include "ecore_xcb_private.h" + +#ifndef MIN +# define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +/* local structures */ +typedef struct _Version_Cache_Item +{ + Ecore_X_Window win; + int ver; +} Version_Cache_Item; + +/* local function prototypes */ +static Eina_Bool _ecore_xcb_dnd_converter_copy(char *target __UNUSED__, + void *data, + int size, + void **data_ret, + int *size_ret, + Ecore_X_Atom *tprop __UNUSED__, + int *count __UNUSED__); + +/* local variables */ +static int _ecore_xcb_dnd_init_count = 0; +static Ecore_X_DND_Source *_source = NULL; +static Ecore_X_DND_Target *_target = NULL; +static Version_Cache_Item *_version_cache = NULL; +static int _version_cache_num = 0, _version_cache_alloc = 0; +static void (*_posupdatecb)(void *, + Ecore_X_Xdnd_Position *); +static void *_posupdatedata; + +/* external variables */ +EAPI int ECORE_X_EVENT_XDND_ENTER = 0; +EAPI int ECORE_X_EVENT_XDND_POSITION = 0; +EAPI int ECORE_X_EVENT_XDND_STATUS = 0; +EAPI int ECORE_X_EVENT_XDND_LEAVE = 0; +EAPI int ECORE_X_EVENT_XDND_DROP = 0; +EAPI int ECORE_X_EVENT_XDND_FINISHED = 0; + +void +_ecore_xcb_dnd_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!_ecore_xcb_dnd_init_count) + { + _source = calloc(1, sizeof(Ecore_X_DND_Source)); + if (!_source) return; + _source->version = ECORE_X_DND_VERSION; + _source->win = XCB_NONE; + _source->dest = XCB_NONE; + _source->state = ECORE_X_DND_SOURCE_IDLE; + _source->prev.window = 0; + + _target = calloc(1, sizeof(Ecore_X_DND_Target)); + if (!_target) + { + free(_source); + _source = NULL; + return; + } + _target->win = XCB_NONE; + _target->source = XCB_NONE; + _target->state = ECORE_X_DND_TARGET_IDLE; + + ECORE_X_EVENT_XDND_ENTER = ecore_event_type_new(); + ECORE_X_EVENT_XDND_POSITION = ecore_event_type_new(); + ECORE_X_EVENT_XDND_STATUS = ecore_event_type_new(); + ECORE_X_EVENT_XDND_LEAVE = ecore_event_type_new(); + ECORE_X_EVENT_XDND_DROP = ecore_event_type_new(); + ECORE_X_EVENT_XDND_FINISHED = ecore_event_type_new(); + } + _ecore_xcb_dnd_init_count++; +} + +void +_ecore_xcb_dnd_shutdown(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_xcb_dnd_init_count--; + if (_ecore_xcb_dnd_init_count > 0) return; + if (_source) free(_source); + _source = NULL; + if (_target) free(_target); + _target = NULL; + _ecore_xcb_dnd_init_count = 0; +} + +EAPI void +ecore_x_dnd_send_status(Eina_Bool will_accept, + Eina_Bool suppress, + Ecore_X_Rectangle rect, + Ecore_X_Atom action) +{ + xcb_client_message_event_t ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (_target->state == ECORE_X_DND_TARGET_IDLE) return; + + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + + _target->will_accept = will_accept; + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.type = ECORE_X_ATOM_XDND_STATUS; + ev.format = 32; + ev.window = _target->source; + ev.data.data32[0] = _target->win; + ev.data.data32[1] = 0; + if (will_accept) ev.data.data32[1] |= 0x1UL; + if (!suppress) ev.data.data32[1] |= 0x2UL; + + ev.data.data32[2] = rect.x; + ev.data.data32[2] <<= 16; + ev.data.data32[2] |= rect.y; + ev.data.data32[3] = rect.width; + ev.data.data32[3] <<= 16; + ev.data.data32[3] |= rect.height; + + if (will_accept) + ev.data.data32[4] = action; + else + ev.data.data32[4] = XCB_NONE; + _target->accepted_action = action; + + xcb_send_event(_ecore_xcb_conn, 0, _target->source, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); +} + +EAPI Eina_Bool +ecore_x_dnd_drop(void) +{ + xcb_client_message_event_t ev; + Eina_Bool status = EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + + if (_source->dest) + { + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 32; + ev.window = _source->dest; + + if (_source->will_accept) + { + ev.type = ECORE_X_ATOM_XDND_DROP; + ev.data.data32[0] = _source->win; + ev.data.data32[1] = 0; + ev.data.data32[2] = _source->time; + + xcb_send_event(_ecore_xcb_conn, 0, _source->dest, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); + _source->state = ECORE_X_DND_SOURCE_DROPPED; + status = EINA_TRUE; + } + else + { + ev.type = ECORE_X_ATOM_XDND_LEAVE; + ev.data.data32[0] = _source->win; + ev.data.data32[1] = 0; + + xcb_send_event(_ecore_xcb_conn, 0, _source->dest, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); + _source->state = ECORE_X_DND_SOURCE_IDLE; + } + } + else + { + ecore_x_selection_xdnd_clear(); + _source->state = ECORE_X_DND_SOURCE_IDLE; + } + + ecore_x_window_ignore_set(_source->win, 0); + _source->prev.window = 0; + + return status; +} + +EAPI void +ecore_x_dnd_aware_set(Ecore_X_Window win, + Eina_Bool on) +{ + Ecore_X_Atom prop_data = ECORE_X_DND_VERSION; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (on) + ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_AWARE, + ECORE_X_ATOM_ATOM, 32, &prop_data, 1); + else + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_AWARE); +} + +EAPI int +ecore_x_dnd_version_get(Ecore_X_Window win) +{ + unsigned char *data; + int num = 0; + Version_Cache_Item *t; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (_source->state == ECORE_X_DND_SOURCE_DRAGGING) + { + if (_version_cache) + { + int i = 0; + + for (i = 0; i < _version_cache_num; i++) + { + if (_version_cache[i].win == win) + return _version_cache[i].ver; + } + } + } + + if (ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_AWARE, + ECORE_X_ATOM_ATOM, 32, &data, &num)) + { + int version = 0; + + version = (int)*data; + free(data); + if (_source->state == ECORE_X_DND_SOURCE_DRAGGING) + { + _version_cache_num++; + if (_version_cache_num > _version_cache_alloc) + _version_cache_alloc += 16; + t = realloc(_version_cache, + _version_cache_alloc * sizeof(Version_Cache_Item)); + if (!t) return 0; + _version_cache = t; + _version_cache[_version_cache_num - 1].win = win; + _version_cache[_version_cache_num - 1].ver = version; + } + return version; + } + + if (_source->state == ECORE_X_DND_SOURCE_DRAGGING) + { + _version_cache_num++; + if (_version_cache_num > _version_cache_alloc) + _version_cache_alloc += 16; + t = realloc(_version_cache, + _version_cache_alloc * sizeof(Version_Cache_Item)); + if (!t) return 0; + _version_cache = t; + _version_cache[_version_cache_num - 1].win = win; + _version_cache[_version_cache_num - 1].ver = 0; + } + + return 0; +} + +EAPI Eina_Bool +ecore_x_dnd_type_isset(Ecore_X_Window win, + const char *type) +{ + int num = 0, i = 0; + Eina_Bool ret = EINA_FALSE; + unsigned char *data; + Ecore_X_Atom *atoms, atom; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_TYPE_LIST, + ECORE_X_ATOM_ATOM, 32, &data, &num)) + return ret; + + atom = ecore_x_atom_get(type); + atoms = (Ecore_X_Atom *)data; + for (i = 0; i < num; ++i) + { + if (atom == atoms[i]) + { + ret = EINA_TRUE; + break; + } + } + + free(data); + return ret; +} + +EAPI void +ecore_x_dnd_type_set(Ecore_X_Window win, + const char *type, + Eina_Bool on) +{ + Ecore_X_Atom atom, *oldset = NULL, *newset = NULL; + int i = 0, j = 0, num = 0; + unsigned char *data = NULL, *old_data = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + atom = ecore_x_atom_get(type); + ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_TYPE_LIST, + ECORE_X_ATOM_ATOM, 32, &old_data, &num); + oldset = (Ecore_X_Atom *)old_data; + if (on) + { + if (ecore_x_dnd_type_isset(win, type)) + { + free(old_data); + return; + } + newset = calloc(num + 1, sizeof(Ecore_X_Atom)); + if (!newset) return; + data = (unsigned char *)newset; + for (i = 0; i < num; i++) + newset[i + 1] = oldset[i]; + newset[0] = atom; + ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST, + ECORE_X_ATOM_ATOM, 32, data, num + 1); + } + else + { + if (!ecore_x_dnd_type_isset(win, type)) + { + free(old_data); + return; + } + newset = calloc(num - 1, sizeof(Ecore_X_Atom)); + if (!newset) + { + free(old_data); + return; + } + data = (unsigned char *)newset; + for (i = 0; i < num; i++) + if (oldset[i] != atom) + newset[j++] = oldset[i]; + ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST, + ECORE_X_ATOM_ATOM, 32, data, num - 1); + } + free(oldset); + free(newset); +} + +EAPI void +ecore_x_dnd_types_set(Ecore_X_Window win, + const char **types, + unsigned int num_types) +{ + Ecore_X_Atom *newset = NULL; + unsigned int i; + unsigned char *data = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!num_types) + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_TYPE_LIST); + else + { + newset = calloc(num_types, sizeof(Ecore_X_Atom)); + if (!newset) return; + + data = (unsigned char *)newset; + for (i = 0; i < num_types; i++) + { + newset[i] = ecore_x_atom_get(types[i]); + ecore_x_selection_converter_atom_add(newset[i], + _ecore_xcb_dnd_converter_copy); + } + ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST, + ECORE_X_ATOM_ATOM, 32, data, + num_types); + free(newset); + } +} + +EAPI void +ecore_x_dnd_actions_set(Ecore_X_Window win, + Ecore_X_Atom *actions, + unsigned int num_actions) +{ + unsigned int i; + unsigned char *data = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!num_actions) + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_ACTION_LIST); + else + { + data = (unsigned char *)actions; + for (i = 0; i < num_actions; i++) + ecore_x_selection_converter_atom_add(actions[i], + _ecore_xcb_dnd_converter_copy); + ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_ACTION_LIST, + ECORE_X_ATOM_ATOM, 32, data, + num_actions); + } +} + +/** + * The DND position update cb is called Ecore_X sends a DND position to a + * client. + * + * It essentially mirrors some of the data sent in the position message. + * Generally this cb should be set just before position update is called. + * Please note well you need to look after your own data pointer if someone + * trashes you position update cb set. + * + * It is considered good form to clear this when the dnd event finishes. + * + * @param cb Callback to updated each time ecore_x sends a position update. + * @param data User data. + */ +EAPI void +ecore_x_dnd_callback_pos_update_set(void (*cb)(void *, Ecore_X_Xdnd_Position *data), + const void *data) +{ + _posupdatecb = cb; + _posupdatedata = (void *)data; +} + +EAPI Eina_Bool +ecore_x_dnd_begin(Ecore_X_Window source, + unsigned char *data, + int size) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_dnd_version_get(source)) return EINA_FALSE; + + /* Take ownership of XdndSelection */ + if (!ecore_x_selection_xdnd_set(source, data, size)) return EINA_FALSE; + + if (_version_cache) + { + free(_version_cache); + _version_cache = NULL; + _version_cache_num = 0; + _version_cache_alloc = 0; + } + + ecore_x_window_shadow_tree_flush(); + + _source->win = source; + ecore_x_window_ignore_set(_source->win, 1); + _source->state = ECORE_X_DND_SOURCE_DRAGGING; + _source->time = _ecore_xcb_events_last_time_get(); + _source->prev.window = 0; + + /* Default Accepted Action: move */ + _source->action = ECORE_X_ATOM_XDND_ACTION_MOVE; + _source->accepted_action = XCB_NONE; + _source->dest = XCB_NONE; + + return EINA_TRUE; +} + +EAPI void +ecore_x_dnd_send_finished(void) +{ + xcb_client_message_event_t ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (_target->state == ECORE_X_DND_TARGET_IDLE) return; + + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 32; + ev.type = ECORE_X_ATOM_XDND_FINISHED; + ev.window = _target->source; + ev.data.data32[0] = _target->win; + ev.data.data32[1] = 0; + ev.data.data32[2] = 0; + if (_target->will_accept) + { + ev.data.data32[1] |= 0x1UL; + ev.data.data32[2] = _target->accepted_action; + } + + xcb_send_event(_ecore_xcb_conn, 0, _target->source, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); + _target->state = ECORE_X_DND_TARGET_IDLE; +} + +EAPI void +ecore_x_dnd_source_action_set(Ecore_X_Atom action) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _source->action = action; + if (_source->prev.window) + _ecore_xcb_dnd_drag(_source->prev.window, + _source->prev.x, _source->prev.y); +} + +Ecore_X_DND_Source * +_ecore_xcb_dnd_source_get(void) +{ + return _source; +} + +Ecore_X_DND_Target * +_ecore_xcb_dnd_target_get(void) +{ + return _target; +} + +void +_ecore_xcb_dnd_drag(Ecore_X_Window root, + int x, + int y) +{ + xcb_client_message_event_t ev; + Ecore_X_Window win, *skip; + Ecore_X_Xdnd_Position pos; + int num = 0; + + if (_source->state != ECORE_X_DND_SOURCE_DRAGGING) return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 32; + + skip = ecore_x_window_ignore_list(&num); + win = ecore_x_window_shadow_tree_at_xy_with_skip_get(root, x, y, skip, num); + while ((win) && !(ecore_x_dnd_version_get(win))) + win = ecore_x_window_shadow_parent_get(root, win); + + if ((_source->dest) && (win != _source->dest)) + { + ev.window = _source->dest; + ev.type = ECORE_X_ATOM_XDND_LEAVE; + ev.data.data32[0] = _source->win; + ev.data.data32[1] = 0; + + xcb_send_event(_ecore_xcb_conn, 0, _source->dest, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); + _source->suppress = 0; + } + + if (win) + { + int x1, x2, y1, y2; + + _source->version = MIN(ECORE_X_DND_VERSION, + ecore_x_dnd_version_get(win)); + if (win != _source->dest) + { + int i = 0; + unsigned char *data; + Ecore_X_Atom *types; + + ecore_x_window_prop_property_get(_source->win, + ECORE_X_ATOM_XDND_TYPE_LIST, + ECORE_X_ATOM_ATOM, 32, + &data, &num); + types = (Ecore_X_Atom *)data; + ev.window = win; + ev.type = ECORE_X_ATOM_XDND_ENTER; + ev.data.data32[0] = _source->win; + ev.data.data32[1] = 0; + if (num > 3) + ev.data.data32[1] |= 0x1UL; + else + ev.data.data32[1] &= 0xfffffffeUL; + ev.data.data32[1] |= ((unsigned long)_source->version) << 24; + + for (i = 2; i < 5; i++) + ev.data.data32[i] = 0; + for (i = 0; i < MIN(num, 3); ++i) + ev.data.data32[i + 2] = types[i]; + free(data); + + xcb_send_event(_ecore_xcb_conn, 0, win, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); + _source->await_status = 0; + _source->will_accept = 0; + } + + x1 = _source->rectangle.x; + x2 = _source->rectangle.x + _source->rectangle.width; + y1 = _source->rectangle.y; + y2 = _source->rectangle.y + _source->rectangle.height; + + if ((!_source->await_status) || (!_source->suppress) || + ((x < x1) || (x > x2) || (y < y1) || (y > y2))) + { + ev.window = win; + ev.type = ECORE_X_ATOM_XDND_POSITION; + ev.data.data32[0] = _source->win; + ev.data.data32[1] = 0; + ev.data.data32[2] = ((x << 16) & 0xffff0000) | (y & 0xffff); + ev.data.data32[3] = _source->time; + ev.data.data32[4] = _source->action; + + xcb_send_event(_ecore_xcb_conn, 0, win, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); + _source->await_status = 1; + } + } + + if (_posupdatecb) + { + pos.position.x = x; + pos.position.y = y; + pos.win = win; + pos.prev = _source->dest; + _posupdatecb(_posupdatedata, &pos); + } + + _source->prev.x = x; + _source->prev.y = y; + _source->prev.window = root; + _source->dest = win; +} + +EAPI Ecore_X_Atom +ecore_x_dnd_source_action_get(void) +{ + return _source->action; +} + +/* local functions */ +static Eina_Bool +_ecore_xcb_dnd_converter_copy(char *target __UNUSED__, + void *data, + int size, + void **data_ret, + int *size_ret, + Ecore_X_Atom *tprop __UNUSED__, + int *count __UNUSED__) +{ + Ecore_Xcb_Textproperty text_prop; + Ecore_Xcb_Encoding_Style style = XcbTextStyle; + char *mystr; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if ((!data) || (!size)) return EINA_FALSE; + + mystr = calloc(1, size + 1); + if (!mystr) return EINA_FALSE; + + memcpy(mystr, data, size); + if (_ecore_xcb_mb_textlist_to_textproperty(&mystr, 1, style, &text_prop)) + { + int len; + + len = strlen((char *)text_prop.value) + 1; + if (!(*data_ret = malloc(len))) + { + free(mystr); + return EINA_FALSE; + } + memcpy(*data_ret, text_prop.value, len); + *size_ret = len; + free(text_prop.value); + free(mystr); + return EINA_TRUE; + } + else + { + free(mystr); + return EINA_FALSE; + } +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_dpms.c b/src/lib/ecore_x/xcb/ecore_xcb_dpms.c new file mode 100644 index 0000000..39ef589 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_dpms.c @@ -0,0 +1,320 @@ +#include "ecore_xcb_private.h" +#ifdef ECORE_XCB_DAMAGE +# include +#endif + +/* local variables */ +static Eina_Bool _dpms_avail = EINA_FALSE; + +void +_ecore_xcb_dpms_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_DPMS + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_dpms_id); +#endif +} + +void +_ecore_xcb_dpms_finalize(void) +{ +#ifdef ECORE_XCB_DPMS + const xcb_query_extension_reply_t *ext_reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_DPMS + ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_dpms_id); + if ((ext_reply) && (ext_reply->present)) + { + xcb_dpms_get_version_cookie_t cookie; + xcb_dpms_get_version_reply_t *reply; + + cookie = + xcb_dpms_get_version_unchecked(_ecore_xcb_conn, + XCB_DPMS_MAJOR_VERSION, + XCB_DPMS_MINOR_VERSION); + reply = xcb_dpms_get_version_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + if (reply->server_major_version >= 1) + _dpms_avail = EINA_TRUE; + free(reply); + } + } +#endif +} + +/** + * @defgroup Ecore_X_DPMS_Group X DPMS Extension Functions + * + * Functions related to the X DPMS Extension + */ + +/** + * Checks if the DPMS extension is available or not. + * + * @return @c EINA_TRUE if the DPMS extension is available, + * @c EINA_FALSE otherwise. + * + * Return @c EINA_TRUE if the X server supports the DPMS Extension version 1.0, + * @c EINA_FALSE otherwise. + * + * @ingroup Ecore_X_DPMS_Group + */ +EAPI Eina_Bool +ecore_x_dpms_query(void) +{ +// LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _dpms_avail; +} + +/** + * Checks if the X server is capable of DPMS. + * @return @c 1 if the X server is capable of DPMS, @c 0 otherwise. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI Eina_Bool +ecore_x_dpms_capable_get(void) +{ + Eina_Bool ret = EINA_FALSE; +#ifdef ECORE_XCB_DPMS + xcb_dpms_capable_cookie_t cookie; + xcb_dpms_capable_reply_t *reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_dpms_avail) return EINA_FALSE; + +#ifdef ECORE_XCB_DPMS + cookie = xcb_dpms_capable_unchecked(_ecore_xcb_conn); + reply = xcb_dpms_capable_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + ret = reply->capable; + free(reply); + } +#endif + + return ret; +} + +/** + * Checks the DPMS state of the display. + * @return @c EINA_TRUE if DPMS is enabled, @c EINA_FALSE otherwise. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI Eina_Bool +ecore_x_dpms_enabled_get(void) +{ + Eina_Bool ret = EINA_FALSE; +#ifdef ECORE_XCB_DPMS + xcb_dpms_info_cookie_t cookie; + xcb_dpms_info_reply_t *reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_dpms_avail) return EINA_FALSE; + +#ifdef ECORE_XCB_DPMS + cookie = xcb_dpms_info_unchecked(_ecore_xcb_conn); + reply = xcb_dpms_info_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return EINA_FALSE; + if (reply->state) ret = EINA_TRUE; + free(reply); +#endif + + return ret; +} + +/** + * Sets the DPMS state of the display. + * @param enabled @c 0 to disable DPMS characteristics of the server, enable it otherwise. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI void +ecore_x_dpms_enabled_set(int enabled) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_dpms_avail) return; + +#ifdef ECORE_XCB_DPMS + if (enabled) + xcb_dpms_enable(_ecore_xcb_conn); + else + xcb_dpms_disable(_ecore_xcb_conn); +#endif +} + +/** + * Gets the timeouts. The values are in unit of seconds. + * @param standby Amount of time of inactivity before standby mode will be invoked. + * @param suspend Amount of time of inactivity before the screen is placed into suspend mode. + * @param off Amount of time of inactivity before the monitor is shut off. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI void +ecore_x_dpms_timeouts_get(unsigned int *standby, + unsigned int *suspend, + unsigned int *off) +{ +#ifdef ECORE_XCB_DPMS + xcb_dpms_get_timeouts_cookie_t cookie; + xcb_dpms_get_timeouts_reply_t *reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (standby) *standby = 0; + if (suspend) *suspend = 0; + if (off) *off = 0; + + if (!_dpms_avail) return; + +#ifdef ECORE_XCB_DPMS + cookie = xcb_dpms_get_timeouts_unchecked(_ecore_xcb_conn); + reply = xcb_dpms_get_timeouts_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return; + if (standby) *standby = reply->standby_timeout; + if (suspend) *suspend = reply->suspend_timeout; + if (off) *off = reply->off_timeout; + free(reply); +#endif +} + +/** + * Sets the timeouts. The values are in unit of seconds. + * + * @param standby Amount of time of inactivity before standby mode will be invoked. + * @param suspend Amount of time of inactivity before the screen is placed into suspend mode. + * @param off Amount of time of inactivity before the monitor is shut off. + * @return @c EINA_TRUE on success, @c EINA_FALSE on failure. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI Eina_Bool +ecore_x_dpms_timeouts_set(unsigned int standby, + unsigned int suspend, + unsigned int off) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_dpms_avail) return EINA_FALSE; + +#ifdef ECORE_XCB_DPMS + // FIXME: Add request check + xcb_dpms_set_timeouts(_ecore_xcb_conn, standby, suspend, off); + return EINA_TRUE; +#endif + + return EINA_FALSE; +} + +/** + * Returns the amount of time of inactivity before standby mode is invoked. + * @return The standby timeout value. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI unsigned int +ecore_x_dpms_timeout_standby_get(void) +{ + unsigned int standby = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_dpms_timeouts_get(&standby, NULL, NULL); + return standby; +} + +/** + * Returns the amount of time of inactivity before the second level of + * power saving is invoked. + * @return The suspend timeout value. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI unsigned int +ecore_x_dpms_timeout_suspend_get(void) +{ + unsigned int suspend = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_dpms_timeouts_get(NULL, &suspend, NULL); + return suspend; +} + +/** + * Returns the amount of time of inactivity before the third and final + * level of power saving is invoked. + * @return The off timeout value. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI unsigned int +ecore_x_dpms_timeout_off_get(void) +{ + unsigned int off = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_dpms_timeouts_get(NULL, NULL, &off); + return off; +} + +/** + * Sets the standby timeout (in unit of seconds). + * @param new_timeout Amount of time of inactivity before standby mode will be invoked. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI void +ecore_x_dpms_timeout_standby_set(unsigned int new_timeout) +{ + unsigned int standby = 0, suspend = 0, off = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_dpms_timeouts_get(&standby, &suspend, &off); + ecore_x_dpms_timeouts_set(new_timeout, suspend, off); +} + +/** + * Sets the suspend timeout (in unit of seconds). + * @param new_timeout Amount of time of inactivity before the screen is placed into suspend mode. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI void +ecore_x_dpms_timeout_suspend_set(unsigned int new_timeout) +{ + unsigned int standby = 0, suspend = 0, off = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_dpms_timeouts_get(&standby, &suspend, &off); + ecore_x_dpms_timeouts_set(standby, new_timeout, off); +} + +/** + * Sets the off timeout (in unit of seconds). + * @param new_timeout Amount of time of inactivity before the monitor is shut off. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI void +ecore_x_dpms_timeout_off_set(unsigned int new_timeout) +{ + unsigned int standby = 0, suspend = 0, off = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_dpms_timeouts_get(&standby, &suspend, &off); + ecore_x_dpms_timeouts_set(standby, suspend, new_timeout); +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_drawable.c b/src/lib/ecore_x/xcb/ecore_xcb_drawable.c new file mode 100644 index 0000000..4e9a356 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_drawable.c @@ -0,0 +1,123 @@ +#include "ecore_xcb_private.h" + +/** + * @defgroup Ecore_X_Drawable_Group X Drawable Functions + * + * Functions that operate on drawables. + */ + +/** + * Fill the specified rectangle on a drawable. + * @param d The given drawable. + * @param gc The graphic context that controls the fill rules. + * @param x The X coordinate of the top-left corner of the rectangle. + * @param y The Y coordinate of the top-left corner of the rectangle. + * @param width The width of the rectangle. + * @param height The height of the rectangle. + */ +EAPI void +ecore_x_drawable_rectangle_fill(Ecore_X_Drawable draw, + Ecore_X_GC gc, + int x, + int y, + int w, + int h) +{ + xcb_rectangle_t rect; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + xcb_poly_fill_rectangle(_ecore_xcb_conn, draw, gc, 1, + (const xcb_rectangle_t *)&rect); +// ecore_x_flush(); +} + +/** + * Retrieves the geometry of the given drawable. + * @param d The given drawable. + * @param x Pointer to an integer into which the X position is to be stored. + * @param y Pointer to an integer into which the Y position is to be stored. + * @param w Pointer to an integer into which the width is to be stored. + * @param h Pointer to an integer into which the height is to be stored. + * @ingroup Ecore_X_Drawable_Group + */ +EAPI void +ecore_x_drawable_geometry_get(Ecore_X_Drawable draw, + int *x, + int *y, + int *w, + int *h) +{ + xcb_get_geometry_cookie_t cookie; + xcb_get_geometry_reply_t *reply; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (x) *x = 0; + if (y) *y = 0; + if (w) *w = 0; + if (h) *h = 0; + cookie = xcb_get_geometry_unchecked(_ecore_xcb_conn, draw); + reply = xcb_get_geometry_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return; + if (x) *x = reply->x; + if (y) *y = reply->y; + if (w) *w = (int)reply->width; + if (h) *h = (int)reply->height; + free(reply); +} + +/** + * Retrieves the width of the border of the given drawable. + * @param d The given drawable. + * @return The border width of the given drawable. + * @ingroup Ecore_X_Drawable_Group + */ +EAPI int +ecore_x_drawable_border_width_get(Ecore_X_Drawable d) +{ + xcb_get_geometry_cookie_t cookie; + xcb_get_geometry_reply_t *reply; + int ret = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + cookie = xcb_get_geometry_unchecked(_ecore_xcb_conn, d); + reply = xcb_get_geometry_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return 0; + ret = (int)reply->border_width; + free(reply); + return ret; +} + +/** + * Retrieves the depth of the given drawable. + * @param d The given drawable. + * @return The depth of the given drawable. + * @ingroup Ecore_X_Drawable_Group + */ +EAPI int +ecore_x_drawable_depth_get(Ecore_X_Drawable d) +{ + xcb_get_geometry_cookie_t cookie; + xcb_get_geometry_reply_t *reply; + int ret = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + cookie = xcb_get_geometry_unchecked(_ecore_xcb_conn, d); + reply = xcb_get_geometry_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return 0; + ret = (int)reply->depth; + free(reply); + return ret; +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_e.c b/src/lib/ecore_x/xcb/ecore_xcb_e.c new file mode 100644 index 0000000..d86d0c7 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_e.c @@ -0,0 +1,1552 @@ +#include "ecore_xcb_private.h" + +/* local function prototypes */ +static Ecore_X_Atom _ecore_xcb_e_vkbd_atom_get(Ecore_X_Virtual_Keyboard_State state); +static Ecore_X_Virtual_Keyboard_State _ecore_xcb_e_vkbd_state_get(Ecore_X_Atom atom); +static Ecore_X_Atom _ecore_xcb_e_quickpanel_atom_get(Ecore_X_Illume_Quickpanel_State state); +static Ecore_X_Illume_Quickpanel_State _ecore_xcb_e_quickpanel_state_get(Ecore_X_Atom atom); +static Ecore_X_Atom _ecore_xcb_e_illume_atom_get(Ecore_X_Illume_Mode mode); +static Ecore_X_Illume_Mode _ecore_xcb_e_illume_mode_get(Ecore_X_Atom atom); +static Ecore_X_Atom _ecore_xcb_e_indicator_atom_get(Ecore_X_Illume_Indicator_State state); +static Ecore_X_Illume_Indicator_State _ecore_xcb_e_indicator_state_get(Ecore_X_Atom atom); + +EAPI void +ecore_x_e_init(void) +{ +} + +EAPI void +ecore_x_e_comp_sync_draw_done_send(Ecore_X_Window root, + Ecore_X_Window win) +{ + xcb_client_message_event_t ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!root) root = ((xcb_screen_t *)_ecore_xcb_screen)->root; + + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 32; + ev.window = win; + ev.type = ECORE_X_ATOM_E_COMP_SYNC_DRAW_DONE; + ev.data.data32[0] = win; + ev.data.data32[1] = 0; + ev.data.data32[2] = 0; + ev.data.data32[3] = 0; + ev.data.data32[4] = 0; + + xcb_send_event(_ecore_xcb_conn, 0, root, + (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY), (const char *)&ev); +// ecore_x_flush(); +} + +EAPI void +ecore_x_e_comp_sync_draw_size_done_send(Ecore_X_Window root, + Ecore_X_Window win, + int w, + int h) +{ + xcb_client_message_event_t ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!root) root = ((xcb_screen_t *)_ecore_xcb_screen)->root; + + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 32; + ev.window = win; + ev.type = ECORE_X_ATOM_E_COMP_SYNC_DRAW_DONE; + ev.data.data32[0] = win; + ev.data.data32[1] = 1; + ev.data.data32[2] = w; + ev.data.data32[3] = h; + ev.data.data32[4] = 0; + + xcb_send_event(_ecore_xcb_conn, 0, root, + (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY), (const char *)&ev); +// ecore_x_flush(); +} + +EAPI void +ecore_x_e_comp_sync_counter_set(Ecore_X_Window win, + Ecore_X_Sync_Counter counter) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (counter) + ecore_x_window_prop_xid_set(win, ECORE_X_ATOM_E_COMP_SYNC_COUNTER, + ECORE_X_ATOM_CARDINAL, &counter, 1); + else + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_E_COMP_SYNC_COUNTER); +} + +EAPI Ecore_X_Sync_Counter +ecore_x_e_comp_sync_counter_get(Ecore_X_Window win) +{ + Ecore_X_Sync_Counter counter = 0; + int ret = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ret = ecore_x_window_prop_xid_get(win, ECORE_X_ATOM_E_COMP_SYNC_COUNTER, + ECORE_X_ATOM_CARDINAL, &counter, 1); + if (ret != 1) return 0; + return counter; +} + +EAPI Eina_Bool +ecore_x_e_comp_sync_supported_get(Ecore_X_Window root) +{ + Ecore_X_Window win, win2; + int ret = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!root) root = ((xcb_screen_t *)_ecore_xcb_screen)->root; + ret = + ecore_x_window_prop_xid_get(root, ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED, + ECORE_X_ATOM_WINDOW, &win, 1); + if ((ret == 1) && (win)) + { + ret = + ecore_x_window_prop_xid_get(win, ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED, + ECORE_X_ATOM_WINDOW, &win2, 1); + if ((ret == 1) && (win2 == win)) + return EINA_TRUE; + } + return EINA_FALSE; +} + +EAPI void +ecore_x_e_window_profile_list_set(Ecore_X_Window win, + const char **profiles, + unsigned int num_profiles) +{ + Ecore_X_Atom *atoms; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!win) + return; + + if (!num_profiles) + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_E_PROFILE_LIST); + else + { + atoms = alloca(num_profiles * sizeof(Ecore_X_Atom)); + ecore_x_atoms_get(profiles, num_profiles, atoms); + ecore_x_window_prop_property_set(win, + ECORE_X_ATOM_E_PROFILE_LIST, + ECORE_X_ATOM_ATOM, 32, (void *)atoms, + num_profiles); + } +} + +EAPI Eina_Bool +ecore_x_e_window_profile_list_get(Ecore_X_Window win, + const char ***profiles, + int *ret_num) +{ + unsigned char *data = NULL; + Ecore_X_Atom *atoms; + int num, i; + + if (ret_num) + *ret_num = 0; + + if (profiles) + *profiles = NULL; + + if (!win) + return EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_property_get(win, + ECORE_X_ATOM_E_PROFILE_LIST, + ECORE_X_ATOM_ATOM, 32, &data, &num)) + return EINA_FALSE; + + if (ret_num) + *ret_num = num; + + if (profiles) + { + (*profiles) = calloc(num, sizeof(char *)); + if (!(*profiles)) + { + if (ret_num) + *ret_num = 0; + + if (data) + free(data); + + return EINA_FALSE; + } + + atoms = (Ecore_X_Atom *)data; + for (i = 0; i < num; i++) + (*profiles)[i] = ecore_x_atom_name_get(atoms[i]); + } + + if (data) + free(data); + + return EINA_TRUE; +} + +EAPI void +ecore_x_e_window_profile_set(Ecore_X_Window win, + const char *profile) +{ + Ecore_X_Atom atom; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!win) + return; + + if (!profile) + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_E_PROFILE); + else + { + atom = ecore_x_atom_get(profile); + ecore_x_window_prop_property_set(win, ECORE_X_ATOM_E_PROFILE, + ECORE_X_ATOM_ATOM, 32, (void *)&atom, 1); + } +} + +EAPI char * +ecore_x_e_window_profile_get(Ecore_X_Window win) +{ + Ecore_X_Atom *atom = NULL; + unsigned char *data; + char *profile = NULL; + int num; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_property_get(win, ECORE_X_ATOM_E_PROFILE, + ECORE_X_ATOM_ATOM, 32, &data, &num)) + return NULL; + + if (data) + atom = (Ecore_X_Atom *)data; + + if (atom) + profile = ecore_x_atom_name_get(atom[0]); + + return profile; +} + +EAPI void +ecore_x_e_comp_sync_supported_set(Ecore_X_Window root, + Eina_Bool enabled) +{ + Ecore_X_Window win; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!root) root = ((xcb_screen_t *)_ecore_xcb_screen)->root; + if (enabled) + { + win = ecore_x_window_new(root, 1, 2, 3, 4); + ecore_x_window_prop_xid_set(win, ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED, + ECORE_X_ATOM_WINDOW, &win, 1); + ecore_x_window_prop_xid_set(root, ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED, + ECORE_X_ATOM_WINDOW, &win, 1); + } + else + { + int ret = 0; + + ret = ecore_x_window_prop_xid_get(root, + ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED, + ECORE_X_ATOM_WINDOW, &win, 1); + if ((ret == 1) && (win)) + { + ecore_x_window_prop_property_del(root, + ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED); + ecore_x_window_free(win); + } + } +} + +EAPI void +ecore_x_e_comp_sync_begin_send(Ecore_X_Window win) +{ + xcb_client_message_event_t ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 32; + ev.window = win; + ev.type = ECORE_X_ATOM_E_COMP_SYNC_BEGIN; + ev.data.data32[0] = win; + ev.data.data32[1] = 0; + ev.data.data32[2] = 0; + ev.data.data32[3] = 0; + ev.data.data32[4] = 0; + + xcb_send_event(_ecore_xcb_conn, 0, win, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); +} + +EAPI void +ecore_x_e_comp_sync_end_send(Ecore_X_Window win) +{ + xcb_client_message_event_t ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 32; + ev.window = win; + ev.type = ECORE_X_ATOM_E_COMP_SYNC_END; + ev.data.data32[0] = win; + ev.data.data32[1] = 0; + ev.data.data32[2] = 0; + ev.data.data32[3] = 0; + ev.data.data32[4] = 0; + + xcb_send_event(_ecore_xcb_conn, 0, win, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); +} + +EAPI void +ecore_x_e_comp_sync_cancel_send(Ecore_X_Window win) +{ + xcb_client_message_event_t ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 32; + ev.window = win; + ev.type = ECORE_X_ATOM_E_COMP_SYNC_CANCEL; + ev.data.data32[0] = win; + ev.data.data32[1] = 0; + ev.data.data32[2] = 0; + ev.data.data32[3] = 0; + ev.data.data32[4] = 0; + + xcb_send_event(_ecore_xcb_conn, 0, win, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); +} + +EAPI void +ecore_x_e_comp_flush_send(Ecore_X_Window win) +{ + xcb_client_message_event_t ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 32; + ev.window = win; + ev.type = ECORE_X_ATOM_E_COMP_FLUSH; + ev.data.data32[0] = win; + ev.data.data32[1] = 0; + ev.data.data32[2] = 0; + ev.data.data32[3] = 0; + ev.data.data32[4] = 0; + + xcb_send_event(_ecore_xcb_conn, 0, win, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); +} + +EAPI void +ecore_x_e_comp_dump_send(Ecore_X_Window win) +{ + xcb_client_message_event_t ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 32; + ev.window = win; + ev.type = ECORE_X_ATOM_E_COMP_DUMP; + ev.data.data32[0] = win; + ev.data.data32[1] = 0; + ev.data.data32[2] = 0; + ev.data.data32[3] = 0; + ev.data.data32[4] = 0; + + xcb_send_event(_ecore_xcb_conn, 0, win, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); +} + +EAPI void +ecore_x_e_comp_pixmap_set(Ecore_X_Window win, + Ecore_X_Pixmap pixmap) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (pixmap) + ecore_x_window_prop_xid_set(win, ECORE_X_ATOM_E_COMP_PIXMAP, + ECORE_X_ATOM_PIXMAP, &pixmap, 1); + else + ecore_x_window_prop_property_del(win, pixmap); +} + +EAPI Ecore_X_Pixmap +ecore_x_e_comp_pixmap_get(Ecore_X_Window win) +{ + Ecore_X_Pixmap pixmap = 0; + int ret = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ret = ecore_x_window_prop_xid_get(win, ECORE_X_ATOM_E_COMP_PIXMAP, + ECORE_X_ATOM_PIXMAP, &pixmap, 1); + if (ret != 1) return 0; + return pixmap; +} + +EAPI void +ecore_x_e_frame_size_set(Ecore_X_Window win, + int fl, + int fr, + int ft, + int fb) +{ + uint32_t frames[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + frames[0] = fl; + frames[1] = fr; + frames[2] = ft; + frames[3] = fb; + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_FRAME_SIZE, frames, 4); +} + +EAPI Ecore_X_Virtual_Keyboard_State +ecore_x_e_virtual_keyboard_state_get(Ecore_X_Window win) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_atom_get(win, ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE, + &atom, 1)) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_UNKNOWN; + + return _ecore_xcb_e_vkbd_state_get(atom); +} + +EAPI void +ecore_x_e_virtual_keyboard_state_set(Ecore_X_Window win, + Ecore_X_Virtual_Keyboard_State state) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + atom = _ecore_xcb_e_vkbd_atom_get(state); + ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE, + &atom, 1); +} + +EAPI void +ecore_x_e_virtual_keyboard_state_send(Ecore_X_Window win, + Ecore_X_Virtual_Keyboard_State state) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + _ecore_xcb_e_vkbd_atom_get(state), + 0, 0, 0, 0); +} + +EAPI void +ecore_x_e_virtual_keyboard_set(Ecore_X_Window win, + unsigned int is_keyboard) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_VIRTUAL_KEYBOARD, + &is_keyboard, 1); +} + +EAPI Eina_Bool +ecore_x_e_virtual_keyboard_get(Ecore_X_Window win) +{ + unsigned int val = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_E_VIRTUAL_KEYBOARD, + &val, 1)) + return EINA_FALSE; + + return val ? EINA_TRUE : EINA_FALSE; +} + +EAPI int +ecore_x_e_illume_quickpanel_priority_major_get(Ecore_X_Window win) +{ + unsigned int val = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_card32_get(win, + ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR, + &val, 1)) + return 0; + + return val; +} + +EAPI void +ecore_x_e_illume_quickpanel_priority_major_set(Ecore_X_Window win, + unsigned int priority) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_card32_set(win, + ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR, + &priority, 1); +} + +EAPI int +ecore_x_e_illume_quickpanel_priority_minor_get(Ecore_X_Window win) +{ + unsigned int val = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_card32_get(win, + ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MINOR, + &val, 1)) + return 0; + + return val; +} + +EAPI void +ecore_x_e_illume_quickpanel_priority_minor_set(Ecore_X_Window win, + unsigned int priority) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_card32_set(win, + ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MINOR, + &priority, 1); +} + +EAPI void +ecore_x_e_illume_quickpanel_zone_set(Ecore_X_Window win, + unsigned int zone) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ZONE, + &zone, 1); +} + +EAPI int +ecore_x_e_illume_quickpanel_zone_get(Ecore_X_Window win) +{ + unsigned int val = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_card32_get(win, + ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ZONE, + &val, 1)) + return 0; + + return val; +} + +EAPI void +ecore_x_e_illume_quickpanel_position_update_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_client_message32_send(win, + ECORE_X_ATOM_E_ILLUME_QUICKPANEL_POSITION_UPDATE, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + 1, 0, 0, 0, 0); +} + +EAPI Eina_Bool +ecore_x_e_illume_conformant_get(Ecore_X_Window win) +{ + unsigned int val = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_E_ILLUME_CONFORMANT, + &val, 1)) + return EINA_FALSE; + + return val ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_x_e_illume_conformant_set(Ecore_X_Window win, + unsigned int is_conformant) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_CONFORMANT, + &is_conformant, 1); +} + +EAPI void +ecore_x_e_illume_softkey_geometry_set(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ + unsigned int geom[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + geom[0] = x; + geom[1] = y; + geom[2] = w; + geom[3] = h; + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_SOFTKEY_GEOMETRY, + geom, 4); +} + +EAPI Eina_Bool +ecore_x_e_illume_softkey_geometry_get(Ecore_X_Window win, + int *x, + int *y, + int *w, + int *h) +{ + unsigned int geom[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (x) *x = 0; + if (y) *y = 0; + if (w) *w = 0; + if (h) *h = 0; + + if (ecore_x_window_prop_card32_get(win, + ECORE_X_ATOM_E_ILLUME_SOFTKEY_GEOMETRY, + geom, 4) != 4) + return EINA_FALSE; + + if (x) *x = geom[0]; + if (y) *y = geom[1]; + if (w) *w = geom[2]; + if (h) *h = geom[3]; + + return EINA_TRUE; +} + +EAPI void +ecore_x_e_illume_indicator_geometry_set(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ + unsigned int geom[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + geom[0] = x; + geom[1] = y; + geom[2] = w; + geom[3] = h; + ecore_x_window_prop_card32_set(win, + ECORE_X_ATOM_E_ILLUME_INDICATOR_GEOMETRY, + geom, 4); +} + +EAPI Eina_Bool +ecore_x_e_illume_indicator_geometry_get(Ecore_X_Window win, + int *x, + int *y, + int *w, + int *h) +{ + unsigned int geom[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (x) *x = 0; + if (y) *y = 0; + if (w) *w = 0; + if (h) *h = 0; + + if (ecore_x_window_prop_card32_get(win, + ECORE_X_ATOM_E_ILLUME_INDICATOR_GEOMETRY, + geom, 4) != 4) + return EINA_FALSE; + + if (x) *x = geom[0]; + if (y) *y = geom[1]; + if (w) *w = geom[2]; + if (h) *h = geom[3]; + + return EINA_TRUE; +} + +EAPI void +ecore_x_e_illume_keyboard_geometry_set(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ + unsigned int geom[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + geom[0] = x; + geom[1] = y; + geom[2] = w; + geom[3] = h; + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_KEYBOARD_GEOMETRY, + geom, 4); +} + +EAPI Eina_Bool +ecore_x_e_illume_keyboard_geometry_get(Ecore_X_Window win, + int *x, + int *y, + int *w, + int *h) +{ + unsigned int geom[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (x) *x = 0; + if (y) *y = 0; + if (w) *w = 0; + if (h) *h = 0; + + if (ecore_x_window_prop_card32_get(win, + ECORE_X_ATOM_E_ILLUME_KEYBOARD_GEOMETRY, + geom, 4) != 4) + return EINA_FALSE; + + if (x) *x = geom[0]; + if (y) *y = geom[1]; + if (w) *w = geom[2]; + if (h) *h = geom[3]; + + return EINA_TRUE; +} + +EAPI void +ecore_x_e_illume_quickpanel_set(Ecore_X_Window win, + unsigned int is_quickpanel) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_QUICKPANEL, + &is_quickpanel, 1); +} + +EAPI Eina_Bool +ecore_x_e_illume_quickpanel_get(Ecore_X_Window win) +{ + unsigned int val = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_E_ILLUME_QUICKPANEL, + &val, 1)) + return EINA_FALSE; + + return val ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_x_e_illume_quickpanel_state_set(Ecore_X_Window win, + Ecore_X_Illume_Quickpanel_State state) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + atom = _ecore_xcb_e_quickpanel_atom_get(state); + ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE, + &atom, 1); +} + +EAPI Ecore_X_Illume_Quickpanel_State +ecore_x_e_illume_quickpanel_state_get(Ecore_X_Window win) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_atom_get(win, + ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE, + &atom, 1)) + return ECORE_X_ILLUME_QUICKPANEL_STATE_UNKNOWN; + + return _ecore_xcb_e_quickpanel_state_get(atom); +} + +EAPI void +ecore_x_e_illume_quickpanel_state_send(Ecore_X_Window win, + Ecore_X_Illume_Quickpanel_State state) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + _ecore_xcb_e_quickpanel_atom_get(state), + 0, 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_quickpanel_state_toggle(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, + ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE_TOGGLE, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + 0, 0, 0, 0, 0); +} + +static Ecore_X_Atom +_ecore_xcb_e_clipboard_atom_get(Ecore_X_Illume_Clipboard_State state) +{ + switch (state) + { + case ECORE_X_ILLUME_CLIPBOARD_STATE_ON: + return ECORE_X_ATOM_E_ILLUME_CLIPBOARD_ON; + case ECORE_X_ILLUME_CLIPBOARD_STATE_OFF: + return ECORE_X_ATOM_E_ILLUME_CLIPBOARD_OFF; + default: + break; + } + return 0; +} + +static Ecore_X_Illume_Clipboard_State +_ecore_xcb_e_clipboard_state_get(Ecore_X_Atom atom) +{ + if (atom == ECORE_X_ATOM_E_ILLUME_CLIPBOARD_ON) + return ECORE_X_ILLUME_CLIPBOARD_STATE_ON; + + if (atom == ECORE_X_ATOM_E_ILLUME_CLIPBOARD_OFF) + return ECORE_X_ILLUME_CLIPBOARD_STATE_OFF; + + return ECORE_X_ILLUME_INDICATOR_STATE_UNKNOWN; +} + +EAPI void +ecore_x_e_illume_clipboard_state_set(Ecore_X_Window win, + Ecore_X_Illume_Clipboard_State state) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + atom = _ecore_xcb_e_clipboard_atom_get(state); + + ecore_x_window_prop_atom_set(win, + ECORE_X_ATOM_E_ILLUME_CLIPBOARD_STATE, + &atom, 1); +} + +EAPI Ecore_X_Illume_Clipboard_State +ecore_x_e_illume_clipboard_state_get(Ecore_X_Window win) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_atom_get(win, + ECORE_X_ATOM_E_ILLUME_CLIPBOARD_STATE, + &atom, 1)) + return ECORE_X_ILLUME_CLIPBOARD_STATE_UNKNOWN; + return _ecore_xcb_e_clipboard_state_get(atom); +} + +EAPI void +ecore_x_e_illume_clipboard_geometry_set(Ecore_X_Window win, + int x, int y, int w, int h) +{ + unsigned int geom[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + geom[0] = x; + geom[1] = y; + geom[2] = w; + geom[3] = h; + ecore_x_window_prop_card32_set(win, + ECORE_X_ATOM_E_ILLUME_CLIPBOARD_GEOMETRY, + geom, 4); +} + +EAPI Eina_Bool +ecore_x_e_illume_clipboard_geometry_get(Ecore_X_Window win, + int *x, int *y, int *w, int *h) +{ + int ret = 0; + unsigned int geom[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ret = + ecore_x_window_prop_card32_get(win, + ECORE_X_ATOM_E_ILLUME_CLIPBOARD_GEOMETRY, + geom, 4); + if (ret != 4) return EINA_FALSE; + + if (x) *x = geom[0]; + if (y) *y = geom[1]; + if (w) *w = geom[2]; + if (h) *h = geom[3]; + + return EINA_TRUE; +} + +EAPI void +ecore_x_e_illume_mode_set(Ecore_X_Window win, + Ecore_X_Illume_Mode mode) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + atom = _ecore_xcb_e_illume_atom_get(mode); + ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_E_ILLUME_MODE, &atom, 1); +} + +EAPI Ecore_X_Illume_Mode +ecore_x_e_illume_mode_get(Ecore_X_Window win) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_atom_get(win, ECORE_X_ATOM_E_ILLUME_MODE, &atom, 1)) + return ECORE_X_ILLUME_MODE_UNKNOWN; + + return _ecore_xcb_e_illume_mode_get(atom); +} + +EAPI void +ecore_x_e_illume_mode_send(Ecore_X_Window win, + Ecore_X_Illume_Mode mode) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_MODE, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + _ecore_xcb_e_illume_atom_get(mode), + 0, 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_focus_back_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_FOCUS_BACK, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + 1, 0, 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_focus_forward_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_FOCUS_FORWARD, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + 1, 0, 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_focus_home_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_FOCUS_HOME, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + 1, 0, 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_close_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_CLOSE, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + 1, 0, 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_home_new_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_HOME_NEW, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + 1, 0, 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_home_del_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_HOME_DEL, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + 1, 0, 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_access_action_next_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + win, + ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_NEXT, + 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_access_action_prev_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + win, + ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_PREV, + 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_access_action_activate_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + win, + ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_ACTIVATE, + 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_access_action_read_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + win, + ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ, + 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_access_action_read_next_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + win, + ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_NEXT, + 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_access_action_read_prev_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + win, + ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_PREV, + 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_drag_set(Ecore_X_Window win, + unsigned int drag) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_DRAG, &drag, 1); +} + +EAPI void +ecore_x_e_illume_drag_locked_set(Ecore_X_Window win, + unsigned int is_locked) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_DRAG_LOCKED, + &is_locked, 1); +} + +EAPI Eina_Bool +ecore_x_e_illume_drag_locked_get(Ecore_X_Window win) +{ + unsigned int val = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_E_ILLUME_DRAG_LOCKED, + &val, 1)) + return EINA_FALSE; + + return val ? EINA_TRUE : EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_e_illume_drag_get(Ecore_X_Window win) +{ + unsigned int val = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_E_ILLUME_DRAG, &val, 1)) + return EINA_FALSE; + + return val ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_x_e_illume_drag_start_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_DRAG_START, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + 1, 0, 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_drag_end_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_DRAG_END, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + 1, 0, 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_zone_set(Ecore_X_Window win, + Ecore_X_Window zone) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_window_set(win, ECORE_X_ATOM_E_ILLUME_ZONE, &zone, 1); +} + +EAPI Ecore_X_Window +ecore_x_e_illume_zone_get(Ecore_X_Window win) +{ + Ecore_X_Window zone; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_window_get(win, ECORE_X_ATOM_E_ILLUME_ZONE, + &zone, 1)) + return 0; + + return zone; +} + +EAPI void +ecore_x_e_illume_zone_list_set(Ecore_X_Window win, + Ecore_X_Window *zones, + unsigned int num) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_window_set(win, ECORE_X_ATOM_E_ILLUME_ZONE_LIST, + zones, num); +} + +/* local functions */ +static Ecore_X_Atom +_ecore_xcb_e_vkbd_atom_get(Ecore_X_Virtual_Keyboard_State state) +{ + switch (state) + { + case ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_ON: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_ALPHA: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ALPHA; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_NUMERIC: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_NUMERIC; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_PIN: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PIN; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_PHONE_NUMBER: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PHONE_NUMBER; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_HEX: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HEX; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_TERMINAL: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_TERMINAL; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_PASSWORD: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PASSWORD; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_IP: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_IP; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_HOST: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HOST; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_FILE: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_FILE; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_URL: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_URL; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_KEYPAD: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_KEYPAD; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_J2ME: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_J2ME; + + default: + break; + } + return 0; +} + +static Ecore_X_Virtual_Keyboard_State +_ecore_xcb_e_vkbd_state_get(Ecore_X_Atom atom) +{ + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_ON; + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF; + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ALPHA) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_ALPHA; + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_NUMERIC) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_NUMERIC; + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PIN) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_PIN; + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PHONE_NUMBER) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_PHONE_NUMBER; + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HEX) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_HEX; + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_TERMINAL) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_TERMINAL; + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PASSWORD) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_PASSWORD; + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_IP) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_IP; + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HOST) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_HOST; + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_FILE) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_FILE; + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_URL) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_URL; + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_KEYPAD) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_KEYPAD; + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_J2ME) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_J2ME; + + return ECORE_X_VIRTUAL_KEYBOARD_STATE_UNKNOWN; +} + +static Ecore_X_Atom +_ecore_xcb_e_quickpanel_atom_get(Ecore_X_Illume_Quickpanel_State state) +{ + switch (state) + { + case ECORE_X_ILLUME_QUICKPANEL_STATE_ON: + return ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ON; + + case ECORE_X_ILLUME_QUICKPANEL_STATE_OFF: + return ECORE_X_ATOM_E_ILLUME_QUICKPANEL_OFF; + + default: + break; + } + return 0; +} + +static Ecore_X_Illume_Quickpanel_State +_ecore_xcb_e_quickpanel_state_get(Ecore_X_Atom atom) +{ + if (atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ON) + return ECORE_X_ILLUME_QUICKPANEL_STATE_ON; + if (atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_OFF) + return ECORE_X_ILLUME_QUICKPANEL_STATE_OFF; + + return ECORE_X_ILLUME_QUICKPANEL_STATE_UNKNOWN; +} + +static Ecore_X_Atom +_ecore_xcb_e_illume_atom_get(Ecore_X_Illume_Mode mode) +{ + switch (mode) + { + case ECORE_X_ILLUME_MODE_SINGLE: + return ECORE_X_ATOM_E_ILLUME_MODE_SINGLE; + + case ECORE_X_ILLUME_MODE_DUAL_TOP: + return ECORE_X_ATOM_E_ILLUME_MODE_DUAL_TOP; + + case ECORE_X_ILLUME_MODE_DUAL_LEFT: + return ECORE_X_ATOM_E_ILLUME_MODE_DUAL_LEFT; + + default: + break; + } + return ECORE_X_ILLUME_MODE_UNKNOWN; +} + +static Ecore_X_Illume_Mode +_ecore_xcb_e_illume_mode_get(Ecore_X_Atom atom) +{ + if (atom == ECORE_X_ATOM_E_ILLUME_MODE_SINGLE) + return ECORE_X_ILLUME_MODE_SINGLE; + if (atom == ECORE_X_ATOM_E_ILLUME_MODE_DUAL_TOP) + return ECORE_X_ILLUME_MODE_DUAL_TOP; + if (atom == ECORE_X_ATOM_E_ILLUME_MODE_DUAL_LEFT) + return ECORE_X_ILLUME_MODE_DUAL_LEFT; + + return ECORE_X_ILLUME_MODE_UNKNOWN; +} + +static Ecore_X_Atom +_ecore_xcb_e_indicator_atom_get(Ecore_X_Illume_Indicator_State state) +{ + switch (state) + { + case ECORE_X_ILLUME_INDICATOR_STATE_ON: + return ECORE_X_ATOM_E_ILLUME_INDICATOR_ON; + + case ECORE_X_ILLUME_INDICATOR_STATE_OFF: + return ECORE_X_ATOM_E_ILLUME_INDICATOR_OFF; + + default: + break; + } + return 0; +} + +static Ecore_X_Illume_Indicator_State +_ecore_xcb_e_indicator_state_get(Ecore_X_Atom atom) +{ + if (atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_ON) + return ECORE_X_ILLUME_INDICATOR_STATE_ON; + if (atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_OFF) + return ECORE_X_ILLUME_INDICATOR_STATE_OFF; + + return ECORE_X_ILLUME_INDICATOR_STATE_UNKNOWN; +} + +EAPI void +ecore_x_e_illume_indicator_state_set(Ecore_X_Window win, + Ecore_X_Illume_Indicator_State state) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + atom = _ecore_xcb_e_indicator_atom_get(state); + ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_E_ILLUME_INDICATOR_STATE, + &atom, 1); +} + +EAPI Ecore_X_Illume_Indicator_State +ecore_x_e_illume_indicator_state_get(Ecore_X_Window win) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_atom_get(win, + ECORE_X_ATOM_E_ILLUME_INDICATOR_STATE, + &atom, 1)) + return ECORE_X_ILLUME_INDICATOR_STATE_UNKNOWN; + + return _ecore_xcb_e_indicator_state_get(atom); +} + +EAPI void +ecore_x_e_illume_indicator_state_send(Ecore_X_Window win, + Ecore_X_Illume_Indicator_State state) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_INDICATOR_STATE, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + _ecore_xcb_e_indicator_atom_get(state), + 0, 0, 0, 0); +} + +static Ecore_X_Atom +_ecore_x_e_indicator_opacity_atom_get(Ecore_X_Illume_Indicator_Opacity_Mode mode) +{ + switch (mode) + { + case ECORE_X_ILLUME_INDICATOR_OPAQUE: + return ECORE_X_ATOM_E_ILLUME_INDICATOR_OPAQUE; + + case ECORE_X_ILLUME_INDICATOR_TRANSLUCENT: + return ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSLUCENT; + + case ECORE_X_ILLUME_INDICATOR_TRANSPARENT: + return ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSPARENT; + + default: + break; + } + return 0; +} + +static Ecore_X_Illume_Indicator_Opacity_Mode +_ecore_x_e_indicator_opacity_get(Ecore_X_Atom atom) +{ + if (atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_OPAQUE) + return ECORE_X_ILLUME_INDICATOR_OPAQUE; + + if (atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSLUCENT) + return ECORE_X_ILLUME_INDICATOR_TRANSLUCENT; + + if (atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSPARENT) + return ECORE_X_ILLUME_INDICATOR_TRANSPARENT; + + return ECORE_X_ILLUME_INDICATOR_OPACITY_UNKNOWN; +} + +EAPI void +ecore_x_e_illume_indicator_opacity_set(Ecore_X_Window win, + Ecore_X_Illume_Indicator_Opacity_Mode mode) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + atom = _ecore_x_e_indicator_opacity_atom_get(mode); + ecore_x_window_prop_atom_set(win, + ECORE_X_ATOM_E_ILLUME_INDICATOR_OPACITY_MODE, + &atom, 1); +} + +EAPI Ecore_X_Illume_Indicator_Opacity_Mode +ecore_x_e_illume_indicator_opacity_get(Ecore_X_Window win) +{ + Ecore_X_Atom atom; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_atom_get(win, + ECORE_X_ATOM_E_ILLUME_INDICATOR_OPACITY_MODE, + &atom, 1)) + return ECORE_X_ILLUME_INDICATOR_OPACITY_UNKNOWN; + + return _ecore_x_e_indicator_opacity_get(atom); +} + +EAPI void +ecore_x_e_illume_indicator_opacity_send(Ecore_X_Window win, + Ecore_X_Illume_Indicator_Opacity_Mode mode) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, + ECORE_X_ATOM_E_ILLUME_INDICATOR_OPACITY_MODE, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + _ecore_x_e_indicator_opacity_atom_get(mode), + 0, 0, 0, 0); +} + +static Ecore_X_Atom +_ecore_x_e_illume_window_state_atom_get(Ecore_X_Illume_Window_State state) +{ + switch (state) + { + case ECORE_X_ILLUME_WINDOW_STATE_NORMAL: + return ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_NORMAL; + + case ECORE_X_ILLUME_WINDOW_STATE_FLOATING: + return ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_FLOATING; + + default: + break; + } + return 0; +} + +static Ecore_X_Illume_Window_State +_ecore_x_e_illume_window_state_get(Ecore_X_Atom atom) +{ + if (atom == ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_NORMAL) + return ECORE_X_ILLUME_WINDOW_STATE_NORMAL; + + if (atom == ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_FLOATING) + return ECORE_X_ILLUME_WINDOW_STATE_FLOATING; + + return ECORE_X_ILLUME_WINDOW_STATE_NORMAL; +} + +EAPI void +ecore_x_e_illume_window_state_set(Ecore_X_Window win, + Ecore_X_Illume_Window_State state) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + atom = _ecore_x_e_illume_window_state_atom_get(state); + ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_E_ILLUME_WINDOW_STATE, + &atom, 1); +} + +EAPI Ecore_X_Illume_Window_State +ecore_x_e_illume_window_state_get(Ecore_X_Window win) +{ + Ecore_X_Atom atom; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_atom_get(win, + ECORE_X_ATOM_E_ILLUME_WINDOW_STATE, + &atom, 1)) + return ECORE_X_ILLUME_WINDOW_STATE_NORMAL; + + return _ecore_x_e_illume_window_state_get(atom); +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_error.c b/src/lib/ecore_x/xcb/ecore_xcb_error.c new file mode 100644 index 0000000..fc32926 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_error.c @@ -0,0 +1,123 @@ +#include "ecore_xcb_private.h" +#include + +/* local variables */ +static void (*_error_func)(void *data) = NULL; +static void *_error_data = NULL; +static void (*_io_error_func)(void *data) = NULL; +static void *_io_error_data = NULL; +static int _error_request_code = 0; +static int _error_code = 0; +static Ecore_X_ID _error_resource_id = 0; + +/** + * Set the error handler. + * @param func The error handler function + * @param data The data to be passed to the handler function + * + * Set the X error handler function + */ +EAPI void +ecore_x_error_handler_set(void (*func)(void *data), + const void *data) +{ + _error_func = func; + _error_data = (void *)data; +} + +/** + * Set the I/O error handler. + * @param func The I/O error handler function + * @param data The data to be passed to the handler function + * + * Set the X I/O error handler function + */ +EAPI void +ecore_x_io_error_handler_set(void (*func)(void *data), + const void *data) +{ + _io_error_func = func; + _io_error_data = (void *)data; +} + +/** + * Get the request code that caused the error. + * @return The request code causing the X error + * + * Return the X request code that caused the last X error + */ +EAPI int +ecore_x_error_request_get(void) +{ + return _error_request_code; +} + +/** + * Get the error code from the error. + * @return The error code from the X error + * + * Return the error code from the last X error + */ +EAPI int +ecore_x_error_code_get(void) +{ + return _error_code; +} + +/** + * Get the resource id that caused the error. + * @return The resource id causing the X error + * + * Return the X resource id that caused the last X error + */ +EAPI Ecore_X_ID +ecore_x_error_resource_id_get(void) +{ + return _error_resource_id; +} + +int +_ecore_xcb_error_handle(xcb_generic_error_t *err) +{ + WRN("Got Error:"); + WRN("\tEvent: %s", xcb_event_get_request_label(err->major_code)); + WRN("\tError: %s", xcb_event_get_error_label(err->error_code)); + +#ifdef OLD_XCB_VERSION + if (err->error_code == XCB_EVENT_ERROR_BAD_VALUE) + WRN("\tBad Value: %d", ((xcb_value_error_t *)err)->bad_value); + else if (err->error_code == XCB_EVENT_ERROR_BAD_WINDOW) + WRN("\tBad Window: %d", ((xcb_window_error_t *)err)->bad_value); +#else + if (err->error_code == XCB_VALUE) + WRN("\tBad Value: %d", ((xcb_value_error_t *)err)->bad_value); + else if (err->error_code == XCB_WINDOW) + WRN("\tBad Window: %d", ((xcb_window_error_t *)err)->bad_value); +#endif + + _error_request_code = err->sequence; + _error_code = err->error_code; + _error_resource_id = err->resource_id; + if (_error_func) + _error_func(_error_data); + + return 0; +} + +int +_ecore_xcb_io_error_handle(xcb_generic_error_t *err) +{ + CRIT("IO Error:"); + if (err) + { + CRIT("\tRequest: %d", err->sequence); + CRIT("\tCode: %d", err->error_code); + } + if (_io_error_func) + _io_error_func(_io_error_data); + else + exit(-1); + + return 0; +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_events.c b/src/lib/ecore_x/xcb/ecore_xcb_events.c new file mode 100644 index 0000000..5722b46 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_events.c @@ -0,0 +1,2820 @@ +#include "ecore_xcb_private.h" +//#include "Ecore_X_Atoms.h" +#include +#include +#include +# ifdef ECORE_XCB_DAMAGE +# include +# endif +# ifdef ECORE_XCB_RANDR +# include +# endif +# ifdef ECORE_XCB_SCREENSAVER +# include +# endif +# ifdef ECORE_XCB_SYNC +# include +# endif +# ifdef ECORE_XCB_XFIXES +# include +# endif +# ifdef ECORE_XCB_XGESTURE +# include +# endif + +#ifndef CODESET +# define CODESET "INVALID" +#endif + +typedef struct _Ecore_X_Mouse_Down_Info +{ + EINA_INLIST; + int dev; + Ecore_X_Time last_time; + Ecore_X_Time last_last_time; + Ecore_X_Window last_win; + Ecore_X_Window last_last_win; + Ecore_X_Window last_event_win; + Ecore_X_Window last_last_event_win; + Eina_Bool did_double : 1; + Eina_Bool did_triple : 1; +} Ecore_X_Mouse_Down_Info; + +/* local function prototypes */ +static void _ecore_xcb_event_handle_any_event(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_key_press(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_key_release(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_button_press(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_button_release(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_motion_notify(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_enter_notify(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_leave_notify(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_keymap_notify(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_focus_in(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_focus_out(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_expose(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_graphics_exposure(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_visibility_notify(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_create_notify(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_destroy_notify(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_map_notify(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_unmap_notify(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_map_request(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_reparent_notify(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_configure_notify(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_configure_request(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_gravity_notify(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_resize_request(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_circulate_notify(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_circulate_request(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_property_notify(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_selection_clear(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_selection_request(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_selection_notify(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_colormap_notify(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_client_message(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_mapping_notify(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_damage_notify(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_randr_change(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_randr_notify(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_randr_crtc_change(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_randr_output_change(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_randr_output_property_change(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_screensaver_notify(xcb_generic_event_t *event); +#ifdef ECORE_XCB_XGESTURE +static void _ecore_xcb_event_handle_gesture_notify_flick(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_gesture_notify_pan(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_gesture_notify_pinchrotation(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_gesture_notify_tap(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_gesture_notify_tapnhold(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_gesture_notify_hold(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_gesture_notify_group(xcb_generic_event_t *event); +#endif +#ifdef ECORE_XCB_SHAPE +static void _ecore_xcb_event_handle_shape_change(xcb_generic_event_t *event); +#endif +static void _ecore_xcb_event_handle_sync_counter(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_sync_alarm(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_xfixes_selection_notify(xcb_generic_event_t *event __UNUSED__); +static void _ecore_xcb_event_handle_xfixes_cursor_notify(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_generic_event(xcb_generic_event_t *event); +static void _ecore_xcb_event_handle_input_event(xcb_generic_event_t *event); + +static void _ecore_xcb_event_key_press(xcb_generic_event_t *event); +static void _ecore_xcb_event_key_release(xcb_generic_event_t *event); +static void _ecore_xcb_event_mouse_move_free(void *data __UNUSED__, + void *event); +static Ecore_X_Event_Mode _ecore_xcb_event_mode_get(uint8_t mode); +static Ecore_X_Event_Detail _ecore_xcb_event_detail_get(uint8_t detail); +static void _ecore_xcb_event_xdnd_enter_free(void *data __UNUSED__, + void *event); +static void _ecore_xcb_event_selection_notify_free(void *data __UNUSED__, + void *event); +static void _ecore_xcb_event_generic_event_free(void *data, + void *event); +static void _ecore_xcb_event_mouse_down_info_clear(void); +static Ecore_X_Mouse_Down_Info *_ecore_xcb_event_mouse_down_info_get(int dev); + +/* local variables */ +static Eina_Bool _ecore_xcb_event_last_mouse_move = EINA_FALSE; +//static Ecore_Event *_ecore_xcb_event_last_mouse_move_event = NULL; +static Eina_Inlist *_ecore_xcb_mouse_down_info_list = NULL; +static Ecore_X_Time _ecore_xcb_event_last_time; +static Ecore_X_Window _ecore_xcb_event_last_window = 0; + +/* public variables */ +int16_t _ecore_xcb_event_last_root_x = 0; +int16_t _ecore_xcb_event_last_root_y = 0; + +EAPI int ECORE_X_EVENT_ANY = 0; +EAPI int ECORE_X_EVENT_MOUSE_IN = 0; +EAPI int ECORE_X_EVENT_MOUSE_OUT = 0; +EAPI int ECORE_X_EVENT_WINDOW_FOCUS_IN = 0; +EAPI int ECORE_X_EVENT_WINDOW_FOCUS_OUT = 0; +EAPI int ECORE_X_EVENT_WINDOW_KEYMAP = 0; +EAPI int ECORE_X_EVENT_WINDOW_DAMAGE = 0; +EAPI int ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE = 0; +EAPI int ECORE_X_EVENT_WINDOW_CREATE = 0; +EAPI int ECORE_X_EVENT_WINDOW_DESTROY = 0; +EAPI int ECORE_X_EVENT_WINDOW_HIDE = 0; +EAPI int ECORE_X_EVENT_WINDOW_SHOW = 0; +EAPI int ECORE_X_EVENT_WINDOW_SHOW_REQUEST = 0; +EAPI int ECORE_X_EVENT_WINDOW_REPARENT = 0; +EAPI int ECORE_X_EVENT_WINDOW_CONFIGURE = 0; +EAPI int ECORE_X_EVENT_WINDOW_CONFIGURE_REQUEST = 0; +EAPI int ECORE_X_EVENT_WINDOW_GRAVITY = 0; +EAPI int ECORE_X_EVENT_WINDOW_RESIZE_REQUEST = 0; +EAPI int ECORE_X_EVENT_WINDOW_STACK = 0; +EAPI int ECORE_X_EVENT_WINDOW_STACK_REQUEST = 0; +EAPI int ECORE_X_EVENT_WINDOW_PROPERTY = 0; +EAPI int ECORE_X_EVENT_WINDOW_COLORMAP = 0; +EAPI int ECORE_X_EVENT_WINDOW_MAPPING = 0; +EAPI int ECORE_X_EVENT_MAPPING_CHANGE = 0; +EAPI int ECORE_X_EVENT_SELECTION_CLEAR = 0; +EAPI int ECORE_X_EVENT_SELECTION_REQUEST = 0; +EAPI int ECORE_X_EVENT_SELECTION_NOTIFY = 0; +EAPI int ECORE_X_EVENT_FIXES_SELECTION_NOTIFY = 0; +EAPI int ECORE_X_EVENT_CLIENT_MESSAGE = 0; +EAPI int ECORE_X_EVENT_WINDOW_SHAPE = 0; +EAPI int ECORE_X_EVENT_SCREENSAVER_NOTIFY = 0; +EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_FLICK = 0; +EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_PAN = 0; +EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_PINCHROTATION = 0; +EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_TAP = 0; +EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_TAPNHOLD = 0; +EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_HOLD = 0; +EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_GROUP = 0; +EAPI int ECORE_X_EVENT_SYNC_COUNTER = 0; +EAPI int ECORE_X_EVENT_SYNC_ALARM = 0; +EAPI int ECORE_X_EVENT_SCREEN_CHANGE = 0; +EAPI int ECORE_X_EVENT_DAMAGE_NOTIFY = 0; +EAPI int ECORE_X_EVENT_RANDR_CRTC_CHANGE = 0; +EAPI int ECORE_X_EVENT_RANDR_OUTPUT_CHANGE = 0; +EAPI int ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY = 0; +EAPI int ECORE_X_EVENT_WINDOW_DELETE_REQUEST = 0; +EAPI int ECORE_X_EVENT_WINDOW_MOVE_RESIZE_REQUEST = 0; +EAPI int ECORE_X_EVENT_WINDOW_STATE_REQUEST = 0; +EAPI int ECORE_X_EVENT_FRAME_EXTENTS_REQUEST = 0; +EAPI int ECORE_X_EVENT_PING = 0; +EAPI int ECORE_X_EVENT_DESKTOP_CHANGE = 0; +EAPI int ECORE_X_EVENT_STARTUP_SEQUENCE_NEW = 0; +EAPI int ECORE_X_EVENT_STARTUP_SEQUENCE_CHANGE = 0; +EAPI int ECORE_X_EVENT_STARTUP_SEQUENCE_REMOVE = 0; +EAPI int ECORE_X_EVENT_XKB_STATE_NOTIFY = 0; +EAPI int ECORE_X_EVENT_XKB_NEWKBD_NOTIFY = 0; +EAPI int ECORE_X_EVENT_GENERIC = 0; + +void +_ecore_xcb_events_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ECORE_X_EVENT_ANY) + { + ECORE_X_EVENT_ANY = ecore_event_type_new(); + ECORE_X_EVENT_MOUSE_IN = ecore_event_type_new(); + ECORE_X_EVENT_MOUSE_OUT = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_FOCUS_IN = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_FOCUS_OUT = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_KEYMAP = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_DAMAGE = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_CREATE = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_DESTROY = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_HIDE = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_SHOW = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_SHOW_REQUEST = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_REPARENT = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_CONFIGURE = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_CONFIGURE_REQUEST = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_GRAVITY = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_RESIZE_REQUEST = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_STACK = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_STACK_REQUEST = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_PROPERTY = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_COLORMAP = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_MAPPING = ecore_event_type_new(); + ECORE_X_EVENT_MAPPING_CHANGE = ecore_event_type_new(); + ECORE_X_EVENT_SELECTION_CLEAR = ecore_event_type_new(); + ECORE_X_EVENT_SELECTION_REQUEST = ecore_event_type_new(); + ECORE_X_EVENT_SELECTION_NOTIFY = ecore_event_type_new(); + ECORE_X_EVENT_FIXES_SELECTION_NOTIFY = ecore_event_type_new(); + ECORE_X_EVENT_CLIENT_MESSAGE = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_SHAPE = ecore_event_type_new(); + ECORE_X_EVENT_SCREENSAVER_NOTIFY = ecore_event_type_new(); + ECORE_X_EVENT_GESTURE_NOTIFY_FLICK = ecore_event_type_new(); + ECORE_X_EVENT_GESTURE_NOTIFY_PAN = ecore_event_type_new(); + ECORE_X_EVENT_GESTURE_NOTIFY_PINCHROTATION = ecore_event_type_new(); + ECORE_X_EVENT_GESTURE_NOTIFY_TAP = ecore_event_type_new(); + ECORE_X_EVENT_GESTURE_NOTIFY_TAPNHOLD = ecore_event_type_new(); + ECORE_X_EVENT_GESTURE_NOTIFY_HOLD = ecore_event_type_new(); + ECORE_X_EVENT_GESTURE_NOTIFY_GROUP = ecore_event_type_new(); + ECORE_X_EVENT_SYNC_COUNTER = ecore_event_type_new(); + ECORE_X_EVENT_SYNC_ALARM = ecore_event_type_new(); + ECORE_X_EVENT_SCREEN_CHANGE = ecore_event_type_new(); + ECORE_X_EVENT_RANDR_CRTC_CHANGE = ecore_event_type_new(); + ECORE_X_EVENT_RANDR_OUTPUT_CHANGE = ecore_event_type_new(); + ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY = ecore_event_type_new(); + ECORE_X_EVENT_DAMAGE_NOTIFY = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_DELETE_REQUEST = ecore_event_type_new(); + ECORE_X_EVENT_DESKTOP_CHANGE = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_MOVE_RESIZE_REQUEST = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_STATE_REQUEST = ecore_event_type_new(); + ECORE_X_EVENT_FRAME_EXTENTS_REQUEST = ecore_event_type_new(); + ECORE_X_EVENT_PING = ecore_event_type_new(); + ECORE_X_EVENT_STARTUP_SEQUENCE_NEW = ecore_event_type_new(); + ECORE_X_EVENT_STARTUP_SEQUENCE_CHANGE = ecore_event_type_new(); + ECORE_X_EVENT_STARTUP_SEQUENCE_REMOVE = ecore_event_type_new(); + ECORE_X_EVENT_XKB_STATE_NOTIFY = ecore_event_type_new(); + ECORE_X_EVENT_XKB_NEWKBD_NOTIFY = ecore_event_type_new(); + ECORE_X_EVENT_GENERIC = ecore_event_type_new(); + } +} + +void +_ecore_xcb_events_shutdown(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_xcb_event_mouse_down_info_clear(); + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; +// if (_ecore_xcb_event_last_mouse_move_event) +// { +// ecore_event_del(_ecore_xcb_event_last_mouse_move_event); +// _ecore_xcb_event_last_mouse_move_event = NULL; +// } +} + +void +_ecore_xcb_events_handle(xcb_generic_event_t *ev) +{ + uint8_t response = 0; + +// LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + /* strip highest bit (set if event is generated) */ + response = (ev->response_type & ~0x80); + if (response == 0) + { + xcb_generic_error_t *err; + + err = (xcb_generic_error_t *)ev; + + /* NB: There is no way to check access of destroyed windows, + * so trap those cases and ignore. We also ignore BadValue from + * xcb_grab/ungrab_button (happens when we are using any_mod) + * and a few others */ +#ifdef OLD_XCB_VERSION + if (err->error_code == XCB_EVENT_ERROR_BAD_WINDOW) return; + else if (err->error_code == XCB_EVENT_ERROR_BAD_MATCH) + { + if ((err->major_code == XCB_SET_INPUT_FOCUS) || + (err->major_code == XCB_CONFIGURE_WINDOW)) + return; + } + else if (err->error_code == XCB_EVENT_ERROR_BAD_VALUE) + { + if ((err->major_code == XCB_KILL_CLIENT) || + (err->major_code == XCB_GRAB_BUTTON) || + (err->major_code == XCB_UNGRAB_BUTTON)) + return; + } +#else + if (err->error_code == XCB_WINDOW) return; + else if (err->error_code == XCB_MATCH) + { + if ((err->major_code == XCB_SET_INPUT_FOCUS) || + (err->major_code == XCB_CONFIGURE_WINDOW)) + return; + } + else if (err->error_code == XCB_VALUE) + { + if ((err->major_code == XCB_KILL_CLIENT) || + (err->major_code == XCB_GRAB_BUTTON) || + (err->major_code == XCB_UNGRAB_BUTTON)) + return; + } +#endif + WRN("Got Event Error:"); + WRN("\tMajor Code: %d", err->major_code); + WRN("\tMinor Code: %d", err->minor_code); + WRN("\tRequest: %s", xcb_event_get_request_label(err->major_code)); + WRN("\tError: %s", xcb_event_get_error_label(err->error_code)); + if (err->error_code == 2) // bad value + WRN("\tValue: %d", ((xcb_value_error_t *)err)->bad_value); + else if (err->error_code == 8) // bad match + WRN("\tMatch: %d", ((xcb_match_error_t *)err)->bad_value); + + if (err->major_code == XCB_SEND_EVENT) + { + WRN("\tSend Event Error"); + WRN("\t\tSeq: %d", ev->sequence); + WRN("\t\tFull Seq: %d", ev->full_sequence); + WRN("\t\tType: %d", ev->response_type); + } + /* if (err->major_code == 148) */ + /* { */ + /* printf("GOT 148 Error\n"); */ + /* } */ + return; + } + + /* FIXME: Filter event for xim when xcb supports xim */ + + _ecore_xcb_event_handle_any_event(ev); + + if (response == XCB_KEY_PRESS) + _ecore_xcb_event_handle_key_press(ev); + else if (response == XCB_KEY_RELEASE) + _ecore_xcb_event_handle_key_release(ev); + else if (response == XCB_BUTTON_PRESS) + _ecore_xcb_event_handle_button_press(ev); + else if (response == XCB_BUTTON_RELEASE) + _ecore_xcb_event_handle_button_release(ev); + else if (response == XCB_MOTION_NOTIFY) + _ecore_xcb_event_handle_motion_notify(ev); + else if (response == XCB_ENTER_NOTIFY) + _ecore_xcb_event_handle_enter_notify(ev); + else if (response == XCB_LEAVE_NOTIFY) + _ecore_xcb_event_handle_leave_notify(ev); + else if (response == XCB_KEYMAP_NOTIFY) + _ecore_xcb_event_handle_keymap_notify(ev); + else if (response == XCB_FOCUS_IN) + _ecore_xcb_event_handle_focus_in(ev); + else if (response == XCB_FOCUS_OUT) + _ecore_xcb_event_handle_focus_out(ev); + else if (response == XCB_EXPOSE) + _ecore_xcb_event_handle_expose(ev); + else if (response == XCB_GRAPHICS_EXPOSURE) + _ecore_xcb_event_handle_graphics_exposure(ev); + else if (response == XCB_VISIBILITY_NOTIFY) + _ecore_xcb_event_handle_visibility_notify(ev); + else if (response == XCB_CREATE_NOTIFY) + _ecore_xcb_event_handle_create_notify(ev); + else if (response == XCB_DESTROY_NOTIFY) + _ecore_xcb_event_handle_destroy_notify(ev); + else if (response == XCB_MAP_NOTIFY) + _ecore_xcb_event_handle_map_notify(ev); + else if (response == XCB_UNMAP_NOTIFY) + _ecore_xcb_event_handle_unmap_notify(ev); + else if (response == XCB_MAP_REQUEST) + _ecore_xcb_event_handle_map_request(ev); + else if (response == XCB_REPARENT_NOTIFY) + _ecore_xcb_event_handle_reparent_notify(ev); + else if (response == XCB_CONFIGURE_NOTIFY) + _ecore_xcb_event_handle_configure_notify(ev); + else if (response == XCB_CONFIGURE_REQUEST) + _ecore_xcb_event_handle_configure_request(ev); + else if (response == XCB_GRAVITY_NOTIFY) + _ecore_xcb_event_handle_gravity_notify(ev); + else if (response == XCB_RESIZE_REQUEST) + _ecore_xcb_event_handle_resize_request(ev); + else if (response == XCB_CIRCULATE_NOTIFY) + _ecore_xcb_event_handle_circulate_notify(ev); + else if (response == XCB_CIRCULATE_REQUEST) + _ecore_xcb_event_handle_circulate_request(ev); + else if (response == XCB_PROPERTY_NOTIFY) + _ecore_xcb_event_handle_property_notify(ev); + else if (response == XCB_SELECTION_CLEAR) + _ecore_xcb_event_handle_selection_clear(ev); + else if (response == XCB_SELECTION_REQUEST) + _ecore_xcb_event_handle_selection_request(ev); + else if (response == XCB_SELECTION_NOTIFY) + _ecore_xcb_event_handle_selection_notify(ev); + else if (response == XCB_COLORMAP_NOTIFY) + _ecore_xcb_event_handle_colormap_notify(ev); + else if (response == XCB_CLIENT_MESSAGE) + _ecore_xcb_event_handle_client_message(ev); + else if (response == XCB_MAPPING_NOTIFY) + _ecore_xcb_event_handle_mapping_notify(ev); + else if (response == 35) /* GenericEvent == 35 */ + _ecore_xcb_event_handle_generic_event(ev); +#ifdef ECORE_XCB_DAMAGE + else if ((_ecore_xcb_event_damage >= 0) && + (response == (_ecore_xcb_event_damage + XCB_DAMAGE_NOTIFY))) + _ecore_xcb_event_handle_damage_notify(ev); +#endif +#ifdef ECORE_XCB_RANDR + else if ((_ecore_xcb_event_randr >= 0) && + (response == + _ecore_xcb_event_randr + XCB_RANDR_SCREEN_CHANGE_NOTIFY)) + _ecore_xcb_event_handle_randr_change(ev); + else if ((_ecore_xcb_event_randr >= 0) && + (response == (_ecore_xcb_event_randr + XCB_RANDR_NOTIFY))) + _ecore_xcb_event_handle_randr_notify(ev); +#endif +#ifdef ECORE_XCB_SCREENSAVER + else if ((_ecore_xcb_event_screensaver >= 0) && + (response == + _ecore_xcb_event_screensaver + XCB_SCREENSAVER_NOTIFY)) + _ecore_xcb_event_handle_screensaver_notify(ev); +#endif +#ifdef ECORE_XCB_XGESTURE + else if ((_ecore_xcb_event_gesture >= 0) && + (response == + _ecore_xcb_event_gesture + XCB_GESTURE_NOTIFY_FLICK)) + _ecore_xcb_event_handle_gesture_notify_flick(ev); + else if ((_ecore_xcb_event_gesture >= 0) && + (response == + _ecore_xcb_event_gesture + XCB_GESTURE_NOTIFY_PAN)) + _ecore_xcb_event_handle_gesture_notify_pan(ev); + else if ((_ecore_xcb_event_gesture >= 0) && + (response == + _ecore_xcb_event_gesture + XCB_GESTURE_NOTIFY_PINCH_ROTATION)) + _ecore_xcb_event_handle_gesture_notify_pinchrotation(ev); + else if ((_ecore_xcb_event_gesture >= 0) && + (response == + _ecore_xcb_event_gesture + XCB_GESTURE_NOTIFY_TAP)) + _ecore_xcb_event_handle_gesture_notify_tap(ev); + else if ((_ecore_xcb_event_gesture >= 0) && + (response == + _ecore_xcb_event_gesture + XCB_GESTURE_NOTIFY_TAP_N_HOLD)) + _ecore_xcb_event_handle_gesture_notify_tapnhold(ev); + else if ((_ecore_xcb_event_gesture >= 0) && + (response == + _ecore_xcb_event_gesture + XCB_GESTURE_NOTIFY_HOLD)) + _ecore_xcb_event_handle_gesture_notify_hold(ev); + else if ((_ecore_xcb_event_gesture >= 0) && + (response == + _ecore_xcb_event_gesture + XCB_GESTURE_NOTIFY_GROUP)) + _ecore_xcb_event_handle_gesture_notify_group(ev); +#endif +#ifdef ECORE_XCB_SHAPE + else if ((_ecore_xcb_event_shape >= 0) && + (response == (_ecore_xcb_event_shape + XCB_SHAPE_NOTIFY))) + _ecore_xcb_event_handle_shape_change(ev); +#endif +#ifdef ECORE_XCB_SYNC + else if ((_ecore_xcb_event_sync >= 0) && + (response == (_ecore_xcb_event_sync + XCB_SYNC_COUNTER_NOTIFY))) + _ecore_xcb_event_handle_sync_counter(ev); + else if ((_ecore_xcb_event_sync >= 0) && + (response == (_ecore_xcb_event_sync + XCB_SYNC_ALARM_NOTIFY))) + _ecore_xcb_event_handle_sync_alarm(ev); +#endif +#ifdef ECORE_XCB_XFIXES + else if ((_ecore_xcb_event_xfixes >= 0) && + (response == + _ecore_xcb_event_xfixes + XCB_XFIXES_SELECTION_NOTIFY)) + _ecore_xcb_event_handle_xfixes_selection_notify(ev); + else if ((_ecore_xcb_event_xfixes >= 0) && + (response == (_ecore_xcb_event_xfixes + XCB_XFIXES_CURSOR_NOTIFY))) + _ecore_xcb_event_handle_xfixes_cursor_notify(ev); +#endif +} + +Ecore_X_Time +_ecore_xcb_events_last_time_get(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _ecore_xcb_event_last_time; +} + +EAPI void +ecore_x_event_mask_set(Ecore_X_Window win, + Ecore_X_Event_Mask mask) +{ + xcb_get_window_attributes_cookie_t cookie; + xcb_get_window_attributes_reply_t *reply; + uint32_t list; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!win) win = ((xcb_screen_t *)_ecore_xcb_screen)->root; + cookie = xcb_get_window_attributes_unchecked(_ecore_xcb_conn, win); + reply = xcb_get_window_attributes_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return; + + list = (mask | reply->your_event_mask); + free(reply); + xcb_change_window_attributes(_ecore_xcb_conn, win, + XCB_CW_EVENT_MASK, &list); +// ecore_x_flush(); +} + +EAPI void +ecore_x_event_mask_unset(Ecore_X_Window win, + Ecore_X_Event_Mask mask) +{ + xcb_get_window_attributes_cookie_t cookie; + xcb_get_window_attributes_reply_t *reply; + uint32_t list; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!win) win = ((xcb_screen_t *)_ecore_xcb_screen)->root; + cookie = xcb_get_window_attributes_unchecked(_ecore_xcb_conn, win); + reply = xcb_get_window_attributes_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return; + + list = (reply->your_event_mask & ~mask); + free(reply); + xcb_change_window_attributes(_ecore_xcb_conn, win, + XCB_CW_EVENT_MASK, &list); +// ecore_x_flush(); +} + +unsigned int +_ecore_xcb_events_modifiers_get(unsigned int state) +{ + unsigned int modifiers = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (state & ECORE_X_MODIFIER_SHIFT) + modifiers |= ECORE_EVENT_MODIFIER_SHIFT; + if (state & ECORE_X_MODIFIER_CTRL) + modifiers |= ECORE_EVENT_MODIFIER_CTRL; + if (state & ECORE_X_MODIFIER_ALT) + modifiers |= ECORE_EVENT_MODIFIER_ALT; + if (state & ECORE_X_MODIFIER_WIN) + modifiers |= ECORE_EVENT_MODIFIER_WIN; + if (state & ECORE_X_MODIFIER_ALTGR) + modifiers |= ECORE_EVENT_MODIFIER_ALTGR; + if (state & ECORE_X_LOCK_SCROLL) + modifiers |= ECORE_EVENT_LOCK_SCROLL; + if (state & ECORE_X_LOCK_CAPS) + modifiers |= ECORE_EVENT_LOCK_CAPS; + if (state & ECORE_X_LOCK_NUM) + modifiers |= ECORE_EVENT_LOCK_NUM; + if (state & ECORE_X_LOCK_SHIFT) + modifiers |= ECORE_EVENT_LOCK_SHIFT; + + return modifiers; +} + +/* local functions */ +static void +_ecore_xcb_event_handle_any_event(xcb_generic_event_t *event) +{ + xcb_generic_event_t *ev; + +// LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ev = malloc(sizeof(xcb_generic_event_t)); + if (!ev) return; + + memcpy(ev, event, sizeof(xcb_generic_event_t)); + ecore_event_add(ECORE_X_EVENT_ANY, ev, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_key_press(xcb_generic_event_t *event) +{ + _ecore_xcb_event_key_press(event); +} + +static void +_ecore_xcb_event_handle_key_release(xcb_generic_event_t *event) +{ + _ecore_xcb_event_key_release(event); +} + +static void +_ecore_xcb_event_handle_button_press(xcb_generic_event_t *event) +{ + xcb_button_press_event_t *ev; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + + ev = (xcb_button_press_event_t *)event; + if ((ev->detail > 3) && (ev->detail < 8)) + { + Ecore_Event_Mouse_Wheel *e; + + if (!(e = malloc(sizeof(Ecore_Event_Mouse_Wheel)))) return; + + e->timestamp = ev->time; + e->modifiers = _ecore_xcb_events_modifiers_get(ev->state); + switch (ev->detail) + { + case 4: + e->direction = 0; + e->z = -1; + break; + + case 5: + e->direction = 0; + e->z = 1; + break; + + case 6: + e->direction = 1; + e->z = -1; + break; + + case 7: + e->direction = 1; + e->z = 1; + break; + + default: + e->direction = 0; + e->z = 0; + break; + } + e->x = ev->event_x; + e->y = ev->event_y; + e->root.x = ev->root_x; + e->root.y = ev->root_y; + if (ev->child) + e->window = ev->child; + else + e->window = ev->event; + + e->event_window = ev->event; + e->same_screen = ev->same_screen; + e->root_window = ev->root; + + _ecore_xcb_event_last_time = e->timestamp; + _ecore_xcb_event_last_window = e->window; + _ecore_xcb_event_last_root_x = e->root.x; + _ecore_xcb_event_last_root_y = e->root.y; + + ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, e, NULL, NULL); + + _ecore_xcb_window_grab_allow_events(ev->event, ev->child, + ECORE_EVENT_MOUSE_WHEEL, + e, ev->time); + } + else + { + Ecore_Event_Mouse_Button *e; + unsigned int child_win = 0; + + child_win = (ev->child ? ev->child : ev->event); + + _ecore_xcb_event_mouse_move(ev->time, ev->state, + ev->event_x, ev->event_y, + ev->root_x, ev->root_y, + ev->event, child_win, + ev->root, ev->same_screen, + 0, 1, 1, 1.0, 0.0, + ev->event_x, ev->event_y, + ev->root_x, ev->root_y); + + e = _ecore_xcb_event_mouse_button(ECORE_EVENT_MOUSE_BUTTON_DOWN, + ev->time, + ev->state, ev->detail, + ev->event_x, ev->event_y, + ev->root_x, ev->root_y, ev->event, + child_win, + ev->root, ev->same_screen, + 0, 1, 1, 1.0, 0.0, + ev->event_x, ev->event_y, + ev->root_x, ev->root_y); + if (e) + _ecore_xcb_window_grab_allow_events(ev->event, ev->child, + ECORE_EVENT_MOUSE_BUTTON_DOWN, + e, ev->time); + } +} + +static void +_ecore_xcb_event_handle_button_release(xcb_generic_event_t *event) +{ + xcb_button_release_event_t *ev; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_button_release_event_t *)event; + if ((ev->detail <= 3) || (ev->detail > 7)) + { + _ecore_xcb_event_mouse_move(ev->time, ev->state, + ev->event_x, ev->event_y, + ev->root_x, ev->root_y, + ev->event, + (ev->child ? ev->child : ev->event), + ev->root, ev->same_screen, + 0, 1, 1, 1.0, 0.0, + ev->event_x, ev->event_y, + ev->root_x, ev->root_y); + + _ecore_xcb_event_mouse_button(ECORE_EVENT_MOUSE_BUTTON_UP, ev->time, + ev->state, ev->detail, + ev->event_x, ev->event_y, ev->root_x, + ev->root_y, ev->event, + (ev->child ? ev->child : ev->event), + ev->root, ev->same_screen, + 0, 1, 1, 1.0, 0.0, + ev->event_x, ev->event_y, + ev->root_x, ev->root_y); + } +} + +static void +_ecore_xcb_event_handle_motion_notify(xcb_generic_event_t *event) +{ + xcb_motion_notify_event_t *ev; + + ev = (xcb_motion_notify_event_t *)event; + + /* if (_ecore_xcb_event_last_mouse_move_event) */ + /* { */ + /* ecore_event_del(_ecore_xcb_event_last_mouse_move_event); */ + /* _ecore_xcb_event_last_mouse_move = EINA_FALSE; */ + /* _ecore_xcb_event_last_mouse_move_event = NULL; */ + /* } */ + + _ecore_xcb_event_mouse_move(ev->time, ev->state, + ev->event_x, ev->event_y, + ev->root_x, ev->root_y, + ev->event, + (ev->child ? ev->child : ev->event), + ev->root, ev->same_screen, + 0, 1, 1, 1.0, 0.0, + ev->event_x, ev->event_y, + ev->root_x, ev->root_y); + _ecore_xcb_event_last_mouse_move = EINA_TRUE; + + _ecore_xcb_dnd_drag(ev->root, ev->root_x, ev->root_y); +} + +static void +_ecore_xcb_event_handle_enter_notify(xcb_generic_event_t *event) +{ + xcb_enter_notify_event_t *ev; + Ecore_X_Event_Mouse_In *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_enter_notify_event_t *)event; + + _ecore_xcb_event_mouse_move(ev->time, ev->state, + ev->event_x, ev->event_y, + ev->root_x, ev->root_y, + ev->event, + (ev->child ? ev->child : ev->event), + ev->root, ev->same_screen_focus, + 0, 1, 1, 1.0, 0.0, + ev->event_x, ev->event_y, + ev->root_x, ev->root_y); + + if (!(e = calloc(1, sizeof(Ecore_X_Event_Mouse_In)))) return; + + e->modifiers = _ecore_xcb_events_modifiers_get(ev->state); + e->x = ev->event_x; + e->y = ev->event_y; + e->root.x = ev->root_x; + e->root.y = ev->root_y; + if (ev->child) + e->win = ev->child; + else + e->win = ev->event; + e->event_win = ev->event; + e->same_screen = ev->same_screen_focus; + e->root_win = ev->root; + e->mode = _ecore_xcb_event_mode_get(ev->mode); + e->detail = _ecore_xcb_event_detail_get(ev->detail); + e->time = ev->time; + _ecore_xcb_event_last_time = e->time; + + ecore_event_add(ECORE_X_EVENT_MOUSE_IN, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_leave_notify(xcb_generic_event_t *event) +{ + xcb_leave_notify_event_t *ev; + Ecore_X_Event_Mouse_Out *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_enter_notify_event_t *)event; + + _ecore_xcb_event_mouse_move(ev->time, ev->state, + ev->event_x, ev->event_y, + ev->root_x, ev->root_y, + ev->event, + (ev->child ? ev->child : ev->event), + ev->root, ev->same_screen_focus, + 0, 1, 1, 1.0, 0.0, + ev->event_x, ev->event_y, + ev->root_x, ev->root_y); + + if (!(e = calloc(1, sizeof(Ecore_X_Event_Mouse_Out)))) return; + + e->modifiers = _ecore_xcb_events_modifiers_get(ev->state); + e->x = ev->event_x; + e->y = ev->event_y; + e->root.x = ev->root_x; + e->root.y = ev->root_y; + if (ev->child) + e->win = ev->child; + else + e->win = ev->event; + e->event_win = ev->event; + e->same_screen = ev->same_screen_focus; + e->root_win = ev->root; + e->mode = _ecore_xcb_event_mode_get(ev->mode); + e->detail = _ecore_xcb_event_detail_get(ev->detail); + + e->time = ev->time; + _ecore_xcb_event_last_time = e->time; + _ecore_xcb_event_last_window = e->win; + _ecore_xcb_event_last_root_x = e->root.x; + _ecore_xcb_event_last_root_y = e->root.y; + + ecore_event_add(ECORE_X_EVENT_MOUSE_OUT, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_keymap_notify(xcb_generic_event_t *event __UNUSED__) +{ +// LOGFN(__FILE__, __LINE__, __FUNCTION__); + + // FIXME: handle this event type + _ecore_xcb_event_last_mouse_move = EINA_FALSE; +} + +static void +_ecore_xcb_event_handle_focus_in(xcb_generic_event_t *event) +{ + xcb_focus_in_event_t *ev; + Ecore_X_Event_Window_Focus_In *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_focus_in_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Focus_In)))) return; + + e->win = ev->event; + e->mode = _ecore_xcb_event_mode_get(ev->mode); + e->detail = _ecore_xcb_event_detail_get(ev->detail); + + e->time = _ecore_xcb_event_last_time; + _ecore_xcb_event_last_time = e->time; + + ecore_event_add(ECORE_X_EVENT_WINDOW_FOCUS_IN, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_focus_out(xcb_generic_event_t *event) +{ + xcb_focus_out_event_t *ev; + Ecore_X_Event_Window_Focus_Out *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_focus_out_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Focus_Out)))) return; + + e->win = ev->event; + e->mode = _ecore_xcb_event_mode_get(ev->mode); + e->detail = _ecore_xcb_event_detail_get(ev->detail); + + e->time = _ecore_xcb_event_last_time; + _ecore_xcb_event_last_time = e->time; + + ecore_event_add(ECORE_X_EVENT_WINDOW_FOCUS_OUT, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_expose(xcb_generic_event_t *event) +{ + xcb_expose_event_t *ev; + Ecore_X_Event_Window_Damage *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_expose_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Damage)))) return; + + e->win = ev->window; + e->time = _ecore_xcb_event_last_time; + e->x = ev->x; + e->y = ev->y; + e->w = ev->width; + e->h = ev->height; + e->count = ev->count; + + ecore_event_add(ECORE_X_EVENT_WINDOW_DAMAGE, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_graphics_exposure(xcb_generic_event_t *event) +{ + xcb_graphics_exposure_event_t *ev; + Ecore_X_Event_Window_Damage *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_graphics_exposure_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Damage)))) return; + + e->win = ev->drawable; + e->x = ev->x; + e->y = ev->y; + e->w = ev->width; + e->h = ev->height; + e->count = ev->count; + e->time = _ecore_xcb_event_last_time; + + ecore_event_add(ECORE_X_EVENT_WINDOW_DAMAGE, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_visibility_notify(xcb_generic_event_t *event) +{ + xcb_visibility_notify_event_t *ev; + Ecore_X_Event_Window_Visibility_Change *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_visibility_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Visibility_Change)))) + return; + + e->win = ev->window; + e->time = _ecore_xcb_event_last_time; + if (ev->state == XCB_VISIBILITY_FULLY_OBSCURED) + e->fully_obscured = 1; + else + e->fully_obscured = 0; + + ecore_event_add(ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_create_notify(xcb_generic_event_t *event) +{ + xcb_create_notify_event_t *ev; + Ecore_X_Event_Window_Create *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_create_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Create)))) return; + + e->win = ev->window; + e->parent = ev->parent; + if (ev->override_redirect) + e->override = 1; + else + e->override = 0; + e->x = ev->x; + e->y = ev->y; + e->w = ev->width; + e->h = ev->height; + e->border = ev->border_width; + e->time = _ecore_xcb_event_last_time; + + ecore_event_add(ECORE_X_EVENT_WINDOW_CREATE, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_destroy_notify(xcb_generic_event_t *event) +{ + xcb_destroy_notify_event_t *ev; + Ecore_X_Event_Window_Destroy *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_destroy_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Destroy)))) return; + + e->win = ev->window; + e->event_win = ev->event; + if (e->win == _ecore_xcb_event_last_window) + _ecore_xcb_event_last_window = 0; + e->time = _ecore_xcb_event_last_time; + + ecore_event_add(ECORE_X_EVENT_WINDOW_DESTROY, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_map_notify(xcb_generic_event_t *event) +{ + xcb_map_notify_event_t *ev; + Ecore_X_Event_Window_Show *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_map_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Show)))) return; + + e->win = ev->window; + e->event_win = ev->event; + e->time = _ecore_xcb_event_last_time; + + ecore_event_add(ECORE_X_EVENT_WINDOW_SHOW, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_unmap_notify(xcb_generic_event_t *event) +{ + xcb_unmap_notify_event_t *ev; + Ecore_X_Event_Window_Hide *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_unmap_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Hide)))) return; + + e->win = ev->window; + e->event_win = ev->event; + e->time = _ecore_xcb_event_last_time; + + ecore_event_add(ECORE_X_EVENT_WINDOW_HIDE, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_map_request(xcb_generic_event_t *event) +{ + xcb_map_request_event_t *ev; + Ecore_X_Event_Window_Show_Request *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_map_request_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Show_Request)))) return; + + e->win = ev->window; + e->parent = ev->parent; + e->time = _ecore_xcb_event_last_time; + + ecore_event_add(ECORE_X_EVENT_WINDOW_SHOW_REQUEST, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_reparent_notify(xcb_generic_event_t *event) +{ + xcb_reparent_notify_event_t *ev; + Ecore_X_Event_Window_Reparent *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_reparent_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Reparent)))) return; + + e->win = ev->window; + e->event_win = ev->event; + e->parent = ev->parent; + e->time = _ecore_xcb_event_last_time; + + ecore_event_add(ECORE_X_EVENT_WINDOW_REPARENT, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_configure_notify(xcb_generic_event_t *event) +{ + xcb_configure_notify_event_t *ev; + Ecore_X_Event_Window_Configure *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_configure_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Configure)))) return; + + e->win = ev->window; + e->event_win = ev->event; + e->abovewin = ev->above_sibling; + e->x = ev->x; + e->y = ev->y; + e->w = ev->width; + e->h = ev->height; + e->border = ev->border_width; + e->override = ev->override_redirect; + /* send_event is bit 7 (0x80) of response_type */ + e->from_wm = ((ev->response_type & 0x80) ? 1 : 0); + e->time = _ecore_xcb_event_last_time; + + ecore_event_add(ECORE_X_EVENT_WINDOW_CONFIGURE, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_configure_request(xcb_generic_event_t *event) +{ + xcb_configure_request_event_t *ev; + Ecore_X_Event_Window_Configure_Request *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_configure_request_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Configure_Request)))) + return; + + e->win = ev->window; + e->parent_win = ev->parent; + e->abovewin = ev->sibling; + e->x = ev->x; + e->y = ev->y; + e->w = ev->width; + e->h = ev->height; + e->border = ev->border_width; + e->value_mask = ev->value_mask; + switch (ev->stack_mode) + { + case XCB_STACK_MODE_ABOVE: + e->detail = ECORE_X_WINDOW_STACK_ABOVE; + break; + + case XCB_STACK_MODE_BELOW: + e->detail = ECORE_X_WINDOW_STACK_BELOW; + break; + + case XCB_STACK_MODE_TOP_IF: + e->detail = ECORE_X_WINDOW_STACK_TOP_IF; + break; + + case XCB_STACK_MODE_BOTTOM_IF: + e->detail = ECORE_X_WINDOW_STACK_BOTTOM_IF; + break; + + case XCB_STACK_MODE_OPPOSITE: + e->detail = ECORE_X_WINDOW_STACK_OPPOSITE; + break; + } + e->time = _ecore_xcb_event_last_time; + + ecore_event_add(ECORE_X_EVENT_WINDOW_CONFIGURE_REQUEST, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_gravity_notify(xcb_generic_event_t *event __UNUSED__) +{ +/* + xcb_gravity_notify_event_t *ev; + Ecore_X_Event_Window_Gravity *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_gravity_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Gravity)))) return; + + e->win = ev->window; + e->event_win = ev->event; + e->time = _ecore_xcb_event_last_time; + + ecore_event_add(ECORE_X_EVENT_WINDOW_GRAVITY, e, NULL, NULL); + */ +} + +static void +_ecore_xcb_event_handle_resize_request(xcb_generic_event_t *event) +{ + xcb_resize_request_event_t *ev; + Ecore_X_Event_Window_Resize_Request *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_resize_request_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Resize_Request)))) return; + + e->win = ev->window; + e->w = ev->width; + e->h = ev->height; + e->time = _ecore_xcb_event_last_time; + + ecore_event_add(ECORE_X_EVENT_WINDOW_RESIZE_REQUEST, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_circulate_notify(xcb_generic_event_t *event) +{ + xcb_circulate_notify_event_t *ev; + Ecore_X_Event_Window_Stack *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_circulate_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Stack)))) return; + + e->win = ev->window; + e->event_win = ev->event; + if (ev->place == XCB_PLACE_ON_TOP) + e->detail = ECORE_X_WINDOW_STACK_ABOVE; + else + e->detail = ECORE_X_WINDOW_STACK_BELOW; + e->time = _ecore_xcb_event_last_time; + + ecore_event_add(ECORE_X_EVENT_WINDOW_STACK, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_circulate_request(xcb_generic_event_t *event) +{ + xcb_circulate_request_event_t *ev; + Ecore_X_Event_Window_Stack_Request *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_circulate_request_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Stack_Request)))) return; + + e->win = ev->window; + e->parent = ev->event; + if (ev->place == XCB_PLACE_ON_TOP) + e->detail = ECORE_X_WINDOW_STACK_ABOVE; + else + e->detail = ECORE_X_WINDOW_STACK_BELOW; + e->time = _ecore_xcb_event_last_time; + + ecore_event_add(ECORE_X_EVENT_WINDOW_STACK_REQUEST, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_property_notify(xcb_generic_event_t *event) +{ + xcb_property_notify_event_t *ev; + Ecore_X_Event_Window_Property *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_property_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Property)))) return; + + e->win = ev->window; + e->atom = ev->atom; + e->time = ev->time; + _ecore_xcb_event_last_time = e->time; + + ecore_event_add(ECORE_X_EVENT_WINDOW_PROPERTY, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_selection_clear(xcb_generic_event_t *event) +{ + xcb_selection_clear_event_t *ev; + Ecore_X_Event_Selection_Clear *e; + Ecore_X_Atom sel; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_selection_clear_event_t *)event; + if (!(e = malloc(sizeof(Ecore_X_Event_Selection_Clear)))) return; + + e->win = ev->owner; + e->atom = sel = ev->selection; + if (sel == ECORE_X_ATOM_SELECTION_PRIMARY) + e->selection = ECORE_X_SELECTION_PRIMARY; + else if (sel == ECORE_X_ATOM_SELECTION_SECONDARY) + e->selection = ECORE_X_SELECTION_SECONDARY; + else if (sel == ECORE_X_ATOM_SELECTION_CLIPBOARD) + e->selection = ECORE_X_SELECTION_CLIPBOARD; + else + e->selection = ECORE_X_SELECTION_OTHER; + e->time = ev->time; + + ecore_event_add(ECORE_X_EVENT_SELECTION_CLEAR, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_selection_request(xcb_generic_event_t *event) +{ + xcb_selection_request_event_t *ev; + Ecore_X_Event_Selection_Request *e; + Ecore_X_Selection_Intern *sd; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_selection_request_event_t *)event; + if (!(e = malloc(sizeof(Ecore_X_Event_Selection_Request)))) return; + + e->owner = ev->owner; + e->requestor = ev->requestor; + e->selection = ev->selection; + e->target = ev->target; + e->property = ev->property; + e->time = ev->time; + + ecore_event_add(ECORE_X_EVENT_SELECTION_REQUEST, e, NULL, NULL); + + if ((sd = _ecore_xcb_selection_get(ev->selection)) && + (sd->win == ev->owner)) + { + Ecore_X_Selection_Intern *si; + + si = _ecore_xcb_selection_get(ev->selection); + if (si->data) + { + Ecore_X_Atom property = XCB_NONE, type; + void *data = NULL; + int len = 0, typesize = 0; + + type = ev->target; + typesize = 8; + len = sd->length; + + if (!ecore_x_selection_convert(ev->selection, ev->target, + &data, &len, &type, &typesize)) + property = XCB_NONE; + else if (data) + { + ecore_x_window_prop_property_set(ev->requestor, ev->property, + type, typesize, data, len); + property = ev->property; + free(data); + } + ecore_x_selection_notify_send(ev->requestor, ev->selection, + ev->target, property, ev->time); + } + } +} + +static void +_ecore_xcb_event_handle_selection_notify(xcb_generic_event_t *event) +{ + xcb_selection_notify_event_t *ev; + Ecore_X_Event_Selection_Notify *e; + unsigned char *data = NULL; + Ecore_X_Atom selection; + int num = 0, format = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_selection_notify_event_t *)event; + selection = ev->selection; + if (ev->target == ECORE_X_ATOM_SELECTION_TARGETS) + { + format = + ecore_x_window_prop_property_get(ev->requestor, ev->property, + XCB_ATOM_ATOM, 32, &data, &num); + if (!format) + { + /* fallback if targets handling is not working and try get the + * selection directly */ + xcb_convert_selection(_ecore_xcb_conn, ev->requestor, + selection, selection, + ECORE_X_ATOM_UTF8_STRING, XCB_CURRENT_TIME); + return; + } + } + else + { + format = + ecore_x_window_prop_property_get(ev->requestor, ev->property, + XCB_GET_PROPERTY_TYPE_ANY, 8, + &data, &num); + if (!format) return; + } + + e = calloc(1, sizeof(Ecore_X_Event_Selection_Notify)); + if (!e) return; + e->win = ev->requestor; + e->time = ev->time; + e->atom = selection; + e->target = _ecore_xcb_selection_target_get(ev->target); + + if (selection == ECORE_X_ATOM_SELECTION_PRIMARY) + e->selection = ECORE_X_SELECTION_PRIMARY; + else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY) + e->selection = ECORE_X_SELECTION_SECONDARY; + else if (selection == ECORE_X_ATOM_SELECTION_XDND) + e->selection = ECORE_X_SELECTION_XDND; + else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD) + e->selection = ECORE_X_SELECTION_CLIPBOARD; + else + e->selection = ECORE_X_SELECTION_OTHER; + + e->data = _ecore_xcb_selection_parse(e->target, data, num, format); + + ecore_event_add(ECORE_X_EVENT_SELECTION_NOTIFY, e, + _ecore_xcb_event_selection_notify_free, NULL); +} + +static void +_ecore_xcb_event_handle_colormap_notify(xcb_generic_event_t *event) +{ + xcb_colormap_notify_event_t *ev; + Ecore_X_Event_Window_Colormap *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_colormap_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Colormap)))) return; + + e->win = ev->window; + e->cmap = ev->colormap; + if (ev->state == XCB_COLORMAP_STATE_INSTALLED) + e->installed = 1; + else + e->installed = 0; + e->time = _ecore_xcb_event_last_time; + + ecore_event_add(ECORE_X_EVENT_WINDOW_COLORMAP, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_client_message(xcb_generic_event_t *event) +{ + xcb_client_message_event_t *ev; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_client_message_event_t *)event; + + /* Special client message event handling here. need to put LOTS of if */ + /* checks here and generate synthetic events per special message known */ + /* otherwise generate generic client message event. this would handle*/ + /* netwm, ICCCM, gnomewm, old kde and mwm hint client message protocols */ + + if ((ev->type == ECORE_X_ATOM_WM_PROTOCOLS) && (ev->format == 32) && + (ev->data.data32[0] == ECORE_X_ATOM_WM_DELETE_WINDOW)) + { + Ecore_X_Event_Window_Delete_Request *e; + + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Delete_Request)))) + return; + e->win = ev->window; + e->time = _ecore_xcb_event_last_time; + ecore_event_add(ECORE_X_EVENT_WINDOW_DELETE_REQUEST, e, NULL, NULL); + } + else if ((ev->type == ECORE_X_ATOM_NET_WM_MOVERESIZE) && + (ev->format == 32) && (ev->data.data32[2] < 9)) + { + Ecore_X_Event_Window_Move_Resize_Request *e; + + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Move_Resize_Request)))) + return; + e->win = ev->window; + e->x = ev->data.data32[0]; + e->y = ev->data.data32[1]; + e->direction = ev->data.data32[2]; + e->button = ev->data.data32[3]; + e->source = ev->data.data32[4]; + ecore_event_add(ECORE_X_EVENT_WINDOW_MOVE_RESIZE_REQUEST, e, NULL, NULL); + } + else if (ev->type == ECORE_X_ATOM_XDND_ENTER) + { + Ecore_X_Event_Xdnd_Enter *e; + Ecore_X_DND_Target *target; + + DBG("Got Xdnd Enter Event"); + if (!(e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Enter)))) return; + target = _ecore_xcb_dnd_target_get(); + target->state = ECORE_X_DND_TARGET_ENTERED; + target->source = ev->data.data32[0]; + target->win = ev->window; + target->version = (int)(ev->data.data32[1] >> 24); + if (target->version > ECORE_X_DND_VERSION) + { + WRN("DND: Requested version %d but we only support up to %d", + target->version, ECORE_X_DND_VERSION); + free(e); + return; + } + if (ev->data.data32[1] & 0x1UL) + { + unsigned char *data; + Ecore_X_Atom *types; + int num_ret = 0; + + if (!ecore_x_window_prop_property_get(target->source, + ECORE_X_ATOM_XDND_TYPE_LIST, + ECORE_X_ATOM_ATOM, 32, + &data, &num_ret)) + { + WRN("DND: Could not fetch data type list from source window"); + free(e); + return; + } + types = (Ecore_X_Atom *)data; + e->types = calloc(num_ret, sizeof(char *)); + if (e->types) + { + int i = 0; + + for (i = 0; i < num_ret; i++) + e->types[i] = ecore_x_atom_name_get(types[i]); + } + e->num_types = num_ret; + } + else + { + int i = 0; + + e->types = calloc(3, sizeof(char *)); + if (e->types) + { + while ((i < 3) && (ev->data.data32[i + 2])) + { + e->types[i] = + ecore_x_atom_name_get(ev->data.data32[i + 2]); + i++; + } + } + e->num_types = i; + } + + e->win = target->win; + e->source = target->source; + ecore_event_add(ECORE_X_EVENT_XDND_ENTER, e, + _ecore_xcb_event_xdnd_enter_free, NULL); + } + else if (ev->type == ECORE_X_ATOM_XDND_POSITION) + { + Ecore_X_Event_Xdnd_Position *e; + Ecore_X_DND_Target *target; + + DBG("Got Xdnd Position Event"); + target = _ecore_xcb_dnd_target_get(); + if ((target->source != (Ecore_X_Window)ev->data.data32[0]) || + (target->win != ev->window)) return; + target->pos.x = ev->data.data32[2] >> 16; + target->pos.y = ev->data.data32[2] & 0xFFFFUL; + target->action = ev->data.data32[4]; + target->time = (target->version >= 1) ? + (Ecore_X_Time)ev->data.data32[3] : XCB_CURRENT_TIME; + + e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Position)); + if (!e) return; + e->win = target->win; + e->source = target->source; + e->position.x = target->pos.x; + e->position.y = target->pos.y; + e->action = target->action; + ecore_event_add(ECORE_X_EVENT_XDND_POSITION, e, NULL, NULL); + } + else if (ev->type == ECORE_X_ATOM_XDND_STATUS) + { + Ecore_X_Event_Xdnd_Status *e; + Ecore_X_DND_Source *source; + + DBG("Got Xdnd Status Event"); + source = _ecore_xcb_dnd_source_get(); + if ((source->win != ev->window) || + (source->dest != (Ecore_X_Window)ev->data.data32[0])) + return; + + source->await_status = 0; + source->will_accept = ev->data.data32[1] & 0x1UL; + source->suppress = (ev->data.data32[1] & 0x2UL) ? 0 : 1; + source->rectangle.x = ev->data.data32[2] >> 16; + source->rectangle.y = ev->data.data32[2] & 0xFFFFUL; + source->rectangle.width = ev->data.data32[3] >> 16; + source->rectangle.height = ev->data.data32[3] & 0xFFFFUL; + source->accepted_action = ev->data.data32[4]; + + e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Status)); + if (!e) return; + e->win = source->win; + e->target = source->dest; + e->will_accept = source->will_accept; + e->rectangle.x = source->rectangle.x; + e->rectangle.y = source->rectangle.y; + e->rectangle.width = source->rectangle.width; + e->rectangle.height = source->rectangle.height; + e->action = source->accepted_action; + + ecore_event_add(ECORE_X_EVENT_XDND_STATUS, e, NULL, NULL); + } + else if (ev->type == ECORE_X_ATOM_XDND_LEAVE) + { + Ecore_X_Event_Xdnd_Leave *e; + Ecore_X_DND_Target *target; + + DBG("Got Xdnd Leave Event"); + target = _ecore_xcb_dnd_target_get(); + if ((target->source != (Ecore_X_Window)ev->data.data32[0]) || + (target->win != ev->window)) + return; + target->state = ECORE_X_DND_TARGET_IDLE; + e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Leave)); + if (!e) return; + e->win = ev->window; + e->source = (Ecore_X_Window)ev->data.data32[0]; + ecore_event_add(ECORE_X_EVENT_XDND_LEAVE, e, NULL, NULL); + } + else if (ev->type == ECORE_X_ATOM_XDND_DROP) + { + Ecore_X_Event_Xdnd_Drop *e; + Ecore_X_DND_Target *target; + + DBG("Got Xdnd Drop Event"); + target = _ecore_xcb_dnd_target_get(); + if ((target->source != (Ecore_X_Window)ev->data.data32[0]) || + (target->win != ev->window)) + return; + target->time = (target->version >= 1) ? + (Ecore_X_Time)ev->data.data32[2] : _ecore_xcb_event_last_time; + + e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Drop)); + if (!e) return; + e->win = target->win; + e->source = target->source; + e->action = target->action; + e->position.x = target->pos.x; + e->position.y = target->pos.y; + ecore_event_add(ECORE_X_EVENT_XDND_DROP, e, NULL, NULL); + } + else if (ev->type == ECORE_X_ATOM_XDND_FINISHED) + { + Ecore_X_Event_Xdnd_Finished *e; + Ecore_X_DND_Source *source; + Eina_Bool completed = EINA_TRUE; + + DBG("Got Xdnd Finished Event"); + source = _ecore_xcb_dnd_source_get(); + if ((source->win != ev->window) || + (source->dest != (Ecore_X_Window)ev->data.data32[0])) + return; + if ((source->version < 5) || (ev->data.data32[1] & 0x1UL)) + { + ecore_x_selection_xdnd_clear(); + source->state = ECORE_X_DND_SOURCE_IDLE; + } + else if (source->version >= 5) + { + completed = EINA_FALSE; + source->state = ECORE_X_DND_SOURCE_CONVERTING; + /* FIXME: Probably need to add a timer to switch back to idle + * and discard the selection data */ + } + + if (!(e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Finished)))) + return; + e->win = source->win; + e->target = source->dest; + e->completed = completed; + if (source->version >= 5) + { + source->accepted_action = ev->data.data32[2]; + e->action = source->accepted_action; + } + else + { + source->accepted_action = 0; + e->action = source->action; + } + ecore_event_add(ECORE_X_EVENT_XDND_FINISHED, e, NULL, NULL); + } + else if (ev->type == ECORE_X_ATOM_NET_WM_STATE) + { + Ecore_X_Event_Window_State_Request *e; + + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_State_Request)))) + return; + e->win = ev->window; + if (ev->data.data32[0] == 0) + e->action = ECORE_X_WINDOW_STATE_ACTION_REMOVE; + else if (ev->data.data32[0] == 1) + e->action = ECORE_X_WINDOW_STATE_ACTION_ADD; + else if (ev->data.data32[0] == 2) + e->action = ECORE_X_WINDOW_STATE_ACTION_TOGGLE; + else + { + free(e); + return; + } + e->state[0] = _ecore_xcb_netwm_window_state_get(ev->data.data32[1]); + if (e->state[0] == ECORE_X_WINDOW_STATE_UNKNOWN) + { + /* FIXME */ + } + e->state[1] = _ecore_xcb_netwm_window_state_get(ev->data.data32[2]); + if (e->state[1] == ECORE_X_WINDOW_STATE_UNKNOWN) + { + /* FIXME */ + } + e->source = ev->data.data32[3]; + ecore_event_add(ECORE_X_EVENT_WINDOW_STATE_REQUEST, e, NULL, NULL); + } +#ifdef OLD_XCB_VERSION + else if ((ev->type == ECORE_X_ATOM_WM_CHANGE_STATE) && + (ev->format == 32) && (ev->data.data32[0] == XCB_WM_STATE_ICONIC)) +#else + else if ((ev->type == ECORE_X_ATOM_WM_CHANGE_STATE) && (ev->format == 32) && + (ev->data.data32[0] == XCB_ICCCM_WM_STATE_ICONIC)) +#endif + { + Ecore_X_Event_Window_State_Request *e; + + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_State_Request)))) + return; + e->win = ev->window; + e->action = ECORE_X_WINDOW_STATE_ACTION_ADD; + e->state[0] = ECORE_X_WINDOW_STATE_ICONIFIED; + ecore_event_add(ECORE_X_EVENT_WINDOW_STATE_REQUEST, e, NULL, NULL); + } + else if ((ev->type == ECORE_X_ATOM_NET_WM_DESKTOP) && (ev->format == 32)) + { + Ecore_X_Event_Desktop_Change *e; + + if (!(e = calloc(1, sizeof(Ecore_X_Event_Desktop_Change)))) + return; + e->win = ev->window; + e->desk = ev->data.data32[0]; + e->source = ev->data.data32[1]; + ecore_event_add(ECORE_X_EVENT_DESKTOP_CHANGE, e, NULL, NULL); + } + else if (ev->type == ECORE_X_ATOM_NET_REQUEST_FRAME_EXTENTS) + { + Ecore_X_Event_Frame_Extents_Request *e; + + if (!(e = calloc(1, sizeof(Ecore_X_Event_Frame_Extents_Request)))) + return; + e->win = ev->window; + ecore_event_add(ECORE_X_EVENT_FRAME_EXTENTS_REQUEST, e, NULL, NULL); + } + else if ((ev->type == ECORE_X_ATOM_WM_PROTOCOLS) && + ((Ecore_X_Atom)ev->data.data32[0] == ECORE_X_ATOM_NET_WM_PING) && + (ev->format == 32)) + { + Ecore_X_Event_Ping *e; + Ecore_X_Window root = 0; + int count = 0; + + if (!(e = calloc(1, sizeof(Ecore_X_Event_Ping)))) return; + e->win = ev->window; + e->time = ev->data.data32[1]; + e->event_win = ev->data.data32[2]; + ecore_event_add(ECORE_X_EVENT_PING, e, NULL, NULL); + + CHECK_XCB_CONN; + + count = xcb_setup_roots_length(xcb_get_setup(_ecore_xcb_conn)); + if (count > 1) + root = ecore_x_window_root_get(e->win); + else + root = ((xcb_screen_t *)_ecore_xcb_screen)->root; + + if (ev->window != root) + { + ev->window = root; + xcb_send_event(_ecore_xcb_conn, 0, root, + (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY), + (const char *)&ev); +// ecore_x_flush(); + } + } + else if ((ev->type == ECORE_X_ATOM_NET_STARTUP_INFO_BEGIN) && + (ev->format == 8)) + { + _ecore_xcb_netwm_startup_info_begin(ev->window, ev->data.data8[0]); + } + else if ((ev->type == ECORE_X_ATOM_NET_STARTUP_INFO) && (ev->format == 8)) + { + _ecore_xcb_netwm_startup_info(ev->window, ev->data.data8[0]); + } + else if ((ev->type == 27777) && (ev->data.data32[0] == 0x7162534) && + (ev->format == 32)) // && (ev->window = _private_window)) + { + if (ev->data.data32[1] == 0x10000001) + _ecore_xcb_window_button_grab_remove(ev->data.data32[2]); + else if (ev->data.data32[1] == 0x10000002) + _ecore_xcb_window_key_grab_remove(ev->data.data32[2]); + } + else + { + Ecore_X_Event_Client_Message *e; + int i = 0; + + if (!(e = calloc(1, sizeof(Ecore_X_Event_Client_Message)))) + return; + + e->win = ev->window; + e->message_type = ev->type; + e->format = ev->format; + for (i = 0; i < 5; i++) + e->data.l[i] = ev->data.data32[i]; + ecore_event_add(ECORE_X_EVENT_CLIENT_MESSAGE, e, NULL, NULL); + } +} + +static void +_ecore_xcb_event_handle_mapping_notify(xcb_generic_event_t *event) +{ + xcb_mapping_notify_event_t *ev; + Ecore_X_Event_Mapping_Change *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + + ev = (xcb_mapping_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Mapping_Change)))) return; + + _ecore_xcb_keymap_refresh(ev); + _ecore_xcb_modifiers_get(); + + switch (ev->request) + { + case XCB_MAPPING_MODIFIER: + e->type = ECORE_X_MAPPING_MODIFIER; + break; + + case XCB_MAPPING_KEYBOARD: + e->type = ECORE_X_MAPPING_KEYBOARD; + break; + + case XCB_MAPPING_POINTER: + default: + e->type = ECORE_X_MAPPING_MOUSE; + break; + } + e->keycode = ev->first_keycode; + e->num = ev->count; + + ecore_event_add(ECORE_X_EVENT_MAPPING_CHANGE, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_damage_notify(xcb_generic_event_t *event) +{ +#ifdef ECORE_XCB_DAMAGE + xcb_damage_notify_event_t *ev; + Ecore_X_Event_Damage *e; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; +#ifdef ECORE_XCB_DAMAGE + ev = (xcb_damage_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Damage)))) return; + + e->level = ev->level; + e->drawable = ev->drawable; + e->damage = ev->damage; + e->time = ev->timestamp; + e->area.x = ev->area.x; + e->area.y = ev->area.y; + e->area.width = ev->area.width; + e->area.height = ev->area.height; + e->geometry.x = ev->geometry.x; + e->geometry.y = ev->geometry.y; + e->geometry.width = ev->geometry.width; + e->geometry.height = ev->geometry.height; + + ecore_event_add(ECORE_X_EVENT_DAMAGE_NOTIFY, e, NULL, NULL); +#endif +} + +static void +_ecore_xcb_event_handle_randr_change(xcb_generic_event_t *event) +{ +#ifdef ECORE_XCB_RANDR + xcb_randr_screen_change_notify_event_t *ev; + Ecore_X_Event_Screen_Change *e; +#endif + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; +#ifdef ECORE_XCB_RANDR + ev = (xcb_randr_screen_change_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Screen_Change)))) return; + + e->win = ev->request_window; + e->root = ev->root; + e->size.width = ev->width; + e->size.height = ev->height; + e->time = ev->timestamp; + e->config_time = ev->config_timestamp; + e->size.width_mm = ev->mwidth; + e->size.height_mm = ev->mheight; + e->orientation = ev->rotation; + e->subpixel_order = ev->subpixel_order; + + ecore_event_add(ECORE_X_EVENT_SCREEN_CHANGE, e, NULL, NULL); +#endif +} + +static void +_ecore_xcb_event_handle_randr_notify(xcb_generic_event_t *event) +{ +#ifdef ECORE_XCB_RANDR + xcb_randr_notify_event_t *ev; +#endif + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; +#ifdef ECORE_XCB_RANDR + ev = (xcb_randr_notify_event_t *)event; + switch (ev->subCode) + { + case XCB_RANDR_NOTIFY_CRTC_CHANGE: + _ecore_xcb_event_handle_randr_crtc_change(event); + break; + + case XCB_RANDR_NOTIFY_OUTPUT_CHANGE: + _ecore_xcb_event_handle_randr_output_change(event); + break; + + case XCB_RANDR_NOTIFY_OUTPUT_PROPERTY: + _ecore_xcb_event_handle_randr_output_property_change(event); + break; + + default: + break; + } +#endif +} + +static void +_ecore_xcb_event_handle_randr_crtc_change(xcb_generic_event_t *event) +{ +#ifdef ECORE_XCB_RANDR + xcb_randr_notify_event_t *ev; + Ecore_X_Event_Randr_Crtc_Change *e; +#endif + +#ifdef ECORE_XCB_RANDR + ev = (xcb_randr_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Randr_Crtc_Change)))) + return; + + e->win = ev->u.cc.window; + e->crtc = ev->u.cc.crtc; + e->mode = ev->u.cc.mode; + e->orientation = ev->u.cc.rotation; + e->geo.x = ev->u.cc.x; + e->geo.y = ev->u.cc.y; + e->geo.w = ev->u.cc.width; + e->geo.h = ev->u.cc.height; + + ecore_event_add(ECORE_X_EVENT_RANDR_CRTC_CHANGE, e, NULL, NULL); +#endif +} + +static void +_ecore_xcb_event_handle_randr_output_change(xcb_generic_event_t *event) +{ +#ifdef ECORE_XCB_RANDR + xcb_randr_notify_event_t *ev; + Ecore_X_Event_Randr_Output_Change *e; +#endif + +#ifdef ECORE_XCB_RANDR + ev = (xcb_randr_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Randr_Crtc_Change)))) + return; + + e->win = ev->u.oc.window; + e->output = ev->u.oc.output; + e->crtc = ev->u.oc.crtc; + e->mode = ev->u.oc.mode; + e->orientation = ev->u.oc.rotation; + e->connection = ev->u.oc.connection; + e->subpixel_order = ev->u.oc.subpixel_order; + + ecore_event_add(ECORE_X_EVENT_RANDR_OUTPUT_CHANGE, e, NULL, NULL); +#endif +} + +static void +_ecore_xcb_event_handle_randr_output_property_change(xcb_generic_event_t *event) +{ +#ifdef ECORE_XCB_RANDR + xcb_randr_notify_event_t *ev; + Ecore_X_Event_Randr_Output_Property_Notify *e; +#endif + +#ifdef ECORE_XCB_RANDR + ev = (xcb_randr_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Randr_Output_Property_Notify)))) + return; + + e->win = ev->u.op.window; + e->output = ev->u.op.output; + e->property = ev->u.op.atom; + e->time = ev->u.op.timestamp; + if (ev->u.op.status == XCB_PROPERTY_NEW_VALUE) + e->state = ECORE_X_RANDR_PROPERTY_CHANGE_ADD; + else + e->state = ECORE_X_RANDR_PROPERTY_CHANGE_DEL; + + ecore_event_add(ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY, e, NULL, NULL); +#endif +} + +static void +_ecore_xcb_event_handle_screensaver_notify(xcb_generic_event_t *event) +{ +#ifdef ECORE_XCB_SCREENSAVER + xcb_screensaver_notify_event_t *ev; + Ecore_X_Event_Screensaver_Notify *e; +#endif + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; +#ifdef ECORE_XCB_SCREENSAVER + ev = (xcb_screensaver_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Screensaver_Notify)))) return; + + e->win = ev->window; + e->on = EINA_FALSE; + if ((ev->state == XCB_SCREENSAVER_STATE_ON) || + (ev->state == XCB_SCREENSAVER_STATE_CYCLE)) e->on = EINA_TRUE; + e->time = ev->time; + + ecore_event_add(ECORE_X_EVENT_SCREENSAVER_NOTIFY, e, NULL, NULL); +#endif +} + +#ifdef ECORE_XCB_XGESTURE +static void +_ecore_xcb_event_handle_gesture_notify_flick(xcb_generic_event_t *event) +{ + xcb_gesture_notify_flick_event_t *ev; + Ecore_X_Event_Gesture_Notify_Flick *e; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + fprintf(stderr, "[ECORE_XCB][%s]...\n", __FUNCTION__); + + ev = (xcb_gesture_notify_flick_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_Flick)))) return; + + e->win = ev->window; + e->time = ev->time; + e->subtype = ev->kind; + e->num_fingers = ev->num_finger; + e->distance = ev->distance; + e->duration = ev->duration; + e->direction = ev->direction; + e->angle = XFixedToDouble(ev->angle); + + ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_FLICK, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_gesture_notify_pan(xcb_generic_event_t *event) +{ + xcb_gesture_notify_pan_event_t *ev; + Ecore_X_Event_Gesture_Notify_Pan *e; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + fprintf(stderr, "[ECORE_XCB][%s]...\n", __FUNCTION__); + + ev = (xcb_gesture_notify_pan_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_Pan)))) return; + + e->win = ev->window; + e->time = ev->time; + e->subtype = ev->kind; + e->num_fingers = ev->num_finger; + e->dx = ev->dx; + e->dy = ev->dy; + e->distance = ev->distance; + e->duration = ev->duration; + e->direction = ev->direction; + + ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_PAN, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_gesture_notify_pinchrotation(xcb_generic_event_t *event) +{ + xcb_gesture_notify_pinch_rotation_event_t *ev; + Ecore_X_Event_Gesture_Notify_PinchRotation *e; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + fprintf(stderr, "[ECORE_XCB][%s]...\n", __FUNCTION__); + + ev = (xcb_gesture_notify_pinch_rotation_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_PinchRotation)))) return; + + e->win = ev->window; + e->time = ev->time; + e->subtype = ev->kind; + e->num_fingers = ev->num_finger; + e->distance = ev->distance; + e->cx = ev->cx; + e->cy = ev->cy; + e->zoom = XFixedToDouble(ev->zoom); + e->angle = XFixedToDouble(ev->angle); + + ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_PINCHROTATION, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_gesture_notify_tap(xcb_generic_event_t *event) +{ + xcb_gesture_notify_tap_event_t *ev; + Ecore_X_Event_Gesture_Notify_Tap *e; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + fprintf(stderr, "[ECORE_XCB][%s]...\n", __FUNCTION__); + + ev = (xcb_gesture_notify_tap_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_Tap)))) return; + + e->win = ev->window; + e->time = ev->time; + e->subtype = ev->kind; + e->num_fingers = ev->num_finger; + e->cx = ev->cx; + e->cy = ev->cy; + e->tap_repeat = ev->tap_repeat; + e->interval = ev->interval; + + ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_TAP, e, NULL, NULL); +} + +static void +_ecore_xcb_event_handle_gesture_notify_tapnhold(xcb_generic_event_t *event) +{ + xcb_gesture_notify_tap_n_hold_event_t *ev; + Ecore_X_Event_Gesture_Notify_TapNHold *e; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + fprintf(stderr, "[ECORE_XCB][%s]...\n", __FUNCTION__); + + ev = (xcb_gesture_notify_tap_n_hold_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_TapNHold)))) return; + + e->win = ev->window; + e->time = ev->time; + e->subtype = ev->kind; + e->num_fingers = ev->num_finger; + e->cx = ev->cx; + e->cy = ev->cy; + e->interval = ev->interval; + e->hold_time = ev->holdtime; + + ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_TAPNHOLD, e, NULL, NULL); +} + +static void + _ecore_xcb_event_handle_gesture_notify_hold(xcb_generic_event_t *event) +{ + xcb_gesture_notify_hold_event_t *ev; + Ecore_X_Event_Gesture_Notify_Hold *e; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + fprintf(stderr, "[ECORE_XCB][%s]...\n", __FUNCTION__); + + ev = (xcb_gesture_notify_hold_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_Hold)))) return; + + e->win = ev->window; + e->time = ev->time; + e->subtype = ev->kind; + e->num_fingers = ev->num_finger; + e->cx = ev->cx; + e->cy = ev->cy; + e->hold_time = ev->holdtime; + + ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_HOLD, e, NULL, NULL); +} + +static void + _ecore_xcb_event_handle_gesture_notify_group(xcb_generic_event_t *event) +{ + xcb_gesture_notify_group_event_t *ev; + Ecore_X_Event_Gesture_Notify_Group *e; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + fprintf(stderr, "[ECORE_XCB][%s]...\n", __FUNCTION__); + + ev = (xcb_gesture_notify_group_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_Group)))) return; + + e->win = ev->window; + e->time = ev->time; + e->subtype = ev->kind; + e->num_groups = ev->num_group; + e->group_id = ev->groupid; + + ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_GROUP, e, NULL, NULL); +} +#endif + +#ifdef ECORE_XCB_SHAPE +static void +_ecore_xcb_event_handle_shape_change(xcb_generic_event_t *event) +{ + xcb_shape_notify_event_t *ev; + Ecore_X_Event_Window_Shape *e; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + ev = (xcb_shape_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Shape)))) return; + + e->win = ev->affected_window; + e->time = ev->server_time; + switch (ev->shape_kind) + { + case XCB_SHAPE_SK_BOUNDING: + e->type = ECORE_X_SHAPE_BOUNDING; + break; + + case XCB_SHAPE_SK_CLIP: + e->type = ECORE_X_SHAPE_CLIP; + break; + + case XCB_SHAPE_SK_INPUT: + e->type = ECORE_X_SHAPE_INPUT; + break; + + default: + break; + } + e->x = ev->extents_x; + e->y = ev->extents_y; + e->w = ev->extents_width; + e->h = ev->extents_height; + e->shaped = ev->shaped; + + ecore_event_add(ECORE_X_EVENT_WINDOW_SHAPE, e, NULL, NULL); +} + +#endif + +static void +_ecore_xcb_event_handle_sync_counter(xcb_generic_event_t *event) +{ +#ifdef ECORE_XCB_SYNC + xcb_sync_counter_notify_event_t *ev; + Ecore_X_Event_Sync_Counter *e; +#endif + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + +#ifdef ECORE_XCB_SYNC + ev = (xcb_sync_counter_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Sync_Counter)))) return; + + e->time = ev->timestamp; + + ecore_event_add(ECORE_X_EVENT_SYNC_COUNTER, e, NULL, NULL); +#endif +} + +static void +_ecore_xcb_event_handle_sync_alarm(xcb_generic_event_t *event) +{ +#ifdef ECORE_XCB_SYNC + xcb_sync_alarm_notify_event_t *ev; + Ecore_X_Event_Sync_Alarm *e; +#endif + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; +#ifdef ECORE_XCB_SYNC + ev = (xcb_sync_alarm_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Sync_Alarm)))) return; + + e->time = ev->timestamp; + e->alarm = ev->alarm; + + ecore_event_add(ECORE_X_EVENT_SYNC_ALARM, e, NULL, NULL); +#endif +} + +static void +_ecore_xcb_event_handle_xfixes_selection_notify(xcb_generic_event_t *event) +{ +#ifdef ECORE_XCB_XFIXES + Ecore_X_Event_Fixes_Selection_Notify *e; + Ecore_X_Atom sel; + xcb_xfixes_selection_notify_event_t *ev; +#endif + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; +#ifdef ECORE_XCB_XFIXES + ev = (xcb_xfixes_selection_notify_event_t *)event; + + if (!(e = calloc(1, sizeof(*e)))) return; + + e->win = ev->window; + e->owner = ev->owner; + e->time = ev->timestamp; + e->selection_time = ev->selection_timestamp; + e->atom = sel = ev->selection; + if (sel == ECORE_X_ATOM_SELECTION_PRIMARY) + e->selection = ECORE_X_SELECTION_PRIMARY; + else if (sel == ECORE_X_ATOM_SELECTION_SECONDARY) + e->selection = ECORE_X_SELECTION_SECONDARY; + else if (sel == ECORE_X_ATOM_SELECTION_CLIPBOARD) + e->selection = ECORE_X_SELECTION_CLIPBOARD; + else + e->selection = ECORE_X_SELECTION_OTHER; + e->reason = ev->subtype; + + ecore_event_add(ECORE_X_EVENT_FIXES_SELECTION_NOTIFY, e, NULL, NULL); +#endif +} + +static void +_ecore_xcb_event_handle_xfixes_cursor_notify(xcb_generic_event_t *event __UNUSED__) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); +// FIXME: TBD +} + +static void +_ecore_xcb_event_handle_generic_event(xcb_generic_event_t *event) +{ + xcb_ge_event_t *ev; + Ecore_X_Event_Generic *e; + + ev = (xcb_ge_event_t *)event; + + /* pad0 *IS* extension - bug in xcb */ + if (ev->pad0 == _ecore_xcb_event_input) + { + _ecore_xcb_event_handle_input_event(event); +// FIXME: should we generate generic events as WELL as input events? +// return; + } + + if (!(e = calloc(1, sizeof(Ecore_X_Event_Generic)))) + return; + + DBG("Handle Generic Event: %d", ev->event_type); + + e->cookie = ev->sequence; + /* NB: These are bugs in xcb ge_event structure. The struct should have a + * field for extension & data, but does not. + * + * XCB people have been notified of this issue */ + e->extension = ev->pad0; + /* e->data = ev->pad1; */ + if (ev->length > 0) + { + int len = ev->length * sizeof(int); + e->data = malloc(len); + if (e->data) memcpy(e->data, &(event[1]), len); + } + + e->evtype = ev->event_type; + + ecore_event_add(ECORE_X_EVENT_GENERIC, e, + _ecore_xcb_event_generic_event_free, e->data); +} + +static void +_ecore_xcb_event_handle_input_event(xcb_generic_event_t *event) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_xcb_input_handle_event(event); +} + +static void +_ecore_xcb_event_key_press(xcb_generic_event_t *event) +{ + Ecore_Event_Key *e; + xcb_keysym_t sym = XCB_NO_SYMBOL; + xcb_keycode_t keycode = 0; + xcb_key_press_event_t *xevent; + char *keyname = NULL, *key = NULL; + char *compose = NULL; + char compose_buffer[256]; + int val = 0; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + + xevent = (xcb_key_press_event_t *)event; + keycode = xevent->detail; + + sym = _ecore_xcb_keymap_keycode_to_keysym(keycode, xevent->state); + keyname = _ecore_xcb_keymap_keysym_to_string(sym); + if (!keyname) + { + char buff[256]; + + snprintf(buff, sizeof(buff), "Keycode-%i", keycode); + keyname = buff; + } + + val = + _ecore_xcb_keymap_lookup_string(keycode, xevent->state, compose_buffer, + sizeof(compose_buffer), &sym); + if (val > 0) + { + compose_buffer[val] = 0; + compose = + eina_str_convert(nl_langinfo(CODESET), "UTF-8", compose_buffer); + if (!compose) + ERR("Ecore_X cannot convert input key string '%s' to UTF-8. " + "Is Eina built with iconv support?", compose_buffer); + } + + key = _ecore_xcb_keymap_keysym_to_string(sym); + if (!key) key = keyname; + + e = malloc(sizeof(Ecore_Event_Key) + strlen(key) + strlen(keyname) + + (compose ? strlen(compose) : 0) + 3); + if (e) + { + e->keyname = (char *)(e + 1); + e->key = e->keyname + strlen(keyname) + 1; + + e->compose = NULL; + if (compose) e->compose = (e->key + strlen(key) + 1); + e->string = e->compose; + + strcpy((char *)e->keyname, keyname); + strcpy((char *)e->key, key); + if (compose) strcpy((char *)e->compose, compose); + + e->modifiers = _ecore_xcb_events_modifiers_get(xevent->state); + e->timestamp = xevent->time; + e->window = xevent->child ? xevent->child : xevent->event; + e->event_window = xevent->event; + e->same_screen = xevent->same_screen; + e->root_window = xevent->root; + + DBG("Sending Key Down Event: %s", e->keyname); + ecore_event_add(ECORE_EVENT_KEY_DOWN, e, NULL, NULL); + } + _ecore_xcb_event_last_time = xevent->time; +} + +static void +_ecore_xcb_event_key_release(xcb_generic_event_t *event) +{ + Ecore_Event_Key *e; + xcb_keysym_t sym = XCB_NO_SYMBOL; + xcb_keycode_t keycode = 0; + xcb_key_release_event_t *xevent; + char *keyname = NULL, *key = NULL; + char *compose = NULL; + char compose_buffer[256]; + int val = 0; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; + + xevent = (xcb_key_release_event_t *)event; + keycode = xevent->detail; + + sym = _ecore_xcb_keymap_keycode_to_keysym(keycode, xevent->state); + keyname = _ecore_xcb_keymap_keysym_to_string(sym); + if (!keyname) + { + char buff[256]; + + snprintf(buff, sizeof(buff), "Keycode-%i", keycode); + keyname = buff; + } + + val = + _ecore_xcb_keymap_lookup_string(keycode, xevent->state, compose_buffer, + sizeof(compose_buffer), &sym); + if (val > 0) + { + compose_buffer[val] = 0; + compose = + eina_str_convert(nl_langinfo(CODESET), "UTF-8", compose_buffer); +// tmp = compose; + } + + key = _ecore_xcb_keymap_keysym_to_string(sym); + if (!key) key = keyname; + + e = malloc(sizeof(Ecore_Event_Key) + strlen(key) + strlen(keyname) + + (compose ? strlen(compose) : 0) + 3); + if (e) + { + e->keyname = (char *)(e + 1); + e->key = e->keyname + strlen(keyname) + 1; + + e->compose = NULL; + if (compose) e->compose = (e->key + strlen(key) + 1); + e->string = e->compose; + + strcpy((char *)e->keyname, keyname); + strcpy((char *)e->key, key); + if (compose) strcpy((char *)e->compose, compose); + + e->modifiers = _ecore_xcb_events_modifiers_get(xevent->state); + e->timestamp = xevent->time; + e->window = xevent->child ? xevent->child : xevent->event; + e->event_window = xevent->event; + e->same_screen = xevent->same_screen; + e->root_window = xevent->root; + + ecore_event_add(ECORE_EVENT_KEY_UP, e, NULL, NULL); + } + _ecore_xcb_event_last_time = xevent->time; +} + +void +_ecore_xcb_event_mouse_move(uint16_t timestamp, + uint16_t modifiers, + int16_t x, + int16_t y, + int16_t root_x, + int16_t root_y, + xcb_window_t event_win, + xcb_window_t win, + xcb_window_t root_win, + uint8_t same_screen, + int dev, + double radx, + double rady, + double pressure, + double angle, + int16_t mx, + int16_t my, + int16_t mrx, + int16_t mry) +{ + Ecore_Event_Mouse_Move *e; + Ecore_Event *event; + + if (!(e = malloc(sizeof(Ecore_Event_Mouse_Move)))) return; + + e->window = win; + e->root_window = root_win; + e->timestamp = timestamp; + e->same_screen = same_screen; + e->event_window = event_win; + e->modifiers = _ecore_xcb_events_modifiers_get(modifiers); + e->x = x; + e->y = y; + e->root.x = root_x; + e->root.y = root_y; + e->multi.device = dev; + e->multi.radius = ((radx + rady) / 2); + e->multi.radius_x = radx; + e->multi.radius_y = rady; + e->multi.pressure = pressure; + e->multi.angle = angle; + e->multi.x = mx; + e->multi.y = my; + e->multi.root.x = mrx; + e->multi.root.y = mry; + + event = ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, + _ecore_xcb_event_mouse_move_free, NULL); + + _ecore_xcb_event_last_time = e->timestamp; + _ecore_xcb_event_last_window = e->window; + _ecore_xcb_event_last_root_x = root_x; + _ecore_xcb_event_last_root_y = root_y; +// _ecore_xcb_event_last_mouse_move_event = event; +} + +static void +_ecore_xcb_event_mouse_move_free(void *data __UNUSED__, + void *event) +{ + Ecore_Event_Mouse_Move *ev; + + ev = event; +// if (_ecore_xcb_event_last_mouse_move_event) +// { +// _ecore_xcb_event_last_mouse_move = EINA_FALSE; +// _ecore_xcb_event_last_mouse_move_event = NULL; +// } + if (ev) free(ev); +} + +Ecore_Event_Mouse_Button * +_ecore_xcb_event_mouse_button(int event, + uint16_t timestamp, + uint16_t modifiers, + xcb_button_t buttons, + int16_t x, + int16_t y, + int16_t root_x, + int16_t root_y, + xcb_window_t event_win, + xcb_window_t win, + xcb_window_t root_win, + uint8_t same_screen, + int dev, + double radx, + double rady, + double pressure, + double angle, + int16_t mx, + int16_t my, + int16_t mrx, + int16_t mry) +{ + Ecore_Event_Mouse_Button *e; + Ecore_X_Mouse_Down_Info *info = NULL; + + if (!(e = malloc(sizeof(Ecore_Event_Mouse_Button)))) return NULL; + + e->window = win; + e->root_window = root_win; + e->timestamp = timestamp; + e->same_screen = same_screen; + e->event_window = event_win; + e->buttons = buttons; + e->modifiers = _ecore_xcb_events_modifiers_get(modifiers); + e->double_click = 0; + e->triple_click = 0; + e->x = x; + e->y = y; + e->root.x = root_x; + e->root.y = root_y; + + if ((info = _ecore_xcb_event_mouse_down_info_get(dev))) + { + if ((event == ECORE_EVENT_MOUSE_BUTTON_DOWN) && + (info->did_triple)) + { + info->last_win = 0; + info->last_last_win = 0; + info->last_event_win = 0; + info->last_time = 0; + info->last_last_time = 0; + } + if (event_win == win) + { + if (event == ECORE_EVENT_MOUSE_BUTTON_DOWN) + { + if (((int)(timestamp - info->last_time) <= + (int)(1000 * _ecore_xcb_double_click_time)) && + (win == info->last_win) && + (event_win == info->last_event_win)) + { + e->double_click = 1; + info->did_double = EINA_TRUE; + } + else + { + info->did_double = EINA_FALSE; + info->did_triple = EINA_FALSE; + } + if (((int)(timestamp - info->last_last_time) <= + (int)(2 * 1000 * _ecore_xcb_double_click_time)) && + (win == info->last_win) && + (win == info->last_last_win) && + (event_win == info->last_event_win) && + (event_win == info->last_last_event_win)) + { + e->triple_click = 1; + info->did_triple = EINA_TRUE; + } + else + info->did_triple = EINA_FALSE; + } + else + { + if (info->did_double) e->double_click = 1; + if (info->did_triple) e->triple_click = 1; + } + } + } + + /* NB: Comment out right now because _ecore_xcb_mouse_up_count is + * only used here...nowhere else in the code */ + + /* if ((event == ECORE_EVENT_MOUSE_BUTTON_DOWN) && */ + /* (!e->double_click) && (!e->triple_click)) */ + /* _ecore_xcb_mouse_up_count = 0; */ + + e->multi.device = dev; + e->multi.radius = ((radx + rady) / 2); + e->multi.radius_x = radx; + e->multi.radius_y = rady; + e->multi.pressure = pressure; + e->multi.angle = angle; + e->multi.x = mx; + e->multi.y = my; + e->multi.root.x = mrx; + e->multi.root.y = mry; + + _ecore_xcb_event_last_time = e->timestamp; + _ecore_xcb_event_last_window = e->window; + _ecore_xcb_event_last_root_x = root_x; + _ecore_xcb_event_last_root_y = root_y; + + ecore_event_add(event, e, NULL, NULL); + + if ((info) && (event == ECORE_EVENT_MOUSE_BUTTON_DOWN) && + (win == event_win) && (!info->did_triple)) + { + info->last_last_win = info->last_win; + info->last_win = win; + info->last_last_event_win = info->last_event_win; + info->last_event_win = event_win; + info->last_last_time = info->last_time; + info->last_time = timestamp; + } + + return e; +} + +static Ecore_X_Event_Mode +_ecore_xcb_event_mode_get(uint8_t mode) +{ + switch (mode) + { + case XCB_NOTIFY_MODE_NORMAL: + return ECORE_X_EVENT_MODE_NORMAL; + + case XCB_NOTIFY_MODE_WHILE_GRABBED: + return ECORE_X_EVENT_MODE_WHILE_GRABBED; + + case XCB_NOTIFY_MODE_GRAB: + return ECORE_X_EVENT_MODE_GRAB; + + case XCB_NOTIFY_MODE_UNGRAB: + return ECORE_X_EVENT_MODE_UNGRAB; + + default: + return ECORE_X_EVENT_MODE_NORMAL; + } +} + +static Ecore_X_Event_Detail +_ecore_xcb_event_detail_get(uint8_t detail) +{ + switch (detail) + { + case XCB_NOTIFY_DETAIL_ANCESTOR: + return ECORE_X_EVENT_DETAIL_ANCESTOR; + + case XCB_NOTIFY_DETAIL_VIRTUAL: + return ECORE_X_EVENT_DETAIL_VIRTUAL; + + case XCB_NOTIFY_DETAIL_INFERIOR: + return ECORE_X_EVENT_DETAIL_INFERIOR; + + case XCB_NOTIFY_DETAIL_NONLINEAR: + return ECORE_X_EVENT_DETAIL_NON_LINEAR; + + case XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL: + return ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL; + + case XCB_NOTIFY_DETAIL_POINTER: + return ECORE_X_EVENT_DETAIL_POINTER; + + case XCB_NOTIFY_DETAIL_POINTER_ROOT: + return ECORE_X_EVENT_DETAIL_POINTER_ROOT; + + case XCB_NOTIFY_DETAIL_NONE: + default: + return ECORE_X_EVENT_DETAIL_ANCESTOR; + } +} + +static void +_ecore_xcb_event_xdnd_enter_free(void *data __UNUSED__, + void *event) +{ + Ecore_X_Event_Xdnd_Enter *e; + int i = 0; + + e = event; + for (i = 0; i < e->num_types; i++) + free(e->types[i]); + free(e->types); + free(e); +} + +static void +_ecore_xcb_event_selection_notify_free(void *data __UNUSED__, + void *event) +{ + Ecore_X_Event_Selection_Notify *e; + Ecore_X_Selection_Data *sel; + + e = event; + if (!(sel = e->data)) return; + if (sel->free) sel->free(sel); + free(e->target); + free(e); +} + +static void +_ecore_xcb_event_generic_event_free(void *data, + void *event) +{ + Ecore_X_Event_Generic *e; + + e = (Ecore_X_Event_Generic *)event; + if (e->data) free(data); + free(e); +} + +static void +_ecore_xcb_event_mouse_down_info_clear(void) +{ + Eina_Inlist *l; + Ecore_X_Mouse_Down_Info *info = NULL; + + l = _ecore_xcb_mouse_down_info_list; + while (l) + { + info = EINA_INLIST_CONTAINER_GET(l, Ecore_X_Mouse_Down_Info); + l = eina_inlist_remove(l, l); + free(info); + } + _ecore_xcb_mouse_down_info_list = NULL; +} + +static Ecore_X_Mouse_Down_Info * +_ecore_xcb_event_mouse_down_info_get(int dev) +{ + Eina_Inlist *l; + Ecore_X_Mouse_Down_Info *info = NULL; + + l = _ecore_xcb_mouse_down_info_list; + EINA_INLIST_FOREACH(l, info) + if (info->dev == dev) return info; + + if (!(info = calloc(1, sizeof(Ecore_X_Mouse_Down_Info)))) return NULL; + + info->dev = dev; + l = eina_inlist_append(l, (Eina_Inlist *)info); + _ecore_xcb_mouse_down_info_list = l; + + return info; +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_extensions.c b/src/lib/ecore_x/xcb/ecore_xcb_extensions.c new file mode 100644 index 0000000..40c10ac --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_extensions.c @@ -0,0 +1,148 @@ +#include "ecore_xcb_private.h" + +void +_ecore_xcb_extensions_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_big_requests_id); + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_shm_id); + +#ifdef ECORE_XCB_SHAPE + _ecore_xcb_shape_init(); +#endif + +#ifdef ECORE_XCB_SCREENSAVER + _ecore_xcb_screensaver_init(); +#endif + +#ifdef ECORE_XCB_SYNC + _ecore_xcb_sync_init(); +#endif + +#ifdef ECORE_XCB_RANDR + _ecore_xcb_randr_init(); +#endif + +#ifdef ECORE_XCB_XFIXES + _ecore_xcb_xfixes_init(); +#endif + +#ifdef ECORE_XCB_DAMAGE + _ecore_xcb_damage_init(); +#endif + +#ifdef ECORE_XCB_RENDER + _ecore_xcb_render_init(); +#endif + +#ifdef ECORE_XCB_COMPOSITE + _ecore_xcb_composite_init(); +#endif + +#ifdef ECORE_XCB_DPMS + _ecore_xcb_dpms_init(); +#endif + +#ifdef ECORE_XCB_DPMS + _ecore_xcb_dpms_init(); +#endif + +#ifdef ECORE_XCB_CURSOR + _ecore_xcb_cursor_init(); +#endif + +#ifdef ECORE_XCB_XINERAMA + _ecore_xcb_xinerama_init(); +#endif + +#ifdef ECORE_XCB_XINPUT + _ecore_xcb_input_init(); +#endif + +#ifdef ECORE_XCB_GESTURE + _ecore_xcb_gesture_init(); +#endif + +/* #ifdef ECORE_XCB_DRI */ +/* _ecore_xcb_dri_init(); */ +/* #endif */ + +#ifdef ECORE_XCB_XTEST + _ecore_xcb_xtest_init(); +#endif + + xcb_prefetch_maximum_request_length(_ecore_xcb_conn); +} + +void +_ecore_xcb_extensions_finalize(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + xcb_get_extension_data(_ecore_xcb_conn, &xcb_big_requests_id); + xcb_get_extension_data(_ecore_xcb_conn, &xcb_shm_id); + +#ifdef ECORE_XCB_SHAPE + _ecore_xcb_shape_finalize(); +#endif + +#ifdef ECORE_XCB_SCREENSAVER + _ecore_xcb_screensaver_finalize(); +#endif + +#ifdef ECORE_XCB_SYNC + _ecore_xcb_sync_finalize(); +#endif + +#ifdef ECORE_XCB_RANDR + _ecore_xcb_randr_finalize(); +#endif + +#ifdef ECORE_XCB_XFIXES + _ecore_xcb_xfixes_finalize(); +#endif + +#ifdef ECORE_XCB_DAMAGE + _ecore_xcb_damage_finalize(); +#endif + +#ifdef ECORE_XCB_RENDER + _ecore_xcb_render_finalize(); +#endif + +#ifdef ECORE_XCB_COMPOSITE + _ecore_xcb_composite_finalize(); +#endif + +#ifdef ECORE_XCB_DPMS + _ecore_xcb_dpms_finalize(); +#endif + +#ifdef ECORE_XCB_CURSOR + _ecore_xcb_cursor_finalize(); +#endif + +#ifdef ECORE_XCB_XINERAMA + _ecore_xcb_xinerama_finalize(); +#endif + +#ifdef ECORE_XCB_XINPUT + _ecore_xcb_input_finalize(); +#endif + +#ifdef ECORE_XCB_GESTURE + _ecore_xcb_gesture_finalize(); +#endif + +/* #ifdef ECORE_XCB_DRI */ +/* _ecore_xcb_dri_finalize(); */ +/* #endif */ + +#ifdef ECORE_XCB_XTEST + _ecore_xcb_xtest_finalize(); +#endif + + xcb_get_maximum_request_length(_ecore_xcb_conn); +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_gc.c b/src/lib/ecore_x/xcb/ecore_xcb_gc.c new file mode 100644 index 0000000..d811b54 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_gc.c @@ -0,0 +1,173 @@ +#include "ecore_xcb_private.h" + +/** + * Creates a new default graphics context associated with the given + * drawable. + * @param draw Drawable to create graphics context with. If @c 0 is + * given instead, the default root window is used. + * @param value_mask Bitmask values. + * @param value_list List of values. The order of values must be the + * same than the corresponding bitmaks. + * @return The new default graphics context. + */ +EAPI Ecore_X_GC +ecore_x_gc_new(Ecore_X_Drawable drawable, + Ecore_X_GC_Value_Mask value_mask, + const unsigned int *value_list) +{ + xcb_gcontext_t gc; + uint32_t vmask = 0; + int i = 0, mask = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!drawable) drawable = ((xcb_screen_t *)_ecore_xcb_screen)->root; + + for (i = 0, mask = 1; i <= 22; i++, mask <<= 1) + { + switch (mask & value_mask) + { + case ECORE_X_GC_VALUE_MASK_FUNCTION: + vmask |= XCB_GC_FUNCTION; + break; + + case ECORE_X_GC_VALUE_MASK_PLANE_MASK: + vmask |= XCB_GC_PLANE_MASK; + break; + + case ECORE_X_GC_VALUE_MASK_FOREGROUND: + vmask |= XCB_GC_FOREGROUND; + break; + + case ECORE_X_GC_VALUE_MASK_BACKGROUND: + vmask |= XCB_GC_BACKGROUND; + break; + + case ECORE_X_GC_VALUE_MASK_LINE_WIDTH: + vmask |= XCB_GC_LINE_WIDTH; + break; + + case ECORE_X_GC_VALUE_MASK_LINE_STYLE: + vmask |= XCB_GC_LINE_STYLE; + break; + + case ECORE_X_GC_VALUE_MASK_CAP_STYLE: + vmask |= XCB_GC_CAP_STYLE; + break; + + case ECORE_X_GC_VALUE_MASK_JOIN_STYLE: + vmask |= XCB_GC_JOIN_STYLE; + break; + + case ECORE_X_GC_VALUE_MASK_FILL_STYLE: + vmask |= XCB_GC_FILL_STYLE; + break; + + case ECORE_X_GC_VALUE_MASK_FILL_RULE: + vmask |= XCB_GC_FILL_RULE; + break; + + case ECORE_X_GC_VALUE_MASK_TILE: + vmask |= XCB_GC_TILE; + break; + + case ECORE_X_GC_VALUE_MASK_STIPPLE: + vmask |= XCB_GC_STIPPLE; + break; + + case ECORE_X_GC_VALUE_MASK_TILE_STIPPLE_ORIGIN_X: + vmask |= XCB_GC_TILE_STIPPLE_ORIGIN_X; + break; + + case ECORE_X_GC_VALUE_MASK_TILE_STIPPLE_ORIGIN_Y: + vmask |= XCB_GC_TILE_STIPPLE_ORIGIN_Y; + break; + + case ECORE_X_GC_VALUE_MASK_FONT: + vmask |= XCB_GC_FONT; + break; + + case ECORE_X_GC_VALUE_MASK_SUBWINDOW_MODE: + vmask |= XCB_GC_SUBWINDOW_MODE; + break; + + case ECORE_X_GC_VALUE_MASK_GRAPHICS_EXPOSURES: + vmask |= XCB_GC_GRAPHICS_EXPOSURES; + break; + + case ECORE_X_GC_VALUE_MASK_CLIP_ORIGIN_X: + vmask |= XCB_GC_CLIP_ORIGIN_X; + break; + + case ECORE_X_GC_VALUE_MASK_CLIP_ORIGIN_Y: + vmask |= XCB_GC_CLIP_ORIGIN_Y; + break; + + case ECORE_X_GC_VALUE_MASK_CLIP_MASK: + vmask |= XCB_GC_CLIP_MASK; + break; + + case ECORE_X_GC_VALUE_MASK_DASH_OFFSET: + vmask |= XCB_GC_DASH_OFFSET; + break; + + case ECORE_X_GC_VALUE_MASK_DASH_LIST: + vmask |= XCB_GC_DASH_LIST; + break; + + case ECORE_X_GC_VALUE_MASK_ARC_MODE: + vmask |= XCB_GC_ARC_MODE; + break; + } + } + + gc = xcb_generate_id(_ecore_xcb_conn); + xcb_create_gc(_ecore_xcb_conn, gc, drawable, vmask, value_list); + +// ecore_x_flush(); + return gc; +} + +/** + * Deletes and frees the given graphics context. + * @param gc The given graphics context. + */ +EAPI void +ecore_x_gc_free(Ecore_X_GC gc) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_free_gc(_ecore_xcb_conn, gc); +// ecore_x_flush(); +} + +EAPI void +ecore_x_gc_foreground_set(Ecore_X_GC gc, + unsigned long foreground) +{ + uint32_t list; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + list = foreground; + xcb_change_gc(_ecore_xcb_conn, gc, XCB_GC_FOREGROUND, &list); +// ecore_x_flush(); +} + +EAPI void +ecore_x_gc_background_set(Ecore_X_GC gc, + unsigned long background) +{ + uint32_t list; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + list = background; + xcb_change_gc(_ecore_xcb_conn, gc, XCB_GC_BACKGROUND, &list); +// ecore_x_flush(); +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_gesture.c b/src/lib/ecore_x/xcb/ecore_xcb_gesture.c new file mode 100644 index 0000000..263dade --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_gesture.c @@ -0,0 +1,203 @@ +#include "ecore_xcb_private.h" +#ifdef ECORE_XCB_XGESTURE +# include +# include +#endif + +/* local variables */ +static Eina_Bool _gesture_available = EINA_FALSE; + +/* external variables */ +int _ecore_xcb_event_gesture = -1; + +void +_ecore_xcb_gesture_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_XGESTURE + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_gesture_id); +#endif +} + +void +_ecore_xcb_gesture_finalize(void) +{ +#ifdef ECORE_XCB_XGESTURE + xcb_gesture_query_version_cookie_t cookie; + xcb_gesture_query_version_reply_t *reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_XGESTURE + cookie = + xcb_gesture_query_version_unchecked(_ecore_xcb_conn); + reply = + xcb_gesture_query_version_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + _gesture_available = EINA_TRUE; + free(reply); + } + + if (_gesture_available) + { + const xcb_query_extension_reply_t *ext_reply; + + ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_gesture_id); + if (ext_reply) + _ecore_xcb_event_gesture = ext_reply->first_event; + } +#endif +} + +void +_ecore_xcb_gesture_shutdown(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); +} + +EAPI Eina_Bool +ecore_x_gesture_supported(void) +{ + return _gesture_available; +} + +#ifdef ECORE_XCB_XGESTURE +EAPI Eina_Bool +ecore_x_gesture_events_select(Ecore_X_Window win, + Ecore_X_Gesture_Event_Mask mask) +#else +EAPI Eina_Bool +ecore_x_gesture_events_select(Ecore_X_Window win __UNUSED__, + Ecore_X_Gesture_Event_Mask mask __UNUSED__) +#endif + +{ +#ifdef ECORE_XCB_XGESTURE + if (!_gesture_available) return EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN + + xcb_gesture_select_events(_ecore_xcb_conn, win, mask); + + return EINA_TRUE; +#else + return EINA_FALSE; +#endif +} + +#ifdef ECORE_XCB_XGESTURE +EAPI Ecore_X_Gesture_Event_Mask +ecore_x_gesture_events_selected_get(Ecore_X_Window win) +#else +EAPI Ecore_X_Gesture_Event_Mask +ecore_x_gesture_events_selected_get(Ecore_X_Window win __UNUSED__) +#endif +{ +#ifdef ECORE_XCB_XGESTURE + xcb_gesture_get_selected_events_cookie_t ecookie; + xcb_gesture_get_selected_events_reply_t *ereply; + Ecore_X_Gesture_Event_Mask mask = ECORE_X_GESTURE_EVENT_MASK_NONE; + + if (!_gesture_available) return mask; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN + + ecookie = xcb_gesture_get_selected_events(_ecore_xcb_conn, win); + ereply = + xcb_gesture_get_selected_events_reply(_ecore_xcb_conn, ecookie, NULL); + if (ereply) + { + mask = ereply->mask; + free(ereply); + } + + return mask; +#else + return ECORE_X_GESTURE_EVENT_MASK_NONE; +#endif +} + +#ifdef ECORE_XCB_XGESTURE +EAPI Eina_Bool +ecore_x_gesture_event_grab(Ecore_X_Window win, + Ecore_X_Gesture_Event_Type type, + int num_fingers) +#else +EAPI Eina_Bool +ecore_x_gesture_event_grab(Ecore_X_Window win __UNUSED__, + Ecore_X_Gesture_Event_Type type __UNUSED__, + int num_fingers __UNUSED__) +#endif +{ +#ifdef ECORE_XCB_XGESTURE + Eina_Bool status = EINA_TRUE; + xcb_gesture_grab_event_cookie_t ecookie; + xcb_gesture_grab_event_reply_t *ereply; + + if (!_gesture_available) return EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN + + ecookie = + xcb_gesture_grab_event(_ecore_xcb_conn, win, type, num_fingers, 0L); + ereply = xcb_gesture_grab_event_reply(_ecore_xcb_conn, ecookie, NULL); + + if (ereply) + { + if (ereply->status) status = EINA_FALSE; + free(ereply); + } + else + status = EINA_FALSE; + + return status; +#else + return EINA_FALSE; +#endif +} + +#ifdef ECORE_XCB_XGESTURE +EAPI Eina_Bool +ecore_x_gesture_event_ungrab(Ecore_X_Window win, + Ecore_X_Gesture_Event_Type type, + int num_fingers) +#else +EAPI Eina_Bool +ecore_x_gesture_event_ungrab(Ecore_X_Window win __UNUSED__, + Ecore_X_Gesture_Event_Type type __UNUSED__, + int num_fingers __UNUSED__) +#endif +{ +#ifdef ECORE_XCB_XGESTURE + Eina_Bool status = EINA_TRUE; + xcb_gesture_ungrab_event_cookie_t ecookie; + xcb_gesture_ungrab_event_reply_t *ereply; + + if (!_gesture_available) return EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN + + ecookie = + xcb_gesture_ungrab_event(_ecore_xcb_conn, win, type, num_fingers, 0L); + ereply = xcb_gesture_ungrab_event_reply(_ecore_xcb_conn, ecookie, NULL); + + if (ereply) + { + if (ereply->status) status = EINA_FALSE; + free(ereply); + } + else + status = EINA_FALSE; + + return status; +#else + return EINA_FALSE; +#endif +} diff --git a/src/lib/ecore_x/xcb/ecore_xcb_icccm.c b/src/lib/ecore_x/xcb/ecore_xcb_icccm.c new file mode 100644 index 0000000..8dea861 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_icccm.c @@ -0,0 +1,1569 @@ +#include "ecore_xcb_private.h" +#include + +EAPI void +ecore_x_icccm_init(void) +{ +} + +/** + * Sets the WM_COMMAND property for @a win. + * + * @param win The window. + * @param argc Number of arguments. + * @param argv Arguments. + */ +EAPI void +ecore_x_icccm_command_set(Ecore_X_Window win, + int argc, + char **argv) +{ + void *buf; + char *b; + int nbytes, i; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + for (i = 0, nbytes = 0; i < argc; i++) + if (argv[i]) nbytes += strlen(argv[i]) + 1; + + buf = malloc(sizeof(char) * nbytes); + if (!buf) return; + + b = (char *)buf; + for (i = 0; i < argc; i++) + { + if (argv[i]) + { + strcpy(b, argv[i]); + b += strlen(argv[i]) + 1; + } + else + *b++ = '\0'; + } + xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, + ECORE_X_ATOM_WM_COMMAND, ECORE_X_ATOM_STRING, 8, + nbytes, buf); + free(buf); +} + +/** + * Get the WM_COMMAND property for @a win. + * + * Return the command of a window. String must be free'd when done with. + * + * @param win The window. + * @param argc Number of arguments. + * @param argv Arguments. + */ +EAPI void +ecore_x_icccm_command_get(Ecore_X_Window win, + int *argc, + char ***argv) +{ + xcb_get_property_cookie_t cookie; + xcb_get_property_reply_t *reply; + int len = 0; + char **v, *data, *cp, *start; + int c = 0, i = 0, j = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (argc) *argc = 0; + if (argv) *argv = NULL; + + cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, win, + ECORE_X_ATOM_WM_COMMAND, + XCB_GET_PROPERTY_TYPE_ANY, + 0, 1000000L); + reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return; + + if ((reply->type != ECORE_X_ATOM_STRING) || (reply->format != 8)) + { + free(reply); + return; + } + + len = reply->value_len; + if (len < 1) + { + free(reply); + return; + } + + data = (char *)xcb_get_property_value(reply); + if (len && (data[len - 1] == '\0')) + len--; + + c = 1; + for (cp = (char *)data, i = len; i > 0; cp++, i--) + if (*cp == '\0') c++; + + v = (char **)malloc((c + 1) * sizeof(char *)); + if (!v) + { + free(reply); + return; + } + + start = (char *)malloc((len + 1) * sizeof(char)); + if (!start) + { + free(reply); + free(v); + return; + } + + memcpy(start, (char *)data, len); + start[len] = '\0'; + for (cp = start, i = len + 1, j = 0; i > 0; cp++, i--) + { + if (*cp == '\0') + { + v[j] = start; + start = (cp + 1); + j++; + } + } + + if (c < 1) + { + free(reply); + free(v); + return; + } + + if (argc) *argc = c; + + if (argv) + { + (*argv) = malloc(c * sizeof(char *)); + if (!*argv) + { + free(reply); + free(v); + if (argc) *argc = 0; + return; + } + + for (i = 0; i < c; i++) + { + if (v[i]) + (*argv)[i] = strdup(v[i]); + else + (*argv)[i] = strdup(""); + } + } + + free(reply); + free(v); +} + +EAPI char * +ecore_x_icccm_title_get(Ecore_X_Window win) +{ + xcb_get_property_cookie_t cookie; +#ifdef OLD_XCB_VERSION + xcb_get_text_property_reply_t prop; +#else + xcb_icccm_get_text_property_reply_t prop; +#endif + uint8_t ret = 0; + char *title = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!win) return NULL; +#ifdef OLD_XCB_VERSION + cookie = xcb_get_wm_name_unchecked(_ecore_xcb_conn, win); + ret = xcb_get_wm_name_reply(_ecore_xcb_conn, cookie, &prop, NULL); +#else + cookie = xcb_icccm_get_wm_name_unchecked(_ecore_xcb_conn, win); + ret = xcb_icccm_get_wm_name_reply(_ecore_xcb_conn, cookie, &prop, NULL); +#endif + if (ret == 0) return NULL; + if (prop.name_len < 1) + { +#ifdef OLD_XCB_VERSION + xcb_get_text_property_reply_wipe(&prop); +#else + xcb_icccm_get_text_property_reply_wipe(&prop); +#endif + return NULL; + } + + if (!(title = malloc((prop.name_len + 1) * sizeof(char *)))) + { +#ifdef OLD_XCB_VERSION + xcb_get_text_property_reply_wipe(&prop); +#else + xcb_icccm_get_text_property_reply_wipe(&prop); +#endif + return NULL; + } + memcpy(title, prop.name, sizeof(char *) * prop.name_len); + title[prop.name_len] = '\0'; + + if (prop.encoding != ECORE_X_ATOM_UTF8_STRING) + { + Ecore_Xcb_Textproperty tp; + int count = 0; + char **list = NULL; + Eina_Bool ret = EINA_FALSE; + + tp.value = strdup(title); + tp.nitems = prop.name_len; + tp.encoding = prop.encoding; +#ifdef HAVE_ICONV + ret = _ecore_xcb_utf8_textproperty_to_textlist(&tp, &list, &count); +#else + ret = _ecore_xcb_mb_textproperty_to_textlist(&tp, &list, &count); +#endif + if (ret) + { + if (count > 0) + title = strdup(list[0]); + + if (list) free(list); + } + } + +#ifdef OLD_XCB_VERSION + xcb_get_text_property_reply_wipe(&prop); +#else + xcb_icccm_get_text_property_reply_wipe(&prop); +#endif + return title; +} + +EAPI void +ecore_x_icccm_title_set(Ecore_X_Window win, + const char *title) +{ + Ecore_Xcb_Textproperty prop; + char *list[1]; + Eina_Bool ret = EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!title) return; + + prop.value = NULL; + list[0] = strdup(title); + +#ifdef HAVE_ICONV + ret = _ecore_xcb_utf8_textlist_to_textproperty(list, 1, XcbUTF8StringStyle, + &prop); +#else + ret = _ecore_xcb_mb_textlist_to_textproperty(list, 1, XcbStdICCTextStyle, + &prop); +#endif + + if (ret) + { +#ifdef OLD_XCB_VERSION + xcb_set_wm_name(_ecore_xcb_conn, win, ECORE_X_ATOM_STRING, + strlen(prop.value), prop.value); +#else + xcb_icccm_set_wm_name(_ecore_xcb_conn, win, ECORE_X_ATOM_STRING, 8, + strlen(prop.value), prop.value); +#endif + if (prop.value) free(prop.value); + } + else +#ifdef OLD_XCB_VERSION + xcb_set_wm_name(_ecore_xcb_conn, win, ECORE_X_ATOM_STRING, + strlen(title), title); +#else + xcb_icccm_set_wm_name(_ecore_xcb_conn, win, ECORE_X_ATOM_STRING, 8, + strlen(title), title); +#endif + free(list[0]); +} + +/** + * Get a window name & class. + * @param win The window + * @param n The name string + * @param c The class string + * + * Get a window name * class + */ +EAPI void +ecore_x_icccm_name_class_get(Ecore_X_Window win, + char **name, + char **class) +{ + xcb_get_property_cookie_t cookie; +#ifdef OLD_XCB_VERSION + xcb_get_wm_class_reply_t prop; +#else + xcb_icccm_get_wm_class_reply_t prop; +#endif + uint8_t ret = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (name) *name = NULL; + if (class) *class = NULL; + +#ifdef OLD_XCB_VERSION + cookie = xcb_get_wm_class_unchecked(_ecore_xcb_conn, win); + ret = xcb_get_wm_class_reply(_ecore_xcb_conn, cookie, &prop, NULL); +#else + cookie = xcb_icccm_get_wm_class_unchecked(_ecore_xcb_conn, win); + ret = xcb_icccm_get_wm_class_reply(_ecore_xcb_conn, cookie, &prop, NULL); +#endif + if (ret == 0) return; + + if (name) *name = strdup(prop.instance_name); + if (class) *class = strdup(prop.class_name); + +#ifdef OLD_XCB_VERSION + xcb_get_wm_class_reply_wipe(&prop); +#else + xcb_icccm_get_wm_class_reply_wipe(&prop); +#endif +} + +/** + * Set a window name & class. + * @param win The window + * @param n The name string + * @param c The class string + * + * Set a window name * class + */ +EAPI void +ecore_x_icccm_name_class_set(Ecore_X_Window win, + const char *name, + const char *class) +{ + char *class_string, *s; + int length_name, length_class; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + length_name = strlen(name); + length_class = strlen(class); + class_string = + (char *)malloc(sizeof(char) * (length_name + length_class + 2)); + if (!class_string) return; + + s = class_string; + if (length_name) + { + strcpy(s, name); + s += length_name + 1; + } + else + *s++ = '\0'; + + if (length_class) + strcpy(s, class); + else + *s = '\0'; + + xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, + ECORE_X_ATOM_WM_CLASS, ECORE_X_ATOM_STRING, 8, + length_name + length_class + 2, (void *)class_string); + free(class_string); +} + +/** + * Specify that a window is transient for another top-level window and should be handled accordingly. + * @param win the transient window + * @param forwin the toplevel window + */ +EAPI void +ecore_x_icccm_transient_for_set(Ecore_X_Window win, + Ecore_X_Window forwindow) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, + ECORE_X_ATOM_WM_TRANSIENT_FOR, ECORE_X_ATOM_WINDOW, 32, + 1, (void *)&forwindow); +} + +/** + * Remove the transient_for setting from a window. + * @param win The window + */ +EAPI void +ecore_x_icccm_transient_for_unset(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_WM_TRANSIENT_FOR); +} + +/** + * Get the window this window is transient for, if any. + * @param win The window to check + * @return The window ID of the top-level window, or 0 if the property does not exist. + */ +EAPI Ecore_X_Window +ecore_x_icccm_transient_for_get(Ecore_X_Window win) +{ + Ecore_X_Window forwin = 0; + xcb_get_property_cookie_t cookie; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef OLD_XCB_VERSION + cookie = xcb_get_wm_transient_for_unchecked(_ecore_xcb_conn, win); + xcb_get_wm_transient_for_reply(_ecore_xcb_conn, cookie, &forwin, NULL); +#else + cookie = xcb_icccm_get_wm_transient_for_unchecked(_ecore_xcb_conn, win); + xcb_icccm_get_wm_transient_for_reply(_ecore_xcb_conn, cookie, &forwin, NULL); +#endif + + return forwin; +} + +/** + * Get the window role. + * @param win The window + * @return The window's role string. + */ +EAPI char * +ecore_x_icccm_window_role_get(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return ecore_x_window_prop_string_get(win, ECORE_X_ATOM_WM_WINDOW_ROLE); +} + +/** + * Set the window role hint. + * @param win The window + * @param role The role string + */ +EAPI void +ecore_x_icccm_window_role_set(Ecore_X_Window win, + const char *role) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_string_set(win, ECORE_X_ATOM_WM_WINDOW_ROLE, role); +} + +/** + * Get the window's client leader. + * @param win The window + * @return The window's client leader window, or 0 if unset + */ +EAPI Ecore_X_Window +ecore_x_icccm_client_leader_get(Ecore_X_Window win) +{ + Ecore_X_Window leader; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (ecore_x_window_prop_window_get(win, ECORE_X_ATOM_WM_CLIENT_LEADER, + &leader, 1) > 0) + return leader; + + return 0; +} + +/** + * Set the window's client leader. + * @param win The window + * @param l The client leader window + * + * All non-transient top-level windows created by an app other than + * the main window must have this property set to the app's main window. + */ +EAPI void +ecore_x_icccm_client_leader_set(Ecore_X_Window win, + Ecore_X_Window leader) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_window_set(win, ECORE_X_ATOM_WM_CLIENT_LEADER, + &leader, 1); +} + +EAPI Ecore_X_Window_State_Hint +ecore_x_icccm_state_get(Ecore_X_Window win) +{ + xcb_get_property_cookie_t cookie; + xcb_get_property_reply_t *reply; + Ecore_X_Window_State_Hint hint = ECORE_X_WINDOW_STATE_HINT_NONE; + uint8_t *prop; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + cookie = + xcb_get_property_unchecked(_ecore_xcb_conn, 0, win, + ECORE_X_ATOM_WM_STATE, ECORE_X_ATOM_WM_STATE, + 0L, 0x7fffffff); + reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return hint; + if ((reply->type == 0) || (reply->format != 8) || (reply->value_len != 2)) + { + free(reply); + return hint; + } + + prop = (uint8_t *)xcb_get_property_value(reply); +#ifdef OLD_XCB_VERSION + switch (prop[0]) + { + case XCB_WM_STATE_WITHDRAWN: + hint = ECORE_X_WINDOW_STATE_HINT_WITHDRAWN; + break; + + case XCB_WM_STATE_NORMAL: + hint = ECORE_X_WINDOW_STATE_HINT_NORMAL; + break; + + case XCB_WM_STATE_ICONIC: + hint = ECORE_X_WINDOW_STATE_HINT_ICONIC; + break; + + default: + break; + } +#else + switch (prop[0]) + { + case XCB_ICCCM_WM_STATE_WITHDRAWN: + hint = ECORE_X_WINDOW_STATE_HINT_WITHDRAWN; + break; + + case XCB_ICCCM_WM_STATE_NORMAL: + hint = ECORE_X_WINDOW_STATE_HINT_NORMAL; + break; + + case XCB_ICCCM_WM_STATE_ICONIC: + hint = ECORE_X_WINDOW_STATE_HINT_ICONIC; + break; + + default: + break; + } +#endif + + free(reply); + return hint; +} + +EAPI void +ecore_x_icccm_state_set(Ecore_X_Window win, + Ecore_X_Window_State_Hint state) +{ +#ifdef OLD_XCB_VERSION + xcb_wm_hints_t hints; +#else + xcb_icccm_wm_hints_t hints; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef OLD_XCB_VERSION + xcb_wm_hints_set_none(&hints); + + hints.flags = XCB_WM_HINT_STATE; + + if (state == ECORE_X_WINDOW_STATE_HINT_WITHDRAWN) + xcb_wm_hints_set_withdrawn(&hints); + else if (state == ECORE_X_WINDOW_STATE_HINT_NORMAL) + xcb_wm_hints_set_normal(&hints); + else if (state == ECORE_X_WINDOW_STATE_HINT_ICONIC) + xcb_wm_hints_set_iconic(&hints); + + xcb_set_wm_hints(_ecore_xcb_conn, win, &hints); +#else + xcb_icccm_wm_hints_set_none(&hints); + + hints.flags = XCB_ICCCM_WM_HINT_STATE; + + if (state == ECORE_X_WINDOW_STATE_HINT_WITHDRAWN) + xcb_icccm_wm_hints_set_withdrawn(&hints); + else if (state == ECORE_X_WINDOW_STATE_HINT_NORMAL) + xcb_icccm_wm_hints_set_normal(&hints); + else if (state == ECORE_X_WINDOW_STATE_HINT_ICONIC) + xcb_icccm_wm_hints_set_iconic(&hints); + + xcb_icccm_set_wm_hints(_ecore_xcb_conn, win, &hints); +#endif +} + +EAPI void +ecore_x_icccm_delete_window_send(Ecore_X_Window win, + Ecore_X_Time t) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_WM_PROTOCOLS, + ECORE_X_EVENT_MASK_NONE, + ECORE_X_ATOM_WM_DELETE_WINDOW, t, 0, 0, 0); +} + +EAPI void +ecore_x_icccm_hints_set(Ecore_X_Window win, + Eina_Bool accepts_focus, + Ecore_X_Window_State_Hint initial_state, + Ecore_X_Pixmap icon_pixmap, + Ecore_X_Pixmap icon_mask, + Ecore_X_Window icon_window, + Ecore_X_Window window_group, + Eina_Bool is_urgent) +{ +#ifdef OLD_XCB_VERSION + xcb_wm_hints_t hints; +#else + xcb_icccm_wm_hints_t hints; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef OLD_XCB_VERSION + xcb_wm_hints_set_none(&hints); + xcb_wm_hints_set_input(&hints, accepts_focus); + + if (initial_state == ECORE_X_WINDOW_STATE_HINT_WITHDRAWN) + xcb_wm_hints_set_withdrawn(&hints); + else if (initial_state == ECORE_X_WINDOW_STATE_HINT_NORMAL) + xcb_wm_hints_set_normal(&hints); + else if (initial_state == ECORE_X_WINDOW_STATE_HINT_ICONIC) + xcb_wm_hints_set_iconic(&hints); + + if (icon_pixmap != 0) xcb_wm_hints_set_icon_pixmap(&hints, icon_pixmap); + if (icon_mask != 0) xcb_wm_hints_set_icon_mask(&hints, icon_mask); + if (icon_window != 0) xcb_wm_hints_set_icon_window(&hints, icon_window); + if (window_group != 0) xcb_wm_hints_set_window_group(&hints, window_group); + if (is_urgent) xcb_wm_hints_set_urgency(&hints); + + xcb_set_wm_hints(_ecore_xcb_conn, win, &hints); +#else + xcb_icccm_wm_hints_set_none(&hints); + xcb_icccm_wm_hints_set_input(&hints, accepts_focus); + + if (initial_state == ECORE_X_WINDOW_STATE_HINT_WITHDRAWN) + xcb_icccm_wm_hints_set_withdrawn(&hints); + else if (initial_state == ECORE_X_WINDOW_STATE_HINT_NORMAL) + xcb_icccm_wm_hints_set_normal(&hints); + else if (initial_state == ECORE_X_WINDOW_STATE_HINT_ICONIC) + xcb_icccm_wm_hints_set_iconic(&hints); + + if (icon_pixmap != 0) + xcb_icccm_wm_hints_set_icon_pixmap(&hints, icon_pixmap); + if (icon_mask != 0) + xcb_icccm_wm_hints_set_icon_mask(&hints, icon_mask); + if (icon_window != 0) + xcb_icccm_wm_hints_set_icon_window(&hints, icon_window); + if (window_group != 0) + xcb_icccm_wm_hints_set_window_group(&hints, window_group); + if (is_urgent) + xcb_icccm_wm_hints_set_urgency(&hints); + + xcb_icccm_set_wm_hints(_ecore_xcb_conn, win, &hints); +#endif +} + +EAPI Eina_Bool +ecore_x_icccm_hints_get(Ecore_X_Window win, + Eina_Bool *accepts_focus, + Ecore_X_Window_State_Hint *initial_state, + Ecore_X_Pixmap *icon_pixmap, + Ecore_X_Pixmap *icon_mask, + Ecore_X_Window *icon_window, + Ecore_X_Window *window_group, + Eina_Bool *is_urgent) +{ + xcb_get_property_cookie_t cookie; +#ifdef OLD_XCB_VERSION + xcb_wm_hints_t hints; +#else + xcb_icccm_wm_hints_t hints; +#endif + uint8_t ret = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (accepts_focus) *accepts_focus = EINA_TRUE; + if (initial_state) *initial_state = ECORE_X_WINDOW_STATE_HINT_NORMAL; + if (icon_pixmap) *icon_pixmap = 0; + if (icon_mask) *icon_mask = 0; + if (icon_window) *icon_window = 0; + if (window_group) *window_group = 0; + if (is_urgent) *is_urgent = EINA_FALSE; + +#ifdef OLD_XCB_VERSION + xcb_wm_hints_set_none(&hints); + cookie = xcb_get_wm_hints_unchecked(_ecore_xcb_conn, win); + ret = xcb_get_wm_hints_reply(_ecore_xcb_conn, cookie, &hints, NULL); +#else + xcb_icccm_wm_hints_set_none(&hints); + cookie = xcb_icccm_get_wm_hints_unchecked(_ecore_xcb_conn, win); + ret = xcb_icccm_get_wm_hints_reply(_ecore_xcb_conn, cookie, &hints, NULL); +#endif + if (!ret) return EINA_FALSE; + +#ifdef OLD_XCB_VERSION + if ((hints.flags & XCB_WM_HINT_INPUT) && (accepts_focus)) +#else + if ((hints.flags & XCB_ICCCM_WM_HINT_INPUT) && (accepts_focus)) +#endif + { + if (hints.input) + *accepts_focus = EINA_TRUE; + else + *accepts_focus = EINA_FALSE; + } + +#ifdef OLD_XCB_VERSION + if ((hints.flags & XCB_WM_HINT_STATE) && (initial_state)) + { + if (hints.initial_state == XCB_WM_STATE_WITHDRAWN) + *initial_state = ECORE_X_WINDOW_STATE_HINT_WITHDRAWN; + else if (hints.initial_state == XCB_WM_STATE_NORMAL) + *initial_state = ECORE_X_WINDOW_STATE_HINT_NORMAL; + else if (hints.initial_state == XCB_WM_STATE_ICONIC) + *initial_state = ECORE_X_WINDOW_STATE_HINT_ICONIC; + } + + if ((hints.flags & XCB_WM_HINT_ICON_PIXMAP) && (icon_pixmap)) + *icon_pixmap = hints.icon_pixmap; + + if ((hints.flags & XCB_WM_HINT_ICON_MASK) && (icon_mask)) + *icon_mask = hints.icon_mask; + + if ((hints.flags & XCB_WM_HINT_ICON_WINDOW) && (icon_window)) + *icon_window = hints.icon_window; + + if ((hints.flags & XCB_WM_HINT_WINDOW_GROUP) && (window_group)) + *window_group = hints.window_group; + + if ((hints.flags & XCB_WM_HINT_X_URGENCY) && (is_urgent)) + *is_urgent = EINA_TRUE; +#else + if ((hints.flags & XCB_ICCCM_WM_HINT_STATE) && (initial_state)) + { + if (hints.initial_state == XCB_ICCCM_WM_STATE_WITHDRAWN) + *initial_state = ECORE_X_WINDOW_STATE_HINT_WITHDRAWN; + else if (hints.initial_state == XCB_ICCCM_WM_STATE_NORMAL) + *initial_state = ECORE_X_WINDOW_STATE_HINT_NORMAL; + else if (hints.initial_state == XCB_ICCCM_WM_STATE_ICONIC) + *initial_state = ECORE_X_WINDOW_STATE_HINT_ICONIC; + } + + if ((hints.flags & XCB_ICCCM_WM_HINT_ICON_PIXMAP) && (icon_pixmap)) + *icon_pixmap = hints.icon_pixmap; + + if ((hints.flags & XCB_ICCCM_WM_HINT_ICON_MASK) && (icon_mask)) + *icon_mask = hints.icon_mask; + + if ((hints.flags & XCB_ICCCM_WM_HINT_ICON_WINDOW) && (icon_window)) + *icon_window = hints.icon_window; + + if ((hints.flags & XCB_ICCCM_WM_HINT_WINDOW_GROUP) && (window_group)) + *window_group = hints.window_group; + + if ((hints.flags & XCB_ICCCM_WM_HINT_X_URGENCY) && (is_urgent)) + *is_urgent = EINA_TRUE; +#endif + + return EINA_TRUE; +} + +/** + * Get a window icon name. + * @param win The window + * @return The windows icon name string + * + * Return the icon name of a window. String must be free'd when done with. + */ +EAPI char * +ecore_x_icccm_icon_name_get(Ecore_X_Window win) +{ + xcb_get_property_cookie_t cookie; +#ifdef OLD_XCB_VERSION + xcb_get_text_property_reply_t prop; +#else + xcb_icccm_get_text_property_reply_t prop; +#endif + uint8_t ret = 0; + char *tmp = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!win) return NULL; + +#ifdef OLD_XCB_VERSION + cookie = xcb_get_wm_icon_name_unchecked(_ecore_xcb_conn, win); + ret = xcb_get_wm_icon_name_reply(_ecore_xcb_conn, cookie, &prop, NULL); +#else + cookie = xcb_icccm_get_wm_icon_name_unchecked(_ecore_xcb_conn, win); + ret = xcb_icccm_get_wm_icon_name_reply(_ecore_xcb_conn, cookie, &prop, NULL); +#endif + if (ret == 0) return NULL; + + if (prop.name_len < 1) + { +#ifdef OLD_XCB_VERSION + xcb_get_text_property_reply_wipe(&prop); +#else + xcb_icccm_get_text_property_reply_wipe(&prop); +#endif + return NULL; + } + + if (!(tmp = malloc((prop.name_len + 1) * sizeof(char *)))) + { +#ifdef OLD_XCB_VERSION + xcb_get_text_property_reply_wipe(&prop); +#else + xcb_icccm_get_text_property_reply_wipe(&prop); +#endif + return NULL; + } + memcpy(tmp, prop.name, sizeof(char *) * prop.name_len); + tmp[prop.name_len] = '\0'; + + if (prop.encoding != ECORE_X_ATOM_UTF8_STRING) + { + Ecore_Xcb_Textproperty tp; + int count = 0; + char **list = NULL; + Eina_Bool ret = EINA_FALSE; + + tp.value = strdup(tmp); + tp.nitems = prop.name_len; + tp.encoding = prop.encoding; +#ifdef HAVE_ICONV + ret = _ecore_xcb_utf8_textproperty_to_textlist(&tp, &list, &count); +#else + ret = _ecore_xcb_mb_textproperty_to_textlist(&tp, &list, &count); +#endif + if (ret) + { + if (count > 0) + tmp = strdup(list[0]); + + if (list) free(list); + } + } + +#ifdef OLD_XCB_VERSION + xcb_get_text_property_reply_wipe(&prop); +#else + xcb_icccm_get_text_property_reply_wipe(&prop); +#endif + return tmp; +} + +/** + * Set a window icon name. + * @param win The window + * @param t The icon name string + * + * Set a window icon name + */ +EAPI void +ecore_x_icccm_icon_name_set(Ecore_X_Window win, + const char *name) +{ + Ecore_Xcb_Textproperty prop; + char *list[1]; + Eina_Bool ret = EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if ((!win) || (!name)) return; + + prop.value = NULL; + list[0] = strdup(name); + +#ifdef HAVE_ICONV + ret = _ecore_xcb_utf8_textlist_to_textproperty(list, 1, XcbUTF8StringStyle, + &prop); +#else + ret = _ecore_xcb_mb_textlist_to_textproperty(list, 1, XcbStdICCTextStyle, + &prop); +#endif + + if (ret) + { +#ifdef OLD_XCB_VERSION + xcb_set_wm_icon_name(_ecore_xcb_conn, win, ECORE_X_ATOM_STRING, + strlen(prop.value), prop.value); +#else + xcb_icccm_set_wm_icon_name(_ecore_xcb_conn, win, ECORE_X_ATOM_STRING, + 8, strlen(prop.value), prop.value); +#endif + if (prop.value) free(prop.value); + } + else +#ifdef OLD_XCB_VERSION + xcb_set_wm_icon_name(_ecore_xcb_conn, win, ECORE_X_ATOM_STRING, + strlen(name), name); +#else + xcb_icccm_set_wm_icon_name(_ecore_xcb_conn, win, ECORE_X_ATOM_STRING, + 8, strlen(name), name); +#endif + + free(list[0]); +} + +EAPI void +ecore_x_icccm_iconic_request_send(Ecore_X_Window win, + Ecore_X_Window root) +{ + xcb_client_message_event_t ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!win) return; + if (!root) root = ((xcb_screen_t *)_ecore_xcb_screen)->root; + + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 32; + ev.window = win; + ev.type = ECORE_X_ATOM_WM_CHANGE_STATE; +#ifdef OLD_XCB_VERSION + ev.data.data32[0] = XCB_WM_STATE_ICONIC; +#else + ev.data.data32[0] = XCB_ICCCM_WM_STATE_ICONIC; +#endif + + xcb_send_event(_ecore_xcb_conn, 0, root, + (XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | + XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT), + (const char *)&ev); +// ecore_x_flush(); +} + +/** + * Set or unset a wm protocol property. + * @param win The Window + * @param protocol The protocol to enable/disable + * @param on On/Off + */ +EAPI void +ecore_x_icccm_protocol_set(Ecore_X_Window win, + Ecore_X_WM_Protocol protocol, + Eina_Bool on) +{ + Ecore_X_Atom proto; + xcb_get_property_cookie_t cookie; +#ifdef OLD_XCB_VERSION + xcb_get_wm_protocols_reply_t protos; +#else + xcb_icccm_get_wm_protocols_reply_t protos; +#endif + int i = 0, count = 0, set = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (protocol >= ECORE_X_WM_PROTOCOL_NUM) return; + proto = _ecore_xcb_atoms_wm_protocol[protocol]; +#ifdef OLD_XCB_VERSION + cookie = xcb_get_wm_protocols_unchecked(_ecore_xcb_conn, win, proto); + if (!xcb_get_wm_protocols_reply(_ecore_xcb_conn, cookie, &protos, NULL)) +#else + cookie = xcb_icccm_get_wm_protocols_unchecked(_ecore_xcb_conn, win, proto); + if (!xcb_icccm_get_wm_protocols_reply(_ecore_xcb_conn, cookie, &protos, NULL)) +#endif + count = 0; + else + count = protos.atoms_len; + + for (i = 0; i < count; i++) + { + if (protos.atoms[i] == proto) + { + set = 1; + break; + } + } + + if (on) + { + if (!set) + { + Ecore_X_Atom *atoms = NULL; + + atoms = malloc((count + 1) * sizeof(Ecore_X_Atom)); + if (atoms) + { + for (i = 0; i < count; i++) + atoms[i] = protos.atoms[i]; + atoms[count] = proto; +#ifdef OLD_XCB_VERSION + xcb_set_wm_protocols(_ecore_xcb_conn, + ECORE_X_ATOM_WM_PROTOCOLS, + win, count, atoms); +#else + xcb_icccm_set_wm_protocols(_ecore_xcb_conn, win, + ECORE_X_ATOM_WM_PROTOCOLS, + count, atoms); +#endif + free(atoms); + } + } + } + else + { + if (set) + { + for (i = 0; i < count; i++) + { + if (protos.atoms[i] == proto) + { + int j = 0; + + for (j = (i + 1); j < count; j++) + protos.atoms[j - 1] = protos.atoms[j]; + if (count > 1) +#ifdef OLD_XCB_VERSION + xcb_set_wm_protocols(_ecore_xcb_conn, + ECORE_X_ATOM_WM_PROTOCOLS, + win, count - 1, protos.atoms); +#else + xcb_icccm_set_wm_protocols(_ecore_xcb_conn, win, + ECORE_X_ATOM_WM_PROTOCOLS, + count - 1, protos.atoms); +#endif + else + ecore_x_window_prop_property_del(win, + ECORE_X_ATOM_WM_PROTOCOLS); + break; + } + } + } + } + +#ifdef OLD_XCB_VERSION + xcb_get_wm_protocols_reply_wipe(&protos); +#else + xcb_icccm_get_wm_protocols_reply_wipe(&protos); +#endif +} + +/** + * Determines whether a protocol is set for a window. + * @param win The Window + * @param protocol The protocol to query + * @return 1 if the protocol is set, else 0. + */ +EAPI Eina_Bool +ecore_x_icccm_protocol_isset(Ecore_X_Window win, + Ecore_X_WM_Protocol protocol) +{ + Ecore_X_Atom proto; + Eina_Bool ret = EINA_FALSE; + xcb_get_property_cookie_t cookie; +#ifdef OLD_XCB_VERSION + xcb_get_wm_protocols_reply_t reply; +#else + xcb_icccm_get_wm_protocols_reply_t reply; +#endif + uint8_t val = 0; + unsigned int i = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (protocol >= ECORE_X_WM_PROTOCOL_NUM) return EINA_FALSE; + + proto = _ecore_xcb_atoms_wm_protocol[protocol]; +#ifdef OLD_XCB_VERSION + cookie = xcb_get_wm_protocols_unchecked(_ecore_xcb_conn, win, proto); + val = xcb_get_wm_protocols_reply(_ecore_xcb_conn, cookie, &reply, NULL); +#else + cookie = xcb_icccm_get_wm_protocols_unchecked(_ecore_xcb_conn, win, proto); + val = xcb_icccm_get_wm_protocols_reply(_ecore_xcb_conn, cookie, &reply, NULL); +#endif + if (!val) return EINA_FALSE; + + for (i = 0; i < reply.atoms_len; i++) + if (reply.atoms[i] == proto) + { + ret = EINA_TRUE; + break; + } + +#ifdef OLD_XCB_VERSION + xcb_get_wm_protocols_reply_wipe(&reply); +#else + xcb_icccm_get_wm_protocols_reply_wipe(&reply); +#endif + + return ret; +} + +/** + * Set protocol atoms explicitly + * @param win The Window + * @param protos An array of protocol atoms + * @param num the number of members of the array + */ +EAPI void +ecore_x_icccm_protocol_atoms_set(Ecore_X_Window win, + Ecore_X_Atom *protos, + int num) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (num > 0) +#ifdef OLD_XCB_VERSION + xcb_set_wm_protocols(_ecore_xcb_conn, ECORE_X_ATOM_WM_PROTOCOLS, + win, num, protos); +#else + xcb_icccm_set_wm_protocols(_ecore_xcb_conn, win, + ECORE_X_ATOM_WM_PROTOCOLS, num, protos); +#endif + else + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_WM_PROTOCOLS); +} + +EAPI Eina_Bool +ecore_x_icccm_size_pos_hints_get(Ecore_X_Window win, + Eina_Bool *request_pos, + Ecore_X_Gravity *gravity, + int *min_w, + int *min_h, + int *max_w, + int *max_h, + int *base_w, + int *base_h, + int *step_x, + int *step_y, + double *min_aspect, + double *max_aspect) +{ + xcb_size_hints_t hints; + xcb_get_property_cookie_t cookie; + uint8_t ret = 0; + int32_t minw = 0, minh = 0; + int32_t maxw = 32767, maxh = 32767; + int32_t basew = -1, baseh = -1; + int32_t stepx = -1, stepy = -1; + double mina = 0.0, maxa = 0.0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (request_pos) *request_pos = EINA_FALSE; + if (gravity) *gravity = ECORE_X_GRAVITY_NW; + if (min_w) *min_w = minw; + if (min_h) *min_h = minh; + if (max_w) *max_w = maxw; + if (max_h) *max_h = maxh; + if (base_w) *base_w = basew; + if (base_h) *base_h = baseh; + if (step_x) *step_x = stepx; + if (step_y) *step_y = stepy; + if (min_aspect) *min_aspect = mina; + if (max_aspect) *max_aspect = maxa; + +#ifdef OLD_XCB_VERSION + cookie = xcb_get_wm_normal_hints_unchecked(_ecore_xcb_conn, win); + ret = xcb_get_wm_normal_hints_reply(_ecore_xcb_conn, cookie, &hints, NULL); +#else + cookie = xcb_icccm_get_wm_normal_hints_unchecked(_ecore_xcb_conn, win); + ret = xcb_icccm_get_wm_normal_hints_reply(_ecore_xcb_conn, cookie, + &hints, NULL); +#endif + if (!ret) return EINA_FALSE; + +#ifdef OLD_XCB_VERSION + if ((hints.flags & XCB_SIZE_HINT_US_POSITION) || + (hints.flags & XCB_SIZE_HINT_P_POSITION)) +#else + if ((hints.flags & XCB_ICCCM_SIZE_HINT_US_POSITION) || + (hints.flags & XCB_ICCCM_SIZE_HINT_P_POSITION)) +#endif + { + if (request_pos) *request_pos = EINA_TRUE; + } + +#ifdef OLD_XCB_VERSION + if (hints.flags & XCB_SIZE_HINT_P_WIN_GRAVITY) +#else + if (hints.flags & XCB_ICCCM_SIZE_HINT_P_WIN_GRAVITY) +#endif + { + if (gravity) *gravity = hints.win_gravity; + } + +#ifdef OLD_XCB_VERSION + if (hints.flags & XCB_SIZE_HINT_P_MIN_SIZE) +#else + if (hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) +#endif + { + minw = hints.min_width; + minh = hints.min_height; + } + +#ifdef OLD_XCB_VERSION + if (hints.flags & XCB_SIZE_HINT_P_MAX_SIZE) +#else + if (hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE) +#endif + { + maxw = hints.max_width; + maxh = hints.max_height; + if (maxw < minw) maxw = minw; + if (maxh < minh) maxh = minh; + } + +#ifdef OLD_XCB_VERSION + if (hints.flags & XCB_SIZE_HINT_BASE_SIZE) +#else + if (hints.flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE) +#endif + { + basew = hints.base_width; + baseh = hints.base_height; + if (basew > minw) minw = basew; + if (baseh > minh) minh = baseh; + } + +#ifdef OLD_XCB_VERSION + if (hints.flags & XCB_SIZE_HINT_P_RESIZE_INC) +#else + if (hints.flags & XCB_ICCCM_SIZE_HINT_P_RESIZE_INC) +#endif + { + stepx = hints.width_inc; + stepy = hints.height_inc; + if (stepx < 1) stepx = 1; + if (stepy < 1) stepy = 1; + } + +#ifdef OLD_XCB_VERSION + if (hints.flags & XCB_SIZE_HINT_P_ASPECT) +#else + if (hints.flags & XCB_ICCCM_SIZE_HINT_P_ASPECT) +#endif + { + if (hints.min_aspect_den > 0) + mina = ((double)hints.min_aspect_num) / ((double)hints.min_aspect_den); + + if (hints.max_aspect_den > 0) + maxa = ((double)hints.max_aspect_num) / ((double)hints.max_aspect_den); + } + + if (min_w) *min_w = minw; + if (min_h) *min_h = minh; + if (max_w) *max_w = maxw; + if (max_h) *max_h = maxh; + if (base_w) *base_w = basew; + if (base_h) *base_h = baseh; + if (step_x) *step_x = stepx; + if (step_y) *step_y = stepy; + if (min_aspect) *min_aspect = mina; + if (max_aspect) *max_aspect = maxa; + + return EINA_TRUE; +} + +EAPI void +ecore_x_icccm_size_pos_hints_set(Ecore_X_Window win, + Eina_Bool request_pos, + Ecore_X_Gravity gravity, + int min_w, + int min_h, + int max_w, + int max_h, + int base_w, + int base_h, + int step_x, + int step_y, + double min_aspect, + double max_aspect) +{ + xcb_get_property_cookie_t cookie; + xcb_size_hints_t hints; + uint8_t ret = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef OLD_XCB_VERSION + cookie = xcb_get_wm_normal_hints_unchecked(_ecore_xcb_conn, win); + ret = xcb_get_wm_normal_hints_reply(_ecore_xcb_conn, cookie, &hints, NULL); +#else + cookie = xcb_icccm_get_wm_normal_hints_unchecked(_ecore_xcb_conn, win); + ret = xcb_icccm_get_wm_normal_hints_reply(_ecore_xcb_conn, cookie, + &hints, NULL); +#endif + if (!ret) memset(&hints, 0, sizeof(xcb_size_hints_t)); + + hints.flags = 0; + +#ifdef OLD_XCB_VERSION + if (request_pos) + hints.flags |= XCB_SIZE_HINT_US_POSITION; + + if (gravity != ECORE_X_GRAVITY_NW) + xcb_size_hints_set_win_gravity(&hints, gravity); + if ((min_w > 0) || (min_h > 0)) + xcb_size_hints_set_min_size(&hints, min_w, min_h); + if ((max_w > 0) || (max_h > 0)) + xcb_size_hints_set_max_size(&hints, max_w, max_h); + if ((base_w > 0) || (base_h > 0)) + xcb_size_hints_set_base_size(&hints, base_w, base_h); + if ((step_x > 1) || (step_y > 1)) + xcb_size_hints_set_resize_inc(&hints, step_x, step_y); + if ((min_aspect > 0.0) || (max_aspect > 0.0)) + xcb_size_hints_set_aspect(&hints, + (int32_t)(min_aspect * 10000), 10000, + (int32_t)(max_aspect * 10000), 10000); + + xcb_set_wm_normal_hints(_ecore_xcb_conn, win, &hints); +#else + if (request_pos) + hints.flags |= XCB_ICCCM_SIZE_HINT_US_POSITION; + + if (gravity != ECORE_X_GRAVITY_NW) + xcb_icccm_size_hints_set_win_gravity(&hints, gravity); + if ((min_w > 0) || (min_h > 0)) + xcb_icccm_size_hints_set_min_size(&hints, min_w, min_h); + if ((max_w > 0) || (max_h > 0)) + xcb_icccm_size_hints_set_max_size(&hints, max_w, max_h); + if ((base_w > 0) || (base_h > 0)) + xcb_icccm_size_hints_set_base_size(&hints, base_w, base_h); + if ((step_x > 1) || (step_y > 1)) + xcb_icccm_size_hints_set_resize_inc(&hints, step_x, step_y); + if ((min_aspect > 0.0) || (max_aspect > 0.0)) + xcb_icccm_size_hints_set_aspect(&hints, + (int32_t)(min_aspect * 10000), 10000, + (int32_t)(max_aspect * 10000), 10000); + + xcb_icccm_set_wm_normal_hints(_ecore_xcb_conn, win, &hints); +#endif +} + +EAPI void +ecore_x_icccm_move_resize_send(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ + xcb_configure_notify_event_t ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!win) return; + + memset(&ev, 0, sizeof(xcb_configure_notify_event_t)); + + ev.response_type = XCB_CONFIGURE_NOTIFY; + ev.event = win; + ev.window = win; + ev.above_sibling = XCB_NONE; + ev.x = x; + ev.y = y; + ev.width = w; + ev.height = h; + ev.border_width = 0; + ev.override_redirect = 0; + + xcb_send_event(_ecore_xcb_conn, 0, win, + XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char *)&ev); +// ecore_x_flush(); +} + +/** + * Get a window client machine string. + * @param win The window + * @return The windows client machine string + * + * Return the client machine of a window. String must be free'd when done with. + */ +EAPI char * +ecore_x_icccm_client_machine_get(Ecore_X_Window win) +{ + xcb_get_property_cookie_t cookie; +#ifdef OLD_XCB_VERSION + xcb_get_text_property_reply_t prop; +#else + xcb_icccm_get_text_property_reply_t prop; +#endif + uint8_t ret = 0; + char *tmp = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef OLD_XCB_VERSION + cookie = xcb_get_wm_client_machine_unchecked(_ecore_xcb_conn, win); + ret = xcb_get_wm_client_machine_reply(_ecore_xcb_conn, cookie, &prop, NULL); +#else + cookie = xcb_icccm_get_wm_client_machine_unchecked(_ecore_xcb_conn, win); + ret = xcb_icccm_get_wm_client_machine_reply(_ecore_xcb_conn, cookie, + &prop, NULL); +#endif + if (ret == 0) return NULL; + + tmp = malloc((prop.name_len + 1) * sizeof(char *)); + if (!tmp) + { +#ifdef OLD_XCB_VERSION + xcb_get_text_property_reply_wipe(&prop); +#else + xcb_icccm_get_text_property_reply_wipe(&prop); +#endif + return NULL; + } + memcpy(tmp, prop.name, sizeof(char *) * prop.name_len); + tmp[prop.name_len] = '\0'; + +#ifdef OLD_XCB_VERSION + xcb_get_text_property_reply_wipe(&prop); +#else + xcb_icccm_get_text_property_reply_wipe(&prop); +#endif + + return tmp; +} + +EAPI void +ecore_x_icccm_take_focus_send(Ecore_X_Window win, + Ecore_X_Time t) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + ecore_x_client_message32_send(win, ECORE_X_ATOM_WM_PROTOCOLS, + XCB_EVENT_MASK_NO_EVENT, + ECORE_X_ATOM_WM_TAKE_FOCUS, t, 0, 0, 0); +} + +EAPI void +ecore_x_icccm_save_yourself_send(Ecore_X_Window win, + Ecore_X_Time t) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_WM_PROTOCOLS, + XCB_EVENT_MASK_NO_EVENT, + ECORE_X_ATOM_WM_SAVE_YOURSELF, t, 0, 0, 0); +} + +/** + * Add a subwindow to the list of windows that need a different colormap installed. + * @param win The toplevel window + * @param subwin The subwindow to be added to the colormap windows list + */ +EAPI void +ecore_x_icccm_colormap_window_set(Ecore_X_Window win, + Ecore_X_Window subwin) +{ + int num = 0, i = 0; + unsigned char *odata = NULL, *data = NULL; + Ecore_X_Window *newset = NULL, *oldset = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_property_get(win, ECORE_X_ATOM_WM_COLORMAP_WINDOWS, + ECORE_X_ATOM_WINDOW, 32, &odata, &num)) + { + if (!(newset = calloc(1, sizeof(Ecore_X_Window)))) return; + newset[0] = subwin; + num = 1; + data = (unsigned char *)newset; + } + else + { + if (!(newset = calloc(num + 1, sizeof(Ecore_X_Window)))) return; + oldset = (Ecore_X_Window *)odata; + for (i = 0; i < num; i++) + { + if (oldset[i] == subwin) + { + if (odata) free(odata); + odata = NULL; + free(newset); + return; + } + newset[i] = oldset[i]; + } + newset[num++] = subwin; + if (odata) free(odata); + data = (unsigned char *)newset; + } + ecore_x_window_prop_property_set(win, ECORE_X_ATOM_WM_COLORMAP_WINDOWS, + ECORE_X_ATOM_WINDOW, 32, data, num); + free(newset); +} + +/** + * Remove a window from the list of colormap windows. + * @param win The toplevel window + * @param subwin The window to be removed from the colormap window list. + */ +EAPI void +ecore_x_icccm_colormap_window_unset(Ecore_X_Window win, + Ecore_X_Window subwin) +{ + int num = 0, i = 0, j = 0, k = 0; + unsigned char *odata = NULL, *data = NULL; + Ecore_X_Window *newset = NULL, *oldset = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_property_get(win, ECORE_X_ATOM_WM_COLORMAP_WINDOWS, + ECORE_X_ATOM_WINDOW, 32, &odata, &num)) + return; + + oldset = (Ecore_X_Window *)odata; + for (i = 0; i < num; i++) + { + if (oldset[i] == subwin) + { + if (num == 1) + { + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_WM_COLORMAP_WINDOWS); + if (odata) free(odata); + odata = NULL; + return; + } + else + { + newset = calloc(num - 1, sizeof(Ecore_X_Window)); + data = (unsigned char *)newset; + for (j = 0; j < num; ++j) + if (oldset[j] != subwin) + newset[k++] = oldset[j]; + + ecore_x_window_prop_property_set(win, ECORE_X_ATOM_WM_COLORMAP_WINDOWS, + ECORE_X_ATOM_WINDOW, 32, data, k); + if (odata) free(odata); + odata = NULL; + free(newset); + return; + } + } + } + if (odata) free(odata); +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_image.c b/src/lib/ecore_x/xcb/ecore_xcb_image.c new file mode 100644 index 0000000..6789b94 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_image.c @@ -0,0 +1,740 @@ +#include "ecore_xcb_private.h" +#include +#include +#include +#include + +struct _Ecore_X_Image +{ + xcb_shm_segment_info_t shminfo; + xcb_image_t *xim; + Ecore_X_Visual vis; + int depth, w, h; + int bpl, bpp, rows; + unsigned char *data; + Eina_Bool shm : 1; +}; + +/* local function prototypes */ +static void _ecore_xcb_image_shm_check(void); +static void _ecore_xcb_image_shm_create(Ecore_X_Image *im); +static xcb_format_t *_ecore_xcb_image_find_format(const xcb_setup_t *setup, + uint8_t depth); + +/* local variables */ +static int _ecore_xcb_image_shm_can = -1; + +EAPI Ecore_X_Image * +ecore_x_image_new(int w, + int h, + Ecore_X_Visual vis, + int depth) +{ + Ecore_X_Image *im; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(im = calloc(1, sizeof(Ecore_X_Image)))) return NULL; + im->w = w; + im->h = h; + im->vis = vis; + im->depth = depth; + _ecore_xcb_image_shm_check(); + im->shm = _ecore_xcb_image_shm_can; + return im; +} + +EAPI void +ecore_x_image_free(Ecore_X_Image *im) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!im) return; + if (im->shm) + { + if (im->xim) + { + xcb_shm_detach(_ecore_xcb_conn, im->shminfo.shmseg); + xcb_image_destroy(im->xim); + shmdt(im->shminfo.shmaddr); + shmctl(im->shminfo.shmid, IPC_RMID, 0); + } + } + else if (im->xim) + { + if (im->xim->data) free(im->xim->data); + im->xim->data = NULL; + xcb_image_destroy(im->xim); + } + + free(im); +// ecore_x_flush(); +} + +EAPI Eina_Bool +ecore_x_image_get(Ecore_X_Image *im, + Ecore_X_Drawable draw, + int x, + int y, + int sx, + int sy, + int w, + int h) +{ + Eina_Bool ret = EINA_TRUE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (im->shm) + { + if (!im->xim) _ecore_xcb_image_shm_create(im); + if (!im->xim) return EINA_FALSE; + + if ((sx == 0) && (w == im->w)) + { + im->xim->data = (uint8_t *)im->data + (im->xim->stride * sy) + + (sx * im->bpp); + im->xim->width = w; + im->xim->height = h; + + ecore_x_grab(); + if (!xcb_image_shm_get(_ecore_xcb_conn, draw, im->xim, + im->shminfo, x, y, 0xffffffff)) + { + DBG("\tImage Shm Get Failed"); + ret = EINA_FALSE; + } + ecore_x_ungrab(); + ecore_x_sync(); // needed + } + else + { + Ecore_X_Image *tim; + + tim = ecore_x_image_new(w, h, im->vis, im->depth); + if (tim) + { + ret = ecore_x_image_get(tim, draw, x, y, 0, 0, w, h); + if (ret) + { + unsigned char *spixels, *pixels; + int sbpp = 0, sbpl = 0, srows = 0; + int bpp = 0, bpl = 0, rows = 0; + + spixels = + ecore_x_image_data_get(tim, &sbpl, &srows, &sbpp); + pixels = ecore_x_image_data_get(im, &bpl, &rows, &bpp); + if ((spixels) && (pixels)) + { + unsigned char *p, *sp; + int r = 0; + + p = (pixels + (sy * bpl) + (sx * bpp)); + sp = spixels; + for (r = srows; r > 0; r--) + { + memcpy(p, sp, sbpl); + p += bpl; + sp += sbpl; + } + } + } + ecore_x_image_free(tim); + } + } + } + else + { + ret = EINA_FALSE; + ecore_x_grab(); + im->xim = + xcb_image_get(_ecore_xcb_conn, draw, x, y, w, h, + 0xffffffff, XCB_IMAGE_FORMAT_Z_PIXMAP); + if (!im->xim) ret = EINA_FALSE; + ecore_x_ungrab(); + ecore_x_sync(); // needed + + if (im->xim) + { + im->data = (unsigned char *)im->xim->data; + im->bpl = im->xim->stride; + im->rows = im->xim->height; + if (im->xim->bpp <= 8) + im->bpp = 1; + else if (im->xim->bpp <= 16) + im->bpp = 2; + else + im->bpp = 4; + } + } + + return ret; +} + +EAPI void * +ecore_x_image_data_get(Ecore_X_Image *im, + int *bpl, + int *rows, + int *bpp) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!im) return NULL; + if (!im->xim) _ecore_xcb_image_shm_create(im); + if (!im->xim) return NULL; + + if (bpl) *bpl = im->bpl; + if (rows) *rows = im->rows; + if (bpp) *bpp = im->bpp; + + return im->data; +} + +EAPI void +ecore_x_image_put(Ecore_X_Image *im, + Ecore_X_Drawable draw, + Ecore_X_GC gc, + int x, + int y, + int sx, + int sy, + int w, + int h) +{ + Ecore_X_GC tgc = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!gc) + { + uint32_t mask, values[1]; + + tgc = xcb_generate_id(_ecore_xcb_conn); + mask = XCB_GC_SUBWINDOW_MODE; + values[0] = XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS; + xcb_create_gc(_ecore_xcb_conn, tgc, draw, mask, values); + gc = tgc; + } + if (!im->xim) _ecore_xcb_image_shm_create(im); + if (im->xim) + { + if (im->shm) + xcb_shm_put_image(_ecore_xcb_conn, draw, gc, im->xim->width, + im->xim->height, sx, sy, w, h, x, y, + im->xim->depth, im->xim->format, 0, + im->shminfo.shmseg, + im->xim->data - im->shminfo.shmaddr); +// xcb_image_shm_put(_ecore_xcb_conn, draw, gc, im->xim, +// im->shminfo, sx, sy, x, y, w, h, 0); + else + xcb_image_put(_ecore_xcb_conn, draw, gc, im->xim, sx, sy, 0); + } + if (tgc) ecore_x_gc_free(tgc); + ecore_x_sync(); +} + +EAPI Eina_Bool +ecore_x_image_is_argb32_get(Ecore_X_Image *im) +{ + xcb_visualtype_t *vis; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + vis = (xcb_visualtype_t *)im->vis; + if (!im->xim) _ecore_xcb_image_shm_create(im); + + if (((vis->_class == XCB_VISUAL_CLASS_TRUE_COLOR) || + (vis->_class == XCB_VISUAL_CLASS_DIRECT_COLOR)) && + (im->depth >= 24) && (vis->red_mask == 0xff0000) && + (vis->green_mask == 0x00ff00) && (vis->blue_mask == 0x0000ff)) + { +#ifdef WORDS_BIGENDIAN + if (im->xim->byte_order == XCB_IMAGE_ORDER_LSB_FIRST) + return EINA_TRUE; +#else + if (im->xim->byte_order == XCB_IMAGE_ORDER_MSB_FIRST) + return EINA_TRUE; +#endif + } + + return EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_image_to_argb_convert(void *src, + int sbpp, + int sbpl, + Ecore_X_Colormap c, + Ecore_X_Visual v, + int x, + int y, + int w, + int h, + unsigned int *dst, + int dbpl, + int dx, + int dy) +{ + xcb_visualtype_t *vis; + uint32_t *cols; + int n = 0, nret = 0, i, row, mode = 0; + unsigned int pal[256], r, g, b; + enum + { + rgbnone = 0, + rgb565, + bgr565, + rgbx555, + argbx888, + abgrx888, + rgba888x, + bgra888x, + argbx666 + }; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + sbpp *= 8; + + vis = (xcb_visualtype_t *)v; + n = vis->colormap_entries; + if ((n <= 256) && + ((vis->_class == XCB_VISUAL_CLASS_PSEUDO_COLOR) || + (vis->_class == XCB_VISUAL_CLASS_STATIC_COLOR) || + (vis->_class == XCB_VISUAL_CLASS_GRAY_SCALE) || + (vis->_class == XCB_VISUAL_CLASS_STATIC_GRAY))) + { + xcb_query_colors_cookie_t cookie; + xcb_query_colors_reply_t *reply; + + if (!c) + { + c = (xcb_colormap_t)((xcb_screen_t *) + _ecore_xcb_screen)->default_colormap; + } + + cols = alloca(n * sizeof(uint32_t)); + for (i = 0; i < n; i++) + cols[i] = i; + + cookie = xcb_query_colors_unchecked(_ecore_xcb_conn, c, n, cols); + reply = xcb_query_colors_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + xcb_rgb_iterator_t iter; + xcb_rgb_t *ret; + + iter = xcb_query_colors_colors_iterator(reply); + ret = xcb_query_colors_colors(reply); + if (ret) + { + for (i = 0; iter.rem; xcb_rgb_next(&iter), i++) + { + pal[i] = 0xff000000 | + ((iter.data->red >> 8) << 16) | + ((iter.data->green >> 8) << 8) | + ((iter.data->blue >> 8)); + } + nret = n; + } + free(reply); + } + } + else if ((vis->_class == XCB_VISUAL_CLASS_TRUE_COLOR) || + (vis->_class == XCB_VISUAL_CLASS_DIRECT_COLOR)) + { + if ((vis->red_mask == 0x00ff0000) && + (vis->green_mask == 0x0000ff00) && + (vis->blue_mask == 0x000000ff)) + mode = argbx888; + else if ((vis->red_mask == 0x000000ff) && + (vis->green_mask == 0x0000ff00) && + (vis->blue_mask == 0x00ff0000)) + mode = abgrx888; + else if ((vis->red_mask == 0xff000000) && + (vis->green_mask == 0x00ff0000) && + (vis->blue_mask == 0x0000ff00)) + mode = rgba888x; + else if ((vis->red_mask == 0x0000ff00) && + (vis->green_mask == 0x00ff0000) && + (vis->blue_mask == 0xff000000)) + mode = bgra888x; + else if ((vis->red_mask == 0x0003f000) && + (vis->green_mask == 0x00000fc0) && + (vis->blue_mask == 0x0000003f)) + mode = argbx666; + else if ((vis->red_mask == 0x0000f800) && + (vis->green_mask == 0x000007e0) && + (vis->blue_mask == 0x0000001f)) + mode = rgb565; + else if ((vis->red_mask == 0x0000001f) && + (vis->green_mask == 0x000007e0) && + (vis->blue_mask == 0x0000f800)) + mode = bgr565; + else if ((vis->red_mask == 0x00007c00) && + (vis->green_mask == 0x000003e0) && + (vis->blue_mask == 0x0000001f)) + mode = rgbx555; + else + return EINA_FALSE; + } + for (row = 0; row < h; row++) + { + unsigned char *s8; + unsigned short *s16; + unsigned int *s32, *dp, *de; + + dp = ((unsigned int *)(((unsigned char *)dst) + + ((dy + row) * dbpl))) + dx; + de = dp + w; + switch (sbpp) + { + case 8: + s8 = ((unsigned char *)(((unsigned char *)src) + + ((y + row) * sbpl))) + x; + if (nret > 0) + { + while (dp < de) + { + *dp = pal[*s8]; + s8++; dp++; + } + } + else + return EINA_FALSE; + break; + + case 16: + s16 = ((unsigned short *)(((unsigned char *)src) + + ((y + row) * sbpl))) + x; + switch (mode) + { + case rgb565: + while (dp < de) + { + r = (*s16 & 0xf800) << 8; + g = (*s16 & 0x07e0) << 5; + b = (*s16 & 0x001f) << 3; + r |= (r >> 5) & 0xff0000; + g |= (g >> 6) & 0x00ff00; + b |= (b >> 5); + *dp = 0xff000000 | r | g | b; + s16++; dp++; + } + break; + + case bgr565: + while (dp < de) + { + r = (*s16 & 0x001f) << 19; + g = (*s16 & 0x07e0) << 5; + b = (*s16 & 0xf800) >> 8; + r |= (r >> 5) & 0xff0000; + g |= (g >> 6) & 0x00ff00; + b |= (b >> 5); + *dp = 0xff000000 | r | g | b; + s16++; dp++; + } + break; + + case rgbx555: + while (dp < de) + { + r = (*s16 & 0x7c00) << 9; + g = (*s16 & 0x03e0) << 6; + b = (*s16 & 0x001f) << 3; + r |= (r >> 5) & 0xff0000; + g |= (g >> 5) & 0x00ff00; + b |= (b >> 5); + *dp = 0xff000000 | r | g | b; + s16++; dp++; + } + break; + + default: + return EINA_FALSE; + break; + } + break; + + case 24: + case 32: + s32 = ((unsigned int *)(((unsigned char *)src) + + ((y + row) * sbpl))) + x; + switch (mode) + { + case argbx888: + while (dp < de) + { + *dp = 0xff000000 | *s32; + s32++; dp++; + } + break; + + case abgrx888: + while (dp < de) + { + r = *s32 & 0x000000ff; + g = *s32 & 0x0000ff00; + b = *s32 & 0x00ff0000; + *dp = 0xff000000 | (r << 16) | (g) | (b >> 16); + s32++; dp++; + } + break; + + case rgba888x: + while (dp < de) + { + *dp = 0xff000000 | (*s32 >> 8); + s32++; dp++; + } + break; + + case bgra888x: + while (dp < de) + { + r = *s32 & 0x0000ff00; + g = *s32 & 0x00ff0000; + b = *s32 & 0xff000000; + *dp = 0xff000000 | (r << 8) | (g >> 8) | (b >> 24); + s32++; dp++; + } + break; + + case argbx666: + while (dp < de) + { + r = (*s32 & 0x3f000) << 6; + g = (*s32 & 0x00fc0) << 4; + b = (*s32 & 0x0003f) << 2; + r |= (r >> 6) & 0xff0000; + g |= (g >> 6) & 0x00ff00; + b |= (b >> 6); + *dp = 0xff000000 | r | g | b; + s32++; dp++; + } + break; + + default: + return EINA_FALSE; + break; + } + break; + break; + + default: + return EINA_FALSE; + break; + } + } + return EINA_TRUE; +} + +/* local functions */ +static void +_ecore_xcb_image_shm_check(void) +{ +// xcb_shm_query_version_reply_t *reply; + xcb_shm_segment_info_t shminfo; + xcb_shm_get_image_cookie_t cookie; + xcb_shm_get_image_reply_t *ireply; + xcb_image_t *img = 0; + uint8_t depth = 0; + + if (_ecore_xcb_image_shm_can != -1) return; + CHECK_XCB_CONN; + + /* reply = */ + /* xcb_shm_query_version_reply(_ecore_xcb_conn, */ + /* xcb_shm_query_version(_ecore_xcb_conn), NULL); */ + /* if (!reply) */ + /* { */ + /* _ecore_xcb_image_shm_can = 0; */ + /* return; */ + /* } */ + + /* if ((reply->major_version < 1) || */ + /* ((reply->major_version == 1) && (reply->minor_version == 0))) */ + /* { */ + /* _ecore_xcb_image_shm_can = 0; */ + /* free(reply); */ + /* return; */ + /* } */ + + /* free(reply); */ + + depth = ((xcb_screen_t *)_ecore_xcb_screen)->root_depth; + + ecore_x_sync(); // needed + + img = _ecore_xcb_image_create_native(1, 1, XCB_IMAGE_FORMAT_Z_PIXMAP, + depth, NULL, ~0, NULL); + if (!img) + { + _ecore_xcb_image_shm_can = 0; + return; + } + + shminfo.shmid = + shmget(IPC_PRIVATE, img->stride * img->height, (IPC_CREAT | 0666)); + if (shminfo.shmid == (uint32_t)-1) + { + xcb_image_destroy(img); + _ecore_xcb_image_shm_can = 0; + return; + } + + shminfo.shmaddr = shmat(shminfo.shmid, 0, 0); + img->data = shminfo.shmaddr; + if (img->data == (uint8_t *)-1) + { + xcb_image_destroy(img); + _ecore_xcb_image_shm_can = 0; + return; + } + + shminfo.shmseg = xcb_generate_id(_ecore_xcb_conn); + xcb_shm_attach(_ecore_xcb_conn, shminfo.shmseg, shminfo.shmid, 0); + + cookie = + xcb_shm_get_image(_ecore_xcb_conn, + ((xcb_screen_t *)_ecore_xcb_screen)->root, + 0, 0, img->width, img->height, + 0xffffffff, img->format, + shminfo.shmseg, img->data - shminfo.shmaddr); + + ecore_x_sync(); // needed + + ireply = xcb_shm_get_image_reply(_ecore_xcb_conn, cookie, NULL); + if (ireply) + { + _ecore_xcb_image_shm_can = 1; + free(ireply); + } + else + _ecore_xcb_image_shm_can = 0; + + xcb_shm_detach(_ecore_xcb_conn, shminfo.shmseg); + xcb_image_destroy(img); + shmdt(shminfo.shmaddr); + shmctl(shminfo.shmid, IPC_RMID, 0); +} + +static void +_ecore_xcb_image_shm_create(Ecore_X_Image *im) +{ + CHECK_XCB_CONN; + + im->xim = + _ecore_xcb_image_create_native(im->w, im->h, XCB_IMAGE_FORMAT_Z_PIXMAP, + im->depth, NULL, ~0, NULL); + if (!im->xim) return; + + im->shminfo.shmid = shmget(IPC_PRIVATE, im->xim->size, (IPC_CREAT | 0666)); + if (im->shminfo.shmid == (uint32_t)-1) + { + xcb_image_destroy(im->xim); + return; + } + + im->shminfo.shmaddr = shmat(im->shminfo.shmid, 0, 0); + im->xim->data = im->shminfo.shmaddr; + if ((!im->xim->data) || (im->xim->data == (uint8_t *)-1)) + { + DBG("Shm Create No Image Data"); + xcb_image_destroy(im->xim); + shmdt(im->shminfo.shmaddr); + shmctl(im->shminfo.shmid, IPC_RMID, 0); + return; + } + + im->shminfo.shmseg = xcb_generate_id(_ecore_xcb_conn); + xcb_shm_attach(_ecore_xcb_conn, im->shminfo.shmseg, im->shminfo.shmid, 0); + + im->data = (unsigned char *)im->xim->data; + im->bpl = im->xim->stride; + im->rows = im->xim->height; + if (im->xim->bpp <= 8) + im->bpp = 1; + else if (im->xim->bpp <= 16) + im->bpp = 2; + else + im->bpp = 4; +} + +xcb_image_t * +_ecore_xcb_image_create_native(int w, + int h, + xcb_image_format_t format, + uint8_t depth, + void *base, + uint32_t bytes, + uint8_t *data) +{ + static uint8_t dpth = 0; + static xcb_format_t *fmt = NULL; + const xcb_setup_t *setup; + xcb_image_format_t xif; + + CHECK_XCB_CONN; + + /* NB: We cannot use xcb_image_create_native as it only creates images + * using MSB_FIRST, so this routine recreates that function and uses + * the endian-ness of the server setup */ + setup = xcb_get_setup(_ecore_xcb_conn); + xif = format; + + if ((xif == XCB_IMAGE_FORMAT_Z_PIXMAP) && (depth == 1)) + xif = XCB_IMAGE_FORMAT_XY_PIXMAP; + + if (dpth != depth) + { + dpth = depth; + fmt = _ecore_xcb_image_find_format(setup, depth); + if (!fmt) return 0; + } + + switch (xif) + { + case XCB_IMAGE_FORMAT_XY_BITMAP: + if (depth != 1) return 0; + + case XCB_IMAGE_FORMAT_XY_PIXMAP: + case XCB_IMAGE_FORMAT_Z_PIXMAP: + return xcb_image_create(w, h, xif, + fmt->scanline_pad, + fmt->depth, fmt->bits_per_pixel, + setup->bitmap_format_scanline_unit, + setup->image_byte_order, + setup->bitmap_format_bit_order, + base, bytes, data); + + default: + break; + } + + return 0; +} + +static xcb_format_t * +_ecore_xcb_image_find_format(const xcb_setup_t *setup, + uint8_t depth) +{ + xcb_format_t *fmt, *fmtend; + + CHECK_XCB_CONN; + + fmt = xcb_setup_pixmap_formats(setup); + fmtend = fmt + xcb_setup_pixmap_formats_length(setup); + for (; fmt != fmtend; ++fmt) + if (fmt->depth == depth) + return fmt; + + return 0; +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_input.c b/src/lib/ecore_x/xcb/ecore_xcb_input.c new file mode 100644 index 0000000..c0338c2 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_input.c @@ -0,0 +1,274 @@ +#include "ecore_xcb_private.h" +#ifdef ECORE_XCB_XINPUT +# include +# include +#endif + +/* FIXME: this is a guess. can't find defines for touch events in xcb libs + * online */ +/* these are not yet defined in xcb support for xi2 - so manually create */ +#ifndef XCB_INPUT_DEVICE_TOUCH_BEGIN +#define XCB_INPUT_DEVICE_TOUCH_BEGIN 18 +#endif +#ifndef XCB_INPUT_DEVICE_TOUCH_END +#define XCB_INPUT_DEVICE_TOUCH_END 19 +#endif +#ifndef XCB_INPUT_DEVICE_TOUCH_UPDATE +#define XCB_INPUT_DEVICE_TOUCH_UPDATE 21 +#endif + +#ifndef XCB_INPUT_POINTER_EMULATED_MASK +#define XCB_INPUT_POINTER_EMULATED_MASK (1 << 16) +#endif + +/* local variables */ +static Eina_Bool _input_avail = EINA_FALSE; + +/* external variables */ +int _ecore_xcb_event_input = 0; + +void +_ecore_xcb_input_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_XINPUT + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_input_id); +#endif +} + +void +_ecore_xcb_input_finalize(void) +{ +#ifdef ECORE_XCB_XINPUT + xcb_input_get_extension_version_cookie_t cookie; + xcb_input_get_extension_version_reply_t *reply; + char buff[128]; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_XINPUT + cookie = + xcb_input_get_extension_version_unchecked(_ecore_xcb_conn, 127, buff); + reply = + xcb_input_get_extension_version_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + _input_avail = EINA_TRUE; + free(reply); + } + + if (_input_avail) + { + const xcb_query_extension_reply_t *ext_reply; + + ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_input_id); + if (ext_reply) + _ecore_xcb_event_input = ext_reply->first_event; + } +#endif +} + +void +_ecore_xcb_input_shutdown(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); +} + +void +#ifdef ECORE_XCB_XINPUT +_ecore_xcb_input_handle_event(xcb_generic_event_t *event) +#else +_ecore_xcb_input_handle_event(xcb_generic_event_t * event __UNUSED__) +#endif +{ +#ifdef ECORE_XCB_XINPUT + xcb_ge_event_t *ev; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + /* FIXME: look at xlib ecore_x_xi2.c to copy logic in when i can find an + * xcb-input lib to test with */ +#ifdef ECORE_XCB_XINPUT + ev = (xcb_ge_event_t *)event; + switch (ev->event_type) + { + case XCB_INPUT_DEVICE_MOTION_NOTIFY: + { + xcb_input_device_motion_notify_event_t *de; + unsigned int child_win = 0; + + de = (xcb_input_device_motion_notify_event_t *)ev->pad1; + child_win = (de->child ? de->child : de->event); + _ecore_xcb_event_mouse_move(de->time, de->state, de->event_x, + de->event_y, de->root_x, de->root_y, + de->event, child_win, de->root, + de->same_screen, de->device_id, + 1, 1, 1.0, 0.0, + de->event_x, de->event_y, + de->root_x, de->root_y); + } + break; + + case XCB_INPUT_DEVICE_BUTTON_PRESS: + { + xcb_input_device_button_press_event_t *de; + unsigned int child_win = 0; + + de = (xcb_input_device_button_press_event_t *)ev->pad1; + child_win = (de->child ? de->child : de->event); + _ecore_xcb_event_mouse_button(ECORE_EVENT_MOUSE_BUTTON_DOWN, + de->time, de->state, de->detail, + de->event_x, de->event_y, + de->root_x, de->root_y, de->event, + child_win, de->root, + de->same_screen, de->device_id, + 1, 1, 1.0, 0.0, + de->event_x, de->event_y, + de->root_x, de->root_y); + } + break; + + case XCB_INPUT_DEVICE_BUTTON_RELEASE: + { + xcb_input_device_button_release_event_t *de; + unsigned int child_win = 0; + + de = (xcb_input_device_button_release_event_t *)ev->pad1; + child_win = (de->child ? de->child : de->event); + _ecore_xcb_event_mouse_button(ECORE_EVENT_MOUSE_BUTTON_UP, + de->time, de->state, de->detail, + de->event_x, de->event_y, + de->root_x, de->root_y, de->event, + child_win, de->root, + de->same_screen, de->device_id, + 1, 1, 1.0, 0.0, + de->event_x, de->event_y, + de->root_x, de->root_y); + } + break; + + case XCB_INPUT_DEVICE_TOUCH_UPDATE: + { + xcb_input_device_motion_notify_event_t *de; + unsigned int child_win = 0; + + de = (xcb_input_device_motion_notify_event_t *)ev->pad1; + child_win = (de->child ? de->child : de->event); + _ecore_xcb_event_mouse_move(de->time, de->state, de->event_x, + de->event_y, de->root_x, de->root_y, + de->event, child_win, de->root, + de->same_screen, de->device_id, + 1, 1, 1.0, 0.0, + de->event_x, de->event_y, + de->root_x, de->root_y); + } + break; + + case XCB_INPUT_DEVICE_TOUCH_BEGIN: + { + xcb_input_device_button_press_event_t *de; + unsigned int child_win = 0; + + de = (xcb_input_device_button_press_event_t *)ev->pad1; + child_win = (de->child ? de->child : de->event); + _ecore_xcb_event_mouse_button(ECORE_EVENT_MOUSE_BUTTON_DOWN, + de->time, de->state, de->detail, + de->event_x, de->event_y, + de->root_x, de->root_y, de->event, + child_win, de->root, + de->same_screen, de->device_id, + 1, 1, 1.0, 0.0, + de->event_x, de->event_y, + de->root_x, de->root_y); + } + break; + + case XCB_INPUT_DEVICE_TOUCH_END: + { + xcb_input_device_button_release_event_t *de; + unsigned int child_win = 0; + + de = (xcb_input_device_button_release_event_t *)ev->pad1; + child_win = (de->child ? de->child : de->event); + _ecore_xcb_event_mouse_button(ECORE_EVENT_MOUSE_BUTTON_UP, + de->time, de->state, de->detail, + de->event_x, de->event_y, + de->root_x, de->root_y, de->event, + child_win, de->root, + de->same_screen, de->device_id, + 1, 1, 1.0, 0.0, + de->event_x, de->event_y, + de->root_x, de->root_y); + } + break; + + default: + break; + } +#endif +} + +EAPI Eina_Bool +ecore_x_input_multi_select(Ecore_X_Window win) +{ + Eina_Bool find = EINA_FALSE; +#ifdef ECORE_XCB_XINPUT + xcb_input_list_input_devices_cookie_t dcookie; + xcb_input_list_input_devices_reply_t *dreply; + xcb_input_device_info_iterator_t diter; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_input_avail) return EINA_FALSE; + + /* FIXME: i can't seemingly test this! no xcb input lib so can't look and + * test and look at types etc. - look at xlib code and copy logic over + * when we can */ +#ifdef ECORE_XCB_XINPUT + dcookie = xcb_input_list_input_devices_unchecked(_ecore_xcb_conn); + dreply = + xcb_input_list_input_devices_reply(_ecore_xcb_conn, dcookie, NULL); + if (!dreply) return EINA_FALSE; + + diter = xcb_input_list_input_devices_devices_iterator(dreply); + while (diter.rem) + { + xcb_input_device_info_t *dev; + const xcb_input_event_class_t iclass[] = + { + XCB_INPUT_DEVICE_BUTTON_PRESS, + XCB_INPUT_DEVICE_BUTTON_RELEASE, + XCB_INPUT_DEVICE_MOTION_NOTIFY, + XCB_INPUT_DEVICE_TOUCH_BEGIN, + XCB_INPUT_DEVICE_TOUCH_END, + XCB_INPUT_DEVICE_TOUCH_UPDATE + }; + + dev = diter.data; + if (dev->device_use == XCB_INPUT_DEVICE_USE_IS_X_EXTENSION_DEVICE) + { + DBG("Device %d", dev->device_id); + DBG("\tType: %d", dev->device_type); + DBG("\tNum Classes: %d", dev->num_class_info); + DBG("\tUse: %d", dev->device_use); + + xcb_input_select_extension_event(_ecore_xcb_conn, win, + sizeof(iclass) / sizeof(xcb_input_event_class_t), + iclass); + find = EINA_TRUE; + } + xcb_input_device_info_next(&diter); + } + free(dreply); +#endif + + return find; + win = 0; +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_keymap.c b/src/lib/ecore_x/xcb/ecore_xcb_keymap.c new file mode 100644 index 0000000..6c11246 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_keymap.c @@ -0,0 +1,491 @@ +#include "ecore_xcb_private.h" +#define NEED_KEYSYM_TABLE +#define NEED_VTABLE +#include "ecore_xcb_keysym_table.h" +#include +#include + +/* local function prototypes */ +static int _ecore_xcb_keymap_mask_get(void *reply, + xcb_keysym_t sym); +static xcb_keysym_t _ecore_xcb_keymap_string_to_keysym(const char *str); +static int _ecore_xcb_keymap_translate_key(xcb_keycode_t keycode, + unsigned int modifiers, + unsigned int *modifiers_return, + xcb_keysym_t *keysym_return); +static int _ecore_xcb_keymap_translate_keysym(xcb_keysym_t keysym, + unsigned int modifiers, + char *buffer, + int bytes); + +/* local variables */ +static xcb_key_symbols_t *_ecore_xcb_keysyms; +static int _ecore_xcb_mode_switch = 0; + +/* public variables */ +EAPI int ECORE_X_MODIFIER_SHIFT = 0; +EAPI int ECORE_X_MODIFIER_CTRL = 0; +EAPI int ECORE_X_MODIFIER_ALT = 0; +EAPI int ECORE_X_MODIFIER_WIN = 0; +EAPI int ECORE_X_MODIFIER_ALTGR = 0; +EAPI int ECORE_X_LOCK_SCROLL = 0; +EAPI int ECORE_X_LOCK_NUM = 0; +EAPI int ECORE_X_LOCK_CAPS = 0; +EAPI int ECORE_X_LOCK_SHIFT = 0; + +void +_ecore_xcb_keymap_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_xcb_keysyms = xcb_key_symbols_alloc(_ecore_xcb_conn); +} + +void +_ecore_xcb_keymap_finalize(void) +{ + xcb_get_modifier_mapping_cookie_t cookie; + xcb_get_modifier_mapping_reply_t *reply; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + cookie = xcb_get_modifier_mapping_unchecked(_ecore_xcb_conn); + reply = xcb_get_modifier_mapping_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) + { + xcb_key_symbols_free(_ecore_xcb_keysyms); + return; + } + + _ecore_xcb_mode_switch = _ecore_xcb_keymap_mask_get(reply, XK_Mode_switch); + + ECORE_X_MODIFIER_SHIFT = _ecore_xcb_keymap_mask_get(reply, XK_Shift_L); + ECORE_X_MODIFIER_CTRL = _ecore_xcb_keymap_mask_get(reply, XK_Control_L); + + ECORE_X_MODIFIER_ALT = _ecore_xcb_keymap_mask_get(reply, XK_Alt_L); + if (!ECORE_X_MODIFIER_ALT) + ECORE_X_MODIFIER_ALT = _ecore_xcb_keymap_mask_get(reply, XK_Meta_L); + if (!ECORE_X_MODIFIER_ALT) + ECORE_X_MODIFIER_ALT = _ecore_xcb_keymap_mask_get(reply, XK_Super_L); + + ECORE_X_MODIFIER_WIN = _ecore_xcb_keymap_mask_get(reply, XK_Super_L); + if (!ECORE_X_MODIFIER_WIN) + ECORE_X_MODIFIER_WIN = _ecore_xcb_keymap_mask_get(reply, XK_Meta_L); + + ECORE_X_MODIFIER_ALTGR = _ecore_xcb_keymap_mask_get(reply, XK_Mode_switch); + + if (ECORE_X_MODIFIER_WIN == ECORE_X_MODIFIER_ALT) + ECORE_X_MODIFIER_WIN = 0; + if (ECORE_X_MODIFIER_ALT == ECORE_X_MODIFIER_CTRL) + ECORE_X_MODIFIER_ALT = 0; + + ECORE_X_LOCK_SCROLL = _ecore_xcb_keymap_mask_get(reply, XK_Scroll_Lock); + ECORE_X_LOCK_NUM = _ecore_xcb_keymap_mask_get(reply, XK_Num_Lock); + ECORE_X_LOCK_CAPS = _ecore_xcb_keymap_mask_get(reply, XK_Caps_Lock); + ECORE_X_LOCK_SHIFT = _ecore_xcb_keymap_mask_get(reply, XK_Shift_Lock); +} + +void +_ecore_xcb_modifiers_get(void) +{ + _ecore_xcb_keymap_finalize(); +} + +void +_ecore_xcb_keymap_shutdown(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (_ecore_xcb_keysyms) xcb_key_symbols_free(_ecore_xcb_keysyms); +} + +void +_ecore_xcb_keymap_refresh(xcb_mapping_notify_event_t *event) +{ + CHECK_XCB_CONN; + xcb_refresh_keyboard_mapping(_ecore_xcb_keysyms, event); +} + +xcb_keysym_t +_ecore_xcb_keymap_keycode_to_keysym(xcb_keycode_t keycode, + int col) +{ + xcb_keysym_t key0, key1; + + CHECK_XCB_CONN; + if (col & _ecore_xcb_mode_switch) + { + key0 = xcb_key_symbols_get_keysym(_ecore_xcb_keysyms, keycode, 4); + key1 = xcb_key_symbols_get_keysym(_ecore_xcb_keysyms, keycode, 5); + } + else + { + key0 = xcb_key_symbols_get_keysym(_ecore_xcb_keysyms, keycode, 0); + key1 = xcb_key_symbols_get_keysym(_ecore_xcb_keysyms, keycode, 1); + } + + if (key1 == XCB_NO_SYMBOL) + key1 = key0; + + if ((col & ECORE_X_LOCK_NUM) && + ((xcb_is_keypad_key(key1)) || (xcb_is_private_keypad_key(key1)))) + { + if ((col & XCB_MOD_MASK_SHIFT) || + ((col & XCB_MOD_MASK_LOCK) && (col & ECORE_X_LOCK_SHIFT))) + return key0; + else + return key1; + } + else if (!(col & XCB_MOD_MASK_SHIFT) && !(col & XCB_MOD_MASK_LOCK)) + return key0; + else if (!(col & XCB_MOD_MASK_SHIFT) && + (col & XCB_MOD_MASK_LOCK && (col & ECORE_X_LOCK_CAPS))) + return key1; + else if ((col & XCB_MOD_MASK_SHIFT) && + (col & XCB_MOD_MASK_LOCK) && (col & ECORE_X_LOCK_CAPS)) + return key0; + else if ((col & XCB_MOD_MASK_SHIFT) || + (col & XCB_MOD_MASK_LOCK && (col & ECORE_X_LOCK_SHIFT))) + return key1; + + return XCB_NO_SYMBOL; +} + +xcb_keycode_t * +_ecore_xcb_keymap_keysym_to_keycode(xcb_keysym_t keysym) +{ + CHECK_XCB_CONN; + return xcb_key_symbols_get_keycode(_ecore_xcb_keysyms, keysym); +} + +char * +_ecore_xcb_keymap_keysym_to_string(xcb_keysym_t keysym) +{ + int i = 0, n = 0, h = 0, idx = 0; + const unsigned char *entry; + unsigned char val1, val2, val3, val4; + + CHECK_XCB_CONN; + if (!keysym) return NULL; + if (keysym == XK_VoidSymbol) keysym = 0; + if (keysym <= 0x1fffffff) + { + val1 = (keysym >> 24); + val2 = ((keysym >> 16) & 0xff); + val3 = ((keysym >> 8) & 0xff); + val4 = (keysym & 0xff); + i = keysym % VTABLESIZE; + h = i + 1; + n = VMAXHASH; + while ((idx = hashKeysym[i])) + { + entry = &_ecore_xcb_keytable[idx]; + if ((entry[0] == val1) && (entry[1] == val2) && + (entry[2] == val3) && (entry[3] == val4)) + return (char *)entry + 4; + if (!--n) break; + i += h; + if (i >= VTABLESIZE) i -= VTABLESIZE; + } + } + + if ((keysym >= 0x01000100) && (keysym <= 0x0110ffff)) + { + xcb_keysym_t val; + char *s = NULL; + int i = 0; + + val = (keysym & 0xffffff); + if (val & 0xff0000) + i = 10; + else + i = 6; + + if (!(s = malloc(i))) return NULL; + i--; + s[i--] = '\0'; + for (; i; i--) + { + val1 = (val & 0xf); + val >>= 4; + if (val1 < 10) + s[i] = '0' + val1; + else + s[i] = 'A' + val1 - 10; + } + s[i] = 'U'; + return s; + } + + return NULL; +} + +xcb_keycode_t +_ecore_xcb_keymap_string_to_keycode(const char *key) +{ + if (!strncmp(key, "Keycode-", 8)) + return atoi(key + 8); + else + { + xcb_keysym_t keysym = XCB_NO_SYMBOL; + xcb_keycode_t *keycodes, keycode = 0; + int i = 0; + + CHECK_XCB_CONN; + + keysym = _ecore_xcb_keymap_string_to_keysym(key); + if (keysym == XCB_NO_SYMBOL) return XCB_NO_SYMBOL; + + keycodes = _ecore_xcb_keymap_keysym_to_keycode(keysym); + if (!keycodes) return XCB_NO_SYMBOL; + + while (keycodes[i] != XCB_NO_SYMBOL) + { + if (keycodes[i] != 0) + { + keycode = keycodes[i]; + break; + } + i++; + } + return keycode; + } +} + +int +_ecore_xcb_keymap_lookup_string(xcb_keycode_t keycode, + int state, + char *buffer, + int bytes, + xcb_keysym_t *sym) +{ + unsigned int modifiers = 0; + xcb_keysym_t keysym; + + CHECK_XCB_CONN; + if (!_ecore_xcb_keymap_translate_key(keycode, state, &modifiers, &keysym)) + return 0; + + if (sym) *sym = keysym; + + return _ecore_xcb_keymap_translate_keysym(keysym, state, buffer, bytes); +} + +EAPI const char * +ecore_x_keysym_string_get(int keysym) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _ecore_xcb_keymap_keysym_to_string(keysym); +} + +EAPI int +ecore_x_keysym_keycode_get(const char *keyname) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _ecore_xcb_keymap_string_to_keycode(keyname); +} + +/* local functions */ +static int +_ecore_xcb_keymap_mask_get(void *reply, + xcb_keysym_t sym) +{ + xcb_get_modifier_mapping_reply_t *rep; + xcb_keysym_t sym2; + int mask = 0; + const int masks[8] = + { + XCB_MOD_MASK_SHIFT, XCB_MOD_MASK_LOCK, XCB_MOD_MASK_CONTROL, + XCB_MOD_MASK_1, XCB_MOD_MASK_2, XCB_MOD_MASK_3, XCB_MOD_MASK_4, + XCB_MOD_MASK_5 + }; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + rep = (xcb_get_modifier_mapping_reply_t *)reply; + if ((rep) && (rep->keycodes_per_modifier > 0)) + { + int i = 0; + xcb_keycode_t *modmap; + + modmap = xcb_get_modifier_mapping_keycodes(rep); + for (i = 0; i < (8 * rep->keycodes_per_modifier); i++) + { + int j = 0; + + for (j = 0; j < 8; j++) + { + sym2 = + xcb_key_symbols_get_keysym(_ecore_xcb_keysyms, + modmap[i], j); + if (sym2 != 0) break; + } + if (sym2 == sym) + { + mask = masks[i / rep->keycodes_per_modifier]; + break; + } + } + } + + return mask; +} + +static xcb_keysym_t +_ecore_xcb_keymap_string_to_keysym(const char *str) +{ + int i = 0, n = 0, h = 0; + unsigned long sig = 0; + const char *p = NULL; + int c = 0, idx = 0; + const unsigned char *entry; + unsigned char sig1, sig2; + long unsigned int val; + + p = str; + while ((c = *p++)) + sig = (sig << 1) + c; + + i = (sig % KTABLESIZE); + h = i + 1; + sig1 = (sig >> 8) & 0xff; + sig2 = sig & 0xff; + n = KMAXHASH; + + while ((idx = hashString[i])) + { + entry = &_ecore_xcb_keytable[idx]; + if ((entry[0] == sig1) && (entry[1] == sig2) && + !strcmp(str, (char *)entry + 6)) + { + val = ((entry[2] << 24) | (entry[3] << 16) | + (entry[4] << 8) | (entry[5])); + if (!val) val = 0xffffff; + return val; + } + if (!--n) break; + i += h; + if (i >= KTABLESIZE) i -= KTABLESIZE; + } + + if (*str == 'U') + { + val = 0; + for (p = &str[1]; *p; p++) + { + c = *p; + if (('0' <= c) && (c <= '9')) + val = (val << 4) + c - '0'; + else if (('a' <= c) && (c <= 'f')) + val = (val << 4) + c - 'a' + 10; + else if (('A' <= c) && (c <= 'F')) + val = (val << 4) + c - 'A' + 10; + else + return XCB_NO_SYMBOL; + if (val > 0x10ffff) return XCB_NO_SYMBOL; + } + if ((val < 0x20) || ((val > 0x7e) && (val < 0xa0))) + return XCB_NO_SYMBOL; + if (val < 0x100) return val; + return val | 0x01000000; + } + + if ((strlen(str) > 2) && (str[0] == '0') && (str[1] == 'x')) + { + char *tmp = NULL; + + val = strtoul(str, &tmp, 16); + if ((val == ULONG_MAX) || ((tmp) && (*tmp != '\0'))) + return XCB_NO_SYMBOL; + else + return val; + } + + if (!strncmp(str, "XF86_", 5)) + { + long unsigned int ret; + char *tmp; + + tmp = strdup(str); + if (!tmp) return XCB_NO_SYMBOL; + memmove(&tmp[4], &tmp[5], strlen(str) - 5 + 1); + ret = _ecore_xcb_keymap_string_to_keysym(tmp); + free(tmp); + return ret; + } + + return XCB_NO_SYMBOL; +} + +static int +_ecore_xcb_keymap_translate_key(xcb_keycode_t keycode, + unsigned int modifiers, + unsigned int *modifiers_return, + xcb_keysym_t *keysym_return) +{ + xcb_keysym_t sym; + + if (!_ecore_xcb_keysyms) return 0; + + sym = _ecore_xcb_keymap_keycode_to_keysym(keycode, modifiers); + + if (modifiers_return) + *modifiers_return = ((XCB_MOD_MASK_SHIFT | XCB_MOD_MASK_LOCK) | + _ecore_xcb_mode_switch | ECORE_X_LOCK_NUM); + if (keysym_return) + *keysym_return = sym; + + return 1; +} + +static int +_ecore_xcb_keymap_translate_keysym(xcb_keysym_t keysym, + unsigned int modifiers, + char *buffer, + int bytes) +{ + unsigned long hbytes = 0; + unsigned char c; + + if (!keysym) return 0; + hbytes = (keysym >> 8); + + if (!(bytes && + ((hbytes == 0) || + ((hbytes == 0xFF) && + (((keysym >= XK_BackSpace) && (keysym <= XK_Clear)) || + (keysym == XK_Return) || (keysym == XK_Escape) || + (keysym == XK_KP_Space) || (keysym == XK_KP_Tab) || + (keysym == XK_KP_Enter) || + ((keysym >= XK_KP_Multiply) && (keysym <= XK_KP_9)) || + (keysym == XK_KP_Equal) || (keysym == XK_Delete)))))) + return 0; + + if (keysym == XK_KP_Space) + c = (XK_space & 0x7F); + else if (hbytes == 0xFF) + c = (keysym & 0x7F); + else + c = (keysym & 0xFF); + + if (modifiers & ECORE_X_MODIFIER_CTRL) + { + if (((c >= '@') && (c < '\177')) || c == ' ') + c &= 0x1F; + else if (c == '2') + c = '\000'; + else if ((c >= '3') && (c <= '7')) + c -= ('3' - '\033'); + else if (c == '8') + c = '\177'; + else if (c == '/') + c = '_' & 0x1F; + } + buffer[0] = c; + return 1; +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_mwm.c b/src/lib/ecore_x/xcb/ecore_xcb_mwm.c new file mode 100644 index 0000000..6c95331 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_mwm.c @@ -0,0 +1,104 @@ +#include "ecore_xcb_private.h" +//#include "Ecore_X_Atoms.h" + +#define ECORE_X_MWM_HINTS_FUNCTIONS (1 << 0) +#define ECORE_X_MWM_HINTS_DECORATIONS (1 << 1) +#define ECORE_X_MWM_HINTS_INPUT_MODE (1 << 2) +#define ECORE_X_MWM_HINTS_STATUS (1 << 3) + +typedef struct _mwmhints +{ + uint32_t flags; + uint32_t functions; + uint32_t decorations; + int32_t inputmode; + uint32_t status; +} MWMHints; + +/** + * @defgroup Ecore_X_MWM_Group MWM related functions. + * + * Functions related to MWM. + */ + +/** + * Sets the borderless flag of a window using MWM. + * + * @param win The window. + * @param borderless The borderless flag. + * + * @ingroup Ecore_X_MWM_Group + */ +EAPI void +ecore_x_mwm_borderless_set(Ecore_X_Window win, + Eina_Bool borderless) +{ + uint32_t data[5] = { 0, 0, 0, 0, 0 }; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + data[0] = 2; + data[2] = !borderless; + + ecore_x_window_prop_property_set(win, + ECORE_X_ATOM_MOTIF_WM_HINTS, + ECORE_X_ATOM_MOTIF_WM_HINTS, 32, + (void *)data, 5); +} + +EAPI Eina_Bool +ecore_x_mwm_hints_get(Ecore_X_Window win, + Ecore_X_MWM_Hint_Func *fhint, + Ecore_X_MWM_Hint_Decor *dhint, + Ecore_X_MWM_Hint_Input *ihint) +{ + xcb_get_property_cookie_t cookie; + xcb_get_property_reply_t *reply; + MWMHints *mwmhints = NULL; + int ret = EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + cookie = + xcb_get_property_unchecked(_ecore_xcb_conn, 0, win, + ECORE_X_ATOM_MOTIF_WM_HINTS, + ECORE_X_ATOM_MOTIF_WM_HINTS, 0, UINT_MAX); + reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return EINA_FALSE; + if ((reply->format != 32) || (reply->value_len == 0)) + { + free(reply); + return EINA_FALSE; + } + + mwmhints = xcb_get_property_value(reply); + if (reply->value_len >= 4) + { + if (dhint) + { + if (mwmhints->flags & ECORE_X_MWM_HINTS_DECORATIONS) + *dhint = mwmhints->decorations; + else + *dhint = ECORE_X_MWM_HINT_DECOR_ALL; + } + if (fhint) + { + if (mwmhints->flags & ECORE_X_MWM_HINTS_FUNCTIONS) + *fhint = mwmhints->functions; + else + *fhint = ECORE_X_MWM_HINT_FUNC_ALL; + } + if (ihint) + { + if (mwmhints->flags & ECORE_X_MWM_HINTS_INPUT_MODE) + *ihint = mwmhints->inputmode; + else + *ihint = ECORE_X_MWM_HINT_INPUT_MODELESS; + } + ret = EINA_TRUE; + } + free(reply); + return ret; +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_netwm.c b/src/lib/ecore_x/xcb/ecore_xcb_netwm.c new file mode 100644 index 0000000..954e663 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_netwm.c @@ -0,0 +1,1604 @@ +#include "ecore_xcb_private.h" + +/* local function prototypes */ +/* static void _ecore_xcb_netwm_startup_info_free(void *data); */ +static Ecore_X_Atom _ecore_xcb_netwm_window_type_atom_get(Ecore_X_Window_Type type); +static Ecore_X_Window_Type _ecore_xcb_netwm_window_type_type_get(Ecore_X_Atom atom); +static Ecore_X_Atom _ecore_xcb_netwm_window_state_atom_get(Ecore_X_Window_State state); +static Ecore_X_Atom _ecore_xcb_netwm_action_atom_get(Ecore_X_Action action); + +/* local variables */ +//static Eina_Hash *_startup_info = NULL; + +/* local structures */ +typedef struct _Ecore_Xcb_Startup_Info Ecore_Xcb_Startup_Info; +struct _Ecore_Xcb_Startup_Info +{ + Ecore_X_Window win; + int init, size; + char *buffer; + int length; + + /* sequence info fields */ + char *id, *name; + int screen; + char *bin, *icon; + int desktop, timestamp; + char *description, *wmclass; + int silent; +}; + +EAPI void +ecore_x_netwm_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +// _startup_info = +// eina_hash_string_superfast_new(_ecore_xcb_netwm_startup_info_free); +} + +EAPI void +ecore_x_netwm_shutdown(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +// if (_startup_info) eina_hash_free(_startup_info); +// _startup_info = NULL; +} + +EAPI Eina_Bool +ecore_x_netwm_pid_get(Ecore_X_Window win, + int *pid) +{ + uint32_t tmp; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_PID, &tmp, 1)) + return EINA_FALSE; + + if (pid) *pid = tmp; + + return EINA_TRUE; +} + +EAPI void +ecore_x_netwm_pid_set(Ecore_X_Window win, + int pid) +{ + unsigned int tmp; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + tmp = pid; + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_PID, &tmp, 1); +} + +EAPI Eina_Bool +ecore_x_netwm_window_type_get(Ecore_X_Window win, + Ecore_X_Window_Type *type) +{ + Ecore_X_Atom *atoms; + int num = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (type) *type = ECORE_X_WINDOW_TYPE_NORMAL; + + num = + ecore_x_window_prop_atom_list_get(win, + ECORE_X_ATOM_NET_WM_WINDOW_TYPE, &atoms); + if ((type) && (num >= 1) && (atoms)) + *type = _ecore_xcb_netwm_window_type_type_get(atoms[0]); + + if (atoms) free(atoms); + + if (num >= 1) return EINA_TRUE; + return EINA_FALSE; +} + +EAPI void +ecore_x_netwm_window_type_set(Ecore_X_Window win, + Ecore_X_Window_Type type) +{ + Ecore_X_Atom atom; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + atom = _ecore_xcb_netwm_window_type_atom_get(type); + ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_NET_WM_WINDOW_TYPE, &atom, 1); +} + +EAPI int +ecore_x_netwm_window_types_get(Ecore_X_Window win, + Ecore_X_Window_Type **types) +{ + int num = 0, i = 0; + Ecore_X_Atom *atoms = NULL; + Ecore_X_Window_Type *atoms2 = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (types) *types = NULL; + num = + ecore_x_window_prop_atom_list_get(win, ECORE_X_ATOM_NET_WM_WINDOW_TYPE, + &atoms); + if ((num <= 0) || (!atoms)) + { + if (atoms) free(atoms); + return 0; + } + + atoms2 = malloc(num * sizeof(Ecore_X_Window_Type)); + if (!atoms2) + { + if (atoms) free(atoms); + return 0; + } + + for (i = 0; i < num; i++) + atoms2[i] = _ecore_xcb_netwm_window_type_type_get(atoms[i]); + if (atoms) free(atoms); + + if (types) + *types = atoms2; + else + free(atoms2); + + return num; +} + +EAPI int +ecore_x_netwm_name_get(Ecore_X_Window win, + char **name) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (name) + *name = ecore_x_window_prop_string_get(win, ECORE_X_ATOM_NET_WM_NAME); + return 1; +} + +EAPI void +ecore_x_netwm_name_set(Ecore_X_Window win, + const char *name) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_string_set(win, ECORE_X_ATOM_NET_WM_NAME, name); +} + +EAPI void +ecore_x_netwm_opacity_set(Ecore_X_Window win, + unsigned int opacity) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_WINDOW_OPACITY, + &opacity, 1); +} + +EAPI Eina_Bool +ecore_x_netwm_opacity_get(Ecore_X_Window win, + unsigned int *opacity) +{ + unsigned int tmp = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_WINDOW_OPACITY, + &tmp, 1)) + return EINA_FALSE; + + if (opacity) *opacity = tmp; + + return EINA_TRUE; +} + +EAPI void +ecore_x_netwm_wm_identify(Ecore_X_Window root, + Ecore_X_Window check, + const char *wm_name) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_window_set(check, ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK, + &check, 1); + ecore_x_window_prop_string_set(check, ECORE_X_ATOM_NET_WM_NAME, wm_name); + ecore_x_window_prop_string_set(root, ECORE_X_ATOM_NET_WM_NAME, wm_name); + ecore_x_window_prop_window_set(root, ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK, + &check, 1); +} + +EAPI void +ecore_x_netwm_supported_set(Ecore_X_Window root, + Ecore_X_Atom *supported, + int num) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_atom_set(root, ECORE_X_ATOM_NET_SUPPORTED, + supported, num); +} + +EAPI Eina_Bool +ecore_x_netwm_supported_get(Ecore_X_Window root, + Ecore_X_Atom **supported, + int *num) +{ + int num_ret = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (num) *num = 0; + if (supported) *supported = NULL; + + num_ret = + ecore_x_window_prop_atom_list_get(root, ECORE_X_ATOM_NET_SUPPORTED, + supported); + if (num_ret <= 0) return EINA_FALSE; + if (num) *num = num_ret; + + return EINA_TRUE; +} + +EAPI void +ecore_x_netwm_desk_count_set(Ecore_X_Window root, + unsigned int n_desks) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_NUMBER_OF_DESKTOPS, + &n_desks, 1); +} + +EAPI void +ecore_x_netwm_desk_roots_set(Ecore_X_Window root, + Ecore_X_Window *vroots, + unsigned int n_desks) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_window_set(root, ECORE_X_ATOM_NET_VIRTUAL_ROOTS, + vroots, n_desks); +} + +EAPI void +ecore_x_netwm_desk_names_set(Ecore_X_Window root, + const char **names, + unsigned int n_desks) +{ + char ss[32], *buf = NULL, *t = NULL; + const char *s; + uint32_t len = 0, i, l; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + for (i = 0; i < n_desks; i++) + { + s = ((names) ? names[i] : NULL); + if (!s) + { + /* Default to "Desk-" */ + sprintf(ss, "Desk-%d", i); + s = ss; + } + + l = strlen(s) + 1; + t = realloc(buf, len + 1); + if (t) + { + buf = t; + memcpy(buf + len, s, l); + } + len += l; + } + + xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, root, + ECORE_X_ATOM_NET_DESKTOP_NAMES, + ECORE_X_ATOM_UTF8_STRING, 8, len, (const void *)buf); +// ecore_x_flush(); + free(buf); +} + +EAPI void +ecore_x_netwm_desk_size_set(Ecore_X_Window root, + unsigned int width, + unsigned int height) +{ + uint32_t size[2]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + size[0] = width; + size[1] = height; + ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_DESKTOP_GEOMETRY, + size, 2); +} + +EAPI void +ecore_x_netwm_desk_viewports_set(Ecore_X_Window root, + unsigned int *origins, + unsigned int n_desks) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_DESKTOP_VIEWPORT, + origins, (2 * n_desks)); +} + +EAPI void +ecore_x_netwm_desk_layout_set(Ecore_X_Window root, + int orientation, + int columns, + int rows, + int starting_corner) +{ + unsigned int layout[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + layout[0] = orientation; + layout[1] = columns; + layout[2] = rows; + layout[3] = starting_corner; + ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_DESKTOP_LAYOUT, + layout, 4); +} + +EAPI void +ecore_x_netwm_desk_workareas_set(Ecore_X_Window root, + unsigned int *areas, + unsigned int n_desks) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_WORKAREA, areas, + 4 * n_desks); +} + +EAPI unsigned int * +ecore_x_netwm_desk_workareas_get(Ecore_X_Window root, unsigned int *n_desks) +{ + int ret; + unsigned int *areas = NULL; + + if (!root) root = ((xcb_screen_t *)_ecore_xcb_screen)->root; + + ret = ecore_x_window_prop_card32_list_get(root, ECORE_X_ATOM_NET_WORKAREA, + &areas); + if (!areas) + { + if (n_desks) *n_desks = 0; + return 0; + } + if (n_desks) *n_desks = ret / 4; + return areas; +} + +EAPI void +ecore_x_netwm_desk_current_set(Ecore_X_Window root, + unsigned int desk) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_CURRENT_DESKTOP, + &desk, 1); +} + +EAPI void +ecore_x_netwm_showing_desktop_set(Ecore_X_Window root, + Eina_Bool on) +{ + unsigned int val = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + val = ((on) ? 1 : 0); + ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_SHOWING_DESKTOP, + &val, 1); +} + +EAPI int +ecore_x_netwm_startup_id_get(Ecore_X_Window win, + char **id) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (id) + { + *id = + ecore_x_window_prop_string_get(win, ECORE_X_ATOM_NET_STARTUP_ID); + } + + return 1; +} + +EAPI void +ecore_x_netwm_startup_id_set(Ecore_X_Window win, + const char *id) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_string_set(win, ECORE_X_ATOM_NET_STARTUP_ID, id); +} + +EAPI void +ecore_x_netwm_state_request_send(Ecore_X_Window win, + Ecore_X_Window root, + Ecore_X_Window_State s1, + Ecore_X_Window_State s2, + Eina_Bool set) +{ + xcb_client_message_event_t ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!win) return; + if (!root) root = ((xcb_screen_t *)_ecore_xcb_screen)->root; + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 32; + ev.window = win; + ev.type = ECORE_X_ATOM_NET_WM_STATE; + ev.data.data32[0] = !!set; + ev.data.data32[1] = _ecore_xcb_netwm_window_state_atom_get(s1); + ev.data.data32[2] = _ecore_xcb_netwm_window_state_atom_get(s2); + /* 1 == normal client, if used in a pager this should be 2 */ + ev.data.data32[3] = 1; + ev.data.data32[4] = 0; + + xcb_send_event(_ecore_xcb_conn, 0, root, + (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY), (const char *)&ev); +// ecore_x_flush(); +} + +EAPI void +ecore_x_netwm_window_state_set(Ecore_X_Window win, + Ecore_X_Window_State *state, + unsigned int num) +{ + Ecore_X_Atom *set; + unsigned int i = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!num) + { + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_NET_WM_STATE); + return; + } + + set = malloc(num * sizeof(Ecore_X_Atom)); + if (!set) return; + + for (i = 0; i < num; i++) + set[i] = _ecore_xcb_netwm_window_state_atom_get(state[i]); + + ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_NET_WM_STATE, set, num); + free(set); +} + +EAPI Eina_Bool +ecore_x_netwm_window_state_get(Ecore_X_Window win, + Ecore_X_Window_State **state, + unsigned int *num) +{ + Ecore_X_Atom *atoms; + int ret = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (num) *num = 0; + if (state) *state = NULL; + + ret = + ecore_x_window_prop_atom_list_get(win, ECORE_X_ATOM_NET_WM_STATE, &atoms); + + if (ret <= 0) return EINA_FALSE; + + if (state) + { + *state = malloc(ret * sizeof(Ecore_X_Window_State)); + if (*state) + { + int i = 0; + + for (i = 0; i < ret; i++) + (*state)[i] = _ecore_xcb_netwm_window_state_get(atoms[i]); + if (num) *num = ret; + } + } + + free(atoms); + + return EINA_TRUE; +} + +EAPI void +ecore_x_netwm_client_active_set(Ecore_X_Window root, + Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_window_set(root, + ECORE_X_ATOM_NET_ACTIVE_WINDOW, &win, 1); +} + +EAPI void +ecore_x_netwm_client_active_request(Ecore_X_Window root, + Ecore_X_Window win, + int type, + Ecore_X_Window current_win) +{ + xcb_client_message_event_t ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!root) root = ((xcb_screen_t *)_ecore_xcb_screen)->root; + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 32; + ev.window = win; + ev.type = ECORE_X_ATOM_NET_ACTIVE_WINDOW; + ev.data.data32[0] = type; + ev.data.data32[1] = XCB_CURRENT_TIME; + ev.data.data32[2] = current_win; + ev.data.data32[3] = 0; + ev.data.data32[4] = 0; + + xcb_send_event(_ecore_xcb_conn, 0, root, + (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY), (const char *)&ev); +// ecore_x_flush(); +} + +EAPI void +ecore_x_netwm_client_list_set(Ecore_X_Window root, + Ecore_X_Window *p_clients, + unsigned int n_clients) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_window_set(root, ECORE_X_ATOM_NET_CLIENT_LIST, + p_clients, n_clients); +} + +EAPI void +ecore_x_netwm_client_list_stacking_set(Ecore_X_Window root, + Ecore_X_Window *p_clients, + unsigned int n_clients) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_window_set(root, ECORE_X_ATOM_NET_CLIENT_LIST_STACKING, + p_clients, n_clients); +} + +EAPI Eina_Bool +ecore_x_screen_is_composited(int screen) +{ + char buff[32]; + xcb_get_selection_owner_cookie_t ocookie; + xcb_get_selection_owner_reply_t *oreply; + Ecore_X_Window win; + static Ecore_X_Atom atom = XCB_NONE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + snprintf(buff, sizeof(buff), "_NET_WM_CM_S%i", screen); + + if (atom == XCB_NONE) + { + xcb_intern_atom_cookie_t acookie; + xcb_intern_atom_reply_t *areply; + + acookie = + xcb_intern_atom_unchecked(_ecore_xcb_conn, 0, strlen(buff), buff); + areply = xcb_intern_atom_reply(_ecore_xcb_conn, acookie, NULL); + if (!areply) return EINA_FALSE; + atom = areply->atom; + free(areply); + } + if (atom == XCB_NONE) return EINA_FALSE; + + ocookie = xcb_get_selection_owner_unchecked(_ecore_xcb_conn, atom); + oreply = xcb_get_selection_owner_reply(_ecore_xcb_conn, ocookie, NULL); + if (!oreply) return EINA_FALSE; + win = oreply->owner; + free(oreply); + + return (win != XCB_NONE) ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_x_screen_is_composited_set(int screen, + Ecore_X_Window win) +{ + static Ecore_X_Atom atom = XCB_NONE; + char buff[32]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + snprintf(buff, sizeof(buff), "_NET_WM_CM_S%i", screen); + if (atom == XCB_NONE) + { + xcb_intern_atom_cookie_t acookie; + xcb_intern_atom_reply_t *areply; + + acookie = + xcb_intern_atom_unchecked(_ecore_xcb_conn, 0, strlen(buff), buff); + areply = xcb_intern_atom_reply(_ecore_xcb_conn, acookie, NULL); + if (!areply) return; + atom = areply->atom; + free(areply); + } + if (atom == XCB_NONE) return; + xcb_set_selection_owner(_ecore_xcb_conn, win, atom, + _ecore_xcb_events_last_time_get()); +} + +EAPI void +ecore_x_netwm_ping_send(Ecore_X_Window win) +{ + xcb_client_message_event_t ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!win) return; + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 32; + ev.window = win; + ev.type = ECORE_X_ATOM_WM_PROTOCOLS; + ev.data.data32[0] = ECORE_X_ATOM_NET_WM_PING; + ev.data.data32[1] = ecore_x_current_time_get(); + ev.data.data32[2] = win; + ev.data.data32[3] = 0; + ev.data.data32[4] = 0; + + xcb_send_event(_ecore_xcb_conn, 0, win, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); +} + +EAPI void +ecore_x_netwm_frame_size_set(Ecore_X_Window win, + int fl, + int fr, + int ft, + int fb) +{ + uint32_t frames[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + frames[0] = fl; + frames[1] = fr; + frames[2] = ft; + frames[3] = fb; + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_FRAME_EXTENTS, + frames, 4); +} + +EAPI Eina_Bool +ecore_x_netwm_frame_size_get(Ecore_X_Window win, + int *fl, + int *fr, + int *ft, + int *fb) +{ + int ret = 0; + unsigned int frames[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ret = ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_FRAME_EXTENTS, + frames, 4); + if (ret != 4) return EINA_FALSE; + + if (fl) *fl = frames[0]; + if (fr) *fr = frames[1]; + if (ft) *ft = frames[2]; + if (fb) *fb = frames[3]; + + return EINA_TRUE; +} + +EAPI void +ecore_x_netwm_sync_request_send(Ecore_X_Window win, + unsigned int serial) +{ + xcb_client_message_event_t ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!win) return; + + /* FIXME: Maybe need XSyncIntToValue ?? */ + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 32; + ev.window = win; + ev.type = ECORE_X_ATOM_WM_PROTOCOLS; + ev.data.data32[0] = ECORE_X_ATOM_NET_WM_SYNC_REQUEST; + ev.data.data32[1] = _ecore_xcb_events_last_time_get(); + ev.data.data32[2] = serial; + ev.data.data32[3] = 0; + ev.data.data32[4] = 0; + + xcb_send_event(_ecore_xcb_conn, 0, win, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); +} + +EAPI void +ecore_x_netwm_desktop_set(Ecore_X_Window win, + unsigned int desk) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_DESKTOP, &desk, 1); +} + +EAPI Eina_Bool +ecore_x_netwm_desktop_get(Ecore_X_Window win, + unsigned int *desk) +{ + unsigned int tmp = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_DESKTOP, + &tmp, 1)) + return EINA_FALSE; + + if (desk) *desk = tmp; + + return EINA_TRUE; +} + +EAPI void +ecore_x_netwm_desktop_request_send(Ecore_X_Window win, + Ecore_X_Window root, + unsigned int desktop) +{ + xcb_client_message_event_t ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!root) root = ((xcb_screen_t *)_ecore_xcb_screen)->root; + + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 32; + ev.window = win; + ev.type = ECORE_X_ATOM_NET_WM_DESKTOP; + ev.data.data32[0] = desktop; + + xcb_send_event(_ecore_xcb_conn, 0, root, + (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY), (const char *)&ev); +// ecore_x_flush(); +} + +EAPI void +ecore_x_netwm_moveresize_request_send(Ecore_X_Window win, + int x, + int y, + Ecore_X_Netwm_Direction direction, + unsigned int button) +{ + xcb_client_message_event_t ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 32; + ev.window = win; + ev.type = ECORE_X_ATOM_NET_WM_MOVERESIZE; + ev.data.data32[0] = x; + ev.data.data32[1] = y; + ev.data.data32[2] = direction; + ev.data.data32[3] = button; + ev.data.data32[4] = 1; + + xcb_send_event(_ecore_xcb_conn, 0, win, + (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY), (const char *)&ev); +} + +EAPI void +ecore_x_netwm_handled_icons_set(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_HANDLED_ICONS, + NULL, 0); +} + +EAPI Eina_Bool +ecore_x_netwm_handled_icons_get(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_HANDLED_ICONS, + NULL, 0)) + return EINA_FALSE; + + return EINA_TRUE; +} + +EAPI int +ecore_x_netwm_icon_name_get(Ecore_X_Window win, + char **name) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (name) + { + *name = + ecore_x_window_prop_string_get(win, ECORE_X_ATOM_NET_WM_ICON_NAME); + } + + return 1; +} + +EAPI void +ecore_x_netwm_icon_name_set(Ecore_X_Window win, + const char *name) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_string_set(win, ECORE_X_ATOM_NET_WM_ICON_NAME, name); +} + +EAPI void +ecore_x_netwm_icons_set(Ecore_X_Window win, + Ecore_X_Icon *icon, + int num) +{ + unsigned int *data, *p, *p2; + unsigned int i, size, x, y; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + size = 0; + for (i = 0; i < (unsigned int)num; i++) + { + size += 2 + (icon[i].width * icon[i].height); + } + data = malloc(size * sizeof(unsigned int)); + if (!data) return; + p = data; + for (i = 0; i < (unsigned int)num; i++) + { + p[0] = icon[i].width; + p[1] = icon[i].height; + p += 2; + p2 = icon[i].data; + for (y = 0; y < icon[i].height; y++) + { + for (x = 0; x < icon[i].width; x++) + { + unsigned int r, g, b, a; + + a = (*p2 >> 24) & 0xff; + r = (*p2 >> 16) & 0xff; + g = (*p2 >> 8 ) & 0xff; + b = (*p2 ) & 0xff; + if ((a > 0) && (a < 255)) + { + r = (r * 255) / a; + g = (g * 255) / a; + b = (b * 255) / a; + } + *p = (a << 24) | (r << 16) | (g << 8) | b; + p++; + p2++; + } + } + } + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_ICON, + data, size); + free(data); +} + +EAPI Eina_Bool +ecore_x_netwm_icons_get(Ecore_X_Window win, + Ecore_X_Icon **icon, + int *num) +{ + int num_ret = 0; + unsigned int i = 0, len = 0, icons = 0; + unsigned int *data, *p, *src; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (num) *num = 0; + if (icon) *icon = NULL; + + num_ret = + ecore_x_window_prop_card32_list_get(win, ECORE_X_ATOM_NET_WM_ICON, &data); + + if ((num_ret <= 0) || (!data)) + { + if (data) free(data); + return EINA_FALSE; + } + if (num_ret < 2) + { + if (data) free(data); + return EINA_FALSE; + } + + icons = 0; + p = data; + while (p) + { + len = (p[0] * p[1]); + p += (len + 2); + if ((p - data) > num_ret) + { + if (data) free(data); + return EINA_FALSE; + } + icons++; + if ((p - data) == num_ret) p = NULL; + } + if (num) *num = icons; + if (!icon) + { + if (data) free(data); + return EINA_TRUE; + } + + *icon = malloc(icons * sizeof(Ecore_X_Icon)); + if (!(*icon)) + { + if (data) free(data); + return EINA_FALSE; + } + + /* Fetch the icons */ + p = data; + for (i = 0; i < icons; i++) + { + unsigned int *ps, *pd, *pe; + + len = p[0] * p[1]; + ((*icon)[i]).width = p[0]; + ((*icon)[i]).height = p[1]; + src = &(p[2]); + ((*icon)[i]).data = malloc(len * sizeof(unsigned int)); + if (!((*icon)[i]).data) + { + while (i) + free(((*icon)[--i]).data); + free(*icon); + free(data); + return EINA_FALSE; + } + + pd = ((*icon)[i]).data; + ps = src; + pe = ps + len; + for (; ps < pe; ps++) + { + unsigned int r, g, b, a; + + a = (*ps >> 24) & 0xff; + r = (((*ps >> 16) & 0xff) * a) / 255; + g = (((*ps >> 8) & 0xff) * a) / 255; + b = (((*ps) & 0xff) * a) / 255; + *pd = (a << 24) | (r << 16) | (g << 8) | (b); + pd++; + } + p += (len + 2); + } + + if (data) free(data); + return EINA_TRUE; +} + +EAPI void +ecore_x_netwm_icon_geometry_set(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ + unsigned int geom[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + geom[0] = x; + geom[1] = y; + geom[2] = w; + geom[3] = h; + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_ICON_GEOMETRY, + geom, 4); +} + +EAPI Eina_Bool +ecore_x_netwm_icon_geometry_get(Ecore_X_Window win, + int *x, + int *y, + int *w, + int *h) +{ + int ret = 0; + unsigned int geom[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ret = + ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_ICON_GEOMETRY, + geom, 4); + if (ret != 4) return EINA_FALSE; + if (x) *x = geom[0]; + if (y) *y = geom[1]; + if (w) *w = geom[2]; + if (h) *h = geom[3]; + + return EINA_TRUE; +} + +EAPI void +ecore_x_netwm_strut_set(Ecore_X_Window win, + int l, + int r, + int t, + int b) +{ + unsigned int strut[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + strut[0] = l; + strut[1] = r; + strut[2] = t; + strut[3] = b; + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_STRUT, strut, 4); +} + +EAPI Eina_Bool +ecore_x_netwm_strut_get(Ecore_X_Window win, + int *l, + int *r, + int *t, + int *b) +{ + unsigned int strut[4]; + int ret = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ret = + ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_STRUT, strut, 4); + if (ret != 4) return EINA_FALSE; + + if (l) *l = strut[0]; + if (r) *r = strut[1]; + if (t) *t = strut[2]; + if (b) *b = strut[3]; + + return EINA_TRUE; +} + +EAPI void +ecore_x_netwm_strut_partial_set(Ecore_X_Window win, + int left, + int right, + int top, + int bottom, + int left_start_y, + int left_end_y, + int right_start_y, + int right_end_y, + int top_start_x, + int top_end_x, + int bottom_start_x, + int bottom_end_x) +{ + unsigned int strut[12]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + strut[0] = left; + strut[1] = right; + strut[2] = top; + strut[3] = bottom; + strut[4] = left_start_y; + strut[5] = left_end_y; + strut[6] = right_start_y; + strut[7] = right_end_y; + strut[8] = top_start_x; + strut[9] = top_end_x; + strut[10] = bottom_start_x; + strut[11] = bottom_end_x; + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_STRUT_PARTIAL, + strut, 12); +} + +EAPI Eina_Bool +ecore_x_netwm_strut_partial_get(Ecore_X_Window win, + int *left, + int *right, + int *top, + int *bottom, + int *left_start_y, + int *left_end_y, + int *right_start_y, + int *right_end_y, + int *top_start_x, + int *top_end_x, + int *bottom_start_x, + int *bottom_end_x) +{ + unsigned int strut[12]; + int ret = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ret = + ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_STRUT_PARTIAL, + strut, 12); + if (ret != 12) return EINA_FALSE; + + if (left) *left = strut[0]; + if (right) *right = strut[1]; + if (top) *top = strut[2]; + if (bottom) *bottom = strut[3]; + if (left_start_y) *left_start_y = strut[4]; + if (left_end_y) *left_end_y = strut[5]; + if (right_start_y) *right_start_y = strut[6]; + if (right_end_y) *right_end_y = strut[7]; + if (top_start_x) *top_start_x = strut[8]; + if (top_end_x) *top_end_x = strut[9]; + if (bottom_start_x) *bottom_start_x = strut[10]; + if (bottom_end_x) *bottom_end_x = strut[11]; + + return EINA_TRUE; +} + +EAPI void +ecore_x_netwm_user_time_set(Ecore_X_Window win, + unsigned int t) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_USER_TIME, &t, 1); +} + +EAPI Eina_Bool +ecore_x_netwm_user_time_get(Ecore_X_Window win, + unsigned int *t) +{ + unsigned int tmp; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_USER_TIME, + &tmp, 1)) + return EINA_FALSE; + + if (t) *t = tmp; + + return EINA_TRUE; +} + +EAPI void +ecore_x_netwm_visible_name_set(Ecore_X_Window win, + const char *name) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_string_set(win, ECORE_X_ATOM_NET_WM_VISIBLE_NAME, + name); +} + +EAPI int +ecore_x_netwm_visible_name_get(Ecore_X_Window win, + char **name) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (name) + *name = ecore_x_window_prop_string_get(win, + ECORE_X_ATOM_NET_WM_VISIBLE_NAME); + return 1; +} + +EAPI void +ecore_x_netwm_visible_icon_name_set(Ecore_X_Window win, + const char *name) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_string_set(win, ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME, + name); +} + +EAPI int +ecore_x_netwm_visible_icon_name_get(Ecore_X_Window win, + char **name) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (name) + { + *name = + ecore_x_window_prop_string_get(win, + ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME); + } + + return 1; +} + +EAPI Eina_Bool +ecore_x_netwm_sync_counter_get(Ecore_X_Window win, + Ecore_X_Sync_Counter *counter) +{ + unsigned int tmp; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_card32_get(win, + ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER, + &tmp, 1)) + return EINA_FALSE; + + if (counter) *counter = tmp; + + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_x_netwm_allowed_action_isset(Ecore_X_Window win, + Ecore_X_Action action) +{ + int num = 0, i = 0; + Ecore_X_Atom *atoms, atom; + Eina_Bool ret = EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + num = + ecore_x_window_prop_atom_list_get(win, ECORE_X_ATOM_NET_WM_WINDOW_TYPE, + &atoms); + if (num <= 0) return EINA_FALSE; + + atom = _ecore_xcb_netwm_action_atom_get(action); + for (i = 0; i < num; i++) + { + if (atoms[i] == atom) + { + ret = EINA_TRUE; + break; + } + } + + if (atoms) free(atoms); + return ret; +} + +EAPI Eina_Bool +ecore_x_netwm_allowed_action_get(Ecore_X_Window win, + Ecore_X_Action **action, + unsigned int *num) +{ + Ecore_X_Atom *atoms; + int num_ret = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (num) *num = 0; + if (action) *action = NULL; + + num_ret = + ecore_x_window_prop_atom_list_get(win, ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS, + &atoms); + if (num_ret <= 0) return EINA_FALSE; + if (action) + { + *action = malloc(num_ret * sizeof(Ecore_X_Action)); + if (*action) + { + int i = 0; + + for (i = 0; i < num_ret; i++) + (*action)[i] = _ecore_xcb_netwm_action_atom_get(atoms[i]); + } + if (num) *num = num_ret; + } + free(atoms); + return EINA_TRUE; +} + +EAPI void +ecore_x_netwm_allowed_action_set(Ecore_X_Window win, + Ecore_X_Action *action, + unsigned int num) +{ + Ecore_X_Atom *set; + unsigned int i = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!num) + { + ecore_x_window_prop_property_del(win, + ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS); + return; + } + + set = malloc(num * sizeof(Ecore_X_Atom)); + if (!set) return; + + for (i = 0; i < num; i++) + set[i] = _ecore_xcb_netwm_action_atom_get(action[i]); + + ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS, + set, num); + free(set); +} + +/* local functions */ +int +_ecore_xcb_netwm_startup_info_begin(Ecore_X_Window win __UNUSED__, + uint8_t data __UNUSED__) +{ + // TODO: TBD + return 1; +} + +int +_ecore_xcb_netwm_startup_info(Ecore_X_Window win __UNUSED__, + uint8_t data __UNUSED__) +{ + // TODO: TBD + return 1; +} + +/* static void */ +/* _ecore_xcb_netwm_startup_info_free(void *data) */ +/* { */ +/* Ecore_Xcb_Startup_Info *info; */ + +/* LOGFN(__FILE__, __LINE__, __FUNCTION__); */ + +/* if (!(info = data)) return; */ +/* if (info->buffer) free(info->buffer); */ +/* if (info->id) free(info->id); */ +/* if (info->name) free(info->name); */ +/* if (info->bin) free(info->bin); */ +/* if (info->icon) free(info->icon); */ +/* if (info->description) free(info->description); */ +/* if (info->wmclass) free(info->wmclass); */ +/* free(info); */ +/* } */ + +static Ecore_X_Atom +_ecore_xcb_netwm_window_type_atom_get(Ecore_X_Window_Type type) +{ + switch (type) + { + case ECORE_X_WINDOW_TYPE_DESKTOP: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DESKTOP; + + case ECORE_X_WINDOW_TYPE_DOCK: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DOCK; + + case ECORE_X_WINDOW_TYPE_TOOLBAR: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR; + + case ECORE_X_WINDOW_TYPE_MENU: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_MENU; + + case ECORE_X_WINDOW_TYPE_UTILITY: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_UTILITY; + + case ECORE_X_WINDOW_TYPE_SPLASH: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_SPLASH; + + case ECORE_X_WINDOW_TYPE_DIALOG: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DIALOG; + + case ECORE_X_WINDOW_TYPE_NORMAL: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NORMAL; + + case ECORE_X_WINDOW_TYPE_DROPDOWN_MENU: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DROPDOWN_MENU; + + case ECORE_X_WINDOW_TYPE_POPUP_MENU: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_POPUP_MENU; + + case ECORE_X_WINDOW_TYPE_TOOLTIP: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLTIP; + + case ECORE_X_WINDOW_TYPE_NOTIFICATION: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION; + + case ECORE_X_WINDOW_TYPE_COMBO: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_COMBO; + + case ECORE_X_WINDOW_TYPE_DND: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DND; + + default: + return 0; + } +} + +static Ecore_X_Window_Type +_ecore_xcb_netwm_window_type_type_get(Ecore_X_Atom atom) +{ + if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DESKTOP) + return ECORE_X_WINDOW_TYPE_DESKTOP; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DOCK) + return ECORE_X_WINDOW_TYPE_DOCK; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR) + return ECORE_X_WINDOW_TYPE_TOOLBAR; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_MENU) + return ECORE_X_WINDOW_TYPE_MENU; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_UTILITY) + return ECORE_X_WINDOW_TYPE_UTILITY; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_SPLASH) + return ECORE_X_WINDOW_TYPE_SPLASH; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DIALOG) + return ECORE_X_WINDOW_TYPE_DIALOG; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NORMAL) + return ECORE_X_WINDOW_TYPE_NORMAL; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DROPDOWN_MENU) + return ECORE_X_WINDOW_TYPE_DROPDOWN_MENU; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_POPUP_MENU) + return ECORE_X_WINDOW_TYPE_POPUP_MENU; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLTIP) + return ECORE_X_WINDOW_TYPE_TOOLTIP; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION) + return ECORE_X_WINDOW_TYPE_NOTIFICATION; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_COMBO) + return ECORE_X_WINDOW_TYPE_COMBO; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DND) + return ECORE_X_WINDOW_TYPE_DND; + else + return ECORE_X_WINDOW_TYPE_UNKNOWN; +} + +static Ecore_X_Atom +_ecore_xcb_netwm_window_state_atom_get(Ecore_X_Window_State state) +{ + switch (state) + { + case ECORE_X_WINDOW_STATE_MODAL: + return ECORE_X_ATOM_NET_WM_STATE_MODAL; + + case ECORE_X_WINDOW_STATE_STICKY: + return ECORE_X_ATOM_NET_WM_STATE_STICKY; + + case ECORE_X_WINDOW_STATE_MAXIMIZED_VERT: + return ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT; + + case ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ: + return ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ; + + case ECORE_X_WINDOW_STATE_SHADED: + return ECORE_X_ATOM_NET_WM_STATE_SHADED; + + case ECORE_X_WINDOW_STATE_SKIP_TASKBAR: + return ECORE_X_ATOM_NET_WM_STATE_SKIP_TASKBAR; + + case ECORE_X_WINDOW_STATE_SKIP_PAGER: + return ECORE_X_ATOM_NET_WM_STATE_SKIP_PAGER; + + case ECORE_X_WINDOW_STATE_HIDDEN: + return ECORE_X_ATOM_NET_WM_STATE_HIDDEN; + + case ECORE_X_WINDOW_STATE_FULLSCREEN: + return ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN; + + case ECORE_X_WINDOW_STATE_ABOVE: + return ECORE_X_ATOM_NET_WM_STATE_ABOVE; + + case ECORE_X_WINDOW_STATE_BELOW: + return ECORE_X_ATOM_NET_WM_STATE_BELOW; + + case ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION: + return ECORE_X_ATOM_NET_WM_STATE_DEMANDS_ATTENTION; + + default: + return 0; + } +} + +Ecore_X_Window_State +_ecore_xcb_netwm_window_state_get(Ecore_X_Atom atom) +{ + if (atom == ECORE_X_ATOM_NET_WM_STATE_MODAL) + return ECORE_X_WINDOW_STATE_MODAL; + else if (atom == ECORE_X_ATOM_NET_WM_STATE_STICKY) + return ECORE_X_WINDOW_STATE_STICKY; + else if (atom == ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT) + return ECORE_X_WINDOW_STATE_MAXIMIZED_VERT; + else if (atom == ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ) + return ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ; + else if (atom == ECORE_X_ATOM_NET_WM_STATE_SHADED) + return ECORE_X_WINDOW_STATE_SHADED; + else if (atom == ECORE_X_ATOM_NET_WM_STATE_SKIP_TASKBAR) + return ECORE_X_WINDOW_STATE_SKIP_TASKBAR; + else if (atom == ECORE_X_ATOM_NET_WM_STATE_SKIP_PAGER) + return ECORE_X_WINDOW_STATE_SKIP_PAGER; + else if (atom == ECORE_X_ATOM_NET_WM_STATE_HIDDEN) + return ECORE_X_WINDOW_STATE_HIDDEN; + else if (atom == ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN) + return ECORE_X_WINDOW_STATE_FULLSCREEN; + else if (atom == ECORE_X_ATOM_NET_WM_STATE_ABOVE) + return ECORE_X_WINDOW_STATE_ABOVE; + else if (atom == ECORE_X_ATOM_NET_WM_STATE_BELOW) + return ECORE_X_WINDOW_STATE_BELOW; + else if (atom == ECORE_X_ATOM_NET_WM_STATE_DEMANDS_ATTENTION) + return ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION; + else + return ECORE_X_WINDOW_STATE_UNKNOWN; +} + +static Ecore_X_Atom +_ecore_xcb_netwm_action_atom_get(Ecore_X_Action action) +{ + switch (action) + { + case ECORE_X_ACTION_MOVE: + return ECORE_X_ATOM_NET_WM_ACTION_MOVE; + + case ECORE_X_ACTION_RESIZE: + return ECORE_X_ATOM_NET_WM_ACTION_RESIZE; + + case ECORE_X_ACTION_MINIMIZE: + return ECORE_X_ATOM_NET_WM_ACTION_MINIMIZE; + + case ECORE_X_ACTION_SHADE: + return ECORE_X_ATOM_NET_WM_ACTION_SHADE; + + case ECORE_X_ACTION_STICK: + return ECORE_X_ATOM_NET_WM_ACTION_STICK; + + case ECORE_X_ACTION_MAXIMIZE_HORZ: + return ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_HORZ; + + case ECORE_X_ACTION_MAXIMIZE_VERT: + return ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_VERT; + + case ECORE_X_ACTION_FULLSCREEN: + return ECORE_X_ATOM_NET_WM_ACTION_FULLSCREEN; + + case ECORE_X_ACTION_CHANGE_DESKTOP: + return ECORE_X_ATOM_NET_WM_ACTION_CHANGE_DESKTOP; + + case ECORE_X_ACTION_CLOSE: + return ECORE_X_ATOM_NET_WM_ACTION_CLOSE; + + case ECORE_X_ACTION_ABOVE: + return ECORE_X_ATOM_NET_WM_ACTION_ABOVE; + + case ECORE_X_ACTION_BELOW: + return ECORE_X_ATOM_NET_WM_ACTION_BELOW; + + default: + return 0; + } +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_pixmap.c b/src/lib/ecore_x/xcb/ecore_xcb_pixmap.c new file mode 100644 index 0000000..f9bf525 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_pixmap.c @@ -0,0 +1,128 @@ +#include "ecore_xcb_private.h" + +/** + * @defgroup Ecore_X_Pixmap_Group X Pixmap Functions + * + * Functions that operate on pixmaps. + */ + +/** + * Creates a new pixmap. + * @param win Window used to determine which screen of the display the + * pixmap should be created on. If 0, the default root window + * is used. + * @param w Width of the new pixmap. + * @param h Height of the new pixmap. + * @param dep Depth of the pixmap. If 0, the default depth of the default + * screen is used. + * @return New pixmap. + * @ingroup Ecore_X_Pixmap_Group + */ +EAPI Ecore_X_Pixmap +ecore_x_pixmap_new(Ecore_X_Window win, + int w, + int h, + int dep) +{ + Ecore_X_Pixmap pmap; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (win == 0) win = ((xcb_screen_t *)_ecore_xcb_screen)->root; + if (dep == 0) dep = ((xcb_screen_t *)_ecore_xcb_screen)->root_depth; + + pmap = xcb_generate_id(_ecore_xcb_conn); + xcb_create_pixmap(_ecore_xcb_conn, dep, pmap, win, w, h); + +// ecore_x_flush(); + return pmap; +} + +/** + * Deletes the reference to the given pixmap. + * + * If no other clients have a reference to the given pixmap, the server + * will destroy it. + * + * @param pmap The given pixmap. + * @ingroup Ecore_X_Pixmap_Group + */ +EAPI void +ecore_x_pixmap_free(Ecore_X_Pixmap pmap) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_free_pixmap(_ecore_xcb_conn, pmap); +// ecore_x_flush(); +} + +/** + * Pastes a rectangular area of the given pixmap onto the given drawable. + * @param pmap The given pixmap. + * @param dest The given drawable. + * @param gc The graphics context which governs which operation will + * be used to paste the area onto the drawable. + * @param sx The X position of the area on the pixmap. + * @param sy The Y position of the area on the pixmap. + * @param w The width of the area. + * @param h The height of the area. + * @param dx The X position at which to paste the area on @p dest. + * @param dy The Y position at which to paste the area on @p dest. + * @ingroup Ecore_X_Pixmap_Group + */ +EAPI void +ecore_x_pixmap_paste(Ecore_X_Pixmap pmap, + Ecore_X_Drawable dest, + Ecore_X_GC gc, + int sx, + int sy, + int w, + int h, + int dx, + int dy) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_copy_area(_ecore_xcb_conn, pmap, dest, gc, sx, sy, dx, dy, w, h); +// ecore_x_flush(); +} + +/** + * Retrieves the size of the given pixmap. + * @param pmap The given pixmap. + * @param x Pointer to an integer in which to store the X position. + * @param y Pointer to an integer in which to store the Y position. + * @param w Pointer to an integer in which to store the width. + * @param h Pointer to an integer in which to store the height. + * @ingroup Ecore_X_Pixmap_Group + */ +EAPI void +ecore_x_pixmap_geometry_get(Ecore_X_Pixmap pmap, + int *x, + int *y, + int *w, + int *h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (pmap) + ecore_x_drawable_geometry_get(pmap, x, y, w, h); +} + +/** + * Retrieves the depth of the given pixmap. + * @param pmap The given pixmap. + * @return The depth of the pixmap. + * @ingroup Ecore_X_Pixmap_Group + */ +EAPI int +ecore_x_pixmap_depth_get(Ecore_X_Pixmap pmap) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return ecore_x_drawable_depth_get(pmap); +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_private.h b/src/lib/ecore_x/xcb/ecore_xcb_private.h new file mode 100644 index 0000000..838c278 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_private.h @@ -0,0 +1,442 @@ +#ifndef __ECORE_XCB_PRIVATE_H__ +# define __ECORE_XCB_PRIVATE_H__ + +//# define LOGFNS 1 + +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif + +# include // included for close & gethostname functions + +/* generic xcb includes */ +# include +# include +# include +# include + +/* EFL includes */ +# include "Ecore.h" +# include "Ecore_Input.h" +# include "Ecore_X.h" + +/* logging */ +extern int _ecore_xcb_log_dom; + +# ifdef ECORE_XCB_DEFAULT_LOG_COLOR +# undef ECORE_XCB_DEFAULT_LOG_COLOR +# endif +# define ECORE_XCB_DEFAULT_LOG_COLOR EINA_COLOR_BLUE + +# ifdef ERR +# undef ERR +# endif +# define ERR(...) EINA_LOG_DOM_ERR(_ecore_xcb_log_dom, __VA_ARGS__) + +# ifdef DBG +# undef DBG +# endif +# define DBG(...) EINA_LOG_DOM_DBG(_ecore_xcb_log_dom, __VA_ARGS__) + +# ifdef INF +# undef INF +# endif +# define INF(...) EINA_LOG_DOM_INFO(_ecore_xcb_log_dom, __VA_ARGS__) + +# ifdef WRN +# undef WRN +# endif +# define WRN(...) EINA_LOG_DOM_WARN(_ecore_xcb_log_dom, __VA_ARGS__) + +# ifdef CRIT +# undef CRIT +# endif +# define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_xcb_log_dom, __VA_ARGS__) + +# ifdef LOGFNS +# include +# define LOGFN(fl, ln, fn) printf("-ECORE-XCB: %25s: %5i - %s\n", fl, ln, fn); +# else +# define LOGFN(fl, ln, fn) +# endif + +# ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 256 +# endif + +# ifndef MIN +# define MIN(x, y) (((x) > (y)) ? (y) : (x)) +# endif + +# ifndef MAX +# define MAX(a, b) ((a < b) ? b : a) +# endif + +#define CHECK_XCB_CONN \ + { \ + if (xcb_connection_has_error(_ecore_xcb_conn)) \ + { \ + DBG("XCB Connection Has Error !!"); \ + _ecore_xcb_io_error_handle(NULL); \ + } \ + } + +/* enums */ +typedef enum _Ecore_Xcb_Encoding_Style Ecore_Xcb_Encoding_Style; + +enum _Ecore_Xcb_Encoding_Style +{ + XcbStringStyle, + XcbCompoundTextStyle, + XcbTextStyle, + XcbStdICCTextStyle, + XcbUTF8StringStyle +}; + +/* structures */ +typedef struct _Ecore_X_DND_Source Ecore_X_DND_Source; +typedef struct _Ecore_X_DND_Target Ecore_X_DND_Target; +typedef struct _Ecore_X_Selection_Intern Ecore_X_Selection_Intern; +typedef struct _Ecore_X_Selection_Converter Ecore_X_Selection_Converter; +typedef struct _Ecore_X_Selection_Parser Ecore_X_Selection_Parser; +typedef struct _Ecore_Xcb_Textproperty Ecore_Xcb_Textproperty; + +struct _Ecore_X_DND_Source +{ + int version; + Ecore_X_Window win, dest; + + enum + { + ECORE_X_DND_SOURCE_IDLE, + ECORE_X_DND_SOURCE_DRAGGING, + ECORE_X_DND_SOURCE_DROPPED, + ECORE_X_DND_SOURCE_CONVERTING + } state; + + struct + { + short x, y; + unsigned short width, height; + } rectangle; + + struct + { + Ecore_X_Window window; + int x, y; + } prev; + + Ecore_X_Time time; + + Ecore_X_Atom action, accepted_action; + + int will_accept, suppress; + int await_status; +}; + +struct _Ecore_X_DND_Target +{ + int version; + Ecore_X_Window win, source; + + enum + { + ECORE_X_DND_TARGET_IDLE, + ECORE_X_DND_TARGET_ENTERED + } state; + + struct + { + int x, y; + } pos; + + Ecore_X_Time time; + + Ecore_X_Atom action, accepted_action; + int will_accept; +}; + +struct _Ecore_X_Selection_Intern +{ + Ecore_X_Window win; + Ecore_X_Atom selection; + unsigned char *data; + int length; + Ecore_X_Time time; +}; + +struct _Ecore_X_Selection_Converter +{ + Ecore_X_Atom target; + Eina_Bool (*convert)(char *target, + void *data, + int size, + void **data_ret, + int *size_ret, + Ecore_X_Atom *type, + int *size_type); + Ecore_X_Selection_Converter *next; +}; + +struct _Ecore_X_Selection_Parser +{ + char *target; + void *(*parse)(const char *target, void *data, int size, int format); + Ecore_X_Selection_Parser *next; +}; + +struct _Ecore_Xcb_Textproperty +{ + char *value; + Ecore_X_Atom encoding; + unsigned int format, nitems; +}; + +/* external variables */ +extern Ecore_X_Connection *_ecore_xcb_conn; +extern Ecore_X_Screen *_ecore_xcb_screen; +extern double _ecore_xcb_double_click_time; +extern int16_t _ecore_xcb_event_last_root_x; +extern int16_t _ecore_xcb_event_last_root_y; + +/* external variables for extension events */ +extern int _ecore_xcb_event_damage; +extern int _ecore_xcb_event_randr; +extern int _ecore_xcb_event_screensaver; +extern int _ecore_xcb_event_shape; +extern int _ecore_xcb_event_sync; +extern int _ecore_xcb_event_xfixes; +extern int _ecore_xcb_event_input; +extern int _ecore_xcb_event_gesture; + +extern Ecore_X_Atom _ecore_xcb_atoms_wm_protocol[ECORE_X_WM_PROTOCOL_NUM]; + +extern int _ecore_xcb_button_grabs_num; +extern int _ecore_xcb_key_grabs_num; +extern Ecore_X_Window *_ecore_xcb_button_grabs; +extern Ecore_X_Window *_ecore_xcb_key_grabs; +extern Eina_Bool (*_ecore_xcb_window_grab_replay_func)(void *data, + int type, + void *event); +extern void *_ecore_xcb_window_grab_replay_data; + +/* private function prototypes */ +void _ecore_xcb_error_handler_init(void); +void _ecore_xcb_error_handler_shutdown(void); + +void _ecore_xcb_atoms_init(void); +void _ecore_xcb_atoms_finalize(void); + +void _ecore_xcb_extensions_init(void); +void _ecore_xcb_extensions_finalize(void); + +void _ecore_xcb_shape_init(void); +void _ecore_xcb_shape_finalize(void); + +void _ecore_xcb_screensaver_init(void); +void _ecore_xcb_screensaver_finalize(void); + +void _ecore_xcb_sync_init(void); +void _ecore_xcb_sync_finalize(void); +void _ecore_xcb_sync_magic_send(int val, + Ecore_X_Window win); + +void _ecore_xcb_render_init(void); +void _ecore_xcb_render_finalize(void); +Eina_Bool _ecore_xcb_render_argb_get(void); +Eina_Bool _ecore_xcb_render_anim_get(void); +Eina_Bool _ecore_xcb_render_avail_get(void); + +Eina_Bool _ecore_xcb_render_visual_supports_alpha(Ecore_X_Visual visual); +uint32_t _ecore_xcb_render_find_visual_id(int type, + Eina_Bool check_alpha); +Ecore_X_Visual *_ecore_xcb_render_visual_get(int visual_id); + +void _ecore_xcb_randr_init(void); +void _ecore_xcb_randr_finalize(void); + +void _ecore_xcb_gesture_init(void); +void _ecore_xcb_gesture_finalize(void); +void _ecore_xcb_gesture_shutdown(void); + +void _ecore_xcb_xfixes_init(void); +void _ecore_xcb_xfixes_finalize(void); +Eina_Bool _ecore_xcb_xfixes_avail_get(void); + +void _ecore_xcb_damage_init(void); +void _ecore_xcb_damage_finalize(void); + +void _ecore_xcb_composite_init(void); +void _ecore_xcb_composite_finalize(void); + +void _ecore_xcb_dpms_init(void); +void _ecore_xcb_dpms_finalize(void); + +void _ecore_xcb_cursor_init(void); +void _ecore_xcb_cursor_finalize(void); + +void _ecore_xcb_xinerama_init(void); +void _ecore_xcb_xinerama_finalize(void); + +void _ecore_xcb_dnd_init(void); +void _ecore_xcb_dnd_shutdown(void); +Ecore_X_DND_Source *_ecore_xcb_dnd_source_get(void); +Ecore_X_DND_Target *_ecore_xcb_dnd_target_get(void); +void _ecore_xcb_dnd_drag(Ecore_X_Window root, + int x, + int y); + +void _ecore_xcb_selection_init(void); +void _ecore_xcb_selection_shutdown(void); +void *_ecore_xcb_selection_parse(const char *target, + void *data, + int size, + int format); +char *_ecore_xcb_selection_target_get(Ecore_X_Atom target); +Ecore_X_Selection_Intern *_ecore_xcb_selection_get(Ecore_X_Atom selection); + +# ifdef HAVE_ICONV +Eina_Bool _ecore_xcb_utf8_textlist_to_textproperty(char **list, + int count, + Ecore_Xcb_Encoding_Style style, + Ecore_Xcb_Textproperty *ret); +# endif +Eina_Bool _ecore_xcb_mb_textlist_to_textproperty(char **list, + int count, + Ecore_Xcb_Encoding_Style style, + Ecore_Xcb_Textproperty *ret); +Eina_Bool _ecore_xcb_textlist_to_textproperty(const char *type, + char **list, + int count, + Ecore_Xcb_Encoding_Style style, + Ecore_Xcb_Textproperty *ret); + +# ifdef HAVE_ICONV +Eina_Bool _ecore_xcb_utf8_textproperty_to_textlist(const Ecore_Xcb_Textproperty *text_prop, + char ***list_ret, + int *count_ret); +# endif +Eina_Bool _ecore_xcb_mb_textproperty_to_textlist(const Ecore_Xcb_Textproperty *text_prop, + char ***list_ret, + int *count_ret); +Eina_Bool _ecore_xcb_textproperty_to_textlist(const Ecore_Xcb_Textproperty *text_prop, + const char *type, + char ***list_ret, + int *count_ret); + +void _ecore_xcb_events_init(void); +void _ecore_xcb_events_shutdown(void); +void _ecore_xcb_events_handle(xcb_generic_event_t *ev); +Ecore_X_Time _ecore_xcb_events_last_time_get(void); +unsigned int _ecore_xcb_events_modifiers_get(unsigned int state); +void _ecore_xcb_event_mouse_move(uint16_t timestamp, + uint16_t modifiers, + int16_t x, + int16_t y, + int16_t root_x, + int16_t root_y, + xcb_window_t event_win, + xcb_window_t win, + xcb_window_t root_win, + uint8_t same_screen, + int dev, + double radx, + double rady, + double pressure, + double angle, + int16_t mx, + int16_t my, + int16_t mrx, + int16_t mry); +Ecore_Event_Mouse_Button *_ecore_xcb_event_mouse_button(int event, + uint16_t timestamp, + uint16_t modifiers, + xcb_button_t buttons, + int16_t x, + int16_t y, + int16_t root_x, + int16_t root_y, + xcb_window_t event_win, + xcb_window_t win, + xcb_window_t root_win, + uint8_t same_screen, + int dev, + double radx, + double rady, + double pressure, + double angle, + int16_t mx, + int16_t my, + int16_t mrx, + int16_t mry); + +void _ecore_xcb_keymap_init(void); +void _ecore_xcb_keymap_finalize(void); +void _ecore_xcb_keymap_shutdown(void); +void _ecore_xcb_keymap_refresh(xcb_mapping_notify_event_t *event); +xcb_keysym_t _ecore_xcb_keymap_keycode_to_keysym(xcb_keycode_t keycode, + int col); +xcb_keycode_t *_ecore_xcb_keymap_keysym_to_keycode(xcb_keysym_t keysym); +char *_ecore_xcb_keymap_keysym_to_string(xcb_keysym_t keysym); +xcb_keycode_t _ecore_xcb_keymap_string_to_keycode(const char *key); +int _ecore_xcb_keymap_lookup_string(xcb_keycode_t keycode, + int state, + char *buffer, + int bytes, + xcb_keysym_t *sym); + +void _ecore_xcb_input_init(void); +void _ecore_xcb_input_finalize(void); +void _ecore_xcb_input_shutdown(void); +# ifdef ECORE_XCB_XINPUT +void _ecore_xcb_input_handle_event(xcb_generic_event_t *event); +# else +void _ecore_xcb_input_handle_event(xcb_generic_event_t *event __UNUSED__); +# endif + +void _ecore_xcb_dri_init(void); +void _ecore_xcb_dri_finalize(void); + +void _ecore_xcb_xtest_init(void); +void _ecore_xcb_xtest_finalize(void); + +Ecore_X_Window _ecore_xcb_window_root_of_screen_get(int screen); +void _ecore_xcb_window_prop_string_utf8_set(Ecore_X_Window win, + Ecore_X_Atom atom, + const char *str); +Ecore_X_Visual _ecore_xcb_window_visual_get(Ecore_X_Window win); +void _ecore_xcb_window_button_grab_remove(Ecore_X_Window win); +void _ecore_xcb_window_key_grab_remove(Ecore_X_Window win); +void _ecore_xcb_window_grab_allow_events(Ecore_X_Window event_win, + Ecore_X_Window child_win, + int type, + void *event, + Ecore_X_Time timestamp); + +int _ecore_xcb_netwm_startup_info_begin(Ecore_X_Window win __UNUSED__, + uint8_t data __UNUSED__); +int _ecore_xcb_netwm_startup_info(Ecore_X_Window win __UNUSED__, + uint8_t data __UNUSED__); +Ecore_X_Window_State _ecore_xcb_netwm_window_state_get(Ecore_X_Atom atom); + +int _ecore_xcb_error_handle(xcb_generic_error_t *err); +int _ecore_xcb_io_error_handle(xcb_generic_error_t *err); + +xcb_image_t *_ecore_xcb_image_create_native(int w, + int h, + xcb_image_format_t format, + uint8_t depth, + void *base, + uint32_t bytes, + uint8_t *data); + +void _ecore_xcb_xdefaults_init(void); +void _ecore_xcb_xdefaults_shutdown(void); +char *_ecore_xcb_xdefaults_string_get(const char *prog, + const char *param); +int _ecore_xcb_xdefaults_int_get(const char *prog, + const char *param); + +void _ecore_xcb_modifiers_get(void); + +#endif diff --git a/src/lib/ecore_x/xcb/ecore_xcb_randr.c b/src/lib/ecore_x/xcb/ecore_xcb_randr.c new file mode 100644 index 0000000..a96b047 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_randr.c @@ -0,0 +1,3807 @@ +/* TODO: List of missing functions + * + * ecore_x_randr_crtc_clone_set + * ecore_x_randr_output_crtc_set + * ecore_x_randr_edid_version_get + * ecore_x_randr_edid_info_has_valid_checksum + * ecore_x_randr_edid_manufacturer_name_get + * ecore_x_randr_edid_display_ascii_get + * ecore_x_randr_edid_display_serial_get + * ecore_x_randr_edid_model_get + * ecore_x_randr_edid_manufacturer_serial_number_get + * ecore_x_randr_edid_manufacturer_model_get + * ecore_x_randr_edid_dpms_available_get + * ecore_x_randr_edid_dpms_standby_available_get + * ecore_x_randr_edid_dpms_suspend_available_get + * ecore_x_randr_edid_dpms_off_available_get + * ecore_x_randr_edid_display_aspect_ratio_preferred_get + * ecore_x_randr_edid_display_aspect_ratios_get + * ecore_x_randr_edid_display_colorscheme_get + * ecore_x_randr_edid_display_type_digital_get + * ecore_x_randr_edid_display_interface_type_get + * ecore_x_randr_screen_backlight_level_set + * ecore_x_randr_output_subpixel_order_get + * ecore_x_randr_output_wired_clones_get + * ecore_x_randr_output_compatibility_list_get + * ecore_x_randr_output_signal_formats_get + * ecore_x_randr_output_signal_format_set + * ecore_x_randr_output_signal_properties_get + * ecore_x_randr_output_connector_number_get + * ecore_x_randr_output_connector_type_get + * ecore_x_randr_crtc_panning_area_get + * ecore_x_randr_crtc_panning_area_set + * ecore_x_randr_crtc_tracking_area_get + * ecore_x_randr_crtc_tracking_area_set + * ecore_x_randr_crtc_border_area_get + * ecore_x_randr_crtc_border_area_set + */ + +#include "ecore_xcb_private.h" +# ifdef ECORE_XCB_RANDR +# include +# endif + +#define Ecore_X_Randr_None 0 +#define Ecore_X_Randr_Unset -1 + +#define RANDR_1_1 ((1 << 16) | 1) +#define RANDR_1_2 ((1 << 16) | 2) +#define RANDR_1_3 ((1 << 16) | 3) + +#define RANDR_CHECK_1_1_RET(ret) if (_randr_version < RANDR_1_1) return ret +#define RANDR_CHECK_1_2_RET(ret) if (_randr_version < RANDR_1_2) return ret +#define RANDR_CHECK_1_3_RET(ret) if (_randr_version < RANDR_1_3) return ret + +#define ECORE_X_RANDR_EDID_VERSION_13 ((1 << 8) | 3) +#define _ECORE_X_RANDR_EDID_OFFSET_VERSION_MAJOR 0x12 +#define _ECORE_X_RANDR_EDID_OFFSET_VERSION_MINOR 0x13 +#define _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK 0x36 +#define _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE 3 +#define _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_CONTENT 5 +#define _ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX 13 + +#define _ECORE_X_RANDR_EDID_FOR_EACH_DESCRIPTOR_BLOCK(edid, block) \ + for (block = edid + _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK; block <= (edid + _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK + (3 * 18)); block += 18) + +#define _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block) \ + _ECORE_X_RANDR_EDID_FOR_EACH_DESCRIPTOR_BLOCK(edid, block) \ + if ((block[0] == 0) && (block[1] == 0)) + +/* local function prototypes */ +static Eina_Bool _ecore_xcb_randr_output_validate(Ecore_X_Window root, + Ecore_X_Randr_Output output); +static Eina_Bool _ecore_xcb_randr_crtc_validate(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc); +static Eina_Bool _ecore_xcb_randr_root_validate(Ecore_X_Window root); +static int _ecore_xcb_randr_root_to_screen(Ecore_X_Window root); +#ifdef ECORE_XCB_RANDR +static xcb_randr_get_screen_resources_reply_t *_ecore_xcb_randr_12_get_resources(Ecore_X_Window win); +static xcb_randr_get_screen_resources_current_reply_t *_ecore_xcb_randr_13_get_resources(Ecore_X_Window win); +#endif +static xcb_timestamp_t _ecore_xcb_randr_12_get_resource_timestamp(Ecore_X_Window win); +static xcb_timestamp_t _ecore_xcb_randr_13_get_resource_timestamp(Ecore_X_Window win); + +static Ecore_X_Randr_Mode *_ecore_xcb_randr_12_output_modes_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *num, + int *npreferred); +static Ecore_X_Randr_Mode *_ecore_xcb_randr_13_output_modes_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *num, + int *npreferred); +static Ecore_X_Randr_Mode_Info *_ecore_xcb_randr_12_mode_info_get(Ecore_X_Window root, + Ecore_X_Randr_Mode mode); +static Ecore_X_Randr_Mode_Info *_ecore_xcb_randr_13_mode_info_get(Ecore_X_Window root, + Ecore_X_Randr_Mode mode); +static Ecore_X_Randr_Mode_Info **_ecore_xcb_randr_12_modes_info_get(Ecore_X_Window root, + int *num); +static Ecore_X_Randr_Mode_Info **_ecore_xcb_randr_13_modes_info_get(Ecore_X_Window root, + int *num); +static void _ecore_xcb_randr_12_mode_size_get(Ecore_X_Window root, + Ecore_X_Randr_Mode mode, + int *w, + int *h); +static void _ecore_xcb_randr_13_mode_size_get(Ecore_X_Window root, + Ecore_X_Randr_Mode mode, + int *w, + int *h); +static Ecore_X_Randr_Output *_ecore_xcb_randr_12_output_clones_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *num); +static Ecore_X_Randr_Output *_ecore_xcb_randr_13_output_clones_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *num); +static Ecore_X_Randr_Crtc *_ecore_xcb_randr_12_output_possible_crtcs_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *num); +static Ecore_X_Randr_Crtc *_ecore_xcb_randr_13_output_possible_crtcs_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *num); +static char *_ecore_xcb_randr_12_output_name_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *len); +static char *_ecore_xcb_randr_13_output_name_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *len); +static Ecore_X_Randr_Connection_Status _ecore_xcb_randr_12_output_connection_status_get(Ecore_X_Window root, + Ecore_X_Randr_Output output); +static Ecore_X_Randr_Connection_Status _ecore_xcb_randr_13_output_connection_status_get(Ecore_X_Window root, + Ecore_X_Randr_Output output); +static Ecore_X_Randr_Output *_ecore_xcb_randr_12_outputs_get(Ecore_X_Window root, + int *num); +static Ecore_X_Randr_Output *_ecore_xcb_randr_13_outputs_get(Ecore_X_Window root, + int *num); +static Ecore_X_Randr_Crtc _ecore_xcb_randr_12_output_crtc_get(Ecore_X_Window root, + Ecore_X_Randr_Output output); +static Ecore_X_Randr_Crtc _ecore_xcb_randr_13_output_crtc_get(Ecore_X_Window root, + Ecore_X_Randr_Output output); + +/* local variables */ +static Eina_Bool _randr_avail = EINA_FALSE; +static int _randr_version = -1; + +/* external variables */ +int _ecore_xcb_event_randr = -1; + +void +_ecore_xcb_randr_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_RANDR + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_randr_id); +#endif +} + +void +_ecore_xcb_randr_finalize(void) +{ +#ifdef ECORE_XCB_RANDR + const xcb_query_extension_reply_t *ext_reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_RANDR + ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_randr_id); + if ((ext_reply) && (ext_reply->present)) + { + xcb_randr_query_version_cookie_t cookie; + xcb_randr_query_version_reply_t *reply; + + cookie = + xcb_randr_query_version_unchecked(_ecore_xcb_conn, + XCB_RANDR_MAJOR_VERSION, + XCB_RANDR_MINOR_VERSION); + reply = xcb_randr_query_version_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + if ((reply->major_version >= XCB_RANDR_MAJOR_VERSION) && + (reply->minor_version >= XCB_RANDR_MINOR_VERSION)) + _randr_avail = EINA_TRUE; + + _randr_version = + ((reply->major_version << 16) | reply->minor_version); + + free(reply); + } + + if (_randr_avail) + _ecore_xcb_event_randr = ext_reply->first_event; + } +#endif +} + +static Eina_Bool +#ifdef ECORE_XCB_RANDR +_ecore_xcb_randr_root_validate(Ecore_X_Window root) +#else +_ecore_xcb_randr_root_validate(Ecore_X_Window root __UNUSED__) +#endif +{ +#ifdef ECORE_XCB_RANDR + Ecore_X_Randr_Screen scr = -1; +# define RANDR_VALIDATE_ROOT(screen, root) \ + ((screen == _ecore_xcb_randr_root_to_screen(root)) != -1) +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_RANDR + if ((root) && RANDR_VALIDATE_ROOT(scr, root)) + return EINA_TRUE; +#endif + + return EINA_FALSE; +} + +static int +_ecore_xcb_randr_root_to_screen(Ecore_X_Window root) +{ + int count = 0, num = 0; + + CHECK_XCB_CONN; + + count = xcb_setup_roots_length(xcb_get_setup(_ecore_xcb_conn)); + for (num = 0; num < count; num++) + if (_ecore_xcb_window_root_of_screen_get(num) == root) + return num; + + return -1; +} + +/* public functions */ + +/* + * @brief Query whether RandR is available or not. + * + * @return @c EINA_TRUE if extension is available, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_x_randr_query(void) +{ + return _randr_avail; +} + +/* + * @return version of the RandRR extension supported by the server or, + * in case RandRR extension is not available, Ecore_X_Randr_Unset (=-1). + * bit version information: 31 MAJOR 16 | 15 MINOR 0 + */ +EAPI int +ecore_x_randr_version_get(void) +{ + return _randr_version; +} + +/* + * @param root window which's primary output will be queried + */ +EAPI Ecore_X_Randr_Orientation +ecore_x_randr_screen_primary_output_orientations_get(Ecore_X_Window root) +{ + int ret = Ecore_X_Randr_None; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_info_cookie_t cookie; + xcb_randr_get_screen_info_reply_t *reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + cookie = xcb_randr_get_screen_info_unchecked(_ecore_xcb_conn, root); + reply = xcb_randr_get_screen_info_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + ret = reply->rotations; + free(reply); + } +#endif + + return ret; +} + +/* + * @param root window which's primary output will be queried + * @return the current orientation of the root window's screen primary output + */ +EAPI Ecore_X_Randr_Orientation +ecore_x_randr_screen_primary_output_orientation_get(Ecore_X_Window root) +{ + int ret = Ecore_X_Randr_None; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_info_cookie_t cookie; + xcb_randr_get_screen_info_reply_t *reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + cookie = xcb_randr_get_screen_info_unchecked(_ecore_xcb_conn, root); + reply = xcb_randr_get_screen_info_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + ret = reply->rotation; + free(reply); + } +#endif + + return ret; +} + +/* + * @brief Sets a given screen's primary output's orientation. + * + * @param root Window which's screen's primary output will be queried. + * @param orientation Orientation which should be set for the root window's + * screen primary output. + * @return @c EINA_TRUE if the primary output's orientation could be + * successfully altered. + */ +EAPI Eina_Bool +ecore_x_randr_screen_primary_output_orientation_set(Ecore_X_Window root, + Ecore_X_Randr_Orientation orientation) +{ + int ret = EINA_FALSE; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_info_cookie_t cookie; + xcb_randr_get_screen_info_reply_t *reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + cookie = xcb_randr_get_screen_info_unchecked(_ecore_xcb_conn, root); + reply = xcb_randr_get_screen_info_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + xcb_randr_set_screen_config_cookie_t scookie; + xcb_randr_set_screen_config_reply_t *sreply; + + scookie = + xcb_randr_set_screen_config_unchecked(_ecore_xcb_conn, root, + XCB_CURRENT_TIME, + reply->config_timestamp, + reply->sizeID, orientation, + reply->rate); + sreply = + xcb_randr_set_screen_config_reply(_ecore_xcb_conn, scookie, NULL); + if (!sreply) + ret = EINA_FALSE; + else + { + ret = (sreply->status == XCB_RANDR_SET_CONFIG_SUCCESS) ? + EINA_TRUE : EINA_FALSE; + free(sreply); + } + free(reply); + } +#endif + + return ret; +} + +/* + * @brief gets a screen's primary output's possible sizes + * @param root window which's primary output will be queried + * @param num number of sizes reported as supported by the screen's primary output + * @return an array of sizes reported as supported by the screen's primary output or - if query failed - NULL + */ +EAPI Ecore_X_Randr_Screen_Size_MM * +ecore_x_randr_screen_primary_output_sizes_get(Ecore_X_Window root, + int *num) +{ +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_info_cookie_t cookie; + xcb_randr_get_screen_info_reply_t *reply; + Ecore_X_Randr_Screen_Size_MM *ret = NULL; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + cookie = xcb_randr_get_screen_info_unchecked(_ecore_xcb_conn, root); + reply = xcb_randr_get_screen_info_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + int len = 0, i = 0; + xcb_randr_screen_size_t *sizes; + + len = xcb_randr_get_screen_info_sizes_length(reply); + sizes = xcb_randr_get_screen_info_sizes(reply); + if ((!sizes) || (len <= 0)) + { + free(reply); + return NULL; + } + if (num) *num = len; + ret = calloc(len, sizeof(Ecore_X_Randr_Screen_Size_MM)); + if (!ret) + { + free(reply); + return NULL; + } + for (i = 0; i < len; i++) + { + ret[i].width = sizes[i].width; + ret[i].height = sizes[i].height; + ret[i].width_mm = sizes[i].mwidth; + ret[i].height_mm = sizes[i].mheight; + } + + free(reply); + } + + return ret; +#else + return NULL; +#endif +} + +/* + * @brief get the current set size of a given screen's primary output + * @param root window which's primary output will be queried + * @param w the current size's width + * @param h the current size's height + * @param w_mm the current size's width in mm + * @param h_mm the current size's height in mm + * @param size_index of current set size to be used with ecore_x_randr_primary_output_size_set() + */ +EAPI void +ecore_x_randr_screen_primary_output_current_size_get(Ecore_X_Window root, + int *w, + int *h, + int *w_mm, + int *h_mm, + int *size_index) +{ +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_info_cookie_t cookie; + xcb_randr_get_screen_info_reply_t *reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + cookie = xcb_randr_get_screen_info_unchecked(_ecore_xcb_conn, root); + reply = xcb_randr_get_screen_info_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + int len = 0, idx = 0; + xcb_randr_screen_size_t *sizes; + + len = xcb_randr_get_screen_info_sizes_length(reply); + sizes = xcb_randr_get_screen_info_sizes(reply); + if ((!sizes) || (len <= 0)) + { + free(reply); + return; + } + idx = reply->sizeID; + if ((idx < len) && (idx >= 0)) + { + if (w) *w = sizes[idx].width; + if (h) *h = sizes[idx].height; + if (w_mm) *w_mm = sizes[idx].mwidth; + if (h_mm) *h_mm = sizes[idx].mheight; + if (size_index) *size_index = idx; + } + + free(reply); + } +#endif +} + +/* + * @brief Sets a given screen's primary output size, but disables all other + * outputs at the same time. + * + * @param root Window which's primary output will be queried. + * @param size_index Within the list of sizes reported as supported by the root + * window's screen primary output. + * @return @c EINA_TRUE on success, @c EINA_FALSE on failure due to e.g. + * invalid times. + */ +EAPI Eina_Bool +ecore_x_randr_screen_primary_output_size_set(Ecore_X_Window root, + int size_index) +{ + Eina_Bool ret = EINA_FALSE; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_info_cookie_t cookie; + xcb_randr_get_screen_info_reply_t *reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + if (!((size_index >= 0) && (_ecore_xcb_randr_root_validate(root)))) + return EINA_FALSE; + + cookie = xcb_randr_get_screen_info_unchecked(_ecore_xcb_conn, root); + reply = xcb_randr_get_screen_info_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + int len = 0; + + len = xcb_randr_get_screen_info_sizes_length(reply); + if (len <= 0) + { + free(reply); + return EINA_FALSE; + } + if ((size_index < len) && (size_index >= 0)) + { + xcb_randr_set_screen_config_cookie_t scookie; + xcb_randr_set_screen_config_reply_t *sreply; + + scookie = + xcb_randr_set_screen_config_unchecked(_ecore_xcb_conn, root, + XCB_CURRENT_TIME, + reply->config_timestamp, + size_index, + reply->rotation, + reply->rate); + sreply = + xcb_randr_set_screen_config_reply(_ecore_xcb_conn, + scookie, NULL); + if (!sreply) + ret = EINA_FALSE; + else + { + ret = (sreply->status == XCB_RANDR_SET_CONFIG_SUCCESS) ? + EINA_TRUE : EINA_FALSE; + free(sreply); + } + } + + free(reply); + } +#endif + return ret; +} + +/* + * @param root window which's primary output will be queried + * @return currently used refresh rate or - if request failed or RandRR is not available - 0.0 + */ +EAPI Ecore_X_Randr_Refresh_Rate +ecore_x_randr_screen_primary_output_current_refresh_rate_get(Ecore_X_Window root) +{ +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_info_cookie_t cookie; + xcb_randr_get_screen_info_reply_t *reply; + Ecore_X_Randr_Refresh_Rate ret = 0.0; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + if (!_ecore_xcb_randr_root_validate(root)) return ret; + + cookie = xcb_randr_get_screen_info_unchecked(_ecore_xcb_conn, root); + reply = xcb_randr_get_screen_info_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + ret = reply->rate; + free(reply); + } + + return ret; +#else + return 0.0; +#endif +} + +/* + * @param root window which's primary output will be queried + * @param size_index referencing the size to query valid refresh rates for + * @return currently used refresh rate or - if request failed or RandRR is not available - NULL + */ +EAPI Ecore_X_Randr_Refresh_Rate * +ecore_x_randr_screen_primary_output_refresh_rates_get(Ecore_X_Window root, + int size_index, + int *num) +{ +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_info_cookie_t cookie; + xcb_randr_get_screen_info_reply_t *reply; + Ecore_X_Randr_Refresh_Rate *ret = NULL; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + if (!_ecore_xcb_randr_root_validate(root)) return ret; + + cookie = xcb_randr_get_screen_info_unchecked(_ecore_xcb_conn, root); + reply = xcb_randr_get_screen_info_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + int len = 0; + + len = xcb_randr_get_screen_info_rates_length(reply); + if (num) *num = len; + + ret = malloc(sizeof(Ecore_X_Randr_Refresh_Rate) * len); + if (ret) + { + xcb_randr_refresh_rates_iterator_t iter; + int i = 0; + + iter = xcb_randr_get_screen_info_rates_iterator(reply); + while (i++ < size_index) + xcb_randr_refresh_rates_next(&iter); + + memcpy(ret, xcb_randr_refresh_rates_rates(iter.data), + sizeof(Ecore_X_Randr_Refresh_Rate) * len); + } + free(reply); + } + + return ret; +#else + return NULL; +#endif +} + +/* + * @brief Sets the current primary output's refresh rate. + * + * @param root Window which's primary output will be queried. + * @param size_index Referencing the size to be set. + * @param rate The refresh rate to be set. + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_x_randr_screen_primary_output_refresh_rate_set(Ecore_X_Window root, + int size_index, + Ecore_X_Randr_Refresh_Rate rate) +{ + Eina_Bool ret = EINA_FALSE; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_info_cookie_t cookie; + xcb_randr_get_screen_info_reply_t *reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + if (_randr_version < RANDR_1_1) return EINA_FALSE; + + cookie = xcb_randr_get_screen_info_unchecked(_ecore_xcb_conn, root); + reply = xcb_randr_get_screen_info_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + xcb_randr_set_screen_config_cookie_t scookie; + xcb_randr_set_screen_config_reply_t *sreply; + + scookie = + xcb_randr_set_screen_config_unchecked(_ecore_xcb_conn, root, + XCB_CURRENT_TIME, + reply->config_timestamp, + size_index, + reply->rotation, rate); + sreply = + xcb_randr_set_screen_config_reply(_ecore_xcb_conn, + scookie, NULL); + if (!sreply) + ret = EINA_FALSE; + else + { + ret = (sreply->status == XCB_RANDR_SET_CONFIG_SUCCESS) ? + EINA_TRUE : EINA_FALSE; + free(sreply); + } + free(reply); + } +#endif + + return ret; +} + +/* + * @brief Free detailed mode information. The pointer handed in will be set to + * @c NULL after freeing the memory. + * + * @param mode_info The mode information that should be freed. + */ +EAPI void +ecore_x_randr_mode_info_free(Ecore_X_Randr_Mode_Info *mode_info) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + RANDR_CHECK_1_2_RET(); + + if (!mode_info) return; + + if (mode_info->name) free(mode_info->name); + free(mode_info); + mode_info = NULL; +} + +/* + * @param root window which's screen should be queried + * @return Ecore_X_Randr_Ouptut_Id or - if query failed or none is set - Ecore_X_Randr_None + */ +EAPI Ecore_X_Randr_Output +ecore_x_randr_primary_output_get(Ecore_X_Window root) +{ + Ecore_X_Randr_Output ret = Ecore_X_Randr_None; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_output_primary_cookie_t cookie; + xcb_randr_get_output_primary_reply_t *reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_3_RET(Ecore_X_Randr_None); + + if (!_ecore_xcb_randr_root_validate(root)) + return Ecore_X_Randr_None; + + cookie = xcb_randr_get_output_primary_unchecked(_ecore_xcb_conn, root); + reply = xcb_randr_get_output_primary_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + ret = reply->output; + free(reply); + } +#endif + return ret; +} + +/* + * @param root window which's screen should be queried + * @param output that should be set as given root window's screen primary output + */ +EAPI void +ecore_x_randr_primary_output_set(Ecore_X_Window root, + Ecore_X_Randr_Output output) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_3_RET(); + + if ((output) && (_ecore_xcb_randr_root_validate(root))) + xcb_randr_set_output_primary(_ecore_xcb_conn, root, output); +#endif +} + +EAPI Ecore_X_Randr_Mode * +ecore_x_randr_output_modes_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *num, + int *npreferred) +{ + Ecore_X_Randr_Mode *modes = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(NULL); + + if (_randr_version >= RANDR_1_3) + { + modes = + _ecore_xcb_randr_13_output_modes_get(root, output, num, npreferred); + } + else if (_randr_version == RANDR_1_2) + { + modes = + _ecore_xcb_randr_12_output_modes_get(root, output, num, npreferred); + } +#endif + + return modes; +} + +EAPI Eina_Bool +ecore_x_randr_output_mode_add(Ecore_X_Randr_Output output, Ecore_X_Randr_Mode mode) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + + if ((output == Ecore_X_Randr_None) || (mode == Ecore_X_Randr_None)) + return EINA_FALSE; + + xcb_randr_add_output_mode(_ecore_xcb_conn, output, mode); + return EINA_TRUE; +#endif + return EINA_FALSE; +} + +/* + * @brief get detailed information for a given mode id + * @param root window which's screen's ressources are queried + * @param mode the XID which identifies the mode of interest + * @return mode's detailed information + */ +EAPI Ecore_X_Randr_Mode_Info * +ecore_x_randr_mode_info_get(Ecore_X_Window root, + Ecore_X_Randr_Mode mode) +{ + Ecore_X_Randr_Mode_Info *ret = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(NULL); + + if (!_ecore_xcb_randr_root_validate(root)) return NULL; + + if (_randr_version >= RANDR_1_3) + ret = _ecore_xcb_randr_13_mode_info_get(root, mode); + else if (_randr_version == RANDR_1_2) + ret = _ecore_xcb_randr_12_mode_info_get(root, mode); +#endif + return ret; +} + +/* + * @brief add a mode to a display + * @param root window to which's screen's ressources are added + * @param mode_info + * @return Ecore_X_Randr_Mode of the added mode. Ecore_X_Randr_None if mode + * adding failed. + * @since 1.2.0 + */ +EAPI Ecore_X_Randr_Mode +ecore_x_randr_mode_info_add(Ecore_X_Window root, Ecore_X_Randr_Mode_Info *mode_info) +{ + Ecore_X_Randr_Mode mode = Ecore_X_Randr_None; +#ifdef ECORE_XCB_RANDR + xcb_randr_create_mode_cookie_t cookie; + xcb_randr_create_mode_reply_t *reply; + xcb_randr_mode_info_t info; + int namelen = 0; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + + if (!mode_info) return Ecore_X_Randr_None; + if (!_ecore_xcb_randr_root_validate(root)) return Ecore_X_Randr_None; + + namelen = strlen(mode_info->name); + + memset(&info, 0, sizeof(info)); + info.width = mode_info->width; + info.height = mode_info->height; + info.dot_clock = mode_info->dotClock; + info.hsync_start = mode_info->hSyncStart; + info.hsync_end = mode_info->hSyncEnd; + info.htotal = mode_info->hTotal; + info.hskew = mode_info->hSkew; + info.vsync_start = mode_info->vSyncStart; + info.vsync_end = mode_info->vSyncEnd; + info.vtotal = mode_info->vTotal; + info.mode_flags = mode_info->modeFlags; + info.name_len = namelen; + + cookie = + xcb_randr_create_mode_unchecked(_ecore_xcb_conn, root, info, + namelen, mode_info->name); + reply = xcb_randr_create_mode_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + mode = mode_info->xid; + free(reply); + } +#endif + return mode; +} + +/* + * @brief get detailed information for all modes related to a root window's screen + * @param root window which's screen's ressources are queried + * @param num number of modes returned + * @return modes' information + */ +EAPI Ecore_X_Randr_Mode_Info ** +ecore_x_randr_modes_info_get(Ecore_X_Window root, + int *num) +{ + Ecore_X_Randr_Mode_Info **ret = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (num) *num = 0; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(NULL); + + if (!_ecore_xcb_randr_root_validate(root)) return NULL; + + if (_randr_version >= RANDR_1_3) + ret = _ecore_xcb_randr_13_modes_info_get(root, num); + else if (_randr_version == RANDR_1_2) + ret = _ecore_xcb_randr_12_modes_info_get(root, num); +#endif + return ret; +} + +/** + * @brief Gets the width and hight of a given mode. + * + * @param root Window which's screen's ressources are queried. + * @param mode The mode which's size is to be looked up. + * @param w Width of given mode in px. + * @param h Height of given mode in px. + */ +EAPI void +ecore_x_randr_mode_size_get(Ecore_X_Window root, + Ecore_X_Randr_Mode mode, + int *w, + int *h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(); + + if (mode == Ecore_X_Randr_None) return; + + if (_randr_version >= RANDR_1_3) + _ecore_xcb_randr_13_mode_size_get(root, mode, w, h); + else if (_randr_version == RANDR_1_2) + _ecore_xcb_randr_12_mode_size_get(root, mode, w, h); +#endif +} + +/** + * @brief Gets the EDID information of an attached output if available. + * Note that this information is not to be compared using ordinary string + * comparison functions, since it includes 0-bytes. + * + * @param root Window this information should be queried from. + * @param output The XID of the output. + * @param length Length of the byte-array. If @c NULL, request will fail. + * @return EDID information of the output. + */ +EAPI unsigned char * +ecore_x_randr_output_edid_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + unsigned long *length) +{ + unsigned char *ret = NULL; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_output_property_cookie_t cookie; + xcb_randr_get_output_property_reply_t *reply; + Ecore_X_Atom atom; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(NULL); + + if ((!length) || (!_ecore_xcb_randr_output_validate(root, output))) + return NULL; + + atom = ecore_x_atom_get("EDID"); + cookie = + xcb_randr_get_output_property_unchecked(_ecore_xcb_conn, output, atom, + XCB_GET_PROPERTY_TYPE_ANY, + 0, 100, 0, 0); + reply = + xcb_randr_get_output_property_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + if ((reply->type == XCB_ATOM_INTEGER) && (reply->format == 8)) + { + if (length) *length = reply->num_items; + if ((ret = malloc(reply->num_items * sizeof(unsigned char)))) + { + memcpy(ret, xcb_randr_get_output_property_data(reply), + (reply->num_items * sizeof(unsigned char))); + } + } + free(reply); + } +#endif + return ret; +} + +/** + * @brief Gets the outputs which might be used simultaneously on the same CRTC. + * + * @param root Window that this information should be queried for. + * @param output The output which's clones we concern. + * @param num Number of possible clones. + * @return The existing outputs, @c NULL otherwise. + */ +EAPI Ecore_X_Randr_Output * +ecore_x_randr_output_clones_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *num) +{ + Ecore_X_Randr_Output *outputs = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(NULL); + + if (output == Ecore_X_Randr_None) return NULL; + + if (_randr_version >= RANDR_1_3) + outputs = _ecore_xcb_randr_13_output_clones_get(root, output, num); + else if (_randr_version == RANDR_1_2) + outputs = _ecore_xcb_randr_12_output_clones_get(root, output, num); +#endif + return outputs; +} + +EAPI Ecore_X_Randr_Crtc * +ecore_x_randr_output_possible_crtcs_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *num) +{ + Ecore_X_Randr_Crtc *crtcs = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(NULL); + + if (output == Ecore_X_Randr_None) return NULL; + + if (_randr_version >= RANDR_1_3) + crtcs = _ecore_xcb_randr_13_output_possible_crtcs_get(root, output, num); + else if (_randr_version == RANDR_1_2) + crtcs = _ecore_xcb_randr_12_output_possible_crtcs_get(root, output, num); +#endif + return crtcs; +} + +/** + * @brief gets the given output's name as reported by X + * @param root the window which's screen will be queried + * @param output The output name given to be reported. + * @param len length of returned c-string. + * @return name of the output as reported by X + */ +EAPI char * +ecore_x_randr_output_name_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *len) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(NULL); + + if (output == Ecore_X_Randr_None) return NULL; + + if (_randr_version >= RANDR_1_3) + return _ecore_xcb_randr_13_output_name_get(root, output, len); + else if (_randr_version == RANDR_1_2) + return _ecore_xcb_randr_12_output_name_get(root, output, len); +#endif + + return NULL; +} + +EAPI Ecore_X_Randr_Connection_Status +ecore_x_randr_output_connection_status_get(Ecore_X_Window root, + Ecore_X_Randr_Output output) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN); + + if (output == Ecore_X_Randr_None) + return ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN; + + if (_randr_version >= RANDR_1_3) + return _ecore_xcb_randr_13_output_connection_status_get(root, output); + else if (_randr_version == RANDR_1_2) + return _ecore_xcb_randr_12_output_connection_status_get(root, output); +#endif + + return ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN; +} + +EAPI Ecore_X_Randr_Output * +ecore_x_randr_outputs_get(Ecore_X_Window root, + int *num) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(NULL); + + if (_randr_version >= RANDR_1_3) + return _ecore_xcb_randr_13_outputs_get(root, num); + else if (_randr_version == RANDR_1_2) + return _ecore_xcb_randr_12_outputs_get(root, num); +#endif + + return NULL; +} + +EAPI Ecore_X_Randr_Crtc +ecore_x_randr_output_crtc_get(Ecore_X_Window root, + Ecore_X_Randr_Output output) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(Ecore_X_Randr_None); + + if (output == Ecore_X_Randr_None) return Ecore_X_Randr_None; + + if (_randr_version >= RANDR_1_3) + return _ecore_xcb_randr_13_output_crtc_get(root, output); + else if (_randr_version == RANDR_1_2) + return _ecore_xcb_randr_12_output_crtc_get(root, output); +#endif + + return Ecore_X_Randr_None; +} + +EAPI void +ecore_x_randr_output_size_mm_get(Ecore_X_Window root, Ecore_X_Randr_Output output, int *w_mm, int *h_mm) +{ +#ifdef ECORE_XCB_RANDR + xcb_randr_get_output_info_cookie_t ocookie; + xcb_randr_get_output_info_reply_t *oreply; + xcb_timestamp_t timestamp = 0; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (w_mm) *w_mm = 0; + if (h_mm) *h_mm = 0; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(); + + if ((output != Ecore_X_Randr_None) && (_randr_version >= RANDR_1_3)) + { + xcb_randr_get_screen_resources_current_reply_t *reply; + + reply = _ecore_xcb_randr_13_get_resources(root); + timestamp = reply->config_timestamp; + free(reply); + } + else if ((output != Ecore_X_Randr_None) && (_randr_version == RANDR_1_2)) + { + xcb_randr_get_screen_resources_reply_t *reply; + + reply = _ecore_xcb_randr_12_get_resources(root); + timestamp = reply->config_timestamp; + free(reply); + } + + ocookie = + xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output, timestamp); + oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn, ocookie, NULL); + if (oreply) + { + if (w_mm) *w_mm = oreply->mm_width; + if (h_mm) *h_mm = oreply->mm_height; + free(oreply); + } +#endif +} + +/** + * @brief Sets the demanded parameters for a given CRTC. Note that the CRTC is + * auto enabled in it's preferred mode, when it was disabled before. + * + * @param root The root window which's default display will be queried. + * @param crtc The CRTC which's configuration should be altered. + * @param outputs An array of outputs, that should display this CRTC's content. + * @param noutputs Number of outputs in the array of outputs. If set to + * Ecore_X_Randr_Unset, current outputs and number of outputs will be used. If + * set to Ecore_X_Randr_None, CRTC will be disabled. + * @param x New x coordinate. If <0 (e.g. Ecore_X_Randr_Unset) the current x + * coordinate will be assumed. + * @param y New y coordinate. If <0 (e.g. Ecore_X_Randr_Unset) the current y + * coordinate will be assumed. + * @param mode The new mode to be set. If Ecore_X_Randr_None is passed, the + * CRTC will be disabled. If Ecore_X_Randr_Unset is passed, the current mode is + * assumed. + * @param orientation The new orientation to be set. If Ecore_X_Randr_Unset is + * used, the current mode is assumed. + * @return @c EINA_TRUE if the configuration alteration was successful, + * @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_x_randr_crtc_settings_set(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc, + Ecore_X_Randr_Output *outputs, + int noutputs, + int x, + int y, + Ecore_X_Randr_Mode mode, + Ecore_X_Randr_Orientation orientation) +{ + Eina_Bool ret = EINA_FALSE; +#ifdef ECORE_XCB_RANDR + xcb_timestamp_t stamp = 0; + xcb_randr_get_crtc_info_cookie_t ccookie; + xcb_randr_get_crtc_info_reply_t *creply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + + if (!_ecore_xcb_randr_crtc_validate(root, crtc)) return ret; + + if (_randr_version >= RANDR_1_3) + stamp = _ecore_xcb_randr_13_get_resource_timestamp(root); + else if (_randr_version == RANDR_1_2) + stamp = _ecore_xcb_randr_12_get_resource_timestamp(root); + + ccookie = + xcb_randr_get_crtc_info_unchecked(_ecore_xcb_conn, crtc, stamp); + creply = + xcb_randr_get_crtc_info_reply(_ecore_xcb_conn, ccookie, NULL); + if (creply) + { + xcb_randr_set_crtc_config_cookie_t scookie; + xcb_randr_set_crtc_config_reply_t *sreply; + + if ((mode == Ecore_X_Randr_None) || + (noutputs == Ecore_X_Randr_None)) + { + outputs = NULL; + noutputs = 0; + } + else if (noutputs == (int)Ecore_X_Randr_Unset) + { + outputs = xcb_randr_get_crtc_info_outputs(creply); + noutputs = creply->num_outputs; + } + if ((int)mode == Ecore_X_Randr_Unset) mode = creply->mode; + if (x < 0) x = creply->x; + if (y < 0) y = creply->y; + if ((int)orientation == Ecore_X_Randr_Unset) + orientation = creply->rotation; + + scookie = + xcb_randr_set_crtc_config_unchecked(_ecore_xcb_conn, + crtc, XCB_CURRENT_TIME, stamp, + x, y, mode, orientation, + noutputs, outputs); + sreply = + xcb_randr_set_crtc_config_reply(_ecore_xcb_conn, scookie, NULL); + if (sreply) + { + ret = (sreply->status == XCB_RANDR_SET_CONFIG_SUCCESS) ? + EINA_TRUE : EINA_FALSE; + free(sreply); + } + free(creply); + } +#endif + + return ret; +} + +/** + * @brief Sets a mode for a CRTC and the outputs attached to it. + * + * @param root The window's screen to be queried + * @param crtc The CRTC which shall be set + * @param outputs Array of outputs which have to be compatible with the mode. If + * @c NULL CRTC will be disabled. + * @param noutputs Number of outputs in array to be used. Use + * Ecore_X_Randr_Unset (or @c -1) to use currently used outputs. + * @param mode XID of the mode to be set. If set to @c 0 the CRTC will be + * disabled. If set to @c -1 the call will fail. + * @return @c EINA_TRUE if mode setting was successful, @c EINA_FALSE + * otherwise. + */ +EAPI Eina_Bool +ecore_x_randr_crtc_mode_set(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc, + Ecore_X_Randr_Output *outputs, + int noutputs, + Ecore_X_Randr_Mode mode) +{ + Eina_Bool ret = EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + + if ((int)mode == Ecore_X_Randr_Unset) return ret; + ret = + ecore_x_randr_crtc_settings_set(root, crtc, outputs, noutputs, + Ecore_X_Randr_Unset, Ecore_X_Randr_Unset, + mode, Ecore_X_Randr_Unset); +#endif + + return ret; +} + +/** + * @brief Get the current set mode of a given CRTC + * @param root the window's screen to be queried + * @param crtc the CRTC which's should be queried + * @return currently set mode or - in case parameters are invalid - + * Ecore_X_Randr_Unset + */ +EAPI Ecore_X_Randr_Mode +ecore_x_randr_crtc_mode_get(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc) +{ + Ecore_X_Randr_Mode ret = Ecore_X_Randr_Unset; +#ifdef ECORE_XCB_RANDR + xcb_timestamp_t stamp = 0; + xcb_randr_get_crtc_info_cookie_t ocookie; + xcb_randr_get_crtc_info_reply_t *oreply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(Ecore_X_Randr_Unset); + + if (!_ecore_xcb_randr_crtc_validate(root, crtc)) return ret; + + if (_randr_version >= RANDR_1_3) + stamp = _ecore_xcb_randr_13_get_resource_timestamp(root); + else if (_randr_version == RANDR_1_2) + stamp = _ecore_xcb_randr_12_get_resource_timestamp(root); + + ocookie = + xcb_randr_get_crtc_info_unchecked(_ecore_xcb_conn, crtc, stamp); + oreply = xcb_randr_get_crtc_info_reply(_ecore_xcb_conn, ocookie, NULL); + if (oreply) + { + ret = oreply->mode; + free(oreply); + } +#endif + + return ret; +} + +EAPI Ecore_X_Randr_Orientation +ecore_x_randr_crtc_orientation_get(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc) +{ + Ecore_X_Randr_Orientation ret = Ecore_X_Randr_None; +#ifdef ECORE_XCB_RANDR + xcb_timestamp_t stamp = 0; + xcb_randr_get_crtc_info_cookie_t ocookie; + xcb_randr_get_crtc_info_reply_t *oreply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(Ecore_X_Randr_None); + + if (!_ecore_xcb_randr_crtc_validate(root, crtc)) return ret; + + if (_randr_version >= RANDR_1_3) + stamp = _ecore_xcb_randr_13_get_resource_timestamp(root); + else if (_randr_version == RANDR_1_2) + stamp = _ecore_xcb_randr_12_get_resource_timestamp(root); + + ocookie = + xcb_randr_get_crtc_info_unchecked(_ecore_xcb_conn, crtc, stamp); + oreply = xcb_randr_get_crtc_info_reply(_ecore_xcb_conn, ocookie, NULL); + if (oreply) + { + ret = oreply->rotation; + free(oreply); + } +#endif + + return ret; +} + +EAPI Eina_Bool +ecore_x_randr_crtc_orientation_set(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc, + Ecore_X_Randr_Orientation orientation) +{ + Eina_Bool ret = EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + + if (orientation != Ecore_X_Randr_None) + { + ret = + ecore_x_randr_crtc_settings_set(root, crtc, NULL, + Ecore_X_Randr_Unset, Ecore_X_Randr_Unset, + Ecore_X_Randr_Unset, Ecore_X_Randr_Unset, + orientation); + } +#endif + return ret; +} + +EAPI Ecore_X_Randr_Orientation +ecore_x_randr_crtc_orientations_get(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc) +{ + Ecore_X_Randr_Orientation ret = Ecore_X_Randr_None; +#ifdef ECORE_XCB_RANDR + xcb_timestamp_t stamp = 0; + xcb_randr_get_crtc_info_cookie_t ocookie; + xcb_randr_get_crtc_info_reply_t *oreply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(Ecore_X_Randr_None); + + if (!_ecore_xcb_randr_crtc_validate(root, crtc)) return ret; + + if (_randr_version >= RANDR_1_3) + stamp = _ecore_xcb_randr_13_get_resource_timestamp(root); + else if (_randr_version == RANDR_1_2) + stamp = _ecore_xcb_randr_12_get_resource_timestamp(root); + + ocookie = + xcb_randr_get_crtc_info_unchecked(_ecore_xcb_conn, crtc, stamp); + oreply = + xcb_randr_get_crtc_info_reply(_ecore_xcb_conn, ocookie, NULL); + if (oreply) + { + ret = oreply->rotations; + free(oreply); + } +#endif + + return ret; +} + +/* + * @brief get a CRTC's possible outputs. + * @param root the root window which's screen will be queried + * @param num number of possible outputs referenced by given CRTC + */ +EAPI Ecore_X_Randr_Output * +ecore_x_randr_crtc_possible_outputs_get(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc, + int *num) +{ + Ecore_X_Randr_Output *ret = NULL; +#ifdef ECORE_XCB_RANDR + xcb_timestamp_t stamp = 0; + xcb_randr_get_crtc_info_cookie_t ocookie; + xcb_randr_get_crtc_info_reply_t *oreply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(NULL); + + if (!_ecore_xcb_randr_crtc_validate(root, crtc)) return ret; + + if (_randr_version >= RANDR_1_3) + stamp = _ecore_xcb_randr_13_get_resource_timestamp(root); + else if (_randr_version == RANDR_1_2) + stamp = _ecore_xcb_randr_12_get_resource_timestamp(root); + + ocookie = + xcb_randr_get_crtc_info_unchecked(_ecore_xcb_conn, crtc, stamp); + oreply = xcb_randr_get_crtc_info_reply(_ecore_xcb_conn, ocookie, NULL); + if (oreply) + { + if (num) *num = oreply->num_possible_outputs; + ret = malloc(sizeof(Ecore_X_Randr_Output) * + oreply->num_possible_outputs); + if (ret) + { + memcpy(ret, xcb_randr_get_crtc_info_possible(oreply), + sizeof(Ecore_X_Randr_Output) * + oreply->num_possible_outputs); + } + free(oreply); + } +#endif + + return ret; +} + +/* + * @brief get all known CRTCs related to a root window's screen + * @param root window which's screen's ressources are queried + * @param num number of CRTCs returned + * @return CRTC IDs + */ +EAPI Ecore_X_Randr_Crtc * +ecore_x_randr_crtcs_get(Ecore_X_Window root, + int *num) +{ + Ecore_X_Randr_Crtc *ret = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(NULL); + + if (_randr_version >= RANDR_1_3) + { + xcb_randr_get_screen_resources_current_reply_t *reply; + + reply = _ecore_xcb_randr_13_get_resources(root); + if (reply) + { + if (num) *num = reply->num_crtcs; + ret = malloc(sizeof(Ecore_X_Randr_Crtc) * reply->num_crtcs); + if (ret) + memcpy(ret, xcb_randr_get_screen_resources_current_crtcs(reply), + sizeof(Ecore_X_Randr_Crtc) * reply->num_crtcs); + free(reply); + } + } + else if (_randr_version == RANDR_1_2) + { + xcb_randr_get_screen_resources_reply_t *reply; + + reply = _ecore_xcb_randr_12_get_resources(root); + if (reply) + { + if (num) *num = reply->num_crtcs; + ret = malloc(sizeof(Ecore_X_Randr_Crtc) * reply->num_crtcs); + if (ret) + memcpy(ret, xcb_randr_get_screen_resources_crtcs(reply), + sizeof(Ecore_X_Randr_Crtc) * reply->num_crtcs); + free(reply); + } + } +#endif + + return ret; +} + +/* + * @deprecated bad naming. Use ecore_x_randr_window_crtcs_get instead. + * @brief Get the CRTCs, which display a certain window. + * + * @param window Window the displaying CRTCs shall be found for. + * @param num The number of CRTCs displaying the window. + * @return Array of CRTCs that display a certain window. @c NULL if no CRTCs + * was found that displays the specified window. + */ +EAPI Ecore_X_Randr_Crtc * +ecore_x_randr_current_crtc_get(Ecore_X_Window window, + int *num) +{ + return ecore_x_randr_window_crtcs_get(window, num); +} + +/* + * @brief Get the CRTCs, which display a certain window. + * + * @param window Window the displaying crtcs shall be found for. + * @param num The number of crtcs displaying the window. + * @return Array of crtcs that display a certain window. @c NULL if no crtcs + * was found that displays the specified window. + * @since 1.2.0 + */ +EAPI Ecore_X_Randr_Crtc * +ecore_x_randr_window_crtcs_get(Ecore_X_Window window, + int *num) +{ +#ifdef ECORE_XCB_RANDR + Ecore_X_Window root; + Eina_Rectangle w_geo, c_geo; + Ecore_X_Randr_Crtc *crtcs, *ret = NULL; + Ecore_X_Randr_Mode mode; + int ncrtcs, i, nret = 0; + xcb_translate_coordinates_cookie_t cookie; + xcb_translate_coordinates_reply_t *trans; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(NULL); + + ecore_x_window_geometry_get(window, &w_geo.x, &w_geo.y, &w_geo.w, &w_geo.h); + + root = ecore_x_window_root_get(window); + crtcs = ecore_x_randr_crtcs_get(root, &ncrtcs); + if (!crtcs) goto _ecore_x_randr_window_crtcs_get_fail; + + /* now get window RELATIVE to root window - thats what matters. */ + cookie = xcb_translate_coordinates(_ecore_xcb_conn, window, root, 0, 0); + trans = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie, NULL); + w_geo.x = trans->dst_x; + w_geo.y = trans->dst_y; + free(trans); + + ret = calloc(1, ncrtcs * sizeof(Ecore_X_Randr_Crtc)); + if (!ret) + { + free(crtcs); + goto _ecore_x_randr_window_crtcs_get_fail; + } + for (i = 0, nret = 0; i < ncrtcs; i++) + { + /* if crtc is not enabled, don't bother about it any further */ + mode = ecore_x_randr_crtc_mode_get(root, crtcs[i]); + if (mode == Ecore_X_Randr_None) continue; + + ecore_x_randr_crtc_geometry_get(root, crtcs[i], &c_geo.x, &c_geo.y, + &c_geo.w, &c_geo.h); + if (eina_rectangles_intersect(&w_geo, &c_geo)) + { + ret[nret] = crtcs[i]; + nret++; + } + } + free(crtcs); + + if (num) *num = nret; + return ret; + +_ecore_x_randr_window_crtcs_get_fail: +#endif + if (num) *num = 0; + return NULL; +} + +/* + * @brief get a CRTC's outputs. + * @param root the root window which's screen will be queried + * @param num number of outputs referenced by given CRTC + */ +EAPI Ecore_X_Randr_Output * +ecore_x_randr_crtc_outputs_get(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc, + int *num) +{ + Ecore_X_Randr_Output *ret = NULL; +#ifdef ECORE_XCB_RANDR + xcb_timestamp_t stamp = 0; + xcb_randr_get_crtc_info_cookie_t ocookie; + xcb_randr_get_crtc_info_reply_t *oreply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(NULL); + + if (!_ecore_xcb_randr_crtc_validate(root, crtc)) return ret; + + if (_randr_version >= RANDR_1_3) + stamp = _ecore_xcb_randr_13_get_resource_timestamp(root); + else if (_randr_version == RANDR_1_2) + stamp = _ecore_xcb_randr_12_get_resource_timestamp(root); + + ocookie = + xcb_randr_get_crtc_info_unchecked(_ecore_xcb_conn, crtc, stamp); + oreply = xcb_randr_get_crtc_info_reply(_ecore_xcb_conn, ocookie, NULL); + if (oreply) + { + if (num) *num = oreply->num_outputs; + ret = malloc(sizeof(Ecore_X_Randr_Output) * oreply->num_outputs); + if (ret) + memcpy(ret, xcb_randr_get_crtc_info_outputs(oreply), + sizeof(Ecore_X_Randr_Output) * oreply->num_outputs); + free(oreply); + } +#endif + + return ret; +} + +EAPI void +ecore_x_randr_crtc_geometry_get(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc, + int *x, + int *y, + int *w, + int *h) +{ +#ifdef ECORE_XCB_RANDR + xcb_timestamp_t stamp = 0; + xcb_randr_get_crtc_info_cookie_t ocookie; + xcb_randr_get_crtc_info_reply_t *oreply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(); + + if (!_ecore_xcb_randr_crtc_validate(root, crtc)) return; + + if (_randr_version >= RANDR_1_3) + stamp = _ecore_xcb_randr_13_get_resource_timestamp(root); + else if (_randr_version == RANDR_1_2) + stamp = _ecore_xcb_randr_12_get_resource_timestamp(root); + + ocookie = + xcb_randr_get_crtc_info_unchecked(_ecore_xcb_conn, crtc, stamp); + oreply = xcb_randr_get_crtc_info_reply(_ecore_xcb_conn, ocookie, NULL); + if (oreply) + { + if (x) *x = oreply->x; + if (y) *y = oreply->y; + if (w) *w = oreply->width; + if (h) *h = oreply->height; + free(oreply); + } +#endif +} + +/** + * @brief Sets a CRTC relative to another one. + * + * @param root The window on which CRTC's position will be set. + * @param crtc_r1 The CRTC to be positioned. + * @param crtc_r2 The CRTC the position should be relative to. + * @param policy The relation between the crtcs. + * @param alignment In case CRTCs size differ, aligns CRTC1 accordingly at + * CRTC2's borders. + * @return @c EINA_TRUE if crtc could be successfully positioned, @c EINA_FALSE + * if repositioning failed or if position of new crtc would be out of given + * screen's min/max bounds. + */ +EAPI Eina_Bool +ecore_x_randr_crtc_pos_relative_set(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc_r1, + Ecore_X_Randr_Crtc crtc_r2, + Ecore_X_Randr_Output_Policy policy, + Ecore_X_Randr_Relative_Alignment alignment) +{ +#ifdef ECORE_XCB_RANDR + Eina_Rectangle r1, r2; + int w_max = 0, h_max = 0, cw = 0, ch = 0, xn = -1, yn = -1; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + + if ((ecore_x_randr_crtc_mode_get(root, crtc_r1) == 0) || + (ecore_x_randr_crtc_mode_get(root, crtc_r2) == 0)) + return EINA_FALSE; + + if ((!_ecore_xcb_randr_crtc_validate(root, crtc_r1) || + (!(crtc_r1 != crtc_r2) && (!_ecore_xcb_randr_crtc_validate(root, crtc_r2))))) + return EINA_FALSE; + + ecore_x_randr_crtc_geometry_get(root, crtc_r1, &r1.x, &r1.y, &r1.w, &r1.h); + ecore_x_randr_crtc_geometry_get(root, crtc_r2, &r2.x, &r2.y, &r2.w, &r2.h); + ecore_x_randr_screen_size_range_get(root, NULL, NULL, &w_max, &h_max); + ecore_x_randr_screen_current_size_get(root, &cw, &ch, NULL, NULL); + + switch (policy) + { + case ECORE_X_RANDR_OUTPUT_POLICY_RIGHT: + xn = (r2.x + r2.w); + if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE) + yn = -1; + else if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL) + yn = ((int)(((double)r2.h / 2.0) + (double)r2.y - ((double)r1.h / 2.0))); + else if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR) + yn = ((int)((double)ch / 2.0) - ((double)r1.h / 2.0)); + break; + + case ECORE_X_RANDR_OUTPUT_POLICY_LEFT: + xn = (r2.x - r1.w); + if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE) + yn = -1; + else if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL) + yn = ((int)(((double)r2.h / 2.0) + (double)r2.y - ((double)r1.h / 2.0))); + else if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR) + yn = ((int)((double)ch / 2.0) - ((double)r1.h / 2.0)); + break; + + case ECORE_X_RANDR_OUTPUT_POLICY_BELOW: + yn = (r2.y + r2.h); + if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE) + xn = -1; + else if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL) + xn = ((int)((((double)r2.x + (double)r2.w) / 2.0) - ((double)r1.w / 2.0))); + else if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR) + xn = ((int)((double)cw / 2.0)); + break; + + case ECORE_X_RANDR_OUTPUT_POLICY_ABOVE: + yn = (r2.y - r1.h); + if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE) + xn = -1; + else if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL) + xn = ((int)((((double)r2.x + (double)r2.w) / 2.0) - ((double)r1.w / 2.0))); + else if (alignment == ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR) + xn = ((int)((double)cw / 2.0)); + break; + + case ECORE_X_RANDR_OUTPUT_POLICY_CLONE: + return ecore_x_randr_crtc_pos_set(root, crtc_r1, r2.x, r2.y); + break; + + case ECORE_X_RANDR_OUTPUT_POLICY_NONE: + break; + default: + return EINA_FALSE; + } + + if ((xn == r1.x) && (yn == r1.x)) return EINA_TRUE; + if (((yn + r1.h) > h_max) || ((xn + r1.w) > w_max)) + return EINA_FALSE; + + return ecore_x_randr_crtc_pos_set(root, crtc_r1, xn, yn); +#endif + + return EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_randr_move_all_crtcs_but(Ecore_X_Window root, + const Ecore_X_Randr_Crtc *not_moved, + int num, + int dx, + int dy) +{ + Eina_Bool ret = EINA_FALSE; +#ifdef ECORE_XCB_RANDR + Ecore_X_Randr_Crtc *crtcs = NULL, *move = NULL; + int i = 0, j = 0, k = 0, n = 0, total = 0; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + if ((num <= 0) || (!not_moved) || (!_ecore_xcb_randr_root_validate(root))) + return EINA_FALSE; + + crtcs = ecore_x_randr_crtcs_get(root, &total); + n = (total - num); + move = malloc(sizeof(Ecore_X_Randr_Crtc) * n); + if (move) + { + for (i = 0, k = 0; (i < total) && (k < n); i++) + { + for (j = 0; j < num; j++) + if (crtcs[i] == not_moved[j]) break; + if (j == num) + move[k++] = crtcs[i]; + } + ret = ecore_x_randr_move_crtcs(root, move, n, dx, dy); + free(move); + free(crtcs); + } +#endif + + return ret; +} + +EAPI void +ecore_x_randr_crtc_pos_get(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc, + int *x, + int *y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(); + + ecore_x_randr_crtc_geometry_get(root, crtc, x, y, NULL, NULL); +#endif +} + +/* + * @brief Sets the position of given CRTC within root window's screen. + * + * @param root The window's screen to be queried. + * @param crtc The CRTC which's position within the mentioned screen is to be + * altered. + * @param x Position on the x-axis (0 == left) of the screen. if x < 0 current + * value will be kept. + * @param y Position on the y-ayis (0 == top) of the screen. if y < 0, current + * value will be kept. + * @return @c EINA_TRUE if position could be successfully be altered. + */ +EAPI Eina_Bool +ecore_x_randr_crtc_pos_set(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc, + int x, + int y) +{ + Eina_Bool ret = EINA_FALSE; +#ifdef ECORE_XCB_RANDR + int w = 0, h = 0, nw = 0, nh = 0; + Eina_Rectangle rect; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + + ecore_x_randr_crtc_geometry_get(root, crtc, + &rect.x, &rect.y, &rect.w, &rect.h); + ecore_x_randr_screen_current_size_get(root, &w, &h, NULL, NULL); + if (x < 0) x = rect.x; + if (y < 0) y = rect.y; + if ((x + rect.w) > w) + nw = (x + rect.w); + if ((y + rect.h) > h) + nh = (y + rect.h); + + if ((nw != 0) || (nh != 0)) + { + if (!ecore_x_randr_screen_current_size_set(root, nw, nh, 0, 0)) + return EINA_FALSE; + } + + ret = ecore_x_randr_crtc_settings_set(root, crtc, NULL, -1, x, y, -1, -1); +#endif + + return ret; +} + +EAPI void +ecore_x_randr_crtc_size_get(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc, + int *w, + int *h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(); + ecore_x_randr_crtc_geometry_get(root, crtc, NULL, NULL, w, h); +#endif +} + +EAPI Ecore_X_Randr_Refresh_Rate +ecore_x_randr_crtc_refresh_rate_get(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc, + Ecore_X_Randr_Mode mode) +{ + Ecore_X_Randr_Refresh_Rate ret = 0.0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(0.0); + + if (!_ecore_xcb_randr_crtc_validate(root, crtc)) return 0.0; + + if (_randr_version >= RANDR_1_3) + { + xcb_randr_get_screen_resources_current_reply_t *reply; + + reply = _ecore_xcb_randr_13_get_resources(root); + if (reply) + { + xcb_randr_mode_info_iterator_t miter; + + miter = + xcb_randr_get_screen_resources_current_modes_iterator(reply); + while (miter.rem) + { + xcb_randr_mode_info_t *minfo; + + minfo = miter.data; + if (minfo->id == mode) + { + if ((minfo->htotal) && (minfo->vtotal)) + { + ret = ((double)minfo->dot_clock / + ((double)minfo->htotal * + (double)minfo->vtotal)); + } + break; + } + xcb_randr_mode_info_next(&miter); + } + free(reply); + } + } + else if (_randr_version == RANDR_1_2) + { + xcb_randr_get_screen_resources_reply_t *reply; + + reply = _ecore_xcb_randr_12_get_resources(root); + if (reply) + { + xcb_randr_mode_info_iterator_t miter; + + miter = xcb_randr_get_screen_resources_modes_iterator(reply); + while (miter.rem) + { + xcb_randr_mode_info_t *minfo; + + minfo = miter.data; + if (minfo->id == mode) + { + if ((minfo->htotal) && (minfo->vtotal)) + { + ret = ((double)minfo->dot_clock / + ((double)minfo->htotal * + (double)minfo->vtotal)); + } + break; + } + xcb_randr_mode_info_next(&miter); + } + free(reply); + } + } +#endif + return ret; +} + +/* + * @brief Move given CRTCs belonging to the given root window's screen dx/dy + * pixels relative to their current position. The screen size will be + * automatically adjusted if necessary and possible. + * + * @param root Window which's screen's resources are used. + * @param crtcs List of CRTCs to be moved. + * @param ncrtc Number of CRTCs in array. + * @param dx Amount of pixels the CRTCs should be moved in x direction. + * @param dy Amount of pixels the CRTCs should be moved in y direction. + * @return @c EINA_TRUE if all crtcs could be moved successfully. + */ +EAPI Eina_Bool +ecore_x_randr_move_crtcs(Ecore_X_Window root, + const Ecore_X_Randr_Crtc *crtcs, + int num, + int dx, + int dy) +{ + Eina_Bool ret = EINA_TRUE; +#ifdef ECORE_XCB_RANDR + xcb_timestamp_t stamp = 0; + xcb_randr_get_crtc_info_reply_t *oreply[num]; + int i = 0, cw = 0, ch = 0; + int mw = 0, mh = 0, nw = 0, nh = 0; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + + if (!_ecore_xcb_randr_root_validate(root)) return EINA_FALSE; + + if (_randr_version >= RANDR_1_3) + stamp = _ecore_xcb_randr_13_get_resource_timestamp(root); + else if (_randr_version == RANDR_1_2) + stamp = _ecore_xcb_randr_12_get_resource_timestamp(root); + + ecore_x_randr_screen_size_range_get(root, NULL, NULL, &mw, &mh); + ecore_x_randr_screen_current_size_get(root, &cw, &ch, NULL, NULL); + nw = cw; + nh = ch; + + for (i = 0; i < num; i++) + { + xcb_randr_get_crtc_info_cookie_t ocookie; + + ocookie = + xcb_randr_get_crtc_info_unchecked(_ecore_xcb_conn, crtcs[i], + stamp); + oreply[i] = xcb_randr_get_crtc_info_reply(_ecore_xcb_conn, + ocookie, NULL); + if (oreply[i]) + { + if (((oreply[i]->x + dx) < 0) || + ((oreply[i]->y + dy) < 0) || + ((oreply[i]->x + oreply[i]->width + dx) > mw) || + ((oreply[i]->y + oreply[i]->height + dy) > mh)) + { + continue; + } + nw = MAX((int)(oreply[i]->x + oreply[i]->width + dx), nw); + nh = MAX((int)(oreply[i]->y + oreply[i]->height + dy), nh); + } + } + + if ((nw > cw) || (nh > ch)) + { + if (!ecore_x_randr_screen_current_size_set(root, nw, nh, -1, -1)) + { + for (i = 0; i < num; i++) + if (oreply[i]) free(oreply[i]); + + return EINA_FALSE; + } + } + + for (i = 0; ((i < num) && (oreply[i])); i++) + { + if (!oreply[i]) continue; + if (!ecore_x_randr_crtc_settings_set(root, crtcs[i], NULL, -1, + (oreply[i]->x + dx), + (oreply[i]->y + dy), + oreply[i]->mode, + oreply[i]->rotation)) + { + ret = EINA_FALSE; + break; + } + } + + if (i < num) + { + while (i-- >= 0) + { + if (oreply[i]) + ecore_x_randr_crtc_settings_set(root, crtcs[i], NULL, -1, + (oreply[i]->x - dx), + (oreply[i]->y - dy), + oreply[i]->mode, + oreply[i]->rotation); + } + } + + for (i = 0; i < num; i++) + if (oreply[i]) free(oreply[i]); +#endif + + return ret; +} + +/** + * @brief enable event selection. This enables basic interaction with + * output/crtc events and requires RRandR >= 1.2. + * @param win select this window's properties for RandRR events + * @param on enable/disable selecting + */ +EAPI void +ecore_x_randr_events_select(Ecore_X_Window win, + Eina_Bool on) +{ +#ifdef ECORE_XCB_RANDR + uint16_t mask = 0; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + if (on) + { + mask = XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE; + if (_randr_version >= ((1 << 16) | 2)) + { + mask |= (XCB_RANDR_NOTIFY_MASK_CRTC_CHANGE | + XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE | + XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY); + } + } + + xcb_randr_select_input(_ecore_xcb_conn, win, mask); +#endif +} + +/** + * @brief removes unused screen space. The most upper left CRTC is set to 0x0 + * and all other CRTCs dx,dy respectively. + * @param root the window's screen which will be reset. + */ +EAPI void +ecore_x_randr_screen_reset(Ecore_X_Window root) +{ +#ifdef ECORE_XCB_RANDR + xcb_timestamp_t stamp = 0; + Ecore_X_Randr_Crtc *crtcs = NULL; + int total = 0, i = 0, w = 0, h = 0; + int dx = 100000, dy = 100000, num = 0; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + if (!_ecore_xcb_randr_root_validate(root)) return; + crtcs = ecore_x_randr_crtcs_get(root, &total); + + if (_randr_version >= RANDR_1_3) + stamp = _ecore_xcb_randr_13_get_resource_timestamp(root); + else if (_randr_version == RANDR_1_2) + stamp = _ecore_xcb_randr_12_get_resource_timestamp(root); + + /* I hate declaring variables inside code like this, but we need the + * value of 'total' before we can */ + Ecore_X_Randr_Crtc enabled[total]; + + for (i = 0; i < total; i++) + { + xcb_randr_get_crtc_info_cookie_t ocookie; + xcb_randr_get_crtc_info_reply_t *oreply; + + ocookie = + xcb_randr_get_crtc_info_unchecked(_ecore_xcb_conn, crtcs[i], stamp); + oreply = xcb_randr_get_crtc_info_reply(_ecore_xcb_conn, + ocookie, NULL); + if (!oreply) continue; + if ((oreply->mode <= 0) || (oreply->num_outputs == 0)) + { + free(oreply); + continue; + } + + enabled[num++] = crtcs[i]; + if ((int)(oreply->x + oreply->width) > w) + w = (oreply->x + oreply->width); + if ((int)(oreply->y + oreply->height) > h) + h = (oreply->y + oreply->height); + + if (oreply->x < dx) dx = oreply->x; + if (oreply->y < dy) dy = oreply->y; + + free(oreply); + } + free(crtcs); + + if ((dx > 0) || (dy > 0)) + { + if (ecore_x_randr_move_crtcs(root, enabled, num, -dx, -dy)) + { + w -= dx; + h -= dy; + } + } + + ecore_x_randr_screen_current_size_set(root, w, h, -1, -1); +#endif +} + +/* + * @param root window which's screen will be queried + * @param wmin minimum width the screen can be set to + * @param hmin minimum height the screen can be set to + * @param wmax maximum width the screen can be set to + * @param hmax maximum height the screen can be set to + */ +EAPI void +ecore_x_randr_screen_size_range_get(Ecore_X_Window root, + int *minw, + int *minh, + int *maxw, + int *maxh) +{ +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_size_range_cookie_t cookie; + xcb_randr_get_screen_size_range_reply_t *reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(); + + cookie = xcb_randr_get_screen_size_range_unchecked(_ecore_xcb_conn, root); + reply = xcb_randr_get_screen_size_range_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + if (minw) *minw = reply->min_width; + if (minh) *minh = reply->min_height; + if (maxw) *maxw = reply->max_width; + if (maxh) *maxh = reply->max_height; + free(reply); + } +#endif +} + +/* + * @param w width of screen in px + * @param h height of screen in px + */ +EAPI void +ecore_x_randr_screen_current_size_get(Ecore_X_Window root, + int *w, + int *h, + int *w_mm, + int *h_mm) +{ +#ifdef ECORE_XCB_RANDR + Ecore_X_Randr_Screen scr = 0; + xcb_screen_t *s; +# define RANDR_VALIDATE_ROOT(screen, root) \ + ((screen == _ecore_xcb_randr_root_to_screen(root)) != -1) +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(); + + if (!RANDR_VALIDATE_ROOT(scr, root)) return; + + s = ecore_x_screen_get(scr); + if (w) *w = s->width_in_pixels; + if (h) *h = s->height_in_pixels; + if (w_mm) *w_mm = s->width_in_millimeters; + if (h_mm) *h_mm = s->height_in_millimeters; +#endif +} + +/* + * @param root Window which's screen's size should be set. If invalid (e.g. + * @c NULL) no action is taken. + * @param w Width in px the screen should be set to. If out of valid + * boundaries, current value is assumed. + * @param h Height in px the screen should be set to. If out of valid + * boundaries, current value is assumed. + * @param w_mm Width in mm the screen should be set to. If @c 0, current + * aspect is assumed. + * @param h_mm Height in mm the screen should be set to. If @c 0, current + * aspect is assumed. + * @return @c EINA_TRUE if request was successfully sent or screen is already + * in requested size, @c EINA_FALSE if parameters are invalid. + */ +EAPI Eina_Bool +ecore_x_randr_screen_current_size_set(Ecore_X_Window root, + int w, + int h, + int w_mm, + int h_mm) +{ + Eina_Bool ret = EINA_TRUE; +#ifdef ECORE_XCB_RANDR + Ecore_X_Randr_Screen scr; + int wc = 0, hc = 0, w_mm_c = 0, h_mm_c = 0; + int mw = 0, mh = 0, xw = 0, xh = 0; +# define RANDR_VALIDATE_ROOT(screen, root) \ + ((screen == _ecore_xcb_randr_root_to_screen(root)) != -1) +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + + if (!RANDR_VALIDATE_ROOT(scr, root)) return EINA_FALSE; + ecore_x_randr_screen_current_size_get(root, &wc, &hc, &w_mm_c, &h_mm_c); + if ((w == wc) && (h == hc) && (w_mm == w_mm_c) && (h_mm == h_mm_c)) + return EINA_TRUE; + ecore_x_randr_screen_size_range_get(root, &mw, &mh, &xw, &xh); + if (((w != 1) && ((w < mw) || (w > xw))) || + ((h != -1) && ((h < mh) || (h > xh)))) return EINA_FALSE; + + if (w <= 0) + w = ((xcb_screen_t *)_ecore_xcb_screen)->width_in_pixels; + if (h <= 0) + h = ((xcb_screen_t *)_ecore_xcb_screen)->height_in_pixels; + + /* NB: Hmmmm, xlib version divides w_mm by width ... that seems wrong */ + if (w_mm <= 0) + w_mm = ((xcb_screen_t *)_ecore_xcb_screen)->width_in_millimeters; + if (h_mm <= 0) + h_mm = ((xcb_screen_t *)_ecore_xcb_screen)->height_in_millimeters; + + xcb_randr_set_screen_size(_ecore_xcb_conn, root, w, h, w_mm, h_mm); +#endif + + return ret; +} + +/* + * @deprecated bad naming. Use ecore_x_randr_window_outputs_get instead. + * @brief Get the outputs, which display a certain window. + * + * @param window Window the displaying outputs shall be found for. + * @param num The number of outputs displaying the window. + * @return Array of outputs that display a certain window. @c NULL if no + * outputs was found that displays the specified window. + */ + +Ecore_X_Randr_Output * +ecore_x_randr_current_output_get(Ecore_X_Window window, + int *num) +{ + return ecore_x_randr_window_outputs_get(window, num); +} + +/* + * @brief Get the outputs, which display a certain window. + * + * @param window Window the displaying outputs shall be found for. + * @param num The number of outputs displaying the window. + * @return Array of outputs that display a certain window. @c NULL if no + * outputs was found that displays the specified window. + */ +EAPI Ecore_X_Randr_Output * +ecore_x_randr_window_outputs_get(Ecore_X_Window window, + int *num) +{ +#ifdef ECORE_XCB_RANDR + Ecore_X_Window root; + Ecore_X_Randr_Crtc *crtcs; + Ecore_X_Randr_Output *outputs, *ret = NULL, *tret; + int ncrtcs, noutputs, i, nret = 0; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (num) *num = 0; + +#ifdef ECORE_XCB_RANDR + if (_randr_version < RANDR_1_2) goto _ecore_x_randr_current_output_get_fail; + + root = ecore_x_window_root_get(window); + if (!(crtcs = ecore_x_randr_window_crtcs_get(window, &ncrtcs))) + goto _ecore_x_randr_current_output_get_fail; + + for (i = 0, nret = 0; i < ncrtcs; i++) + { + + outputs = ecore_x_randr_crtc_outputs_get(root, crtcs[i], + &noutputs); + if (!outputs) + goto _ecore_x_randr_current_output_get_fail_free; + tret = realloc(ret, ((nret + noutputs) * sizeof(Ecore_X_Randr_Output))); + if (!tret) goto _ecore_x_randr_current_output_get_fail_free; + ret = tret; + memcpy(&ret[nret], outputs, (noutputs * sizeof(Ecore_X_Randr_Output))); + nret += noutputs; + free(outputs); + outputs = NULL; + } + free(crtcs); + + if (num) + *num = nret; + + return ret; + +_ecore_x_randr_current_output_get_fail_free: + free(outputs); + free(crtcs); + free(ret); +_ecore_x_randr_current_output_get_fail: +#endif + if (num) *num = 0; + return NULL; +} + +/* + * @brief get the backlight level of the given output + * @param root window which's screen should be queried + * @param output from which the backlight level should be retrieved + * @return the backlight level + */ +EAPI double +ecore_x_randr_output_backlight_level_get(Ecore_X_Window root, + Ecore_X_Randr_Output output) +{ +#ifdef ECORE_XCB_RANDR + Ecore_X_Atom _backlight; + xcb_intern_atom_cookie_t acookie; + xcb_intern_atom_reply_t *areply; + xcb_randr_get_output_property_cookie_t cookie; + xcb_randr_get_output_property_reply_t *reply; + xcb_randr_query_output_property_cookie_t qcookie; + xcb_randr_query_output_property_reply_t *qreply; + double dvalue; + long value, max, min; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(-1); + + acookie = + xcb_intern_atom_unchecked(_ecore_xcb_conn, 1, + strlen("Backlight"), "Backlight"); + areply = xcb_intern_atom_reply(_ecore_xcb_conn, acookie, NULL); + + if (!areply) + { + ERR("Backlight property is not suppported on this server or driver"); + return -1; + } + else + { + _backlight = areply->atom; + free(areply); + } + + if (!_ecore_xcb_randr_output_validate(root, output)) + { + ERR("Invalid output"); + return -1; + } + + cookie = + xcb_randr_get_output_property_unchecked(_ecore_xcb_conn, + output, _backlight, + XCB_ATOM_NONE, 0, 4, 0, 0); + reply = + xcb_randr_get_output_property_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) + { + WRN("Backlight not supported on this output"); + return -1; + } + + if ((reply->format != 32) || (reply->num_items != 1) || + (reply->type != XCB_ATOM_INTEGER)) + { + free(reply); + return -1; + } + + value = *((long *)xcb_randr_get_output_property_data(reply)); + free (reply); + + /* I have the current value of the backlight */ + /* Now retrieve the min and max intensities of the output */ + qcookie = + xcb_randr_query_output_property_unchecked(_ecore_xcb_conn, + output, _backlight); + qreply = + xcb_randr_query_output_property_reply(_ecore_xcb_conn, qcookie, NULL); + if (qreply) + { + dvalue = -1; + if ((qreply->range) && + (xcb_randr_query_output_property_valid_values_length(qreply) == 2)) + { + int32_t *vals; + + vals = xcb_randr_query_output_property_valid_values(qreply); + /* finally convert the current value in the interval [0..1] */ + min = vals[0]; + max = vals[1]; + dvalue = ((double)(value - min)) / ((double)(max - min)); + } + free(qreply); + return dvalue; + } +#endif + return -1; +} + +/* + * @brief Set the backlight level of a given output. + * + * @param root Window which's screen should be queried. + * @param output That should be set. + * @param level For which the backlight should be set. + * @return @c EINA_TRUE in case of success. + */ +EAPI Eina_Bool +ecore_x_randr_output_backlight_level_set(Ecore_X_Window root, + Ecore_X_Randr_Output output, + double level) +{ +#ifdef ECORE_XCB_RANDR + Ecore_X_Atom _backlight; + xcb_intern_atom_cookie_t acookie; + xcb_intern_atom_reply_t *areply; + xcb_randr_query_output_property_cookie_t qcookie; + xcb_randr_query_output_property_reply_t *qreply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + + if ((level < 0) || (level > 1)) + { + ERR("Backlight level should be between 0 and 1"); + return EINA_FALSE; + } + + if (!_ecore_xcb_randr_output_validate(root, output)) + { + ERR("Wrong output value"); + return EINA_FALSE; + } + + acookie = + xcb_intern_atom_unchecked(_ecore_xcb_conn, 1, + strlen("Backlight"), "Backlight"); + areply = xcb_intern_atom_reply(_ecore_xcb_conn, acookie, NULL); + if (!areply) + { + WRN("Backlight property is not suppported on this server or driver"); + return EINA_FALSE; + } + else + { + _backlight = areply->atom; + free(areply); + } + + qcookie = + xcb_randr_query_output_property_unchecked(_ecore_xcb_conn, + output, _backlight); + qreply = + xcb_randr_query_output_property_reply(_ecore_xcb_conn, qcookie, NULL); + if (qreply) + { + if ((qreply->range) && (qreply->length == 2)) + { + int32_t *vals; + double min, max, tmp; + long n; + + vals = xcb_randr_query_output_property_valid_values(qreply); + min = vals[0]; + max = vals[1]; + tmp = (level * (max - min)) + min; + n = tmp; + if (n > max) n = max; + if (n < min) n = min; + xcb_randr_change_output_property(_ecore_xcb_conn, output, + _backlight, XCB_ATOM_INTEGER, + 32, XCB_PROP_MODE_REPLACE, + 1, (unsigned char *)&n); + ecore_x_flush(); // needed + } + + free(qreply); + return EINA_TRUE; + } +#endif + return EINA_FALSE; +} + +/* + * @brief Check if a backlight is available. + * + * @return Whether a backlight is available. + */ +EAPI Eina_Bool +ecore_x_randr_output_backlight_available(void) +{ +#ifdef ECORE_XCB_RANDR + Ecore_X_Atom _backlight; + xcb_intern_atom_cookie_t acookie; + xcb_intern_atom_reply_t *areply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + + acookie = + xcb_intern_atom_unchecked(_ecore_xcb_conn, 1, + strlen("Backlight"), "Backlight"); + areply = xcb_intern_atom_reply(_ecore_xcb_conn, acookie, NULL); + + if (!areply) + { + ERR("Backlight property is not suppported on this server or driver"); + return EINA_FALSE; + } + else + { + _backlight = areply->atom; + free(areply); + return EINA_TRUE; + } +#endif + return EINA_FALSE; +} + +EAPI int +ecore_x_randr_edid_version_get(unsigned char *edid, unsigned long edid_length) +{ + if ((edid_length > _ECORE_X_RANDR_EDID_OFFSET_VERSION_MINOR) && + (ecore_x_randr_edid_has_valid_header(edid, edid_length))) + return (edid[_ECORE_X_RANDR_EDID_OFFSET_VERSION_MAJOR] << 8) | + edid[_ECORE_X_RANDR_EDID_OFFSET_VERSION_MINOR]; + return ECORE_X_RANDR_EDID_UNKNOWN_VALUE; +} + +EAPI char * +ecore_x_randr_edid_display_name_get(unsigned char *edid, unsigned long edid_length) +{ + unsigned char *block = NULL; + int version = 0; + + version = ecore_x_randr_edid_version_get(edid, edid_length); + if (version < ECORE_X_RANDR_EDID_VERSION_13) return NULL; + + _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block) + { + if (block[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] == 0xfc) + { + char *name, *p; + const char *edid_name; + + edid_name = (const char *)block + + _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_CONTENT; + name = + malloc(sizeof(char) * + _ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX); + if (!name) return NULL; + + strncpy(name, edid_name, + (_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX - 1)); + name[_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX] = 0; + for (p = name; *p; p++) + if ((*p < ' ') || (*p > '~')) *p = 0; + + return name; + } + } + return NULL; +} + +EAPI Eina_Bool +ecore_x_randr_edid_has_valid_header(unsigned char *edid, unsigned long edid_length) +{ + const unsigned char header[] = + { + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 + }; + + if ((!edid) || (edid_length < 8)) return EINA_FALSE; + if (!memcmp(edid, header, 8)) return EINA_TRUE; + return EINA_FALSE; +} + +/* local functions */ +static Eina_Bool +_ecore_xcb_randr_output_validate(Ecore_X_Window root, + Ecore_X_Randr_Output output) +{ + Eina_Bool ret = EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + + if ((output) && (_ecore_xcb_randr_root_validate(root))) + { + if (_randr_version >= RANDR_1_3) + { + xcb_randr_get_screen_resources_current_reply_t *reply; + + reply = _ecore_xcb_randr_13_get_resources(root); + if (reply) + { + int len = 0, i = 0; + xcb_randr_output_t *outputs; + + len = + xcb_randr_get_screen_resources_current_outputs_length(reply); + outputs = + xcb_randr_get_screen_resources_current_outputs(reply); + for (i = 0; i < len; i++) + { + if (outputs[i] == output) + { + ret = EINA_TRUE; + break; + } + } + free(reply); + } + } + else if (_randr_version == RANDR_1_2) + { + xcb_randr_get_screen_resources_reply_t *reply; + + reply = _ecore_xcb_randr_12_get_resources(root); + if (reply) + { + int len = 0, i = 0; + xcb_randr_output_t *outputs; + + len = xcb_randr_get_screen_resources_outputs_length(reply); + outputs = xcb_randr_get_screen_resources_outputs(reply); + for (i = 0; i < len; i++) + { + if (outputs[i] == output) + { + ret = EINA_TRUE; + break; + } + } + free(reply); + } + } + } +#endif + return ret; +} + +/** + * @brief Validates a CRTC for a given root window's screen. + * + * @param root The window which's default display will be queried. + * @param crtc The CRTC to be validated. + * @return In case it is found @c EINA_TRUE will be returned, else + * @c EINA_FALSE is returned. + */ +static Eina_Bool +_ecore_xcb_randr_crtc_validate(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc) +{ + Eina_Bool ret = EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + + if (((int)crtc == Ecore_X_Randr_None) || ((int)crtc == Ecore_X_Randr_Unset)) + return ret; + + if ((crtc) && (_ecore_xcb_randr_root_validate(root))) + { + if (_randr_version >= RANDR_1_3) + { + xcb_randr_get_screen_resources_current_reply_t *reply; + + reply = _ecore_xcb_randr_13_get_resources(root); + if (reply) + { + int i = 0; + xcb_randr_crtc_t *crtcs; + + crtcs = xcb_randr_get_screen_resources_current_crtcs(reply); + for (i = 0; i < reply->num_crtcs; i++) + { + if (crtcs[i] == crtc) + { + ret = EINA_TRUE; + break; + } + } + free(reply); + } + } + else if (_randr_version == RANDR_1_2) + { + xcb_randr_get_screen_resources_reply_t *reply; + + reply = _ecore_xcb_randr_12_get_resources(root); + if (reply) + { + int i = 0; + xcb_randr_crtc_t *crtcs; + + crtcs = xcb_randr_get_screen_resources_crtcs(reply); + for (i = 0; i < reply->num_crtcs; i++) + { + if (crtcs[i] == crtc) + { + ret = EINA_TRUE; + break; + } + } + free(reply); + } + } + } +#endif + + return ret; +} + +static Ecore_X_Randr_Mode * +_ecore_xcb_randr_12_output_modes_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *num, + int *npreferred) +{ + Ecore_X_Randr_Mode *modes = NULL; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_resources_reply_t *reply; + + reply = _ecore_xcb_randr_12_get_resources(root); + if (reply) + { + xcb_randr_get_output_info_cookie_t ocookie; + xcb_randr_get_output_info_reply_t *oreply; + + ocookie = + xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output, + reply->config_timestamp); + oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn, + ocookie, NULL); + if (oreply) + { + if (num) *num = oreply->num_modes; + if (npreferred) *npreferred = oreply->num_preferred; + + modes = malloc(sizeof(Ecore_X_Randr_Mode) * + oreply->num_modes); + if (modes) + { + xcb_randr_mode_t *rmodes; + int len = 0; + + len = xcb_randr_get_output_info_modes_length(oreply); + rmodes = xcb_randr_get_output_info_modes(oreply); + memcpy(modes, rmodes, sizeof(Ecore_X_Randr_Mode) * len); + } + free(oreply); + } + free(reply); + } +#endif + return modes; +} + +static Ecore_X_Randr_Mode * +_ecore_xcb_randr_13_output_modes_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *num, + int *npreferred) +{ + Ecore_X_Randr_Mode *modes = NULL; +#ifdef ECORE_XCB_RANDR + xcb_timestamp_t stamp = 0; + xcb_randr_get_output_info_cookie_t ocookie; + xcb_randr_get_output_info_reply_t *oreply; + + stamp = _ecore_xcb_randr_13_get_resource_timestamp(root); + + ocookie = + xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output, stamp); + oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn, ocookie, NULL); + if (oreply) + { + if (num) *num = oreply->num_modes; + if (npreferred) *npreferred = oreply->num_preferred; + + modes = malloc(sizeof(Ecore_X_Randr_Mode) * oreply->num_modes); + if (modes) + { + xcb_randr_mode_t *rmodes; + int len = 0; + + len = xcb_randr_get_output_info_modes_length(oreply); + rmodes = xcb_randr_get_output_info_modes(oreply); + memcpy(modes, rmodes, sizeof(Ecore_X_Randr_Mode) * len); + } + free(oreply); + } +#endif + return modes; +} + +static Ecore_X_Randr_Mode_Info * +_ecore_xcb_randr_12_mode_info_get(Ecore_X_Window root, + Ecore_X_Randr_Mode mode) +{ + Ecore_X_Randr_Mode_Info *ret = NULL; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_resources_reply_t *reply; + + reply = _ecore_xcb_randr_12_get_resources(root); + if (reply) + { + if ((ret = malloc(sizeof(Ecore_X_Randr_Mode_Info)))) + { + uint8_t *nbuf; + xcb_randr_mode_info_iterator_t miter; + + nbuf = xcb_randr_get_screen_resources_names(reply); + miter = xcb_randr_get_screen_resources_modes_iterator(reply); + while (miter.rem) + { + xcb_randr_mode_info_t *minfo; + + minfo = miter.data; + nbuf += minfo->name_len; + + if (minfo->id == mode) + { + ret->xid = minfo->id; + ret->width = minfo->width; + ret->height = minfo->height; + ret->dotClock = minfo->dot_clock; + ret->hSyncStart = minfo->hsync_start; + ret->hSyncEnd = minfo->hsync_end; + ret->hTotal = minfo->htotal; + ret->vSyncStart = minfo->vsync_start; + ret->vSyncEnd = minfo->vsync_end; + ret->vTotal = minfo->vtotal; + ret->modeFlags = minfo->mode_flags; + + ret->name = NULL; + ret->nameLength = minfo->name_len; + if (ret->nameLength > 0) + { + ret->name = malloc(ret->nameLength + 1); + if (ret->name) + memcpy(ret->name, nbuf, ret->nameLength + 1); + } + + break; + } + xcb_randr_mode_info_next(&miter); + } + } + + free(reply); + } +#endif + return ret; +} + +static Ecore_X_Randr_Mode_Info * +_ecore_xcb_randr_13_mode_info_get(Ecore_X_Window root, + Ecore_X_Randr_Mode mode) +{ + Ecore_X_Randr_Mode_Info *ret = NULL; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_resources_current_reply_t *reply; + + reply = _ecore_xcb_randr_13_get_resources(root); + if (reply) + { + if ((ret = malloc(sizeof(Ecore_X_Randr_Mode_Info)))) + { + uint8_t *nbuf; + xcb_randr_mode_info_iterator_t miter; + + nbuf = xcb_randr_get_screen_resources_current_names(reply); + miter = + xcb_randr_get_screen_resources_current_modes_iterator(reply); + while (miter.rem) + { + xcb_randr_mode_info_t *minfo; + + minfo = miter.data; + nbuf += minfo->name_len; + + if (minfo->id == mode) + { + ret->xid = minfo->id; + ret->width = minfo->width; + ret->height = minfo->height; + ret->dotClock = minfo->dot_clock; + ret->hSyncStart = minfo->hsync_start; + ret->hSyncEnd = minfo->hsync_end; + ret->hTotal = minfo->htotal; + ret->vSyncStart = minfo->vsync_start; + ret->vSyncEnd = minfo->vsync_end; + ret->vTotal = minfo->vtotal; + ret->modeFlags = minfo->mode_flags; + + ret->name = NULL; + ret->nameLength = minfo->name_len; + if (ret->nameLength > 0) + { + ret->name = malloc(ret->nameLength + 1); + if (ret->name) + memcpy(ret->name, nbuf, ret->nameLength + 1); + } + + break; + } + xcb_randr_mode_info_next(&miter); + } + } + + free(reply); + } +#endif + return ret; +} + +static Ecore_X_Randr_Mode_Info ** +_ecore_xcb_randr_12_modes_info_get(Ecore_X_Window root, + int *num) +{ + Ecore_X_Randr_Mode_Info **ret = NULL; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_resources_reply_t *reply; + + reply = _ecore_xcb_randr_12_get_resources(root); + if (reply) + { + if (num) *num = reply->num_modes; + ret = malloc(sizeof(Ecore_X_Randr_Mode_Info *) * reply->num_modes); + if (ret) + { + xcb_randr_mode_info_iterator_t miter; + int i = 0; + uint8_t *nbuf; + + nbuf = xcb_randr_get_screen_resources_names(reply); + miter = xcb_randr_get_screen_resources_modes_iterator(reply); + while (miter.rem) + { + xcb_randr_mode_info_t *minfo; + + minfo = miter.data; + nbuf += minfo->name_len; + if ((ret[i] = malloc(sizeof(Ecore_X_Randr_Mode_Info)))) + { + ret[i]->xid = minfo->id; + ret[i]->width = minfo->width; + ret[i]->height = minfo->height; + ret[i]->dotClock = minfo->dot_clock; + ret[i]->hSyncStart = minfo->hsync_start; + ret[i]->hSyncEnd = minfo->hsync_end; + ret[i]->hTotal = minfo->htotal; + ret[i]->vSyncStart = minfo->vsync_start; + ret[i]->vSyncEnd = minfo->vsync_end; + ret[i]->vTotal = minfo->vtotal; + ret[i]->modeFlags = minfo->mode_flags; + + ret[i]->name = NULL; + ret[i]->nameLength = minfo->name_len; + if (ret[i]->nameLength > 0) + { + ret[i]->name = malloc(ret[i]->nameLength + 1); + if (ret[i]->name) + memcpy(ret[i]->name, nbuf, + ret[i]->nameLength + 1); + } + } + else + { + while (i > 0) + free(ret[--i]); + free(ret); + ret = NULL; + break; + } + i++; + xcb_randr_mode_info_next(&miter); + } + } + free(reply); + } +#endif + return ret; +} + +static Ecore_X_Randr_Mode_Info ** +_ecore_xcb_randr_13_modes_info_get(Ecore_X_Window root, + int *num) +{ + Ecore_X_Randr_Mode_Info **ret = NULL; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_resources_current_reply_t *reply; + + reply = _ecore_xcb_randr_13_get_resources(root); + if (reply) + { + if (num) *num = reply->num_modes; + ret = malloc(sizeof(Ecore_X_Randr_Mode_Info *) * reply->num_modes); + if (ret) + { + xcb_randr_mode_info_iterator_t miter; + int i = 0; + uint8_t *nbuf; + + nbuf = xcb_randr_get_screen_resources_current_names(reply); + miter = + xcb_randr_get_screen_resources_current_modes_iterator(reply); + while (miter.rem) + { + xcb_randr_mode_info_t *minfo; + + minfo = miter.data; + nbuf += minfo->name_len; + if ((ret[i] = malloc(sizeof(Ecore_X_Randr_Mode_Info)))) + { + ret[i]->xid = minfo->id; + ret[i]->width = minfo->width; + ret[i]->height = minfo->height; + ret[i]->dotClock = minfo->dot_clock; + ret[i]->hSyncStart = minfo->hsync_start; + ret[i]->hSyncEnd = minfo->hsync_end; + ret[i]->hTotal = minfo->htotal; + ret[i]->vSyncStart = minfo->vsync_start; + ret[i]->vSyncEnd = minfo->vsync_end; + ret[i]->vTotal = minfo->vtotal; + ret[i]->modeFlags = minfo->mode_flags; + + ret[i]->name = NULL; + ret[i]->nameLength = minfo->name_len; + if (ret[i]->nameLength > 0) + { + ret[i]->name = malloc(ret[i]->nameLength + 1); + if (ret[i]->name) + memcpy(ret[i]->name, nbuf, + ret[i]->nameLength + 1); + } + } + else + { + while (i > 0) + free(ret[--i]); + free(ret); + ret = NULL; + break; + } + i++; + xcb_randr_mode_info_next(&miter); + } + } + free(reply); + } +#endif + return ret; +} + +static void +_ecore_xcb_randr_12_mode_size_get(Ecore_X_Window root, + Ecore_X_Randr_Mode mode, + int *w, + int *h) +{ + if (w) *w = 0; + if (h) *h = 0; + +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_resources_reply_t *reply; + + reply = _ecore_xcb_randr_12_get_resources(root); + if (reply) + { + xcb_randr_mode_info_iterator_t miter; + + miter = xcb_randr_get_screen_resources_modes_iterator(reply); + while (miter.rem) + { + xcb_randr_mode_info_t *minfo; + + minfo = miter.data; + if (minfo->id == mode) + { + if (w) *w = minfo->width; + if (h) *h = minfo->height; + break; + } + xcb_randr_mode_info_next(&miter); + } + free(reply); + } +#endif +} + +static void +_ecore_xcb_randr_13_mode_size_get(Ecore_X_Window root, + Ecore_X_Randr_Mode mode, + int *w, + int *h) +{ + if (w) *w = 0; + if (h) *h = 0; + +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_resources_current_reply_t *reply; + + reply = _ecore_xcb_randr_13_get_resources(root); + if (reply) + { + xcb_randr_mode_info_iterator_t miter; + + miter = xcb_randr_get_screen_resources_current_modes_iterator(reply); + while (miter.rem) + { + xcb_randr_mode_info_t *minfo; + + minfo = miter.data; + if (minfo->id == mode) + { + if (w) *w = minfo->width; + if (h) *h = minfo->height; + break; + } + xcb_randr_mode_info_next(&miter); + } + free(reply); + } +#endif +} + +static Ecore_X_Randr_Output * +_ecore_xcb_randr_12_output_clones_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *num) +{ + Ecore_X_Randr_Output *outputs = NULL; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_resources_reply_t *reply; + + reply = _ecore_xcb_randr_12_get_resources(root); + if (reply) + { + xcb_randr_get_output_info_cookie_t ocookie; + xcb_randr_get_output_info_reply_t *oreply; + + ocookie = + xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output, + reply->config_timestamp); + oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn, + ocookie, NULL); + if (oreply) + { + if (num) *num = oreply->num_clones; + + outputs = + malloc(sizeof(Ecore_X_Randr_Output) * oreply->num_clones); + if (outputs) + { + memcpy(outputs, xcb_randr_get_output_info_clones(oreply), + sizeof(Ecore_X_Randr_Output) * oreply->num_clones); + } + free(oreply); + } + free(reply); + } +#endif + return outputs; +} + +static Ecore_X_Randr_Output * +_ecore_xcb_randr_13_output_clones_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *num) +{ + Ecore_X_Randr_Output *outputs = NULL; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_resources_current_reply_t *reply; + + reply = _ecore_xcb_randr_13_get_resources(root); + if (reply) + { + xcb_randr_get_output_info_cookie_t ocookie; + xcb_randr_get_output_info_reply_t *oreply; + + ocookie = + xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output, + reply->config_timestamp); + oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn, + ocookie, NULL); + if (oreply) + { + if (num) *num = oreply->num_clones; + + outputs = + malloc(sizeof(Ecore_X_Randr_Output) * oreply->num_clones); + if (outputs) + { + memcpy(outputs, xcb_randr_get_output_info_clones(oreply), + sizeof(Ecore_X_Randr_Output) * oreply->num_clones); + } + free(oreply); + } + free(reply); + } +#endif + return outputs; +} + +static Ecore_X_Randr_Crtc * +_ecore_xcb_randr_12_output_possible_crtcs_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *num) +{ + Ecore_X_Randr_Crtc *crtcs = NULL; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_resources_reply_t *reply; + + reply = _ecore_xcb_randr_12_get_resources(root); + if (reply) + { + xcb_randr_get_output_info_cookie_t ocookie; + xcb_randr_get_output_info_reply_t *oreply; + + ocookie = + xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output, + reply->config_timestamp); + oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn, + ocookie, NULL); + if (oreply) + { + if (num) *num = oreply->num_crtcs; + + crtcs = malloc(sizeof(Ecore_X_Randr_Crtc) * oreply->num_crtcs); + if (crtcs) + { + memcpy(crtcs, xcb_randr_get_output_info_crtcs(oreply), + sizeof(Ecore_X_Randr_Crtc) * oreply->num_crtcs); + } + free(oreply); + } + free(reply); + } +#endif + return crtcs; +} + +static Ecore_X_Randr_Crtc * +_ecore_xcb_randr_13_output_possible_crtcs_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *num) +{ + Ecore_X_Randr_Crtc *crtcs = NULL; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_resources_current_reply_t *reply; + + reply = _ecore_xcb_randr_13_get_resources(root); + if (reply) + { + xcb_randr_get_output_info_cookie_t ocookie; + xcb_randr_get_output_info_reply_t *oreply; + + ocookie = + xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output, + reply->config_timestamp); + oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn, + ocookie, NULL); + if (oreply) + { + if (num) *num = oreply->num_crtcs; + + crtcs = malloc(sizeof(Ecore_X_Randr_Crtc) * oreply->num_crtcs); + if (crtcs) + { + memcpy(crtcs, xcb_randr_get_output_info_crtcs(oreply), + sizeof(Ecore_X_Randr_Crtc) * oreply->num_crtcs); + } + free(oreply); + } + free(reply); + } +#endif + return crtcs; +} + +static char * +_ecore_xcb_randr_12_output_name_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *len) +{ + char *ret = NULL; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_resources_reply_t *reply; + + reply = _ecore_xcb_randr_12_get_resources(root); + if (reply) + { + xcb_randr_get_output_info_cookie_t ocookie; + xcb_randr_get_output_info_reply_t *oreply; + + ocookie = + xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output, + reply->config_timestamp); + oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn, + ocookie, NULL); + if (oreply) + { + uint8_t *nbuf; + + nbuf = xcb_randr_get_output_info_name(oreply); + nbuf += oreply->name_len; + + if (len) *len = oreply->name_len; + if (oreply->name_len > 0) + { + ret = malloc(oreply->name_len + 1); + if (ret) + memcpy(ret, nbuf, oreply->name_len + 1); + } + + free(oreply); + } + free(reply); + } +#endif + return ret; +} + +static char * +_ecore_xcb_randr_13_output_name_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *len) +{ + char *ret = NULL; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_resources_current_reply_t *reply; + + reply = _ecore_xcb_randr_13_get_resources(root); + if (reply) + { + xcb_randr_get_output_info_cookie_t ocookie; + xcb_randr_get_output_info_reply_t *oreply; + + ocookie = + xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output, + reply->config_timestamp); + oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn, + ocookie, NULL); + if (oreply) + { + uint8_t *nbuf; + + nbuf = xcb_randr_get_output_info_name(oreply); + nbuf += oreply->name_len; + + if (len) *len = oreply->name_len; + if (oreply->name_len > 0) + { + ret = malloc(oreply->name_len + 1); + if (ret) + memcpy(ret, nbuf, oreply->name_len + 1); + } + + free(oreply); + } + free(reply); + } +#endif + return ret; +} + +static Ecore_X_Randr_Connection_Status +_ecore_xcb_randr_12_output_connection_status_get(Ecore_X_Window root, + Ecore_X_Randr_Output output) +{ + Ecore_X_Randr_Connection_Status ret = ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_resources_reply_t *reply; + + reply = _ecore_xcb_randr_12_get_resources(root); + if (reply) + { + xcb_randr_get_output_info_cookie_t ocookie; + xcb_randr_get_output_info_reply_t *oreply; + + ocookie = + xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output, + reply->config_timestamp); + oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn, + ocookie, NULL); + if (oreply) + { + ret = oreply->connection; + free(oreply); + } + free(reply); + } +#endif + return ret; +} + +static Ecore_X_Randr_Connection_Status +_ecore_xcb_randr_13_output_connection_status_get(Ecore_X_Window root, + Ecore_X_Randr_Output output) +{ + Ecore_X_Randr_Connection_Status ret = ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_resources_current_reply_t *reply; + + reply = _ecore_xcb_randr_13_get_resources(root); + if (reply) + { + xcb_randr_get_output_info_cookie_t ocookie; + xcb_randr_get_output_info_reply_t *oreply; + + ocookie = + xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output, + reply->config_timestamp); + oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn, + ocookie, NULL); + if (oreply) + { + ret = oreply->connection; + free(oreply); + } + free(reply); + } +#endif + return ret; +} + +static Ecore_X_Randr_Output * +_ecore_xcb_randr_12_outputs_get(Ecore_X_Window root, + int *num) +{ + Ecore_X_Randr_Output *ret = NULL; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_resources_reply_t *reply; + + reply = _ecore_xcb_randr_12_get_resources(root); + if (reply) + { + if (num) *num = reply->num_outputs; + ret = malloc(sizeof(Ecore_X_Randr_Output) * reply->num_outputs); + if (ret) + memcpy(ret, xcb_randr_get_screen_resources_outputs(reply), + sizeof(Ecore_X_Randr_Output) * reply->num_outputs); + free(reply); + } +#endif + return ret; +} + +static Ecore_X_Randr_Output * +_ecore_xcb_randr_13_outputs_get(Ecore_X_Window root, + int *num) +{ + Ecore_X_Randr_Output *ret = NULL; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_resources_current_reply_t *reply; + + reply = _ecore_xcb_randr_13_get_resources(root); + if (reply) + { + if (num) *num = reply->num_outputs; + ret = malloc(sizeof(Ecore_X_Randr_Output) * reply->num_outputs); + if (ret) + memcpy(ret, xcb_randr_get_screen_resources_current_outputs(reply), + sizeof(Ecore_X_Randr_Output) * reply->num_outputs); + free(reply); + } +#endif + return ret; +} + +static Ecore_X_Randr_Crtc +_ecore_xcb_randr_12_output_crtc_get(Ecore_X_Window root, + Ecore_X_Randr_Output output) +{ + Ecore_X_Randr_Crtc ret = Ecore_X_Randr_None; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_resources_reply_t *reply; + + reply = _ecore_xcb_randr_12_get_resources(root); + if (reply) + { + xcb_randr_get_output_info_cookie_t ocookie; + xcb_randr_get_output_info_reply_t *oreply; + + ocookie = + xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output, + reply->config_timestamp); + oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn, + ocookie, NULL); + if (oreply) + { + ret = oreply->crtc; + free(oreply); + } + free(reply); + } +#endif + return ret; +} + +static Ecore_X_Randr_Crtc +_ecore_xcb_randr_13_output_crtc_get(Ecore_X_Window root, + Ecore_X_Randr_Output output) +{ + Ecore_X_Randr_Crtc ret = Ecore_X_Randr_None; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_resources_current_reply_t *reply; + + reply = _ecore_xcb_randr_13_get_resources(root); + if (reply) + { + xcb_randr_get_output_info_cookie_t ocookie; + xcb_randr_get_output_info_reply_t *oreply; + + ocookie = + xcb_randr_get_output_info_unchecked(_ecore_xcb_conn, output, + reply->config_timestamp); + oreply = xcb_randr_get_output_info_reply(_ecore_xcb_conn, + ocookie, NULL); + if (oreply) + { + ret = oreply->crtc; + free(oreply); + } + free(reply); + } +#endif + return ret; +} + +static xcb_randr_get_screen_resources_reply_t * +_ecore_xcb_randr_12_get_resources(Ecore_X_Window win) +{ + xcb_randr_get_screen_resources_cookie_t cookie; + xcb_randr_get_screen_resources_reply_t *reply; + + cookie = xcb_randr_get_screen_resources_unchecked(_ecore_xcb_conn, win); + reply = xcb_randr_get_screen_resources_reply(_ecore_xcb_conn, cookie, NULL); + return reply; +} + +static xcb_randr_get_screen_resources_current_reply_t * +_ecore_xcb_randr_13_get_resources(Ecore_X_Window win) +{ + xcb_randr_get_screen_resources_current_cookie_t cookie; + xcb_randr_get_screen_resources_current_reply_t *reply; + + cookie = + xcb_randr_get_screen_resources_current_unchecked(_ecore_xcb_conn, win); + reply = + xcb_randr_get_screen_resources_current_reply(_ecore_xcb_conn, + cookie, NULL); + return reply; +} + +static xcb_timestamp_t +_ecore_xcb_randr_12_get_resource_timestamp(Ecore_X_Window win) +{ + xcb_timestamp_t stamp = 0; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_resources_reply_t *reply; + + reply = _ecore_xcb_randr_12_get_resources(win); + stamp = reply->config_timestamp; + free(reply); +#endif + return stamp; +} + +static xcb_timestamp_t +_ecore_xcb_randr_13_get_resource_timestamp(Ecore_X_Window win) +{ + xcb_timestamp_t stamp = 0; +#ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_resources_current_reply_t *reply; + + reply = _ecore_xcb_randr_13_get_resources(win); + stamp = reply->config_timestamp; + free(reply); +#endif + return stamp; +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_region.c b/src/lib/ecore_x/xcb/ecore_xcb_region.c new file mode 100644 index 0000000..a221d8f --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_region.c @@ -0,0 +1,159 @@ +#include "ecore_xcb_private.h" +#include + +/* + * [ ] XPolygonRegion + * [ ] XShrinkRegion + * [ ] XClipBox + * [ ] XXorRegion + */ + +EAPI Ecore_X_XRegion * +ecore_x_xregion_new() +{ + pixman_region16_t *region; + + region = (pixman_region16_t *)malloc(sizeof(pixman_region16_t)); + if (!region) return NULL; + + pixman_region_init(region); + + return (Ecore_X_XRegion *)region; +} + +EAPI void +ecore_x_xregion_free(Ecore_X_XRegion *region) +{ + if (!region) return; + + pixman_region_fini(region); + free(region); +} + +EAPI Eina_Bool +ecore_x_xregion_set(Ecore_X_XRegion *region, + Ecore_X_GC gc) +{ + xcb_rectangle_t *rects; + pixman_box16_t *boxes; + int num = 0, i = 0; + + CHECK_XCB_CONN; + + if (!region) return EINA_FALSE; + + boxes = pixman_region_rectangles((pixman_region16_t *)region, &num); + if ((!boxes) || (num == 0)) return EINA_FALSE; + + rects = (xcb_rectangle_t *)malloc(sizeof(xcb_rectangle_t) * num); + if (!rects) return EINA_FALSE; + + for (i = 0; i < num; i++) + { + rects[i].x = boxes[i].x1; + rects[i].y = boxes[i].y1; + rects[i].width = boxes[i].x2 - boxes[i].x1 + 1; + rects[i].height = boxes[i].y2 - boxes[i].y1 + 1; + } + + xcb_set_clip_rectangles(_ecore_xcb_conn, XCB_CLIP_ORDERING_YX_BANDED, + gc, 0, 0, num, rects); + +// ecore_x_flush(); + return EINA_TRUE; +} + +EAPI void +ecore_x_xregion_translate(Ecore_X_XRegion *region, + int x, + int y) +{ + if (!region) return; + + pixman_region_translate((pixman_region16_t *)region, x, y); +} + +EAPI Eina_Bool +ecore_x_xregion_intersect(Ecore_X_XRegion *dst, + Ecore_X_XRegion *r1, + Ecore_X_XRegion *r2) +{ + return pixman_region_intersect((pixman_region16_t *)dst, + (pixman_region16_t *)r1, + (pixman_region16_t *)r2); +} + +EAPI Eina_Bool +ecore_x_xregion_union(Ecore_X_XRegion *dst, + Ecore_X_XRegion *r1, + Ecore_X_XRegion *r2) +{ + return pixman_region_union((pixman_region16_t *)dst, + (pixman_region16_t *)r1, + (pixman_region16_t *)r2); +} + +EAPI Eina_Bool +ecore_x_xregion_union_rect(Ecore_X_XRegion *dst, + Ecore_X_XRegion *src, + Ecore_X_Rectangle *rect) +{ + return pixman_region_union_rect((pixman_region16_t *)dst, + (pixman_region16_t *)src, + rect->x, rect->y, rect->width, rect->height); +} + +EAPI Eina_Bool +ecore_x_xregion_subtract(Ecore_X_XRegion *dst, + Ecore_X_XRegion *rm, + Ecore_X_XRegion *rs) +{ + return pixman_region_subtract((pixman_region16_t *)dst, + (pixman_region16_t *)rm, + (pixman_region16_t *)rs); +} + +EAPI Eina_Bool +ecore_x_xregion_is_empty(Ecore_X_XRegion *region) +{ + if (!region) return EINA_TRUE; + + return !pixman_region_not_empty((pixman_region16_t *)region); +} + +EAPI Eina_Bool +ecore_x_xregion_is_equal(Ecore_X_XRegion *r1, + Ecore_X_XRegion *r2) +{ + if ((!r1) || (!r2)) return EINA_FALSE; + + return pixman_region_equal((pixman_region16_t *)r1, + (pixman_region16_t *)r2); +} + +EAPI Eina_Bool +ecore_x_xregion_point_contain(Ecore_X_XRegion *region, + int x, + int y) +{ + if (!region) return EINA_FALSE; + + return pixman_region_contains_point((pixman_region16_t *)region, x, y, NULL); +} + +EAPI Eina_Bool +ecore_x_xregion_rect_contain(Ecore_X_XRegion *region, + Ecore_X_Rectangle *rect) +{ + pixman_box16_t box; + + if ((!region) || (!rect)) return EINA_FALSE; + + box.x1 = rect->x; + box.y1 = rect->y; + box.x2 = rect->x + rect->width - 1; + box.y2 = rect->y + rect->height - 1; + + return pixman_region_contains_rectangle((pixman_region16_t *)region, &box); +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_render.c b/src/lib/ecore_x/xcb/ecore_xcb_render.c new file mode 100644 index 0000000..f36b4d2 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_render.c @@ -0,0 +1,225 @@ +#include "ecore_xcb_private.h" +#include // for isupper/tolower +#ifdef ECORE_XCB_RENDER +# include +# include +#endif + +/* local function prototypes */ +static Eina_Bool _ecore_xcb_render_parse_boolean(char *v); + +/* local variables */ +static Eina_Bool _render_avail = EINA_FALSE; +static Eina_Bool _render_argb = EINA_FALSE; +static Eina_Bool _render_anim = EINA_FALSE; + +void +_ecore_xcb_render_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_RENDER + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_render_id); +#endif +} + +void +_ecore_xcb_render_finalize(void) +{ +#ifdef ECORE_XCB_RENDER + const xcb_query_extension_reply_t *ext_reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_RENDER + ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_render_id); + if ((ext_reply) && (ext_reply->present)) + { + xcb_render_query_version_cookie_t cookie; + xcb_render_query_version_reply_t *reply; + + cookie = + xcb_render_query_version_unchecked(_ecore_xcb_conn, + XCB_RENDER_MAJOR_VERSION, + XCB_RENDER_MINOR_VERSION); + reply = xcb_render_query_version_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { +// if ((reply->major_version >= XCB_RENDER_MAJOR_VERSION) && + if (reply->minor_version >= XCB_RENDER_MINOR_VERSION) + { + char *v = NULL; + + _render_avail = EINA_TRUE; + _ecore_xcb_xdefaults_init(); + if ((reply->major_version > 0) || (reply->minor_version >= 5)) + { + _render_argb = EINA_TRUE; + v = getenv("XCURSOR_CORE"); + if (!v) + v = _ecore_xcb_xdefaults_string_get("Xcursor", "core"); + if ((v) && (_ecore_xcb_render_parse_boolean(v))) + _render_argb = EINA_FALSE; + } + if ((_render_argb) && + ((reply->major_version > 0) || (reply->minor_version >= 8))) + { + _render_anim = EINA_TRUE; + v = getenv("XCURSOR_ANIM"); + if (!v) + v = _ecore_xcb_xdefaults_string_get("Xcursor", "anim"); + if ((v) && (_ecore_xcb_render_parse_boolean(v))) + _render_anim = EINA_FALSE; + } + _ecore_xcb_xdefaults_shutdown(); + } + } + free(reply); + } +#endif +} + +Eina_Bool +_ecore_xcb_render_avail_get(void) +{ + return _render_avail; +} + +Eina_Bool +_ecore_xcb_render_argb_get(void) +{ + return _render_argb; +} + +Eina_Bool +_ecore_xcb_render_anim_get(void) +{ + return _render_anim; +} + +Eina_Bool +_ecore_xcb_render_visual_supports_alpha(Ecore_X_Visual visual) +{ + Eina_Bool ret = EINA_FALSE; +#ifdef ECORE_XCB_RENDER + const xcb_render_query_pict_formats_reply_t *reply; + xcb_render_pictvisual_t *vis; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!visual) return EINA_FALSE; + if (!_render_avail) return EINA_FALSE; + +#ifdef ECORE_XCB_RENDER + reply = xcb_render_util_query_formats(_ecore_xcb_conn); + if (!reply) return EINA_FALSE; + + vis = + xcb_render_util_find_visual_format(reply, + ((xcb_visualtype_t *)visual)->visual_id); + if (vis) + { + xcb_render_pictforminfo_t temp; + xcb_render_pictforminfo_t *format; + + temp.id = vis->format; + format = + xcb_render_util_find_format(reply, XCB_PICT_FORMAT_ID, &temp, 0); + + if ((format->type == XCB_RENDER_PICT_TYPE_DIRECT) && + (format->direct.alpha_mask)) + ret = EINA_TRUE; + } + +#endif + + return ret; +} + +uint32_t +_ecore_xcb_render_find_visual_id(int type, + Eina_Bool check_alpha) +{ +#ifdef ECORE_XCB_RENDER + const xcb_render_query_pict_formats_reply_t *reply; + xcb_render_pictvisual_t *visual = NULL; + xcb_render_pictscreen_iterator_t screens; + xcb_render_pictdepth_iterator_t depths; + xcb_render_pictvisual_iterator_t visuals; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_render_avail) return 0; + +#ifdef ECORE_XCB_RENDER + reply = xcb_render_util_query_formats(_ecore_xcb_conn); + if (!reply) return 0; + + for (screens = xcb_render_query_pict_formats_screens_iterator(reply); + screens.rem; xcb_render_pictscreen_next(&screens)) + { + for (depths = xcb_render_pictscreen_depths_iterator(screens.data); + depths.rem; xcb_render_pictdepth_next(&depths)) + { + for (visuals = xcb_render_pictdepth_visuals_iterator(depths.data); + visuals.rem; xcb_render_pictvisual_next(&visuals)) + { + xcb_render_pictforminfo_t temp; + xcb_render_pictforminfo_t *format; + + visual = visuals.data; + temp.id = visual->format; + + format = + xcb_render_util_find_format(reply, XCB_PICT_FORMAT_ID, + &temp, 0); + if (!format) continue; + if (format->type == type) + { + if (check_alpha) + { + if (format->direct.alpha_mask) + return visual->visual; + } + else + return visual->visual; + } + } + } + } +#endif + + return 0; +} + +/* local function prototypes */ +static Eina_Bool +_ecore_xcb_render_parse_boolean(char *v) +{ + char c; + + c = *v; + if (isupper((int)c)) + c = tolower(c); + if ((c == 't') || (c == 'y') || (c == '1')) + return EINA_TRUE; + if ((c == 'f') || (c == 'n') || (c == '0')) + return EINA_FALSE; + if (c == 'o') + { + char d; + + d = v[1]; + if (isupper((int)d)) + d = tolower(d); + if (d == 'n') return EINA_TRUE; + if (d == 'f') return EINA_FALSE; + } + return EINA_FALSE; +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_screensaver.c b/src/lib/ecore_x/xcb/ecore_xcb_screensaver.c new file mode 100644 index 0000000..b48cb9a --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_screensaver.c @@ -0,0 +1,371 @@ +#include "ecore_xcb_private.h" +# ifdef ECORE_XCB_SCREENSAVER +# include +# endif + +/* local variables */ +static Eina_Bool _screensaver_avail = EINA_FALSE; + +/* external variables */ +int _ecore_xcb_event_screensaver = -1; + +void +_ecore_xcb_screensaver_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_SCREENSAVER + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_screensaver_id); +#endif +} + +void +_ecore_xcb_screensaver_finalize(void) +{ +#ifdef ECORE_XCB_SCREENSAVER + const xcb_query_extension_reply_t *ext_reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_SCREENSAVER + ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_screensaver_id); + if ((ext_reply) && (ext_reply->present)) + { + xcb_screensaver_query_version_cookie_t cookie; + xcb_screensaver_query_version_reply_t *reply; + + cookie = + xcb_screensaver_query_version_unchecked(_ecore_xcb_conn, + XCB_SCREENSAVER_MAJOR_VERSION, + XCB_SCREENSAVER_MINOR_VERSION); + reply = + xcb_screensaver_query_version_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + if ((reply->server_major_version >= XCB_SCREENSAVER_MAJOR_VERSION) && + (reply->server_minor_version >= XCB_SCREENSAVER_MINOR_VERSION)) + _screensaver_avail = EINA_TRUE; + + free(reply); + } + + if (_screensaver_avail) + _ecore_xcb_event_screensaver = ext_reply->first_event; + } +#endif +} + +EAPI int +ecore_x_screensaver_idle_time_get(void) +{ + int ret = 0; +#ifdef ECORE_XCB_SCREENSAVER + xcb_screensaver_query_info_cookie_t cookie; + xcb_screensaver_query_info_reply_t *reply; + Ecore_X_Window root; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_screensaver_avail) return 0; + +#ifdef ECORE_XCB_SCREENSAVER + root = ((xcb_screen_t *)_ecore_xcb_screen)->root; + cookie = xcb_screensaver_query_info_unchecked(_ecore_xcb_conn, root); + reply = xcb_screensaver_query_info_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return 0; + ret = (reply->ms_until_server / 1000); + free(reply); +#endif + + return ret; +} + +EAPI void +ecore_x_screensaver_set(int timeout, + int interval, + int prefer_blanking, + int allow_exposures) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_screensaver_avail) return; + +#ifdef ECORE_XCB_SCREENSAVER + xcb_set_screen_saver(_ecore_xcb_conn, + timeout, interval, prefer_blanking, allow_exposures); +#endif +} + +EAPI void +ecore_x_screensaver_timeout_set(int timeout) +{ +#ifdef ECORE_XCB_SCREENSAVER + xcb_get_screen_saver_cookie_t cookie; + xcb_get_screen_saver_reply_t *reply; + uint16_t pint; + uint8_t pblank, pexpo; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_screensaver_avail) return; + +#ifdef ECORE_XCB_SCREENSAVER + cookie = xcb_get_screen_saver_unchecked(_ecore_xcb_conn); + reply = xcb_get_screen_saver_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return; + pint = reply->interval; + pblank = reply->prefer_blanking; + pexpo = reply->allow_exposures; + free(reply); + xcb_set_screen_saver(_ecore_xcb_conn, timeout, pint, pblank, pexpo); +#endif +} + +EAPI int +ecore_x_screensaver_timeout_get(void) +{ + int timeout = 0; +#ifdef ECORE_XCB_SCREENSAVER + xcb_get_screen_saver_cookie_t cookie; + xcb_get_screen_saver_reply_t *reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_screensaver_avail) return 0; + +#ifdef ECORE_XCB_SCREENSAVER + cookie = xcb_get_screen_saver_unchecked(_ecore_xcb_conn); + reply = xcb_get_screen_saver_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return 0; + timeout = reply->timeout; + free(reply); +#endif + + return timeout; +} + +EAPI void +ecore_x_screensaver_blank_set(int blank) +{ +#ifdef ECORE_XCB_SCREENSAVER + xcb_get_screen_saver_cookie_t cookie; + xcb_get_screen_saver_reply_t *reply; + uint16_t pint, pto; + uint8_t pexpo; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_screensaver_avail) return; + +#ifdef ECORE_XCB_SCREENSAVER + cookie = xcb_get_screen_saver_unchecked(_ecore_xcb_conn); + reply = xcb_get_screen_saver_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return; + pto = reply->timeout; + pint = reply->interval; + pexpo = reply->allow_exposures; + free(reply); + xcb_set_screen_saver(_ecore_xcb_conn, pto, pint, blank, pexpo); +#endif +} + +EAPI int +ecore_x_screensaver_blank_get(void) +{ + int blank = 0; +#ifdef ECORE_XCB_SCREENSAVER + xcb_get_screen_saver_cookie_t cookie; + xcb_get_screen_saver_reply_t *reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_screensaver_avail) return 0; + +#ifdef ECORE_XCB_SCREENSAVER + cookie = xcb_get_screen_saver_unchecked(_ecore_xcb_conn); + reply = xcb_get_screen_saver_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return 0; + blank = reply->prefer_blanking; + free(reply); +#endif + + return blank; +} + +EAPI void +ecore_x_screensaver_expose_set(int expose) +{ +#ifdef ECORE_XCB_SCREENSAVER + xcb_get_screen_saver_cookie_t cookie; + xcb_get_screen_saver_reply_t *reply; + uint16_t pint, pto; + uint8_t pblank; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_screensaver_avail) return; + +#ifdef ECORE_XCB_SCREENSAVER + cookie = xcb_get_screen_saver_unchecked(_ecore_xcb_conn); + reply = xcb_get_screen_saver_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return; + pto = reply->timeout; + pint = reply->interval; + pblank = reply->prefer_blanking; + free(reply); + xcb_set_screen_saver(_ecore_xcb_conn, pto, pint, pblank, expose); +#endif +} + +EAPI int +ecore_x_screensaver_expose_get(void) +{ + int expose = 0; +#ifdef ECORE_XCB_SCREENSAVER + xcb_get_screen_saver_cookie_t cookie; + xcb_get_screen_saver_reply_t *reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_screensaver_avail) return 0; + +#ifdef ECORE_XCB_SCREENSAVER + cookie = xcb_get_screen_saver_unchecked(_ecore_xcb_conn); + reply = xcb_get_screen_saver_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return 0; + expose = reply->allow_exposures; + free(reply); +#endif + + return expose; +} + +EAPI void +ecore_x_screensaver_interval_set(int interval) +{ +#ifdef ECORE_XCB_SCREENSAVER + xcb_get_screen_saver_cookie_t cookie; + xcb_get_screen_saver_reply_t *reply; + uint16_t pto; + uint8_t pblank, pexpose; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_screensaver_avail) return; + +#ifdef ECORE_XCB_SCREENSAVER + cookie = xcb_get_screen_saver_unchecked(_ecore_xcb_conn); + reply = xcb_get_screen_saver_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return; + pto = reply->timeout; + pblank = reply->prefer_blanking; + pexpose = reply->allow_exposures; + free(reply); + xcb_set_screen_saver(_ecore_xcb_conn, pto, interval, pblank, pexpose); +#endif +} + +EAPI int +ecore_x_screensaver_interval_get(void) +{ + int interval = 0; +#ifdef ECORE_XCB_SCREENSAVER + xcb_get_screen_saver_cookie_t cookie; + xcb_get_screen_saver_reply_t *reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_screensaver_avail) return 0; + +#ifdef ECORE_XCB_SCREENSAVER + cookie = xcb_get_screen_saver_unchecked(_ecore_xcb_conn); + reply = xcb_get_screen_saver_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return 0; + interval = reply->interval; + free(reply); +#endif + + return interval; +} + +EAPI void +ecore_x_screensaver_event_listen_set(Eina_Bool on) +{ +#ifdef ECORE_XCB_SCREENSAVER + Ecore_X_Window root; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_screensaver_avail) return; + +#ifdef ECORE_XCB_SCREENSAVER + root = ((xcb_screen_t *)_ecore_xcb_screen)->root; + if (on) + xcb_screensaver_select_input(_ecore_xcb_conn, root, + XCB_SCREENSAVER_EVENT_NOTIFY_MASK | + XCB_SCREENSAVER_EVENT_CYCLE_MASK + ); + else + xcb_screensaver_select_input(_ecore_xcb_conn, root, 0); +#endif +} + +EAPI Eina_Bool +ecore_x_screensaver_event_available_get(void) +{ + return _screensaver_avail; +} + +EAPI Eina_Bool +ecore_x_screensaver_custom_blanking_enable(void) +{ +#ifdef ECORE_XCB_SCREENSAVER + uint32_t mask_list[9]; + + xcb_screensaver_set_attributes_checked + (_ecore_xcb_conn, + ((xcb_screen_t *)_ecore_xcb_screen)->root, + -9999, -9999, 1, 1, 0, + XCB_WINDOW_CLASS_INPUT_ONLY. + XCB_COPY_FROM_PARENT, XCB_COPY_FROM_PARENT, + 0, mask_list); + return EINA_TRUE; +#else + return EINA_FALSE; +#endif +} + +EAPI Eina_Bool +ecore_x_screensaver_custom_blanking_disable(void) +{ +#ifdef ECORE_XCB_SCREENSAVER + xcb_screensaver_unset_attributes_checked + (_ecore_xcb_conn, + ((xcb_screen_t *)_ecore_xcb_screen)->root); + return EINA_TRUE; +#else + return EINA_FALSE; +#endif +} diff --git a/src/lib/ecore_x/xcb/ecore_xcb_selection.c b/src/lib/ecore_x/xcb/ecore_xcb_selection.c new file mode 100644 index 0000000..afb1b8c --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_selection.c @@ -0,0 +1,1033 @@ +#include "ecore_xcb_private.h" +//#include "Ecore_X_Atoms.h" + +#define ECORE_XCB_SELECTION_DATA(x) ((Ecore_X_Selection_Data *)(x)) + +/* local function prototypes */ +static Eina_Bool _ecore_xcb_selection_converter_text(char *target, + void *data, + int size, + void **data_ret, + int *size_ret, + Ecore_X_Atom *type, + int *size_type); +static void *_ecore_xcb_selection_parser_text(const char *target __UNUSED__, + void *data, + int size, + int format __UNUSED__); +static void *_ecore_xcb_selection_parser_files(const char *target, + void *data, + int size, + int format __UNUSED__); +static void *_ecore_xcb_selection_parser_targets(const char *target __UNUSED__, + void *data, + int size, + int format __UNUSED__); + +//static int _ecore_xcb_selection_data_free(void *data); +static int _ecore_xcb_selection_data_text_free(void *data); +static int _ecore_xcb_selection_data_targets_free(void *data); +static int _ecore_xcb_selection_data_files_free(void *data); +static int _ecore_xcb_selection_data_default_free(void *data); +static Eina_Bool _ecore_xcb_selection_set(Ecore_X_Window win, + const void *data, + int size, + Ecore_X_Atom selection); +static void _ecore_xcb_selection_request(Ecore_X_Window win, + Ecore_X_Atom selection, + const char *target); +static Ecore_X_Atom _ecore_xcb_selection_target_atom_get(const char *target); + +/* local variables */ +static Ecore_X_Selection_Intern _selections[4]; +static Ecore_X_Selection_Converter *_converters = NULL; +static Ecore_X_Selection_Parser *_parsers = NULL; + +/* local functions */ +void +_ecore_xcb_selection_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + memset(_selections, 0, sizeof(_selections)); + + /* init converters */ + ecore_x_selection_converter_atom_add(ECORE_X_ATOM_TEXT, + _ecore_xcb_selection_converter_text); + ecore_x_selection_converter_atom_add(ECORE_X_ATOM_UTF8_STRING, + _ecore_xcb_selection_converter_text); + ecore_x_selection_converter_atom_add(ECORE_X_ATOM_COMPOUND_TEXT, + _ecore_xcb_selection_converter_text); + ecore_x_selection_converter_atom_add(ECORE_X_ATOM_STRING, + _ecore_xcb_selection_converter_text); + + /* init parsers */ + ecore_x_selection_parser_add("text/plain", + _ecore_xcb_selection_parser_text); + ecore_x_selection_parser_add(ECORE_X_SELECTION_TARGET_UTF8_STRING, + _ecore_xcb_selection_parser_text); + ecore_x_selection_parser_add("text/uri-list", + _ecore_xcb_selection_parser_files); + ecore_x_selection_parser_add("_NETSCAPE_URL", + _ecore_xcb_selection_parser_files); + ecore_x_selection_parser_add(ECORE_X_SELECTION_TARGET_TARGETS, + _ecore_xcb_selection_parser_targets); +} + +void +_ecore_xcb_selection_shutdown(void) +{ + Ecore_X_Selection_Converter *cnv; + Ecore_X_Selection_Parser *prs; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + /* free selection converters */ + cnv = _converters; + while (cnv) + { + Ecore_X_Selection_Converter *tmp; + + tmp = cnv->next; + free(cnv); + cnv = tmp; + } + _converters = NULL; + + /* free parsers */ + prs = _parsers; + while (prs) + { + Ecore_X_Selection_Parser *tmp; + + tmp = prs; + prs = prs->next; + free(tmp->target); + free(tmp); + } + _parsers = NULL; +} + +/* public functions */ +EAPI void +ecore_x_selection_converter_atom_add(Ecore_X_Atom target, + Eina_Bool (*func)(char *target, + void *data, + int size, + void **data_ret, + int *size_ret, + Ecore_X_Atom *type, + int *size_type)) +{ + Ecore_X_Selection_Converter *cnv; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + cnv = _converters; + if (_converters) + { + while (1) + { + if (cnv->target == target) + { + cnv->convert = func; + return; + } + if (cnv->next) + cnv = cnv->next; + else + break; + } + cnv->next = calloc(1, sizeof(Ecore_X_Selection_Converter)); + if (!cnv->next) return; + cnv = cnv->next; + } + else + { + _converters = calloc(1, sizeof(Ecore_X_Selection_Converter)); + if (!_converters) return; + cnv = _converters; + } + cnv->target = target; + cnv->convert = func; +} + +EAPI void +ecore_x_selection_converter_add(char *target, + Eina_Bool (*func)(char *target, + void *data, + int size, + void **date_ret, + int *size_ret, + Ecore_X_Atom *atom_ret, + int *ret)) +{ + Ecore_X_Atom atarget; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if ((!func) || (!target)) return; + atarget = _ecore_xcb_selection_target_atom_get(target); + ecore_x_selection_converter_atom_add(atarget, func); +} + +EAPI void +ecore_x_selection_converter_del(char *target) +{ + Ecore_X_Atom atarget; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!target) return; + atarget = _ecore_xcb_selection_target_atom_get(target); + ecore_x_selection_converter_atom_del(atarget); +} + +EAPI void +ecore_x_selection_converter_atom_del(Ecore_X_Atom target) +{ + Ecore_X_Selection_Converter *conv, *pconv = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + conv = _converters; + while (conv) + { + if (conv->target == target) + { + if (pconv) + pconv->next = conv->next; + else + _converters = conv->next; + free(conv); + return; + } + pconv = conv; + conv = conv->next; + } +} + +EAPI void +ecore_x_selection_parser_add(const char *target, + void *(*func)(const char *target, void *data, int size, int format)) +{ + Ecore_X_Selection_Parser *prs; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!target) return; + prs = _parsers; + if (prs) + { + while (prs->next) + { + if (!strcmp(prs->target, target)) + { + prs->parse = func; + return; + } + prs = prs->next; + } + prs->next = calloc(1, sizeof(Ecore_X_Selection_Parser)); + prs = prs->next; + } + else + { + _parsers = calloc(1, sizeof(Ecore_X_Selection_Parser)); + prs = _parsers; + } + prs->target = strdup(target); + prs->parse = func; +} + +EAPI void +ecore_x_selection_parser_del(const char *target) +{ + Ecore_X_Selection_Parser *prs, *pprs = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!target) return; + + prs = _parsers; + while (prs) + { + if (!strcmp(prs->target, target)) + { + if (pprs) + pprs->next = prs->next; + else + _parsers = prs->next; + free(prs->target); + free(prs); + return; + } + pprs = prs; + prs = prs->next; + } +} + +/** + * Claim ownership of the PRIMARY selection and set its data. + * @param w The window to which this selection belongs + * @param data The data associated with the selection + * @param size The size of the data buffer in bytes + * @return Returns 1 if the ownership of the selection was successfully + * claimed, or 0 if unsuccessful. + */ +EAPI Eina_Bool +ecore_x_selection_primary_set(Ecore_X_Window win, + const void *data, + int size) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _ecore_xcb_selection_set(win, data, size, + ECORE_X_ATOM_SELECTION_PRIMARY); +} + +/** + * Release ownership of the primary selection + * @return Returns 1 if the selection was successfully cleared, + * or 0 if unsuccessful. + */ +EAPI Eina_Bool +ecore_x_selection_primary_clear(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _ecore_xcb_selection_set(XCB_NONE, NULL, 0, + ECORE_X_ATOM_SELECTION_PRIMARY); +} + +EAPI void +ecore_x_selection_primary_request(Ecore_X_Window win, + const char *target) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_xcb_selection_request(win, ECORE_X_ATOM_SELECTION_PRIMARY, target); +} + +/** + * Claim ownership of the SECONDARY selection and set its data. + * @param w The window to which this selection belongs + * @param data The data associated with the selection + * @param size The size of the data buffer in bytes + * @return Returns 1 if the ownership of the selection was successfully + * claimed, or 0 if unsuccessful. + */ +EAPI Eina_Bool +ecore_x_selection_secondary_set(Ecore_X_Window win, + const void *data, + int size) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _ecore_xcb_selection_set(win, data, size, + ECORE_X_ATOM_SELECTION_SECONDARY); +} + +/** + * Release ownership of the secondary selection + * @return Returns 1 if the selection was successfully cleared, + * or 0 if unsuccessful. + */ +EAPI Eina_Bool +ecore_x_selection_secondary_clear(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _ecore_xcb_selection_set(XCB_NONE, NULL, 0, + ECORE_X_ATOM_SELECTION_SECONDARY); +} + +EAPI void +ecore_x_selection_secondary_request(Ecore_X_Window win, + const char *target) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_xcb_selection_request(win, ECORE_X_ATOM_SELECTION_SECONDARY, target); +} + +/** + * Claim ownership of the XDND selection and set its data. + * @param w The window to which this selection belongs + * @param data The data associated with the selection + * @param size The size of the data buffer in bytes + * @return Returns 1 if the ownership of the selection was successfully + * claimed, or 0 if unsuccessful. + */ +EAPI Eina_Bool +ecore_x_selection_xdnd_set(Ecore_X_Window win, + const void *data, + int size) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _ecore_xcb_selection_set(win, data, size, + ECORE_X_ATOM_SELECTION_XDND); +} + +/** + * Release ownership of the XDND selection + * @return Returns 1 if the selection was successfully cleared, + * or 0 if unsuccessful. + */ +EAPI Eina_Bool +ecore_x_selection_xdnd_clear(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _ecore_xcb_selection_set(XCB_NONE, NULL, 0, + ECORE_X_ATOM_SELECTION_XDND); +} + +EAPI void +ecore_x_selection_xdnd_request(Ecore_X_Window win, + const char *target) +{ + Ecore_X_Atom atom; + Ecore_X_DND_Target *_target; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + _target = _ecore_xcb_dnd_target_get(); + atom = _ecore_xcb_selection_target_atom_get(target); + + xcb_convert_selection(_ecore_xcb_conn, win, ECORE_X_ATOM_SELECTION_XDND, + atom, ECORE_X_ATOM_SELECTION_PROP_XDND, _target->time); +} + +/** + * Claim ownership of the CLIPBOARD selection and set its data. + * @param w The window to which this selection belongs + * @param data The data associated with the selection + * @param size The size of the data buffer in bytes + * @return Returns 1 if the ownership of the selection was successfully + * claimed, or 0 if unsuccessful. + * + * Get the converted data from a previous CLIPBOARD selection + * request. The buffer must be freed when done with. + */ +EAPI Eina_Bool +ecore_x_selection_clipboard_set(Ecore_X_Window win, + const void *data, + int size) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _ecore_xcb_selection_set(win, data, size, + ECORE_X_ATOM_SELECTION_CLIPBOARD); +} + +/** + * Release ownership of the clipboard selection + * @return Returns 1 if the selection was successfully cleared, + * or 0 if unsuccessful. + */ +EAPI Eina_Bool +ecore_x_selection_clipboard_clear(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _ecore_xcb_selection_set(XCB_NONE, NULL, 0, + ECORE_X_ATOM_SELECTION_CLIPBOARD); +} + +EAPI void +ecore_x_selection_clipboard_request(Ecore_X_Window win, + const char *target) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_xcb_selection_request(win, ECORE_X_ATOM_SELECTION_CLIPBOARD, target); +} + +EAPI Eina_Bool +ecore_x_selection_convert(Ecore_X_Atom selection, + Ecore_X_Atom target, + void **data_ret, + int *size, + Ecore_X_Atom *targtype, + int *typesize) +{ + Ecore_X_Selection_Intern *sel; + Ecore_X_Selection_Converter *cnv; + void *data; + char *tgt_str; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + sel = _ecore_xcb_selection_get(selection); + tgt_str = _ecore_xcb_selection_target_get(target); + + for (cnv = _converters; cnv; cnv = cnv->next) + { + if (cnv->target == target) + { + int r = 0; + + r = cnv->convert(tgt_str, sel->data, sel->length, &data, size, + targtype, typesize); + free(tgt_str); + if (r) + { + if (data_ret) *data_ret = data; + return r; + } + else + return EINA_FALSE; + } + } + + return EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_selection_notify_send(Ecore_X_Window requestor, + Ecore_X_Atom selection, + Ecore_X_Atom target, + Ecore_X_Atom property, + Ecore_X_Time tim) +{ + xcb_selection_notify_event_t ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + memset(&ev, 0, sizeof(xcb_selection_notify_event_t)); + + ev.response_type = XCB_SELECTION_NOTIFY; + ev.requestor = requestor; + ev.selection = selection; + ev.target = target; + ev.property = property; + ev.time = tim; + + xcb_send_event(_ecore_xcb_conn, 0, requestor, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); + + return EINA_TRUE; +} + +EAPI void +ecore_x_selection_owner_set(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Time tim) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_set_selection_owner(_ecore_xcb_conn, win, atom, tim); +} + +EAPI Ecore_X_Window +ecore_x_selection_owner_get(Ecore_X_Atom atom) +{ + xcb_get_selection_owner_cookie_t cookie; + xcb_get_selection_owner_reply_t *reply; + Ecore_X_Window ret; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + cookie = xcb_get_selection_owner(_ecore_xcb_conn, atom); + reply = xcb_get_selection_owner_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return 0; + ret = reply->owner; + free(reply); + return ret; +} + +void * +_ecore_xcb_selection_parse(const char *target, + void *data, + int size, + int format) +{ + Ecore_X_Selection_Parser *prs; + Ecore_X_Selection_Data *sel; + + for (prs = _parsers; prs; prs = prs->next) + { + if (!strcmp(prs->target, target)) + { + sel = prs->parse(target, data, size, format); + if (sel) return sel; + } + } + + sel = calloc(1, sizeof(Ecore_X_Selection_Data)); + if (!sel) return NULL; + sel->free = _ecore_xcb_selection_data_default_free; + sel->length = size; + sel->format = format; + sel->data = data; + + return sel; +} + +Ecore_X_Selection_Intern * +_ecore_xcb_selection_get(Ecore_X_Atom selection) +{ + if (selection == ECORE_X_ATOM_SELECTION_PRIMARY) + return &_selections[0]; + else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY) + return &_selections[1]; + else if (selection == ECORE_X_ATOM_SELECTION_XDND) + return &_selections[2]; + else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD) + return &_selections[3]; + else + return NULL; +} + +/* local functions */ +static Eina_Bool +_ecore_xcb_selection_set(Ecore_X_Window win, + const void *data, + int size, + Ecore_X_Atom selection) +{ + xcb_get_selection_owner_cookie_t cookie; + xcb_get_selection_owner_reply_t *reply; + int in = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_set_selection_owner(_ecore_xcb_conn, win, selection, XCB_CURRENT_TIME); + + cookie = xcb_get_selection_owner(_ecore_xcb_conn, selection); + reply = xcb_get_selection_owner_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return EINA_FALSE; + + if (reply->owner != win) + { + free(reply); + return EINA_FALSE; + } + free(reply); + + if (selection == ECORE_X_ATOM_SELECTION_PRIMARY) + in = 0; + else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY) + in = 1; + else if (selection == ECORE_X_ATOM_SELECTION_XDND) + in = 2; + else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD) + in = 3; + else + return EINA_FALSE; + + if (data) + { + unsigned char *buff = NULL; + + _selections[in].win = win; + _selections[in].selection = selection; + _selections[in].length = size; + _selections[in].time = _ecore_xcb_events_last_time_get(); + + buff = malloc(size); + if (!buff) return EINA_FALSE; + memcpy(buff, data, size); + _selections[in].data = buff; + } + else if (_selections[in].data) + { + free(_selections[in].data); + memset(&_selections[in], 0, sizeof(Ecore_X_Selection_Data)); + } + + return EINA_TRUE; +} + +static void +_ecore_xcb_selection_request(Ecore_X_Window win, + Ecore_X_Atom selection, + const char *target) +{ + Ecore_X_Atom atarget, prop; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (selection == ECORE_X_ATOM_SELECTION_PRIMARY) + prop = ECORE_X_ATOM_SELECTION_PROP_PRIMARY; + else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY) + prop = ECORE_X_ATOM_SELECTION_PROP_SECONDARY; + else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD) + prop = ECORE_X_ATOM_SELECTION_PROP_CLIPBOARD; + else + return; + + atarget = _ecore_xcb_selection_target_atom_get(target); + + xcb_convert_selection(_ecore_xcb_conn, win, selection, atarget, prop, + XCB_CURRENT_TIME); +} + +static Eina_Bool +_ecore_xcb_selection_converter_text(char *target, + void *data, + int size, + void **data_ret, + int *size_ret, + Ecore_X_Atom *type __UNUSED__, + int *size_type __UNUSED__) +{ + Ecore_Xcb_Encoding_Style style; + Ecore_Xcb_Textproperty ret; + char *str; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if ((!data) || (!size)) return EINA_FALSE; + + if (!strcmp(target, ECORE_X_SELECTION_TARGET_TEXT)) + style = XcbTextStyle; + else if (!strcmp(target, ECORE_X_SELECTION_TARGET_COMPOUND_TEXT)) + style = XcbCompoundTextStyle; + else if (!strcmp(target, ECORE_X_SELECTION_TARGET_STRING)) + style = XcbStringStyle; +#ifdef HAVE_ICONV + else if (!strcmp(target, ECORE_X_SELECTION_TARGET_UTF8_STRING)) + style = XcbUTF8StringStyle; +#endif + else + return EINA_FALSE; + + str = alloca(size + 1); + memcpy(str, data, size); + str[size] = '\0'; + +#ifdef HAVE_ICONV + if (_ecore_xcb_utf8_textlist_to_textproperty(&str, 1, style, &ret)) + { + int size = 0; + + size = (strlen((char *)ret.value) + 1); + *data_ret = malloc(size); + if (!*data_ret) return EINA_FALSE; + memcpy(*data_ret, ret.value, size); + *size_ret = size; + if (ret.value) free(ret.value); + return EINA_TRUE; + } +#else + if (_ecore_xcb_mb_textlist_to_textproperty(&str, 1, style, &ret)) + { + int size = 0; + + size = (strlen((char *)ret.value) + 1); + *data_ret = malloc(size); + if (!*data_ret) return EINA_FALSE; + memcpy(*data_ret, ret.value, size); + *size_ret = size; + if (ret.value) free(ret.value); + return EINA_TRUE; + } +#endif + else + return EINA_TRUE; +} + +static void * +_ecore_xcb_selection_parser_text(const char *target __UNUSED__, + void *data, + int size, + int format __UNUSED__) +{ + Ecore_X_Selection_Data_Text *sel; + unsigned char *_data; + void *t; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(_data = data)) return NULL; + + sel = calloc(1, sizeof(Ecore_X_Selection_Data_Text)); + if (!sel) return NULL; + + if (_data[size - 1]) + { + size++; + t = realloc(_data, size); + if (!t) + { + free(sel); + return NULL; + } + _data = t; + _data[size - 1] = 0; + } + sel->text = (char *)_data; + ECORE_XCB_SELECTION_DATA(sel)->length = size; + ECORE_XCB_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_TEXT; + ECORE_XCB_SELECTION_DATA(sel)->data = _data; + ECORE_XCB_SELECTION_DATA(sel)->free = _ecore_xcb_selection_data_text_free; + return sel; +} + +static void * +_ecore_xcb_selection_parser_files(const char *target, + void *data, + int size, + int format __UNUSED__) +{ + Ecore_X_Selection_Data_Files *sel; + char *_data, *tmp, *t, **t2; + int i = 0, is = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if ((strcmp(target, "text/uri-list")) && + (strcmp(target, "_NETSCAPE_URL"))) return NULL; + + if (!(_data = data)) return NULL; + + sel = calloc(1, sizeof(Ecore_X_Selection_Data_Files)); + if (!sel) return NULL; + + ECORE_XCB_SELECTION_DATA(sel)->free = _ecore_xcb_selection_data_files_free; + + if (_data[size - 1]) + { + size++; + t = realloc(_data, size); + if (!t) + { + free(sel); + return NULL; + } + _data = t; + _data[size - 1] = 0; + } + + tmp = malloc(size); + if (!tmp) + { + free(sel); + return NULL; + } + + while ((is < size) && (_data[is])) + { + if ((i == 0) && (_data[is] == '#')) + { + for (; ((_data[is]) && (_data[is] != '\n')); is++) ; + } + else + { + if ((_data[is] != '\r') && (_data[is] != '\n')) + tmp[i++] = _data[is++]; + else + { + while ((_data[is] == '\r') || (_data[is] == '\n')) + is++; + tmp[i] = 0; + sel->num_files++; + t2 = realloc(sel->files, sel->num_files * sizeof(char *)); + if (t2) + { + sel->files = t2; + sel->files[sel->num_files - 1] = strdup(tmp); + } + tmp[0] = 0; + i = 0; + } + } + } + if (i > 0) + { + tmp[i] = 0; + sel->num_files++; + t2 = realloc(sel->files, sel->num_files * sizeof(char *)); + if (t2) + { + sel->files = t2; + sel->files[sel->num_files - 1] = strdup(tmp); + } + } + if (tmp) free(tmp); + if (_data) free(_data); + + ECORE_XCB_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_FILES; + ECORE_XCB_SELECTION_DATA(sel)->length = sel->num_files; + + return ECORE_XCB_SELECTION_DATA(sel); +} + +static void * +_ecore_xcb_selection_parser_targets(const char *target __UNUSED__, + void *data, + int size, + int format __UNUSED__) +{ + Ecore_X_Selection_Data_Targets *sel; + unsigned long *targets; + int i = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!(targets = (unsigned long *)data)) return NULL; + + sel = calloc(1, sizeof(Ecore_X_Selection_Data_Targets)); + if (!sel) return NULL; + + sel->num_targets = (size - 2); + sel->targets = malloc((size - 2) * sizeof(char *)); + if (!sel->targets) + { + free(sel); + return NULL; + } + + for (i = 2; i < size; i++) + { + xcb_get_atom_name_cookie_t cookie; + xcb_get_atom_name_reply_t *reply; + char *name = NULL; + int len = 0; + + cookie = xcb_get_atom_name_unchecked(_ecore_xcb_conn, targets[i]); + reply = xcb_get_atom_name_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + len = xcb_get_atom_name_name_length(reply); + name = (char *)malloc(sizeof(char) * (len + 1)); + if (name) + { + memcpy(name, xcb_get_atom_name_name(reply), len); + name[len] = '\0'; + sel->targets[i - 2] = name; + } + free(reply); + } + } + + ECORE_XCB_SELECTION_DATA(sel)->free = + _ecore_xcb_selection_data_targets_free; + ECORE_XCB_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_TARGETS; + ECORE_XCB_SELECTION_DATA(sel)->length = size; + ECORE_XCB_SELECTION_DATA(sel)->data = data; + + return sel; +} + +/* + static int + _ecore_xcb_selection_data_free(void *data) + { + Ecore_X_Selection_Data *sel; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(sel = data)) return 0; + if (sel->data) free(sel->data); + free(sel); + return 1; + } + */ + +static int +_ecore_xcb_selection_data_text_free(void *data) +{ + Ecore_X_Selection_Data_Text *sel; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(sel = data)) return 0; + if (sel->text) free(sel->text); + free(sel); + return 1; +} + +static int +_ecore_xcb_selection_data_targets_free(void *data) +{ + Ecore_X_Selection_Data_Targets *sel; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(sel = data)) return 0; + if (sel->targets) free(sel->targets); + free(ECORE_XCB_SELECTION_DATA(sel)->data); + free(sel); + return 1; +} + +static int +_ecore_xcb_selection_data_files_free(void *data) +{ + Ecore_X_Selection_Data_Files *sel; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(sel = data)) return 0; + if (sel->files) + { + int i = 0; + + for (i = 0; i < sel->num_files; i++) + if (sel->files[i]) free(sel->files[i]); + if (sel->files) free(sel->files); + } + free(sel); + return 0; +} + +static int +_ecore_xcb_selection_data_default_free(void *data) +{ + Ecore_X_Selection_Data *sel; + + if (!(sel = data)) return 1; + free(sel->data); + free(sel); + return 1; +} + +static Ecore_X_Atom +_ecore_xcb_selection_target_atom_get(const char *target) +{ + Ecore_X_Atom x_target; + + if (!strcmp(target, ECORE_X_SELECTION_TARGET_TEXT)) + x_target = ECORE_X_ATOM_TEXT; + else if (!strcmp(target, ECORE_X_SELECTION_TARGET_COMPOUND_TEXT)) + x_target = ECORE_X_ATOM_COMPOUND_TEXT; + else if (!strcmp(target, ECORE_X_SELECTION_TARGET_STRING)) + x_target = ECORE_X_ATOM_STRING; + else if (!strcmp(target, ECORE_X_SELECTION_TARGET_UTF8_STRING)) + x_target = ECORE_X_ATOM_UTF8_STRING; + else if (!strcmp(target, ECORE_X_SELECTION_TARGET_FILENAME)) + x_target = ECORE_X_ATOM_FILE_NAME; + else + x_target = ecore_x_atom_get(target); + + return x_target; +} + +char * +_ecore_xcb_selection_target_get(Ecore_X_Atom target) +{ + if (target == ECORE_X_ATOM_FILE_NAME) + return strdup(ECORE_X_SELECTION_TARGET_FILENAME); + else if (target == ECORE_X_ATOM_STRING) + return strdup(ECORE_X_SELECTION_TARGET_STRING); + else if (target == ECORE_X_ATOM_UTF8_STRING) + return strdup(ECORE_X_SELECTION_TARGET_UTF8_STRING); + else if (target == ECORE_X_ATOM_TEXT) + return strdup(ECORE_X_SELECTION_TARGET_TEXT); + else + return ecore_x_atom_name_get(target); +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_shape.c b/src/lib/ecore_x/xcb/ecore_xcb_shape.c new file mode 100644 index 0000000..913f199 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_shape.c @@ -0,0 +1,50 @@ +#include "ecore_xcb_private.h" +#ifdef ECORE_XCB_SHAPE +# include +#endif + +/* external variables */ +int _ecore_xcb_event_shape = -1; + +void +_ecore_xcb_shape_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_SHAPE + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_shape_id); +#endif +} + +void +_ecore_xcb_shape_finalize(void) +{ +#ifdef ECORE_XCB_SHAPE + const xcb_query_extension_reply_t *ext_reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_SHAPE + ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_shape_id); + if ((ext_reply) && (ext_reply->present)) + { + xcb_shape_query_version_cookie_t cookie; + xcb_shape_query_version_reply_t *reply; + Eina_Bool _shape_avail; + + _shape_avail = EINA_FALSE; + cookie = xcb_shape_query_version_unchecked(_ecore_xcb_conn); + reply = xcb_shape_query_version_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + _shape_avail = EINA_TRUE; + free(reply); + } + + if (_shape_avail) + _ecore_xcb_event_shape = ext_reply->first_event; + } +#endif +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_sync.c b/src/lib/ecore_x/xcb/ecore_xcb_sync.c new file mode 100644 index 0000000..75f4e4f --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_sync.c @@ -0,0 +1,338 @@ +#include "ecore_xcb_private.h" +# ifdef ECORE_XCB_SYNC +# include +# endif + +/* local variables */ +static Eina_Bool _sync_avail = EINA_FALSE; + +/* external variables */ +int _ecore_xcb_event_sync = -1; + +void +_ecore_xcb_sync_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_SYNC + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_sync_id); +#endif +} + +void +_ecore_xcb_sync_finalize(void) +{ +#ifdef ECORE_XCB_SYNC + const xcb_query_extension_reply_t *ext_reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_SYNC + ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_sync_id); + if ((ext_reply) && (ext_reply->present)) + { + xcb_sync_initialize_cookie_t cookie; + xcb_sync_initialize_reply_t *reply; + + cookie = + xcb_sync_initialize_unchecked(_ecore_xcb_conn, + XCB_SYNC_MAJOR_VERSION, + XCB_SYNC_MINOR_VERSION); + reply = xcb_sync_initialize_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + if (reply->major_version >= 3) _sync_avail = EINA_TRUE; + free(reply); + } + + if (_sync_avail) + _ecore_xcb_event_sync = ext_reply->first_event; + } +#endif +} + +void +_ecore_xcb_sync_magic_send(int val, + Ecore_X_Window win) +{ + xcb_client_message_event_t ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 32; + ev.window = win; + ev.type = 27777; + ev.data.data32[0] = 0x7162534; + ev.data.data32[1] = (0x10000000 + val); + ev.data.data32[2] = win; + + xcb_send_event(_ecore_xcb_conn, 0, win, XCB_EVENT_MASK_NO_EVENT, + (const char *)&ev); +// ecore_x_flush(); +} + +/* public functions */ +EAPI Ecore_X_Sync_Alarm +ecore_x_sync_alarm_new(Ecore_X_Sync_Counter counter) +{ +#ifdef ECORE_XCB_SYNC + uint32_t list[6], mask; + xcb_sync_int64_t init; + Ecore_X_Sync_Alarm alarm; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if ((!_sync_avail) || (!counter)) return 0; + +#ifdef ECORE_XCB_SYNC + init.lo = 0; + init.hi = 0; + xcb_sync_set_counter(_ecore_xcb_conn, counter, init); + + mask = (XCB_SYNC_CA_COUNTER | XCB_SYNC_CA_VALUE_TYPE | + XCB_SYNC_CA_VALUE | XCB_SYNC_CA_TEST_TYPE | + XCB_SYNC_CA_DELTA | XCB_SYNC_CA_EVENTS); + list[0] = counter; + list[1] = XCB_SYNC_VALUETYPE_ABSOLUTE; + list[2] = 1; + list[3] = XCB_SYNC_TESTTYPE_POSITIVE_COMPARISON; + list[4] = 1; + list[5] = 1; + alarm = xcb_generate_id(_ecore_xcb_conn); + + xcb_sync_create_alarm(_ecore_xcb_conn, alarm, mask, list); + ecore_x_sync(); // needed + + return alarm; +#endif + return 0; +} + +EAPI Eina_Bool +ecore_x_sync_alarm_free(Ecore_X_Sync_Alarm alarm) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if ((!_sync_avail) || (!alarm)) return EINA_FALSE; + +#ifdef ECORE_XCB_SYNC + xcb_sync_destroy_alarm(_ecore_xcb_conn, alarm); +// ecore_x_flush(); + return EINA_TRUE; +#endif + + return EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_sync_counter_query(Ecore_X_Sync_Counter counter, + unsigned int *val) +{ +#ifdef ECORE_XCB_SYNC + xcb_sync_query_counter_cookie_t cookie; + xcb_sync_query_counter_reply_t *reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if ((!_sync_avail) || (!counter)) return EINA_FALSE; + +#ifdef ECORE_XCB_SYNC + cookie = xcb_sync_query_counter_unchecked(_ecore_xcb_conn, counter); + reply = xcb_sync_query_counter_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + if (val) *val = (unsigned int)reply->counter_value.lo; + free(reply); + return EINA_TRUE; + } +#endif + return EINA_FALSE; +} + +EAPI void +ecore_x_sync_counter_inc(Ecore_X_Sync_Counter counter, + int by) +{ +#ifdef ECORE_XCB_SYNC + xcb_sync_int64_t v; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if ((!_sync_avail) || (!counter)) return; + +#ifdef ECORE_XCB_SYNC + v.hi = (by < 0) ? ~0 : 0; + v.lo = by; + + xcb_sync_change_counter(_ecore_xcb_conn, counter, v); +// ecore_x_flush(); +#endif +} + +EAPI void +ecore_x_sync_counter_val_wait(Ecore_X_Sync_Counter counter, + int val) +{ +#ifdef ECORE_XCB_SYNC + xcb_sync_query_counter_cookie_t cookie; + xcb_sync_query_counter_reply_t *reply; + xcb_sync_int64_t v1, v2; + xcb_sync_waitcondition_t cond; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if ((!_sync_avail) || (!counter)) return; + +#ifdef ECORE_XCB_SYNC + cookie = xcb_sync_query_counter_unchecked(_ecore_xcb_conn, counter); + reply = xcb_sync_query_counter_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return; + v1 = reply->counter_value; + free(reply); + + v1.hi = (val < 0) ? ~0 : 0; + v1.lo = val; + v2.hi = ((val + 1) < 0) ? ~0 : 0; + v2.lo = (val + 1); + + cond.trigger.counter = counter; + cond.trigger.wait_type = XCB_SYNC_VALUETYPE_ABSOLUTE; + cond.trigger.wait_value = v1; + cond.trigger.test_type = XCB_SYNC_TESTTYPE_POSITIVE_COMPARISON; + cond.event_threshold = v2; + + xcb_sync_await(_ecore_xcb_conn, 1, &cond); +// ecore_x_flush(); +#endif +} + +EAPI Ecore_X_Sync_Counter +ecore_x_sync_counter_new(int val) +{ +#ifdef ECORE_XCB_SYNC + xcb_sync_counter_t counter; + xcb_sync_int64_t v; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_sync_avail) return 0; + +#ifdef ECORE_XCB_SYNC + v.hi = (val < 0) ? ~0 : 0; + v.lo = val; + + counter = xcb_generate_id(_ecore_xcb_conn); + xcb_sync_create_counter(_ecore_xcb_conn, counter, v); +// ecore_x_flush(); + + return counter; +#endif + + return 0; +} + +EAPI void +ecore_x_sync_counter_free(Ecore_X_Sync_Counter counter) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if ((!_sync_avail) || (!counter)) return; + +#ifdef ECORE_XCB_SYNC + xcb_sync_destroy_counter(_ecore_xcb_conn, counter); +// ecore_x_flush(); +#endif +} + +EAPI void +ecore_x_sync_counter_set(Ecore_X_Sync_Counter counter, + int val) +{ +#ifdef ECORE_XCB_SYNC + xcb_sync_int64_t v; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if ((!_sync_avail) || (!counter)) return; + +#ifdef ECORE_XCB_SYNC + v.hi = (val < 0) ? ~0 : 0; + v.lo = val; + + xcb_sync_set_counter(_ecore_xcb_conn, counter, v); +// ecore_x_flush(); +#endif +} + +EAPI void +ecore_x_sync_counter_2_set(Ecore_X_Sync_Counter counter, + int val_hi, + unsigned int val_lo) +{ +#ifdef ECORE_XCB_SYNC + xcb_sync_int64_t v; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if ((!_sync_avail) || (!counter)) return; + +#ifdef ECORE_XCB_SYNC + v.hi = val_hi; + v.lo = val_lo; + + xcb_sync_set_counter(_ecore_xcb_conn, counter, v); +// ecore_x_flush(); +#endif +} + +EAPI Eina_Bool +ecore_x_sync_counter_2_query(Ecore_X_Sync_Counter counter, + int *val_hi, + unsigned int *val_lo) +{ +#ifdef ECORE_XCB_SYNC + xcb_sync_query_counter_cookie_t cookie; + xcb_sync_query_counter_reply_t *reply; + xcb_sync_int64_t value; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if ((!_sync_avail) || (!counter)) return EINA_FALSE; + +#ifdef ECORE_XCB_SYNC + cookie = + xcb_sync_query_counter_unchecked(_ecore_xcb_conn, + (xcb_sync_counter_t)counter); + reply = xcb_sync_query_counter_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return EINA_FALSE; + value = reply->counter_value; + free(reply); + if (val_hi) *val_hi = (int)value.hi; + if (val_lo) *val_lo = (unsigned int)value.lo; + return EINA_TRUE; +#endif + + return EINA_FALSE; +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_textlist.c b/src/lib/ecore_x/xcb/ecore_xcb_textlist.c new file mode 100644 index 0000000..2a5c854 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_textlist.c @@ -0,0 +1,509 @@ +#include "ecore_xcb_private.h" +//#include "Ecore_X_Atoms.h" +#include +#ifdef HAVE_ICONV +# include +#endif +#ifndef CODESET +# define CODESET "INVALID" +#endif + +static int _ecore_xcb_textlist_get_buffer_size(Eina_Bool is_wide, + void *list, + int count); +static int _ecore_xcb_textlist_get_wc_len(wchar_t *wstr); +static void *_ecore_xcb_textlist_alloc_list(Eina_Bool is_wide, + int count, + int nitems); +static void _ecore_xcb_textlist_copy_list(Eina_Bool is_wide, + void *text, + char **list, + int count); +static wchar_t *_ecore_xcb_textlist_copy_wchar(wchar_t *str1, + wchar_t *str2); +static int _ecore_xcb_textlist_len_wchar(wchar_t *str); + +#ifdef HAVE_ICONV +Eina_Bool +_ecore_xcb_utf8_textlist_to_textproperty(char **list, + int count, + Ecore_Xcb_Encoding_Style style, + Ecore_Xcb_Textproperty *ret) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _ecore_xcb_textlist_to_textproperty("utf8string", list, count, + style, ret); +} + +#endif + +Eina_Bool +_ecore_xcb_mb_textlist_to_textproperty(char **list, + int count, + Ecore_Xcb_Encoding_Style style, + Ecore_Xcb_Textproperty *ret) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _ecore_xcb_textlist_to_textproperty("multiByte", list, count, + style, ret); +} + +/* NB: This Function May Not Be Correct !!! + * (as I do not know text conversion, locales, etc, etc very well) + * + * Portions were ripped from libX11 XTextListToTextProperty + */ +Eina_Bool +_ecore_xcb_textlist_to_textproperty(const char *type, + char **list, + int count, + Ecore_Xcb_Encoding_Style style, + Ecore_Xcb_Textproperty *ret) +{ + Eina_Bool is_wide = EINA_FALSE; + Ecore_X_Atom encoding; + int len = 0, nitems = 0, i = 0; + size_t from_left = 0, to_left = 0; + int unconv_num = 0, val = 0; + char *buff, *to, *value, *from; + const char *to_type, *from_type; + char **mb = NULL; + wchar_t **wc = NULL; +#ifdef HAVE_ICONV + iconv_t conv; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!strcmp("wideChar", type)) is_wide = EINA_TRUE; + len = _ecore_xcb_textlist_get_buffer_size(is_wide, list, count); + if (!(buff = (char *)malloc(len * sizeof(char)))) return EINA_FALSE; + from_type = nl_langinfo(CODESET); + switch (style) + { + case XcbStringStyle: + case XcbStdICCTextStyle: + encoding = ECORE_X_ATOM_STRING; + to_type = nl_langinfo(CODESET); +// to_type = "string"; + break; + + case XcbUTF8StringStyle: + encoding = ECORE_X_ATOM_UTF8_STRING; + to_type = "UTF-8"; + break; + + case XcbCompoundTextStyle: + encoding = ECORE_X_ATOM_COMPOUND_TEXT; + to_type = nl_langinfo(CODESET); +// to_type = "compoundText"; + break; + + case XcbTextStyle: + encoding = ECORE_X_ATOM_TEXT; + to_type = nl_langinfo(CODESET); +// to_type = "multiByte"; + if (!is_wide) + { + nitems = 0; + mb = (char **)list; + to = buff; + for (i = 0; ((i < count) && (len > 0)); i++) + { + if (*mb) strcpy(to, *mb); + else *to = '\0'; + from_left = (*mb ? strlen(*mb) : 0) + 1; + nitems += from_left; + to += from_left; + mb++; + } + unconv_num = 0; + goto done; + } + break; + + default: + free(buff); + return EINA_FALSE; + break; + } + + if (count < 1) + { + nitems = 0; + goto done; + } + +retry: +#ifdef HAVE_ICONV + conv = iconv_open(to_type, from_type); +#endif + + if (is_wide) + wc = (wchar_t **)list; + else + mb = (char **)list; + + to = buff; + to_left = len; + unconv_num = 0; + for (i = 1; to_left > 0; i++) + { + if (is_wide) + { + from = (char *)*wc; + from_left = _ecore_xcb_textlist_get_wc_len(*wc); + wc++; + } + else + { + from = *mb; + from_left = (*mb ? strlen(*mb) : 0); + mb++; + } + +#ifdef HAVE_ICONV + val = iconv(conv, &from, &from_left, &to, &to_left); +#endif + if (val < 0) continue; + if ((val > 0) && (style == XcbStdICCTextStyle) && + (encoding == ECORE_X_ATOM_STRING)) + { +#ifdef HAVE_ICONV + iconv_close(conv); +#endif + encoding = ECORE_X_ATOM_COMPOUND_TEXT; + goto retry; + } + + unconv_num += val; + *to++ = '\0'; + to_left--; + if (i >= count) break; + } + +#ifdef HAVE_ICONV + iconv_close(conv); +#endif + nitems = (to - buff); + +done: + if (nitems <= 0) nitems = 1; + if (!(value = (char *)malloc(nitems * sizeof(char)))) + { + free(buff); + return EINA_FALSE; + } + if (nitems == 1) + *value = 0; + else + memcpy(value, buff, nitems); + nitems--; + free(buff); + + ret->value = value; + ret->encoding = encoding; + ret->format = 8; + ret->nitems = nitems; + + return EINA_TRUE; +} + +#ifdef HAVE_ICONV +Eina_Bool +_ecore_xcb_utf8_textproperty_to_textlist(const Ecore_Xcb_Textproperty *text_prop, + char ***list_ret, + int *count_ret) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _ecore_xcb_textproperty_to_textlist(text_prop, "utf8String", + list_ret, count_ret); +} + +#endif + +Eina_Bool +_ecore_xcb_mb_textproperty_to_textlist(const Ecore_Xcb_Textproperty *text_prop, + char ***list_ret, + int *count_ret) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _ecore_xcb_textproperty_to_textlist(text_prop, "multiByte", + list_ret, count_ret); +} + +Eina_Bool +_ecore_xcb_textproperty_to_textlist(const Ecore_Xcb_Textproperty *text_prop, + const char *type, + char ***list_ret, + int *count_ret) +{ + Eina_Bool is_wide = EINA_FALSE; + Eina_Bool do_strcpy = EINA_FALSE; + const char *from_type; + char *buff, *to, *from; + char *lptr, *sptr; + int nitems = 0, len = 0, num = 0, ret = 0; + size_t from_left = 0, to_left = 0; +#ifdef HAVE_ICONV + iconv_t conv = 0; +#endif + + *list_ret = NULL; + *count_ret = 0; + if (!strcmp("wideChar", type)) is_wide = EINA_TRUE; + + nitems = text_prop->nitems; + if (nitems <= 0) return EINA_TRUE; + + if (text_prop->format != 8) return EINA_FALSE; + + from_type = nl_langinfo(CODESET); + if (text_prop->encoding == ECORE_X_ATOM_UTF8_STRING) + from_type = "UTF-8"; + + if (is_wide) + len = (text_prop->nitems + 1) * sizeof(wchar_t); + else + { + if (!strcmp(type, "utf8String")) + len = text_prop->nitems * 6 + 1; + else + len = text_prop->nitems * MB_CUR_MAX + 1; + } + + buff = (char *)malloc(len * sizeof(char)); + if (!buff) return EINA_FALSE; + + to = buff; + to_left = len; + + if (!strcmp(from_type, type)) + do_strcpy = EINA_TRUE; + else + { +#ifdef HAVE_ICONV + conv = iconv_open(type, from_type); +#endif + if (!conv) + { + free(buff); + return EINA_FALSE; + } + } + + lptr = sptr = text_prop->value; + num = *count_ret = 0; + while (1) + { + if ((nitems == 0) || (*sptr == 0)) + { + from = lptr; + from_left = sptr - lptr; + lptr = sptr; + if (do_strcpy) + { + int l = 0; + + l = MIN(from_left, to_left); + strncpy(to, from, l); + from += len; + to += len; + from_left -= l; + to_left -= l; + ret = 0; + } + else + ret = iconv(conv, &from, &from_left, &to, &to_left); + + if (ret < 0) continue; + num += ret; + (*count_ret)++; + if (nitems == 0) break; + lptr = ++sptr; + if (is_wide) + { + *((wchar_t *)to) = (wchar_t)0; + to += sizeof(wchar_t); + to_left -= sizeof(wchar_t); + } + else + { + *((char *)to) = '\0'; + to++; + to_left--; + } + } + else + sptr++; + + nitems--; + } + +#if HAVE_ICONV + if (!do_strcpy) iconv_close(conv); +#endif + + if (is_wide) + { + *((wchar_t *)to) = (wchar_t)0; + to_left -= sizeof(wchar_t); + } + else + { + *((char *)to) = '\0'; + to_left--; + } + + *list_ret = + _ecore_xcb_textlist_alloc_list(is_wide, *count_ret, (len - to_left)); + if (*list_ret) + _ecore_xcb_textlist_copy_list(is_wide, buff, *list_ret, *count_ret); + + free(buff); + + return EINA_TRUE; +} + +static int +_ecore_xcb_textlist_get_buffer_size(Eina_Bool is_wide, + void *list, + int count) +{ + int len = 0; + char **mb; + wchar_t **wc; + + if (!list) return 0; + if (is_wide) + { + wc = (wchar_t **)list; + for (; count-- > 0; wc++) + if (*wc) len += _ecore_xcb_textlist_get_wc_len(*wc) + 1; + len *= 5; + } + else + { + mb = (char **)list; + for (; count-- > 0; mb++) + if (*mb) len += strlen(*mb) + 1; + len *= 3; + } + len = (len / 2048 + 1) * 2048; + return len; +} + +static int +_ecore_xcb_textlist_get_wc_len(wchar_t *wstr) +{ + wchar_t *ptr; + + ptr = wstr; + while (*ptr) + ptr++; + + return ptr - wstr; +} + +static void * +_ecore_xcb_textlist_alloc_list(Eina_Bool is_wide, + int count, + int nitems) +{ + if (is_wide) + { + wchar_t **list; + + list = (wchar_t **)malloc(count * sizeof(wchar_t *)); + if (!list) return NULL; + *list = (wchar_t *)malloc(nitems * sizeof(wchar_t)); + if (!*list) + { + free(list); + return NULL; + } + return *list; + } + else + { + char **list; + + list = (char **)malloc(count * sizeof(char *)); + if (!list) return NULL; + *list = (char *)malloc(nitems * sizeof(char)); + if (!*list) + { + free(list); + return NULL; + } + return *list; + } +} + +static void +_ecore_xcb_textlist_copy_list(Eina_Bool is_wide, + void *text, + char **list, + int count) +{ + int len = 0; + + if (is_wide) + { + wchar_t *txt, *str, **wlist; + + txt = (wchar_t *)text; + wlist = (wchar_t **)list; + for (str = *wlist; count > 0; count--, wlist++) + { + _ecore_xcb_textlist_copy_wchar(str, txt); + *wlist = str; + len = (_ecore_xcb_textlist_len_wchar(str) + 1); + str += len; + txt += len; + } + } + else + { + char *txt, *str, **slist; + + txt = (char *)text; + slist = (char **)list; + for (str = *slist; count > 0; count--, slist++) + { + strcpy(str, txt); + *slist = str; + len = strlen(str) + 1; + str += len; + txt += len; + } + } +} + +static wchar_t * +_ecore_xcb_textlist_copy_wchar(wchar_t *str1, + wchar_t *str2) +{ + wchar_t *tmp; + + tmp = str1; + while ((*str1++ = *str2++)) + ; + return tmp; +} + +static int +_ecore_xcb_textlist_len_wchar(wchar_t *str) +{ + wchar_t *ptr; + + ptr = str; + while (*ptr) + ptr++; + return ptr - str; +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_vsync.c b/src/lib/ecore_x/xcb/ecore_xcb_vsync.c new file mode 100644 index 0000000..47efefc --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_vsync.c @@ -0,0 +1,375 @@ +#include "ecore_xcb_private.h" +# include +# include +# include + +#define ECORE_XCB_VSYNC_DRI2 1 +#define DRM_EVENT_CONTEXT_VERSION 2 + +#ifdef ECORE_XCB_VSYNC_DRI2 + +/* relevant header bits of dri/drm inlined here to avoid needing external */ +/* headers to build drm */ +typedef unsigned int drm_magic_t; + +typedef enum +{ + DRM_VBLANK_ABSOLUTE = 0x00000000, + DRM_VBLANK_RELATIVE = 0x00000001, + DRM_VBLANK_EVENT = 0x04000000, + DRM_VBLANK_FLIP = 0x08000000, + DRM_VBLANK_NEXTONMISS = 0x10000000, + DRM_VBLANK_SECONDARY = 0x20000000, + DRM_VBLANK_SIGNAL = 0x40000000 +} drmVBlankSeqType; + +typedef struct _drmVBlankReq +{ + drmVBlankSeqType type; + unsigned int sequence; + unsigned long signal; +} drmVBlankReq; + +typedef struct _drmVBlankReply +{ + drmVBlankSeqType type; + unsigned int sequence; + long tval_sec, tval_usec; +} drmVBlankReply; + +typedef union _drmVBlank +{ + drmVBlankReq request; + drmVBlankReply reply; +} drmVBlank; + +typedef struct _drmEventContext +{ + int version; + void (*vblank_handler)(int fd, + unsigned int sequence, + unsigned int tv_sec, + unsigned int tv_usec, + void *user_data); + void (*page_flip_handler)(int fd, + unsigned int sequence, + unsigned int tv_sec, + unsigned int tv_usec, + void *user_data); +} drmEventContext; + +static int (*sym_drmClose)(int fd) = NULL; +static int (*sym_drmGetMagic)(int fd, + drm_magic_t *magic) = NULL; +static int (*sym_drmWaitVBlank)(int fd, + drmVBlank *vbl) = NULL; +static int (*sym_drmHandleEvent)(int fd, + drmEventContext *evctx) = NULL; + +/* dri */ +static Bool (*sym_DRI2QueryExtension)(Display *display, + int *eventBase, + int *errorBase) = NULL; +static Bool (*sym_DRI2QueryVersion)(Display *display, + int *major, + int *minor) = NULL; +static Bool (*sym_DRI2Connect)(Display *display, + XID window, + char **driverName, + char **deviceName) = NULL; +static Bool (*sym_DRI2Authenticate)(Display *display, + XID window, + drm_magic_t magic) = NULL; + +/* local function prototypes */ +static Eina_Bool _ecore_xcb_dri_link(void); +static Eina_Bool _ecore_xcb_dri_start(void); +static void _ecore_xcb_dri_shutdown(void); + +static Eina_Bool _ecore_xcb_dri_cb(void *data __UNUSED__, + Ecore_Fd_Handler *fdh __UNUSED__); +static void _ecore_xcb_dri_tick_begin(void *data __UNUSED__); +static void _ecore_xcb_dri_tick_end(void *data __UNUSED__); +static void _ecore_xcb_dri_tick_schedule(void); +static void _ecore_xcb_dri_vblank_handler(int fd __UNUSED__, + unsigned int frame __UNUSED__, + unsigned int sec __UNUSED__, + unsigned int usec __UNUSED__, + void *data __UNUSED__); + +/* local variables */ +static Ecore_X_Window _vsync_root = 0; +static int _drm_fd = -1; +static Ecore_Fd_Handler *_drm_fdh = NULL; +static unsigned int _drm_magic = 0; +static Eina_Bool _drm_event_busy = EINA_FALSE; +static void *_drm_lib = NULL; +static void *_dri_lib = NULL; +static drmEventContext _drm_evctx; +#endif + +void +_ecore_xcb_dri_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); +} + +void +_ecore_xcb_dri_finalize(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); +} + +EAPI Eina_Bool +ecore_x_vsync_animator_tick_source_set(Ecore_X_Window win) +{ +#ifdef ECORE_XCB_VSYNC_DRI2 + Ecore_X_Window root; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_VSYNC_DRI2 + root = ecore_x_window_root_get(win); + if (root != _vsync_root) + { + _vsync_root = root; + if (_vsync_root) + { + if (!_ecore_xcb_dri_link()) + { + ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER); + return EINA_FALSE; + } + _ecore_xcb_dri_shutdown(); + if (!_ecore_xcb_dri_start()) + { + _vsync_root = 0; + ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER); + return EINA_FALSE; + } + ecore_animator_custom_source_tick_begin_callback_set + (_ecore_xcb_dri_tick_begin, NULL); + ecore_animator_custom_source_tick_end_callback_set + (_ecore_xcb_dri_tick_end, NULL); + ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_CUSTOM); + } + else + { + if (_drm_fd >= 0) + { + _ecore_xcb_dri_shutdown(); + ecore_animator_custom_source_tick_begin_callback_set + (NULL, NULL); + ecore_animator_custom_source_tick_end_callback_set + (NULL, NULL); + ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER); + } + } + } + return EINA_TRUE; +#else + return EINA_FALSE; + win = 0; +#endif +} + +/* local functions */ +#ifdef ECORE_XCB_VSYNC_DRI2 +static Eina_Bool +_ecore_xcb_dri_link(void) +{ + const char *_drm_libs[] = + { + "libdrm.so.2", + "libdrm.so.1", + "libdrm.so.0", + "libdrm.so", + NULL, + }; + const char *_dri_libs[] = + { + "libdri2.so.2", + "libdri2.so.1", + "libdri2.so.0", + "libdri2.so", + "libGL.so.4", + "libGL.so.3", + "libGL.so.2", + "libGL.so.1", + "libGL.so.0", + "libGL.so", + NULL, + }; + int i = 0, fail = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +# define SYM(lib, xx) \ + do { \ + sym_## xx = dlsym(lib, #xx); \ + if (!(sym_## xx)) { \ + fprintf(stderr, "%s\n", dlerror()); \ + fail = 1; \ + } \ + } while (0); + + if (_drm_lib) return EINA_TRUE; + + for (i = 0; _drm_libs[i]; i++) + { + _drm_lib = dlopen(_drm_libs[i], (RTLD_LOCAL | RTLD_LAZY)); + if (_drm_lib) + { + fail = 0; + SYM(_drm_lib, drmClose); + SYM(_drm_lib, drmGetMagic); + SYM(_drm_lib, drmWaitVBlank); + SYM(_drm_lib, drmHandleEvent); + if (fail) + { + dlclose(_drm_lib); + _drm_lib = NULL; + } + else + break; + } + } + if (!_drm_lib) return EINA_FALSE; + for (i = 0; _dri_libs[i]; i++) + { + if ((_dri_lib = dlopen(_dri_libs[i], (RTLD_LOCAL | RTLD_LAZY)))) + { + fail = 0; + SYM(_dri_lib, DRI2QueryExtension); + SYM(_dri_lib, DRI2QueryVersion); + SYM(_dri_lib, DRI2Connect); + SYM(_dri_lib, DRI2Authenticate); + if (fail) + { + dlclose(_dri_lib); + _dri_lib = NULL; + } + else + break; + } + } + if (!_dri_lib) + { + dlclose(_drm_lib); + _drm_lib = NULL; + return EINA_FALSE; + } + + return EINA_TRUE; +} + +static Eina_Bool +_ecore_xcb_dri_start(void) +{ + Ecore_X_Display *disp; + int _dri2_event = 0, _dri2_error = 0; + int _dri2_major = 0, _dri2_minor = 0; + char *device = NULL, *driver = NULL; + + disp = ecore_x_display_get(); + if (!sym_DRI2QueryExtension(disp, &_dri2_event, &_dri2_error)) + return 0; + if (!sym_DRI2QueryVersion(disp, &_dri2_major, &_dri2_minor)) + return 0; + if (_dri2_major < 2) return 0; + if (!sym_DRI2Connect(disp, _vsync_root, &driver, &device)) + return 0; + + _drm_fd = open(device, O_RDWR); + if (_drm_fd < 0) return 0; + + sym_drmGetMagic(_drm_fd, &_drm_magic); + if (!sym_DRI2Authenticate(disp, _vsync_root, _drm_magic)) + { + close(_drm_fd); + _drm_fd = -1; + return EINA_FALSE; + } + + memset(&_drm_evctx, 0, sizeof(_drm_evctx)); + _drm_evctx.version = DRM_EVENT_CONTEXT_VERSION; + _drm_evctx.vblank_handler = _ecore_xcb_dri_vblank_handler; + _drm_evctx.page_flip_handler = NULL; + + _drm_fdh = ecore_main_fd_handler_add(_drm_fd, ECORE_FD_READ, + _ecore_xcb_dri_cb, NULL, NULL, NULL); + if (!_drm_fdh) + { + close(_drm_fd); + _drm_fd = -1; + return EINA_FALSE; + } + + return EINA_TRUE; +} + +static void +_ecore_xcb_dri_shutdown(void) +{ + if (_drm_fd >= 0) + { + close(_drm_fd); + _drm_fd = -1; + } + if (_drm_fdh) + { + ecore_main_fd_handler_del(_drm_fdh); + _drm_fdh = NULL; + } +} + +static Eina_Bool +_ecore_xcb_dri_cb(void *data __UNUSED__, + Ecore_Fd_Handler *fdh __UNUSED__) +{ + sym_drmHandleEvent(_drm_fd, &_drm_evctx); + return ECORE_CALLBACK_RENEW; +} + +static void +_ecore_xcb_dri_tick_begin(void *data __UNUSED__) +{ + _drm_event_busy = EINA_TRUE; + _ecore_xcb_dri_tick_schedule(); +} + +static void +_ecore_xcb_dri_tick_end(void *data __UNUSED__) +{ + _drm_event_busy = EINA_FALSE; +} + +static void +_ecore_xcb_dri_tick_schedule(void) +{ + drmVBlank vbl; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + vbl.request.type = (DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT); + vbl.request.sequence = 1; + vbl.request.signal = 0; + + sym_drmWaitVBlank(_drm_fd, &vbl); +} + +static void +_ecore_xcb_dri_vblank_handler(int fd __UNUSED__, + unsigned int frame __UNUSED__, + unsigned int sec __UNUSED__, + unsigned int usec __UNUSED__, + void *data __UNUSED__) +{ + ecore_animator_custom_tick(); + if (_drm_event_busy) _ecore_xcb_dri_tick_schedule(); +} + +#endif diff --git a/src/lib/ecore_x/xcb/ecore_xcb_window.c b/src/lib/ecore_x/xcb/ecore_xcb_window.c new file mode 100644 index 0000000..8e38c5a --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_window.c @@ -0,0 +1,2238 @@ +#include "ecore_xcb_private.h" +#ifdef ECORE_XCB_RENDER +# include +#endif +#ifdef ECORE_XCB_SHAPE +# include +#endif +#ifdef ECORE_XCB_XPRINT +#include +#endif + +/* local function prototypes */ +static Ecore_X_Window _ecore_xcb_window_argb_internal_new(Ecore_X_Window parent, + int x, + int y, + int w, + int h, + uint8_t override_redirect, + uint8_t save_under); +static Ecore_X_Window _ecore_xcb_window_at_xy_get(Ecore_X_Window base, + int bx, + int by, + int x, + int y, + Ecore_X_Window *skip, + int skip_num); +static int _ecore_xcb_window_modifiers_get(unsigned int state); +static xcb_visualtype_t *_ecore_xcb_window_find_visual_by_id(xcb_visualid_t id); +#ifdef ECORE_XCB_XPRINT +static xcb_screen_t *_ecore_xcb_window_screen_of_display(int screen); +#endif + +/* local variables */ +static int ignore_num = 0; +static Ecore_X_Window *ignore_list = NULL; + +/* external variables */ +int _ecore_xcb_button_grabs_num = 0; +int _ecore_xcb_key_grabs_num = 0; +Ecore_X_Window *_ecore_xcb_button_grabs = NULL; +Ecore_X_Window *_ecore_xcb_key_grabs = NULL; +Eina_Bool (*_ecore_xcb_window_grab_replay_func)(void *data, + int type, + void *event); +void *_ecore_xcb_window_grab_replay_data; + +/** + * @defgroup Ecore_X_Window_Create_Group X Window Creation Functions + * + * Functions that can be used to create an X window. + */ + +/** + * Creates a new window. + * @param parent The parent window to use. If @p parent is @c 0, the root + * window of the default display is used. + * @param x X position. + * @param y Y position. + * @param w Width. + * @param h Height. + * @return The new window handle. + * @ingroup Ecore_X_Window_Create_Group + */ +EAPI Ecore_X_Window +ecore_x_window_new(Ecore_X_Window parent, + int x, + int y, + int w, + int h) +{ + Ecore_X_Window win; + uint32_t mask, mask_list[9]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (parent == 0) + parent = ((xcb_screen_t *)_ecore_xcb_screen)->root; + + /* NB: Order here is very important due to xcb_cw_t enum */ + mask = (XCB_CW_BACK_PIXMAP | XCB_CW_BORDER_PIXEL | XCB_CW_BIT_GRAVITY | + XCB_CW_WIN_GRAVITY | XCB_CW_BACKING_STORE | + XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER | XCB_CW_EVENT_MASK | + XCB_CW_DONT_PROPAGATE); + + mask_list[0] = XCB_BACK_PIXMAP_NONE; + mask_list[1] = 0; + mask_list[2] = XCB_GRAVITY_NORTH_WEST; + mask_list[3] = XCB_GRAVITY_NORTH_WEST; + mask_list[4] = XCB_BACKING_STORE_NOT_USEFUL; + mask_list[5] = 0; + mask_list[6] = 0; + mask_list[7] = (XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | + XCB_EVENT_MASK_BUTTON_PRESS | + XCB_EVENT_MASK_BUTTON_RELEASE | + XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | + XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_EXPOSURE | + XCB_EVENT_MASK_VISIBILITY_CHANGE | + XCB_EVENT_MASK_STRUCTURE_NOTIFY | + XCB_EVENT_MASK_FOCUS_CHANGE | + XCB_EVENT_MASK_PROPERTY_CHANGE | + XCB_EVENT_MASK_COLOR_MAP_CHANGE); + mask_list[8] = XCB_EVENT_MASK_NO_EVENT; + + win = xcb_generate_id(_ecore_xcb_conn); + xcb_create_window(_ecore_xcb_conn, XCB_COPY_FROM_PARENT, + win, parent, x, y, w, h, 0, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + XCB_COPY_FROM_PARENT, mask, mask_list); + + if (parent == ((xcb_screen_t *)_ecore_xcb_screen)->root) + ecore_x_window_defaults_set(win); + + return win; +} + +/** + * Creates a window with the override redirect attribute set to @c True. + * @param parent The parent window to use. If @p parent is @c 0, the root + * window of the default display is used. + * @param x X position. + * @param y Y position. + * @param w Width. + * @param h Height. + * @return The new window handle. + * @ingroup Ecore_X_Window_Create_Group + */ +EAPI Ecore_X_Window +ecore_x_window_override_new(Ecore_X_Window parent, + int x, + int y, + int w, + int h) +{ + Ecore_X_Window win; + uint32_t mask, mask_list[9]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (parent == 0) + parent = ((xcb_screen_t *)_ecore_xcb_screen)->root; + + /* NB: Order here is very important due to xcb_cw_t enum */ + mask = (XCB_CW_BACK_PIXMAP | XCB_CW_BORDER_PIXEL | XCB_CW_BIT_GRAVITY | + XCB_CW_WIN_GRAVITY | XCB_CW_BACKING_STORE | + XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER | XCB_CW_EVENT_MASK | + XCB_CW_DONT_PROPAGATE); + + mask_list[0] = XCB_BACK_PIXMAP_NONE; + mask_list[1] = 0; + mask_list[2] = XCB_GRAVITY_NORTH_WEST; + mask_list[3] = XCB_GRAVITY_NORTH_WEST; + mask_list[4] = XCB_BACKING_STORE_NOT_USEFUL; + mask_list[5] = 1; + mask_list[6] = 0; + mask_list[7] = (XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | + XCB_EVENT_MASK_BUTTON_PRESS | + XCB_EVENT_MASK_BUTTON_RELEASE | + XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | + XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_EXPOSURE | + XCB_EVENT_MASK_VISIBILITY_CHANGE | + XCB_EVENT_MASK_STRUCTURE_NOTIFY | + XCB_EVENT_MASK_FOCUS_CHANGE | + XCB_EVENT_MASK_PROPERTY_CHANGE | + XCB_EVENT_MASK_COLOR_MAP_CHANGE); + mask_list[8] = XCB_EVENT_MASK_NO_EVENT; + + win = xcb_generate_id(_ecore_xcb_conn); + xcb_create_window(_ecore_xcb_conn, XCB_COPY_FROM_PARENT, + win, parent, x, y, w, h, 0, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + XCB_COPY_FROM_PARENT, mask, mask_list); + + return win; +} + +/** + * Creates a new input window. + * @param parent The parent window to use. If @p parent is @c 0, the root + * window of the default display is used. + * @param x X position. + * @param y Y position. + * @param w Width. + * @param h Height. + * @return The new window. + * @ingroup Ecore_X_Window_Create_Group + */ +EAPI Ecore_X_Window +ecore_x_window_input_new(Ecore_X_Window parent, + int x, + int y, + int w, + int h) +{ + Ecore_X_Window win; + uint32_t mask, mask_list[3]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__) + CHECK_XCB_CONN; + + if (parent == 0) + parent = ((xcb_screen_t *)_ecore_xcb_screen)->root; + + /* NB: Order here is very important due to xcb_cw_t enum */ + mask = (XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK | + XCB_CW_DONT_PROPAGATE); + + mask_list[0] = 1; + mask_list[1] = (XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | + XCB_EVENT_MASK_BUTTON_PRESS | + XCB_EVENT_MASK_BUTTON_RELEASE | + XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | + XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_EXPOSURE | + XCB_EVENT_MASK_VISIBILITY_CHANGE | + XCB_EVENT_MASK_STRUCTURE_NOTIFY | + XCB_EVENT_MASK_FOCUS_CHANGE | + XCB_EVENT_MASK_PROPERTY_CHANGE | + XCB_EVENT_MASK_COLOR_MAP_CHANGE); + mask_list[2] = XCB_EVENT_MASK_NO_EVENT; + + win = xcb_generate_id(_ecore_xcb_conn); + xcb_create_window(_ecore_xcb_conn, XCB_COPY_FROM_PARENT, + win, parent, x, y, w, h, 0, + XCB_WINDOW_CLASS_INPUT_ONLY, + XCB_COPY_FROM_PARENT, mask, mask_list); + + return win; +} + +/** + * Creates a new window. + * @param parent The parent window to use. If @p parent is @c 0, the root + * window of the default display is used. + * @param x X position. + * @param y Y position. + * @param w Width. + * @param h Height. + * @return The new window handle. + * @ingroup Ecore_X_Window_Create_Group + */ +EAPI Ecore_X_Window +ecore_x_window_manager_argb_new(Ecore_X_Window parent, + int x, + int y, + int w, + int h) +{ + Ecore_X_Window win = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + win = _ecore_xcb_window_argb_internal_new(parent, x, y, w, h, 1, 0); + + return win; +} + +/** + * Creates a new window. + * @param parent The parent window to use. If @p parent is @c 0, the root + * window of the default display is used. + * @param x X position. + * @param y Y position. + * @param w Width. + * @param h Height. + * @return The new window handle. + * @ingroup Ecore_X_Window_Create_Group + */ +EAPI Ecore_X_Window +ecore_x_window_argb_new(Ecore_X_Window parent, + int x, + int y, + int w, + int h) +{ + Ecore_X_Window win = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + win = _ecore_xcb_window_argb_internal_new(parent, x, y, w, h, 0, 0); + + return win; +} + +/** + * Creates a window with the override redirect attribute set to @c True. + * @param parent The parent window to use. If @p parent is @c 0, the root + * window of the default display is used. + * @param x X position. + * @param y Y position. + * @param w Width. + * @param h Height. + * @return The new window handle. + * @ingroup Ecore_X_Window_Create_Group + */ +EAPI Ecore_X_Window +ecore_x_window_override_argb_new(Ecore_X_Window parent, + int x, + int y, + int w, + int h) +{ + Ecore_X_Window win = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + win = _ecore_xcb_window_argb_internal_new(parent, x, y, w, h, 1, 0); + + return win; +} + +/** + * @defgroup Ecore_X_Window_Destroy_Group X Window Destroy Functions + * + * Functions to destroy X windows. + */ + +/** + * Deletes the given window. + * @param win The given window. + * @ingroup Ecore_X_Window_Destroy_Group + */ +EAPI void +ecore_x_window_free(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (win) + { + /* xcb_destroy_notify_event_t ev; */ + /* Ecore_X_Window root; */ + + /* if (xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)).rem == 1) */ + /* root = ((xcb_screen_t *)_ecore_xcb_screen)->root; */ + /* else */ + /* { */ + /* xcb_get_geometry_cookie_t cookie; */ + /* xcb_get_geometry_reply_t *reply; */ + + /* cookie = xcb_get_geometry_unchecked(_ecore_xcb_conn, win); */ + /* reply = xcb_get_geometry_reply(_ecore_xcb_conn, cookie, NULL); */ + /* if (!reply) return; */ + /* root = reply->root; */ + /* free(reply); */ + /* } */ + + /* memset(&ev, 0, sizeof(xcb_destroy_notify_event_t)); */ + + /* ev.response_type = XCB_DESTROY_NOTIFY; */ + /* ev.window = win; */ + /* ev.event = root; */ + + /* xcb_send_event(_ecore_xcb_conn, 0, root, */ + /* XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | */ + /* XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, */ + /* (const char *)&ev); */ + + xcb_destroy_window(_ecore_xcb_conn, win); +// ecore_x_flush(); + } +} + +/** + * Sends a delete request to the given window. + * @param win The given window. + * @ingroup Ecore_X_Window_Destroy_Group + */ +EAPI void +ecore_x_window_delete_request_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!win) return; + ecore_x_client_message32_send(win, ECORE_X_ATOM_WM_PROTOCOLS, + XCB_EVENT_MASK_NO_EVENT, + ECORE_X_ATOM_WM_DELETE_WINDOW, + XCB_CURRENT_TIME, 0, 0, 0); +} + +EAPI void +ecore_x_window_configure(Ecore_X_Window win, + Ecore_X_Window_Configure_Mask mask, + int x, + int y, + int w, + int h, + int border_width, + Ecore_X_Window sibling, + int stack_mode) +{ + uint16_t vmask = 0; + uint32_t vlist[7]; + unsigned int i = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!win) return; + + if (mask & XCB_CONFIG_WINDOW_X) + { + vmask |= XCB_CONFIG_WINDOW_X; + vlist[i++] = x; + } + if (mask & XCB_CONFIG_WINDOW_Y) + { + vmask |= XCB_CONFIG_WINDOW_Y; + vlist[i++] = y; + } + if (mask & XCB_CONFIG_WINDOW_WIDTH) + { + vmask |= XCB_CONFIG_WINDOW_WIDTH; + vlist[i++] = w; + } + if (mask & XCB_CONFIG_WINDOW_HEIGHT) + { + vmask |= XCB_CONFIG_WINDOW_HEIGHT; + vlist[i++] = h; + } + if (mask & XCB_CONFIG_WINDOW_BORDER_WIDTH) + { + vmask |= XCB_CONFIG_WINDOW_BORDER_WIDTH; + vlist[i++] = border_width; + } + if (mask & XCB_CONFIG_WINDOW_SIBLING) + { + vmask |= XCB_CONFIG_WINDOW_SIBLING; + vlist[i++] = sibling; + } + if (mask & XCB_CONFIG_WINDOW_STACK_MODE) + { + vmask |= XCB_CONFIG_WINDOW_STACK_MODE; + vlist[i++] = stack_mode; + } + + xcb_configure_window(_ecore_xcb_conn, win, vmask, + (const uint32_t *)&vlist); +// ecore_x_flush(); +} + +/** + * @defgroup Ecore_X_Window_Geometry_Group X Window Geometry Functions + * + * Functions that change or retrieve the geometry of X windows. + */ + +/** + * Moves a window to the position @p x, @p y. + * + * The position is relative to the upper left hand corner of the + * parent window. + * + * @param win The window to move. + * @param x X position. + * @param y Y position. + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI void +ecore_x_window_move(Ecore_X_Window win, + int x, + int y) +{ + uint32_t list[2], mask; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!win) return; + + mask = (XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y); + list[0] = x; + list[1] = y; + + xcb_configure_window(_ecore_xcb_conn, win, mask, + (const uint32_t *)&list); +// ecore_x_flush(); +} + +/** + * Resizes a window. + * @param win The window to resize. + * @param w New width of the window. + * @param h New height of the window. + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI void +ecore_x_window_resize(Ecore_X_Window win, + int w, + int h) +{ + uint32_t list[2], mask; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!win) return; + if (w < 1) w = 1; + if (h < 1) h = 1; + + mask = (XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT); + list[0] = w; + list[1] = h; + + xcb_configure_window(_ecore_xcb_conn, win, mask, + (const uint32_t *)&list); +// ecore_x_flush(); +} + +/** + * Moves and resizes a window. + * @param win The window to move and resize. + * @param x New X position of the window. + * @param y New Y position of the window. + * @param w New width of the window. + * @param h New height of the window. + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI void +ecore_x_window_move_resize(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ + uint32_t list[4], mask; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!win) return; + if (w < 1) w = 1; + if (h < 1) h = 1; + + mask = (XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | + XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT); + list[0] = x; + list[1] = y; + list[2] = w; + list[3] = h; + + xcb_configure_window(_ecore_xcb_conn, win, mask, + (const uint32_t *)&list); +// ecore_x_flush(); +} + +/** + * Retrieves the width of the border of the given window. + * @param win The given window. + * @return Width of the border of @p win. + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI int +ecore_x_window_border_width_get(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!win) return 0; + return ecore_x_drawable_border_width_get(win); +} + +/** + * Sets the width of the border of the given window. + * @param win The given window. + * @param width The new border width. + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI void +ecore_x_window_border_width_set(Ecore_X_Window win, + int border_width) +{ + uint32_t list; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!win) return; + + list = border_width; + + xcb_configure_window(_ecore_xcb_conn, win, + XCB_CONFIG_WINDOW_BORDER_WIDTH, &list); +// ecore_x_flush(); +} + +/** + * @defgroup Ecore_X_Window_Z_Order_Group X Window Z Order Functions + * + * Functions that change the Z order of X windows. + */ + +/** + * Raises the given window. + * @param win The window to raise. + * @ingroup Ecore_X_Window_Z_Order_Group + */ +EAPI void +ecore_x_window_raise(Ecore_X_Window win) +{ + uint32_t list[] = { XCB_STACK_MODE_ABOVE }; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_configure_window(_ecore_xcb_conn, win, + XCB_CONFIG_WINDOW_STACK_MODE, list); +// ecore_x_flush(); +} + +/** + * Lowers the given window. + * @param win The window to lower. + * @ingroup Ecore_X_Window_Z_Order_Group + */ +EAPI void +ecore_x_window_lower(Ecore_X_Window win) +{ + uint32_t list[] = { XCB_STACK_MODE_BELOW }; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_configure_window(_ecore_xcb_conn, win, + XCB_CONFIG_WINDOW_STACK_MODE, list); +// ecore_x_flush(); +} + +/** + * Retrieves the depth of the given window. + * @param win The given window. + * @return Depth of the window. + */ +EAPI int +ecore_x_window_depth_get(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return ecore_x_drawable_depth_get(win); +} + +/** + * @defgroup Ecore_X_Window_Properties_Group X Window Property Functions + * + * Functions that set window properties. + */ + +/** + * Sets the default properties for the given window. + * + * The default properties set for the window are @c WM_CLIENT_MACHINE and + * @c _NET_WM_PID. + * + * @param win The given window. + * @ingroup Ecore_X_Window_Properties_Group + */ +EAPI void +ecore_x_window_defaults_set(Ecore_X_Window win) +{ + char buff[MAXHOSTNAMELEN], **argv; + int argc; + pid_t pid; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + gethostname(buff, MAXHOSTNAMELEN); + buff[MAXHOSTNAMELEN - 1] = '\0'; + + xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, + ECORE_X_ATOM_WM_CLIENT_MACHINE, ECORE_X_ATOM_STRING, + 8, strlen(buff), buff); + + pid = getpid(); + ecore_x_netwm_pid_set(win, pid); + ecore_x_netwm_window_type_set(win, ECORE_X_WINDOW_TYPE_NORMAL); + ecore_app_args_get(&argc, &argv); + ecore_x_icccm_command_set(win, argc, argv); +} + +/** + * @defgroup Ecore_X_Window_Visibility_Group X Window Visibility Functions + * + * Functions to access and change the visibility of X windows. + */ + +/** + * Shows a window. + * + * Synonymous to "mapping" a window in X Window System terminology. + * + * @param win The window to show. + * @ingroup Ecore_X_Window_Visibility + */ +EAPI void +ecore_x_window_show(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (win) + xcb_map_window(_ecore_xcb_conn, win); +} + +/** + * Hides a window. + * + * Synonymous to "unmapping" a window in X Window System terminology. + * + * @param win The window to hide. + * @ingroup Ecore_X_Window_Visibility + */ +EAPI void +ecore_x_window_hide(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (win) + { + xcb_unmap_notify_event_t ev; + Ecore_X_Window root; + + if (xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)).rem == 1) + root = ((xcb_screen_t *)_ecore_xcb_screen)->root; + else + { + xcb_get_geometry_cookie_t cookie; + xcb_get_geometry_reply_t *reply; + + cookie = xcb_get_geometry_unchecked(_ecore_xcb_conn, win); + reply = xcb_get_geometry_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return; + root = reply->root; + free(reply); + } + + memset(&ev, 0, sizeof(xcb_unmap_notify_event_t)); + + ev.response_type = XCB_UNMAP_NOTIFY; + ev.window = win; + ev.event = root; + ev.from_configure = 0; + + xcb_send_event(_ecore_xcb_conn, 0, root, + (XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | + XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT), + (const char *)&ev); + + xcb_unmap_window(_ecore_xcb_conn, win); +// ecore_x_flush(); + } +} + +/** + * @defgroup Ecore_X_Window_Focus_Functions X Window Focus Functions + * + * Functions that give the focus to an X Window. + */ + +/** + * Sets the focus to the window @p win. + * @param win The window to focus. + * @ingroup Ecore_X_Window_Focus_Functions + */ +EAPI void +ecore_x_window_focus(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!win) win = ((xcb_screen_t *)_ecore_xcb_screen)->root; + + xcb_set_input_focus(_ecore_xcb_conn, + XCB_INPUT_FOCUS_PARENT, win, XCB_CURRENT_TIME); +// ecore_x_flush(); +} + +/** + * Sets the focus to the given window at a specific time. + * @param win The window to focus. + * @param t When to set the focus to the window. + * @ingroup Ecore_X_Window_Focus_Functions + */ +EAPI void +ecore_x_window_focus_at_time(Ecore_X_Window win, + Ecore_X_Time time __UNUSED__) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!win) win = ((xcb_screen_t *)_ecore_xcb_screen)->root; + xcb_set_input_focus(_ecore_xcb_conn, + XCB_INPUT_FOCUS_PARENT, win, XCB_CURRENT_TIME); +// ecore_x_flush(); +} + +/** + * @defgroup Ecore_X_Window_Parent_Group X Window Parent Functions + * + * Functions that retrieve or changes the parent window of a window. + */ + +/** + * Moves a window to within another window at a given position. + * @param win The window to reparent. + * @param new_parent The new parent window. + * @param x X position within new parent window. + * @param y Y position within new parent window. + * @ingroup Ecore_X_Window_Parent_Group + */ +EAPI void +ecore_x_window_reparent(Ecore_X_Window win, + Ecore_X_Window parent, + int x, + int y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (parent == 0) + parent = ((xcb_screen_t *)_ecore_xcb_screen)->root; + + xcb_reparent_window(_ecore_xcb_conn, win, parent, x, y); +// ecore_x_flush(); +} + +EAPI void +ecore_x_window_pixmap_set(Ecore_X_Window win, + Ecore_X_Pixmap pixmap) +{ + uint32_t list; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + list = pixmap; + + xcb_change_window_attributes(_ecore_xcb_conn, win, + XCB_CW_BACK_PIXMAP, &list); +// ecore_x_flush(); +} + +/** + * Sets the background color of the given window. + * @param win The given window + * @param r red value (0...65536, 16 bits) + * @param g green value (0...65536, 16 bits) + * @param b blue value (0...65536, 16 bits) + */ +EAPI void +ecore_x_window_background_color_set(Ecore_X_Window win, + unsigned short red, + unsigned short green, + unsigned short blue) +{ + xcb_alloc_color_cookie_t cookie; + xcb_alloc_color_reply_t *reply; + uint32_t list; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + cookie = + xcb_alloc_color_unchecked(_ecore_xcb_conn, + ((xcb_screen_t *)_ecore_xcb_screen)->default_colormap, + red, green, blue); + reply = xcb_alloc_color_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return; + list = reply->pixel; + free(reply); + + xcb_change_window_attributes(_ecore_xcb_conn, win, + XCB_CW_BACK_PIXEL, &list); +// ecore_x_flush(); +} + +EAPI void +ecore_x_window_pixel_gravity_set(Ecore_X_Window win, + Ecore_X_Gravity gravity) +{ + uint32_t list; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + list = gravity; + + xcb_change_window_attributes(_ecore_xcb_conn, win, + XCB_CW_BIT_GRAVITY, &list); +// ecore_x_flush(); +} + +EAPI void +ecore_x_window_gravity_set(Ecore_X_Window win, + Ecore_X_Gravity gravity) +{ + uint32_t list; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + list = gravity; + + xcb_change_window_attributes(_ecore_xcb_conn, win, + XCB_CW_WIN_GRAVITY, &list); +// ecore_x_flush(); +} + +EAPI void +ecore_x_window_override_set(Ecore_X_Window win, + Eina_Bool override) +{ + uint32_t list; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + list = override; + + xcb_change_window_attributes(_ecore_xcb_conn, win, + XCB_CW_OVERRIDE_REDIRECT, &list); +// ecore_x_flush(); +} + +/** + * @brief Show the cursor on a window of type Ecore_X_Window. + * @param win The window for which the cursor will be showed. + * @param show Enables the show of the cursor on the window if equals EINA_TRUE, disables if equals EINA_FALSE. + */ +EAPI void +ecore_x_window_cursor_show(Ecore_X_Window win, + Eina_Bool show) +{ + uint32_t list = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!win) win = ((xcb_screen_t *)_ecore_xcb_screen)->root; + + if (!show) + { + Ecore_X_Cursor cursor; + Ecore_X_Pixmap p, m; + Ecore_X_GC gc; + xcb_point_t point; + + p = xcb_generate_id(_ecore_xcb_conn); + xcb_create_pixmap(_ecore_xcb_conn, 1, p, win, 1, 1); + m = xcb_generate_id(_ecore_xcb_conn); + xcb_create_pixmap(_ecore_xcb_conn, 1, m, win, 1, 1); + gc = xcb_generate_id(_ecore_xcb_conn); + xcb_create_gc(_ecore_xcb_conn, gc, win, 0, NULL); + xcb_change_gc(_ecore_xcb_conn, gc, XCB_GC_FOREGROUND, &list); + point.x = 0; + point.y = 0; + xcb_poly_point(_ecore_xcb_conn, XCB_COORD_MODE_ORIGIN, + win, gc, 1, &point); + xcb_free_gc(_ecore_xcb_conn, gc); + + cursor = xcb_generate_id(_ecore_xcb_conn); + xcb_create_cursor(_ecore_xcb_conn, cursor, + p, m, 0, 0, 0, 0, 0, 0, 0, 0); + list = cursor; + + xcb_change_window_attributes(_ecore_xcb_conn, win, + XCB_CW_CURSOR, &list); + + xcb_free_cursor(_ecore_xcb_conn, cursor); + xcb_free_pixmap(_ecore_xcb_conn, m); + xcb_free_pixmap(_ecore_xcb_conn, p); + } + else + { + xcb_change_window_attributes(_ecore_xcb_conn, win, + XCB_CW_CURSOR, &list); + } +// ecore_x_flush(); +} + +EAPI void +ecore_x_window_cursor_set(Ecore_X_Window win, + Ecore_X_Cursor cursor) +{ + uint32_t list; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + list = cursor; + + xcb_change_window_attributes(_ecore_xcb_conn, win, XCB_CW_CURSOR, &list); +// ecore_x_flush(); +} + +EAPI void +ecore_x_window_container_manage(Ecore_X_Window win) +{ + uint32_t list; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + list = (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY); + + xcb_change_window_attributes(_ecore_xcb_conn, win, + XCB_CW_EVENT_MASK, &list); +// ecore_x_flush(); +} + +EAPI void +ecore_x_window_client_manage(Ecore_X_Window win) +{ + uint32_t list; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + list = (XCB_EVENT_MASK_VISIBILITY_CHANGE | + XCB_EVENT_MASK_FOCUS_CHANGE | + XCB_EVENT_MASK_PROPERTY_CHANGE | + XCB_EVENT_MASK_COLOR_MAP_CHANGE | + XCB_EVENT_MASK_STRUCTURE_NOTIFY | + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY); + + xcb_change_window_attributes(_ecore_xcb_conn, win, + XCB_CW_EVENT_MASK, &list); + +#ifdef ECORE_XCB_SHAPE + xcb_shape_select_input(_ecore_xcb_conn, win, EINA_TRUE); +#endif +// ecore_x_flush(); +} + +EAPI void +ecore_x_window_sniff(Ecore_X_Window win) +{ + uint32_t list; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + list = (XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | + XCB_EVENT_MASK_PROPERTY_CHANGE); + + xcb_change_window_attributes(_ecore_xcb_conn, win, + XCB_CW_EVENT_MASK, &list); +// ecore_x_flush(); +} + +EAPI void +ecore_x_window_client_sniff(Ecore_X_Window win) +{ + uint32_t list; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + list = (XCB_EVENT_MASK_VISIBILITY_CHANGE | + XCB_EVENT_MASK_STRUCTURE_NOTIFY | + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | + XCB_EVENT_MASK_FOCUS_CHANGE | + XCB_EVENT_MASK_PROPERTY_CHANGE | + XCB_EVENT_MASK_COLOR_MAP_CHANGE); + + xcb_change_window_attributes(_ecore_xcb_conn, win, + XCB_CW_EVENT_MASK, &list); +#ifdef ECORE_XCB_SHAPE + xcb_shape_select_input(_ecore_xcb_conn, win, EINA_TRUE); +#endif +// ecore_x_flush(); +} + +EAPI void +ecore_x_window_area_clear(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_clear_area(_ecore_xcb_conn, 0, win, x, y, w, h); +// ecore_x_flush(); +} + +EAPI void +ecore_x_window_area_expose(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_clear_area(_ecore_xcb_conn, 1, win, x, y, w, h); +// ecore_x_flush(); +} + +EAPI void +ecore_x_window_save_set_add(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_change_save_set(_ecore_xcb_conn, XCB_SET_MODE_INSERT, win); +} + +EAPI void +ecore_x_window_save_set_del(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_change_save_set(_ecore_xcb_conn, XCB_SET_MODE_DELETE, win); +} + +/** + * gets the window that has focus. + * @return The window that has focus. + * @ingroup Ecore_X_Window_Focus_Functions + */ +EAPI Ecore_X_Window +ecore_x_window_focus_get(void) +{ + xcb_get_input_focus_cookie_t cookie; + xcb_get_input_focus_reply_t *reply; + Ecore_X_Window focus = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + cookie = xcb_get_input_focus_unchecked(_ecore_xcb_conn); + reply = xcb_get_input_focus_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return 0; + focus = reply->focus; + free(reply); + return focus; +} + +EAPI int +ecore_x_window_argb_get(Ecore_X_Window win) +{ + uint8_t ret = 0; +#ifdef ECORE_XCB_RENDER + Ecore_X_Visual visual; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +// if (!win) return ret; + +#ifdef ECORE_XCB_RENDER + /* grab the window's visual */ + visual = _ecore_xcb_window_visual_get(win); + + /* check if this visual supports alpha */ + ret = _ecore_xcb_render_visual_supports_alpha(visual); +#endif + + return ret; +} + +EAPI Eina_Bool +ecore_x_window_manage(Ecore_X_Window win) +{ + xcb_get_window_attributes_cookie_t cookie; + xcb_get_window_attributes_reply_t *reply; + xcb_void_cookie_t change_cookie; + xcb_generic_error_t *err; + uint32_t list; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + cookie = xcb_get_window_attributes(_ecore_xcb_conn, win); + reply = xcb_get_window_attributes_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return EINA_FALSE; + + ecore_x_sync(); // needed + + list = (XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | + XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_RESIZE_REDIRECT | + XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | + XCB_EVENT_MASK_STRUCTURE_NOTIFY | + XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | + reply->your_event_mask); + free(reply); + + change_cookie = xcb_change_window_attributes(_ecore_xcb_conn, win, + XCB_CW_EVENT_MASK, &list); + + ecore_x_sync(); // needed + + err = xcb_request_check(_ecore_xcb_conn, change_cookie); + if (err) + { + _ecore_xcb_error_handle(err); + free(err); + return EINA_FALSE; + } + + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_x_window_attributes_get(Ecore_X_Window win, + Ecore_X_Window_Attributes *att_ret) +{ + xcb_get_window_attributes_cookie_t cookie; + xcb_get_window_attributes_reply_t *reply; + xcb_get_geometry_cookie_t gcookie; + xcb_get_geometry_reply_t *greply; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + cookie = xcb_get_window_attributes_unchecked(_ecore_xcb_conn, win); + reply = xcb_get_window_attributes_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return EINA_FALSE; + + memset(att_ret, 0, sizeof(Ecore_X_Window_Attributes)); + + if (reply->map_state != XCB_MAP_STATE_UNMAPPED) + att_ret->visible = EINA_TRUE; + + if (reply->map_state == XCB_MAP_STATE_VIEWABLE) + att_ret->viewable = EINA_TRUE; + + if (reply->override_redirect) + att_ret->override = EINA_TRUE; + + if (reply->_class == XCB_WINDOW_CLASS_INPUT_ONLY) + att_ret->input_only = EINA_TRUE; + + if (reply->save_under) + att_ret->save_under = EINA_TRUE; + + att_ret->event_mask.mine = reply->your_event_mask; + att_ret->event_mask.all = reply->all_event_masks; + att_ret->event_mask.no_propagate = reply->do_not_propagate_mask; + att_ret->window_gravity = reply->win_gravity; + att_ret->pixel_gravity = reply->bit_gravity; + att_ret->colormap = reply->colormap; + att_ret->visual = _ecore_xcb_window_find_visual_by_id(reply->visual); + + free(reply); + + gcookie = xcb_get_geometry_unchecked(_ecore_xcb_conn, win); + greply = xcb_get_geometry_reply(_ecore_xcb_conn, gcookie, NULL); + if (!greply) return EINA_TRUE; + + /* xcb_translate_coordinates_reply_t *trans; */ + /* xcb_query_tree_cookie_t tcookie; */ + /* xcb_query_tree_reply_t *treply; */ + + /* tcookie = xcb_query_tree(_ecore_xcb_conn, win); */ + /* treply = xcb_query_tree_reply(_ecore_xcb_conn, tcookie, NULL); */ + + /* trans = */ + /* xcb_translate_coordinates_reply(_ecore_xcb_conn, */ + /* xcb_translate_coordinates(_ecore_xcb_conn, */ + /* win, treply->parent, greply->x, greply->y), NULL); */ + /* free(treply); */ + + att_ret->root = greply->root; + att_ret->depth = greply->depth; +// att_ret->x = trans->dst_x; +// att_ret->y = trans->dst_y; + att_ret->x = greply->x; + att_ret->y = greply->y; + att_ret->w = greply->width; + att_ret->h = greply->height; + att_ret->border = greply->border_width; + +// free(trans); + + free(greply); + return EINA_TRUE; +} + +/** + * Retrieves the size of the given window. + * @param win The given window. + * @param w Pointer to an integer into which the width is to be stored. + * @param h Pointer to an integer into which the height is to be stored. + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI void +ecore_x_window_size_get(Ecore_X_Window win, + int *width, + int *height) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!win) win = ((xcb_screen_t *)_ecore_xcb_screen)->root; + ecore_x_drawable_geometry_get(win, NULL, NULL, width, height); +} + +/** + * Set if a window should be ignored. + * @param win The given window. + * @param ignore if to ignore + */ +EAPI void +ecore_x_window_ignore_set(Ecore_X_Window win, + int ignore) +{ + int i = 0, j = 0, count = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (ignore) + { + if (ignore_list) + { + for (i = 0; i < ignore_num; i++) + if (win == ignore_list[i]) return; + + ignore_list = + realloc(ignore_list, (ignore_num + 1) * sizeof(Ecore_X_Window)); + if (!ignore_list) return; + + ignore_list[ignore_num++] = win; + } + else + { + ignore_num = 0; + ignore_list = malloc(sizeof(Ecore_X_Window)); + if (!ignore_list) return; + ignore_list[ignore_num++] = win; + } + } + else + { + if (!ignore_list) return; + for (count = ignore_num, i = 0, j = 0; i < count; i++) + { + if (win != ignore_list[i]) + ignore_list[j++] = ignore_list[i]; + else + ignore_num--; + } + if (ignore_num <= 0) + { + free(ignore_list); + ignore_list = NULL; + return; + } + + ignore_list = + realloc(ignore_list, ignore_num * sizeof(Ecore_X_Window)); + } +} + +/** + * Get the ignore list + * @param num number of windows in the list + * @return list of windows to ignore + */ +EAPI Ecore_X_Window * +ecore_x_window_ignore_list(int *num) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (num) *num = ignore_num; + return ignore_list; +} + +/** + * Get a list of all the root windows on the server. + * + * @note The returned array will need to be freed after use. + * @param num_ret Pointer to integer to put number of windows returned in. + * @return An array of all the root windows. @c NULL is returned if memory + * could not be allocated for the list, or if @p num_ret is @c NULL. + */ +EAPI Ecore_X_Window * +ecore_x_window_root_list(int *num_ret) +{ + xcb_screen_iterator_t iter; + uint8_t i, num; + Ecore_X_Window *roots = NULL; +#ifdef ECORE_XCB_XPRINT + const xcb_query_extension_reply_t *ext_reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!num_ret) return NULL; + if (num_ret) *num_ret = 0; + + /* if (xcb_connection_has_error(_ecore_xcb_conn)) */ + /* { */ + /* DBG("XCB Connection Has Error !!!"); */ + /* return NULL; */ + /* } */ + + num = ecore_x_screen_count_get(); + +#ifdef ECORE_XCB_XPRINT + ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_x_print_id); + if ((ext_reply) && (ext_reply->present)) + { + xcb_x_print_print_query_screens_cookie_t cookie; + xcb_x_print_print_query_screens_reply_t *reply; + + cookie = xcb_x_print_print_query_screens_unchecked(_ecore_xcb_conn); + reply = + xcb_x_print_print_query_screens_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + xcb_window_t *screens; + int psnum = 0, overlap = 0, j = 0, k = 0; + + psnum = xcb_x_print_print_query_screens_roots_length(reply); + screens = xcb_x_print_print_query_screens_roots(reply); + for (i = 0; i < num; i++) + { + for (j = 0; j < psnum; j++) + { + xcb_screen_t *s; + + if ((s = _ecore_xcb_window_screen_of_display(i))) + { + if (s->root == screens[j]) + overlap++; + } + } + } + if (!(roots = malloc((num - overlap) + * sizeof(Ecore_X_Window)))) return NULL; + for (i = 0; i < num; i++) + { + Eina_Bool is_print = EINA_FALSE; + + for (j = 0; j < psnum; j++) + { + xcb_screen_t *s; + + if ((s = _ecore_xcb_window_screen_of_display(i))) + { + if (s->root == screens[j]) + { + is_print = EINA_TRUE; + break; + } + } + } + if (!is_print) + { + xcb_screen_t *s; + + if ((s = _ecore_xcb_window_screen_of_display(i))) + { + roots[k] = s->root; + k++; + } + } + } + if (num_ret) *num_ret = k; + free(reply); + } + else + { + /* Fallback to default method */ + iter = + xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)); + if (!(roots = malloc(num * sizeof(Ecore_X_Window)))) return NULL; + if (num_ret) *num_ret = num; + for (i = 0; iter.rem; xcb_screen_next(&iter), i++) + roots[i] = iter.data->root; + } + } + else + { + /* Fallback to default method */ + iter = + xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)); + if (!(roots = malloc(num * sizeof(Ecore_X_Window)))) return NULL; + if (num_ret) *num_ret = num; + for (i = 0; iter.rem; xcb_screen_next(&iter), i++) + roots[i] = iter.data->root; + } +#else + iter = + xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)); + if (!(roots = malloc(num * sizeof(Ecore_X_Window)))) return NULL; + if (num_ret) *num_ret = num; + for (i = 0; iter.rem; xcb_screen_next(&iter), i++) + roots[i] = iter.data->root; +#endif + + return roots; +} + +EAPI Ecore_X_Window * +ecore_x_window_children_get(Ecore_X_Window win, + int *num) +{ + xcb_query_tree_cookie_t cookie; + xcb_query_tree_reply_t *reply; + Ecore_X_Window *windows = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (num) *num = 0; + cookie = xcb_query_tree_unchecked(_ecore_xcb_conn, win); + reply = xcb_query_tree_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return NULL; + + if (num) *num = reply->children_len; + if (reply->children_len > 0) + { + windows = malloc(sizeof(Ecore_X_Window) * reply->children_len); + if (windows) + { + unsigned int i = 0; + xcb_window_t *w; + + w = xcb_query_tree_children(reply); + for (i = 0; i < reply->children_len; i++) + windows[i] = w[i]; + } + } + + free(reply); + return windows; +} + +/** + * Retrieves the root window a given window is on. + * @param win The window to get the root window of + * @return The root window of @p win + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI Ecore_X_Window +ecore_x_window_root_get(Ecore_X_Window win) +{ + xcb_get_geometry_cookie_t gcookie; + xcb_get_geometry_reply_t *greply; + Ecore_X_Window window = 0; + + /* LOGFN(__FILE__, __LINE__, __FUNCTION__); */ + CHECK_XCB_CONN; + + gcookie = xcb_get_geometry_unchecked(_ecore_xcb_conn, win); + greply = xcb_get_geometry_reply(_ecore_xcb_conn, gcookie, NULL); + if (!greply) return 0; + window = greply->root; + free(greply); + + return window; +} + +EAPI Ecore_X_Window +ecore_x_window_root_first_get(void) +{ + return ((xcb_screen_t *)_ecore_xcb_screen)->root; +} + +/** + * Retrieves the geometry of the given window. + * + * Note that the x & y coordingates are relative to your parent. In + * particular for reparenting window managers - relative to you window border. + * If you want screen coordinates either walk the window tree to the root, + * else for ecore_evas applications see ecore_evas_geometry_get(). Elementary + * applications can use elm_win_screen_position_get(). + * + * @param win The given window. + * @param x Pointer to an integer in which the X position is to be stored. + * @param y Pointer to an integer in which the Y position is to be stored. + * @param w Pointer to an integer in which the width is to be stored. + * @param h Pointer to an integer in which the height is to be stored. + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI void +ecore_x_window_geometry_get(Ecore_X_Window win, + int *x, + int *y, + int *w, + int *h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!win) win = ((xcb_screen_t *)_ecore_xcb_screen)->root; + ecore_x_drawable_geometry_get(win, x, y, w, h); +} + +/** + * Retrieves the top, visible window at the given location. + * @param x The given X position. + * @param y The given Y position. + * @return The window at that position. + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI Ecore_X_Window +ecore_x_window_at_xy_get(int x, + int y) +{ + Ecore_X_Window root, win = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + root = ((xcb_screen_t *)_ecore_xcb_screen)->root; + + ecore_x_grab(); + win = _ecore_xcb_window_at_xy_get(root, 0, 0, x, y, NULL, 0); + ecore_x_ungrab(); + + return win ? win : root; +} + +/** + * Retrieves the top, visible window at the given location, + * but skips the windows in the list. + * @param x The given X position. + * @param y The given Y position. + * @param skip The list of windows to be skipped. + * @param skip_num The number of windows to be skipped. + * @return The window at that position. + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI Ecore_X_Window +ecore_x_window_at_xy_with_skip_get(int x, + int y, + Ecore_X_Window *skip, + int skip_num) +{ + Ecore_X_Window root, win = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + root = ((xcb_screen_t *)_ecore_xcb_screen)->root; + + ecore_x_grab(); + win = _ecore_xcb_window_at_xy_get(root, 0, 0, x, y, skip, skip_num); + ecore_x_ungrab(); + + return win ? win : root; +} + +EAPI Ecore_X_Window +ecore_x_window_at_xy_begin_get(Ecore_X_Window begin, + int x, + int y) +{ + Ecore_X_Window win = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + ecore_x_grab(); + win = _ecore_xcb_window_at_xy_get(begin, 0, 0, x, y, NULL, 0); + ecore_x_ungrab(); + + return win ? win : begin; +} + +/** + * Retrieves the parent window of the given window. + * @param win The given window. + * @return The parent window of @p win. + * @ingroup Ecore_X_Window_Parent_Group + */ +EAPI Ecore_X_Window +ecore_x_window_parent_get(Ecore_X_Window win) +{ + xcb_query_tree_cookie_t cookie; + xcb_query_tree_reply_t *reply; + Ecore_X_Window window = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +// if (!win) return 0; + cookie = xcb_query_tree(_ecore_xcb_conn, win); + reply = xcb_query_tree_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return 0; + window = reply->parent; + free(reply); + + return window; +} + +/** + * Finds out whether the given window is currently visible. + * @param win The given window. + * @return 1 if the window is visible, otherwise 0. + * @ingroup Ecore_X_Window_Visibility_Group + */ +EAPI int +ecore_x_window_visible_get(Ecore_X_Window win) +{ + xcb_get_window_attributes_cookie_t cookie; + xcb_get_window_attributes_reply_t *reply; + int ret = EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + cookie = xcb_get_window_attributes_unchecked(_ecore_xcb_conn, win); + reply = xcb_get_window_attributes_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return EINA_FALSE; + + if (reply->map_state == XCB_MAP_STATE_VIEWABLE) + ret = EINA_TRUE; + + free(reply); + return ret; +} + +EAPI void +ecore_x_window_button_grab(Ecore_X_Window win, + int button, + Ecore_X_Event_Mask mask, + int mod, + int any_mod) +{ + int i = 0; + uint16_t m, locks[8], ev; + uint8_t b; + Ecore_X_Window *t; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + b = button; + if (b == 0) + b = XCB_BUTTON_INDEX_ANY; + + m = _ecore_xcb_window_modifiers_get(mod); + if (any_mod) m = XCB_MOD_MASK_ANY; + + locks[0] = 0; + locks[1] = ECORE_X_LOCK_CAPS; + locks[2] = ECORE_X_LOCK_NUM; + locks[3] = ECORE_X_LOCK_SCROLL; + locks[4] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM; + locks[5] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_SCROLL; + locks[6] = ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL; + locks[7] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL; + + ev = mask; + for (i = 0; i < 8; i++) + xcb_grab_button(_ecore_xcb_conn, 0, win, ev, + XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, + XCB_NONE, XCB_NONE, b, m | locks[i]); + + _ecore_xcb_button_grabs_num++; + t = realloc(_ecore_xcb_button_grabs, + _ecore_xcb_button_grabs_num * sizeof(Ecore_X_Window)); + if (!t) return; + + _ecore_xcb_button_grabs = t; + _ecore_xcb_button_grabs[_ecore_xcb_button_grabs_num - 1] = win; +} + +EAPI void +ecore_x_window_button_ungrab(Ecore_X_Window win, + int button, + int mod, + int any_mod) +{ + int i = 0; + uint16_t m = 0, locks[8]; + uint8_t b; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + b = button; + if (b == 0) b = XCB_BUTTON_INDEX_ANY; + + m = _ecore_xcb_window_modifiers_get(mod); + if (any_mod) m = XCB_MOD_MASK_ANY; + + locks[0] = 0; + locks[1] = ECORE_X_LOCK_CAPS; + locks[2] = ECORE_X_LOCK_NUM; + locks[3] = ECORE_X_LOCK_SCROLL; + locks[4] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM; + locks[5] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_SCROLL; + locks[6] = ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL; + locks[7] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL; + + for (i = 0; i < 8; i++) + xcb_ungrab_button(_ecore_xcb_conn, b, win, m | locks[i]); + + _ecore_xcb_sync_magic_send(1, win); +} + +EAPI void +ecore_x_window_key_grab(Ecore_X_Window win, + const char *key, + int mod, + int any_mod) +{ + xcb_keycode_t keycode = XCB_NO_SYMBOL; + uint16_t m = 0, locks[8]; + int i = 0; + Ecore_X_Window *t; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + keycode = _ecore_xcb_keymap_string_to_keycode(key); + if (keycode == XCB_NO_SYMBOL) return; + + m = _ecore_xcb_window_modifiers_get(mod); + if (any_mod) m = XCB_MOD_MASK_ANY; + + locks[0] = 0; + locks[1] = ECORE_X_LOCK_CAPS; + locks[2] = ECORE_X_LOCK_NUM; + locks[3] = ECORE_X_LOCK_SCROLL; + locks[4] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM; + locks[5] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_SCROLL; + locks[6] = ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL; + locks[7] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL; + + for (i = 0; i < 8; i++) + xcb_grab_key(_ecore_xcb_conn, 0, win, m | locks[i], + keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); + _ecore_xcb_key_grabs_num++; + t = realloc(_ecore_xcb_key_grabs, + _ecore_xcb_key_grabs_num * sizeof(Ecore_X_Window)); + if (!t) return; + _ecore_xcb_key_grabs = t; + _ecore_xcb_key_grabs[_ecore_xcb_key_grabs_num - 1] = win; +} + +EAPI void +ecore_x_window_key_ungrab(Ecore_X_Window win, + const char *key, + int mod, + int any_mod) +{ + xcb_keycode_t keycode = XCB_NO_SYMBOL; + uint16_t m = 0, locks[8]; + int i = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + keycode = _ecore_xcb_keymap_string_to_keycode(key); + if (keycode == XCB_NO_SYMBOL) return; + + m = _ecore_xcb_window_modifiers_get(mod); + if (any_mod) m = XCB_MOD_MASK_ANY; + + locks[0] = 0; + locks[1] = ECORE_X_LOCK_CAPS; + locks[2] = ECORE_X_LOCK_NUM; + locks[3] = ECORE_X_LOCK_SCROLL; + locks[4] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM; + locks[5] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_SCROLL; + locks[6] = ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL; + locks[7] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL; + + for (i = 0; i < 8; i++) + xcb_ungrab_key(_ecore_xcb_conn, keycode, win, m | locks[i]); + + _ecore_xcb_sync_magic_send(2, win); +} + +/* local functions */ +Ecore_X_Window +_ecore_xcb_window_root_of_screen_get(int screen) +{ + xcb_screen_iterator_t iter; + + CHECK_XCB_CONN; + iter = xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)); + for (; iter.rem; --screen, xcb_screen_next(&iter)) + if (screen == 0) + { + xcb_screen_t *s; + + if ((s = iter.data)) + return s->root; + } + return 0; +} + +static Ecore_X_Window +_ecore_xcb_window_argb_internal_new(Ecore_X_Window parent, + int x, + int y, + int w, + int h, + uint8_t override_redirect, + uint8_t save_under) +{ + Ecore_X_Window win = 0; +#ifdef ECORE_XCB_RENDER + uint32_t value_list[10]; + uint32_t value_mask; + uint32_t vis; + Ecore_X_Colormap colormap; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RENDER + if (parent == 0) + parent = ((xcb_screen_t *)_ecore_xcb_screen)->root; + + vis = + _ecore_xcb_render_find_visual_id(XCB_RENDER_PICT_TYPE_DIRECT, EINA_TRUE); + + colormap = xcb_generate_id(_ecore_xcb_conn); + xcb_create_colormap(_ecore_xcb_conn, XCB_COLORMAP_ALLOC_NONE, + colormap, parent, vis); + + value_mask = (XCB_CW_BACK_PIXMAP | XCB_CW_BORDER_PIXEL | XCB_CW_BIT_GRAVITY | + XCB_CW_WIN_GRAVITY | XCB_CW_BACKING_STORE | + XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER | + XCB_CW_EVENT_MASK | XCB_CW_DONT_PROPAGATE | XCB_CW_COLORMAP); + + value_list[0] = XCB_BACK_PIXMAP_NONE; + value_list[1] = 0; + value_list[2] = XCB_GRAVITY_NORTH_WEST; + value_list[3] = XCB_GRAVITY_NORTH_WEST; + value_list[4] = XCB_BACKING_STORE_NOT_USEFUL; + value_list[5] = override_redirect; + value_list[6] = save_under; + value_list[7] = (XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | + XCB_EVENT_MASK_BUTTON_PRESS | + XCB_EVENT_MASK_BUTTON_RELEASE | + XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | + XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_EXPOSURE | + XCB_EVENT_MASK_VISIBILITY_CHANGE | + XCB_EVENT_MASK_STRUCTURE_NOTIFY | + XCB_EVENT_MASK_FOCUS_CHANGE | + XCB_EVENT_MASK_PROPERTY_CHANGE | + XCB_EVENT_MASK_COLOR_MAP_CHANGE); + value_list[8] = XCB_EVENT_MASK_NO_EVENT; + value_list[9] = colormap; + + win = xcb_generate_id(_ecore_xcb_conn); + xcb_create_window(_ecore_xcb_conn, 32, win, parent, x, y, w, h, 0, + XCB_WINDOW_CLASS_INPUT_OUTPUT, vis, value_mask, + value_list); + + xcb_free_colormap(_ecore_xcb_conn, colormap); + + if (parent == ((xcb_screen_t *)_ecore_xcb_screen)->root) + ecore_x_window_defaults_set(win); +#endif + + return win; +} + +static Ecore_X_Window +_ecore_xcb_window_at_xy_get(Ecore_X_Window base, + int bx, + int by, + int x, + int y, + Ecore_X_Window *skip, + int skip_num) +{ + xcb_query_tree_cookie_t cookie; + xcb_query_tree_reply_t *reply; + Ecore_X_Window *windows = NULL; + int wx, wy, ww, wh, num, i = 0; + Eina_Bool skipit = EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!ecore_x_window_visible_get(base)) return 0; + + ecore_x_window_geometry_get(base, &wx, &wy, &ww, &wh); + wx += bx; + wy += by; + + if (!((x >= wx) && (y >= wy) && (x < (wx + ww)) && (y < (wy + wh)))) + return 0; + + cookie = xcb_query_tree_unchecked(_ecore_xcb_conn, base); + reply = xcb_query_tree_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return 0; + + num = reply->children_len; + windows = xcb_query_tree_children(reply); + + for (i = (num - 1); i >= 0; --i) + { + skipit = EINA_FALSE; + + if (skip) + { + int j = 0; + + for (j = 0; j < skip_num; j++) + { + if (windows[i] == skip[j]) + { + skipit = EINA_TRUE; + goto onward; + } + } + } +onward: + if (!skipit) + { + Ecore_X_Window child = 0; + + child = + _ecore_xcb_window_at_xy_get(windows[i], + wx, wy, x, y, skip, skip_num); + if (child) + { + if (reply) free(reply); + return child; + } + } + } + + if (reply) free(reply); + return base; +} + +Ecore_X_Visual +_ecore_xcb_window_visual_get(Ecore_X_Window win) +{ + xcb_get_window_attributes_cookie_t cookie; + xcb_get_window_attributes_reply_t *reply; + Ecore_X_Visual visual = 0; + + CHECK_XCB_CONN; + + cookie = xcb_get_window_attributes(_ecore_xcb_conn, win); + reply = xcb_get_window_attributes_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return 0; + visual = _ecore_xcb_window_find_visual_by_id(reply->visual); + free(reply); + + return visual; +} + +void +_ecore_xcb_window_button_grab_remove(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (_ecore_xcb_button_grabs_num > 0) + { + int i = 0, shuffle = 0; + + for (i = 0; i < _ecore_xcb_button_grabs_num; i++) + { + if (shuffle) + _ecore_xcb_button_grabs[i - 1] = _ecore_xcb_button_grabs[i]; + + if ((!shuffle) && (_ecore_xcb_button_grabs[i] == win)) + shuffle = 1; + } + + if (shuffle) + { + Ecore_X_Window *t; + + _ecore_xcb_button_grabs_num--; + if (_ecore_xcb_button_grabs_num <= 0) + { + free(_ecore_xcb_button_grabs); + _ecore_xcb_button_grabs = NULL; + return; + } + + t = realloc(_ecore_xcb_button_grabs, + _ecore_xcb_button_grabs_num * sizeof(Ecore_X_Window)); + if (!t) return; + _ecore_xcb_button_grabs = t; + } + } +} + +void +_ecore_xcb_window_key_grab_remove(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (_ecore_xcb_key_grabs_num > 0) + { + int i = 0, shuffle = 0; + + for (i = 0; i < _ecore_xcb_key_grabs_num; i++) + { + if (shuffle) + _ecore_xcb_key_grabs[i - 1] = _ecore_xcb_key_grabs[i]; + + if ((!shuffle) && (_ecore_xcb_key_grabs[i] == win)) + shuffle = 1; + } + + if (shuffle) + { + Ecore_X_Window *t; + + _ecore_xcb_key_grabs_num--; + if (_ecore_xcb_key_grabs_num <= 0) + { + free(_ecore_xcb_key_grabs); + _ecore_xcb_key_grabs = NULL; + return; + } + + t = realloc(_ecore_xcb_key_grabs, + _ecore_xcb_key_grabs_num * sizeof(Ecore_X_Window)); + if (!t) return; + _ecore_xcb_key_grabs = t; + } + } +} + +void +_ecore_xcb_window_grab_allow_events(Ecore_X_Window event_win, + Ecore_X_Window child_win, + int type, + void *event, + Ecore_X_Time timestamp) +{ + int i = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + for (i = 0; i < _ecore_xcb_button_grabs_num; i++) + { + if ((_ecore_xcb_button_grabs[i] == event_win) || + (_ecore_xcb_button_grabs[i] == child_win)) + { + Eina_Bool replay = EINA_FALSE; + + if (_ecore_xcb_window_grab_replay_func) + { + replay = + _ecore_xcb_window_grab_replay_func(_ecore_xcb_window_grab_replay_data, + type, event); + } + if (replay) + { + xcb_allow_events(_ecore_xcb_conn, + XCB_ALLOW_REPLAY_POINTER, timestamp); + } + else + { + xcb_allow_events(_ecore_xcb_conn, + XCB_ALLOW_ASYNC_POINTER, timestamp); + } + break; + } + } +} + +static int +_ecore_xcb_window_modifiers_get(unsigned int state) +{ + int xmodifiers = 0; + + if (state & ECORE_EVENT_MODIFIER_SHIFT) + xmodifiers |= ECORE_X_MODIFIER_SHIFT; + if (state & ECORE_EVENT_MODIFIER_CTRL) + xmodifiers |= ECORE_X_MODIFIER_CTRL; + if (state & ECORE_EVENT_MODIFIER_ALT) + xmodifiers |= ECORE_X_MODIFIER_ALT; + if (state & ECORE_EVENT_MODIFIER_WIN) + xmodifiers |= ECORE_X_MODIFIER_WIN; + if (state & ECORE_EVENT_MODIFIER_ALTGR) + xmodifiers |= ECORE_X_MODIFIER_ALTGR; + if (state & ECORE_EVENT_LOCK_SCROLL) + xmodifiers |= ECORE_X_LOCK_SCROLL; + if (state & ECORE_EVENT_LOCK_NUM) + xmodifiers |= ECORE_X_LOCK_NUM; + if (state & ECORE_EVENT_LOCK_CAPS) + xmodifiers |= ECORE_X_LOCK_CAPS; + if (state & ECORE_EVENT_LOCK_SHIFT) + xmodifiers |= ECORE_X_LOCK_SHIFT; + + return xmodifiers; +} + +static xcb_visualtype_t * +_ecore_xcb_window_find_visual_by_id(xcb_visualid_t id) +{ + xcb_depth_iterator_t diter; + xcb_visualtype_iterator_t viter; + + CHECK_XCB_CONN; + diter = xcb_screen_allowed_depths_iterator(_ecore_xcb_screen); + for (; diter.rem; xcb_depth_next(&diter)) + { + viter = xcb_depth_visuals_iterator(diter.data); + for (; viter.rem; xcb_visualtype_next(&viter)) + { + if (viter.data->visual_id == id) + return viter.data; + } + } + return 0; +} + +#ifdef ECORE_XCB_XPRINT +static xcb_screen_t * +_ecore_xcb_window_screen_of_display(int screen) +{ + xcb_screen_iterator_t iter; + + CHECK_XCB_CONN; + iter = xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)); + for (; iter.rem; --screen, xcb_screen_next(&iter)) + if (screen == 0) + return iter.data; + + return NULL; +} + +#endif diff --git a/src/lib/ecore_x/xcb/ecore_xcb_window_prop.c b/src/lib/ecore_x/xcb/ecore_xcb_window_prop.c new file mode 100644 index 0000000..e00fdc1 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_window_prop.c @@ -0,0 +1,720 @@ +#include "ecore_xcb_private.h" +#include + +EAPI int +ecore_x_window_prop_card32_get(Ecore_X_Window win, + Ecore_X_Atom atom, + unsigned int *val, + unsigned int len) +{ + xcb_get_property_cookie_t cookie; + xcb_get_property_reply_t *reply; + int num = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, win, atom, + ECORE_X_ATOM_CARDINAL, 0, 0x7fffffff); + reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return -1; + + if ((reply->type != ECORE_X_ATOM_CARDINAL) || (reply->format != 32)) + num = -1; + else if (reply->value_len == 0) + num = 0; + else + { + if (reply->value_len < len) + len = reply->value_len; + + if (val) + { + unsigned int i = 0; + unsigned char *v; + + v = xcb_get_property_value(reply); + for (i = 0; i < len; i++) + val[i] = ((uint32_t *)v)[i]; + num = len; + } + } + + if (reply) free(reply); + return num; +} + +EAPI void +ecore_x_window_prop_card32_set(Ecore_X_Window win, + Ecore_X_Atom atom, + unsigned int *val, + unsigned int num) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#if SIZEOF_INT == SIZEOF_LONG + xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, atom, + ECORE_X_ATOM_CARDINAL, 32, num, (unsigned char *)val); +// ecore_x_flush(); +#else + long *v2; + unsigned int i; + + v2 = malloc(num * sizeof(long)); + if (!v2) return; + for (i = 0; i < num; i++) + v2[i] = val[i]; + + xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, atom, + ECORE_X_ATOM_CARDINAL, 32, num, (unsigned char *)v2); + free(v2); +// ecore_x_flush(); +#endif +} + +EAPI int +ecore_x_window_prop_card32_list_get(Ecore_X_Window win, + Ecore_X_Atom atom, + unsigned int **list) +{ + xcb_get_property_cookie_t cookie; + xcb_get_property_reply_t *reply; + int num = -1; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (list) *list = NULL; + + cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, win, atom, + XCB_ATOM_CARDINAL, 0, 0x7fffffff); + reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return -1; + + if ((reply->type != XCB_ATOM_CARDINAL) || (reply->format != 32)) + num = -1; + else if ((reply->value_len == 0) || (!xcb_get_property_value(reply))) + num = 0; + else + { + num = reply->value_len; + if (list) + { + unsigned int *val; + void *data; + int i = 0; + + val = malloc(num * sizeof(unsigned int)); + if (!val) + { + free(reply); + return -1; + } + data = xcb_get_property_value(reply); + for (i = 0; i < num; i++) + val[i] = ((uint32_t *)data)[i]; + *list = val; + } + } + + free(reply); + return num; +} + +EAPI int +ecore_x_window_prop_atom_get(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Atom *list, + unsigned int len) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return ecore_x_window_prop_xid_get(win, atom, ECORE_X_ATOM_ATOM, list, len); +} + +EAPI void +ecore_x_window_prop_atom_set(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Atom *list, + unsigned int num) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + /* xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, atom, */ + /* ECORE_X_ATOM_ATOM, 32, num, list); */ + ecore_x_window_prop_xid_set(win, atom, ECORE_X_ATOM_ATOM, list, num); +} + +EAPI void +ecore_x_window_prop_xid_set(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Atom type, + Ecore_X_ID *xids, + unsigned int num) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#if SIZEOF_INT == SIZEOF_LONG + xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, atom, + type, 32, num, (unsigned char *)xids); +// ecore_x_flush(); +#else + long *v2; + unsigned int i; + + v2 = malloc(num * sizeof(long)); + if (!v2) return; + for (i = 0; i < num; i++) + v2[i] = xids[i]; + + xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, atom, + type, 32, num, (unsigned char *)v2); + free(v2); +// ecore_x_flush(); +#endif +} + +EAPI int +ecore_x_window_prop_xid_get(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Atom type, + Ecore_X_ID *xids, + unsigned int len) +{ + xcb_get_property_cookie_t cookie; + xcb_get_property_reply_t *reply; + int num = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + num = len; + cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, win, atom, type, + 0, 0x7fffffff); + reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return -1; + + if ((reply->type != type) || (reply->format != 32)) + num = -1; + else if (reply->value_len == 0) + num = 0; + else + { + unsigned int i = 0; + unsigned char *v; + + if (reply->value_len < len) + len = reply->value_len; + + v = xcb_get_property_value(reply); + for (i = 0; i < len; i++) + xids[i] = ((uint32_t *)v)[i]; + + num = len; + } + + if (reply) free(reply); + return num; +} + +EAPI void +ecore_x_window_prop_string_set(Ecore_X_Window win, + Ecore_X_Atom type, + const char *str) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, type, + ECORE_X_ATOM_UTF8_STRING, 8, strlen(str), str); +// ecore_x_flush(); +} + +EAPI char * +ecore_x_window_prop_string_get(Ecore_X_Window win, + Ecore_X_Atom type) +{ + xcb_get_property_cookie_t cookie; + xcb_get_property_reply_t *reply; + char *str = NULL; + int len = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + cookie = + xcb_get_property_unchecked(_ecore_xcb_conn, 0, + win ? win : ((xcb_screen_t *)_ecore_xcb_screen)->root, + type, XCB_GET_PROPERTY_TYPE_ANY, 0, 1000000L); + reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return NULL; + + len = ((reply->value_len * reply->format) / 8); + str = (char *)malloc((len + 1) * sizeof(char)); + memcpy(str, xcb_get_property_value(reply), len); + str[len] = '\0'; + + if (reply->type != ECORE_X_ATOM_UTF8_STRING) + { + Ecore_Xcb_Textproperty prop; + int count = 0; + char **list = NULL; + Eina_Bool ret = EINA_FALSE; + + prop.value = strdup(str); + prop.nitems = len; + prop.encoding = reply->type; + +#ifdef HAVE_ICONV + ret = _ecore_xcb_utf8_textproperty_to_textlist(&prop, &list, &count); +#else + ret = _ecore_xcb_mb_textproperty_to_textlist(&prop, &list, &count); +#endif + if (ret) + { + if (count > 0) + str = strdup(list[0]); + else + str = strdup((char *)prop.value); + + if (list) free(list); + } + else + str = strdup((char *)prop.value); + } + + free(reply); + return str; +} + +EAPI int +ecore_x_window_prop_window_get(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Window *list, + unsigned int len) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return ecore_x_window_prop_xid_get(win, atom, ECORE_X_ATOM_WINDOW, list, len); +} + +EAPI void +ecore_x_window_prop_window_set(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Window *list, + unsigned int num) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_xid_set(win, atom, ECORE_X_ATOM_WINDOW, list, num); +} + +EAPI int +ecore_x_window_prop_window_list_get(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Window **plst) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return ecore_x_window_prop_xid_list_get(win, atom, ECORE_X_ATOM_WINDOW, plst); +} + +EAPI Ecore_X_Atom +ecore_x_window_prop_any_type(void) +{ + return XCB_ATOM_ANY; +} + +EAPI void +ecore_x_window_prop_property_del(Ecore_X_Window win, + Ecore_X_Atom property) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_delete_property(_ecore_xcb_conn, win, property); +} + +EAPI void +ecore_x_window_prop_property_set(Ecore_X_Window win, + Ecore_X_Atom property, + Ecore_X_Atom type, + int size, + void *data, + int num) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (win == 0) + win = ((xcb_screen_t *)_ecore_xcb_screen)->root; + + if (size != 32) + { + xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, + property, type, size, num, (unsigned char *)data); +// ecore_x_flush(); + } + else + { + uint32_t *dat; + int i = 0, *ptr; + + dat = malloc(sizeof(uint32_t) * num); + if (dat) + { + for (ptr = (int *)data, i = 0; i < num; i++) + dat[i] = ptr[i]; + xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, + property, type, size, num, + (unsigned char *)dat); + free(dat); +// ecore_x_flush(); + } + } +} + +EAPI int +ecore_x_window_prop_property_get(Ecore_X_Window win, + Ecore_X_Atom property, + Ecore_X_Atom type, + int size, + unsigned char **data, + int *num) +{ + xcb_get_property_cookie_t cookie; + xcb_get_property_reply_t *reply; + int format = 0; + unsigned int i = 0; + void *value; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (num) *num = 0; + + if (data) + *data = NULL; + else + return 0; + + if (win == 0) + win = ((xcb_screen_t *)_ecore_xcb_screen)->root; + + cookie = + xcb_get_property_unchecked(_ecore_xcb_conn, 0, win, + property, type, 0, UINT_MAX); + reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return 0; + if ((reply->format != size) || (reply->value_len == 0)) + { + free(reply); + return 0; + } + + if (!(*data = malloc(reply->value_len * reply->format / 8))) + { + free(reply); + return 0; + } + + value = xcb_get_property_value(reply); + switch (reply->format) + { + case 8: + for (i = 0; i < reply->value_len; i++) + (*data)[i] = ((unsigned char *)value)[i]; + break; + + case 16: + for (i = 0; i < reply->value_len; i++) + ((unsigned short *)*data)[i] = ((unsigned short *)value)[i]; + break; + + case 32: + for (i = 0; i < reply->value_len; i++) + ((unsigned int *)*data)[i] = ((uint32_t *)value)[i]; + break; + } + + if (num) *num = reply->value_len; + format = reply->format; + free(reply); + return format; +} + +EAPI int +ecore_x_window_prop_atom_list_get(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Atom **list) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return ecore_x_window_prop_xid_list_get(win, atom, ECORE_X_ATOM_ATOM, list); +} + +EAPI void +ecore_x_window_prop_atom_list_change(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Atom item, + int op) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_xid_list_change(win, atom, ECORE_X_ATOM_ATOM, item, op); +} + +EAPI int +ecore_x_window_prop_xid_list_get(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Atom type, + Ecore_X_ID **xids) +{ + xcb_get_property_cookie_t cookie; + xcb_get_property_reply_t *reply; + int num = -1; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (xids) *xids = NULL; + + cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, win, atom, type, + 0, 0x7fffffff); + reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return -1; + + if ((reply->type != type) || (reply->format != 32)) + num = -1; + else if ((reply->value_len == 0) || (!xcb_get_property_value(reply))) + num = 0; + else + { + Ecore_X_Atom *alst; + void *val; + + num = xcb_get_property_value_length(reply); + val = xcb_get_property_value(reply); + alst = malloc(num * sizeof(Ecore_X_ID)); + if (alst) + { + int i = 0; + + for (i = 0; i < num; i++) + alst[i] = ((uint32_t *)val)[i]; + *xids = alst; + } + } + + free(reply); + return num; +} + +EAPI void +ecore_x_window_prop_xid_list_change(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Atom type, + Ecore_X_ID item, + int op) +{ + Ecore_X_ID *lst; + int i = 0, num = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + num = ecore_x_window_prop_xid_list_get(win, atom, type, &lst); + if (num < 0) return; + + for (i = 0; i < num; i++) + { + if (lst[i] == item) break; + } + + if (i < num) + { + if (op == ECORE_X_PROP_LIST_ADD) + goto done; + num--; + for (; i < num; i++) + lst[i] = lst[i + 1]; + } + else + { + if (op == ECORE_X_PROP_LIST_REMOVE) + goto done; + num++; + lst = realloc(lst, num * sizeof(Ecore_X_ID)); + lst[i] = item; + } + ecore_x_window_prop_xid_set(win, atom, type, lst, num); + +done: + if (lst) free(lst); +} + +EAPI Eina_Bool +ecore_x_window_prop_protocol_isset(Ecore_X_Window win, + Ecore_X_WM_Protocol protocol) +{ + Eina_Bool ret = EINA_FALSE; + Ecore_X_Atom proto; +#ifdef OLD_XCB_VERSION + xcb_get_wm_protocols_reply_t protos; +#else + xcb_icccm_get_wm_protocols_reply_t protos; +#endif + xcb_get_property_cookie_t cookie; + uint8_t reply; + uint32_t count = 0, i = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (protocol >= ECORE_X_WM_PROTOCOL_NUM) return EINA_FALSE; + + proto = _ecore_xcb_atoms_wm_protocol[protocol]; +#ifdef OLD_XCB_VERSION + cookie = xcb_get_wm_protocols_unchecked(_ecore_xcb_conn, win, + ECORE_X_ATOM_WM_PROTOCOLS); + reply = xcb_get_wm_protocols_reply(_ecore_xcb_conn, cookie, &protos, NULL); +#else + cookie = xcb_icccm_get_wm_protocols_unchecked(_ecore_xcb_conn, win, + ECORE_X_ATOM_WM_PROTOCOLS); + reply = xcb_icccm_get_wm_protocols_reply(_ecore_xcb_conn, cookie, + &protos, NULL); +#endif + if (!reply) return EINA_FALSE; + + count = protos.atoms_len; + for (i = 0; i < count; i++) + { + if (protos.atoms[i] == proto) + { + ret = EINA_TRUE; + break; + } + } + +#ifdef OLD_XCB_VERSION + xcb_get_wm_protocols_reply_wipe(&protos); +#else + xcb_icccm_get_wm_protocols_reply_wipe(&protos); +#endif + return ret; +} + +EAPI Ecore_X_WM_Protocol * +ecore_x_window_prop_protocol_list_get(Ecore_X_Window win, + int *num_ret) +{ +#ifdef OLD_XCB_VERSION + xcb_get_wm_protocols_reply_t protos; +#else + xcb_icccm_get_wm_protocols_reply_t protos; +#endif + xcb_get_property_cookie_t cookie; + uint8_t reply; + uint32_t count = 0, i = 0; + Ecore_X_WM_Protocol *prot_ret = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!num_ret) return NULL; + + *num_ret = 0; + +#ifdef OLD_XCB_VERSION + cookie = xcb_get_wm_protocols_unchecked(_ecore_xcb_conn, win, + ECORE_X_ATOM_WM_PROTOCOLS); + reply = xcb_get_wm_protocols_reply(_ecore_xcb_conn, cookie, &protos, NULL); +#else + cookie = xcb_icccm_get_wm_protocols_unchecked(_ecore_xcb_conn, win, + ECORE_X_ATOM_WM_PROTOCOLS); + reply = xcb_icccm_get_wm_protocols_reply(_ecore_xcb_conn, cookie, + &protos, NULL); +#endif + if (!reply) return NULL; + + count = protos.atoms_len; + if (count <= 0) + { +#ifdef OLD_XCB_VERSION + xcb_get_wm_protocols_reply_wipe(&protos); +#else + xcb_icccm_get_wm_protocols_reply_wipe(&protos); +#endif + return NULL; + } + + prot_ret = calloc(1, count * sizeof(Ecore_X_WM_Protocol)); + if (!prot_ret) + { +#ifdef OLD_XCB_VERSION + xcb_get_wm_protocols_reply_wipe(&protos); +#else + xcb_icccm_get_wm_protocols_reply_wipe(&protos); +#endif + return NULL; + } + + for (i = 0; i < count; i++) + { + Ecore_X_WM_Protocol j; + + prot_ret[i] = -1; + for (j = 0; j < ECORE_X_WM_PROTOCOL_NUM; j++) + { + if (_ecore_xcb_atoms_wm_protocol[j] == protos.atoms[i]) + prot_ret[i] = j; + } + } + + if (num_ret) *num_ret = count; + +#ifdef OLD_XCB_VERSION + xcb_get_wm_protocols_reply_wipe(&protos); +#else + xcb_icccm_get_wm_protocols_reply_wipe(&protos); +#endif + return prot_ret; +} + +EAPI Ecore_X_Atom * +ecore_x_window_prop_list(Ecore_X_Window win, + int *num) +{ + xcb_list_properties_cookie_t cookie; + xcb_list_properties_reply_t *reply; + xcb_atom_t *atm; + Ecore_X_Atom *atoms; + int i = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (num) *num = 0; + + cookie = xcb_list_properties_unchecked(_ecore_xcb_conn, win); + reply = xcb_list_properties_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return NULL; + + atoms = (Ecore_X_Atom *)malloc(reply->atoms_len * sizeof(Ecore_X_Atom)); + if (!atoms) + { + free(reply); + return NULL; + } + + atm = xcb_list_properties_atoms(reply); + for (i = 0; i < reply->atoms_len; i++) + atoms[i] = atm[i]; + + if (num) *num = reply->atoms_len; + free(reply); + + return atoms; +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_window_shadow.c b/src/lib/ecore_x/xcb/ecore_xcb_window_shadow.c new file mode 100644 index 0000000..82326fa --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_window_shadow.c @@ -0,0 +1,410 @@ +#include "ecore_xcb_private.h" + +typedef struct _Shadow Shadow; +struct _Shadow +{ + Shadow *parent, **children; + Ecore_X_Window win; + int children_num; + short x, y; + unsigned short w, h; +}; + +static Eina_Bool _inside_rects(Shadow *s, + int x, + int y, + int bx, + int by, + Ecore_X_Rectangle *rects, + int num); + +//static int shadow_count = 0; +static Shadow **shadow_base = NULL; +static int shadow_num = 0; + +/* FIXME: round trips */ +static Shadow * +_ecore_x_window_tree_walk(Ecore_X_Window window) +{ + Shadow *s, **sl; + xcb_get_window_attributes_reply_t *reply_attr; + xcb_get_geometry_reply_t *reply_geom; + xcb_query_tree_reply_t *reply_tree; + xcb_get_window_attributes_cookie_t cookie_attr; + xcb_get_geometry_cookie_t cookie_geom; + xcb_query_tree_cookie_t cookie_tree; + int i, j; + + CHECK_XCB_CONN; + + cookie_attr = xcb_get_window_attributes_unchecked(_ecore_xcb_conn, window); + reply_attr = xcb_get_window_attributes_reply(_ecore_xcb_conn, cookie_attr, NULL); + if (!reply_attr) return NULL; + if (reply_attr->map_state != XCB_MAP_STATE_VIEWABLE) + { + free(reply_attr); + return NULL; + } + + free(reply_attr); + + cookie_geom = xcb_get_geometry_unchecked(_ecore_xcb_conn, window); + reply_geom = xcb_get_geometry_reply(_ecore_xcb_conn, cookie_geom, NULL); + if (!reply_geom) return NULL; + + if (!(s = calloc(1, sizeof(Shadow)))) + { + free(reply_geom); + return NULL; + } + + s->win = window; + s->x = reply_geom->x; + s->y = reply_geom->y; + s->w = reply_geom->width; + s->h = reply_geom->height; + + free(reply_geom); + + cookie_tree = xcb_query_tree_unchecked(_ecore_xcb_conn, window); + reply_tree = xcb_query_tree_reply(_ecore_xcb_conn, cookie_tree, NULL); + if (reply_tree) + { + xcb_window_t *list; + int num; + + num = xcb_query_tree_children_length(reply_tree); + list = xcb_query_tree_children(reply_tree); + + s->children = calloc(1, sizeof(Shadow *) * num); + if (s->children) + { + s->children_num = num; + for (i = 0; i < num; i++) + { + s->children[i] = _ecore_x_window_tree_walk(list[i]); + if (s->children[i]) + s->children[i]->parent = s; + } + /* compress list down */ + j = 0; + for (i = 0; i < num; i++) + { + if (s->children[i]) + { + s->children[j] = s->children[i]; + j++; + } + } + if (j == 0) + { + free(s->children); + s->children = NULL; + s->children_num = 0; + } + else + { + s->children_num = j; + sl = realloc(s->children, sizeof(Shadow *) * j); + if (sl) s->children = sl; + } + } + + free(reply_tree); + } + + return s; +} + +static void +_ecore_x_window_tree_shadow_free1(Shadow *s) +{ + int i = 0; + + if (!s) return; + if (s->children) + { + for (i = 0; i < s->children_num; i++) + { + if (s->children[i]) + _ecore_x_window_tree_shadow_free1(s->children[i]); + } + free(s->children); + } + + free(s); +} + +static void +_ecore_x_window_tree_shadow_free(void) +{ + int i = 0; + + if (!shadow_base) return; + + for (i = 0; i < shadow_num; i++) + { + if (!shadow_base[i]) continue; + _ecore_x_window_tree_shadow_free1(shadow_base[i]); + } + free(shadow_base); + shadow_base = NULL; + shadow_num = 0; +} + +static void +_ecore_x_window_tree_shadow_populate(void) +{ + Ecore_X_Window *roots = NULL; + int i = 0, num = 0; + + if ((roots = ecore_x_window_root_list(&num))) + { + shadow_base = calloc(1, sizeof(Shadow *) * num); + if (shadow_base) + { + shadow_num = num; + for (i = 0; i < num; i++) + shadow_base[i] = _ecore_x_window_tree_walk(roots[i]); + } + + free(roots); + } +} + +/* + static void + _ecore_x_window_tree_shadow_start(void) + { + shadow_count++; + if (shadow_count > 1) return; + _ecore_x_window_tree_shadow_populate(); + } + + static void + _ecore_x_window_tree_shadow_stop(void) + { + shadow_count--; + if (shadow_count != 0) return; + _ecore_x_window_tree_shadow_free(); + } + */ + +Shadow * +_ecore_x_window_shadow_tree_find_shadow(Shadow *s, + Ecore_X_Window win) +{ + Shadow *ss; + int i = 0; + + if (s->win == win) return s; + + if (s->children) + { + for (i = 0; i < s->children_num; i++) + { + if (!s->children[i]) continue; + + if ((ss = + _ecore_x_window_shadow_tree_find_shadow(s->children[i], win))) + return ss; + } + } + + return NULL; +} + +Shadow * +_ecore_x_window_shadow_tree_find(Ecore_X_Window base) +{ + Shadow *s; + int i = 0; + + for (i = 0; i < shadow_num; i++) + { + if (!shadow_base[i]) continue; + + if ((s = + _ecore_x_window_shadow_tree_find_shadow(shadow_base[i], base))) + return s; + } + return NULL; +} + +static Ecore_X_Window +_ecore_x_window_shadow_tree_at_xy_get_shadow(Shadow *s, + int bx, + int by, + int x, + int y, + Ecore_X_Window *skip, + int skip_num) +{ + Ecore_X_Window child; + Ecore_X_Rectangle *rects; + int i = 0, j = 0, wx = 0, wy = 0, num = 0; + + wx = s->x + bx; + wy = s->y + by; + if (!((x >= wx) && (y >= wy) && (x < (wx + s->w)) && (y < (wy + s->h)))) + return 0; + + rects = ecore_x_window_shape_rectangles_get(s->win, &num); + if (!_inside_rects(s, x, y, bx, by, rects, num)) return 0; + num = 0; + rects = ecore_x_window_shape_input_rectangles_get(s->win, &num); + if (!_inside_rects(s, x, y, bx, by, rects, num)) return 0; + + if (s->children) + { + int skipit = 0; + + for (i = s->children_num - 1; i >= 0; --i) + { + if (!s->children[i]) continue; + + skipit = 0; + if (skip) + { + for (j = 0; j < skip_num; j++) + { + if (s->children[i]->win == skip[j]) + { + skipit = 1; + goto onward; + } + } + } +onward: + if (!skipit) + { + if ((child = + _ecore_x_window_shadow_tree_at_xy_get_shadow(s->children[i], wx, wy, x, y, skip, skip_num))) + return child; + } + } + } + + return s->win; +} + +static Ecore_X_Window +_ecore_x_window_shadow_tree_at_xy_get(Ecore_X_Window base, + int bx, + int by, + int x, + int y, + Ecore_X_Window *skip, + int skip_num) +{ + Shadow *s; + + if (!shadow_base) + { + _ecore_x_window_tree_shadow_populate(); + if (!shadow_base) return 0; + } + + s = _ecore_x_window_shadow_tree_find(base); + if (!s) return 0; + + return _ecore_x_window_shadow_tree_at_xy_get_shadow(s, bx, by, x, y, skip, skip_num); +} + +static Eina_Bool +_inside_rects(Shadow *s, + int x, + int y, + int bx, + int by, + Ecore_X_Rectangle *rects, + int num) +{ + Eina_Bool inside = EINA_FALSE; + int i = 0; + + if (!rects) return EINA_FALSE; + for (i = 0; i < num; i++) + { + if ((x >= s->x + bx + rects[i].x) && + (y >= s->y + by + rects[i].y) && + (x < (int)(s->x + bx + rects[i].x + rects[i].width)) && + (y < (int)(s->y + by + rects[i].y + rects[i].height))) + { + inside = EINA_TRUE; + break; + } + } + free(rects); + return inside; +} + +/** + * Retrieves the top, visible window at the given location, + * but skips the windows in the list. This uses a shadow tree built from the + * window tree that is only updated the first time + * ecore_x_window_shadow_tree_at_xy_with_skip_get() is called, or the next time + * it is called after a ecore_x_window_shadow_tree_flush() + * @param base The base window to start searching from (normally root). + * @param x The given X position. + * @param y The given Y position. + * @param skip The list of windows to be skipped. + * @param skip_num The number of windows to be skipped. + * @return The window at the desired position. + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI Ecore_X_Window +ecore_x_window_shadow_tree_at_xy_with_skip_get(Ecore_X_Window base, + int x, + int y, + Ecore_X_Window *skip, + int skip_num) +{ + return _ecore_x_window_shadow_tree_at_xy_get(base, 0, 0, x, y, skip, skip_num); +} + +/** + * Retrieves the parent window a given window has. This uses the shadow window + * tree. + * @param root The root window of @p win - if 0, this will be automatically determined with extra processing overhead + * @param win The window to get the parent window of + * @return The parent window of @p win + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI Ecore_X_Window +ecore_x_window_shadow_parent_get(Ecore_X_Window root __UNUSED__, + Ecore_X_Window win) +{ + Shadow *s; + int i = 0; + + if (!shadow_base) + { + _ecore_x_window_tree_shadow_populate(); + if (!shadow_base) return 0; + } + + for (i = 0; i < shadow_num; i++) + { + if (!shadow_base[i]) continue; + + s = _ecore_x_window_shadow_tree_find_shadow(shadow_base[i], win); + if (s) + { + if (!s->parent) return 0; + return s->parent->win; + } + } + return 0; +} + +/** + * Flushes the window shadow tree so nothing is stored. + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI void +ecore_x_window_shadow_tree_flush(void) +{ + _ecore_x_window_tree_shadow_free(); +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_window_shape.c b/src/lib/ecore_x/xcb/ecore_xcb_window_shape.c new file mode 100644 index 0000000..6206a51 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_window_shape.c @@ -0,0 +1,790 @@ +#include "ecore_xcb_private.h" +#ifdef ECORE_XCB_SHAPE +# include +#endif + +/** + * @defgroup Ecore_X_Window_Shape X Window Shape Functions + * + * These functions use the shape extension of the X server to change + * shape of given windows. + */ + +/** + * Sets the input shape of the given window to that given by the pixmap @p mask. + * @param win The given window. + * @param mask A 1-bit depth pixmap that provides the new input shape of the + * window. + * @ingroup Ecore_X_Window_Shape + */ +EAPI void +ecore_x_window_shape_input_mask_set(Ecore_X_Window win, + Ecore_X_Pixmap mask) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_SHAPE + xcb_shape_mask(_ecore_xcb_conn, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, + win, 0, 0, mask); +// ecore_x_flush(); +#else + return; + win = 0; + mask = 0; +#endif +} + +/** + * Sets the shape of the given window to that given by the pixmap @p mask. + * @param win The given window. + * @param mask A 2-bit depth pixmap that provides the new shape of the + * window. + * @ingroup Ecore_X_Window_Shape + */ +EAPI void +ecore_x_window_shape_mask_set(Ecore_X_Window win, + Ecore_X_Pixmap mask) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_SHAPE + xcb_shape_mask(_ecore_xcb_conn, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, + win, 0, 0, mask); +// ecore_x_flush(); +#else + return; + win = 0; + mask = 0; +#endif +} + +EAPI void +ecore_x_window_shape_window_set(Ecore_X_Window win, + Ecore_X_Window shape_win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_SHAPE + xcb_shape_combine(_ecore_xcb_conn, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, + XCB_SHAPE_SK_BOUNDING, win, 0, 0, shape_win); +// ecore_x_flush(); +#else + return; + win = 0; + shape_win = 0; +#endif +} + +EAPI void +ecore_x_window_shape_window_set_xy(Ecore_X_Window win, + Ecore_X_Window shape_win, + int x, + int y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_SHAPE + xcb_shape_combine(_ecore_xcb_conn, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, + XCB_SHAPE_SK_BOUNDING, win, x, y, shape_win); +// ecore_x_flush(); +#else + return; + win = 0; + shape_win = 0; + x = 0; + y = 0; +#endif +} + +EAPI void +ecore_x_window_shape_rectangle_set(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ +#ifdef ECORE_XCB_SHAPE + xcb_rectangle_t rect; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_SHAPE + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_SET, + XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED, + win, 0, 0, 1, &rect); +// ecore_x_flush(); +#else + return; + win = 0; + x = 0; + y = 0; + w = 0; + h = 0; +#endif +} + +EAPI void +ecore_x_window_shape_rectangles_set(Ecore_X_Window win, + Ecore_X_Rectangle *rects, + int num) +{ +#ifdef ECORE_XCB_SHAPE + xcb_rectangle_t *rect = NULL; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!rects) return; + +#ifdef ECORE_XCB_SHAPE + if (num > 0) + { + int i = 0; + + if (!(rect = malloc(sizeof(xcb_rectangle_t) * num))) + return; + + for (i = 0; i < num; i++) + { + rect[i].x = rects[i].x; + rect[i].y = rects[i].y; + rect[i].width = rects[i].width; + rect[i].height = rects[i].height; + } + } + xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_SET, + XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED, + win, 0, 0, num, (xcb_rectangle_t *)rect); + + if (rect) free(rect); +// ecore_x_flush(); +#else + return; + win = 0; + num = 0; + rects = NULL; +#endif +} + +EAPI void +ecore_x_window_shape_window_add(Ecore_X_Window win, + Ecore_X_Window shape_win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_SHAPE + xcb_shape_combine(_ecore_xcb_conn, XCB_SHAPE_SO_UNION, + XCB_SHAPE_SK_BOUNDING, XCB_SHAPE_SK_BOUNDING, + win, 0, 0, shape_win); +// ecore_x_flush(); +#else + return; + win = 0; + shape_win = 0; +#endif +} + +EAPI void +ecore_x_window_shape_window_add_xy(Ecore_X_Window win, + Ecore_X_Window shape_win, + int x, + int y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_SHAPE + xcb_shape_combine(_ecore_xcb_conn, XCB_SHAPE_SO_UNION, + XCB_SHAPE_SK_BOUNDING, XCB_SHAPE_SK_BOUNDING, + win, x, y, shape_win); +// ecore_x_flush(); +#else + return; + win = 0; + shape_win = 0; + x = 0; + y = 0; +#endif +} + +EAPI void +ecore_x_window_shape_rectangle_add(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ +#ifdef ECORE_XCB_SHAPE + xcb_rectangle_t rect; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_SHAPE + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_UNION, + XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED, + win, 0, 0, 1, &rect); +// ecore_x_flush(); +#else + return; + win = 0; + x = 0; + y = 0; + w = 0; + h = 0; +#endif +} + +EAPI void +ecore_x_window_shape_rectangle_subtract(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ +#ifdef ECORE_XCB_SHAPE + xcb_rectangle_t rect; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_SHAPE + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_SUBTRACT, + XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED, + win, 0, 0, 1, &rect); +// ecore_x_flush(); +#else + return; + win = 0; + x = 0; + y = 0; + w = 0; + h = 0; +#endif +} + +EAPI void +ecore_x_window_shape_rectangle_clip(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ +#ifdef ECORE_XCB_SHAPE + xcb_rectangle_t rect; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_SHAPE + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_INTERSECT, + XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED, + win, 0, 0, 1, &rect); +// ecore_x_flush(); +#else + return; + win = 0; + x = 0; + y = 0; + w = 0; + h = 0; +#endif +} + +EAPI void +ecore_x_window_shape_rectangles_add(Ecore_X_Window win, + Ecore_X_Rectangle *rects, + int num) +{ +#ifdef ECORE_XCB_SHAPE + xcb_rectangle_t *rect = NULL; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_SHAPE + if (num > 0) + { + int i = 0; + + if (!(rect = malloc(sizeof(xcb_rectangle_t) * num))) + return; + + for (i = 0; i < num; i++) + { + rect[i].x = rects[i].x; + rect[i].y = rects[i].y; + rect[i].width = rects[i].width; + rect[i].height = rects[i].height; + } + } + + xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_UNION, + XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED, + win, 0, 0, num, (xcb_rectangle_t *)&rect); + + if (rect) free(rect); +// ecore_x_flush(); +#else + return; + win = 0; + num = 0; + rects = NULL; +#endif +} + +EAPI Ecore_X_Rectangle * +ecore_x_window_shape_rectangles_get(Ecore_X_Window win, + int *num_ret) +{ + Ecore_X_Rectangle *rects = NULL; +#ifdef ECORE_XCB_SHAPE + xcb_shape_get_rectangles_cookie_t cookie; + xcb_shape_get_rectangles_reply_t *reply; + xcb_rectangle_t *r; + unsigned int i = 0; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (num_ret) *num_ret = 0; + +#ifdef ECORE_XCB_SHAPE + cookie = + xcb_shape_get_rectangles(_ecore_xcb_conn, win, XCB_SHAPE_SK_BOUNDING); + reply = xcb_shape_get_rectangles_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return NULL; + if (num_ret) *num_ret = reply->rectangles_len; + + if (reply->rectangles_len < 1) + { + free(reply); + if (num_ret) *num_ret = 0; + return NULL; + } + + rects = malloc(sizeof(Ecore_X_Rectangle) * reply->rectangles_len); + if (!rects) + { + free(reply); + if (num_ret) *num_ret = 0; + return NULL; + } + r = xcb_shape_get_rectangles_rectangles(reply); + for (i = 0; i < reply->rectangles_len; i++) + { + rects[i].x = r[i].x; + rects[i].y = r[i].y; + rects[i].width = r[i].width; + rects[i].height = r[i].height; + } + + free(reply); + + return rects; +#else + return rects; + win = 0; +#endif +} + +EAPI void +ecore_x_window_shape_events_select(Ecore_X_Window win, + Eina_Bool on) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_SHAPE + xcb_shape_select_input(_ecore_xcb_conn, win, on); +// ecore_x_flush(); +#else + return; + win = 0; + on = 0; +#endif +} + +EAPI Ecore_X_Rectangle * +ecore_x_window_shape_input_rectangles_get(Ecore_X_Window win, + int *num_ret) +{ + Ecore_X_Rectangle *rects = NULL; +#ifdef ECORE_XCB_SHAPE + xcb_shape_get_rectangles_cookie_t cookie; + xcb_shape_get_rectangles_reply_t *reply; + xcb_rectangle_t *r; + unsigned int i = 0; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (num_ret) *num_ret = 0; + +#ifdef ECORE_XCB_SHAPE + cookie = + xcb_shape_get_rectangles(_ecore_xcb_conn, win, XCB_SHAPE_SK_INPUT); + reply = xcb_shape_get_rectangles_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return NULL; + if (num_ret) *num_ret = reply->rectangles_len; + + if (reply->rectangles_len < 1) + { + free(reply); + if (num_ret) *num_ret = 0; + return NULL; + } + + rects = malloc(sizeof(Ecore_X_Rectangle) * reply->rectangles_len); + if (!rects) + { + free(reply); + if (num_ret) *num_ret = 0; + return NULL; + } + r = xcb_shape_get_rectangles_rectangles(reply); + for (i = 0; i < reply->rectangles_len; i++) + { + rects[i].x = r[i].x; + rects[i].y = r[i].y; + rects[i].width = r[i].width; + rects[i].height = r[i].height; + } + + free(reply); + + return rects; +#else + xcb_get_geometry_cookie_t cookie; + xcb_get_geometry_reply_t *reply; + + if (!(rects = malloc(sizeof(Ecore_X_Rectangle)))) + return NULL; + + /* get geometry */ + cookie = xcb_get_geometry_unchecked(_ecore_xcb_conn, win); + reply = xcb_get_geometry_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + rects[0].x = reply->x; + rects[0].y = reply->y; + rects[0].width = reply->width; + rects[0].height = reply->height; + free(reply); + } + if (num_ret) *num_ret = 1; + return rects; +#endif +} + +EAPI void +ecore_x_window_shape_input_rectangles_set(Ecore_X_Window win, + Ecore_X_Rectangle *rects, + int num) +{ +#ifdef ECORE_XCB_SHAPE + xcb_rectangle_t *rect = NULL; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!rects) return; + +#ifdef ECORE_XCB_SHAPE + if (num > 0) + { + int i = 0; + + if (!(rect = malloc(sizeof(xcb_rectangle_t) * num))) + return; + + for (i = 0; i < num; i++) + { + rect[i].x = rects[i].x; + rect[i].y = rects[i].y; + rect[i].width = rects[i].width; + rect[i].height = rects[i].height; + } + } + xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_SET, + XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED, + win, 0, 0, num, (xcb_rectangle_t *)rect); + + if (rect) free(rect); +// ecore_x_flush(); +#else + return; + win = 0; + num = 0; + rects = NULL; +#endif +} + +EAPI void +ecore_x_window_shape_input_rectangle_subtract(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ +#ifdef ECORE_XCB_SHAPE + xcb_rectangle_t rect; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_SHAPE + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_SUBTRACT, + XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED, + win, 0, 0, 1, &rect); +// ecore_x_flush(); +#else + return; + win = 0; + x = 0; + y = 0; + w = 0; + h = 0; +#endif +} + +EAPI void +ecore_x_window_shape_input_rectangle_add(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ +#ifdef ECORE_XCB_SHAPE + xcb_rectangle_t rect; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_SHAPE + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_UNION, + XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED, + win, 0, 0, 1, &rect); +// ecore_x_flush(); +#else + return; + win = 0; + x = 0; + y = 0; + w = 0; + h = 0; +#endif +} + +EAPI void +ecore_x_window_shape_input_rectangle_set(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ +#ifdef ECORE_XCB_SHAPE + xcb_rectangle_t rect; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_SHAPE + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_SET, + XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED, + win, 0, 0, 1, &rect); +// ecore_x_flush(); +#else + return; + win = 0; + x = 0; + y = 0; + w = 0; + h = 0; +#endif +} + +EAPI void +ecore_x_window_shape_input_window_set_xy(Ecore_X_Window win, + Ecore_X_Window shape_win, + int x, + int y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_SHAPE + xcb_shape_combine(_ecore_xcb_conn, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, + XCB_SHAPE_SK_INPUT, win, x, y, shape_win); +// ecore_x_flush(); +#else + return; + win = 0; + shape_win = 0; + x = 0; + y = 0; +#endif +} + +EAPI void +ecore_x_window_shape_input_window_add_xy(Ecore_X_Window win, + Ecore_X_Window shape_win, + int x, + int y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_SHAPE + xcb_shape_combine(_ecore_xcb_conn, XCB_SHAPE_SO_UNION, XCB_SHAPE_SK_INPUT, + XCB_SHAPE_SK_INPUT, win, x, y, shape_win); +// ecore_x_flush(); +#else + return; + win = 0; + shape_win = 0; + x = 0; + y = 0; +#endif +} + +EAPI void +ecore_x_window_shape_input_window_set(Ecore_X_Window win, + Ecore_X_Window shape_win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_SHAPE + xcb_shape_combine(_ecore_xcb_conn, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, + XCB_SHAPE_SK_INPUT, win, 0, 0, shape_win); +// ecore_x_flush(); +#else + return; + win = 0; + shape_win = 0; +#endif +} + +EAPI void +ecore_x_window_shape_input_rectangle_clip(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ +#ifdef ECORE_XCB_SHAPE + xcb_rectangle_t rect; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_SHAPE + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_INTERSECT, + XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED, + win, 0, 0, 1, &rect); +// ecore_x_flush(); +#else + return; + win = 0; + x = 0; + y = 0; + w = 0; + h = 0; +#endif +} + +EAPI void +ecore_x_window_shape_input_rectangles_add(Ecore_X_Window win, + Ecore_X_Rectangle *rects, + int num) +{ +#ifdef ECORE_XCB_SHAPE + xcb_rectangle_t *rect = NULL; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_SHAPE + if (num > 0) + { + int i = 0; + + if (!(rect = malloc(sizeof(xcb_rectangle_t) * num))) + return; + + for (i = 0; i < num; i++) + { + rect[i].x = rects[i].x; + rect[i].y = rects[i].y; + rect[i].width = rects[i].width; + rect[i].height = rects[i].height; + } + } + + xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_UNION, + XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED, + win, 0, 0, num, (xcb_rectangle_t *)&rect); + + if (rect) free(rect); +// ecore_x_flush(); +#else + return; + win = 0; + num = 0; + rects = NULL; +#endif +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_xdefaults.c b/src/lib/ecore_x/xcb/ecore_xcb_xdefaults.c new file mode 100644 index 0000000..e0e5610 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_xdefaults.c @@ -0,0 +1,116 @@ +#include "ecore_xcb_private.h" +#include + +/* local function prototypes */ +static Eina_Bool _ecore_xcb_xdefaults_glob_match(const char *str, + const char *glob); + +/* local variables */ +static Eina_File *_ecore_xcb_xdefaults_file = NULL; +static char *_ecore_xcb_xdefaults_data = NULL; + +void +_ecore_xcb_xdefaults_init(void) +{ + char buff[PATH_MAX]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + snprintf(buff, sizeof(buff), "%s/.Xdefaults", getenv("HOME")); + if ((_ecore_xcb_xdefaults_file = eina_file_open(buff, EINA_FALSE))) + { + eina_mmap_safety_enabled_set(EINA_TRUE); + + _ecore_xcb_xdefaults_data = + eina_file_map_all(_ecore_xcb_xdefaults_file, EINA_FILE_SEQUENTIAL); + } +} + +void +_ecore_xcb_xdefaults_shutdown(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!_ecore_xcb_xdefaults_file) return; + if (_ecore_xcb_xdefaults_data) + eina_file_map_free(_ecore_xcb_xdefaults_file, _ecore_xcb_xdefaults_data); + if (_ecore_xcb_xdefaults_file) eina_file_close(_ecore_xcb_xdefaults_file); +} + +char * +_ecore_xcb_xdefaults_string_get(const char *prog, + const char *param) +{ + char buff[1024], ret[1024]; + char *str = NULL; + char **ea = NULL; + unsigned int count = 0, i = 0; + + if ((!_ecore_xcb_xdefaults_data) || (!_ecore_xcb_xdefaults_file)) + return NULL; + + snprintf(buff, sizeof(buff), "*%s*.*%s*", prog, param); + + str = _ecore_xcb_xdefaults_data; + ea = eina_str_split_full(str, "\n", -1, &count); + for (i = 0; i < count; i++) + { + if (_ecore_xcb_xdefaults_glob_match(ea[i], buff)) + sscanf(ea[i], "%*[^:]:%*[ ]%s", ret); + } + if ((ea) && (ea[0])) + { + free(ea[0]); + free(ea); + } + + return strdup(ret); +} + +int +_ecore_xcb_xdefaults_int_get(const char *prog, + const char *param) +{ + char buff[1024]; + char *str = NULL; + char **ea = NULL; + unsigned int count = 0, i = 0; + int ret = -1; + + if ((!_ecore_xcb_xdefaults_data) || (!_ecore_xcb_xdefaults_file)) + return 0; + + snprintf(buff, sizeof(buff), "*%s*.*%s*", prog, param); + + str = _ecore_xcb_xdefaults_data; + ea = eina_str_split_full(str, "\n", -1, &count); + for (i = 0; i < count; i++) + { + if (_ecore_xcb_xdefaults_glob_match(ea[i], buff)) + sscanf(ea[i], "%*[^:]:%*[ ]%d", &ret); + } + if ((ea) && (ea[0])) + { + free(ea[0]); + free(ea); + } + + return ret; +} + +/* local functions */ +static Eina_Bool +_ecore_xcb_xdefaults_glob_match(const char *str, + const char *glob) +{ + if ((!str) || (!glob)) return EINA_FALSE; + if (glob[0] == 0) + { + if (str[0] == 0) return EINA_TRUE; + return EINA_FALSE; + } + if (!strcmp(glob, "*")) return EINA_TRUE; + if (!fnmatch(glob, str, 0)) return EINA_TRUE; + return EINA_FALSE; +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_xfixes.c b/src/lib/ecore_x/xcb/ecore_xcb_xfixes.c new file mode 100644 index 0000000..bbca2a5 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_xfixes.c @@ -0,0 +1,750 @@ +#include "ecore_xcb_private.h" +# ifdef ECORE_XCB_XFIXES +# include +# endif + +/* local function prototypes */ +static xcb_rectangle_t *_ecore_xcb_rect_to_xcb(Ecore_X_Rectangle *rects, + int num); +static Ecore_X_Rectangle *_ecore_xcb_rect_to_ecore(xcb_rectangle_t *rects, + int num); + +/* local variables */ +static Eina_Bool _xfixes_avail = EINA_FALSE; + +/* external variables */ +int _ecore_xcb_event_xfixes = -1; + +void +_ecore_xcb_xfixes_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_XFIXES + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_xfixes_id); +#endif +} + +void +_ecore_xcb_xfixes_finalize(void) +{ +#ifdef ECORE_XCB_XFIXES + const xcb_query_extension_reply_t *ext_reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_XFIXES + ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_xfixes_id); + if ((ext_reply) && (ext_reply->present)) + { + xcb_xfixes_query_version_cookie_t cookie; + xcb_xfixes_query_version_reply_t *reply; + + cookie = + xcb_xfixes_query_version_unchecked(_ecore_xcb_conn, + XCB_XFIXES_MAJOR_VERSION, + XCB_XFIXES_MINOR_VERSION); + reply = xcb_xfixes_query_version_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + /* NB: XFixes Extension >= 3 needed for shape stuff. + * for now, I am removing this check so that it matches the + * xlib code closer. If the extension version ends up being + * that important, then re-enable this */ + + /* if (reply->major_version >= 3) */ + _xfixes_avail = EINA_TRUE; + free(reply); + } + + if (_xfixes_avail) + _ecore_xcb_event_xfixes = ext_reply->first_event; + } +#endif +} + +EAPI Eina_Bool +ecore_x_fixes_selection_notification_request(Ecore_X_Atom selection) +{ +#ifdef ECORE_XCB_XFIXES + Ecore_X_Window root = 0; + xcb_void_cookie_t cookie; + xcb_generic_error_t *err; + int mask = 0; +#endif + + CHECK_XCB_CONN; + + if (!_xfixes_avail) return EINA_FALSE; + +#ifdef ECORE_XCB_XFIXES + root = ((xcb_screen_t *)_ecore_xcb_screen)->root; + + mask = (XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER | + XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY | + XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE); + + cookie = + xcb_xfixes_select_selection_input_checked(_ecore_xcb_conn, root, + selection, mask); + err = xcb_request_check(_ecore_xcb_conn, cookie); + if (err) + { + free(err); + return EINA_FALSE; + } + + return EINA_TRUE; +#endif + return EINA_FALSE; +} + +Eina_Bool +_ecore_xcb_xfixes_avail_get(void) +{ + return _xfixes_avail; +} + +/** + * @defgroup Ecore_X_Fixes_Group X Fixes Extension Functions + * + * Functions related to the X Fixes extension. + */ + +/** + * Create a region from rectangles. + * @param rects The rectangles used to initialize the region. + * @param num The number of rectangles. + * @return The newly created region. + * + * Create a region initialized to the specified list of rectangles + * @p rects. The rectangles may be specified in any order, their union + * becomes the region. + * @ingroup Ecore_X_Fixes_Group + */ +EAPI Ecore_X_Region +ecore_x_region_new(Ecore_X_Rectangle *rects, + int num) +{ + Ecore_X_Region region = 0; +#ifdef ECORE_XCB_XFIXES + xcb_rectangle_t *xrects; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_xfixes_avail) return 0; + +#ifdef ECORE_XCB_XFIXES + xrects = _ecore_xcb_rect_to_xcb(rects, num); + region = xcb_generate_id(_ecore_xcb_conn); + xcb_xfixes_create_region(_ecore_xcb_conn, region, num, xrects); + free(xrects); +// ecore_x_flush(); +#endif + + return region; +} + +/** + * Create a region from a pixmap. + * @param bitmap The bitmap used to initialize the region. + * @return The newly created region. + * + * Creates a region initialized to the set of 'one' pixels in @p bitmap + * (which must be of depth 1, else Match error). + * @ingroup Ecore_X_Fixes_Group + */ +EAPI Ecore_X_Region +ecore_x_region_new_from_bitmap(Ecore_X_Pixmap bitmap) +{ + Ecore_X_Region region = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_xfixes_avail) return 0; + +#ifdef ECORE_XCB_XFIXES + region = xcb_generate_id(_ecore_xcb_conn); + xcb_xfixes_create_region_from_bitmap(_ecore_xcb_conn, region, bitmap); +// ecore_x_flush(); +#endif + + return region; +} + +/** + * Create a region from a window. + * @param win The window used to initialize the region. + * @param type The type of the region. + * @return The newly created region. + * + * Creates a region initialized to the specified @p window region. See + * the Shape extension for the definition of Bounding and Clip + * regions. + * @ingroup Ecore_X_Fixes_Group + */ +EAPI Ecore_X_Region +ecore_x_region_new_from_window(Ecore_X_Window win, + Ecore_X_Region_Type type) +{ + Ecore_X_Region region = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_xfixes_avail) return 0; + +#ifdef ECORE_XCB_XFIXES + region = xcb_generate_id(_ecore_xcb_conn); + xcb_xfixes_create_region_from_window(_ecore_xcb_conn, region, win, type); +// ecore_x_flush(); +#endif + + return region; +} + +/** + * Create a region from a graphic context. + * @param gc The graphic context used to initialize the region. + * @return The newly created region. + * + * Creates a region initialized from the clip list of @p gc. + * @ingroup Ecore_X_Fixes_Group + */ +EAPI Ecore_X_Region +ecore_x_region_new_from_gc(Ecore_X_GC gc) +{ + Ecore_X_Region region = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_xfixes_avail) return 0; + +#ifdef ECORE_XCB_XFIXES + region = xcb_generate_id(_ecore_xcb_conn); + xcb_xfixes_create_region_from_gc(_ecore_xcb_conn, region, gc); +// ecore_x_flush(); +#endif + + return region; +} + +/** + * Create a region from a picture. + * @param picture The picture used to initialize the region. + * @return The newly created region. + * + * Creates a region initialized from the clip list of @p picture. + * @ingroup Ecore_X_Fixes_Group + */ +EAPI Ecore_X_Region +ecore_x_region_new_from_picture(Ecore_X_Picture picture) +{ + Ecore_X_Region region = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_xfixes_avail) return 0; + +#ifdef ECORE_XCB_XFIXES + region = xcb_generate_id(_ecore_xcb_conn); + xcb_xfixes_create_region_from_picture(_ecore_xcb_conn, region, picture); +// ecore_x_flush(); +#endif + + return region; +} + +/** + * Destroy a region. + * @param region The region to destroy. + * + * Destroy the specified @p region. + * @ingroup Ecore_X_Fixes_Group + */ +EAPI void +ecore_x_region_free(Ecore_X_Region region) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_xfixes_avail) return; + +#ifdef ECORE_XCB_XFIXES + xcb_xfixes_destroy_region(_ecore_xcb_conn, region); +// ecore_x_flush(); +#endif +} + +/** + * Set the content of a region. + * @param region The region to destroy. + * @param rects The rectangles used to set the region. + * @param num The number of rectangles. + * + * Replace the current contents of @p region with the region formed + * by the union of the rectangles @p rects. + * @ingroup Ecore_X_Fixes_Group + */ +EAPI void +ecore_x_region_set(Ecore_X_Region region, + Ecore_X_Rectangle *rects, + int num) +{ +#ifdef ECORE_XCB_XFIXES + xcb_rectangle_t *xrects; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_xfixes_avail) return; + +#ifdef ECORE_XCB_XFIXES + xrects = _ecore_xcb_rect_to_xcb(rects, num); + xcb_xfixes_set_region(_ecore_xcb_conn, region, num, xrects); + free(xrects); +// ecore_x_flush(); +#endif +} + +/** + * Copy the content of a region. + * @param dest The destination region. + * @param source The source region. + * + * Replace the contents of @p dest with the contents of @p source. + * @ingroup Ecore_X_Fixes_Group + */ +EAPI void +ecore_x_region_copy(Ecore_X_Region dest, + Ecore_X_Region source) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_xfixes_avail) return; + + // NB: Hmmmm...this may need converting to/fro xcb_rectangle_t +#ifdef ECORE_XCB_XFIXES + xcb_xfixes_copy_region(_ecore_xcb_conn, source, dest); +// ecore_x_flush(); +#endif +} + +/** + * Make the union of two regions. + * @param dest The destination region. + * @param source1 The first source region. + * @param source2 The second source region. + * + * Replace the contents of @p dest with the union of @p source1 and + * @p source2. + * @ingroup Ecore_X_Fixes_Group + */ +EAPI void +ecore_x_region_combine(Ecore_X_Region dest, + Ecore_X_Region source1, + Ecore_X_Region source2) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_xfixes_avail) return; + +#ifdef ECORE_XCB_XFIXES + xcb_xfixes_union_region(_ecore_xcb_conn, source1, source2, dest); +// ecore_x_flush(); +#endif +} + +/** + * Make the intersection of two regions. + * @param dest The destination region. + * @param source1 The first source region. + * @param source2 The second source region. + * + * Replace the contents of @p dest with the intersection of @p source1 and + * @p source2. + * @ingroup Ecore_X_Fixes_Group + */ +EAPI void +ecore_x_region_intersect(Ecore_X_Region dest, + Ecore_X_Region source1, + Ecore_X_Region source2) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_xfixes_avail) return; + +#ifdef ECORE_XCB_XFIXES + xcb_xfixes_intersect_region(_ecore_xcb_conn, source1, source2, dest); +// ecore_x_flush(); +#endif +} + +/** + * Make the subtraction of two regions. + * @param dest The destination region. + * @param source1 The first source region. + * @param source2 The second source region. + * + * Replace the contents of @p dest with the subtraction of @p source1 by + * @p source2. + * @ingroup Ecore_X_Fixes_Group + */ +EAPI void +ecore_x_region_subtract(Ecore_X_Region dest, + Ecore_X_Region source1, + Ecore_X_Region source2) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_xfixes_avail) return; + +#ifdef ECORE_XCB_XFIXES + xcb_xfixes_subtract_region(_ecore_xcb_conn, source1, source2, dest); +// ecore_x_flush(); +#endif +} + +/** + * Make the subtraction of regions by bounds. + * @param dest The destination region. + * @param bounds The bounds. + * @param source The source region. + * + * The @p source region is subtracted from the region specified by + * @p bounds. The result is placed in @p dest, replacing its + * contents. + * @ingroup Ecore_X_Fixes_Group + */ +EAPI void +ecore_x_region_invert(Ecore_X_Region dest, + Ecore_X_Rectangle *bounds, + Ecore_X_Region source) +{ +#ifdef ECORE_XCB_XFIXES + xcb_rectangle_t xrects; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_xfixes_avail) return; + +#ifdef ECORE_XCB_XFIXES + xrects.x = bounds->x; + xrects.y = bounds->y; + xrects.width = bounds->width; + xrects.height = bounds->height; + + xcb_xfixes_invert_region(_ecore_xcb_conn, source, xrects, dest); +// ecore_x_flush(); +#endif +} + +/** + * Translate a region. + * @param region The region to translate. + * @param dx The horizontal translation. + * @param dy The vertical translation. + * + * The @p region is translated by @p dx and @p dy in place. + * @ingroup Ecore_X_Fixes_Group + */ +EAPI void +ecore_x_region_translate(Ecore_X_Region region, + int dx, + int dy) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_xfixes_avail) return; + +#ifdef ECORE_XCB_XFIXES + xcb_xfixes_translate_region(_ecore_xcb_conn, region, dx, dy); +// ecore_x_flush(); +#endif +} + +/** + * Extent a region. + * @param dest The destination region. + * @param source The source region. + * + * The extents of the @p source region are placed in @p dest. + * @ingroup Ecore_X_Fixes_Group + */ +EAPI void +ecore_x_region_extents(Ecore_X_Region dest, + Ecore_X_Region source) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_xfixes_avail) return; + +#ifdef ECORE_XCB_XFIXES + xcb_xfixes_region_extents(_ecore_xcb_conn, source, dest); +// ecore_x_flush(); +#endif +} + +/** + * Return the rectangles that compose a region. + * @param region The region (Unused). + * @param num The number of returned rectangles. + * @param bounds The returned bounds of the region. + * @return The returned rectangles. + * + * The @p region passed to ecore_xcb_region_fetch_prefetch() is + * returned as a list of rectagles in XY-banded order. + * + * To use this function, you must call before, and in order, + * ecore_xcb_region_fetch_prefetch(), which sends the XFixesFetchRegion request, + * then ecore_xcb_region_fetch_fetch(), which gets the reply. + * @ingroup Ecore_X_Fixes_Group + */ +EAPI Ecore_X_Rectangle * +ecore_x_region_fetch(Ecore_X_Region region, + int *num, + Ecore_X_Rectangle *bounds) +{ + Ecore_X_Rectangle extents = { 0, 0, 0, 0 }; + Ecore_X_Rectangle *rects = NULL; +#ifdef ECORE_XCB_XFIXES + xcb_xfixes_fetch_region_cookie_t cookie; + xcb_xfixes_fetch_region_reply_t *reply; + xcb_rectangle_t *r; + int n = 0; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (num) *num = 0; + if (bounds) *bounds = extents; + if (!_xfixes_avail) return NULL; + +#ifdef ECORE_XCB_XFIXES + cookie = xcb_xfixes_fetch_region_unchecked(_ecore_xcb_conn, region); + reply = xcb_xfixes_fetch_region_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return NULL; + + r = xcb_xfixes_fetch_region_rectangles(reply); + n = xcb_xfixes_fetch_region_rectangles_length(reply); + rects = _ecore_xcb_rect_to_ecore(r, n); + if (num) *num = n; + + /* rects = (Ecore_X_Rectangle *)malloc(n * sizeof(Ecore_X_Rectangle)); */ + /* if (!rects) */ + /* { */ + /* free(reply); */ + /* return NULL; */ + /* } */ + + /* for (i = 0; i < n; i++) */ + /* { */ + /* rects[i].x = r[i].x; */ + /* rects[i].y = r[i].y; */ + /* rects[i].width = r[i].width; */ + /* rects[i].height = r[i].height; */ + /* } */ + + (*bounds).x = reply->extents.x; + (*bounds).y = reply->extents.y; + (*bounds).width = reply->extents.width; + (*bounds).height = reply->extents.height; + + free(reply); +#endif + + return rects; +} + +/** + * Expand a region. + * @param dest The destination region. + * @param source The source region. + * @param left The number of pixels to add on the left. + * @param right The number of pixels to add on the right. + * @param top The number of pixels to add at the top. + * @param bottom The number of pixels to add at the bottom. + * + * Put in @p dest the area specified by expanding each rectangle in + * the @p source region by the specified number of pixels to the + * @p left, @p right, @p top and @p bottom. + * @ingroup Ecore_X_Fixes_Group + */ +EAPI void +ecore_x_region_expand(Ecore_X_Region dest, + Ecore_X_Region source, + unsigned int left, + unsigned int right, + unsigned int top, + unsigned int bottom) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_xfixes_avail) return; + +#ifdef ECORE_XCB_XFIXES + xcb_xfixes_expand_region(_ecore_xcb_conn, source, dest, left, right, top, bottom); +// ecore_x_flush(); +#endif +} + +/** + * Change clip-mask in a graphic context to the specified region. + * @param region The region to change. + * @param gc The clip-mask graphic context. + * @param x The horizontal translation. + * @param y The vertical translation. + * + * Changes clip-mask in @p gc to the specified @p region and + * sets the clip origin with the values of @p x_origin and @p y_origin. + * Output will be clippped to remain contained within the region. The + * clip origin is interpreted relative to the origin of whatever + * destination drawable is specified in a graphics request. The + * region is interpreted relative to the clip origin. Future changes + * to region have no effect on the gc clip-mask. + * @ingroup Ecore_X_Fixes_Group + */ +EAPI void +ecore_x_region_gc_clip_set(Ecore_X_Region region, + Ecore_X_GC gc, + int x, + int y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_xfixes_avail) return; + +#ifdef ECORE_XCB_XFIXES + xcb_xfixes_set_gc_clip_region(_ecore_xcb_conn, gc, region, x, y); +// ecore_x_flush(); +#endif +} + +/** + * Change the shape extension of a window. + * @param region The region. + * @param dest The window whose shape is changed. + * @param type The kind of shape. + * @param x The horizontal offset. + * @param y The vertical offset. + * + * Set the specified Shape extension region of @p window to @p region, + * offset by @p x_offset and @p y_offset. Future changes to region + * have no effect on the window shape. + * @ingroup Ecore_X_Fixes_Group + */ +EAPI void +ecore_x_region_window_shape_set(Ecore_X_Region region, + Ecore_X_Window dest, + Ecore_X_Shape_Type type, + int x, + int y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_xfixes_avail) return; + +#ifdef ECORE_XCB_XFIXES + xcb_xfixes_set_window_shape_region(_ecore_xcb_conn, dest, type, x, y, region); +// ecore_x_flush(); +#endif +} + +/** + * Change clip-mask in picture to the specified region. + * @param region The region. + * @param picture The picture. + * @param x The X coordinate of the origin. + * @param y The Y coordinate of the origin. + * + * Changes clip-mask in picture to the specified @p region + * and sets the clip origin. Input and output will be clipped to + * remain contained within the region. The clip origin is interpreted + * relative to the origin of the drawable associated with @p picture. The + * region is interpreted relative to the clip origin. Future changes + * to region have no effect on the picture clip-mask. + * @ingroup Ecore_X_Fixes_Group + */ +EAPI void +ecore_x_region_picture_clip_set(Ecore_X_Region region, + Ecore_X_Picture picture, + int x, + int y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_xfixes_avail) return; + +#ifdef ECORE_XCB_XFIXES + xcb_xfixes_set_picture_clip_region(_ecore_xcb_conn, picture, region, x, y); +// ecore_x_flush(); +#endif +} + +/* local function prototypes */ +static xcb_rectangle_t * +_ecore_xcb_rect_to_xcb(Ecore_X_Rectangle *rects, + int num) +{ + xcb_rectangle_t *xrect; + int i = 0; + + if (!num) return NULL; + + xrect = malloc(sizeof(xcb_rectangle_t) * num); + if (!xrect) return NULL; + + for (i = 0; i < num; i++) + { + xrect[i].x = rects[i].x; + xrect[i].y = rects[i].y; + xrect[i].width = rects[i].width; + xrect[i].height = rects[i].height; + } + + return xrect; +} + +static Ecore_X_Rectangle * +_ecore_xcb_rect_to_ecore(xcb_rectangle_t *rects, + int num) +{ + Ecore_X_Rectangle *erect; + int i = 0; + + if (!num) return NULL; + + erect = malloc(sizeof(Ecore_X_Rectangle) * num); + if (!erect) return NULL; + + for (i = 0; i < num; i++) + { + erect[i].x = rects[i].x; + erect[i].y = rects[i].y; + erect[i].width = rects[i].width; + erect[i].height = rects[i].height; + } + + return erect; +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_xinerama.c b/src/lib/ecore_x/xcb/ecore_xcb_xinerama.c new file mode 100644 index 0000000..37a2339 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_xinerama.c @@ -0,0 +1,139 @@ +#include "ecore_xcb_private.h" +#ifdef ECORE_XCB_XINERAMA +# include +#endif + +/* local variables */ +static Eina_Bool _xinerama_avail = EINA_FALSE; +static Eina_Bool _xinerama_active = EINA_FALSE; + +void +_ecore_xcb_xinerama_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_XINERAMA + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_xinerama_id); +#endif +} + +void +_ecore_xcb_xinerama_finalize(void) +{ +#ifdef ECORE_XCB_XINERAMA + const xcb_query_extension_reply_t *ext_reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_XINERAMA + ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_xinerama_id); + if ((ext_reply) && (ext_reply->present)) + { + xcb_xinerama_query_version_cookie_t cookie; + xcb_xinerama_query_version_reply_t *reply; + + cookie = + xcb_xinerama_query_version_unchecked(_ecore_xcb_conn, + XCB_XINERAMA_MAJOR_VERSION, + XCB_XINERAMA_MINOR_VERSION); + reply = + xcb_xinerama_query_version_reply(_ecore_xcb_conn, cookie, NULL); + if (reply) + { + _xinerama_avail = EINA_TRUE; + // NB: Do we need to compare version numbers here ? + free(reply); + } + + if (_xinerama_avail) + { + xcb_xinerama_is_active_cookie_t acookie; + xcb_xinerama_is_active_reply_t *areply; + + acookie = xcb_xinerama_is_active_unchecked(_ecore_xcb_conn); + areply = + xcb_xinerama_is_active_reply(_ecore_xcb_conn, acookie, NULL); + if (areply) + { + _xinerama_active = areply->state; + free(areply); + } + } + } +#endif +} + +EAPI int +ecore_x_xinerama_screen_count_get(void) +{ + int count = 0; +#ifdef ECORE_XCB_XINERAMA + xcb_xinerama_query_screens_cookie_t cookie; + xcb_xinerama_query_screens_reply_t *reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_xinerama_avail) return 0; + +#ifdef ECORE_XCB_XINERAMA + cookie = xcb_xinerama_query_screens_unchecked(_ecore_xcb_conn); + reply = + xcb_xinerama_query_screens_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return 0; + count = reply->number; +#endif + + return count; +} + +EAPI Eina_Bool +ecore_x_xinerama_screen_geometry_get(int screen, + int *x, + int *y, + int *w, + int *h) +{ +#ifdef ECORE_XCB_XINERAMA + xcb_xinerama_query_screens_cookie_t cookie; + xcb_xinerama_query_screens_reply_t *reply; + xcb_xinerama_screen_info_t *info; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (x) *x = 0; + if (y) *y = 0; + if (w) *w = ((xcb_screen_t *)_ecore_xcb_screen)->width_in_pixels; + if (h) *h = ((xcb_screen_t *)_ecore_xcb_screen)->height_in_pixels; + + if (!_xinerama_avail) return EINA_FALSE; + +#ifdef ECORE_XCB_XINERAMA + cookie = xcb_xinerama_query_screens_unchecked(_ecore_xcb_conn); + reply = + xcb_xinerama_query_screens_reply(_ecore_xcb_conn, cookie, NULL); + if (!reply) return EINA_FALSE; + + info = xcb_xinerama_query_screens_screen_info(reply); + if (!info) + { + free(reply); + return EINA_FALSE; + } + + if (x) *x = info[screen].x_org; + if (y) *y = info[screen].y_org; + if (w) *w = info[screen].width; + if (h) *h = info[screen].height; + + free(reply); + return EINA_TRUE; +#endif + + return EINA_FALSE; +} + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_xtest.c b/src/lib/ecore_x/xcb/ecore_xcb_xtest.c new file mode 100644 index 0000000..b664dc9 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_xtest.c @@ -0,0 +1,215 @@ +#include "ecore_xcb_private.h" +#ifdef ECORE_XCB_XTEST +# include +# include +#endif + +/* local variables */ +static Eina_Bool _test_avail = EINA_FALSE; + +void +_ecore_xcb_xtest_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_XTEST + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_test_id); +#endif +} + +void +_ecore_xcb_xtest_finalize(void) +{ +#ifdef ECORE_XCB_XTEST + const xcb_query_extension_reply_t *ext_reply; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#ifdef ECORE_XCB_XTEST + ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_test_id); + if ((ext_reply) && (ext_reply->present)) + _test_avail = EINA_TRUE; +#endif +} + +EAPI Eina_Bool +#ifdef ECORE_XCB_XTEST +ecore_x_test_fake_key_down(const char *key) +#else +ecore_x_test_fake_key_down(const char *key __UNUSED__) +#endif +{ +#ifdef ECORE_XCB_XTEST + xcb_keycode_t keycode = 0; + xcb_void_cookie_t cookie; + xcb_generic_error_t *err; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_test_avail) return EINA_FALSE; + +#ifdef ECORE_XCB_XTEST + keycode = _ecore_xcb_keymap_string_to_keycode(key); + if (keycode == XCB_NO_SYMBOL) return EINA_FALSE; + + cookie = + xcb_test_fake_input(_ecore_xcb_conn, XCB_KEY_PRESS, + keycode, XCB_CURRENT_TIME, + ((xcb_screen_t *)_ecore_xcb_screen)->root, 0, 0, 0); + err = xcb_request_check(_ecore_xcb_conn, cookie); + if (err) + { + free(err); + return EINA_FALSE; + } + return EINA_TRUE; +#endif + + return EINA_FALSE; +} + +EAPI Eina_Bool +#ifdef ECORE_XCB_XTEST +ecore_x_test_fake_key_up(const char *key) +#else +ecore_x_test_fake_key_up(const char *key __UNUSED__) +#endif +{ +#ifdef ECORE_XCB_XTEST + xcb_keycode_t keycode = 0; + xcb_void_cookie_t cookie; + xcb_generic_error_t *err; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_test_avail) return EINA_FALSE; + +#ifdef ECORE_XCB_XTEST + keycode = _ecore_xcb_keymap_string_to_keycode(key); + if (keycode == XCB_NO_SYMBOL) return EINA_FALSE; + + cookie = + xcb_test_fake_input(_ecore_xcb_conn, XCB_KEY_RELEASE, + keycode, XCB_CURRENT_TIME, + ((xcb_screen_t *)_ecore_xcb_screen)->root, 0, 0, 0); + err = xcb_request_check(_ecore_xcb_conn, cookie); + if (err) + { + free(err); + return EINA_FALSE; + } + return EINA_TRUE; +#endif + + return EINA_FALSE; +} + +EAPI Eina_Bool +#ifdef ECORE_XCB_XTEST +ecore_x_test_fake_key_press(const char *key) +#else +ecore_x_test_fake_key_press(const char *key __UNUSED__) +#endif +{ +#ifdef ECORE_XCB_XTEST + xcb_keycode_t keycode = 0; + xcb_keysym_t keysym = 0; + xcb_keycode_t shift_code = 0; + xcb_void_cookie_t cookie; + xcb_generic_error_t *err; + Eina_Bool shift = EINA_FALSE; +#endif + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_test_avail) return EINA_FALSE; + +#ifdef ECORE_XCB_XTEST + keycode = _ecore_xcb_keymap_string_to_keycode(key); + keysym = _ecore_xcb_keymap_keycode_to_keysym(keycode, 0); + if (keysym == XCB_NO_SYMBOL) + { + keysym = _ecore_xcb_keymap_keycode_to_keysym(keycode, 1); + if (keysym != XCB_NO_SYMBOL) + shift = EINA_TRUE; + } + + if (shift) + { + xcb_keycode_t *keycodes; + int i = 0; + + keycodes = _ecore_xcb_keymap_keysym_to_keycode(XK_Shift_L); + while (keycodes[i] != XCB_NO_SYMBOL) + { + if (keycodes[i] != 0) + { + shift_code = keycodes[i]; + break; + } + i++; + } + } + + if (shift) + { + cookie = + xcb_test_fake_input(_ecore_xcb_conn, XCB_KEY_PRESS, + shift_code, XCB_CURRENT_TIME, + ((xcb_screen_t *)_ecore_xcb_screen)->root, + 0, 0, 0); + err = xcb_request_check(_ecore_xcb_conn, cookie); + if (err) + { + free(err); + return EINA_FALSE; + } + } + + cookie = + xcb_test_fake_input(_ecore_xcb_conn, XCB_KEY_PRESS, + keycode, XCB_CURRENT_TIME, + ((xcb_screen_t *)_ecore_xcb_screen)->root, 0, 0, 0); + err = xcb_request_check(_ecore_xcb_conn, cookie); + if (err) + { + free(err); + return EINA_FALSE; + } + cookie = + xcb_test_fake_input(_ecore_xcb_conn, XCB_KEY_RELEASE, + keycode, XCB_CURRENT_TIME, + ((xcb_screen_t *)_ecore_xcb_screen)->root, 0, 0, 0); + err = xcb_request_check(_ecore_xcb_conn, cookie); + if (err) + { + free(err); + return EINA_FALSE; + } + + if (shift) + { + cookie = + xcb_test_fake_input(_ecore_xcb_conn, XCB_KEY_RELEASE, + shift_code, XCB_CURRENT_TIME, + ((xcb_screen_t *)_ecore_xcb_screen)->root, + 0, 0, 0); + err = xcb_request_check(_ecore_xcb_conn, cookie); + if (err) + { + free(err); + return EINA_FALSE; + } + } + + return EINA_TRUE; +#endif + + return EINA_FALSE; +} diff --git a/src/lib/ecore_x/xlib/Makefile.am b/src/lib/ecore_x/xlib/Makefile.am new file mode 100644 index 0000000..3c7364c --- /dev/null +++ b/src/lib/ecore_x/xlib/Makefile.am @@ -0,0 +1,94 @@ + +MAINTAINERCLEANFILES = Makefile.in + +if BUILD_ECORE_X_XLIB + +AM_CPPFLAGS = \ +@Xcursor_cflags@ \ +@XKB_CFLAGS@ \ +@XDAMAGE_CFLAGS@ \ +@XCOMPOSITE_CFLAGS@ \ +@XGESTURE_CFLAGS@ \ +@XDPMS_CFLAGS@ \ +@XFIXES_CFLAGS@ \ +@XI2_CFLAGS@ \ +@XINERAMA_CFLAGS@ \ +@XPRINT_CFLAGS@ \ +@XRANDR_CFLAGS@ \ +@XRENDER_CFLAGS@ \ +@XSS_CFLAGS@ \ +@XTEST_CFLAGS@ \ +@x_cflags@ \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore_x \ +-I$(top_srcdir)/src/lib/ecore_input \ +-I$(top_builddir)/src/lib/ecore \ +-I$(top_builddir)/src/lib/ecore_x \ +-I$(top_builddir)/src/lib/ecore_input \ +@EVAS_CFLAGS@ \ +@EINA_CFLAGS@ + +noinst_LTLIBRARIES = libecore_x_xlib.la + +libecore_x_xlib_la_SOURCES = \ +ecore_x.c \ +ecore_x_dnd.c \ +ecore_x_sync.c \ +ecore_x_randr.c \ +ecore_x_randr_11.c \ +ecore_x_randr_12.c \ +ecore_x_randr_12_edid.c \ +ecore_x_randr_13.c \ +ecore_x_fixes.c \ +ecore_x_damage.c \ +ecore_x_composite.c \ +ecore_x_error.c \ +ecore_x_events.c \ +ecore_x_icccm.c \ +ecore_x_netwm.c \ +ecore_x_mwm.c \ +ecore_x_e.c \ +ecore_x_selection.c \ +ecore_x_window.c \ +ecore_x_window_prop.c \ +ecore_x_window_shape.c \ +ecore_x_pixmap.c \ +ecore_x_gc.c \ +ecore_x_xinerama.c \ +ecore_x_screensaver.c \ +ecore_x_dpms.c \ +ecore_x_drawable.c \ +ecore_x_cursor.c \ +ecore_x_test.c \ +ecore_x_atoms.c \ +ecore_x_region.c \ +ecore_x_image.c \ +ecore_x_xi2.c \ +ecore_x_vsync.c \ +ecore_x_randr.h \ +ecore_x_gesture.c + +libecore_x_xlib_la_LIBADD = \ +@Xcursor_libs@ \ +@XKB_LIBS@ \ +@XDAMAGE_LIBS@ \ +@XCOMPOSITE_LIBS@ \ +@XGESTURE_LIBS@ \ +@XDPMS_LIBS@ \ +@XFIXES_LIBS@ \ +@XI2_LIBS@ \ +@XINERAMA_LIBS@ \ +@XPRINT_LIBS@ \ +@XRANDR_LIBS@ \ +@XRENDER_LIBS@ \ +@XSS_LIBS@ \ +@XTEST_LIBS@ \ +@x_libs@ \ +$(top_builddir)/src/lib/ecore/libecore.la \ +$(top_builddir)/src/lib/ecore_input/libecore_input.la \ +@EINA_LIBS@ \ +@dlopen_libs@ + +endif + +EXTRA_DIST = ecore_x_private.h diff --git a/src/lib/ecore_x/xlib/ecore_x.c b/src/lib/ecore_x/xlib/ecore_x.c new file mode 100644 index 0000000..294747b --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x.c @@ -0,0 +1,2208 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include +#include +#include + +//#define LOGRT 1 + +#ifdef LOGRT +#include +#endif /* ifdef LOGRT */ + +#include "Ecore.h" +#include "ecore_private.h" +#include "ecore_x_private.h" +#include "Ecore_X.h" +#include "Ecore_X_Atoms.h" +#include "Ecore_Input.h" + +static Eina_Bool _ecore_x_fd_handler(void *data, + Ecore_Fd_Handler *fd_handler); +static Eina_Bool _ecore_x_fd_handler_buf(void *data, + Ecore_Fd_Handler *fd_handler); +static int _ecore_x_key_mask_get(KeySym sym); +static int _ecore_x_event_modifier(unsigned int state); + +static Ecore_Fd_Handler *_ecore_x_fd_handler_handle = NULL; + +static const int AnyXEvent = 0; /* 0 can be used as there are no event types + * with index 0 and 1 as they are used for + * errors + */ + +static int _ecore_x_event_shape_id = 0; +static int _ecore_x_event_screensaver_id = 0; +static int _ecore_x_event_sync_id = 0; +int _ecore_xlib_log_dom = -1; + +#ifdef ECORE_XRANDR +static int _ecore_x_event_randr_id = 0; +#endif /* ifdef ECORE_XRANDR */ +#ifdef ECORE_XFIXES +static int _ecore_x_event_fixes_selection_id = 0; +#endif /* ifdef ECORE_XFIXES */ +#ifdef ECORE_XDAMAGE +static int _ecore_x_event_damage_id = 0; +#endif /* ifdef ECORE_XDAMAGE */ +#ifdef ECORE_XGESTURE +static int _ecore_x_event_gesture_id = 0; +#endif /* ifdef ECORE_XGESTURE */ +#ifdef ECORE_XKB +static int _ecore_x_event_xkb_id = 0; +#endif /* ifdef ECORE_XKB */ +static int _ecore_x_event_handlers_num = 0; +static void (**_ecore_x_event_handlers) (XEvent * event) = NULL; + +static int _ecore_x_init_count = 0; +static int _ecore_x_grab_count = 0; + +Display *_ecore_x_disp = NULL; +double _ecore_x_double_click_time = 0.25; +Time _ecore_x_event_last_time = 0; +Window _ecore_x_event_last_win = 0; +int _ecore_x_event_last_root_x = 0; +int _ecore_x_event_last_root_y = 0; +Eina_Bool _ecore_x_xcursor = EINA_FALSE; + +Ecore_X_Window _ecore_x_private_win = 0; + +Ecore_X_Atom _ecore_x_atoms_wm_protocols[ECORE_X_WM_PROTOCOL_NUM]; + +EAPI int ECORE_X_EVENT_ANY = 0; +EAPI int ECORE_X_EVENT_MOUSE_IN = 0; +EAPI int ECORE_X_EVENT_MOUSE_OUT = 0; +EAPI int ECORE_X_EVENT_WINDOW_FOCUS_IN = 0; +EAPI int ECORE_X_EVENT_WINDOW_FOCUS_OUT = 0; +EAPI int ECORE_X_EVENT_WINDOW_KEYMAP = 0; +EAPI int ECORE_X_EVENT_WINDOW_DAMAGE = 0; +EAPI int ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE = 0; +EAPI int ECORE_X_EVENT_WINDOW_CREATE = 0; +EAPI int ECORE_X_EVENT_WINDOW_DESTROY = 0; +EAPI int ECORE_X_EVENT_WINDOW_HIDE = 0; +EAPI int ECORE_X_EVENT_WINDOW_SHOW = 0; +EAPI int ECORE_X_EVENT_WINDOW_SHOW_REQUEST = 0; +EAPI int ECORE_X_EVENT_WINDOW_REPARENT = 0; +EAPI int ECORE_X_EVENT_WINDOW_CONFIGURE = 0; +EAPI int ECORE_X_EVENT_WINDOW_CONFIGURE_REQUEST = 0; +EAPI int ECORE_X_EVENT_WINDOW_GRAVITY = 0; +EAPI int ECORE_X_EVENT_WINDOW_RESIZE_REQUEST = 0; +EAPI int ECORE_X_EVENT_WINDOW_STACK = 0; +EAPI int ECORE_X_EVENT_WINDOW_STACK_REQUEST = 0; +EAPI int ECORE_X_EVENT_WINDOW_PROPERTY = 0; +EAPI int ECORE_X_EVENT_WINDOW_COLORMAP = 0; +EAPI int ECORE_X_EVENT_WINDOW_MAPPING = 0; +EAPI int ECORE_X_EVENT_MAPPING_CHANGE = 0; +EAPI int ECORE_X_EVENT_SELECTION_CLEAR = 0; +EAPI int ECORE_X_EVENT_SELECTION_REQUEST = 0; +EAPI int ECORE_X_EVENT_SELECTION_NOTIFY = 0; +EAPI int ECORE_X_EVENT_FIXES_SELECTION_NOTIFY = 0; +EAPI int ECORE_X_EVENT_CLIENT_MESSAGE = 0; +EAPI int ECORE_X_EVENT_WINDOW_SHAPE = 0; +EAPI int ECORE_X_EVENT_SCREENSAVER_NOTIFY = 0; +EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_FLICK; +EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_PAN; +EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_PINCHROTATION; +EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_TAP; +EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_TAPNHOLD; +EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_HOLD; +EAPI int ECORE_X_EVENT_GESTURE_NOTIFY_GROUP; +EAPI int ECORE_X_EVENT_SYNC_COUNTER = 0; +EAPI int ECORE_X_EVENT_SYNC_ALARM = 0; +EAPI int ECORE_X_EVENT_SCREEN_CHANGE = 0; +EAPI int ECORE_X_EVENT_DAMAGE_NOTIFY = 0; +EAPI int ECORE_X_EVENT_RANDR_CRTC_CHANGE = 0; +EAPI int ECORE_X_EVENT_RANDR_OUTPUT_CHANGE = 0; +EAPI int ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY = 0; +EAPI int ECORE_X_EVENT_WINDOW_DELETE_REQUEST = 0; +EAPI int ECORE_X_EVENT_WINDOW_MOVE_RESIZE_REQUEST = 0; +EAPI int ECORE_X_EVENT_WINDOW_STATE_REQUEST = 0; +EAPI int ECORE_X_EVENT_FRAME_EXTENTS_REQUEST = 0; +EAPI int ECORE_X_EVENT_PING = 0; +EAPI int ECORE_X_EVENT_DESKTOP_CHANGE = 0; + +EAPI int ECORE_X_EVENT_STARTUP_SEQUENCE_NEW = 0; +EAPI int ECORE_X_EVENT_STARTUP_SEQUENCE_CHANGE = 0; +EAPI int ECORE_X_EVENT_STARTUP_SEQUENCE_REMOVE = 0; + +EAPI int ECORE_X_EVENT_XKB_STATE_NOTIFY = 0; +EAPI int ECORE_X_EVENT_XKB_NEWKBD_NOTIFY = 0; + + +EAPI int ECORE_X_EVENT_GENERIC = 0; + +EAPI int ECORE_X_MODIFIER_SHIFT = 0; +EAPI int ECORE_X_MODIFIER_CTRL = 0; +EAPI int ECORE_X_MODIFIER_ALT = 0; +EAPI int ECORE_X_MODIFIER_WIN = 0; +EAPI int ECORE_X_MODIFIER_ALTGR = 0; + +EAPI int ECORE_X_LOCK_SCROLL = 0; +EAPI int ECORE_X_LOCK_NUM = 0; +EAPI int ECORE_X_LOCK_CAPS = 0; +EAPI int ECORE_X_LOCK_SHIFT = 0; + +#ifdef LOGRT +static double t0 = 0.0; +static Status (*_logrt_real_reply)(Display *disp, + void *rep, + int extra, + Bool discard) = NULL; +static void +_logrt_init(void) +{ + void *lib; + + lib = dlopen("libX11.so", RTLD_GLOBAL | RTLD_LAZY); + if (!lib) + lib = dlopen("libX11.so.6", RTLD_GLOBAL | RTLD_LAZY); + + if (!lib) + lib = dlopen("libX11.so.6.3", RTLD_GLOBAL | RTLD_LAZY); + + if (!lib) + lib = dlopen("libX11.so.6.3.0", RTLD_GLOBAL | RTLD_LAZY); + + _logrt_real_reply = dlsym(lib, "_XReply"); + t0 = ecore_time_get(); +} + +Status +_XReply(Display *disp, + void *rep, + int extra, + Bool discard) +{ + void *bt[128]; + int i, n; + char **sym; + + n = backtrace(bt, 128); + if (n > 0) + { + sym = backtrace_symbols(bt, n); + printf("ROUNDTRIP: %4.4f :", ecore_time_get() - t0); + if (sym) + { + for (i = n - 1; i > 0; i--) + { + char *fname = strchr(sym[i], '('); + if (fname) + { + char *tsym = alloca(strlen(fname) + 1); + char *end; + strcpy(tsym, fname + 1); + end = strchr(tsym, '+'); + if (end) + { + *end = 0; + printf("%s", tsym); + } + else + printf("???"); + } + else + printf("???"); + + if (i > 1) + printf(" > "); + } + printf("\n"); + } + } + + // fixme: logme + return _logrt_real_reply(disp, rep, extra, discard); +} + +#endif /* ifdef LOGRT */ + +/* wrapper to use XkbKeycodeToKeysym when possible */ +KeySym +_ecore_x_XKeycodeToKeysym(Display *display, KeyCode keycode, int idx) +{ +#ifdef ECORE_XKB + return XkbKeycodeToKeysym(display, keycode, 0, idx); +#else + return XKeycodeToKeysym(display, keycode, idx); +#endif +} + +void +_ecore_x_modifiers_get(void) +{ + /* everything has these... unless its like a pda... :) */ + ECORE_X_MODIFIER_SHIFT = _ecore_x_key_mask_get(XK_Shift_L); + ECORE_X_MODIFIER_CTRL = _ecore_x_key_mask_get(XK_Control_L); + + /* apple's xdarwin has no alt!!!! */ + ECORE_X_MODIFIER_ALT = _ecore_x_key_mask_get(XK_Alt_L); + if (!ECORE_X_MODIFIER_ALT) + ECORE_X_MODIFIER_ALT = _ecore_x_key_mask_get(XK_Meta_L); + + if (!ECORE_X_MODIFIER_ALT) + ECORE_X_MODIFIER_ALT = _ecore_x_key_mask_get(XK_Super_L); + + /* the windows key... a valid modifier :) */ + ECORE_X_MODIFIER_WIN = _ecore_x_key_mask_get(XK_Super_L); + if (!ECORE_X_MODIFIER_WIN) + ECORE_X_MODIFIER_WIN = _ecore_x_key_mask_get(XK_Meta_L); + + ECORE_X_MODIFIER_ALTGR = _ecore_x_key_mask_get(XK_Mode_switch); + + if (ECORE_X_MODIFIER_WIN == ECORE_X_MODIFIER_ALT) + ECORE_X_MODIFIER_WIN = 0; + + if (ECORE_X_MODIFIER_ALT == ECORE_X_MODIFIER_CTRL) + ECORE_X_MODIFIER_ALT = 0; + + ECORE_X_LOCK_SCROLL = _ecore_x_key_mask_get(XK_Scroll_Lock); + ECORE_X_LOCK_NUM = _ecore_x_key_mask_get(XK_Num_Lock); + ECORE_X_LOCK_CAPS = _ecore_x_key_mask_get(XK_Caps_Lock); + ECORE_X_LOCK_SHIFT = _ecore_x_key_mask_get(XK_Shift_Lock); +} + +/** + * @defgroup Ecore_X_Init_Group X Library Init and Shutdown Functions + * + * Functions that start and shut down the Ecore X Library. + */ + +/** + * Initialize the X display connection to the given display. + * + * @param name Display target name. If @c NULL, the default display is + * assumed. + * @return The number of times the library has been initialized without + * being shut down. 0 is returned if an error occurs. + * @ingroup Ecore_X_Init_Group + */ +EAPI int +ecore_x_init(const char *name) +{ + int shape_base = 0; + int shape_err_base = 0; +#ifdef ECORE_XSS + int screensaver_base = 0; + int screensaver_err_base = 0; +#endif /* ifdef ECORE_XSS */ + int sync_base = 0; + int sync_err_base = 0; +#ifdef ECORE_XRANDR + int randr_base = 0; + int randr_err_base = 0; +#endif /* ifdef ECORE_XRANDR */ +#ifdef ECORE_XFIXES + int fixes_base = 0; + int fixes_err_base = 0; +#endif /* ifdef ECORE_XFIXES */ +#ifdef ECORE_XDAMAGE + int damage_base = 0; + int damage_err_base = 0; +#endif /* ifdef ECORE_XDAMAGE */ +#ifdef ECORE_XGESTURE + int gesture_base = 0; + int gesture_err_base = 0; +#endif /* ifdef ECORE_XGESTURE */ +#ifdef ECORE_XKB + int xkb_base = 0; +#endif /* ifdef ECORE_XKB */ + if (++_ecore_x_init_count != 1) + return _ecore_x_init_count; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); +#ifdef LOGRT + _logrt_init(); +#endif /* ifdef LOGRT */ + + eina_init(); + _ecore_xlib_log_dom = eina_log_domain_register + ("ecore_x", ECORE_XLIB_DEFAULT_LOG_COLOR); + if (_ecore_xlib_log_dom < 0) + { + EINA_LOG_ERR( + "Impossible to create a log domain for the Ecore Xlib module."); + return --_ecore_x_init_count; + } + + if (!ecore_init()) + goto shutdown_eina; + if (!ecore_event_init()) + goto shutdown_ecore; + +#ifdef EVAS_FRAME_QUEUING + XInitThreads(); +#endif /* ifdef EVAS_FRAME_QUEUING */ + _ecore_x_disp = XOpenDisplay((char *)name); + if (!_ecore_x_disp) + goto shutdown_ecore_event; + + _ecore_x_error_handler_init(); + _ecore_x_event_handlers_num = LASTEvent; + +#define ECORE_X_EVENT_HANDLERS_GROW(ext_base, ext_num_events) \ + do { \ + if (_ecore_x_event_handlers_num < (ext_base + ext_num_events)) { \ + _ecore_x_event_handlers_num = (ext_base + ext_num_events); } \ + } while (0) + + if (XShapeQueryExtension(_ecore_x_disp, &shape_base, &shape_err_base)) + _ecore_x_event_shape_id = shape_base; + + ECORE_X_EVENT_HANDLERS_GROW(shape_base, ShapeNumberEvents); + +#ifdef ECORE_XSS + if (XScreenSaverQueryExtension(_ecore_x_disp, &screensaver_base, + &screensaver_err_base)) + _ecore_x_event_screensaver_id = screensaver_base; + + ECORE_X_EVENT_HANDLERS_GROW(screensaver_base, ScreenSaverNumberEvents); +#endif /* ifdef ECORE_XSS */ + + if (XSyncQueryExtension(_ecore_x_disp, &sync_base, &sync_err_base)) + { + int major, minor; + + _ecore_x_event_sync_id = sync_base; + if (!XSyncInitialize(_ecore_x_disp, &major, &minor)) + _ecore_x_event_sync_id = 0; + } + + ECORE_X_EVENT_HANDLERS_GROW(sync_base, XSyncNumberEvents); + +#ifdef ECORE_XRANDR + if (XRRQueryExtension(_ecore_x_disp, &randr_base, &randr_err_base)) + _ecore_x_event_randr_id = randr_base; + + ECORE_X_EVENT_HANDLERS_GROW(randr_base, RRNumberEvents); +#endif /* ifdef ECORE_XRANDR */ + +#ifdef ECORE_XFIXES + if (XFixesQueryExtension(_ecore_x_disp, &fixes_base, &fixes_err_base)) + _ecore_x_event_fixes_selection_id = fixes_base; + + ECORE_X_EVENT_HANDLERS_GROW(fixes_base, XFixesNumberEvents); +#endif /* ifdef ECORE_XFIXES */ + +#ifdef ECORE_XDAMAGE + if (XDamageQueryExtension(_ecore_x_disp, &damage_base, &damage_err_base)) + _ecore_x_event_damage_id = damage_base; + + ECORE_X_EVENT_HANDLERS_GROW(damage_base, XDamageNumberEvents); +#endif /* ifdef ECORE_XDAMAGE */ + +#ifdef ECORE_XGESTURE + if (XGestureQueryExtension(_ecore_x_disp, &gesture_base, &gesture_err_base)) + _ecore_x_event_gesture_id = gesture_base; + + ECORE_X_EVENT_HANDLERS_GROW(gesture_base, GestureNumberEvents); +#endif /* ifdef ECORE_XGESTURE */ +#ifdef ECORE_XKB + { + int dummy; + + if (XkbQueryExtension(_ecore_x_disp, &dummy, &xkb_base, + &dummy, &dummy, &dummy)) + _ecore_x_event_xkb_id = xkb_base; + XkbSelectEventDetails(_ecore_x_disp, XkbUseCoreKbd, XkbStateNotify, + XkbAllStateComponentsMask, XkbGroupStateMask); + } + ECORE_X_EVENT_HANDLERS_GROW(xkb_base, XkbNumberEvents); +#endif + + _ecore_x_event_handlers = calloc(_ecore_x_event_handlers_num, sizeof(void *)); + if (!_ecore_x_event_handlers) + goto close_display; + +#ifdef ECORE_XCURSOR + _ecore_x_xcursor = XcursorSupportsARGB(_ecore_x_disp) ? EINA_TRUE : EINA_FALSE; +#endif /* ifdef ECORE_XCURSOR */ + _ecore_x_event_handlers[AnyXEvent] = _ecore_x_event_handle_any_event; + _ecore_x_event_handlers[KeyPress] = _ecore_x_event_handle_key_press; + _ecore_x_event_handlers[KeyRelease] = _ecore_x_event_handle_key_release; + _ecore_x_event_handlers[ButtonPress] = _ecore_x_event_handle_button_press; + _ecore_x_event_handlers[ButtonRelease] = + _ecore_x_event_handle_button_release; + _ecore_x_event_handlers[MotionNotify] = _ecore_x_event_handle_motion_notify; + _ecore_x_event_handlers[EnterNotify] = _ecore_x_event_handle_enter_notify; + _ecore_x_event_handlers[LeaveNotify] = _ecore_x_event_handle_leave_notify; + _ecore_x_event_handlers[FocusIn] = _ecore_x_event_handle_focus_in; + _ecore_x_event_handlers[FocusOut] = _ecore_x_event_handle_focus_out; + _ecore_x_event_handlers[KeymapNotify] = _ecore_x_event_handle_keymap_notify; + _ecore_x_event_handlers[Expose] = _ecore_x_event_handle_expose; + _ecore_x_event_handlers[GraphicsExpose] = + _ecore_x_event_handle_graphics_expose; + _ecore_x_event_handlers[VisibilityNotify] = + _ecore_x_event_handle_visibility_notify; + _ecore_x_event_handlers[CreateNotify] = _ecore_x_event_handle_create_notify; + _ecore_x_event_handlers[DestroyNotify] = + _ecore_x_event_handle_destroy_notify; + _ecore_x_event_handlers[UnmapNotify] = _ecore_x_event_handle_unmap_notify; + _ecore_x_event_handlers[MapNotify] = _ecore_x_event_handle_map_notify; + _ecore_x_event_handlers[MapRequest] = _ecore_x_event_handle_map_request; + _ecore_x_event_handlers[ReparentNotify] = + _ecore_x_event_handle_reparent_notify; + _ecore_x_event_handlers[ConfigureNotify] = + _ecore_x_event_handle_configure_notify; + _ecore_x_event_handlers[ConfigureRequest] = + _ecore_x_event_handle_configure_request; + _ecore_x_event_handlers[GravityNotify] = + _ecore_x_event_handle_gravity_notify; + _ecore_x_event_handlers[ResizeRequest] = + _ecore_x_event_handle_resize_request; + _ecore_x_event_handlers[CirculateNotify] = + _ecore_x_event_handle_circulate_notify; + _ecore_x_event_handlers[CirculateRequest] = + _ecore_x_event_handle_circulate_request; + _ecore_x_event_handlers[PropertyNotify] = + _ecore_x_event_handle_property_notify; + _ecore_x_event_handlers[SelectionClear] = + _ecore_x_event_handle_selection_clear; + _ecore_x_event_handlers[SelectionRequest] = + _ecore_x_event_handle_selection_request; + _ecore_x_event_handlers[SelectionNotify] = + _ecore_x_event_handle_selection_notify; + _ecore_x_event_handlers[ColormapNotify] = + _ecore_x_event_handle_colormap_notify; + _ecore_x_event_handlers[ClientMessage] = + _ecore_x_event_handle_client_message; + _ecore_x_event_handlers[MappingNotify] = + _ecore_x_event_handle_mapping_notify; +#ifdef GenericEvent + _ecore_x_event_handlers[GenericEvent] = _ecore_x_event_handle_generic_event; +#endif /* ifdef GenericEvent */ + + if (_ecore_x_event_shape_id) + _ecore_x_event_handlers[_ecore_x_event_shape_id] = + _ecore_x_event_handle_shape_change; + + if (_ecore_x_event_screensaver_id) + _ecore_x_event_handlers[_ecore_x_event_screensaver_id] = + _ecore_x_event_handle_screensaver_notify; + + if (_ecore_x_event_sync_id) + { + _ecore_x_event_handlers[_ecore_x_event_sync_id + XSyncCounterNotify] = + _ecore_x_event_handle_sync_counter; + _ecore_x_event_handlers[_ecore_x_event_sync_id + XSyncAlarmNotify] = + _ecore_x_event_handle_sync_alarm; + } + +#ifdef ECORE_XRANDR + if (_ecore_x_event_randr_id) + { + _ecore_x_event_handlers[_ecore_x_event_randr_id + + RRScreenChangeNotify] = + _ecore_x_event_handle_randr_change; + _ecore_x_event_handlers[_ecore_x_event_randr_id + + RRNotify] = _ecore_x_event_handle_randr_notify; + } + +#endif /* ifdef ECORE_XRANDR */ +#ifdef ECORE_XFIXES + if (_ecore_x_event_fixes_selection_id) + _ecore_x_event_handlers[_ecore_x_event_fixes_selection_id] = + _ecore_x_event_handle_fixes_selection_notify; + +#endif /* ifdef ECORE_XFIXES */ +#ifdef ECORE_XDAMAGE + if (_ecore_x_event_damage_id) + _ecore_x_event_handlers[_ecore_x_event_damage_id] = + _ecore_x_event_handle_damage_notify; + +#endif /* ifdef ECORE_XDAMAGE */ +#ifdef ECORE_XKB + // set x autorepeat detection to on. that means instead of + // press-release-press-release-press-release + // you get + // press-press-press-press-press-release + do + { + Bool works = 0; + XkbSetDetectableAutoRepeat(_ecore_x_disp, 1, &works); + } + while (0); + if (_ecore_x_event_xkb_id) + _ecore_x_event_handlers[_ecore_x_event_xkb_id] = _ecore_x_event_handle_xkb; +#endif /* ifdef ECORE_XKB */ + +#ifdef ECORE_XGESTURE + if (_ecore_x_event_gesture_id) + { + _ecore_x_event_handlers[_ecore_x_event_gesture_id + GestureNotifyFlick] = + _ecore_x_event_handle_gesture_notify_flick; + _ecore_x_event_handlers[_ecore_x_event_gesture_id + GestureNotifyPan] = + _ecore_x_event_handle_gesture_notify_pan; + _ecore_x_event_handlers[_ecore_x_event_gesture_id + GestureNotifyPinchRotation] = + _ecore_x_event_handle_gesture_notify_pinchrotation; + _ecore_x_event_handlers[_ecore_x_event_gesture_id + GestureNotifyTap] = + _ecore_x_event_handle_gesture_notify_tap; + _ecore_x_event_handlers[_ecore_x_event_gesture_id + GestureNotifyTapNHold] = + _ecore_x_event_handle_gesture_notify_tapnhold; + _ecore_x_event_handlers[_ecore_x_event_gesture_id + GestureNotifyHold] = + _ecore_x_event_handle_gesture_notify_hold; + _ecore_x_event_handlers[_ecore_x_event_gesture_id + GestureNotifyGroup] = + _ecore_x_event_handle_gesture_notify_group; + } + +#endif /* ifdef ECORE_XGESTURE */ + + if (!ECORE_X_EVENT_ANY) + { + ECORE_X_EVENT_ANY = ecore_event_type_new(); + ECORE_X_EVENT_MOUSE_IN = ecore_event_type_new(); + ECORE_X_EVENT_MOUSE_OUT = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_FOCUS_IN = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_FOCUS_OUT = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_KEYMAP = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_DAMAGE = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_CREATE = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_DESTROY = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_HIDE = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_SHOW = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_SHOW_REQUEST = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_REPARENT = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_CONFIGURE = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_CONFIGURE_REQUEST = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_GRAVITY = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_RESIZE_REQUEST = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_STACK = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_STACK_REQUEST = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_PROPERTY = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_COLORMAP = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_MAPPING = ecore_event_type_new(); + ECORE_X_EVENT_MAPPING_CHANGE = ecore_event_type_new(); + ECORE_X_EVENT_SELECTION_CLEAR = ecore_event_type_new(); + ECORE_X_EVENT_SELECTION_REQUEST = ecore_event_type_new(); + ECORE_X_EVENT_SELECTION_NOTIFY = ecore_event_type_new(); + ECORE_X_EVENT_CLIENT_MESSAGE = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_SHAPE = ecore_event_type_new(); + ECORE_X_EVENT_SCREENSAVER_NOTIFY = ecore_event_type_new(); + ECORE_X_EVENT_GESTURE_NOTIFY_FLICK = ecore_event_type_new(); + ECORE_X_EVENT_GESTURE_NOTIFY_PAN = ecore_event_type_new(); + ECORE_X_EVENT_GESTURE_NOTIFY_PINCHROTATION = ecore_event_type_new(); + ECORE_X_EVENT_GESTURE_NOTIFY_TAP = ecore_event_type_new(); + ECORE_X_EVENT_GESTURE_NOTIFY_TAPNHOLD = ecore_event_type_new(); + ECORE_X_EVENT_GESTURE_NOTIFY_HOLD = ecore_event_type_new(); + ECORE_X_EVENT_GESTURE_NOTIFY_GROUP = ecore_event_type_new(); + ECORE_X_EVENT_SYNC_COUNTER = ecore_event_type_new(); + ECORE_X_EVENT_SYNC_ALARM = ecore_event_type_new(); + ECORE_X_EVENT_SCREEN_CHANGE = ecore_event_type_new(); + ECORE_X_EVENT_RANDR_CRTC_CHANGE = ecore_event_type_new(); + ECORE_X_EVENT_RANDR_OUTPUT_CHANGE = ecore_event_type_new(); + ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY = ecore_event_type_new(); + ECORE_X_EVENT_DAMAGE_NOTIFY = ecore_event_type_new(); + + ECORE_X_EVENT_WINDOW_DELETE_REQUEST = ecore_event_type_new(); + + ECORE_X_EVENT_DESKTOP_CHANGE = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_MOVE_RESIZE_REQUEST = ecore_event_type_new(); + ECORE_X_EVENT_WINDOW_STATE_REQUEST = ecore_event_type_new(); + ECORE_X_EVENT_FRAME_EXTENTS_REQUEST = ecore_event_type_new(); + ECORE_X_EVENT_PING = ecore_event_type_new(); + + ECORE_X_EVENT_STARTUP_SEQUENCE_NEW = ecore_event_type_new(); + ECORE_X_EVENT_STARTUP_SEQUENCE_CHANGE = ecore_event_type_new(); + ECORE_X_EVENT_STARTUP_SEQUENCE_REMOVE = ecore_event_type_new(); + + ECORE_X_EVENT_XKB_STATE_NOTIFY = ecore_event_type_new(); + ECORE_X_EVENT_XKB_NEWKBD_NOTIFY = ecore_event_type_new(); + + ECORE_X_EVENT_GENERIC = ecore_event_type_new(); + } + + _ecore_x_modifiers_get(); + + _ecore_x_fd_handler_handle = + ecore_main_fd_handler_add(ConnectionNumber(_ecore_x_disp), + ECORE_FD_READ, + _ecore_x_fd_handler, _ecore_x_disp, + _ecore_x_fd_handler_buf, _ecore_x_disp); + if (!_ecore_x_fd_handler_handle) + goto free_event_handlers; + + _ecore_x_atoms_init(); + + /* Set up the ICCCM hints */ + ecore_x_icccm_init(); + + /* Set up the _NET_... hints */ + ecore_x_netwm_init(); + + /* old e hints init */ + ecore_x_e_init(); + + /* This is just to be anal about naming conventions */ + + _ecore_x_atoms_wm_protocols[ECORE_X_WM_PROTOCOL_DELETE_REQUEST] = + ECORE_X_ATOM_WM_DELETE_WINDOW; + _ecore_x_atoms_wm_protocols[ECORE_X_WM_PROTOCOL_TAKE_FOCUS] = + ECORE_X_ATOM_WM_TAKE_FOCUS; + _ecore_x_atoms_wm_protocols[ECORE_X_NET_WM_PROTOCOL_PING] = + ECORE_X_ATOM_NET_WM_PING; + _ecore_x_atoms_wm_protocols[ECORE_X_NET_WM_PROTOCOL_SYNC_REQUEST] = + ECORE_X_ATOM_NET_WM_SYNC_REQUEST; + + _ecore_x_selection_data_init(); + _ecore_x_dnd_init(); + _ecore_x_fixes_init(); + _ecore_x_damage_init(); + _ecore_x_composite_init(); + _ecore_x_dpms_init(); + _ecore_x_randr_init(); + _ecore_x_gesture_init(); + _ecore_x_input_init(); + _ecore_x_events_init(); + + _ecore_x_private_win = ecore_x_window_override_new(0, -77, -777, 123, 456); + + return _ecore_x_init_count; + +free_event_handlers: + free(_ecore_x_event_handlers); + _ecore_x_event_handlers = NULL; +close_display: + XCloseDisplay(_ecore_x_disp); + _ecore_x_fd_handler_handle = NULL; + _ecore_x_disp = NULL; +shutdown_ecore_event: + ecore_event_shutdown(); +shutdown_ecore: + ecore_shutdown(); +shutdown_eina: + eina_log_domain_unregister(_ecore_xlib_log_dom); + _ecore_xlib_log_dom = -1; + eina_shutdown(); + + return --_ecore_x_init_count; +} + +static int +_ecore_x_shutdown(int close_display) +{ + if (--_ecore_x_init_count != 0) + return _ecore_x_init_count; + + if (!_ecore_x_disp) + return _ecore_x_init_count; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_main_fd_handler_del(_ecore_x_fd_handler_handle); + if (close_display) + XCloseDisplay(_ecore_x_disp); + else + { + close(ConnectionNumber(_ecore_x_disp)); + // FIXME: may have to clean up x display internal here +// getting segv here? hmmm. odd. disable +// XFree(_ecore_x_disp); + } + + free(_ecore_x_event_handlers); + _ecore_x_fd_handler_handle = NULL; + _ecore_x_disp = NULL; + _ecore_x_event_handlers = NULL; + _ecore_x_events_shutdown(); + _ecore_x_input_shutdown(); + _ecore_x_selection_shutdown(); + _ecore_x_dnd_shutdown(); + ecore_x_netwm_shutdown(); + + ecore_event_shutdown(); + ecore_shutdown(); + + eina_log_domain_unregister(_ecore_xlib_log_dom); + _ecore_xlib_log_dom = -1; + eina_shutdown(); + + return _ecore_x_init_count; +} + +/** + * Shuts down the Ecore X library. + * + * In shutting down the library, the X display connection is terminated + * and any event handlers for it are removed. + * + * @return The number of times the library has been initialized without + * being shut down. 0 is returned if an error occurs. + * @ingroup Ecore_X_Init_Group + */ +EAPI int +ecore_x_shutdown(void) +{ + return _ecore_x_shutdown(1); +} + +/** + * Shuts down the Ecore X library. + * + * As ecore_x_shutdown, except do not close Display, only connection. + * + * @ingroup Ecore_X_Init_Group + */ +EAPI int +ecore_x_disconnect(void) +{ + return _ecore_x_shutdown(0); +} + +/** + * @defgroup Ecore_X_Display_Attr_Group X Display Attributes + * + * Functions that set and retrieve X display attributes. + */ + +/** + * Retrieves the Ecore_X_Display handle used for the current X connection. + * @return The current X display. + * @ingroup Ecore_X_Display_Attr_Group + */ +EAPI Ecore_X_Display * +ecore_x_display_get(void) +{ + return (Ecore_X_Display *)_ecore_x_disp; +} + +/** + * Retrieves the X display file descriptor. + * @return The current X display file descriptor. + * @ingroup Ecore_X_Display_Attr_Group + */ +EAPI int +ecore_x_fd_get(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return ConnectionNumber(_ecore_x_disp); +} + +/** + * Retrieves the Ecore_X_Screen handle used for the current X connection. + * @return The current default screen. + * @ingroup Ecore_X_Display_Attr_Group + */ +EAPI Ecore_X_Screen * +ecore_x_default_screen_get(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return (Ecore_X_Screen *)DefaultScreenOfDisplay(_ecore_x_disp); +} + +/** + * Retrieves the size of an Ecore_X_Screen. + * @param screen the handle to the screen to query. + * @param w where to return the width. May be NULL. Returns 0 on errors. + * @param h where to return the height. May be NULL. Returns 0 on errors. + * @ingroup Ecore_X_Display_Attr_Group + * @see ecore_x_default_screen_get() + * + * @since 1.1 + */ +EAPI void +ecore_x_screen_size_get(const Ecore_X_Screen *screen, + int *w, + int *h) +{ + Screen *s = (Screen *)screen; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (w) *w = 0; + if (h) *h = 0; + if (!s) return; + if (w) *w = s->width; + if (h) *h = s->height; +} + +/** + * Retrieves the number of screens. + * + * @return The count of the number of screens. + * @ingroup Ecore_X_Display_Attr_Group + * + * @since 1.1 + */ +EAPI int +ecore_x_screen_count_get(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return ScreenCount(_ecore_x_disp); +} + +/** + * Retrieves the index number of the given screen. + * + * @param screen The screen for which the index will be retrieved. + * @return The index number of the screen. + * @ingroup Ecore_X_Display_Attr_Group + * + * @since 1.1 + */ +EAPI int +ecore_x_screen_index_get(const Ecore_X_Screen *screen) +{ + return XScreenNumberOfScreen((Screen *)screen); +} + +/** + * Retrieves the screen based on index number. + * + * @param idx The index that will be used to retrieve the screen. + * @return The Ecore_X_Screen at this index. + * @ingroup Ecore_X_Display_Attr_Group + * + * @since 1.1 + */ +EAPI Ecore_X_Screen * +ecore_x_screen_get(int idx) +{ + return XScreenOfDisplay(_ecore_x_disp, idx); +} + +/** + * Sets the timeout for a double and triple clicks to be flagged. + * + * This sets the time between clicks before the double_click flag is + * set in a button down event. If 3 clicks occur within double this + * time, the triple_click flag is also set. + * + * @param t The time in seconds + * @ingroup Ecore_X_Display_Attr_Group + */ +EAPI void +ecore_x_double_click_time_set(double t) +{ + if (t < 0.0) + t = 0.0; + + _ecore_x_double_click_time = t; +} + +/** + * Retrieves the double and triple click flag timeout. + * + * See @ref ecore_x_double_click_time_set for more information. + * + * @return The timeout for double clicks in seconds. + * @ingroup Ecore_X_Display_Attr_Group + */ +EAPI double +ecore_x_double_click_time_get(void) +{ + return _ecore_x_double_click_time; +} + +/** + * @defgroup Ecore_X_Flush_Group X Synchronization Functions + * + * Functions that ensure that all commands that have been issued by the + * Ecore X library have been sent to the server. + */ + +/** + * Sends all X commands in the X Display buffer. + * @ingroup Ecore_X_Flush_Group + */ +EAPI void +ecore_x_flush(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XFlush(_ecore_x_disp); +} + +/** + * Flushes the command buffer and waits until all requests have been + * processed by the server. + * @ingroup Ecore_X_Flush_Group + */ +EAPI void +ecore_x_sync(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XSync(_ecore_x_disp, False); +} + +/** + * Kill all clients with subwindows under a given window. + * + * You can kill all clients connected to the X server by using + * @ref ecore_x_window_root_list to get a list of root windows, and + * then passing each root window to this function. + * + * @param root The window whose children will be killed. + */ +EAPI void +ecore_x_killall(Ecore_X_Window root) +{ + unsigned int j; + Window root_r; + Window parent_r; + Window *children_r = NULL; + unsigned int num_children = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XGrabServer(_ecore_x_disp); + /* Tranverse window tree starting from root, and drag each + * before the firing squad */ + while (XQueryTree(_ecore_x_disp, root, &root_r, &parent_r, + &children_r, &num_children) && (num_children > 0)) + { + for (j = 0; j < num_children; ++j) + { + XKillClient(_ecore_x_disp, children_r[j]); + } + + XFree(children_r); + } + XUngrabServer(_ecore_x_disp); + XSync(_ecore_x_disp, False); +} + +/** + * Kill a specific client + * + * You can kill a specific client owning window @p win + * + * @param win Window of the client to be killed + */ +EAPI void +ecore_x_kill(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XKillClient(_ecore_x_disp, win); +} + +/** + * Return the last event time + */ +EAPI Ecore_X_Time +ecore_x_current_time_get(void) +{ + return _ecore_x_event_last_time; +} + +/** + * Return the screen DPI + * + * This is a simplistic call to get DPI. It does not account for differing + * DPI in the x amd y axes nor does it account for multihead or xinerama and + * xrander where different parts of the screen may have different DPI etc. + * + * @return the general screen DPI (dots/pixels per inch). + */ +EAPI int +ecore_x_dpi_get(void) +{ + Screen *s; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + s = DefaultScreenOfDisplay(_ecore_x_disp); + if (s->mwidth <= 0) + return 75; + + return (((s->width * 254) / s->mwidth) + 5) / 10; +} + +/** + * Invoke the standard system beep to alert users + * + * @param percent The volume at which the bell rings. Must be in the range + * [-100,+100]. If percent >= 0, the final volume will be: + * base - [(base * percent) / 100] + percent + * Otherwise, it's calculated as: + * base + [(base * percent) / 100] + * where @c base is the bell's base volume as set by XChangeKeyboardControl(3). + * + * @returns @c EINA_TRUE on success, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_x_bell(int percent) +{ + int ret; + + ret = XBell(_ecore_x_disp, percent); + if (ret == BadValue) + return EINA_FALSE; + + return EINA_TRUE; +} + +static Eina_Bool +_ecore_x_fd_handler(void *data, + Ecore_Fd_Handler *fd_handler __UNUSED__) +{ + Display *d; + + d = data; + while (XPending(d)) + { + XEvent ev; + + XNextEvent(d, &ev); +#ifdef ENABLE_XIM + /* Filter event for XIM */ + if (XFilterEvent(&ev, ev.xkey.window)) + continue; + +#endif /* ifdef ENABLE_XIM */ + if ((ev.type >= 0) && (ev.type < _ecore_x_event_handlers_num)) + { + if (_ecore_x_event_handlers[AnyXEvent]) + _ecore_x_event_handlers[AnyXEvent] (&ev); + + if (_ecore_x_event_handlers[ev.type]) + _ecore_x_event_handlers[ev.type] (&ev); + } + } + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +_ecore_x_fd_handler_buf(void *data, + Ecore_Fd_Handler *fd_handler __UNUSED__) +{ + Display *d; + + d = data; + if (XPending(d)) + return ECORE_CALLBACK_RENEW; + + return ECORE_CALLBACK_CANCEL; +} + +static int +_ecore_x_key_mask_get(KeySym sym) +{ + XModifierKeymap *mod; + KeySym sym2; + int i, j; + const int masks[8] = + { + ShiftMask, LockMask, ControlMask, + Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask + }; + + mod = XGetModifierMapping(_ecore_x_disp); + if ((mod) && (mod->max_keypermod > 0)) + for (i = 0; i < (8 * mod->max_keypermod); i++) + { + for (j = 0; j < 8; j++) + { + sym2 = _ecore_x_XKeycodeToKeysym(_ecore_x_disp, + mod->modifiermap[i], j); + if (sym2 != 0) + break; + } + if (sym2 == sym) + { + int mask; + + mask = masks[i / mod->max_keypermod]; + if (mod->modifiermap) + XFree(mod->modifiermap); + + XFree(mod); + return mask; + } + } + + if (mod) + { + if (mod->modifiermap) + XFree(mod->modifiermap); + + XFree(mod); + } + + return 0; +} + +/*****************************************************************************/ +/*****************************************************************************/ +/*****************************************************************************/ +/* FIXME: these funcs need categorising */ +/*****************************************************************************/ + +/** + * Get a list of all the root windows on the server. + * + * @note The returned array will need to be freed after use. + * @param num_ret Pointer to integer to put number of windows returned in. + * @return An array of all the root windows. @c NULL is returned if memory + * could not be allocated for the list, or if @p num_ret is @c NULL. + */ +EAPI Ecore_X_Window * +ecore_x_window_root_list(int *num_ret) +{ + int num, i; + Ecore_X_Window *roots; +#ifdef ECORE_XPRINT + int xp_base, xp_err_base; +#endif /* ifdef ECORE_XPRINT */ + + if (!num_ret) + return NULL; + + *num_ret = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); +#ifdef ECORE_XPRINT + num = ScreenCount(_ecore_x_disp); + if (XpQueryExtension(_ecore_x_disp, &xp_base, &xp_err_base)) + { + Screen **ps = NULL; + int psnum = 0; + + ps = XpQueryScreens(_ecore_x_disp, &psnum); + if (ps) + { + int overlap, j; + + overlap = 0; + for (i = 0; i < num; i++) + { + for (j = 0; j < psnum; j++) + { + if (ScreenOfDisplay(_ecore_x_disp, i) == ps[j]) + overlap++; + } + } + roots = malloc(MAX((num - overlap) * sizeof(Window), 1)); + if (roots) + { + int k; + + k = 0; + for (i = 0; i < num; i++) + { + int is_print; + + is_print = 0; + for (j = 0; j < psnum; j++) + { + if (ScreenOfDisplay(_ecore_x_disp, i) == ps[j]) + { + is_print = 1; + break; + } + } + if (!is_print) + { + roots[k] = RootWindow(_ecore_x_disp, i); + k++; + } + } + *num_ret = k; + } + + XFree(ps); + } + else + { + roots = malloc(num * sizeof(Window)); + if (!roots) + return NULL; + + *num_ret = num; + for (i = 0; i < num; i++) + roots[i] = RootWindow(_ecore_x_disp, i); + } + } + else + { + roots = malloc(num * sizeof(Window)); + if (!roots) + return NULL; + + *num_ret = num; + for (i = 0; i < num; i++) + roots[i] = RootWindow(_ecore_x_disp, i); + } + +#else /* ifdef ECORE_XPRINT */ + num = ScreenCount(_ecore_x_disp); + roots = malloc(num * sizeof(Window)); + if (!roots) + return NULL; + + *num_ret = num; + for (i = 0; i < num; i++) + roots[i] = RootWindow(_ecore_x_disp, i); +#endif /* ifdef ECORE_XPRINT */ + return roots; +} + +EAPI Ecore_X_Window +ecore_x_window_root_first_get(void) +{ + return RootWindow(_ecore_x_disp, 0); +/* + int num; + Ecore_X_Window root, *roots = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + roots = ecore_x_window_root_list(&num); + if (!(roots)) return 0; + + if (num > 0) + root = roots[0]; + else + root = 0; + + free(roots); + return root; + */ +} + +static void _ecore_x_window_manage_error(void *data); + +static int _ecore_x_window_manage_failed = 0; +static void +_ecore_x_window_manage_error(void *data __UNUSED__) +{ + if ((ecore_x_error_request_get() == X_ChangeWindowAttributes) && + (ecore_x_error_code_get() == BadAccess)) + _ecore_x_window_manage_failed = 1; +} + +EAPI Eina_Bool +ecore_x_window_manage(Ecore_X_Window win) +{ + XWindowAttributes att; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (XGetWindowAttributes(_ecore_x_disp, win, &att) != True) + return EINA_FALSE; + + ecore_x_sync(); + _ecore_x_window_manage_failed = 0; + ecore_x_error_handler_set(_ecore_x_window_manage_error, NULL); + XSelectInput(_ecore_x_disp, win, + EnterWindowMask | + LeaveWindowMask | + PropertyChangeMask | + ResizeRedirectMask | + SubstructureRedirectMask | + SubstructureNotifyMask | + StructureNotifyMask | + KeyPressMask | + KeyReleaseMask | + att.your_event_mask); + ecore_x_sync(); + ecore_x_error_handler_set(NULL, NULL); + if (_ecore_x_window_manage_failed) + { + _ecore_x_window_manage_failed = 0; + return EINA_FALSE; + } + + return EINA_TRUE; +} + +EAPI void +ecore_x_window_container_manage(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XSelectInput(_ecore_x_disp, win, + SubstructureRedirectMask | + SubstructureNotifyMask); +} + +EAPI void +ecore_x_window_client_manage(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XSelectInput(_ecore_x_disp, win, + PropertyChangeMask | +// ResizeRedirectMask | + FocusChangeMask | + ColormapChangeMask | + VisibilityChangeMask | + StructureNotifyMask | + SubstructureNotifyMask + ); + XShapeSelectInput(_ecore_x_disp, win, ShapeNotifyMask); +} + +EAPI void +ecore_x_window_sniff(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XSelectInput(_ecore_x_disp, win, + PropertyChangeMask | + SubstructureNotifyMask); +} + +EAPI void +ecore_x_window_client_sniff(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XSelectInput(_ecore_x_disp, win, + PropertyChangeMask | + FocusChangeMask | + ColormapChangeMask | + VisibilityChangeMask | + StructureNotifyMask | + SubstructureNotifyMask); + XShapeSelectInput(_ecore_x_disp, win, ShapeNotifyMask); +} + +EAPI Eina_Bool +ecore_x_window_attributes_get(Ecore_X_Window win, + Ecore_X_Window_Attributes *att_ret) +{ + XWindowAttributes att; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!XGetWindowAttributes(_ecore_x_disp, win, &att)) + return EINA_FALSE; + + memset(att_ret, 0, sizeof(Ecore_X_Window_Attributes)); + att_ret->root = att.root; + att_ret->x = att.x; + att_ret->y = att.y; + att_ret->w = att.width; + att_ret->h = att.height; + att_ret->border = att.border_width; + att_ret->depth = att.depth; + if (att.map_state != IsUnmapped) + att_ret->visible = 1; + + if (att.map_state == IsViewable) + att_ret->viewable = 1; + + if (att.override_redirect) + att_ret->override = 1; + + if (att.class == InputOnly) + att_ret->input_only = 1; + + if (att.save_under) + att_ret->save_under = 1; + + att_ret->event_mask.mine = att.your_event_mask; + att_ret->event_mask.all = att.all_event_masks; + att_ret->event_mask.no_propagate = att.do_not_propagate_mask; + att_ret->window_gravity = att.win_gravity; + att_ret->pixel_gravity = att.bit_gravity; + att_ret->colormap = att.colormap; + att_ret->visual = att.visual; + return EINA_TRUE; +} + +EAPI void +ecore_x_window_save_set_add(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XAddToSaveSet(_ecore_x_disp, win); +} + +EAPI void +ecore_x_window_save_set_del(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XRemoveFromSaveSet(_ecore_x_disp, win); +} + +EAPI Ecore_X_Window * +ecore_x_window_children_get(Ecore_X_Window win, + int *num) +{ + Ecore_X_Window *windows = NULL; + Window root_ret = 0, parent_ret = 0, *children_ret = NULL; + unsigned int children_ret_num = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!XQueryTree(_ecore_x_disp, win, &root_ret, &parent_ret, &children_ret, + &children_ret_num)) + return NULL; + + if (children_ret) + { + windows = malloc(children_ret_num * sizeof(Ecore_X_Window)); + if (windows) + { + unsigned int i; + + for (i = 0; i < children_ret_num; i++) + windows[i] = children_ret[i]; + *num = children_ret_num; + } + + XFree(children_ret); + } + + return windows; +} + +EAPI Eina_Bool +ecore_x_pointer_control_set(int accel_num, + int accel_denom, + int threshold) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return XChangePointerControl(_ecore_x_disp, 1, 1, + accel_num, accel_denom, threshold) ? EINA_TRUE : EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_pointer_control_get(int *accel_num, + int *accel_denom, + int *threshold) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return XGetPointerControl(_ecore_x_disp, + accel_num, accel_denom, threshold) ? EINA_TRUE : EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_pointer_mapping_set(unsigned char *map, + int nmap) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return (XSetPointerMapping(_ecore_x_disp, map, nmap) == MappingSuccess) ? EINA_TRUE : EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_pointer_mapping_get(unsigned char *map, + int nmap) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return XGetPointerMapping(_ecore_x_disp, map, nmap) ? EINA_TRUE : EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_pointer_grab(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (XGrabPointer(_ecore_x_disp, win, False, + ButtonPressMask | ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask | PointerMotionMask, + GrabModeAsync, GrabModeAsync, + None, None, CurrentTime) == GrabSuccess) + return EINA_TRUE; + + return EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_pointer_confine_grab(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (XGrabPointer(_ecore_x_disp, win, False, + ButtonPressMask | ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask | PointerMotionMask, + GrabModeAsync, GrabModeAsync, + win, None, CurrentTime) == GrabSuccess) + return EINA_TRUE; + + return EINA_FALSE; +} + +EAPI void +ecore_x_pointer_ungrab(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XUngrabPointer(_ecore_x_disp, CurrentTime); +} + +EAPI Eina_Bool +ecore_x_pointer_warp(Ecore_X_Window win, + int x, + int y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return XWarpPointer(_ecore_x_disp, None, win, 0, 0, 0, 0, x, y) ? EINA_TRUE : EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_keyboard_grab(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (XGrabKeyboard(_ecore_x_disp, win, False, + GrabModeAsync, GrabModeAsync, + CurrentTime) == GrabSuccess) + return EINA_TRUE; + + return EINA_FALSE; +} + +EAPI void +ecore_x_keyboard_ungrab(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XUngrabKeyboard(_ecore_x_disp, CurrentTime); +} + +EAPI void +ecore_x_grab(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _ecore_x_grab_count++; + if (_ecore_x_grab_count == 1) + XGrabServer(_ecore_x_disp); +} + +EAPI void +ecore_x_ungrab(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _ecore_x_grab_count--; + if (_ecore_x_grab_count < 0) + _ecore_x_grab_count = 0; + + if (_ecore_x_grab_count == 0) + XUngrabServer(_ecore_x_disp); +} + +int _ecore_window_grabs_num = 0; +Window *_ecore_window_grabs = NULL; +Eina_Bool (*_ecore_window_grab_replay_func)(void *data, + int event_type, + void *event); +void *_ecore_window_grab_replay_data; + +EAPI void +ecore_x_passive_grab_replay_func_set(Eina_Bool (*func)(void *data, + int event_type, + void *event), + void *data) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _ecore_window_grab_replay_func = func; + _ecore_window_grab_replay_data = data; +} + +EAPI void +ecore_x_window_button_grab(Ecore_X_Window win, + int button, + Ecore_X_Event_Mask event_mask, + int mod, + int any_mod) +{ + unsigned int b; + unsigned int m; + unsigned int locks[8]; + int i, ev; + Window *t; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + b = button; + if (b == 0) + b = AnyButton; + + m = _ecore_x_event_modifier(mod); + if (any_mod) + m = AnyModifier; + + locks[0] = 0; + locks[1] = ECORE_X_LOCK_CAPS; + locks[2] = ECORE_X_LOCK_NUM; + locks[3] = ECORE_X_LOCK_SCROLL; + locks[4] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM; + locks[5] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_SCROLL; + locks[6] = ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL; + locks[7] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL; + ev = event_mask; + for (i = 0; i < 8; i++) + XGrabButton(_ecore_x_disp, b, m | locks[i], + win, False, ev, GrabModeSync, GrabModeAsync, None, None); + _ecore_window_grabs_num++; + t = realloc(_ecore_window_grabs, + _ecore_window_grabs_num * sizeof(Window)); + if (!t) return; + _ecore_window_grabs = t; + _ecore_window_grabs[_ecore_window_grabs_num - 1] = win; +} + +void +_ecore_x_sync_magic_send(int val, + Ecore_X_Window swin) +{ + XEvent xev; + + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.display = _ecore_x_disp; + xev.xclient.window = _ecore_x_private_win; + xev.xclient.format = 32; + xev.xclient.message_type = 27777; + xev.xclient.data.l[0] = 0x7162534; + xev.xclient.data.l[1] = 0x10000000 + val; + xev.xclient.data.l[2] = swin; + XSendEvent(_ecore_x_disp, _ecore_x_private_win, False, NoEventMask, &xev); +} + +void +_ecore_x_window_grab_remove(Ecore_X_Window win) +{ + int i, shuffle = 0; + Window *t; + + if (_ecore_window_grabs_num > 0) + { + for (i = 0; i < _ecore_window_grabs_num; i++) + { + if (shuffle) + _ecore_window_grabs[i - 1] = _ecore_window_grabs[i]; + + if ((!shuffle) && (_ecore_window_grabs[i] == win)) + shuffle = 1; + } + if (shuffle) + { + _ecore_window_grabs_num--; + if (_ecore_window_grabs_num <= 0) + { + free(_ecore_window_grabs); + _ecore_window_grabs = NULL; + return; + } + t = realloc(_ecore_window_grabs, + _ecore_window_grabs_num * + sizeof(Window)); + if (!t) return; + _ecore_window_grabs = t; + } + } +} + +EAPI void +ecore_x_window_button_ungrab(Ecore_X_Window win, + int button, + int mod, + int any_mod) +{ + unsigned int b; + unsigned int m; + unsigned int locks[8]; + int i; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + b = button; + if (b == 0) + b = AnyButton; + + m = _ecore_x_event_modifier(mod); + if (any_mod) + m = AnyModifier; + + locks[0] = 0; + locks[1] = ECORE_X_LOCK_CAPS; + locks[2] = ECORE_X_LOCK_NUM; + locks[3] = ECORE_X_LOCK_SCROLL; + locks[4] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM; + locks[5] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_SCROLL; + locks[6] = ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL; + locks[7] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL; + for (i = 0; i < 8; i++) + XUngrabButton(_ecore_x_disp, b, m | locks[i], win); + _ecore_x_sync_magic_send(1, win); +} + +int _ecore_key_grabs_num = 0; +Window *_ecore_key_grabs = NULL; + +EAPI void +ecore_x_window_key_grab(Ecore_X_Window win, + const char *key, + int mod, + int any_mod) +{ + KeyCode keycode = 0; + KeySym keysym; + unsigned int m; + unsigned int locks[8]; + int i; + Window *t; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!strncmp(key, "Keycode-", 8)) + keycode = atoi(key + 8); + else + { + keysym = XStringToKeysym(key); + if (keysym == NoSymbol) + return; + + keycode = XKeysymToKeycode(_ecore_x_disp, XStringToKeysym(key)); + } + + if (keycode == 0) + return; + + m = _ecore_x_event_modifier(mod); + if (any_mod) + m = AnyModifier; + + locks[0] = 0; + locks[1] = ECORE_X_LOCK_CAPS; + locks[2] = ECORE_X_LOCK_NUM; + locks[3] = ECORE_X_LOCK_SCROLL; + locks[4] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM; + locks[5] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_SCROLL; + locks[6] = ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL; + locks[7] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL; + for (i = 0; i < 8; i++) + XGrabKey(_ecore_x_disp, keycode, m | locks[i], + win, False, GrabModeSync, GrabModeAsync); + _ecore_key_grabs_num++; + t = realloc(_ecore_key_grabs, + _ecore_key_grabs_num * sizeof(Window)); + if (!t) return; + _ecore_key_grabs = t; + _ecore_key_grabs[_ecore_key_grabs_num - 1] = win; +} + +void +_ecore_x_key_grab_remove(Ecore_X_Window win) +{ + int i, shuffle = 0; + Window *t; + + if (_ecore_key_grabs_num > 0) + { + for (i = 0; i < _ecore_key_grabs_num; i++) + { + if (shuffle) + _ecore_key_grabs[i - 1] = _ecore_key_grabs[i]; + + if ((!shuffle) && (_ecore_key_grabs[i] == win)) + shuffle = 1; + } + if (shuffle) + { + _ecore_key_grabs_num--; + if (_ecore_key_grabs_num <= 0) + { + free(_ecore_key_grabs); + _ecore_key_grabs = NULL; + return; + } + t = realloc(_ecore_key_grabs, + _ecore_key_grabs_num * sizeof(Window)); + if (!t) return; + _ecore_key_grabs = t; + } + } +} + +EAPI void +ecore_x_window_key_ungrab(Ecore_X_Window win, + const char *key, + int mod, + int any_mod) +{ + KeyCode keycode = 0; + KeySym keysym; + unsigned int m; + unsigned int locks[8]; + int i; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!strncmp(key, "Keycode-", 8)) + keycode = atoi(key + 8); + else + { + keysym = XStringToKeysym(key); + if (keysym == NoSymbol) + return; + + keycode = XKeysymToKeycode(_ecore_x_disp, XStringToKeysym(key)); + } + + if (keycode == 0) + return; + + m = _ecore_x_event_modifier(mod); + if (any_mod) + m = AnyModifier; + + locks[0] = 0; + locks[1] = ECORE_X_LOCK_CAPS; + locks[2] = ECORE_X_LOCK_NUM; + locks[3] = ECORE_X_LOCK_SCROLL; + locks[4] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM; + locks[5] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_SCROLL; + locks[6] = ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL; + locks[7] = ECORE_X_LOCK_CAPS | ECORE_X_LOCK_NUM | ECORE_X_LOCK_SCROLL; + for (i = 0; i < 8; i++) + XUngrabKey(_ecore_x_disp, keycode, m | locks[i], win); + _ecore_x_sync_magic_send(2, win); +} + +/** + * Send client message with given type and format 32. + * + * @param win The window the message is sent to. + * @param type The client message type. + * @param mask The mask of the message to be sent. + * @param d0 The client message data item 1 + * @param d1 The client message data item 2 + * @param d2 The client message data item 3 + * @param d3 The client message data item 4 + * @param d4 The client message data item 5 + * + * @return @c EINA_TRUE on success @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_x_client_message32_send(Ecore_X_Window win, + Ecore_X_Atom type, + Ecore_X_Event_Mask mask, + long d0, + long d1, + long d2, + long d3, + long d4) +{ + XEvent xev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + xev.xclient.window = win; + xev.xclient.type = ClientMessage; + xev.xclient.message_type = type; + xev.xclient.format = 32; + xev.xclient.data.l[0] = d0; + xev.xclient.data.l[1] = d1; + xev.xclient.data.l[2] = d2; + xev.xclient.data.l[3] = d3; + xev.xclient.data.l[4] = d4; + + return XSendEvent(_ecore_x_disp, win, False, mask, &xev) ? EINA_TRUE : EINA_FALSE; +} + +/** + * Send client message with given type and format 8. + * + * @param win The window the message is sent to. + * @param type The client message type. + * @param data Data to be sent. + * @param len Number of data bytes, max @c 20. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_x_client_message8_send(Ecore_X_Window win, + Ecore_X_Atom type, + const void *data, + int len) +{ + XEvent xev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + xev.xclient.window = win; + xev.xclient.type = ClientMessage; + xev.xclient.message_type = type; + xev.xclient.format = 8; + if (len > 20) + len = 20; + + memcpy(xev.xclient.data.b, data, len); + memset(xev.xclient.data.b + len, 0, 20 - len); + + return XSendEvent(_ecore_x_disp, win, False, NoEventMask, &xev) ? EINA_TRUE : EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_mouse_move_send(Ecore_X_Window win, + int x, + int y) +{ + XEvent xev; + XWindowAttributes att; + Window tw; + int rx, ry; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XGetWindowAttributes(_ecore_x_disp, win, &att); + XTranslateCoordinates(_ecore_x_disp, win, att.root, x, y, &rx, &ry, &tw); + xev.xmotion.type = MotionNotify; + xev.xmotion.window = win; + xev.xmotion.root = att.root; + xev.xmotion.subwindow = win; + xev.xmotion.time = _ecore_x_event_last_time; + xev.xmotion.x = x; + xev.xmotion.y = y; + xev.xmotion.x_root = rx; + xev.xmotion.y_root = ry; + xev.xmotion.state = 0; + xev.xmotion.is_hint = 0; + xev.xmotion.same_screen = 1; + return XSendEvent(_ecore_x_disp, win, True, PointerMotionMask, &xev) ? EINA_TRUE : EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_mouse_down_send(Ecore_X_Window win, + int x, + int y, + int b) +{ + XEvent xev; + XWindowAttributes att; + Window tw; + int rx, ry; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XGetWindowAttributes(_ecore_x_disp, win, &att); + XTranslateCoordinates(_ecore_x_disp, win, att.root, x, y, &rx, &ry, &tw); + xev.xbutton.type = ButtonPress; + xev.xbutton.window = win; + xev.xbutton.root = att.root; + xev.xbutton.subwindow = win; + xev.xbutton.time = _ecore_x_event_last_time; + xev.xbutton.x = x; + xev.xbutton.y = y; + xev.xbutton.x_root = rx; + xev.xbutton.y_root = ry; + xev.xbutton.state = 1 << b; + xev.xbutton.button = b; + xev.xbutton.same_screen = 1; + return XSendEvent(_ecore_x_disp, win, True, ButtonPressMask, &xev) ? EINA_TRUE : EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_mouse_up_send(Ecore_X_Window win, + int x, + int y, + int b) +{ + XEvent xev; + XWindowAttributes att; + Window tw; + int rx, ry; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XGetWindowAttributes(_ecore_x_disp, win, &att); + XTranslateCoordinates(_ecore_x_disp, win, att.root, x, y, &rx, &ry, &tw); + xev.xbutton.type = ButtonRelease; + xev.xbutton.window = win; + xev.xbutton.root = att.root; + xev.xbutton.subwindow = win; + xev.xbutton.time = _ecore_x_event_last_time; + xev.xbutton.x = x; + xev.xbutton.y = y; + xev.xbutton.x_root = rx; + xev.xbutton.y_root = ry; + xev.xbutton.state = 0; + xev.xbutton.button = b; + xev.xbutton.same_screen = 1; + return XSendEvent(_ecore_x_disp, win, True, ButtonReleaseMask, &xev) ? EINA_TRUE : EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_mouse_in_send(Ecore_X_Window win, + int x, + int y) +{ + XEvent xev; + XWindowAttributes att; + Window tw; + int rx, ry; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XGetWindowAttributes(_ecore_x_disp, win, &att); + XTranslateCoordinates(_ecore_x_disp, win, att.root, x, y, &rx, &ry, &tw); + xev.xcrossing.type = EnterNotify; + xev.xcrossing.window = win; + xev.xcrossing.root = att.root; + xev.xcrossing.subwindow = win; + xev.xcrossing.time = _ecore_x_event_last_time; + xev.xcrossing.x = x; + xev.xcrossing.y = y; + xev.xcrossing.x_root = rx; + xev.xcrossing.y_root = ry; + xev.xcrossing.mode = NotifyNormal; + xev.xcrossing.detail = NotifyNonlinear; + xev.xcrossing.same_screen = 1; + xev.xcrossing.focus = 0; + xev.xcrossing.state = 0; + return XSendEvent(_ecore_x_disp, win, True, EnterWindowMask, &xev) ? EINA_TRUE : EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_mouse_out_send(Ecore_X_Window win, + int x, + int y) +{ + XEvent xev; + XWindowAttributes att; + Window tw; + int rx, ry; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XGetWindowAttributes(_ecore_x_disp, win, &att); + XTranslateCoordinates(_ecore_x_disp, win, att.root, x, y, &rx, &ry, &tw); + xev.xcrossing.type = LeaveNotify; + xev.xcrossing.window = win; + xev.xcrossing.root = att.root; + xev.xcrossing.subwindow = win; + xev.xcrossing.time = _ecore_x_event_last_time; + xev.xcrossing.x = x; + xev.xcrossing.y = y; + xev.xcrossing.x_root = rx; + xev.xcrossing.y_root = ry; + xev.xcrossing.mode = NotifyNormal; + xev.xcrossing.detail = NotifyNonlinear; + xev.xcrossing.same_screen = 1; + xev.xcrossing.focus = 0; + xev.xcrossing.state = 0; + return XSendEvent(_ecore_x_disp, win, True, LeaveWindowMask, &xev) ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_x_focus_reset(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XSetInputFocus(_ecore_x_disp, PointerRoot, RevertToPointerRoot, CurrentTime); +} + +EAPI void +ecore_x_events_allow_all(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XAllowEvents(_ecore_x_disp, AsyncBoth, CurrentTime); +} + +EAPI void +ecore_x_pointer_last_xy_get(int *x, + int *y) +{ + if (x) + *x = _ecore_x_event_last_root_x; + + if (y) + *y = _ecore_x_event_last_root_y; +} + +EAPI void +ecore_x_pointer_xy_get(Ecore_X_Window win, + int *x, + int *y) +{ + Window rwin, cwin; + int rx, ry, wx, wy, ret; + unsigned int mask; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ret = XQueryPointer(_ecore_x_disp, win, &rwin, &cwin, + &rx, &ry, &wx, &wy, &mask); + if (!ret) + wx = wy = -1; + + if (x) *x = wx; + if (y) *y = wy; +} + +/** + * Retrieve the Visual ID from a given Visual. + * + * @param visual The Visual to get the ID for. + * + * @return The visual id. + * @since 1.1.0 + */ +EAPI unsigned int +ecore_x_visual_id_get(Ecore_X_Visual visual) +{ + return XVisualIDFromVisual(visual); +} + +/** + * Retrieve the default Visual. + * + * @param disp The Display to get the Default Visual from + * @param screen The Screen. + * + * @return The default visual. + * @since 1.1.0 + */ +EAPI Ecore_X_Visual +ecore_x_default_visual_get(Ecore_X_Display *disp, + Ecore_X_Screen *screen) +{ + return DefaultVisual(disp, ecore_x_screen_index_get(screen)); +} + +/** + * Retrieve the default Colormap. + * + * @param disp The Display to get the Default Colormap from + * @param screen The Screen. + * + * @return The default colormap. + * @since 1.1.0 + */ +EAPI Ecore_X_Colormap +ecore_x_default_colormap_get(Ecore_X_Display *disp, + Ecore_X_Screen *screen) +{ + return DefaultColormap(disp, ecore_x_screen_index_get(screen)); +} + +/** + * Retrieve the default depth. + * + * @param disp The Display to get the Default Depth from + * @param screen The Screen. + * + * @return The default depth. + * @since 1.1.0 + */ +EAPI int +ecore_x_default_depth_get(Ecore_X_Display *disp, + Ecore_X_Screen *screen) +{ + return DefaultDepth(disp, ecore_x_screen_index_get(screen)); +} + +EAPI void +ecore_x_xkb_select_group(int group) +{ +#ifdef ECORE_XKB + XkbLockGroup(_ecore_x_disp, XkbUseCoreKbd, group); +#endif +} + +/*****************************************************************************/ +/*****************************************************************************/ +/*****************************************************************************/ + +static int +_ecore_x_event_modifier(unsigned int state) +{ + int xmodifiers = 0; + + if (state & ECORE_EVENT_MODIFIER_SHIFT) + xmodifiers |= ECORE_X_MODIFIER_SHIFT; + + if (state & ECORE_EVENT_MODIFIER_CTRL) + xmodifiers |= ECORE_X_MODIFIER_CTRL; + + if (state & ECORE_EVENT_MODIFIER_ALT) + xmodifiers |= ECORE_X_MODIFIER_ALT; + + if (state & ECORE_EVENT_MODIFIER_WIN) + xmodifiers |= ECORE_X_MODIFIER_WIN; + + if (state & ECORE_EVENT_MODIFIER_ALTGR) + xmodifiers |= ECORE_X_MODIFIER_ALTGR; + + if (state & ECORE_EVENT_LOCK_SCROLL) + xmodifiers |= ECORE_X_LOCK_SCROLL; + + if (state & ECORE_EVENT_LOCK_NUM) + xmodifiers |= ECORE_X_LOCK_NUM; + + if (state & ECORE_EVENT_LOCK_CAPS) + xmodifiers |= ECORE_X_LOCK_CAPS; + + if (state & ECORE_EVENT_LOCK_SHIFT) + xmodifiers |= ECORE_X_LOCK_SHIFT; + + return xmodifiers; +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_atoms.c b/src/lib/ecore_x/xlib/ecore_x_atoms.c new file mode 100644 index 0000000..6518264 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_atoms.c @@ -0,0 +1,100 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#ifdef HAVE_ALLOCA_H +# include +#elif defined __GNUC__ +# define alloca __builtin_alloca +#elif defined _AIX +# define alloca __alloca +#elif defined _MSC_VER +# include +# define alloca _alloca +#else /* ifdef HAVE_ALLOCA_H */ +# include +# ifdef __cplusplus +extern "C" +# endif /* ifdef __cplusplus */ +void *alloca(size_t); +#endif /* ifdef HAVE_ALLOCA_H */ + +#include + +#include "Ecore.h" +#include "ecore_x_private.h" +#include "Ecore_X.h" +#include "Ecore_X_Atoms.h" +#include "ecore_x_atoms_decl.h" + +void +_ecore_x_atoms_init(void) +{ + Atom *atoms; + char **names; + int i, num; + + num = sizeof(atom_items) / sizeof(Atom_Item); + atoms = alloca(num * sizeof(Atom)); + names = alloca(num * sizeof(char *)); + for (i = 0; i < num; i++) + names[i] = (char *) atom_items[i].name; + XInternAtoms(_ecore_x_disp, names, num, False, atoms); + for (i = 0; i < num; i++) + *(atom_items[i].atom) = atoms[i]; +} + +/** + * Retrieves the atom value associated with the given name. + * @param name The given name. + * @return Associated atom value. + */ +EAPI Ecore_X_Atom +ecore_x_atom_get(const char *name) +{ + if (!_ecore_x_disp) + return 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return XInternAtom(_ecore_x_disp, name, False); +} + +EAPI void +ecore_x_atoms_get(const char **names, + int num, + Ecore_X_Atom *atoms) +{ + Atom *atoms_int; + int i; + + if (!_ecore_x_disp) + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + atoms_int = alloca(num * sizeof(Atom)); + XInternAtoms(_ecore_x_disp, (char **)names, num, False, atoms_int); + for (i = 0; i < num; i++) + atoms[i] = atoms_int[i]; +} + +EAPI char * +ecore_x_atom_name_get(Ecore_X_Atom atom) +{ + char *name; + char *xname; + + if (!_ecore_x_disp) + return NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + xname = XGetAtomName(_ecore_x_disp, atom); + if (!xname) + return NULL; + + name = strdup(xname); + XFree(xname); + + return name; +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_composite.c b/src/lib/ecore_x/xlib/ecore_x_composite.c new file mode 100644 index 0000000..b919db9 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_composite.c @@ -0,0 +1,176 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include "ecore_x_private.h" +#include "Ecore_X.h" + +static Eina_Bool _composite_available = EINA_FALSE; + +void +_ecore_x_composite_init(void) +{ + _composite_available = EINA_FALSE; + +#ifdef ECORE_XCOMPOSITE + int major, minor; + + if (XCompositeQueryVersion(_ecore_x_disp, &major, &minor)) + { +# ifdef ECORE_XRENDER + if (XRenderQueryExtension(_ecore_x_disp, &major, &minor)) + { +# ifdef ECORE_XFIXES + if (XFixesQueryVersion(_ecore_x_disp, &major, &minor)) + { + _composite_available = EINA_TRUE; + } +# endif + } +# endif + } +#endif +} + +EAPI Eina_Bool +ecore_x_composite_query(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return _composite_available; +} + +EAPI void +ecore_x_composite_redirect_window(Ecore_X_Window win, + Ecore_X_Composite_Update_Type type) +{ +#ifdef ECORE_XCOMPOSITE + int update = CompositeRedirectAutomatic; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + switch (type) + { + case ECORE_X_COMPOSITE_UPDATE_AUTOMATIC: + update = CompositeRedirectAutomatic; + break; + + case ECORE_X_COMPOSITE_UPDATE_MANUAL: + update = CompositeRedirectManual; + break; + } + XCompositeRedirectWindow(_ecore_x_disp, win, update); +#endif /* ifdef ECORE_XCOMPOSITE */ +} + +EAPI void +ecore_x_composite_redirect_subwindows(Ecore_X_Window win, + Ecore_X_Composite_Update_Type type) +{ +#ifdef ECORE_XCOMPOSITE + int update = CompositeRedirectAutomatic; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + switch (type) + { + case ECORE_X_COMPOSITE_UPDATE_AUTOMATIC: + update = CompositeRedirectAutomatic; + break; + + case ECORE_X_COMPOSITE_UPDATE_MANUAL: + update = CompositeRedirectManual; + break; + } + XCompositeRedirectSubwindows(_ecore_x_disp, win, update); +#endif /* ifdef ECORE_XCOMPOSITE */ +} + +EAPI void +ecore_x_composite_unredirect_window(Ecore_X_Window win, + Ecore_X_Composite_Update_Type type) +{ +#ifdef ECORE_XCOMPOSITE + int update = CompositeRedirectAutomatic; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + switch (type) + { + case ECORE_X_COMPOSITE_UPDATE_AUTOMATIC: + update = CompositeRedirectAutomatic; + break; + + case ECORE_X_COMPOSITE_UPDATE_MANUAL: + update = CompositeRedirectManual; + break; + } + XCompositeUnredirectWindow(_ecore_x_disp, win, update); +#endif /* ifdef ECORE_XCOMPOSITE */ +} + +EAPI void +ecore_x_composite_unredirect_subwindows(Ecore_X_Window win, + Ecore_X_Composite_Update_Type type) +{ +#ifdef ECORE_XCOMPOSITE + int update = CompositeRedirectAutomatic; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + switch (type) + { + case ECORE_X_COMPOSITE_UPDATE_AUTOMATIC: + update = CompositeRedirectAutomatic; + break; + + case ECORE_X_COMPOSITE_UPDATE_MANUAL: + update = CompositeRedirectManual; + break; + } + XCompositeUnredirectSubwindows(_ecore_x_disp, win, update); +#endif /* ifdef ECORE_XCOMPOSITE */ +} + +EAPI Ecore_X_Pixmap +ecore_x_composite_name_window_pixmap_get(Ecore_X_Window win) +{ + Ecore_X_Pixmap pixmap = None; +#ifdef ECORE_XCOMPOSITE + LOGFN(__FILE__, __LINE__, __FUNCTION__); + pixmap = XCompositeNameWindowPixmap(_ecore_x_disp, win); +#endif /* ifdef ECORE_XCOMPOSITE */ + return pixmap; +} + +EAPI void +ecore_x_composite_window_events_disable(Ecore_X_Window win) +{ +#ifdef ECORE_XCOMPOSITE + ecore_x_window_shape_input_rectangle_set(win, -1, -1, 1, 1); +#endif /* ifdef ECORE_XCOMPOSITE */ +} + +EAPI void +ecore_x_composite_window_events_enable(Ecore_X_Window win) +{ +#ifdef ECORE_XCOMPOSITE + ecore_x_window_shape_input_rectangle_set(win, 0, 0, 65535, 65535); +#endif /* ifdef ECORE_XCOMPOSITE */ +} + +EAPI Ecore_X_Window +ecore_x_composite_render_window_enable(Ecore_X_Window root) +{ + Ecore_X_Window win = 0; +#ifdef ECORE_XCOMPOSITE + win = XCompositeGetOverlayWindow(_ecore_x_disp, root); + ecore_x_composite_window_events_disable(win); +#endif /* ifdef ECORE_XCOMPOSITE */ + return win; +} + +EAPI void +ecore_x_composite_render_window_disable(Ecore_X_Window root) +{ +#ifdef ECORE_XCOMPOSITE + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XCompositeReleaseOverlayWindow(_ecore_x_disp, root); +#endif /* ifdef ECORE_XCOMPOSITE */ +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_cursor.c b/src/lib/ecore_x/xlib/ecore_x_cursor.c new file mode 100644 index 0000000..a968c56 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_cursor.c @@ -0,0 +1,246 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include + +#include "ecore_x_private.h" + +EAPI Eina_Bool +ecore_x_cursor_color_supported_get(void) +{ + return _ecore_x_xcursor; +} + +EAPI Ecore_X_Cursor +ecore_x_cursor_new(Ecore_X_Window win, + int *pixels, + int w, + int h, + int hot_x, + int hot_y) +{ +#ifdef ECORE_XCURSOR + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (_ecore_x_xcursor) + { + Cursor c; + XcursorImage *xci; + + xci = XcursorImageCreate(w, h); + if (xci) + { + int i; + + xci->xhot = hot_x; + xci->yhot = hot_y; + xci->delay = 0; + for (i = 0; i < (w * h); i++) + { +// int r, g, b, a; +// +// a = (pixels[i] >> 24) & 0xff; +// r = (((pixels[i] >> 16) & 0xff) * a) / 0xff; +// g = (((pixels[i] >> 8 ) & 0xff) * a) / 0xff; +// b = (((pixels[i] ) & 0xff) * a) / 0xff; + xci->pixels[i] = pixels[i]; +// (a << 24) | (r << 16) | (g << 8) | (b); + } + c = XcursorImageLoadCursor(_ecore_x_disp, xci); + XcursorImageDestroy(xci); + return c; + } + } + else +#endif /* ifdef ECORE_XCURSOR */ + { + XColor c1, c2; + Cursor c; + Pixmap pmap, mask; + GC gc; + XGCValues gcv; + XImage *xim; + unsigned int *pix; + int fr, fg, fb, br, bg, bb; + int brightest = 0; + int darkest = 255 * 3; + int x, y; + const int dither[2][2] = + { + {0, 2}, + {3, 1} + }; + + pmap = XCreatePixmap(_ecore_x_disp, win, w, h, 1); + mask = XCreatePixmap(_ecore_x_disp, win, w, h, 1); + xim = XCreateImage(_ecore_x_disp, + DefaultVisual(_ecore_x_disp, 0), + 1, ZPixmap, 0, NULL, w, h, 32, 0); + xim->data = malloc(xim->bytes_per_line * xim->height); + + fr = 0x00; fg = 0x00; fb = 0x00; + br = 0xff; bg = 0xff; bb = 0xff; + pix = (unsigned int *)pixels; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + int r, g, b, a; + + a = (pix[0] >> 24) & 0xff; + r = (pix[0] >> 16) & 0xff; + g = (pix[0] >> 8) & 0xff; + b = (pix[0]) & 0xff; + if (a > 0) + { + if ((r + g + b) > brightest) + { + brightest = r + g + b; + br = r; + bg = g; + bb = b; + } + + if ((r + g + b) < darkest) + { + darkest = r + g + b; + fr = r; + fg = g; + fb = b; + } + } + + pix++; + } + } + + pix = (unsigned int *)pixels; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + int v; + int r, g, b; + int d1, d2; + + r = (pix[0] >> 16) & 0xff; + g = (pix[0] >> 8) & 0xff; + b = (pix[0]) & 0xff; + d1 = + ((r - fr) * (r - fr)) + + ((g - fg) * (g - fg)) + + ((b - fb) * (b - fb)); + d2 = + ((r - br) * (r - br)) + + ((g - bg) * (g - bg)) + + ((b - bb) * (b - bb)); + if (d1 + d2) + { + v = (((d2 * 255) / (d1 + d2)) * 5) / 256; + if (v > dither[x & 0x1][y & 0x1]) + v = 1; + else + v = 0; + } + else + v = 0; + + XPutPixel(xim, x, y, v); + pix++; + } + } + gc = XCreateGC(_ecore_x_disp, pmap, 0, &gcv); + XPutImage(_ecore_x_disp, pmap, gc, xim, 0, 0, 0, 0, w, h); + XFreeGC(_ecore_x_disp, gc); + + pix = (unsigned int *)pixels; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + int v; + + v = (((pix[0] >> 24) & 0xff) * 5) / 256; + if (v > dither[x & 0x1][y & 0x1]) + v = 1; + else + v = 0; + + XPutPixel(xim, x, y, v); + pix++; + } + } + gc = XCreateGC(_ecore_x_disp, mask, 0, &gcv); + XPutImage(_ecore_x_disp, mask, gc, xim, 0, 0, 0, 0, w, h); + XFreeGC(_ecore_x_disp, gc); + + free(xim->data); + xim->data = NULL; + XDestroyImage(xim); + + c1.pixel = 0; + c1.red = fr << 8 | fr; + c1.green = fg << 8 | fg; + c1.blue = fb << 8 | fb; + c1.flags = DoRed | DoGreen | DoBlue; + + c2.pixel = 0; + c2.red = br << 8 | br; + c2.green = bg << 8 | bg; + c2.blue = bb << 8 | bb; + c2.flags = DoRed | DoGreen | DoBlue; + + c = XCreatePixmapCursor(_ecore_x_disp, + pmap, mask, + &c1, &c2, + hot_x, hot_y); + XFreePixmap(_ecore_x_disp, pmap); + XFreePixmap(_ecore_x_disp, mask); + return c; + } + + return 0; +} + +EAPI void +ecore_x_cursor_free(Ecore_X_Cursor c) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XFreeCursor(_ecore_x_disp, c); +} + +/* + * Returns the cursor for the given shape. + * Note that the return value must not be freed with + * ecore_x_cursor_free()! + */ +EAPI Ecore_X_Cursor +ecore_x_cursor_shape_get(int shape) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + /* Shapes are defined in Ecore_X_Cursor.h */ + return XCreateFontCursor(_ecore_x_disp, shape); +} + +EAPI void +ecore_x_cursor_size_set(int size) +{ +#ifdef ECORE_XCURSOR + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XcursorSetDefaultSize(_ecore_x_disp, size); +#else /* ifdef ECORE_XCURSOR */ + size = 0; +#endif /* ifdef ECORE_XCURSOR */ +} + +EAPI int +ecore_x_cursor_size_get(void) +{ +#ifdef ECORE_XCURSOR + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return XcursorGetDefaultSize(_ecore_x_disp); +#else /* ifdef ECORE_XCURSOR */ + return 0; +#endif /* ifdef ECORE_XCURSOR */ +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_damage.c b/src/lib/ecore_x/xlib/ecore_x_damage.c new file mode 100644 index 0000000..b094f85 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_damage.c @@ -0,0 +1,71 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include "ecore_x_private.h" +#include "Ecore_X.h" + +static Eina_Bool _damage_available = EINA_FALSE; +#ifdef ECORE_XDAMAGE +static int _damage_major, _damage_minor; +#endif /* ifdef ECORE_XDAMAGE */ + +void +_ecore_x_damage_init(void) +{ +#ifdef ECORE_XDAMAGE + _damage_major = 1; + _damage_minor = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (XDamageQueryVersion(_ecore_x_disp, &_damage_major, &_damage_minor)) + _damage_available = EINA_TRUE; + else + _damage_available = EINA_FALSE; + +#else /* ifdef ECORE_XDAMAGE */ + _damage_available = EINA_FALSE; +#endif /* ifdef ECORE_XDAMAGE */ +} + +EAPI Eina_Bool +ecore_x_damage_query(void) +{ + return _damage_available; +} + +EAPI Ecore_X_Damage +ecore_x_damage_new(Ecore_X_Drawable d, + Ecore_X_Damage_Report_Level level) +{ +#ifdef ECORE_XDAMAGE + Ecore_X_Damage damage; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + damage = XDamageCreate(_ecore_x_disp, d, level); + return damage; +#else /* ifdef ECORE_XDAMAGE */ + return 0; +#endif /* ifdef ECORE_XDAMAGE */ +} + +EAPI void +ecore_x_damage_free(Ecore_X_Damage damage) +{ +#ifdef ECORE_XDAMAGE + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XDamageDestroy(_ecore_x_disp, damage); +#endif /* ifdef ECORE_XDAMAGE */ +} + +EAPI void +ecore_x_damage_subtract(Ecore_X_Damage damage, + Ecore_X_Region repair, + Ecore_X_Region parts) +{ +#ifdef ECORE_XDAMAGE + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XDamageSubtract(_ecore_x_disp, damage, repair, parts); +#endif /* ifdef ECORE_XDAMAGE */ +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_dnd.c b/src/lib/ecore_x/xlib/ecore_x_dnd.c new file mode 100644 index 0000000..372470a --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_dnd.c @@ -0,0 +1,706 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include +#include + +#include "Ecore.h" +#include "ecore_x_private.h" +#include "Ecore_X.h" +#include "Ecore_X_Atoms.h" + +EAPI int ECORE_X_EVENT_XDND_ENTER = 0; +EAPI int ECORE_X_EVENT_XDND_POSITION = 0; +EAPI int ECORE_X_EVENT_XDND_STATUS = 0; +EAPI int ECORE_X_EVENT_XDND_LEAVE = 0; +EAPI int ECORE_X_EVENT_XDND_DROP = 0; +EAPI int ECORE_X_EVENT_XDND_FINISHED = 0; + +static Ecore_X_DND_Source *_source = NULL; +static Ecore_X_DND_Target *_target = NULL; +static int _ecore_x_dnd_init_count = 0; + +typedef struct _Version_Cache_Item +{ + Ecore_X_Window win; + int ver; +} Version_Cache_Item; +static Version_Cache_Item *_version_cache = NULL; +static int _version_cache_num = 0, _version_cache_alloc = 0; +static void (*_posupdatecb)(void *, + Ecore_X_Xdnd_Position *); +static void *_posupdatedata; + +void +_ecore_x_dnd_init(void) +{ + if (!_ecore_x_dnd_init_count) + { + _source = calloc(1, sizeof(Ecore_X_DND_Source)); + if (!_source) return; + _source->version = ECORE_X_DND_VERSION; + _source->win = None; + _source->dest = None; + _source->state = ECORE_X_DND_SOURCE_IDLE; + _source->prev.window = 0; + + _target = calloc(1, sizeof(Ecore_X_DND_Target)); + if (!_target) + { + free(_source); + _source = NULL; + return; + } + _target->win = None; + _target->source = None; + _target->state = ECORE_X_DND_TARGET_IDLE; + + ECORE_X_EVENT_XDND_ENTER = ecore_event_type_new(); + ECORE_X_EVENT_XDND_POSITION = ecore_event_type_new(); + ECORE_X_EVENT_XDND_STATUS = ecore_event_type_new(); + ECORE_X_EVENT_XDND_LEAVE = ecore_event_type_new(); + ECORE_X_EVENT_XDND_DROP = ecore_event_type_new(); + ECORE_X_EVENT_XDND_FINISHED = ecore_event_type_new(); + } + + _ecore_x_dnd_init_count++; +} + +void +_ecore_x_dnd_shutdown(void) +{ + _ecore_x_dnd_init_count--; + if (_ecore_x_dnd_init_count > 0) + return; + + if (_source) + free(_source); + + _source = NULL; + + if (_target) + free(_target); + + _target = NULL; + + _ecore_x_dnd_init_count = 0; +} + +static Eina_Bool +_ecore_x_dnd_converter_copy(char *target __UNUSED__, + void *data, + int size, + void **data_ret, + int *size_ret, + Ecore_X_Atom *tprop __UNUSED__, + int *count __UNUSED__) +{ + XTextProperty text_prop; + char *mystr; + XICCEncodingStyle style = XTextStyle; + + if (!data || !size) + return EINA_FALSE; + + mystr = calloc(1, size + 1); + if (!mystr) + return EINA_FALSE; + + memcpy(mystr, data, size); + + if (XmbTextListToTextProperty(_ecore_x_disp, &mystr, 1, style, + &text_prop) == Success) + { + int bufsize = strlen((char *)text_prop.value) + 1; + *data_ret = malloc(bufsize); + if (!*data_ret) + { + free(mystr); + return EINA_FALSE; + } + memcpy(*data_ret, text_prop.value, bufsize); + *size_ret = bufsize; + XFree(text_prop.value); + free(mystr); + return EINA_TRUE; + } + else + { + free(mystr); + return EINA_FALSE; + } +} + +EAPI void +ecore_x_dnd_aware_set(Ecore_X_Window win, + Eina_Bool on) +{ + Ecore_X_Atom prop_data = ECORE_X_DND_VERSION; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (on) + ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_AWARE, + XA_ATOM, 32, &prop_data, 1); + else + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_AWARE); +} + +EAPI int +ecore_x_dnd_version_get(Ecore_X_Window win) +{ + unsigned char *prop_data; + int num; + Version_Cache_Item *t; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + // this looks hacky - and it is, but we need a way of caching info about + // a window while dragging, because we literally query this every mouse + // move and going to and from x multiple times per move is EXPENSIVE + // and slows things down, puts lots of load on x etc. + if (_source->state == ECORE_X_DND_SOURCE_DRAGGING) + if (_version_cache) + { + int i; + + for (i = 0; i < _version_cache_num; i++) + { + if (_version_cache[i].win == win) + return _version_cache[i].ver; + } + } + + if (ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_AWARE, + XA_ATOM, 32, &prop_data, &num)) + { + int version = (int)*prop_data; + free(prop_data); + if (_source->state == ECORE_X_DND_SOURCE_DRAGGING) + { + _version_cache_num++; + if (_version_cache_num > _version_cache_alloc) + _version_cache_alloc += 16; + + t = realloc(_version_cache, + _version_cache_alloc * + sizeof(Version_Cache_Item)); + if (!t) return 0; + _version_cache = t; + _version_cache[_version_cache_num - 1].win = win; + _version_cache[_version_cache_num - 1].ver = version; + } + + return version; + } + + if (_source->state == ECORE_X_DND_SOURCE_DRAGGING) + { + _version_cache_num++; + if (_version_cache_num > _version_cache_alloc) + _version_cache_alloc += 16; + + t = realloc(_version_cache, _version_cache_alloc * + sizeof(Version_Cache_Item)); + if (!t) return 0; + _version_cache = t; + _version_cache[_version_cache_num - 1].win = win; + _version_cache[_version_cache_num - 1].ver = 0; + } + + return 0; +} + +EAPI Eina_Bool +ecore_x_dnd_type_isset(Ecore_X_Window win, + const char *type) +{ + int num, i, ret = EINA_FALSE; + unsigned char *data; + Ecore_X_Atom *atoms, atom; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_TYPE_LIST, + XA_ATOM, 32, &data, &num)) + return ret; + + atom = ecore_x_atom_get(type); + atoms = (Ecore_X_Atom *)data; + + for (i = 0; i < num; ++i) + { + if (atom == atoms[i]) + { + ret = EINA_TRUE; + break; + } + } + + XFree(data); + return ret; +} + +EAPI void +ecore_x_dnd_type_set(Ecore_X_Window win, + const char *type, + Eina_Bool on) +{ + Ecore_X_Atom atom; + Ecore_X_Atom *oldset = NULL, *newset = NULL; + int i, j = 0, num = 0; + unsigned char *data = NULL; + unsigned char *old_data = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + atom = ecore_x_atom_get(type); + ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_TYPE_LIST, + XA_ATOM, 32, &old_data, &num); + oldset = (Ecore_X_Atom *)old_data; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (on) + { + if (ecore_x_dnd_type_isset(win, type)) + { + XFree(old_data); + return; + } + + newset = calloc(num + 1, sizeof(Ecore_X_Atom)); + if (!newset) + return; + + data = (unsigned char *)newset; + + for (i = 0; i < num; i++) + newset[i + 1] = oldset[i]; + /* prepend the new type */ + newset[0] = atom; + + ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST, + XA_ATOM, 32, data, num + 1); + } + else + { + if (!ecore_x_dnd_type_isset(win, type)) + { + XFree(old_data); + return; + } + + newset = calloc(num - 1, sizeof(Ecore_X_Atom)); + if (!newset) + { + XFree(old_data); + return; + } + + data = (unsigned char *)newset; + for (i = 0; i < num; i++) + if (oldset[i] != atom) + newset[j++] = oldset[i]; + + ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST, + XA_ATOM, 32, data, num - 1); + } + + XFree(oldset); + free(newset); +} + +EAPI void +ecore_x_dnd_types_set(Ecore_X_Window win, + const char **types, + unsigned int num_types) +{ + Ecore_X_Atom *newset = NULL; + unsigned int i; + unsigned char *data = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!num_types) + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_TYPE_LIST); + else + { + newset = calloc(num_types, sizeof(Ecore_X_Atom)); + if (!newset) + return; + + data = (unsigned char *)newset; + for (i = 0; i < num_types; i++) + { + newset[i] = ecore_x_atom_get(types[i]); + ecore_x_selection_converter_atom_add(newset[i], + _ecore_x_dnd_converter_copy); + } + ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST, + XA_ATOM, 32, data, num_types); + free(newset); + } +} + +EAPI void +ecore_x_dnd_actions_set(Ecore_X_Window win, + Ecore_X_Atom *actions, + unsigned int num_actions) +{ + unsigned int i; + unsigned char *data = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!num_actions) + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_ACTION_LIST); + else + { + data = (unsigned char *)actions; + for (i = 0; i < num_actions; i++) + { + ecore_x_selection_converter_atom_add(actions[i], + _ecore_x_dnd_converter_copy); + } + ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_ACTION_LIST, + XA_ATOM, 32, data, num_actions); + } +} + +/** + * The DND position update cb is called Ecore_X sends a DND position to a + * client. + * + * It essentially mirrors some of the data sent in the position message. + * Generally this cb should be set just before position update is called. + * Please note well you need to look after your own data pointer if someone + * trashes you position update cb set. + * + * It is considered good form to clear this when the dnd event finishes. + * + * @param cb Callback to updated each time ecore_x sends a position update. + * @param data User data. + */ +EAPI void +ecore_x_dnd_callback_pos_update_set( + void (*cb)(void *, + Ecore_X_Xdnd_Position *data), + const void *data) +{ + _posupdatecb = cb; + _posupdatedata = (void *)data; /* Discard the const early */ +} + +Ecore_X_DND_Source * +_ecore_x_dnd_source_get(void) +{ + return _source; +} + +Ecore_X_DND_Target * +_ecore_x_dnd_target_get(void) +{ + return _target; +} + +EAPI Eina_Bool +ecore_x_dnd_begin(Ecore_X_Window source, + unsigned char *data, + int size) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_dnd_version_get(source)) + return EINA_FALSE; + + /* Take ownership of XdndSelection */ + if (!ecore_x_selection_xdnd_set(source, data, size)) + return EINA_FALSE; + + if (_version_cache) + { + free(_version_cache); + _version_cache = NULL; + _version_cache_num = 0; + _version_cache_alloc = 0; + } + + ecore_x_window_shadow_tree_flush(); + + _source->win = source; + ecore_x_window_ignore_set(_source->win, 1); + _source->state = ECORE_X_DND_SOURCE_DRAGGING; + _source->time = _ecore_x_event_last_time; + _source->prev.window = 0; + + /* Default Accepted Action: move */ + _source->action = ECORE_X_ATOM_XDND_ACTION_MOVE; + _source->accepted_action = None; + _source->dest = None; + + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_x_dnd_drop(void) +{ + XEvent xev; + int status = EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (_source->dest) + { + xev.xany.type = ClientMessage; + xev.xany.display = _ecore_x_disp; + xev.xclient.format = 32; + xev.xclient.window = _source->dest; + + if (_source->will_accept) + { + xev.xclient.message_type = ECORE_X_ATOM_XDND_DROP; + xev.xclient.data.l[0] = _source->win; + xev.xclient.data.l[1] = 0; + xev.xclient.data.l[2] = _source->time; + XSendEvent(_ecore_x_disp, _source->dest, False, 0, &xev); + _source->state = ECORE_X_DND_SOURCE_DROPPED; + status = EINA_TRUE; + } + else + { + xev.xclient.message_type = ECORE_X_ATOM_XDND_LEAVE; + xev.xclient.data.l[0] = _source->win; + xev.xclient.data.l[1] = 0; + XSendEvent(_ecore_x_disp, _source->dest, False, 0, &xev); + _source->state = ECORE_X_DND_SOURCE_IDLE; + } + } + else + { + /* Dropping on nothing */ + ecore_x_selection_xdnd_clear(); + _source->state = ECORE_X_DND_SOURCE_IDLE; + } + + ecore_x_window_ignore_set(_source->win, 0); + + _source->prev.window = 0; + + return status; +} + +EAPI void +ecore_x_dnd_send_status(Eina_Bool will_accept, + Eina_Bool suppress, + Ecore_X_Rectangle rectangle, + Ecore_X_Atom action) +{ + XEvent xev; + + if (_target->state == ECORE_X_DND_TARGET_IDLE) + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + memset(&xev, 0, sizeof(XEvent)); + + _target->will_accept = will_accept; + + xev.xclient.type = ClientMessage; + xev.xclient.display = _ecore_x_disp; + xev.xclient.message_type = ECORE_X_ATOM_XDND_STATUS; + xev.xclient.format = 32; + xev.xclient.window = _target->source; + + xev.xclient.data.l[0] = _target->win; + xev.xclient.data.l[1] = 0; + if (will_accept) + xev.xclient.data.l[1] |= 0x1UL; + + if (!suppress) + xev.xclient.data.l[1] |= 0x2UL; + + /* Set rectangle information */ + xev.xclient.data.l[2] = rectangle.x; + xev.xclient.data.l[2] <<= 16; + xev.xclient.data.l[2] |= rectangle.y; + xev.xclient.data.l[3] = rectangle.width; + xev.xclient.data.l[3] <<= 16; + xev.xclient.data.l[3] |= rectangle.height; + + if (will_accept) + { + xev.xclient.data.l[4] = action; + _target->accepted_action = action; + } + else + { + xev.xclient.data.l[4] = None; + _target->accepted_action = action; + } + + XSendEvent(_ecore_x_disp, _target->source, False, 0, &xev); +} + +EAPI void +ecore_x_dnd_send_finished(void) +{ + XEvent xev; + + if (_target->state == ECORE_X_DND_TARGET_IDLE) + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + xev.xany.type = ClientMessage; + xev.xany.display = _ecore_x_disp; + xev.xclient.message_type = ECORE_X_ATOM_XDND_FINISHED; + xev.xclient.format = 32; + xev.xclient.window = _target->source; + + xev.xclient.data.l[0] = _target->win; + xev.xclient.data.l[1] = 0; + xev.xclient.data.l[2] = 0; + if (_target->will_accept) + { + xev.xclient.data.l[1] |= 0x1UL; + xev.xclient.data.l[2] = _target->accepted_action; + } + + XSendEvent(_ecore_x_disp, _target->source, False, 0, &xev); + + _target->state = ECORE_X_DND_TARGET_IDLE; +} + +EAPI void +ecore_x_dnd_source_action_set(Ecore_X_Atom action) +{ + _source->action = action; + if (_source->prev.window) + _ecore_x_dnd_drag(_source->prev.window, _source->prev.x, _source->prev.y); +} + +EAPI Ecore_X_Atom +ecore_x_dnd_source_action_get(void) +{ + return _source->action; +} + +void +_ecore_x_dnd_drag(Ecore_X_Window root, + int x, + int y) +{ + XEvent xev; + Ecore_X_Window win; + Ecore_X_Window *skip; + Ecore_X_Xdnd_Position pos; + int num; + + if (_source->state != ECORE_X_DND_SOURCE_DRAGGING) + return; + + /* Preinitialize XEvent struct */ + memset(&xev, 0, sizeof(XEvent)); + xev.xany.type = ClientMessage; + xev.xany.display = _ecore_x_disp; + xev.xclient.format = 32; + + /* Attempt to find a DND-capable window under the cursor */ + skip = ecore_x_window_ignore_list(&num); +// WARNING - this function is HEAVY. it goes to and from x a LOT walking the +// window tree - use the SHADOW version - makes a 1-off tree copy, then uses +// that instead. +// win = ecore_x_window_at_xy_with_skip_get(x, y, skip, num); + win = ecore_x_window_shadow_tree_at_xy_with_skip_get(root, x, y, skip, num); + +// NOTE: This now uses the shadow version to find parent windows +// while ((win) && !(ecore_x_dnd_version_get(win))) +// win = ecore_x_window_parent_get(win); + while ((win) && !(ecore_x_dnd_version_get(win))) + win = ecore_x_window_shadow_parent_get(root, win); + + /* Send XdndLeave to current destination window if we have left it */ + if ((_source->dest) && (win != _source->dest)) + { + xev.xclient.window = _source->dest; + xev.xclient.message_type = ECORE_X_ATOM_XDND_LEAVE; + xev.xclient.data.l[0] = _source->win; + xev.xclient.data.l[1] = 0; + + XSendEvent(_ecore_x_disp, _source->dest, False, 0, &xev); + _source->suppress = 0; + } + + if (win) + { + int x1, x2, y1, y2; + + _source->version = MIN(ECORE_X_DND_VERSION, + ecore_x_dnd_version_get(win)); + if (win != _source->dest) + { + int i; + unsigned char *data; + Ecore_X_Atom *types; + + ecore_x_window_prop_property_get(_source->win, + ECORE_X_ATOM_XDND_TYPE_LIST, + XA_ATOM, + 32, + &data, + &num); + types = (Ecore_X_Atom *)data; + + /* Entered new window, send XdndEnter */ + xev.xclient.window = win; + xev.xclient.message_type = ECORE_X_ATOM_XDND_ENTER; + xev.xclient.data.l[0] = _source->win; + xev.xclient.data.l[1] = 0; + if (num > 3) + xev.xclient.data.l[1] |= 0x1UL; + else + xev.xclient.data.l[1] &= 0xfffffffeUL; + + xev.xclient.data.l[1] |= ((unsigned long)_source->version) << 24; + + for (i = 2; i < 5; i++) + xev.xclient.data.l[i] = 0; + for (i = 0; i < MIN(num, 3); ++i) + xev.xclient.data.l[i + 2] = types[i]; + XFree(data); + XSendEvent(_ecore_x_disp, win, False, 0, &xev); + _source->await_status = 0; + _source->will_accept = 0; + } + + /* Determine if we're still in the rectangle from the last status */ + x1 = _source->rectangle.x; + x2 = _source->rectangle.x + _source->rectangle.width; + y1 = _source->rectangle.y; + y2 = _source->rectangle.y + _source->rectangle.height; + + if ((!_source->await_status) || + (!_source->suppress) || + ((x < x1) || (x > x2) || (y < y1) || (y > y2))) + { + xev.xclient.window = win; + xev.xclient.message_type = ECORE_X_ATOM_XDND_POSITION; + xev.xclient.data.l[0] = _source->win; + xev.xclient.data.l[1] = 0; /* Reserved */ + xev.xclient.data.l[2] = ((x << 16) & 0xffff0000) | (y & 0xffff); + xev.xclient.data.l[3] = _source->time; /* Version 1 */ + xev.xclient.data.l[4] = _source->action; /* Version 2, Needs to be pre-set */ + XSendEvent(_ecore_x_disp, win, False, 0, &xev); + + _source->await_status = 1; + } + } + + if (_posupdatecb) + { + pos.position.x = x; + pos.position.y = y; + pos.win = win; + pos.prev = _source->dest; + _posupdatecb(_posupdatedata, &pos); + } + + _source->prev.x = x; + _source->prev.y = y; + _source->prev.window = root; + _source->dest = win; +} + +/* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/ diff --git a/src/lib/ecore_x/xlib/ecore_x_dpms.c b/src/lib/ecore_x/xlib/ecore_x_dpms.c new file mode 100644 index 0000000..23349f4 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_dpms.c @@ -0,0 +1,247 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include "ecore_x_private.h" + +static Eina_Bool _dpms_available = EINA_FALSE; + +void +_ecore_x_dpms_init(void) +{ +#ifdef ECORE_XDPMS + int _dpms_major, _dpms_minor; + + _dpms_major = 1; + _dpms_minor = 0; + + if (DPMSGetVersion(_ecore_x_disp, &_dpms_major, &_dpms_minor)) + _dpms_available = EINA_TRUE; + else + _dpms_available = EINA_FALSE; + +#else /* ifdef ECORE_XDPMS */ + _dpms_available = EINA_FALSE; +#endif /* ifdef ECORE_XDPMS */ +} + +/** + * @defgroup Ecore_X_DPMS_Group X DPMS Extension Functions + * + * Functions related to the X DPMS extension. + */ + +/** + * Checks if the X DPMS extension is available on the server. + * @return @c 1 if the X DPMS extension is available, @c 0 otherwise. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI Eina_Bool +ecore_x_dpms_query(void) +{ + return _dpms_available; +} + +/** + * Checks if the X server is capable of DPMS. + * @return @c 1 if the X server is capable of DPMS, @c 0 otherwise. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI Eina_Bool +ecore_x_dpms_capable_get(void) +{ +#ifdef ECORE_XDPMS + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return DPMSCapable(_ecore_x_disp) ? EINA_TRUE : EINA_FALSE; +#else /* ifdef ECORE_XDPMS */ + return EINA_FALSE; +#endif /* ifdef ECORE_XDPMS */ +} + +/** + * Checks the DPMS state of the display. + * @return @c 1 if DPMS is enabled, @c 0 otherwise. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI Eina_Bool +ecore_x_dpms_enabled_get(void) +{ +#ifdef ECORE_XDPMS + unsigned char state; + unsigned short power_lvl; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + DPMSInfo(_ecore_x_disp, &power_lvl, &state); + return state ? EINA_TRUE : EINA_FALSE; +#else /* ifdef ECORE_XDPMS */ + return EINA_FALSE; +#endif /* ifdef ECORE_XDPMS */ +} + +/** + * Sets the DPMS state of the display. + * @param enabled @c 0 to disable DPMS characteristics of the server, enable it otherwise. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI void +ecore_x_dpms_enabled_set(int enabled) +{ +#ifdef ECORE_XDPMS + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (enabled) + DPMSEnable(_ecore_x_disp); + else + DPMSDisable(_ecore_x_disp); + +#endif /* ifdef ECORE_XDPMS */ +} + +/** + * Gets the timeouts. The values are in unit of seconds. + * @param standby Amount of time of inactivity before standby mode will be invoked. + * @param suspend Amount of time of inactivity before the screen is placed into suspend mode. + * @param off Amount of time of inactivity before the monitor is shut off. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI void +ecore_x_dpms_timeouts_get(unsigned int *standby, + unsigned int *suspend, + unsigned int *off) +{ +#ifdef ECORE_XDPMS + LOGFN(__FILE__, __LINE__, __FUNCTION__); + DPMSGetTimeouts(_ecore_x_disp, (unsigned short *)standby, + (unsigned short *)suspend, (unsigned short *)off); +#endif /* ifdef ECORE_XDPMS */ +} + +/** + * Sets the timeouts. The values are in unit of seconds. + * @param standby Amount of time of inactivity before standby mode will be invoked. + * @param suspend Amount of time of inactivity before the screen is placed into suspend mode. + * @param off Amount of time of inactivity before the monitor is shut off. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI Eina_Bool +ecore_x_dpms_timeouts_set(unsigned int standby, + unsigned int suspend, + unsigned int off) +{ +#ifdef ECORE_XDPMS + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return DPMSSetTimeouts(_ecore_x_disp, standby, suspend, off) ? EINA_TRUE : EINA_FALSE; +#else /* ifdef ECORE_XDPMS */ + return EINA_FALSE; +#endif /* ifdef ECORE_XDPMS */ +} + +/** + * Returns the amount of time of inactivity before standby mode is invoked. + * @return The standby timeout value. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI unsigned int +ecore_x_dpms_timeout_standby_get(void) +{ +#ifdef ECORE_XDPMS + unsigned short standby, suspend, off; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + DPMSGetTimeouts(_ecore_x_disp, &standby, &suspend, &off); + return standby; +#else /* ifdef ECORE_XDPMS */ + return 0; +#endif /* ifdef ECORE_XDPMS */ +} + +/** + * Returns the amount of time of inactivity before the second level of + * power saving is invoked. + * @return The suspend timeout value. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI unsigned int +ecore_x_dpms_timeout_suspend_get(void) +{ +#ifdef ECORE_XDPMS + unsigned short standby, suspend, off; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + DPMSGetTimeouts(_ecore_x_disp, &standby, &suspend, &off); + return suspend; +#else /* ifdef ECORE_XDPMS */ + return 0; +#endif /* ifdef ECORE_XDPMS */ +} + +/** + * Returns the amount of time of inactivity before the third and final + * level of power saving is invoked. + * @return The off timeout value. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI unsigned int +ecore_x_dpms_timeout_off_get(void) +{ +#ifdef ECORE_XDPMS + unsigned short standby, suspend, off; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + DPMSGetTimeouts(_ecore_x_disp, &standby, &suspend, &off); + return off; +#else /* ifdef ECORE_XDPMS */ + return 0; +#endif /* ifdef ECORE_XDPMS */ +} + +/** + * Sets the standby timeout (in unit of seconds). + * @param new_timeout Amount of time of inactivity before standby mode will be invoked. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI void +ecore_x_dpms_timeout_standby_set(unsigned int new_timeout) +{ +#ifdef ECORE_XDPMS + unsigned short standby, suspend, off; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + DPMSGetTimeouts(_ecore_x_disp, &standby, &suspend, &off); + DPMSSetTimeouts(_ecore_x_disp, new_timeout, suspend, off); +#endif /* ifdef ECORE_XDPMS */ +} + +/** + * Sets the suspend timeout (in unit of seconds). + * @param new_timeout Amount of time of inactivity before the screen is placed into suspend mode. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI void +ecore_x_dpms_timeout_suspend_set(unsigned int new_timeout) +{ +#ifdef ECORE_XDPMS + unsigned short standby, suspend, off; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + DPMSGetTimeouts(_ecore_x_disp, &standby, &suspend, &off); + DPMSSetTimeouts(_ecore_x_disp, standby, new_timeout, off); +#endif /* ifdef ECORE_XDPMS */ +} + +/** + * Sets the off timeout (in unit of seconds). + * @param new_timeout Amount of time of inactivity before the monitor is shut off. + * @ingroup Ecore_X_DPMS_Group + */ +EAPI void +ecore_x_dpms_timeout_off_set(unsigned int new_timeout) +{ +#ifdef ECORE_XDPMS + unsigned short standby, suspend, off; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + DPMSGetTimeouts(_ecore_x_disp, &standby, &suspend, &off); + DPMSSetTimeouts(_ecore_x_disp, standby, suspend, new_timeout); +#endif /* ifdef ECORE_XDPMS */ +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_drawable.c b/src/lib/ecore_x/xlib/ecore_x_drawable.c new file mode 100644 index 0000000..d1b4111 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_drawable.c @@ -0,0 +1,118 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include "ecore_x_private.h" + +/** + * @defgroup Ecore_X_Drawable_Group X Drawable Functions + * + * Functions that operate on drawables. + */ + +/** + * Retrieves the geometry of the given drawable. + * @param d The given drawable. + * @param x Pointer to an integer into which the X position is to be stored. + * @param y Pointer to an integer into which the Y position is to be stored. + * @param w Pointer to an integer into which the width is to be stored. + * @param h Pointer to an integer into which the height is to be stored. + * @ingroup Ecore_X_Drawable_Group + */ +EAPI void +ecore_x_drawable_geometry_get(Ecore_X_Drawable d, + int *x, + int *y, + int *w, + int *h) +{ + Window dummy_win; + int ret_x, ret_y; + unsigned int ret_w, ret_h, dummy_border, dummy_depth; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!XGetGeometry(_ecore_x_disp, d, &dummy_win, &ret_x, &ret_y, + &ret_w, &ret_h, &dummy_border, &dummy_depth)) + { + ret_x = 0; + ret_y = 0; + ret_w = 0; + ret_h = 0; + } + + if (x) + *x = ret_x; + + if (y) + *y = ret_y; + + if (w) + *w = (int)ret_w; + + if (h) + *h = (int)ret_h; +} + +/** + * Retrieves the width of the border of the given drawable. + * @param d The given drawable. + * @return The border width of the given drawable. + * @ingroup Ecore_X_Drawable_Group + */ +EAPI int +ecore_x_drawable_border_width_get(Ecore_X_Drawable d) +{ + Window dummy_win; + int dummy_x, dummy_y; + unsigned int dummy_w, dummy_h, border_ret, dummy_depth; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!XGetGeometry(_ecore_x_disp, d, &dummy_win, &dummy_x, &dummy_y, + &dummy_w, &dummy_h, &border_ret, &dummy_depth)) + border_ret = 0; + + return (int)border_ret; +} + +/** + * Retrieves the depth of the given drawable. + * @param d The given drawable. + * @return The depth of the given drawable. + * @ingroup Ecore_X_Drawable_Group + */ +EAPI int +ecore_x_drawable_depth_get(Ecore_X_Drawable d) +{ + Window dummy_win; + int dummy_x, dummy_y; + unsigned int dummy_w, dummy_h, dummy_border, depth_ret; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!XGetGeometry(_ecore_x_disp, d, &dummy_win, &dummy_x, &dummy_y, + &dummy_w, &dummy_h, &dummy_border, &depth_ret)) + depth_ret = 0; + + return (int)depth_ret; +} + +/** + * Fill the specified rectangle on a drawable. + * @param d The given drawable. + * @param gc The graphic context that controls the fill rules. + * @param x The X coordinate of the top-left corner of the rectangle. + * @param y The Y coordinate of the top-left corner of the rectangle. + * @param width The width of the rectangle. + * @param height The height of the rectangle. + */ +EAPI void +ecore_x_drawable_rectangle_fill(Ecore_X_Drawable d, + Ecore_X_GC gc, + int x, + int y, + int width, + int height) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XFillRectangle(_ecore_x_disp, d, gc, x, y, width, height); +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_e.c b/src/lib/ecore_x/xlib/ecore_x_e.c new file mode 100644 index 0000000..fb26a13 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_e.c @@ -0,0 +1,1622 @@ +/* + * OLD E hints + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include "Ecore.h" +#include "ecore_x_private.h" +#include "Ecore_X.h" +#include "Ecore_X_Atoms.h" + +EAPI void +ecore_x_e_init(void) +{ +} + +EAPI void +ecore_x_e_frame_size_set(Ecore_X_Window win, + int fl, + int fr, + int ft, + int fb) +{ + unsigned int frames[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + frames[0] = fl; + frames[1] = fr; + frames[2] = ft; + frames[3] = fb; + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_FRAME_SIZE, frames, 4); +} + +EAPI void +ecore_x_e_virtual_keyboard_set(Ecore_X_Window win, + unsigned int is_keyboard) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_VIRTUAL_KEYBOARD, + &is_keyboard, 1); +} + +EAPI Eina_Bool +ecore_x_e_virtual_keyboard_get(Ecore_X_Window win) +{ + unsigned int val; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_E_VIRTUAL_KEYBOARD, + &val, 1)) + return EINA_FALSE; + + return val ? EINA_TRUE : EINA_FALSE; +} + +static Ecore_X_Virtual_Keyboard_State +_ecore_x_e_vkbd_state_get(Ecore_X_Atom atom) +{ + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_ON; + + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF; + + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ALPHA) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_ALPHA; + + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_NUMERIC) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_NUMERIC; + + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PIN) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_PIN; + + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PHONE_NUMBER) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_PHONE_NUMBER; + + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HEX) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_HEX; + + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_TERMINAL) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_TERMINAL; + + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PASSWORD) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_PASSWORD; + + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_IP) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_IP; + + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HOST) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_HOST; + + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_FILE) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_FILE; + + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_URL) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_URL; + + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_KEYPAD) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_KEYPAD; + + if (atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_J2ME) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_J2ME; + + return ECORE_X_VIRTUAL_KEYBOARD_STATE_UNKNOWN; +} + +static Ecore_X_Atom +_ecore_x_e_vkbd_atom_get(Ecore_X_Virtual_Keyboard_State state) +{ + switch (state) + { + case ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_ON: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_ALPHA: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ALPHA; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_NUMERIC: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_NUMERIC; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_PIN: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PIN; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_PHONE_NUMBER: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PHONE_NUMBER; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_HEX: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HEX; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_TERMINAL: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_TERMINAL; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_PASSWORD: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_PASSWORD; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_IP: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_IP; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_HOST: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_HOST; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_FILE: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_FILE; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_URL: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_URL; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_KEYPAD: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_KEYPAD; + + case ECORE_X_VIRTUAL_KEYBOARD_STATE_J2ME: + return ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_J2ME; + + default: break; + } + return 0; +} + +EAPI void +ecore_x_e_virtual_keyboard_state_set(Ecore_X_Window win, + Ecore_X_Virtual_Keyboard_State state) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + atom = _ecore_x_e_vkbd_atom_get(state); + ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE, + &atom, 1); +} + +EAPI Ecore_X_Virtual_Keyboard_State +ecore_x_e_virtual_keyboard_state_get(Ecore_X_Window win) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_atom_get(win, ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE, + &atom, 1)) + return ECORE_X_VIRTUAL_KEYBOARD_STATE_UNKNOWN; + + return _ecore_x_e_vkbd_state_get(atom); +} + +EAPI void +ecore_x_e_virtual_keyboard_state_send(Ecore_X_Window win, + Ecore_X_Virtual_Keyboard_State state) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + _ecore_x_e_vkbd_atom_get(state), + 0, 0, 0, 0); +} + +static Ecore_X_Atom +_ecore_x_e_illume_atom_get(Ecore_X_Illume_Mode mode) +{ + switch (mode) + { + case ECORE_X_ILLUME_MODE_SINGLE: + return ECORE_X_ATOM_E_ILLUME_MODE_SINGLE; + + case ECORE_X_ILLUME_MODE_DUAL_TOP: + return ECORE_X_ATOM_E_ILLUME_MODE_DUAL_TOP; + + case ECORE_X_ILLUME_MODE_DUAL_LEFT: + return ECORE_X_ATOM_E_ILLUME_MODE_DUAL_LEFT; + + default: + break; + } + return ECORE_X_ILLUME_MODE_UNKNOWN; +} + +static Ecore_X_Illume_Mode +_ecore_x_e_illume_mode_get(Ecore_X_Atom atom) +{ + if (atom == ECORE_X_ATOM_E_ILLUME_MODE_SINGLE) + return ECORE_X_ILLUME_MODE_SINGLE; + + if (atom == ECORE_X_ATOM_E_ILLUME_MODE_DUAL_TOP) + return ECORE_X_ILLUME_MODE_DUAL_TOP; + + if (atom == ECORE_X_ATOM_E_ILLUME_MODE_DUAL_LEFT) + return ECORE_X_ILLUME_MODE_DUAL_LEFT; + + return ECORE_X_ILLUME_MODE_UNKNOWN; +} + +EAPI void +ecore_x_e_illume_zone_set(Ecore_X_Window win, + Ecore_X_Window zone) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_window_set(win, ECORE_X_ATOM_E_ILLUME_ZONE, + &zone, 1); +} + +EAPI Ecore_X_Window +ecore_x_e_illume_zone_get(Ecore_X_Window win) +{ + Ecore_X_Window zone; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_window_get(win, ECORE_X_ATOM_E_ILLUME_ZONE, + &zone, 1)) + return 0; + + return zone; +} + +EAPI void +ecore_x_e_illume_zone_list_set(Ecore_X_Window win, + Ecore_X_Window *zones, + unsigned int n_zones) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_window_set(win, ECORE_X_ATOM_E_ILLUME_ZONE_LIST, + zones, n_zones); +} + +EAPI void +ecore_x_e_illume_conformant_set(Ecore_X_Window win, + unsigned int is_conformant) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_CONFORMANT, + &is_conformant, 1); +} + +EAPI Eina_Bool +ecore_x_e_illume_conformant_get(Ecore_X_Window win) +{ + unsigned int val = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_E_ILLUME_CONFORMANT, + &val, 1)) + return EINA_FALSE; + + return val ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_x_e_illume_mode_set(Ecore_X_Window win, + Ecore_X_Illume_Mode mode) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + atom = _ecore_x_e_illume_atom_get(mode); + ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_E_ILLUME_MODE, + &atom, 1); +} + +EAPI Ecore_X_Illume_Mode +ecore_x_e_illume_mode_get(Ecore_X_Window win) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_atom_get(win, ECORE_X_ATOM_E_ILLUME_MODE, &atom, 1)) + return ECORE_X_ILLUME_MODE_UNKNOWN; + + return _ecore_x_e_illume_mode_get(atom); +} + +EAPI void +ecore_x_e_illume_mode_send(Ecore_X_Window win, + Ecore_X_Illume_Mode mode) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_MODE, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + _ecore_x_e_illume_atom_get(mode), + 0, 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_focus_back_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_FOCUS_BACK, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + 1, 0, 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_focus_forward_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_FOCUS_FORWARD, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + 1, 0, 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_focus_home_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_FOCUS_HOME, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + 1, 0, 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_close_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_CLOSE, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + 1, 0, 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_home_new_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_HOME_NEW, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + 1, 0, 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_home_del_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_HOME_DEL, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + 1, 0, 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_access_action_next_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + win, + ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_NEXT, + 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_access_action_prev_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + win, + ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_PREV, + 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_access_action_activate_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + win, + ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_ACTIVATE, + 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_access_action_read_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + win, + ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ, + 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_access_action_read_next_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + win, + ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_NEXT, + 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_access_action_read_prev_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + win, + ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_PREV, + 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_drag_set(Ecore_X_Window win, + unsigned int drag) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_DRAG, &drag, 1); +} + +EAPI Eina_Bool +ecore_x_e_illume_drag_get(Ecore_X_Window win) +{ + unsigned int val = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_E_ILLUME_DRAG, &val, 1)) + return EINA_FALSE; + + return val ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_x_e_illume_drag_locked_set(Ecore_X_Window win, + unsigned int is_locked) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_DRAG_LOCKED, + &is_locked, 1); +} + +EAPI Eina_Bool +ecore_x_e_illume_drag_locked_get(Ecore_X_Window win) +{ + unsigned int val = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_E_ILLUME_DRAG_LOCKED, + &val, 1)) + return EINA_FALSE; + + return val ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_x_e_illume_drag_start_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_DRAG_START, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + 1, 0, 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_drag_end_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_DRAG_END, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + 1, 0, 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_indicator_geometry_set(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ + unsigned int geom[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + geom[0] = x; + geom[1] = y; + geom[2] = w; + geom[3] = h; + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_INDICATOR_GEOMETRY, + geom, 4); +} + +EAPI Eina_Bool +ecore_x_e_illume_indicator_geometry_get(Ecore_X_Window win, + int *x, + int *y, + int *w, + int *h) +{ + int ret = 0; + unsigned int geom[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ret = + ecore_x_window_prop_card32_get(win, + ECORE_X_ATOM_E_ILLUME_INDICATOR_GEOMETRY, + geom, 4); + if (ret != 4) + return EINA_FALSE; + + if (x) + *x = geom[0]; + + if (y) + *y = geom[1]; + + if (w) + *w = geom[2]; + + if (h) + *h = geom[3]; + + return EINA_TRUE; +} + +EAPI void +ecore_x_e_illume_softkey_geometry_set(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ + unsigned int geom[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + geom[0] = x; + geom[1] = y; + geom[2] = w; + geom[3] = h; + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_SOFTKEY_GEOMETRY, + geom, 4); +} + +EAPI Eina_Bool +ecore_x_e_illume_softkey_geometry_get(Ecore_X_Window win, + int *x, + int *y, + int *w, + int *h) +{ + int ret = 0; + unsigned int geom[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ret = + ecore_x_window_prop_card32_get(win, + ECORE_X_ATOM_E_ILLUME_SOFTKEY_GEOMETRY, + geom, 4); + if (ret != 4) + return EINA_FALSE; + + if (x) + *x = geom[0]; + + if (y) + *y = geom[1]; + + if (w) + *w = geom[2]; + + if (h) + *h = geom[3]; + + return EINA_TRUE; +} + +EAPI void +ecore_x_e_illume_keyboard_geometry_set(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ + unsigned int geom[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + geom[0] = x; + geom[1] = y; + geom[2] = w; + geom[3] = h; + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_KEYBOARD_GEOMETRY, + geom, 4); +} + +EAPI Eina_Bool +ecore_x_e_illume_keyboard_geometry_get(Ecore_X_Window win, + int *x, + int *y, + int *w, + int *h) +{ + int ret = 0; + unsigned int geom[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ret = + ecore_x_window_prop_card32_get(win, + ECORE_X_ATOM_E_ILLUME_KEYBOARD_GEOMETRY, + geom, 4); + if (ret != 4) + return EINA_FALSE; + + if (x) + *x = geom[0]; + + if (y) + *y = geom[1]; + + if (w) + *w = geom[2]; + + if (h) + *h = geom[3]; + + return EINA_TRUE; +} + +static Ecore_X_Atom +_ecore_x_e_quickpanel_atom_get(Ecore_X_Illume_Quickpanel_State state) +{ + switch (state) + { + case ECORE_X_ILLUME_QUICKPANEL_STATE_ON: + return ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ON; + + case ECORE_X_ILLUME_QUICKPANEL_STATE_OFF: + return ECORE_X_ATOM_E_ILLUME_QUICKPANEL_OFF; + + default: + break; + } + return 0; +} + +static Ecore_X_Illume_Quickpanel_State +_ecore_x_e_quickpanel_state_get(Ecore_X_Atom atom) +{ + if (atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ON) + return ECORE_X_ILLUME_QUICKPANEL_STATE_ON; + + if (atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_OFF) + return ECORE_X_ILLUME_QUICKPANEL_STATE_OFF; + + return ECORE_X_ILLUME_QUICKPANEL_STATE_UNKNOWN; +} + +EAPI void +ecore_x_e_illume_quickpanel_set(Ecore_X_Window win, + unsigned int is_quickpanel) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_E_ILLUME_QUICKPANEL, + &is_quickpanel, 1); +} + +EAPI Eina_Bool +ecore_x_e_illume_quickpanel_get(Ecore_X_Window win) +{ + unsigned int val = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_E_ILLUME_QUICKPANEL, + &val, 1)) + return EINA_FALSE; + + return val ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_x_e_illume_quickpanel_state_set(Ecore_X_Window win, + Ecore_X_Illume_Quickpanel_State state) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + atom = _ecore_x_e_quickpanel_atom_get(state); + ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE, + &atom, 1); +} + +EAPI Ecore_X_Illume_Quickpanel_State +ecore_x_e_illume_quickpanel_state_get(Ecore_X_Window win) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_atom_get(win, + ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE, + &atom, 1)) + return ECORE_X_ILLUME_QUICKPANEL_STATE_UNKNOWN; + + return _ecore_x_e_quickpanel_state_get(atom); +} + +EAPI void +ecore_x_e_illume_quickpanel_state_send(Ecore_X_Window win, + Ecore_X_Illume_Quickpanel_State state) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + _ecore_x_e_quickpanel_atom_get(state), + 0, 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_quickpanel_state_toggle(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, + ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE_TOGGLE, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + 0, 0, 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_quickpanel_priority_major_set(Ecore_X_Window win, + unsigned int priority) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_card32_set(win, + ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR, + &priority, 1); +} + +EAPI int +ecore_x_e_illume_quickpanel_priority_major_get(Ecore_X_Window win) +{ + unsigned int val = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_card32_get(win, + ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR, + &val, 1)) + return 0; + + return val; +} + +EAPI void +ecore_x_e_illume_quickpanel_priority_minor_set(Ecore_X_Window win, + unsigned int priority) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_card32_set(win, + ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MINOR, + &priority, 1); +} + +EAPI int +ecore_x_e_illume_quickpanel_priority_minor_get(Ecore_X_Window win) +{ + unsigned int val = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_card32_get(win, + ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MINOR, + &val, 1)) + return 0; + + return val; +} + +EAPI void +ecore_x_e_illume_quickpanel_zone_set(Ecore_X_Window win, + unsigned int zone) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_card32_set(win, + ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ZONE, + &zone, 1); +} + +EAPI int +ecore_x_e_illume_quickpanel_zone_get(Ecore_X_Window win) +{ + unsigned int val = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_card32_get(win, + ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ZONE, + &val, 1)) + return 0; + + return val; +} + +EAPI void +ecore_x_e_illume_quickpanel_position_update_send(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, + ECORE_X_ATOM_E_ILLUME_QUICKPANEL_POSITION_UPDATE, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + 1, 0, 0, 0, 0); +} + +static Ecore_X_Atom +_ecore_x_e_clipboard_atom_get(Ecore_X_Illume_Clipboard_State state) +{ + switch (state) + { + case ECORE_X_ILLUME_CLIPBOARD_STATE_ON: + return ECORE_X_ATOM_E_ILLUME_CLIPBOARD_ON; + case ECORE_X_ILLUME_CLIPBOARD_STATE_OFF: + return ECORE_X_ATOM_E_ILLUME_CLIPBOARD_OFF; + default: + break; + } + return 0; +} + +static Ecore_X_Illume_Clipboard_State +_ecore_x_e_clipboard_state_get(Ecore_X_Atom atom) +{ + if (atom == ECORE_X_ATOM_E_ILLUME_CLIPBOARD_ON) + return ECORE_X_ILLUME_CLIPBOARD_STATE_ON; + + if (atom == ECORE_X_ATOM_E_ILLUME_CLIPBOARD_OFF) + return ECORE_X_ILLUME_CLIPBOARD_STATE_OFF; + + return ECORE_X_ILLUME_INDICATOR_STATE_UNKNOWN; +} + +EAPI void +ecore_x_e_illume_clipboard_state_set(Ecore_X_Window win, + Ecore_X_Illume_Clipboard_State state) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + atom = _ecore_x_e_clipboard_atom_get(state); + + ecore_x_window_prop_atom_set(win, + ECORE_X_ATOM_E_ILLUME_CLIPBOARD_STATE, + &atom, 1); +} + +EAPI Ecore_X_Illume_Clipboard_State +ecore_x_e_illume_clipboard_state_get(Ecore_X_Window win) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ecore_x_window_prop_atom_get(win, + ECORE_X_ATOM_E_ILLUME_CLIPBOARD_STATE, + &atom, 1)) + return ECORE_X_ILLUME_CLIPBOARD_STATE_UNKNOWN; + return _ecore_x_e_clipboard_state_get(atom); +} + +EAPI void +ecore_x_e_illume_clipboard_geometry_set(Ecore_X_Window win, + int x, int y, int w, int h) +{ + unsigned int geom[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + geom[0] = x; + geom[1] = y; + geom[2] = w; + geom[3] = h; + ecore_x_window_prop_card32_set(win, + ECORE_X_ATOM_E_ILLUME_CLIPBOARD_GEOMETRY, + geom, 4); +} + +EAPI Eina_Bool +ecore_x_e_illume_clipboard_geometry_get(Ecore_X_Window win, + int *x, int *y, int *w, int *h) +{ + int ret = 0; + unsigned int geom[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ret = + ecore_x_window_prop_card32_get(win, + ECORE_X_ATOM_E_ILLUME_CLIPBOARD_GEOMETRY, + geom, 4); + if (ret != 4) return EINA_FALSE; + + if (x) *x = geom[0]; + if (y) *y = geom[1]; + if (w) *w = geom[2]; + if (h) *h = geom[3]; + + return EINA_TRUE; +} + +/* for sliding window */ +EAPI void +ecore_x_e_illume_sliding_win_state_set(Ecore_X_Window win, + unsigned int is_visible) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_card32_set(win, + ECORE_X_ATOM_E_ILLUME_SLIDING_WIN_STATE, + &is_visible, 1); +} /* ecore_x_e_illume_sliding_win_state_set */ + +EAPI int +ecore_x_e_illume_sliding_win_state_get(Ecore_X_Window win) +{ + unsigned int is_visible = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_card32_get(win, + ECORE_X_ATOM_E_ILLUME_SLIDING_WIN_STATE, + &is_visible, 1)) + return 0; + + return is_visible; +} + +EAPI void +ecore_x_e_illume_sliding_win_geometry_set(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ + unsigned int geom[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + geom[0] = x; + geom[1] = y; + geom[2] = w; + geom[3] = h; + ecore_x_window_prop_card32_set(win, + ECORE_X_ATOM_E_ILLUME_SLIDING_WIN_GEOMETRY, + geom, 4); +} /* ecore_x_e_illume_sliding_win_geometry_set */ + +EAPI int +ecore_x_e_illume_sliding_win_geometry_get(Ecore_X_Window win, + int *x, + int *y, + int *w, + int *h) +{ + int ret = 0; + unsigned int geom[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ret = + ecore_x_window_prop_card32_get(win, + ECORE_X_ATOM_E_ILLUME_SLIDING_WIN_GEOMETRY, + geom, 4); + if (ret != 4) + return 0; + + if (x) + *x = geom[0]; + + if (y) + *y = geom[1]; + + if (w) + *w = geom[2]; + + if (h) + *h = geom[3]; + + return 1; +}/* ecore_x_e_illume_sliding_win_geometry_get */ + +EAPI void +ecore_x_e_comp_sync_counter_set(Ecore_X_Window win, + Ecore_X_Sync_Counter counter) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (counter) + ecore_x_window_prop_xid_set(win, ECORE_X_ATOM_E_COMP_SYNC_COUNTER, + ECORE_X_ATOM_CARDINAL, &counter, 1); + else + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_E_COMP_SYNC_COUNTER); +} + +EAPI Ecore_X_Sync_Counter +ecore_x_e_comp_sync_counter_get(Ecore_X_Window win) +{ + int ret = 0; + Ecore_X_Sync_Counter counter = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ret = + ecore_x_window_prop_xid_get(win, + ECORE_X_ATOM_E_COMP_SYNC_COUNTER, + ECORE_X_ATOM_CARDINAL, + &counter, 1); + if (ret != 1) + return 0; + + return counter; +} + +EAPI void +ecore_x_e_comp_sync_draw_done_send(Ecore_X_Window root, + Ecore_X_Window win) +{ + XEvent xev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!root) + root = DefaultRootWindow(_ecore_x_disp); + + xev.xclient.type = ClientMessage; + xev.xclient.display = _ecore_x_disp; + xev.xclient.window = win; + xev.xclient.message_type = ECORE_X_ATOM_E_COMP_SYNC_DRAW_DONE; + xev.xclient.format = 32; + xev.xclient.data.l[0] = win; + xev.xclient.data.l[1] = 0; // version + xev.xclient.data.l[2] = 0; // later + xev.xclient.data.l[3] = 0; // later + xev.xclient.data.l[4] = 0; // later + + XSendEvent(_ecore_x_disp, root, False, + SubstructureRedirectMask | SubstructureNotifyMask, + &xev); +} + +EAPI void +ecore_x_e_comp_sync_draw_size_done_send(Ecore_X_Window root, + Ecore_X_Window win, + int w, + int h) +{ + XEvent xev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!root) + root = DefaultRootWindow(_ecore_x_disp); + + xev.xclient.type = ClientMessage; + xev.xclient.display = _ecore_x_disp; + xev.xclient.window = win; + xev.xclient.message_type = ECORE_X_ATOM_E_COMP_SYNC_DRAW_DONE; + xev.xclient.format = 32; + xev.xclient.data.l[0] = win; + xev.xclient.data.l[1] = 1; // version + xev.xclient.data.l[2] = w; // win width at draw time + xev.xclient.data.l[3] = h; // win height at draw time + xev.xclient.data.l[4] = 0; // later + + XSendEvent(_ecore_x_disp, root, False, + SubstructureRedirectMask | SubstructureNotifyMask, + &xev); +} + +/* + * @since 1.3 + * + */ +EAPI void +ecore_x_e_window_profile_list_set(Ecore_X_Window win, + const char **profiles, + unsigned int num_profiles) +{ + Ecore_X_Atom *atoms; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!win) + return; + + if (!num_profiles) + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_E_PROFILE_LIST); + else + { + atoms = alloca(num_profiles * sizeof(Ecore_X_Atom)); + ecore_x_atoms_get(profiles, num_profiles, atoms); + ecore_x_window_prop_property_set(win, + ECORE_X_ATOM_E_PROFILE_LIST, + XA_ATOM, 32, (void *)atoms, + num_profiles); + } +} + +/* + * @since 1.3 + */ +EAPI Eina_Bool +ecore_x_e_window_profile_list_get(Ecore_X_Window win, + const char ***profiles, + int *ret_num) +{ + unsigned char *data; + Ecore_X_Atom *atoms; + int num, i; + + if (ret_num) + *ret_num = 0; + + if (profiles) + *profiles = NULL; + + if (!win) + return EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_property_get(win, + ECORE_X_ATOM_E_PROFILE_LIST, + XA_ATOM, 32, &data, &num)) + return EINA_FALSE; + + if (ret_num) + *ret_num = num; + + if (profiles) + { + (*profiles) = calloc(num, sizeof(char *)); + if (!(*profiles)) + { + if (ret_num) + *ret_num = 0; + + if (data) + free(data); + + return EINA_FALSE; + } + + atoms = (Ecore_X_Atom *)data; + for (i = 0; i < num; i++) + (*profiles)[i] = ecore_x_atom_name_get(atoms[i]); + } + + if (data) + XFree(data); + + return EINA_TRUE; +} + +/* + * @since 1.3 + */ +EAPI void +ecore_x_e_window_profile_set(Ecore_X_Window win, + const char *profile) +{ + Ecore_X_Atom atom; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!win) + return; + + if (!profile) + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_E_PROFILE); + else + { + atom = ecore_x_atom_get(profile); + ecore_x_window_prop_property_set(win, ECORE_X_ATOM_E_PROFILE, + XA_ATOM, 32, (void *)&atom, 1); + } +} + +/* + * @since 1.3 + */ +EAPI char * +ecore_x_e_window_profile_get(Ecore_X_Window win) +{ + Ecore_X_Atom *atom = NULL; + unsigned char *data; + char *profile = NULL; + int num; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_property_get(win, ECORE_X_ATOM_E_PROFILE, + XA_ATOM, 32, &data, &num)) + return NULL; + + if (data) + atom = (Ecore_X_Atom *)data; + + if (atom) + profile = ecore_x_atom_name_get(atom[0]); + + return profile; +} + +EAPI void +ecore_x_e_comp_sync_supported_set(Ecore_X_Window root, + Eina_Bool enabled) +{ + Ecore_X_Window win; + + if (!root) + root = DefaultRootWindow(_ecore_x_disp); + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (enabled) + { + win = ecore_x_window_new(root, 1, 2, 3, 4); + ecore_x_window_prop_xid_set(win, ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED, + ECORE_X_ATOM_WINDOW, &win, 1); + ecore_x_window_prop_xid_set(root, ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED, + ECORE_X_ATOM_WINDOW, &win, 1); + } + else + { + int ret; + + ret = + ecore_x_window_prop_xid_get(root, + ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED, + ECORE_X_ATOM_WINDOW, + &win, 1); + if ((ret == 1) && (win)) + { + ecore_x_window_prop_property_del( + root, + ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED); + ecore_x_window_free(win); + } + } +} + +EAPI Eina_Bool +ecore_x_e_comp_sync_supported_get(Ecore_X_Window root) +{ + Ecore_X_Window win, win2; + int ret; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!root) + root = DefaultRootWindow(_ecore_x_disp); + + ret = + ecore_x_window_prop_xid_get(root, + ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED, + ECORE_X_ATOM_WINDOW, + &win, 1); + if ((ret == 1) && (win)) + { + ret = + ecore_x_window_prop_xid_get(win, + ECORE_X_ATOM_E_COMP_SYNC_SUPPORTED, + ECORE_X_ATOM_WINDOW, + &win2, 1); + if ((ret == 1) && (win2 == win)) + return EINA_TRUE; + } + + return EINA_FALSE; +} + +EAPI void +ecore_x_e_comp_sync_begin_send(Ecore_X_Window win) +{ + XEvent xev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + xev.xclient.type = ClientMessage; + xev.xclient.display = _ecore_x_disp; + xev.xclient.window = win; + xev.xclient.message_type = ECORE_X_ATOM_E_COMP_SYNC_BEGIN; + xev.xclient.format = 32; + xev.xclient.data.l[0] = win; + xev.xclient.data.l[1] = 0; // later + xev.xclient.data.l[2] = 0; // later + xev.xclient.data.l[3] = 0; // later + xev.xclient.data.l[4] = 0; // later + + XSendEvent(_ecore_x_disp, win, False, + NoEventMask, //SubstructureRedirectMask | SubstructureNotifyMask, + &xev); +} + +EAPI void +ecore_x_e_comp_sync_end_send(Ecore_X_Window win) +{ + XEvent xev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + xev.xclient.type = ClientMessage; + xev.xclient.display = _ecore_x_disp; + xev.xclient.window = win; + xev.xclient.message_type = ECORE_X_ATOM_E_COMP_SYNC_END; + xev.xclient.format = 32; + xev.xclient.data.l[0] = win; + xev.xclient.data.l[1] = 0; // later + xev.xclient.data.l[2] = 0; // later + xev.xclient.data.l[3] = 0; // later + xev.xclient.data.l[4] = 0; // later + + XSendEvent(_ecore_x_disp, win, False, + NoEventMask, //SubstructureRedirectMask | SubstructureNotifyMask, + &xev); +} + +EAPI void +ecore_x_e_comp_sync_cancel_send(Ecore_X_Window win) +{ + XEvent xev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + xev.xclient.type = ClientMessage; + xev.xclient.display = _ecore_x_disp; + xev.xclient.window = win; + xev.xclient.message_type = ECORE_X_ATOM_E_COMP_SYNC_CANCEL; + xev.xclient.format = 32; + xev.xclient.data.l[0] = win; + xev.xclient.data.l[1] = 0; // later + xev.xclient.data.l[2] = 0; // later + xev.xclient.data.l[3] = 0; // later + xev.xclient.data.l[4] = 0; // later + + XSendEvent(_ecore_x_disp, win, False, + NoEventMask, //SubstructureRedirectMask | SubstructureNotifyMask, + &xev); +} + +EAPI void +ecore_x_e_comp_flush_send(Ecore_X_Window win) +{ + XEvent xev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + xev.xclient.type = ClientMessage; + xev.xclient.display = _ecore_x_disp; + xev.xclient.window = win; + xev.xclient.message_type = ECORE_X_ATOM_E_COMP_FLUSH; + xev.xclient.format = 32; + xev.xclient.data.l[0] = win; + xev.xclient.data.l[1] = 0; // later + xev.xclient.data.l[2] = 0; // later + xev.xclient.data.l[3] = 0; // later + xev.xclient.data.l[4] = 0; // later + + XSendEvent(_ecore_x_disp, win, False, + NoEventMask, //SubstructureRedirectMask | SubstructureNotifyMask, + &xev); +} + +EAPI void +ecore_x_e_comp_dump_send(Ecore_X_Window win) +{ + XEvent xev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + xev.xclient.type = ClientMessage; + xev.xclient.display = _ecore_x_disp; + xev.xclient.window = win; + xev.xclient.message_type = ECORE_X_ATOM_E_COMP_DUMP; + xev.xclient.format = 32; + xev.xclient.data.l[0] = win; + xev.xclient.data.l[1] = 0; // later + xev.xclient.data.l[2] = 0; // later + xev.xclient.data.l[3] = 0; // later + xev.xclient.data.l[4] = 0; // later + + XSendEvent(_ecore_x_disp, win, False, + NoEventMask, //SubstructureRedirectMask | SubstructureNotifyMask, + &xev); +} + +EAPI void +ecore_x_e_comp_pixmap_set(Ecore_X_Window win, + Ecore_X_Pixmap pixmap) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (pixmap) + ecore_x_window_prop_xid_set(win, ECORE_X_ATOM_E_COMP_PIXMAP, + ECORE_X_ATOM_PIXMAP, &pixmap, 1); + else + ecore_x_window_prop_property_del(win, pixmap); +} + +EAPI Ecore_X_Pixmap +ecore_x_e_comp_pixmap_get(Ecore_X_Window win) +{ + int ret = 0; + Ecore_X_Pixmap pixmap = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ret = + ecore_x_window_prop_xid_get(win, + ECORE_X_ATOM_E_COMP_PIXMAP, + ECORE_X_ATOM_PIXMAP, + &pixmap, 1); + if (ret != 1) + return 0; + + return pixmap; +} + +static Ecore_X_Atom +_ecore_x_e_indicator_atom_get(Ecore_X_Illume_Indicator_State state) +{ + switch (state) + { + case ECORE_X_ILLUME_INDICATOR_STATE_ON: + return ECORE_X_ATOM_E_ILLUME_INDICATOR_ON; + + case ECORE_X_ILLUME_INDICATOR_STATE_OFF: + return ECORE_X_ATOM_E_ILLUME_INDICATOR_OFF; + + default: + break; + } + return 0; +} + +static Ecore_X_Illume_Indicator_State +_ecore_x_e_indicator_state_get(Ecore_X_Atom atom) +{ + if (atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_ON) + return ECORE_X_ILLUME_INDICATOR_STATE_ON; + + if (atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_OFF) + return ECORE_X_ILLUME_INDICATOR_STATE_OFF; + + return ECORE_X_ILLUME_INDICATOR_STATE_UNKNOWN; +} + +EAPI void +ecore_x_e_illume_indicator_state_set(Ecore_X_Window win, + Ecore_X_Illume_Indicator_State state) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + atom = _ecore_x_e_indicator_atom_get(state); + ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_E_ILLUME_INDICATOR_STATE, + &atom, 1); +} + +EAPI Ecore_X_Illume_Indicator_State +ecore_x_e_illume_indicator_state_get(Ecore_X_Window win) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_atom_get(win, + ECORE_X_ATOM_E_ILLUME_INDICATOR_STATE, + &atom, 1)) + return ECORE_X_ILLUME_INDICATOR_STATE_UNKNOWN; + + return _ecore_x_e_indicator_state_get(atom); +} + +EAPI void +ecore_x_e_illume_indicator_state_send(Ecore_X_Window win, + Ecore_X_Illume_Indicator_State state) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_E_ILLUME_INDICATOR_STATE, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + _ecore_x_e_indicator_atom_get(state), + 0, 0, 0, 0); +} + +static Ecore_X_Atom +_ecore_x_e_indicator_opacity_atom_get(Ecore_X_Illume_Indicator_Opacity_Mode mode) +{ + switch (mode) + { + case ECORE_X_ILLUME_INDICATOR_OPAQUE: + return ECORE_X_ATOM_E_ILLUME_INDICATOR_OPAQUE; + + case ECORE_X_ILLUME_INDICATOR_TRANSLUCENT: + return ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSLUCENT; + + case ECORE_X_ILLUME_INDICATOR_TRANSPARENT: + return ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSPARENT; + + default: + break; + } + return 0; +} + +static Ecore_X_Illume_Indicator_Opacity_Mode +_ecore_x_e_indicator_opacity_get(Ecore_X_Atom atom) +{ + if (atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_OPAQUE) + return ECORE_X_ILLUME_INDICATOR_OPAQUE; + + if (atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSLUCENT) + return ECORE_X_ILLUME_INDICATOR_TRANSLUCENT; + + if (atom == ECORE_X_ATOM_E_ILLUME_INDICATOR_TRANSPARENT) + return ECORE_X_ILLUME_INDICATOR_TRANSPARENT; + + return ECORE_X_ILLUME_INDICATOR_OPACITY_UNKNOWN; +} + +EAPI void +ecore_x_e_illume_indicator_opacity_set(Ecore_X_Window win, + Ecore_X_Illume_Indicator_Opacity_Mode mode) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + atom = _ecore_x_e_indicator_opacity_atom_get(mode); + ecore_x_window_prop_atom_set(win, + ECORE_X_ATOM_E_ILLUME_INDICATOR_OPACITY_MODE, + &atom, 1); +} + +EAPI Ecore_X_Illume_Indicator_Opacity_Mode +ecore_x_e_illume_indicator_opacity_get(Ecore_X_Window win) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_atom_get(win, + ECORE_X_ATOM_E_ILLUME_INDICATOR_OPACITY_MODE, + &atom, 1)) + return ECORE_X_ILLUME_INDICATOR_OPACITY_UNKNOWN; + + return _ecore_x_e_indicator_opacity_get(atom); +} + +EAPI void +ecore_x_e_illume_indicator_opacity_send(Ecore_X_Window win, + Ecore_X_Illume_Indicator_Opacity_Mode mode) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, + ECORE_X_ATOM_E_ILLUME_INDICATOR_OPACITY_MODE, + ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, + _ecore_x_e_indicator_opacity_atom_get(mode), + 0, 0, 0, 0); +} + +static Ecore_X_Atom +_ecore_x_e_illume_window_state_atom_get(Ecore_X_Illume_Window_State state) +{ + switch (state) + { + case ECORE_X_ILLUME_WINDOW_STATE_NORMAL: + return ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_NORMAL; + + case ECORE_X_ILLUME_WINDOW_STATE_FLOATING: + return ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_FLOATING; + + default: + break; + } + return 0; +} + +static Ecore_X_Illume_Window_State +_ecore_x_e_illume_window_state_get(Ecore_X_Atom atom) +{ + if (atom == ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_NORMAL) + return ECORE_X_ILLUME_WINDOW_STATE_NORMAL; + + if (atom == ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_FLOATING) + return ECORE_X_ILLUME_WINDOW_STATE_FLOATING; + + return ECORE_X_ILLUME_WINDOW_STATE_NORMAL; +} + +EAPI void +ecore_x_e_illume_window_state_set(Ecore_X_Window win, + Ecore_X_Illume_Window_State state) +{ + Ecore_X_Atom atom = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + atom = _ecore_x_e_illume_window_state_atom_get(state); + ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_E_ILLUME_WINDOW_STATE, + &atom, 1); +} + +EAPI Ecore_X_Illume_Window_State +ecore_x_e_illume_window_state_get(Ecore_X_Window win) +{ + Ecore_X_Atom atom; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_atom_get(win, + ECORE_X_ATOM_E_ILLUME_WINDOW_STATE, + &atom, 1)) + return ECORE_X_ILLUME_WINDOW_STATE_NORMAL; + + return _ecore_x_e_illume_window_state_get(atom); +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_error.c b/src/lib/ecore_x/xlib/ecore_x_error.c new file mode 100644 index 0000000..f6eb075 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_error.c @@ -0,0 +1,126 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include + +#include "Ecore.h" +#include "ecore_private.h" +#include "ecore_x_private.h" +#include "Ecore_X.h" + +static int _ecore_x_error_handle(Display *d, + XErrorEvent *ev); +static int _ecore_x_io_error_handle(Display *d); + +static void (*_error_func)(void *data) = NULL; +static void *_error_data = NULL; +static void (*_io_error_func)(void *data) = NULL; +static void *_io_error_data = NULL; +static int _error_request_code = 0; +static int _error_code = 0; +static Ecore_X_ID _error_resource_id = 0; + +/** + * Set the error handler. + * @param func The error handler function + * @param data The data to be passed to the handler function + * + * Set the X error handler function + */ +EAPI void +ecore_x_error_handler_set(void (*func)(void *data), + const void *data) +{ + _error_func = func; + _error_data = (void *)data; +} + +/** + * Set the I/O error handler. + * @param func The I/O error handler function + * @param data The data to be passed to the handler function + * + * Set the X I/O error handler function + */ +EAPI void +ecore_x_io_error_handler_set(void (*func)(void *data), + const void *data) +{ + _io_error_func = func; + _io_error_data = (void *)data; +} + +/** + * Get the request code that caused the error. + * @return The request code causing the X error + * + * Return the X request code that caused the last X error + */ +EAPI int +ecore_x_error_request_get(void) +{ + return _error_request_code; +} + +/** + * Get the error code from the error. + * @return The error code from the X error + * + * Return the error code from the last X error + */ +//FIXME: Use Ecore_X_Error_Code type when 2.0 is released +EAPI int +ecore_x_error_code_get(void) +{ + return _error_code; +} + +/** + * Get the resource id that caused the error. + * @return The resource id causing the X error + * + * Return the X resource id that caused the last X error + */ +EAPI Ecore_X_ID +ecore_x_error_resource_id_get(void) +{ + return _error_resource_id; +} + +void +_ecore_x_error_handler_init(void) +{ + XSetErrorHandler((XErrorHandler)_ecore_x_error_handle); + XSetIOErrorHandler((XIOErrorHandler)_ecore_x_io_error_handle); +} + +static int +_ecore_x_error_handle(Display *d, + XErrorEvent *ev) +{ + if (d == _ecore_x_disp) + { + _error_request_code = ev->request_code; + _error_code = ev->error_code; + _error_resource_id = ev->resourceid; + if (_error_func) + _error_func(_error_data); + } + return 0; +} + +static int +_ecore_x_io_error_handle(Display *d) +{ + if (d == _ecore_x_disp) + { + if (_io_error_func) + _io_error_func(_io_error_data); + else + exit(-1); + } + + return 0; +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_events.c b/src/lib/ecore_x/xlib/ecore_x_events.c new file mode 100644 index 0000000..7d685cf --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_events.c @@ -0,0 +1,2527 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include +#include +#include + +#include + +#include "Ecore.h" +#include "ecore_private.h" +#include "ecore_x_private.h" +#include "Ecore_X.h" +#include "Ecore_X_Atoms.h" + +/** OpenBSD does not define CODESET + * FIXME ?? + */ + +#ifndef CODESET +#define CODESET "INVALID" +#endif /* ifndef CODESET */ + +typedef struct _Ecore_X_Mouse_Down_Info +{ + EINA_INLIST; + int dev; + Window last_win; + Window last_last_win; + Window last_event_win; + Window last_last_event_win; + Time last_time; + Time last_last_time; + Eina_Bool did_double : 1; + Eina_Bool did_triple : 1; +} Ecore_X_Mouse_Down_Info; + +static int _ecore_x_last_event_mouse_move = 0; +static Ecore_Event *_ecore_x_last_event_mouse_move_event = NULL; +static Eina_Inlist *_ecore_x_mouse_down_info_list = NULL; + +static void +_ecore_x_mouse_down_info_clear(void) +{ + Eina_Inlist *l = _ecore_x_mouse_down_info_list; + Ecore_X_Mouse_Down_Info *info = NULL; + while (l) + { + info = EINA_INLIST_CONTAINER_GET(l, Ecore_X_Mouse_Down_Info); + l = eina_inlist_remove(l, l); + free(info); + } + _ecore_x_mouse_down_info_list = NULL; +} + +void +_ecore_x_events_init(void) +{ + //Actually, Nothing to do. +} + +void +_ecore_x_events_shutdown(void) +{ + _ecore_x_mouse_down_info_clear(); +} + +static Ecore_X_Mouse_Down_Info * +_ecore_x_mouse_down_info_get(int dev) +{ + Eina_Inlist *l = _ecore_x_mouse_down_info_list; + Ecore_X_Mouse_Down_Info *info = NULL; + + //Return the exist info + EINA_INLIST_FOREACH(l, info) + if (info->dev == dev) return info; + + //New Device. Add it. + info = calloc(1, sizeof(Ecore_X_Mouse_Down_Info)); + if (!info) return NULL; + + info->dev = dev; + l = eina_inlist_append(l, (Eina_Inlist *)info); + _ecore_x_mouse_down_info_list = l; + return info; +} + +static void +_ecore_x_event_free_mouse_move(void *data __UNUSED__, + void *ev) +{ + Ecore_Event_Mouse_Move *e; + + e = ev; + if (_ecore_x_last_event_mouse_move) + { + _ecore_x_last_event_mouse_move_event = NULL; + _ecore_x_last_event_mouse_move = 0; + } + + free(e); +} + +EAPI void +ecore_x_event_mask_set(Ecore_X_Window w, + Ecore_X_Event_Mask mask) +{ + XWindowAttributes attr; + XSetWindowAttributes s_attr; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!w) + w = DefaultRootWindow(_ecore_x_disp); + + memset(&attr, 0, sizeof(XWindowAttributes)); + XGetWindowAttributes(_ecore_x_disp, w, &attr); + s_attr.event_mask = mask | attr.your_event_mask; + XChangeWindowAttributes(_ecore_x_disp, w, CWEventMask, &s_attr); +} + +EAPI void +ecore_x_event_mask_unset(Ecore_X_Window w, + Ecore_X_Event_Mask mask) +{ + XWindowAttributes attr; + XSetWindowAttributes s_attr; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!w) + w = DefaultRootWindow(_ecore_x_disp); + + memset(&attr, 0, sizeof(XWindowAttributes)); + XGetWindowAttributes(_ecore_x_disp, w, &attr); + s_attr.event_mask = attr.your_event_mask & ~mask; + XChangeWindowAttributes(_ecore_x_disp, w, CWEventMask, &s_attr); +} + +static void +_ecore_x_event_free_xdnd_enter(void *data __UNUSED__, + void *ev) +{ + Ecore_X_Event_Xdnd_Enter *e; + int i; + + e = ev; + for (i = 0; i < e->num_types; i++) + XFree(e->types[i]); + free(e->types); + free(e); +} + +static void +_ecore_x_event_free_selection_notify(void *data __UNUSED__, + void *ev) +{ + Ecore_X_Event_Selection_Notify *e; + Ecore_X_Selection_Data *sel; + + e = ev; + sel = e->data; + if (sel->free) + sel->free(sel); + + free(e->target); + free(e); +} + +static unsigned int +_ecore_x_event_modifiers(unsigned int state) +{ + unsigned int modifiers = 0; + + if (state & ECORE_X_MODIFIER_SHIFT) + modifiers |= ECORE_EVENT_MODIFIER_SHIFT; + + if (state & ECORE_X_MODIFIER_CTRL) + modifiers |= ECORE_EVENT_MODIFIER_CTRL; + + if (state & ECORE_X_MODIFIER_ALT) + modifiers |= ECORE_EVENT_MODIFIER_ALT; + + if (state & ECORE_X_MODIFIER_WIN) + modifiers |= ECORE_EVENT_MODIFIER_WIN; + + if (state & ECORE_X_MODIFIER_ALTGR) + modifiers |= ECORE_EVENT_MODIFIER_ALTGR; + + if (state & ECORE_X_LOCK_SCROLL) + modifiers |= ECORE_EVENT_LOCK_SCROLL; + + if (state & ECORE_X_LOCK_NUM) + modifiers |= ECORE_EVENT_LOCK_NUM; + + if (state & ECORE_X_LOCK_CAPS) + modifiers |= ECORE_EVENT_LOCK_CAPS; + + if (state & ECORE_X_LOCK_SHIFT) + modifiers |= ECORE_EVENT_LOCK_SHIFT; + + return modifiers; +} + +void +_ecore_mouse_move(unsigned int timestamp, + unsigned int xmodifiers, + int x, + int y, + int x_root, + int y_root, + unsigned int event_window, + unsigned int window, + unsigned int root_win, + int same_screen, + int dev, + double radx, + double rady, + double pressure, + double angle, + double mx, + double my, + double mrx, + double mry) +{ + Ecore_Event_Mouse_Move *e; + Ecore_Event *event; + + e = malloc(sizeof(Ecore_Event_Mouse_Move)); + if (!e) + return; + + e->window = window; + e->root_window = root_win; + e->timestamp = timestamp; + e->same_screen = same_screen; + e->event_window = event_window; + + e->modifiers = _ecore_x_event_modifiers(xmodifiers); + e->x = x; + e->y = y; + e->root.x = x_root; + e->root.y = y_root; + + e->multi.device = dev; + e->multi.radius = (radx + rady) / 2; + e->multi.radius_x = radx; + e->multi.radius_y = rady; + e->multi.pressure = pressure; + e->multi.angle = angle; + e->multi.x = mx; + e->multi.y = my; + e->multi.root.x = mrx; + e->multi.root.y = mry; + + event = ecore_event_add(ECORE_EVENT_MOUSE_MOVE, + e, + _ecore_x_event_free_mouse_move, + NULL); + + _ecore_x_event_last_time = timestamp; + _ecore_x_event_last_win = window; + _ecore_x_event_last_root_x = x_root; + _ecore_x_event_last_root_y = y_root; + + _ecore_x_last_event_mouse_move_event = event; +} + +static void +_ecore_key_press(int event, + XKeyEvent *xevent) +{ + Ecore_Event_Key *e; + char *compose = NULL; + char *tmp = NULL; + char *keyname; + char *key; + char keyname_buffer[256]; + char compose_buffer[256]; + KeySym sym; + XComposeStatus status; + int val; + + _ecore_x_last_event_mouse_move = 0; + keyname = XKeysymToString(_ecore_x_XKeycodeToKeysym(xevent->display, + xevent->keycode, 0)); + if (!keyname) + { + snprintf(keyname_buffer, + sizeof(keyname_buffer), + "Keycode-%i", + xevent->keycode); + keyname = keyname_buffer; + } + + sym = 0; + key = NULL; + compose = NULL; + val = XLookupString(xevent, + compose_buffer, + sizeof(compose_buffer), + &sym, + &status); + if (val > 0) + { + compose_buffer[val] = 0; + compose = eina_str_convert(nl_langinfo(CODESET), "UTF-8", + compose_buffer); + if (!compose) + ERR("Ecore_X cannot convert input key string '%s' to UTF-8. " + "Is Eina built with iconv support?", compose_buffer); + tmp = compose; + } + + key = XKeysymToString(sym); + if (!key) + key = keyname; + + e = + malloc(sizeof(Ecore_Event_Key) + strlen(key) + strlen(keyname) + + (compose ? strlen(compose) : 0) + 3); + if (!e) + goto on_error; + + e->keyname = (char *)(e + 1); + e->key = e->keyname + strlen(keyname) + 1; + e->compose = (compose) ? e->key + strlen(key) + 1 : NULL; + e->string = e->compose; + + strcpy((char *)e->keyname, keyname); + strcpy((char *)e->key, key); + if (compose) + strcpy((char *)e->compose, compose); + + e->modifiers = _ecore_x_event_modifiers(xevent->state); + + e->timestamp = xevent->time; + e->window = xevent->subwindow ? xevent->subwindow : xevent->window; + e->event_window = xevent->window; + e->same_screen = xevent->same_screen; + e->root_window = xevent->root; + + ecore_event_add(event, e, NULL, NULL); + + _ecore_x_event_last_time = e->timestamp; + +on_error: + if (tmp) + free(tmp); +} + +Ecore_Event_Mouse_Button * +_ecore_mouse_button(int event, + unsigned int timestamp, + unsigned int xmodifiers, + unsigned int buttons, + int x, + int y, + int x_root, + int y_root, + unsigned int event_window, + unsigned int window, + unsigned int root_win, + int same_screen, + int dev, + double radx, + double rady, + double pressure, + double angle, + double mx, + double my, + double mrx, + double mry) +{ + Ecore_Event_Mouse_Button *e; + + e = malloc(sizeof(Ecore_Event_Mouse_Button)); + if (!e) + return NULL; + + e->window = window; + e->root_window = root_win; + e->timestamp = timestamp; + e->same_screen = same_screen; + e->event_window = event_window; + + e->buttons = buttons; + e->modifiers = _ecore_x_event_modifiers(xmodifiers); + e->double_click = 0; + e->triple_click = 0; + e->x = x; + e->y = y; + e->root.x = x_root; + e->root.y = y_root; + + Ecore_X_Mouse_Down_Info *down_info = _ecore_x_mouse_down_info_get(dev); + + if (down_info) + { + if ((event == ECORE_EVENT_MOUSE_BUTTON_DOWN) && + down_info->did_triple) + { + down_info->last_win = 0; + down_info->last_last_win = 0; + down_info->last_event_win = 0; + down_info->last_last_event_win = 0; + down_info->last_time = 0; + down_info->last_last_time = 0; + } + if (event_window == window) + { + if (event == ECORE_EVENT_MOUSE_BUTTON_DOWN) + { + //Check Double Clicked + if (((int)(timestamp - down_info->last_time) <= + (int)(1000 * _ecore_x_double_click_time)) && + (window == down_info->last_win) && + (event_window == down_info->last_event_win)) + { + e->double_click = 1; + down_info->did_double = EINA_TRUE; + } + else + { + down_info->did_double = EINA_FALSE; + down_info->did_triple = EINA_FALSE; + } + + //Check Triple Clicked + if (((int)(timestamp - down_info->last_last_time) <= + (int)(2 * 1000 * _ecore_x_double_click_time)) && + (window == down_info->last_win) && + (window == down_info->last_last_win) && + (event_window == down_info->last_event_win) && + (event_window == down_info->last_last_event_win) + ) + { + e->triple_click = 1; + down_info->did_triple = EINA_TRUE; + } + else + { + down_info->did_triple = EINA_FALSE; + } + } + else + { + if (down_info->did_double) + e->double_click = 1; + if (down_info->did_triple) + e->triple_click = 1; + } + } + } + + /* NB: Block commented out as _ecore_x_mouse_up_count appears to have + * no use. The variable is also commented out above. This code block is + * the only place that this variable is used, and appears to serve no + * purpose. - dh + if (event == ECORE_EVENT_MOUSE_BUTTON_DOWN + && !e->double_click + && !e->triple_click) + _ecore_x_mouse_up_count = 0; + */ + + e->multi.device = dev; + e->multi.radius = (radx + rady) / 2; + e->multi.radius_x = radx; + e->multi.radius_y = rady; + e->multi.pressure = pressure; + e->multi.angle = angle; + e->multi.x = mx; + e->multi.y = my; + e->multi.root.x = mrx; + e->multi.root.y = mry; + + _ecore_x_event_last_time = e->timestamp; + _ecore_x_event_last_win = e->window; + _ecore_x_event_last_root_x = x_root; + _ecore_x_event_last_root_y = y_root; + + ecore_event_add(event, e, NULL, NULL); + + if ((down_info) && + (event == ECORE_EVENT_MOUSE_BUTTON_DOWN) && + (window == event_window) && + (!down_info->did_triple)) + { + down_info->last_last_win = down_info->last_win; + down_info->last_win = window; + down_info->last_last_event_win = down_info->last_event_win; + down_info->last_event_win = event_window; + down_info->last_last_time = down_info->last_time; + down_info->last_time = timestamp; + } + + return e; +} + +void +_ecore_x_event_handle_any_event(XEvent *xevent) +{ + XEvent *ev = malloc(sizeof(XEvent)); + if (!ev) return; + memcpy(ev, xevent, sizeof(XEvent)); + ecore_event_add(ECORE_X_EVENT_ANY, ev, NULL, NULL); +} + +void +_ecore_x_event_handle_key_press(XEvent *xevent) +{ + _ecore_key_press(ECORE_EVENT_KEY_DOWN, (XKeyEvent *)xevent); +} + +void +_ecore_x_event_handle_key_release(XEvent *xevent) +{ + _ecore_key_press(ECORE_EVENT_KEY_UP, (XKeyEvent *)xevent); +} + +void +_ecore_x_event_handle_button_press(XEvent *xevent) +{ + int i; + + _ecore_x_last_event_mouse_move = 0; + if ((xevent->xbutton.button > 3) && (xevent->xbutton.button < 8)) + { + Ecore_Event_Mouse_Wheel *e; + + e = malloc(sizeof(Ecore_Event_Mouse_Wheel)); + if (!e) + return; + + e->timestamp = xevent->xbutton.time; + e->modifiers = _ecore_x_event_modifiers(xevent->xbutton.state); + switch (xevent->xbutton.button) + { + case 4: e->direction = 0; e->z = -1; break; + + case 5: e->direction = 0; e->z = 1; break; + + case 6: e->direction = 1; e->z = -1; break; + + case 7: e->direction = 1; e->z = 1; break; + + default: e->direction = 0; e->z = 0; break; + } + + e->x = xevent->xbutton.x; + e->y = xevent->xbutton.y; + e->root.x = xevent->xbutton.x_root; + e->root.y = xevent->xbutton.y_root; + + if (xevent->xbutton.subwindow) + e->window = xevent->xbutton.subwindow; + else + e->window = xevent->xbutton.window; + + e->event_window = xevent->xbutton.window; + e->same_screen = xevent->xbutton.same_screen; + e->root_window = xevent->xbutton.root; + + _ecore_x_event_last_time = e->timestamp; + _ecore_x_event_last_win = e->window; + _ecore_x_event_last_root_x = xevent->xbutton.x_root; + _ecore_x_event_last_root_y = xevent->xbutton.y_root; + ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, e, NULL, NULL); + + for (i = 0; i < _ecore_window_grabs_num; i++) + { + if ((_ecore_window_grabs[i] == xevent->xbutton.window) || + (_ecore_window_grabs[i] == xevent->xbutton.subwindow)) + { + Eina_Bool replay = EINA_FALSE; + + if (_ecore_window_grab_replay_func) + replay = _ecore_window_grab_replay_func( + _ecore_window_grab_replay_data, + ECORE_EVENT_MOUSE_WHEEL, + e); + + if (replay) + XAllowEvents(xevent->xbutton.display, + ReplayPointer, xevent->xbutton.time); + else + XAllowEvents(xevent->xbutton.display, + AsyncPointer, xevent->xbutton.time); + + break; + } + } + } + else + { + { + _ecore_mouse_move(xevent->xbutton.time, xevent->xbutton.state, + xevent->xbutton.x, xevent->xbutton.y, + xevent->xbutton.x_root, xevent->xbutton.y_root, + xevent->xbutton.window, + (xevent->xbutton.subwindow ? xevent->xbutton. + subwindow : xevent->xbutton.window), + xevent->xbutton.root, + xevent->xbutton.same_screen, + 0, 1, 1, + 1.0, // pressure + 0.0, // angle + xevent->xbutton.x, xevent->xbutton.y, + xevent->xbutton.x_root, xevent->xbutton.y_root); + } + { + Ecore_Event_Mouse_Button *e; + int event_window; + int window; + + window = + (xevent->xbutton.subwindow ? xevent->xbutton.subwindow : xevent-> + xbutton.window); + event_window = xevent->xbutton.window; + + e = _ecore_mouse_button(ECORE_EVENT_MOUSE_BUTTON_DOWN, + xevent->xbutton.time, + xevent->xbutton.state, + xevent->xbutton.button, + xevent->xbutton.x, + xevent->xbutton.y, + xevent->xbutton.x_root, + xevent->xbutton.y_root, + event_window, + window, + xevent->xbutton.root, + xevent->xbutton.same_screen, + 0, + 1, + 1, + 1.0, +// pressure + 0.0, +// angle + xevent->xbutton.x, + xevent->xbutton.y, + xevent->xbutton.x_root, + xevent->xbutton.y_root); + if (e) + for (i = 0; i < _ecore_window_grabs_num; i++) + { + if ((_ecore_window_grabs[i] == xevent->xbutton.window) || + (_ecore_window_grabs[i] == xevent->xbutton.subwindow)) + { + Eina_Bool replay = EINA_FALSE; + + if (_ecore_window_grab_replay_func) + replay = _ecore_window_grab_replay_func( + _ecore_window_grab_replay_data, + ECORE_EVENT_MOUSE_BUTTON_DOWN, + e); + + if (replay) + XAllowEvents(xevent->xbutton.display, + ReplayPointer, xevent->xbutton.time); + else + XAllowEvents(xevent->xbutton.display, + AsyncPointer, xevent->xbutton.time); + + break; + } + } + } + } +} + +void +_ecore_x_event_handle_button_release(XEvent *xevent) +{ + _ecore_x_last_event_mouse_move = 0; + /* filter out wheel buttons */ + if ((xevent->xbutton.button <= 3) || (xevent->xbutton.button > 7)) + { + _ecore_mouse_move(xevent->xbutton.time, xevent->xbutton.state, + xevent->xbutton.x, xevent->xbutton.y, + xevent->xbutton.x_root, xevent->xbutton.y_root, + xevent->xbutton.window, + (xevent->xbutton.subwindow ? xevent->xbutton. + subwindow : xevent->xbutton.window), + xevent->xbutton.root, + xevent->xbutton.same_screen, + 0, 1, 1, + 1.0, // pressure + 0.0, // angle + xevent->xbutton.x, xevent->xbutton.y, + xevent->xbutton.x_root, xevent->xbutton.y_root); + + _ecore_mouse_button(ECORE_EVENT_MOUSE_BUTTON_UP, + xevent->xbutton.time, xevent->xbutton.state, + xevent->xbutton.button, + xevent->xbutton.x, xevent->xbutton.y, + xevent->xbutton.x_root, xevent->xbutton.y_root, + xevent->xbutton.window, + (xevent->xbutton.subwindow ? xevent->xbutton. + subwindow : xevent->xbutton.window), + xevent->xbutton.root, + xevent->xbutton.same_screen, + 0, 1, 1, + 1.0, // pressure + 0.0, // angle + xevent->xbutton.x, xevent->xbutton.y, + xevent->xbutton.x_root, xevent->xbutton.y_root); + } +} + +void +_ecore_x_event_handle_motion_notify(XEvent *xevent) +{ +/* + if (_ecore_x_last_event_mouse_move) + { + ecore_event_del(_ecore_x_last_event_mouse_move_event); + _ecore_x_last_event_mouse_move = 0; + _ecore_x_last_event_mouse_move_event = NULL; + } + */ + _ecore_mouse_move(xevent->xmotion.time, xevent->xmotion.state, + xevent->xmotion.x, xevent->xmotion.y, + xevent->xmotion.x_root, xevent->xmotion.y_root, + xevent->xmotion.window, + (xevent->xmotion.subwindow ? xevent->xmotion.subwindow : + xevent->xmotion.window), + xevent->xmotion.root, + xevent->xmotion.same_screen, + 0, 1, 1, + 1.0, // pressure + 0.0, // angle + xevent->xmotion.x, xevent->xmotion.y, + xevent->xmotion.x_root, xevent->xmotion.y_root); + + _ecore_x_last_event_mouse_move = 1; + + /* Xdnd handling */ + _ecore_x_dnd_drag(xevent->xmotion.root, + xevent->xmotion.x_root, + xevent->xmotion.y_root); +} + +void +_ecore_x_event_handle_enter_notify(XEvent *xevent) +{ + _ecore_x_last_event_mouse_move = 0; + { + _ecore_mouse_move(xevent->xcrossing.time, xevent->xcrossing.state, + xevent->xcrossing.x, xevent->xcrossing.y, + xevent->xcrossing.x_root, xevent->xcrossing.y_root, + xevent->xcrossing.window, + (xevent->xcrossing.subwindow ? xevent->xcrossing. + subwindow : xevent->xcrossing.window), + xevent->xcrossing.root, + xevent->xcrossing.same_screen, + 0, 1, 1, + 1.0, // pressure + 0.0, // angle + xevent->xcrossing.x, xevent->xcrossing.y, + xevent->xcrossing.x_root, xevent->xcrossing.y_root); + } + { + Ecore_X_Event_Mouse_In *e; + + e = calloc(1, sizeof(Ecore_X_Event_Mouse_In)); + if (!e) + return; + + e->modifiers = _ecore_x_event_modifiers(xevent->xcrossing.state); + e->x = xevent->xcrossing.x; + e->y = xevent->xcrossing.y; + e->root.x = xevent->xcrossing.x_root; + e->root.y = xevent->xcrossing.y_root; + if (xevent->xcrossing.subwindow) + e->win = xevent->xcrossing.subwindow; + else + e->win = xevent->xcrossing.window; + + e->same_screen = xevent->xcrossing.same_screen; + e->root_win = xevent->xcrossing.root; + e->event_win = xevent->xcrossing.window; + + if (xevent->xcrossing.mode == NotifyNormal) + e->mode = ECORE_X_EVENT_MODE_NORMAL; + else if (xevent->xcrossing.mode == NotifyGrab) + e->mode = ECORE_X_EVENT_MODE_GRAB; + else if (xevent->xcrossing.mode == NotifyUngrab) + e->mode = ECORE_X_EVENT_MODE_UNGRAB; + + if (xevent->xcrossing.detail == NotifyAncestor) + e->detail = ECORE_X_EVENT_DETAIL_ANCESTOR; + else if (xevent->xcrossing.detail == NotifyVirtual) + e->detail = ECORE_X_EVENT_DETAIL_VIRTUAL; + else if (xevent->xcrossing.detail == NotifyInferior) + e->detail = ECORE_X_EVENT_DETAIL_INFERIOR; + else if (xevent->xcrossing.detail == NotifyNonlinear) + e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR; + else if (xevent->xcrossing.detail == NotifyNonlinearVirtual) + e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL; + + e->time = xevent->xcrossing.time; + _ecore_x_event_last_time = e->time; + ecore_event_add(ECORE_X_EVENT_MOUSE_IN, e, NULL, NULL); + } +} + +void +_ecore_x_event_handle_leave_notify(XEvent *xevent) +{ + _ecore_x_last_event_mouse_move = 0; + { + _ecore_mouse_move(xevent->xcrossing.time, xevent->xcrossing.state, + xevent->xcrossing.x, xevent->xcrossing.y, + xevent->xcrossing.x_root, xevent->xcrossing.y_root, + xevent->xcrossing.window, + (xevent->xcrossing.subwindow ? xevent->xcrossing. + subwindow : xevent->xcrossing.window), + xevent->xcrossing.root, + xevent->xcrossing.same_screen, + 0, 1, 1, + 1.0, // pressure + 0.0, // angle + xevent->xcrossing.x, xevent->xcrossing.y, + xevent->xcrossing.x_root, xevent->xcrossing.y_root); + } + { + Ecore_X_Event_Mouse_Out *e; + + e = calloc(1, sizeof(Ecore_X_Event_Mouse_Out)); + if (!e) + return; + + e->modifiers = _ecore_x_event_modifiers(xevent->xcrossing.state); + e->x = xevent->xcrossing.x; + e->y = xevent->xcrossing.y; + e->root.x = xevent->xcrossing.x_root; + e->root.y = xevent->xcrossing.y_root; + if (xevent->xcrossing.subwindow) + e->win = xevent->xcrossing.subwindow; + else + e->win = xevent->xcrossing.window; + + e->same_screen = xevent->xcrossing.same_screen; + e->root_win = xevent->xcrossing.root; + e->event_win = xevent->xcrossing.window; + + if (xevent->xcrossing.mode == NotifyNormal) + e->mode = ECORE_X_EVENT_MODE_NORMAL; + else if (xevent->xcrossing.mode == NotifyGrab) + e->mode = ECORE_X_EVENT_MODE_GRAB; + else if (xevent->xcrossing.mode == NotifyUngrab) + e->mode = ECORE_X_EVENT_MODE_UNGRAB; + + if (xevent->xcrossing.detail == NotifyAncestor) + e->detail = ECORE_X_EVENT_DETAIL_ANCESTOR; + else if (xevent->xcrossing.detail == NotifyVirtual) + e->detail = ECORE_X_EVENT_DETAIL_VIRTUAL; + else if (xevent->xcrossing.detail == NotifyInferior) + e->detail = ECORE_X_EVENT_DETAIL_INFERIOR; + else if (xevent->xcrossing.detail == NotifyNonlinear) + e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR; + else if (xevent->xcrossing.detail == NotifyNonlinearVirtual) + e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL; + + e->time = xevent->xcrossing.time; + _ecore_x_event_last_time = e->time; + _ecore_x_event_last_win = e->win; + _ecore_x_event_last_root_x = e->root.x; + _ecore_x_event_last_root_y = e->root.y; + ecore_event_add(ECORE_X_EVENT_MOUSE_OUT, e, NULL, NULL); + } +} + +void +_ecore_x_event_handle_focus_in(XEvent *xevent) +{ + Ecore_X_Event_Window_Focus_In *e; + + _ecore_x_last_event_mouse_move = 0; + + e = calloc(1, sizeof(Ecore_X_Event_Window_Focus_In)); + if (!e) + return; + + e->win = xevent->xfocus.window; + + if (xevent->xfocus.mode == NotifyNormal) + e->mode = ECORE_X_EVENT_MODE_NORMAL; + else if (xevent->xfocus.mode == NotifyWhileGrabbed) + e->mode = ECORE_X_EVENT_MODE_WHILE_GRABBED; + else if (xevent->xfocus.mode == NotifyGrab) + e->mode = ECORE_X_EVENT_MODE_GRAB; + else if (xevent->xfocus.mode == NotifyUngrab) + e->mode = ECORE_X_EVENT_MODE_UNGRAB; + + if (xevent->xfocus.detail == NotifyAncestor) + e->detail = ECORE_X_EVENT_DETAIL_ANCESTOR; + else if (xevent->xfocus.detail == NotifyVirtual) + e->detail = ECORE_X_EVENT_DETAIL_VIRTUAL; + else if (xevent->xfocus.detail == NotifyInferior) + e->detail = ECORE_X_EVENT_DETAIL_INFERIOR; + else if (xevent->xfocus.detail == NotifyNonlinear) + e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR; + else if (xevent->xfocus.detail == NotifyNonlinearVirtual) + e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL; + else if (xevent->xfocus.detail == NotifyPointer) + e->detail = ECORE_X_EVENT_DETAIL_POINTER; + else if (xevent->xfocus.detail == NotifyPointerRoot) + e->detail = ECORE_X_EVENT_DETAIL_POINTER_ROOT; + else if (xevent->xfocus.detail == NotifyDetailNone) + e->detail = ECORE_X_EVENT_DETAIL_DETAIL_NONE; + + e->time = _ecore_x_event_last_time; + _ecore_x_event_last_time = e->time; + ecore_event_add(ECORE_X_EVENT_WINDOW_FOCUS_IN, e, NULL, NULL); +} + +void +_ecore_x_event_handle_focus_out(XEvent *xevent) +{ + Ecore_X_Event_Window_Focus_Out *e; + + _ecore_x_last_event_mouse_move = 0; + + e = calloc(1, sizeof(Ecore_X_Event_Window_Focus_Out)); + if (!e) + return; + + e->win = xevent->xfocus.window; + + if (xevent->xfocus.mode == NotifyNormal) + e->mode = ECORE_X_EVENT_MODE_NORMAL; + else if (xevent->xfocus.mode == NotifyWhileGrabbed) + e->mode = ECORE_X_EVENT_MODE_WHILE_GRABBED; + else if (xevent->xfocus.mode == NotifyGrab) + e->mode = ECORE_X_EVENT_MODE_GRAB; + else if (xevent->xfocus.mode == NotifyUngrab) + e->mode = ECORE_X_EVENT_MODE_UNGRAB; + + if (xevent->xfocus.detail == NotifyAncestor) + e->detail = ECORE_X_EVENT_DETAIL_ANCESTOR; + else if (xevent->xfocus.detail == NotifyVirtual) + e->detail = ECORE_X_EVENT_DETAIL_VIRTUAL; + else if (xevent->xfocus.detail == NotifyInferior) + e->detail = ECORE_X_EVENT_DETAIL_INFERIOR; + else if (xevent->xfocus.detail == NotifyNonlinear) + e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR; + else if (xevent->xfocus.detail == NotifyNonlinearVirtual) + e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL; + else if (xevent->xfocus.detail == NotifyPointer) + e->detail = ECORE_X_EVENT_DETAIL_POINTER; + else if (xevent->xfocus.detail == NotifyPointerRoot) + e->detail = ECORE_X_EVENT_DETAIL_POINTER_ROOT; + else if (xevent->xfocus.detail == NotifyDetailNone) + e->detail = ECORE_X_EVENT_DETAIL_DETAIL_NONE; + + e->time = _ecore_x_event_last_time; + _ecore_x_event_last_time = e->time; + ecore_event_add(ECORE_X_EVENT_WINDOW_FOCUS_OUT, e, NULL, NULL); +} + +void +_ecore_x_event_handle_keymap_notify(XEvent *xevent __UNUSED__) +{ + _ecore_x_last_event_mouse_move = 0; + /* FIXME: handle this event type */ +} + +void +_ecore_x_event_handle_expose(XEvent *xevent) +{ + Ecore_X_Event_Window_Damage *e; + + _ecore_x_last_event_mouse_move = 0; + e = calloc(1, sizeof(Ecore_X_Event_Window_Damage)); + if (!e) + return; + + e->win = xevent->xexpose.window; + e->time = _ecore_x_event_last_time; + e->x = xevent->xexpose.x; + e->y = xevent->xexpose.y; + e->w = xevent->xexpose.width; + e->h = xevent->xexpose.height; + e->count = xevent->xexpose.count; + ecore_event_add(ECORE_X_EVENT_WINDOW_DAMAGE, e, NULL, NULL); +} + +void +_ecore_x_event_handle_graphics_expose(XEvent *xevent) +{ + Ecore_X_Event_Window_Damage *e; + + _ecore_x_last_event_mouse_move = 0; + e = calloc(1, sizeof(Ecore_X_Event_Window_Damage)); + if (!e) + return; + + e->win = xevent->xgraphicsexpose.drawable; + e->time = _ecore_x_event_last_time; + e->x = xevent->xgraphicsexpose.x; + e->y = xevent->xgraphicsexpose.y; + e->w = xevent->xgraphicsexpose.width; + e->h = xevent->xgraphicsexpose.height; + e->count = xevent->xgraphicsexpose.count; + ecore_event_add(ECORE_X_EVENT_WINDOW_DAMAGE, e, NULL, NULL); +} + +void +_ecore_x_event_handle_visibility_notify(XEvent *xevent) +{ + _ecore_x_last_event_mouse_move = 0; +// if (xevent->xvisibility.state != VisibilityPartiallyObscured) + { + Ecore_X_Event_Window_Visibility_Change *e; + + e = calloc(1, sizeof(Ecore_X_Event_Window_Visibility_Change)); + if (!e) + return; + + e->win = xevent->xvisibility.window; + e->time = _ecore_x_event_last_time; + if (xevent->xvisibility.state == VisibilityFullyObscured) + e->fully_obscured = 1; + else + e->fully_obscured = 0; + + ecore_event_add(ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE, e, NULL, NULL); + } +} + +void +_ecore_x_event_handle_create_notify(XEvent *xevent) +{ + Ecore_X_Event_Window_Create *e; + + _ecore_x_last_event_mouse_move = 0; + e = calloc(1, sizeof(Ecore_X_Event_Window_Create)); + if (!e) + return; + + e->win = xevent->xcreatewindow.window; + e->parent = xevent->xcreatewindow.parent; + if (xevent->xcreatewindow.override_redirect) + e->override = 1; + else + e->override = 0; + + e->x = xevent->xcreatewindow.x; + e->y = xevent->xcreatewindow.y; + e->w = xevent->xcreatewindow.width; + e->h = xevent->xcreatewindow.height; + e->border = xevent->xcreatewindow.border_width; + e->time = _ecore_x_event_last_time; + ecore_event_add(ECORE_X_EVENT_WINDOW_CREATE, e, NULL, NULL); +} + +void +_ecore_x_event_handle_destroy_notify(XEvent *xevent) +{ + Ecore_X_Event_Window_Destroy *e; + + _ecore_x_last_event_mouse_move = 0; + e = calloc(1, sizeof(Ecore_X_Event_Window_Destroy)); + if (!e) + return; + + e->win = xevent->xdestroywindow.window; + e->event_win = xevent->xdestroywindow.event; + e->time = _ecore_x_event_last_time; + if (e->win == _ecore_x_event_last_win) + _ecore_x_event_last_win = 0; + + ecore_event_add(ECORE_X_EVENT_WINDOW_DESTROY, e, NULL, NULL); +} + +void +_ecore_x_event_handle_unmap_notify(XEvent *xevent) +{ + Ecore_X_Event_Window_Hide *e; + + _ecore_x_last_event_mouse_move = 0; + e = calloc(1, sizeof(Ecore_X_Event_Window_Hide)); + if (!e) + return; + + e->win = xevent->xunmap.window; + e->event_win = xevent->xunmap.event; + e->time = _ecore_x_event_last_time; + ecore_event_add(ECORE_X_EVENT_WINDOW_HIDE, e, NULL, NULL); +} + +void +_ecore_x_event_handle_map_notify(XEvent *xevent) +{ + Ecore_X_Event_Window_Show *e; + + _ecore_x_last_event_mouse_move = 0; + e = calloc(1, sizeof(Ecore_X_Event_Window_Show)); + if (!e) + return; + + e->win = xevent->xmap.window; + e->event_win = xevent->xmap.event; + e->time = _ecore_x_event_last_time; + ecore_event_add(ECORE_X_EVENT_WINDOW_SHOW, e, NULL, NULL); +} + +void +_ecore_x_event_handle_map_request(XEvent *xevent) +{ + Ecore_X_Event_Window_Show_Request *e; + + _ecore_x_last_event_mouse_move = 0; + e = calloc(1, sizeof(Ecore_X_Event_Window_Show_Request)); + if (!e) + return; + + e->win = xevent->xmaprequest.window; + e->time = _ecore_x_event_last_time; + e->parent = xevent->xmaprequest.parent; + ecore_event_add(ECORE_X_EVENT_WINDOW_SHOW_REQUEST, e, NULL, NULL); +} + +void +_ecore_x_event_handle_reparent_notify(XEvent *xevent) +{ + Ecore_X_Event_Window_Reparent *e; + + _ecore_x_last_event_mouse_move = 0; + e = calloc(1, sizeof(Ecore_X_Event_Window_Reparent)); + if (!e) + return; + + e->win = xevent->xreparent.window; + e->event_win = xevent->xreparent.event; + e->parent = xevent->xreparent.parent; + e->time = _ecore_x_event_last_time; + ecore_event_add(ECORE_X_EVENT_WINDOW_REPARENT, e, NULL, NULL); +} + +void +_ecore_x_event_handle_configure_notify(XEvent *xevent) +{ + Ecore_X_Event_Window_Configure *e; + + _ecore_x_last_event_mouse_move = 0; + e = calloc(1, sizeof(Ecore_X_Event_Window_Configure)); + if (!e) + return; + + e->win = xevent->xconfigure.window; + e->event_win = xevent->xconfigure.event; + e->abovewin = xevent->xconfigure.above; + e->x = xevent->xconfigure.x; + e->y = xevent->xconfigure.y; + e->w = xevent->xconfigure.width; + e->h = xevent->xconfigure.height; + e->border = xevent->xconfigure.border_width; + e->override = xevent->xconfigure.override_redirect; + e->from_wm = xevent->xconfigure.send_event; + e->time = _ecore_x_event_last_time; + ecore_event_add(ECORE_X_EVENT_WINDOW_CONFIGURE, e, NULL, NULL); +} + +void +_ecore_x_event_handle_configure_request(XEvent *xevent) +{ + Ecore_X_Event_Window_Configure_Request *e; + + _ecore_x_last_event_mouse_move = 0; + e = calloc(1, sizeof(Ecore_X_Event_Window_Configure_Request)); + if (!e) + return; + + e->win = xevent->xconfigurerequest.window; + e->parent_win = xevent->xconfigurerequest.parent; + e->abovewin = xevent->xconfigurerequest.above; + e->x = xevent->xconfigurerequest.x; + e->y = xevent->xconfigurerequest.y; + e->w = xevent->xconfigurerequest.width; + e->h = xevent->xconfigurerequest.height; + e->border = xevent->xconfigurerequest.border_width; + e->value_mask = xevent->xconfigurerequest.value_mask; + e->time = _ecore_x_event_last_time; + + if (xevent->xconfigurerequest.detail == Above) + e->detail = ECORE_X_WINDOW_STACK_ABOVE; + else if (xevent->xconfigurerequest.detail == Below) + e->detail = ECORE_X_WINDOW_STACK_BELOW; + else if (xevent->xconfigurerequest.detail == TopIf) + e->detail = ECORE_X_WINDOW_STACK_TOP_IF; + else if (xevent->xconfigurerequest.detail == BottomIf) + e->detail = ECORE_X_WINDOW_STACK_BOTTOM_IF; + else if (xevent->xconfigurerequest.detail == Opposite) + e->detail = ECORE_X_WINDOW_STACK_OPPOSITE; + + ecore_event_add(ECORE_X_EVENT_WINDOW_CONFIGURE_REQUEST, e, NULL, NULL); +} + +void +_ecore_x_event_handle_gravity_notify(XEvent *xevent __UNUSED__) +{ + _ecore_x_last_event_mouse_move = 0; + /* FIXME: handle this event type */ +} + +void +_ecore_x_event_handle_resize_request(XEvent *xevent) +{ + Ecore_X_Event_Window_Resize_Request *e; + + _ecore_x_last_event_mouse_move = 0; + e = calloc(1, sizeof(Ecore_X_Event_Window_Resize_Request)); + if (!e) + return; + + e->win = xevent->xresizerequest.window; + e->w = xevent->xresizerequest.width; + e->h = xevent->xresizerequest.height; + e->time = _ecore_x_event_last_time; + ecore_event_add(ECORE_X_EVENT_WINDOW_RESIZE_REQUEST, e, NULL, NULL); +} + +void +_ecore_x_event_handle_circulate_notify(XEvent *xevent) +{ + Ecore_X_Event_Window_Stack *e; + + _ecore_x_last_event_mouse_move = 0; + e = calloc(1, sizeof(Ecore_X_Event_Window_Stack)); + if (!e) + return; + + e->win = xevent->xcirculate.window; + e->event_win = xevent->xcirculate.event; + if (xevent->xcirculate.place == PlaceOnTop) + e->detail = ECORE_X_WINDOW_STACK_ABOVE; + else + e->detail = ECORE_X_WINDOW_STACK_BELOW; + + e->time = _ecore_x_event_last_time; + ecore_event_add(ECORE_X_EVENT_WINDOW_STACK, e, NULL, NULL); +} + +void +_ecore_x_event_handle_circulate_request(XEvent *xevent) +{ + Ecore_X_Event_Window_Stack_Request *e; + + _ecore_x_last_event_mouse_move = 0; + e = calloc(1, sizeof(Ecore_X_Event_Window_Stack_Request)); + if (!e) + return; + + e->win = xevent->xcirculaterequest.window; + e->parent = xevent->xcirculaterequest.parent; + if (xevent->xcirculaterequest.place == PlaceOnTop) + e->detail = ECORE_X_WINDOW_STACK_ABOVE; + else + e->detail = ECORE_X_WINDOW_STACK_BELOW; + + e->time = _ecore_x_event_last_time; + ecore_event_add(ECORE_X_EVENT_WINDOW_STACK_REQUEST, e, NULL, NULL); +} + +void +_ecore_x_event_handle_property_notify(XEvent *xevent) +{ + _ecore_x_last_event_mouse_move = 0; + { + Ecore_X_Event_Window_Property *e; + + e = calloc(1, sizeof(Ecore_X_Event_Window_Property)); + if (!e) + return; + + e->win = xevent->xproperty.window; + e->atom = xevent->xproperty.atom; + e->time = xevent->xproperty.time; + _ecore_x_event_last_time = e->time; + ecore_event_add(ECORE_X_EVENT_WINDOW_PROPERTY, e, NULL, NULL); + } +} + +void +_ecore_x_event_handle_selection_clear(XEvent *xevent) +{ +// Ecore_X_Selection_Intern *d; + Ecore_X_Event_Selection_Clear *e; + Ecore_X_Atom sel; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _ecore_x_last_event_mouse_move = 0; +/* errr..... why? paranoia. + d = _ecore_x_selection_get(xevent->xselectionclear.selection); + if (d && (xevent->xselectionclear.time > d->time)) + { + _ecore_x_selection_set(None, NULL, 0, + xevent->xselectionclear.selection); + } + */ +/* Generate event for app cleanup */ + e = malloc(sizeof(Ecore_X_Event_Selection_Clear)); + e->win = xevent->xselectionclear.window; + e->time = xevent->xselectionclear.time; + e->atom = sel = xevent->xselectionclear.selection; + if (sel == ECORE_X_ATOM_SELECTION_PRIMARY) + e->selection = ECORE_X_SELECTION_PRIMARY; + else if (sel == ECORE_X_ATOM_SELECTION_SECONDARY) + e->selection = ECORE_X_SELECTION_SECONDARY; + else if (sel == ECORE_X_ATOM_SELECTION_CLIPBOARD) + e->selection = ECORE_X_SELECTION_CLIPBOARD; + else + e->selection = ECORE_X_SELECTION_OTHER; + + ecore_event_add(ECORE_X_EVENT_SELECTION_CLEAR, e, NULL, NULL); +} + +void +_ecore_x_event_handle_selection_request(XEvent *xevent) +{ + Ecore_X_Event_Selection_Request *e; + Ecore_X_Selection_Intern *sd; + void *data = NULL; + int len; + int typesize; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _ecore_x_last_event_mouse_move = 0; + /* + * Generate a selection request event. + */ + e = malloc(sizeof(Ecore_X_Event_Selection_Request)); + e->owner = xevent->xselectionrequest.owner; + e->requestor = xevent->xselectionrequest.requestor; + e->time = xevent->xselectionrequest.time; + e->selection = xevent->xselectionrequest.selection; + e->target = xevent->xselectionrequest.target; + e->property = xevent->xselectionrequest.property; + ecore_event_add(ECORE_X_EVENT_SELECTION_REQUEST, e, NULL, NULL); + + if ((sd = _ecore_x_selection_get(xevent->xselectionrequest.selection)) && + (sd->win == xevent->xselectionrequest.owner)) + { + Ecore_X_Selection_Intern *si; + + si = _ecore_x_selection_get(xevent->xselectionrequest.selection); + if (si->data) + { + Ecore_X_Atom property = None; + Ecore_X_Atom type; + + /* Set up defaults for strings first */ + type = xevent->xselectionrequest.target; + typesize = 8; + len = sd->length; + + if (!ecore_x_selection_convert(xevent->xselectionrequest.selection, + xevent->xselectionrequest.target, + &data, &len, &type, &typesize)) + /* Refuse selection, conversion to requested target failed */ + property = None; + else if (data) + { + /* FIXME: This does not properly handle large data transfers */ + ecore_x_window_prop_property_set( + xevent->xselectionrequest.requestor, + xevent->xselectionrequest. + property, + type, + typesize, + data, + len); + property = xevent->xselectionrequest.property; + free(data); + } + + ecore_x_selection_notify_send(xevent->xselectionrequest.requestor, + xevent->xselectionrequest.selection, + xevent->xselectionrequest.target, + property, + xevent->xselectionrequest.time); + } + } +} + +void +_ecore_x_event_handle_selection_notify(XEvent *xevent) +{ + Ecore_X_Event_Selection_Notify *e; + unsigned char *data = NULL; + Ecore_X_Atom selection; + int num_ret, format; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _ecore_x_last_event_mouse_move = 0; + selection = xevent->xselection.selection; + + if (xevent->xselection.target == ECORE_X_ATOM_SELECTION_TARGETS) + { + format = ecore_x_window_prop_property_get(xevent->xselection.requestor, + xevent->xselection.property, + XA_ATOM, 32, &data, &num_ret); + if (!format) + { + /* fallback if targets handling is not working and try get the + * selection directly */ + XConvertSelection(_ecore_x_disp, selection, + ECORE_X_ATOM_UTF8_STRING, + selection, + xevent->xselection.requestor, + CurrentTime); + return; + } + } + else + { + format = ecore_x_window_prop_property_get(xevent->xselection.requestor, + xevent->xselection.property, + AnyPropertyType, 8, &data, + &num_ret); + if (!format) + return; + } + + e = calloc(1, sizeof(Ecore_X_Event_Selection_Notify)); + if (!e) + return; + + e->win = xevent->xselection.requestor; + e->time = xevent->xselection.time; + e->atom = selection; + e->target = _ecore_x_selection_target_get(xevent->xselection.target); + + if (selection == ECORE_X_ATOM_SELECTION_PRIMARY) + e->selection = ECORE_X_SELECTION_PRIMARY; + else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY) + e->selection = ECORE_X_SELECTION_SECONDARY; + else if (selection == ECORE_X_ATOM_SELECTION_XDND) + e->selection = ECORE_X_SELECTION_XDND; + else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD) + e->selection = ECORE_X_SELECTION_CLIPBOARD; + else + e->selection = ECORE_X_SELECTION_OTHER; + + e->data = _ecore_x_selection_parse(e->target, data, num_ret, format); + + ecore_event_add(ECORE_X_EVENT_SELECTION_NOTIFY, e, + _ecore_x_event_free_selection_notify, NULL); +} + +void +_ecore_x_event_handle_colormap_notify(XEvent *xevent) +{ + Ecore_X_Event_Window_Colormap *e; + + _ecore_x_last_event_mouse_move = 0; + e = calloc(1, sizeof(Ecore_X_Event_Window_Colormap)); + if (!e) + return; + + e->win = xevent->xcolormap.window; + e->cmap = xevent->xcolormap.colormap; + e->time = _ecore_x_event_last_time; + if (xevent->xcolormap.state == ColormapInstalled) + e->installed = EINA_TRUE; + else + e->installed = EINA_FALSE; + + ecore_event_add(ECORE_X_EVENT_WINDOW_COLORMAP, e, NULL, NULL); +} + +void +_ecore_x_event_handle_client_message(XEvent *xevent) +{ + _ecore_x_last_event_mouse_move = 0; + /* Special client message event handling here. need to put LOTS of if */ + /* checks here and generate synthetic events per special message known */ + /* otherwise generate generic client message event. this would handle*/ + /* netwm, ICCCM, gnomewm, old kde and mwm hint client message protocols */ + if ((xevent->xclient.message_type == ECORE_X_ATOM_WM_PROTOCOLS) && + (xevent->xclient.format == 32) && + (xevent->xclient.data.l[0] == (long)ECORE_X_ATOM_WM_DELETE_WINDOW)) + { + Ecore_X_Event_Window_Delete_Request *e; + + e = calloc(1, sizeof(Ecore_X_Event_Window_Delete_Request)); + if (!e) + return; + + e->win = xevent->xclient.window; + e->time = _ecore_x_event_last_time; + ecore_event_add(ECORE_X_EVENT_WINDOW_DELETE_REQUEST, e, NULL, NULL); + } + else if ((xevent->xclient.message_type == ECORE_X_ATOM_NET_WM_MOVERESIZE) && + (xevent->xclient.format == 32) && +/* Ignore move and resize with keyboard */ + (xevent->xclient.data.l[2] < 9)) + { + Ecore_X_Event_Window_Move_Resize_Request *e; + + e = calloc(1, sizeof(Ecore_X_Event_Window_Move_Resize_Request)); + if (!e) + return; + + e->win = xevent->xclient.window; + e->x = xevent->xclient.data.l[0]; + e->y = xevent->xclient.data.l[1]; + e->direction = xevent->xclient.data.l[2]; + e->button = xevent->xclient.data.l[3]; + e->source = xevent->xclient.data.l[4]; + ecore_event_add(ECORE_X_EVENT_WINDOW_MOVE_RESIZE_REQUEST, e, NULL, NULL); + } + /* Xdnd Client Message Handling Begin */ + /* Message Type: XdndEnter target */ + else if (xevent->xclient.message_type == ECORE_X_ATOM_XDND_ENTER) + { + Ecore_X_Event_Xdnd_Enter *e; + Ecore_X_DND_Target *target; + + e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Enter)); + if (!e) return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + target = _ecore_x_dnd_target_get(); + target->state = ECORE_X_DND_TARGET_ENTERED; + target->source = xevent->xclient.data.l[0]; + target->win = xevent->xclient.window; + target->version = (int)(xevent->xclient.data.l[1] >> 24); + if (target->version > ECORE_X_DND_VERSION) + { + WRN("DND: Requested version %d, we only support up to %d", + target->version, ECORE_X_DND_VERSION); + free(e); + return; + } + + if (xevent->xclient.data.l[1] & 0x1UL) + { + /* source supports more than 3 types, fetch property */ + unsigned char *data; + Ecore_X_Atom *types; + int i, num_ret; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!(ecore_x_window_prop_property_get(target->source, + ECORE_X_ATOM_XDND_TYPE_LIST, + XA_ATOM, + 32, &data, &num_ret))) + { + WRN( + "DND: Could not fetch data type list from source window, aborting."); + free(e); + return; + } + + types = (Ecore_X_Atom *)data; + e->types = calloc(num_ret, sizeof(char *)); + if (e->types) + { + LOGFN(__FILE__, __LINE__, __FUNCTION__); + for (i = 0; i < num_ret; i++) + e->types[i] = XGetAtomName(_ecore_x_disp, types[i]); + } + + e->num_types = num_ret; + } + else + { + int i = 0; + + e->types = calloc(3, sizeof(char *)); + if (e->types) + { + LOGFN(__FILE__, __LINE__, __FUNCTION__); + while ((i < 3) && (xevent->xclient.data.l[i + 2])) + { + e->types[i] = XGetAtomName(_ecore_x_disp, + xevent->xclient.data.l[i + 2]); + i++; + } + } + + e->num_types = i; + } + + e->win = target->win; + e->source = target->source; + ecore_event_add(ECORE_X_EVENT_XDND_ENTER, e, + _ecore_x_event_free_xdnd_enter, NULL); + } + /* Message Type: XdndPosition target */ + else if (xevent->xclient.message_type == ECORE_X_ATOM_XDND_POSITION) + { + Ecore_X_Event_Xdnd_Position *e; + Ecore_X_DND_Target *target; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + target = _ecore_x_dnd_target_get(); + if ((target->source != (Ecore_X_Window)xevent->xclient.data.l[0]) || + (target->win != xevent->xclient.window)) + return; + + target->pos.x = xevent->xclient.data.l[2] >> 16; + target->pos.y = xevent->xclient.data.l[2] & 0xFFFFUL; + target->action = xevent->xclient.data.l[4]; /* Version 2 */ + + target->time = (target->version >= 1) ? + (Time)xevent->xclient.data.l[3] : CurrentTime; + + e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Position)); + if (!e) return; + + e->win = target->win; + e->source = target->source; + e->position.x = target->pos.x; + e->position.y = target->pos.y; + e->action = target->action; + ecore_event_add(ECORE_X_EVENT_XDND_POSITION, e, NULL, NULL); + } + /* Message Type: XdndStatus source */ + else if (xevent->xclient.message_type == ECORE_X_ATOM_XDND_STATUS) + { + Ecore_X_Event_Xdnd_Status *e; + Ecore_X_DND_Source *source; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + source = _ecore_x_dnd_source_get(); + /* Make sure source/target match */ + if ((source->win != xevent->xclient.window) || + (source->dest != (Window)xevent->xclient.data.l[0])) + return; + + source->await_status = 0; + + source->will_accept = xevent->xclient.data.l[1] & 0x1UL; + source->suppress = (xevent->xclient.data.l[1] & 0x2UL) ? 0 : 1; + + source->rectangle.x = xevent->xclient.data.l[2] >> 16; + source->rectangle.y = xevent->xclient.data.l[2] & 0xFFFFUL; + source->rectangle.width = xevent->xclient.data.l[3] >> 16; + source->rectangle.height = xevent->xclient.data.l[3] & 0xFFFFUL; + + source->accepted_action = xevent->xclient.data.l[4]; + + e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Status)); + if (!e) return; + + e->win = source->win; + e->target = source->dest; + e->will_accept = source->will_accept; + e->rectangle.x = source->rectangle.x; + e->rectangle.y = source->rectangle.y; + e->rectangle.width = source->rectangle.width; + e->rectangle.height = source->rectangle.height; + e->action = source->accepted_action; + + ecore_event_add(ECORE_X_EVENT_XDND_STATUS, e, NULL, NULL); + } + /* Message Type: XdndLeave target */ + /* Pretend the whole thing never happened, sort of */ + else if (xevent->xclient.message_type == ECORE_X_ATOM_XDND_LEAVE) + { + Ecore_X_Event_Xdnd_Leave *e; + Ecore_X_DND_Target *target; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + target = _ecore_x_dnd_target_get(); + if ((target->source != (Ecore_X_Window)xevent->xclient.data.l[0]) || + (target->win != xevent->xclient.window)) + return; + + target->state = ECORE_X_DND_TARGET_IDLE; + + e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Leave)); + if (!e) return; + + e->win = xevent->xclient.window; + e->source = (Window)xevent->xclient.data.l[0]; + ecore_event_add(ECORE_X_EVENT_XDND_LEAVE, e, NULL, NULL); + } + /* Message Type: XdndDrop target */ + else if (xevent->xclient.message_type == ECORE_X_ATOM_XDND_DROP) + { + Ecore_X_Event_Xdnd_Drop *e; + Ecore_X_DND_Target *target; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + target = _ecore_x_dnd_target_get(); + /* Match source/target */ + if ((target->source != (Window)xevent->xclient.data.l[0]) || + (target->win != xevent->xclient.window)) + return; + + target->time = (target->version >= 1) ? + (Time)xevent->xclient.data.l[2] : _ecore_x_event_last_time; + + e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Drop)); + if (!e) return; + + e->win = target->win; + e->source = target->source; + e->action = target->action; + e->position.x = target->pos.x; + e->position.y = target->pos.y; + ecore_event_add(ECORE_X_EVENT_XDND_DROP, e, NULL, NULL); + } + /* Message Type: XdndFinished source */ + else if (xevent->xclient.message_type == ECORE_X_ATOM_XDND_FINISHED) + { + Ecore_X_Event_Xdnd_Finished *e; + Ecore_X_DND_Source *source; + Eina_Bool completed = EINA_TRUE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + source = _ecore_x_dnd_source_get(); + /* Match source/target */ + if ((source->win != xevent->xclient.window) || + (source->dest != (Window)xevent->xclient.data.l[0])) + return; + + if ((source->version < 5) || (xevent->xclient.data.l[1] & 0x1UL)) + { + LOGFN(__FILE__, __LINE__, __FUNCTION__); + /* Target successfully performed drop action */ + ecore_x_selection_xdnd_clear(); + source->state = ECORE_X_DND_SOURCE_IDLE; + } + else if (source->version >= 5) + { + completed = EINA_FALSE; + source->state = ECORE_X_DND_SOURCE_CONVERTING; + + /* FIXME: Probably need to add a timer to switch back to idle + * and discard the selection data */ + } + + e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Finished)); + if (!e) return; + + e->win = source->win; + e->target = source->dest; + e->completed = completed; + if (source->version >= 5) + { + source->accepted_action = xevent->xclient.data.l[2]; + e->action = source->accepted_action; + } + else + { + source->accepted_action = 0; + e->action = source->action; + } + + ecore_event_add(ECORE_X_EVENT_XDND_FINISHED, e, NULL, NULL); + } + else if (xevent->xclient.message_type == ECORE_X_ATOM_NET_WM_STATE) + { + Ecore_X_Event_Window_State_Request *e; + + e = calloc(1, sizeof(Ecore_X_Event_Window_State_Request)); + if (!e) return; + + e->win = xevent->xclient.window; + if (xevent->xclient.data.l[0] == 0) + e->action = ECORE_X_WINDOW_STATE_ACTION_REMOVE; + else if (xevent->xclient.data.l[0] == 1) + e->action = ECORE_X_WINDOW_STATE_ACTION_ADD; + else if (xevent->xclient.data.l[0] == 2) + e->action = ECORE_X_WINDOW_STATE_ACTION_TOGGLE; + else + { + free(e); + return; + } + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + e->state[0] = _ecore_x_netwm_state_get(xevent->xclient.data.l[1]); + if (e->state[0] == ECORE_X_WINDOW_STATE_UNKNOWN) + { +// char *name; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +// name = XGetAtomName(_ecore_x_disp, xevent->xclient.data.l[1]); +// if (name) ERR("Unknown state: %s", name); +// XFree(name); + } + e->state[1] = _ecore_x_netwm_state_get(xevent->xclient.data.l[2]); + if (e->state[1] == ECORE_X_WINDOW_STATE_UNKNOWN) + { +// char *name; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +// name = XGetAtomName(_ecore_x_disp, xevent->xclient.data.l[2]); +// if (name) ERR("Unknown state: %s", name); +// XFree(name); + } + + e->source = xevent->xclient.data.l[3]; + + ecore_event_add(ECORE_X_EVENT_WINDOW_STATE_REQUEST, e, NULL, NULL); + } + else if ((xevent->xclient.message_type == ECORE_X_ATOM_WM_CHANGE_STATE) + && (xevent->xclient.format == 32) + && (xevent->xclient.data.l[0] == IconicState)) + { + Ecore_X_Event_Window_State_Request *e; + + e = calloc(1, sizeof(Ecore_X_Event_Window_State_Request)); + if (!e) + return; + + e->win = xevent->xclient.window; + e->action = ECORE_X_WINDOW_STATE_ACTION_ADD; + e->state[0] = ECORE_X_WINDOW_STATE_ICONIFIED; + + ecore_event_add(ECORE_X_EVENT_WINDOW_STATE_REQUEST, e, NULL, NULL); + } + else if ((xevent->xclient.message_type == ECORE_X_ATOM_NET_WM_DESKTOP) + && (xevent->xclient.format == 32)) + { + Ecore_X_Event_Desktop_Change *e; + + e = calloc(1, sizeof(Ecore_X_Event_Desktop_Change)); + if (!e) + return; + + e->win = xevent->xclient.window; + e->desk = xevent->xclient.data.l[0]; + e->source = xevent->xclient.data.l[1]; + + ecore_event_add(ECORE_X_EVENT_DESKTOP_CHANGE, e, NULL, NULL); + } + else if ((xevent->xclient.message_type == + ECORE_X_ATOM_NET_REQUEST_FRAME_EXTENTS)) + { + Ecore_X_Event_Frame_Extents_Request *e; + + e = calloc(1, sizeof(Ecore_X_Event_Frame_Extents_Request)); + if (!e) + return; + + e->win = xevent->xclient.window; + + ecore_event_add(ECORE_X_EVENT_FRAME_EXTENTS_REQUEST, e, NULL, NULL); + } + else if ((xevent->xclient.message_type == ECORE_X_ATOM_WM_PROTOCOLS) + && ((Ecore_X_Atom)xevent->xclient.data.l[0] == + ECORE_X_ATOM_NET_WM_PING) + && (xevent->xclient.format == 32)) + { + Ecore_X_Event_Ping *e; + Ecore_X_Window root = 0; + + e = calloc(1, sizeof(Ecore_X_Event_Ping)); + if (!e) + return; + + e->win = xevent->xclient.window; + e->time = xevent->xclient.data.l[1]; + e->event_win = xevent->xclient.data.l[2]; + + /* send a reply anyway - we are alive... eventloop at least */ + ecore_event_add(ECORE_X_EVENT_PING, e, NULL, NULL); + if (ScreenCount(_ecore_x_disp) > 1) + { + LOGFN(__FILE__, __LINE__, __FUNCTION__); + root = ecore_x_window_root_get(e->win); + } + else + root = DefaultRootWindow(_ecore_x_disp); + + if (xevent->xclient.window != root) + { + xevent->xclient.window = root; + XSendEvent(_ecore_x_disp, root, False, + SubstructureRedirectMask | SubstructureNotifyMask, + xevent); + } + } + else if ((xevent->xclient.message_type == + ECORE_X_ATOM_NET_STARTUP_INFO_BEGIN) && + (xevent->xclient.format == 8)) + _ecore_x_netwm_startup_info_begin(xevent->xclient.window, + xevent->xclient.data.b); + else if ((xevent->xclient.message_type == ECORE_X_ATOM_NET_STARTUP_INFO) && + (xevent->xclient.format == 8)) + _ecore_x_netwm_startup_info(xevent->xclient.window, + xevent->xclient.data.b); + else if ((xevent->xclient.message_type == 27777) + && (xevent->xclient.data.l[0] == 0x7162534) + && (xevent->xclient.format == 32) + && (xevent->xclient.window == _ecore_x_private_win)) + { + /* a grab sync marker */ + if (xevent->xclient.data.l[1] == 0x10000001) + _ecore_x_window_grab_remove(xevent->xclient.data.l[2]); + else if (xevent->xclient.data.l[1] == 0x10000002) + _ecore_x_key_grab_remove(xevent->xclient.data.l[2]); + } + else + { + Ecore_X_Event_Client_Message *e; + int i; + + e = calloc(1, sizeof(Ecore_X_Event_Client_Message)); + if (!e) + return; + + e->win = xevent->xclient.window; + e->message_type = xevent->xclient.message_type; + e->format = xevent->xclient.format; + for (i = 0; i < 5; i++) + e->data.l[i] = xevent->xclient.data.l[i]; + + ecore_event_add(ECORE_X_EVENT_CLIENT_MESSAGE, e, NULL, NULL); + } +} + +void +_ecore_x_event_handle_mapping_notify(XEvent *xevent) +{ + Ecore_X_Event_Mapping_Change *e; + + _ecore_x_last_event_mouse_move = 0; + XRefreshKeyboardMapping((XMappingEvent *)xevent); + _ecore_x_modifiers_get(); + e = calloc(1, sizeof(Ecore_X_Event_Mapping_Change)); + if (!e) return; + switch (xevent->xmapping.request) + { + case MappingModifier: + e->type = ECORE_X_MAPPING_MODIFIER; + break; + + case MappingKeyboard: + e->type = ECORE_X_MAPPING_KEYBOARD; + break; + + case MappingPointer: + default: + e->type = ECORE_X_MAPPING_MOUSE; + break; + } + e->keycode = xevent->xmapping.first_keycode; + e->num = xevent->xmapping.count; + ecore_event_add(ECORE_X_EVENT_MAPPING_CHANGE, e, NULL, NULL); +} + +void +_ecore_x_event_handle_shape_change(XEvent *xevent) +{ + XShapeEvent *shape_event; + Ecore_X_Event_Window_Shape *e; + + _ecore_x_last_event_mouse_move = 0; + shape_event = (XShapeEvent *)xevent; + e = calloc(1, sizeof(Ecore_X_Event_Window_Shape)); + if (!e) + return; + + e->win = shape_event->window; + e->time = shape_event->time; + switch (shape_event->kind) + { + case ShapeBounding: + e->type = ECORE_X_SHAPE_BOUNDING; + break; + + case ShapeClip: + e->type = ECORE_X_SHAPE_CLIP; + break; + + case ShapeInput: + e->type = ECORE_X_SHAPE_INPUT; + break; + + default: + break; + } + e->x = shape_event->x; + e->y = shape_event->y; + e->w = shape_event->width; + e->h = shape_event->height; + e->shaped = shape_event->shaped; + ecore_event_add(ECORE_X_EVENT_WINDOW_SHAPE, e, NULL, NULL); +} + +void +_ecore_x_event_handle_screensaver_notify(XEvent *xevent) +{ +#ifdef ECORE_XSS + XScreenSaverNotifyEvent *screensaver_event; + Ecore_X_Event_Screensaver_Notify *e; + + _ecore_x_last_event_mouse_move = 0; + screensaver_event = (XScreenSaverNotifyEvent *)xevent; + e = calloc(1, sizeof(Ecore_X_Event_Screensaver_Notify)); + if (!e) + return; + + e->win = screensaver_event->window; + if ((screensaver_event->state == ScreenSaverOn) || + (screensaver_event->state == ScreenSaverCycle)) + e->on = EINA_TRUE; + else + e->on = EINA_FALSE; + + e->time = screensaver_event->time; + ecore_event_add(ECORE_X_EVENT_SCREENSAVER_NOTIFY, e, NULL, NULL); +#else /* ifdef ECORE_XSS */ + xevent = NULL; +#endif /* ifdef ECORE_XSS */ +} + +void +_ecore_x_event_handle_sync_counter(XEvent *xevent) +{ + XSyncCounterNotifyEvent *sync_counter_event; + Ecore_X_Event_Sync_Counter *e; + + _ecore_x_last_event_mouse_move = 0; + sync_counter_event = (XSyncCounterNotifyEvent *)xevent; + e = calloc(1, sizeof(Ecore_X_Event_Sync_Counter)); + if (!e) + return; + + e->time = sync_counter_event->time; + ecore_event_add(ECORE_X_EVENT_SYNC_COUNTER, e, NULL, NULL); +} + +void +_ecore_x_event_handle_sync_alarm(XEvent *xevent) +{ + XSyncAlarmNotifyEvent *sync_alarm_event; + Ecore_X_Event_Sync_Alarm *e; + + _ecore_x_last_event_mouse_move = 0; + sync_alarm_event = (XSyncAlarmNotifyEvent *)xevent; + + e = calloc(1, sizeof(Ecore_X_Event_Sync_Alarm)); + if (!e) + return; + + e->time = sync_alarm_event->time; + e->alarm = sync_alarm_event->alarm; + ecore_event_add(ECORE_X_EVENT_SYNC_ALARM, e, NULL, NULL); +} + +#ifdef ECORE_XRANDR +void +_ecore_x_event_handle_randr_change(XEvent *xevent) +{ + XRRScreenChangeNotifyEvent *randr_event; + Ecore_X_Event_Screen_Change *e; + + _ecore_x_last_event_mouse_move = 0; + randr_event = (XRRScreenChangeNotifyEvent *)xevent; + if (!XRRUpdateConfiguration(xevent)) + ERR("Can't update RR config!"); + + e = calloc(1, sizeof(Ecore_X_Event_Screen_Change)); + if (!e) + return; + + e->win = randr_event->window; + e->root = randr_event->root; + e->size.width = randr_event->width; + e->size.height = randr_event->height; + e->time = randr_event->timestamp; + e->config_time = randr_event->config_timestamp; + e->size.width_mm = randr_event->mwidth; + e->size.height_mm = randr_event->mheight; + e->orientation = randr_event->rotation; + e->subpixel_order = randr_event->subpixel_order; + ecore_event_add(ECORE_X_EVENT_SCREEN_CHANGE, e, NULL, NULL); +} + +static void +_ecore_x_event_handle_randr_notify_crtc_change(const XRRNotifyEvent *xevent) +{ + const XRRCrtcChangeNotifyEvent *randr_event; + Ecore_X_Event_Randr_Crtc_Change *e; + + randr_event = (const XRRCrtcChangeNotifyEvent *)xevent; + + e = calloc(1, sizeof(Ecore_X_Event_Randr_Crtc_Change)); + if (!e) + return; + + e->win = randr_event->window; + e->crtc = randr_event->crtc; + e->mode = randr_event->mode; + e->orientation = randr_event->rotation; + e->geo.x = randr_event->x; + e->geo.y = randr_event->y; + e->geo.w = randr_event->width; + e->geo.h = randr_event->height; + ecore_event_add(ECORE_X_EVENT_RANDR_CRTC_CHANGE, e, NULL, NULL); +} + +static void +_ecore_x_event_handle_randr_notify_output_change(const XRRNotifyEvent *xevent) +{ + const XRROutputChangeNotifyEvent *randr_event; + Ecore_X_Event_Randr_Output_Change *e; + + randr_event = (const XRROutputChangeNotifyEvent *)xevent; + + e = calloc(1, sizeof(Ecore_X_Event_Randr_Output_Change)); + if (!e) + return; + + e->win = randr_event->window; + e->output = randr_event->output; + e->crtc = randr_event->crtc; + e->mode = randr_event->mode; + e->orientation = randr_event->rotation; + e->connection = randr_event->connection; + e->subpixel_order = randr_event->subpixel_order; + ecore_event_add(ECORE_X_EVENT_RANDR_OUTPUT_CHANGE, e, NULL, NULL); +} + +static void +_ecore_x_event_handle_randr_notify_output_property(const XRRNotifyEvent *xevent) +{ + const XRROutputPropertyNotifyEvent *randr_event; + Ecore_X_Event_Randr_Output_Property_Notify *e; + + randr_event = (const XRROutputPropertyNotifyEvent *)xevent; + + e = calloc(1, sizeof(Ecore_X_Event_Randr_Output_Property_Notify)); + if (!e) + return; + + e->win = randr_event->window; + e->output = randr_event->output; + e->property = randr_event->property; + e->time = randr_event->timestamp; + if (randr_event->state == PropertyNewValue) + e->state = ECORE_X_RANDR_PROPERTY_CHANGE_ADD; + else + e->state = ECORE_X_RANDR_PROPERTY_CHANGE_DEL; + ecore_event_add(ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY, e, NULL, NULL); +} + +void +_ecore_x_event_handle_randr_notify(XEvent *xevent) +{ + const XRRNotifyEvent *randr_event; + + _ecore_x_last_event_mouse_move = 0; + randr_event = (const XRRNotifyEvent *)xevent; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + switch (randr_event->subtype) + { + case RRNotify_CrtcChange: + _ecore_x_event_handle_randr_notify_crtc_change(randr_event); + break; + + case RRNotify_OutputChange: + _ecore_x_event_handle_randr_notify_output_change(randr_event); + break; + + case RRNotify_OutputProperty: + _ecore_x_event_handle_randr_notify_output_property(randr_event); + break; + + default: + ERR("Unknown XRandR RRNotify subtype: %d.", + randr_event->subtype); + break; + } +} + +#endif /* ifdef ECORE_XRANDR */ + +#ifdef ECORE_XFIXES +void +_ecore_x_event_handle_fixes_selection_notify(XEvent *event) +{ + XFixesSelectionNotifyEvent *notify_event = + (XFixesSelectionNotifyEvent *)event; + Ecore_X_Event_Fixes_Selection_Notify *e; + Ecore_X_Atom sel; + + _ecore_x_last_event_mouse_move = 0; + /* Nothing here yet */ + + e = calloc(1, sizeof(*e)); + if (!e) + return; + + e->win = notify_event->window; + e->owner = notify_event->owner; + e->time = notify_event->timestamp; + e->selection_time = notify_event->selection_timestamp; + e->atom = sel = notify_event->selection; + if (sel == ECORE_X_ATOM_SELECTION_PRIMARY) + e->selection = ECORE_X_SELECTION_PRIMARY; + else if (sel == ECORE_X_ATOM_SELECTION_SECONDARY) + e->selection = ECORE_X_SELECTION_SECONDARY; + else if (sel == ECORE_X_ATOM_SELECTION_CLIPBOARD) + e->selection = ECORE_X_SELECTION_CLIPBOARD; + else + e->selection = ECORE_X_SELECTION_OTHER; + e->reason = notify_event->subtype; + + ecore_event_add(ECORE_X_EVENT_FIXES_SELECTION_NOTIFY, e, NULL, NULL); +} + +#endif /* ifdef ECORE_XFIXES */ + +#ifdef ECORE_XDAMAGE +void +_ecore_x_event_handle_damage_notify(XEvent *event) +{ + XDamageNotifyEvent *damage_event; + Ecore_X_Event_Damage *e; + + _ecore_x_last_event_mouse_move = 0; + damage_event = (XDamageNotifyEvent *)event; + + e = calloc(1, sizeof(Ecore_X_Event_Damage)); + if (!e) + return; + + e->level = damage_event->level; + e->drawable = damage_event->drawable; + e->damage = damage_event->damage; + e->more = damage_event->more; + e->time = damage_event->timestamp; + e->area.x = damage_event->area.x; + e->area.y = damage_event->area.y; + e->area.width = damage_event->area.width; + e->area.height = damage_event->area.height; + e->geometry.x = damage_event->geometry.x; + e->geometry.y = damage_event->geometry.y; + e->geometry.width = damage_event->geometry.width; + e->geometry.height = damage_event->geometry.height; + + ecore_event_add(ECORE_X_EVENT_DAMAGE_NOTIFY, e, NULL, NULL); +} + +#endif /* ifdef ECORE_XDAMAGE */ + +static void +_ecore_x_event_free_generic_event(void *data, + void *ev) +{ +#ifdef ECORE_XI2 + Ecore_X_Event_Generic *e = (Ecore_X_Event_Generic *)ev; + + if (data) + { + if (e->data) + XFreeEventData(_ecore_x_disp, (XGenericEventCookie *)data); + free(data); + } + free(e); +#else + return; + data = NULL; ev = NULL; +#endif /* ifdef ECORE_XI2 */ +} + +void +_ecore_x_event_handle_generic_event(XEvent *event) +{ +#ifdef ECORE_XI2 + XGenericEvent *generic_event; + Ecore_X_Event_Generic *e; + XGenericEventCookie *data; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + generic_event = (XGenericEvent *)event; + + e = calloc(1, sizeof(Ecore_X_Event_Generic)); + if (!e) + return; + + if (XGetEventData(_ecore_x_disp, &(event->xcookie))) + { + e->cookie = event->xcookie.cookie; + e->data = event->xcookie.data; + } + else + { + e->cookie = 0; + e->data = NULL; + } + + e->extension = generic_event->extension; + e->evtype = generic_event->evtype; + + if (e->extension == _ecore_x_xi2_opcode) + _ecore_x_input_handler(event); + + data = malloc(sizeof(XGenericEventCookie)); + if (data) memcpy(data, &(event->xcookie), sizeof(XGenericEventCookie)); + ecore_event_add(ECORE_X_EVENT_GENERIC, + e, + _ecore_x_event_free_generic_event, + data); +#else + return; + event = NULL; +#endif /* ifdef ECORE_XI2 */ +} + +#ifdef ECORE_XGESTURE +void +_ecore_x_event_handle_gesture_notify_flick(XEvent *xevent) +{ + XGestureNotifyFlickEvent *xfe; + Ecore_X_Event_Gesture_Notify_Flick *e; + + _ecore_x_last_event_mouse_move = 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + xfe = (XGestureNotifyFlickEvent *)xevent; + e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_Flick)); + if (!e) + return; + + e->win = xfe->window; + e->time = xfe->time; + e->subtype = xfe->kind; + e->num_fingers = xfe->num_finger; + e->distance = xfe->distance; + e->duration = xfe->duration; + e->direction = xfe->direction; + e->angle = XFixedToDouble(xfe->angle); + + ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_FLICK, e, NULL, NULL); +} + +void +_ecore_x_event_handle_gesture_notify_pan(XEvent *xevent) +{ + XGestureNotifyPanEvent *xpe; + Ecore_X_Event_Gesture_Notify_Pan *e; + + _ecore_x_last_event_mouse_move = 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + xpe = (XGestureNotifyPanEvent *)xevent; + e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_Pan)); + if (!e) + return; + + e->win = xpe->window; + e->time = xpe->time; + e->subtype = xpe->kind; + e->num_fingers = xpe->num_finger; + e->dx = xpe->dx; + e->dy = xpe->dy; + e->distance = xpe->distance; + e->duration = xpe->duration; + e->direction = xpe->direction; + + ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_PAN, e, NULL, NULL); +} + +void +_ecore_x_event_handle_gesture_notify_pinchrotation(XEvent *xevent) +{ + XGestureNotifyPinchRotationEvent *xpre; + Ecore_X_Event_Gesture_Notify_PinchRotation *e; + + _ecore_x_last_event_mouse_move = 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + xpre = (XGestureNotifyPinchRotationEvent *)xevent; + e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_PinchRotation)); + if (!e) + return; + + e->win = xpre->window; + e->time = xpre->time; + e->subtype = xpre->kind; + e->num_fingers = xpre->num_finger; + e->distance = xpre->distance; + e->cx = xpre->cx; + e->cy = xpre->cy; + e->zoom = XFixedToDouble(xpre->zoom); + e->angle = XFixedToDouble(xpre->angle); + + ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_PINCHROTATION, e, NULL, NULL); +} + +void +_ecore_x_event_handle_gesture_notify_tap(XEvent *xevent) +{ + XGestureNotifyTapEvent *xte; + Ecore_X_Event_Gesture_Notify_Tap *e; + + _ecore_x_last_event_mouse_move = 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + xte = (XGestureNotifyTapEvent *)xevent; + e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_Tap)); + if (!e) + return; + + e->win = xte->window; + e->time = xte->time; + e->subtype = xte->kind; + e->num_fingers = xte->num_finger; + e->cx = xte->cx; + e->cy = xte->cy; + e->tap_repeat = xte->tap_repeat; + e->interval = xte->interval; + + ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_TAP, e, NULL, NULL); +} + +void +_ecore_x_event_handle_gesture_notify_tapnhold(XEvent *xevent) +{ + XGestureNotifyTapNHoldEvent *xthe; + Ecore_X_Event_Gesture_Notify_TapNHold *e; + + _ecore_x_last_event_mouse_move = 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + xthe = (XGestureNotifyTapNHoldEvent *)xevent; + e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_TapNHold)); + if (!e) + return; + + e->win = xthe->window; + e->time = xthe->time; + e->subtype = xthe->kind; + e->num_fingers = xthe->num_finger; + e->cx = xthe->cx; + e->cy = xthe->cy; + e->interval = xthe->interval; + e->hold_time = xthe->holdtime; + + ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_TAPNHOLD, e, NULL, NULL); +} + +void +_ecore_x_event_handle_gesture_notify_hold(XEvent *xevent) +{ + XGestureNotifyHoldEvent *xhe; + Ecore_X_Event_Gesture_Notify_Hold *e; + + _ecore_x_last_event_mouse_move = 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + xhe = (XGestureNotifyHoldEvent *)xevent; + e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_Hold)); + if (!e) + return; + + e->win = xhe->window; + e->time = xhe->time; + e->subtype = xhe->kind; + e->num_fingers = xhe->num_finger; + e->cx = xhe->cx; + e->cy = xhe->cy; + e->hold_time = xhe->holdtime; + + ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_HOLD, e, NULL, NULL); +} + +void +_ecore_x_event_handle_gesture_notify_group(XEvent *xevent) +{ + XGestureNotifyGroupEvent *xge; + Ecore_X_Event_Gesture_Notify_Group *e; + + _ecore_x_last_event_mouse_move = 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + xge = (XGestureNotifyGroupEvent *)xevent; + e = calloc(1, sizeof(Ecore_X_Event_Gesture_Notify_Group)); + if (!e) + return; + + e->win = xge->window; + e->time = xge->time; + e->subtype = xge->kind; + e->num_groups = xge->num_group; + e->group_id = xge->groupid; + + ecore_event_add(ECORE_X_EVENT_GESTURE_NOTIFY_GROUP, e, NULL, NULL); +} + +#endif /* ifdef ECORE_XGESTURE */ +#ifdef ECORE_XKB +void +_ecore_x_event_handle_xkb(XEvent *xevent) +{ + XkbEvent *xkbev; + Ecore_X_Event_Xkb *e; + + xkbev = (XkbEvent *) xevent; + e = calloc(1, sizeof(Ecore_X_Event_Xkb)); + if (!e) + return; + e->group = xkbev->state.group; + if (xkbev->any.xkb_type == XkbStateNotify) + ecore_event_add(ECORE_X_EVENT_XKB_STATE_NOTIFY, e, NULL, NULL); + else if ((xkbev->any.xkb_type == XkbNewKeyboardNotify) || + (xkbev->any.xkb_type == XkbMapNotify)) + { + if (xkbev->any.xkb_type == XkbMapNotify) + { + XkbMapNotifyEvent *xkbmapping; + + xkbmapping = (XkbMapNotifyEvent *)xkbev; + XkbRefreshKeyboardMapping(xkbmapping); + } + ecore_event_add(ECORE_X_EVENT_XKB_NEWKBD_NOTIFY, e, NULL, NULL); + } +} +#endif /* ifdef ECORE_XKB */ diff --git a/src/lib/ecore_x/xlib/ecore_x_fixes.c b/src/lib/ecore_x/xlib/ecore_x_fixes.c new file mode 100644 index 0000000..da0a6c3 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_fixes.c @@ -0,0 +1,365 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include + +#include "ecore_x_private.h" +#include "Ecore_X.h" + +static int _fixes_available; +#ifdef ECORE_XFIXES +static int _fixes_major, _fixes_minor; +#endif /* ifdef ECORE_XFIXES */ + +void +_ecore_x_fixes_init(void) +{ +#ifdef ECORE_XFIXES + _fixes_major = 3; + _fixes_minor = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (XFixesQueryVersion(_ecore_x_disp, &_fixes_major, &_fixes_minor)) + { + _fixes_available = 1; + + ECORE_X_EVENT_FIXES_SELECTION_NOTIFY = ecore_event_type_new(); + } + else + _fixes_available = 0; + +#else /* ifdef ECORE_XFIXES */ + _fixes_available = 0; +#endif /* ifdef ECORE_XFIXES */ +} + +#ifdef ECORE_XFIXES +/* I don't know what to call this function. */ +static XRectangle * +_ecore_x_rectangle_ecore_to_x(Ecore_X_Rectangle *rects, + int num) +{ + XRectangle *xrect; + int i; + + if (num == 0) + return NULL; + + xrect = malloc(sizeof(XRectangle) * num); + if (!xrect) + return NULL; + + for (i = 0; i < num; i++) + { + xrect[i].x = rects[i].x; + xrect[i].y = rects[i].y; + xrect[i].width = rects[i].width; + xrect[i].height = rects[i].height; + } + return xrect; +} + +static Ecore_X_Rectangle * +_ecore_x_rectangle_x_to_ecore(XRectangle *xrect, + int num) +{ + Ecore_X_Rectangle *rects; + int i; + + if (num == 0) + return NULL; + + rects = malloc(sizeof(Ecore_X_Rectangle) * num); + if (!rects) + return NULL; + + for (i = 0; i < num; i++) + { + rects[i].x = xrect[i].x; + rects[i].y = xrect[i].y; + rects[i].width = xrect[i].width; + rects[i].height = xrect[i].height; + } + return rects; +} + +#endif /* ifdef ECORE_XFIXES */ + +EAPI Eina_Bool +ecore_x_fixes_selection_notification_request(Ecore_X_Atom selection) +{ +#ifdef ECORE_XFIXES + if (_fixes_available) + { + XFixesSelectSelectionInput (_ecore_x_disp, + DefaultRootWindow(_ecore_x_disp), + selection, + XFixesSetSelectionOwnerNotifyMask | + XFixesSelectionWindowDestroyNotifyMask | + XFixesSelectionClientCloseNotifyMask); + return EINA_TRUE; + } +#endif + return EINA_FALSE; +} + +EAPI Ecore_X_Region +ecore_x_region_new(Ecore_X_Rectangle *rects, + int num) +{ +#ifdef ECORE_XFIXES + Ecore_X_Region region; + XRectangle *xrect; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + xrect = _ecore_x_rectangle_ecore_to_x(rects, num); + region = XFixesCreateRegion(_ecore_x_disp, xrect, num); + free(xrect); + return region; +#else /* ifdef ECORE_XFIXES */ + return 0; +#endif /* ifdef ECORE_XFIXES */ +} + +EAPI Ecore_X_Region +ecore_x_region_new_from_bitmap(Ecore_X_Pixmap bitmap) +{ +#ifdef ECORE_XFIXES + Ecore_X_Region region; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + region = XFixesCreateRegionFromBitmap(_ecore_x_disp, bitmap); + return region; +#else /* ifdef ECORE_XFIXES */ + return 0; +#endif /* ifdef ECORE_XFIXES */ +} + +EAPI Ecore_X_Region +ecore_x_region_new_from_window(Ecore_X_Window win, + Ecore_X_Region_Type type) +{ +#ifdef ECORE_XFIXES + Ecore_X_Region region; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + region = XFixesCreateRegionFromWindow(_ecore_x_disp, win, type); + return region; +#else /* ifdef ECORE_XFIXES */ + return 0; +#endif /* ifdef ECORE_XFIXES */ +} + +EAPI Ecore_X_Region +ecore_x_region_new_from_gc(Ecore_X_GC gc) +{ +#ifdef ECORE_XFIXES + Ecore_X_Region region; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + region = XFixesCreateRegionFromGC(_ecore_x_disp, gc); + return region; +#else /* ifdef ECORE_XFIXES */ + return 0; +#endif /* ifdef ECORE_XFIXES */ +} + +EAPI Ecore_X_Region +ecore_x_region_new_from_picture(Ecore_X_Picture picture) +{ +#ifdef ECORE_XFIXES + Ecore_X_Region region; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + region = XFixesCreateRegionFromPicture(_ecore_x_disp, picture); + return region; +#else /* ifdef ECORE_XFIXES */ + return 0; +#endif /* ifdef ECORE_XFIXES */ +} + +EAPI void +ecore_x_region_free(Ecore_X_Region region) +{ +#ifdef ECORE_XFIXES + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XFixesDestroyRegion(_ecore_x_disp, region); +#endif /* ifdef ECORE_XFIXES */ +} + +EAPI void +ecore_x_region_set(Ecore_X_Region region, + Ecore_X_Rectangle *rects, + int num) +{ +#ifdef ECORE_XFIXES + XRectangle *xrect = _ecore_x_rectangle_ecore_to_x(rects, num); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XFixesSetRegion(_ecore_x_disp, region, xrect, num); +#endif /* ifdef ECORE_XFIXES */ +} + +EAPI void +ecore_x_region_copy(Ecore_X_Region dest, + Ecore_X_Region source) +{ +#ifdef ECORE_XFIXES + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XFixesCopyRegion(_ecore_x_disp, dest, source); +#endif /* ifdef ECORE_XFIXES */ +} + +EAPI void +ecore_x_region_combine(Ecore_X_Region dest, + Ecore_X_Region source1, + Ecore_X_Region source2) +{ +#ifdef ECORE_XFIXES + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XFixesUnionRegion(_ecore_x_disp, dest, source1, source2); +#endif /* ifdef ECORE_XFIXES */ +} + +EAPI void +ecore_x_region_intersect(Ecore_X_Region dest, + Ecore_X_Region source1, + Ecore_X_Region source2) +{ +#ifdef ECORE_XFIXES + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XFixesIntersectRegion(_ecore_x_disp, dest, source1, source2); +#endif /* ifdef ECORE_XFIXES */ +} + +EAPI void +ecore_x_region_subtract(Ecore_X_Region dest, + Ecore_X_Region source1, + Ecore_X_Region source2) +{ +#ifdef ECORE_XFIXES + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XFixesSubtractRegion(_ecore_x_disp, dest, source1, source2); +#endif /* ifdef ECORE_XFIXES */ +} + +EAPI void +ecore_x_region_invert(Ecore_X_Region dest, + Ecore_X_Rectangle *bounds, + Ecore_X_Region source) +{ +#ifdef ECORE_XFIXES + XRectangle *xbound; + int num = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + while (bounds + num) + num++; + xbound = _ecore_x_rectangle_ecore_to_x(bounds, num); + + XFixesInvertRegion(_ecore_x_disp, dest, xbound, source); +#endif /* ifdef ECORE_XFIXES */ +} + +EAPI void +ecore_x_region_translate(Ecore_X_Region region, + int dx, + int dy) +{ +#ifdef ECORE_XFIXES + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XFixesTranslateRegion(_ecore_x_disp, region, dx, dy); +#endif /* ifdef ECORE_XFIXES */ +} + +EAPI void +ecore_x_region_extents(Ecore_X_Region dest, + Ecore_X_Region source) +{ +#ifdef ECORE_XFIXES + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XFixesRegionExtents(_ecore_x_disp, dest, source); +#endif /* ifdef ECORE_XFIXES */ +} + +EAPI Ecore_X_Rectangle * +ecore_x_region_fetch(Ecore_X_Region region, + int *num, + Ecore_X_Rectangle *bounds){ +#ifdef ECORE_XFIXES + Ecore_X_Rectangle *rects; + XRectangle *xrect, xbound; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + xrect = XFixesFetchRegionAndBounds(_ecore_x_disp, region, num, &xbound); + rects = _ecore_x_rectangle_x_to_ecore(xrect, *num); + (*bounds).x = xbound.x; + (*bounds).y = xbound.y; + (*bounds).width = xbound.width; + (*bounds).height = xbound.height; + return rects; +#else /* ifdef ECORE_XFIXES */ + return NULL; +#endif /* ifdef ECORE_XFIXES */ +} + +EAPI void +ecore_x_region_expand(Ecore_X_Region dest, + Ecore_X_Region source, + unsigned int left, + unsigned int right, + unsigned int top, + unsigned int bottom) +{ +#ifdef ECORE_XFIXES + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XFixesExpandRegion(_ecore_x_disp, dest, source, left, right, top, bottom); +#endif /* ifdef ECORE_XFIXES */ +} + +EAPI void +ecore_x_region_gc_clip_set(Ecore_X_Region region, + Ecore_X_GC gc, + int x_origin, + int y_origin) +{ +#ifdef ECORE_XFIXES + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XFixesSetGCClipRegion(_ecore_x_disp, gc, x_origin, y_origin, region); +#endif /* ifdef ECORE_XFIXES */ +} + +EAPI void +ecore_x_region_window_shape_set(Ecore_X_Region region, + Ecore_X_Window win, + Ecore_X_Shape_Type type, + int x_offset, + int y_offset) +{ +#ifdef ECORE_XFIXES + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XFixesSetWindowShapeRegion(_ecore_x_disp, + win, + type, + x_offset, + y_offset, + region); +#endif /* ifdef ECORE_XFIXES */ +} + +EAPI void +ecore_x_region_picture_clip_set(Ecore_X_Region region, + Ecore_X_Picture picture, + int x_origin, + int y_origin) +{ +#ifdef ECORE_XFIXES + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XFixesSetPictureClipRegion(_ecore_x_disp, + picture, + x_origin, + y_origin, + region); +#endif /* ifdef ECORE_XFIXES */ +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_gc.c b/src/lib/ecore_x/xlib/ecore_x_gc.c new file mode 100644 index 0000000..5396366 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_gc.c @@ -0,0 +1,171 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include + +#include "Ecore.h" +#include "ecore_x_private.h" +#include "Ecore_X.h" + +/** + * Creates a new default graphics context associated with the given + * drawable. + * @param draw Drawable to create graphics context with. If @c 0 is + * given instead, the default root window is used. + * @param value_mask Bitmask values. + * @param value_list List of values. The order of values must be the + * same than the corresponding bitmaks. + * @return The new default graphics context. + */ +EAPI Ecore_X_GC +ecore_x_gc_new(Ecore_X_Drawable draw, + Ecore_X_GC_Value_Mask value_mask, + const unsigned int *value_list) +{ + XGCValues gcv; + int mask; + int idx; + int i; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!draw) + draw = DefaultRootWindow(_ecore_x_disp); + + memset(&gcv, 0, sizeof (gcv)); + + for (i = 0, idx = 0, mask = 1; i <= 22; i++, mask <<= 1) + { + switch (mask & value_mask) + { + case ECORE_X_GC_VALUE_MASK_FUNCTION: + gcv.function = value_list[idx]; + idx++; + break; + + case ECORE_X_GC_VALUE_MASK_PLANE_MASK: + gcv.plane_mask = value_list[idx]; + idx++; + break; + + case ECORE_X_GC_VALUE_MASK_FOREGROUND: + gcv.foreground = value_list[idx]; + idx++; + break; + + case ECORE_X_GC_VALUE_MASK_BACKGROUND: + gcv.background = value_list[idx]; + idx++; + break; + + case ECORE_X_GC_VALUE_MASK_LINE_WIDTH: + gcv.line_width = value_list[idx]; + idx++; + break; + + case ECORE_X_GC_VALUE_MASK_LINE_STYLE: + gcv.line_style = value_list[idx]; + idx++; + break; + + case ECORE_X_GC_VALUE_MASK_CAP_STYLE: + gcv.cap_style = value_list[idx]; + idx++; + break; + + case ECORE_X_GC_VALUE_MASK_JOIN_STYLE: + gcv.join_style = value_list[idx]; + idx++; + break; + + case ECORE_X_GC_VALUE_MASK_FILL_STYLE: + gcv.fill_style = value_list[idx]; + idx++; + break; + + case ECORE_X_GC_VALUE_MASK_FILL_RULE: + gcv.fill_rule = value_list[idx]; + idx++; + break; + + case ECORE_X_GC_VALUE_MASK_TILE: + gcv.tile = value_list[idx]; + idx++; + break; + + case ECORE_X_GC_VALUE_MASK_STIPPLE: + gcv.stipple = value_list[idx]; + idx++; + break; + + case ECORE_X_GC_VALUE_MASK_TILE_STIPPLE_ORIGIN_X: + gcv.ts_x_origin = value_list[idx]; + idx++; + break; + + case ECORE_X_GC_VALUE_MASK_TILE_STIPPLE_ORIGIN_Y: + gcv.ts_y_origin = value_list[idx]; + idx++; + break; + + case ECORE_X_GC_VALUE_MASK_FONT: + gcv.font = value_list[idx]; + idx++; + break; + + case ECORE_X_GC_VALUE_MASK_SUBWINDOW_MODE: + gcv.subwindow_mode = value_list[idx]; + idx++; + break; + + case ECORE_X_GC_VALUE_MASK_GRAPHICS_EXPOSURES: + gcv.graphics_exposures = value_list[idx]; + idx++; + break; + + case ECORE_X_GC_VALUE_MASK_CLIP_ORIGIN_X: + gcv.clip_x_origin = value_list[idx]; + idx++; + break; + + case ECORE_X_GC_VALUE_MASK_CLIP_ORIGIN_Y: + gcv.clip_y_origin = value_list[idx]; + idx++; + break; + + case ECORE_X_GC_VALUE_MASK_CLIP_MASK: + gcv.clip_mask = value_list[idx]; + idx++; + break; + + case ECORE_X_GC_VALUE_MASK_DASH_OFFSET: + gcv.dash_offset = value_list[idx]; + idx++; + break; + + case ECORE_X_GC_VALUE_MASK_DASH_LIST: + gcv.dashes = value_list[idx]; + idx++; + break; + + case ECORE_X_GC_VALUE_MASK_ARC_MODE: + gcv.arc_mode = value_list[idx]; + idx++; + break; + } + } + + return XCreateGC(_ecore_x_disp, draw, value_mask, &gcv); +} + +/** + * Deletes and frees the given graphics context. + * @param gc The given graphics context. + */ +EAPI void +ecore_x_gc_free(Ecore_X_GC gc) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XFreeGC(_ecore_x_disp, gc); +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_gesture.c b/src/lib/ecore_x/xlib/ecore_x_gesture.c new file mode 100644 index 0000000..3c390a9 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_gesture.c @@ -0,0 +1,137 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include "ecore_x_private.h" + +static Eina_Bool _gesture_available = EINA_FALSE; + +#ifdef ECORE_XGESTURE +static int _gesture_major, _gesture_minor, _gesture_patch; +int _gesture_version; +#endif /* ifdef ECORE_XGESTURE */ + +void +_ecore_x_gesture_init(void) +{ +#ifdef ECORE_XGESTURE + _gesture_major = 0; + _gesture_minor = 0; + _gesture_patch = 0; + _gesture_version = 0; + + if (XGestureQueryVersion(_ecore_x_disp, &_gesture_major, &_gesture_minor, &_gesture_patch)) + { + _gesture_version = (_gesture_major << 16) | _gesture_minor; + _gesture_available = EINA_TRUE; + } + else + _gesture_available = EINA_FALSE; +#else /* ifdef ECORE_XGESTURE */ + _gesture_available = EINA_FALSE; +#endif /* ifdef ECORE_XGESTURE */ +} + +/* + * @brief Query whether gesture is available or not. + * + * @return @c EINA_TRUE, if extension is available, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_x_gesture_supported(void) +{ + return _gesture_available; +} + +EAPI Eina_Bool +ecore_x_gesture_events_select(Ecore_X_Window win, + Ecore_X_Gesture_Event_Mask mask) +{ +#ifdef ECORE_XGESTURE + if (!_gesture_available) + return EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XGestureSelectEvents(_ecore_x_disp, win, mask); + + return EINA_TRUE; +#else /* ifdef ECORE_XGESTURE */ + return EINA_FALSE; + win = 0; + mask = 0; +#endif /* ifdef ECORE_XGESTURE */ +} + +EAPI Ecore_X_Gesture_Event_Mask +ecore_x_gesture_events_selected_get(Ecore_X_Window win) +{ +#ifdef ECORE_XGESTURE + Ecore_X_Gesture_Event_Mask mask; + + if (!_gesture_available) + return ECORE_X_GESTURE_EVENT_MASK_NONE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (GestureSuccess != XGestureGetSelectedEvents(_ecore_x_disp, win, &mask)) + { + mask = ECORE_X_GESTURE_EVENT_MASK_NONE; + return mask; + } + + return mask; +#else /* ifdef ECORE_XGESTURE */ + return ECORE_X_GESTURE_EVENT_MASK_NONE; + win = 0; +#endif /* ifdef ECORE_XGESTURE */ +} + +EAPI Eina_Bool +ecore_x_gesture_event_grab(Ecore_X_Window win, + Ecore_X_Gesture_Event_Type type, + int num_fingers) +{ +#ifdef ECORE_XGESTURE + if (!_gesture_available) + return EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (GestureGrabSuccess != XGestureGrabEvent(_ecore_x_disp, win, type, num_fingers, CurrentTime)) + { + return EINA_FALSE; + } + + return EINA_TRUE; +#else /* ifdef ECORE_XGESTURE */ + return EINA_FALSE; + win = 0; + type = 0; + num_fingers = 0; +#endif /* ifdef ECORE_XGESTURE */ +} + +EAPI Eina_Bool +ecore_x_gesture_event_ungrab(Ecore_X_Window win, + Ecore_X_Gesture_Event_Type type, + int num_fingers) +{ +#ifdef ECORE_XGESTURE + Ecore_X_Gesture_Event_Mask mask; + + if (!_gesture_available) + return EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (GestureUngrabSuccess != XGestureUngrabEvent(_ecore_x_disp, win, type, num_fingers, CurrentTime)) + { + return EINA_FALSE; + } + + return EINA_TRUE; +#else /* ifdef ECORE_XGESTURE */ + return EINA_FALSE; + win = 0; + type = 0; + num_fingers = 0; +#endif /* ifdef ECORE_XGESTURE */ +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_icccm.c b/src/lib/ecore_x/xlib/ecore_x_icccm.c new file mode 100644 index 0000000..8d6ea1f --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_icccm.c @@ -0,0 +1,1214 @@ +/* + * Various ICCCM related functions. + * + * This is ALL the code involving anything ICCCM related. for both WM and + * client. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include +#include + +#include "Ecore.h" +#include "ecore_x_private.h" +#include "Ecore_X.h" +#include "Ecore_X_Atoms.h" + +EAPI void +ecore_x_icccm_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); +} + +EAPI void +ecore_x_icccm_state_set(Ecore_X_Window win, + Ecore_X_Window_State_Hint state) +{ + unsigned long c[2]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (state == ECORE_X_WINDOW_STATE_HINT_WITHDRAWN) + c[0] = WithdrawnState; + else if (state == ECORE_X_WINDOW_STATE_HINT_NORMAL) + c[0] = NormalState; + else if (state == ECORE_X_WINDOW_STATE_HINT_ICONIC) + c[0] = IconicState; + + c[1] = None; + XChangeProperty(_ecore_x_disp, win, ECORE_X_ATOM_WM_STATE, + ECORE_X_ATOM_WM_STATE, 32, PropModeReplace, + (unsigned char *)c, 2); +} + +EAPI Ecore_X_Window_State_Hint +ecore_x_icccm_state_get(Ecore_X_Window win) +{ + unsigned char *prop_ret = NULL; + Atom type_ret; + unsigned long bytes_after, num_ret; + int format_ret; + Ecore_X_Window_State_Hint hint; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + hint = ECORE_X_WINDOW_STATE_HINT_NONE; + XGetWindowProperty(_ecore_x_disp, win, ECORE_X_ATOM_WM_STATE, + 0, 0x7fffffff, False, ECORE_X_ATOM_WM_STATE, + &type_ret, &format_ret, &num_ret, &bytes_after, + &prop_ret); + if ((prop_ret) && (num_ret == 2)) + { + if (prop_ret[0] == WithdrawnState) + hint = ECORE_X_WINDOW_STATE_HINT_WITHDRAWN; + else if (prop_ret[0] == NormalState) + hint = ECORE_X_WINDOW_STATE_HINT_NORMAL; + else if (prop_ret[0] == IconicState) + hint = ECORE_X_WINDOW_STATE_HINT_ICONIC; + } + + if (prop_ret) + XFree(prop_ret); + + return hint; +} + +EAPI void +ecore_x_icccm_delete_window_send(Ecore_X_Window win, + Ecore_X_Time t) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_WM_PROTOCOLS, + ECORE_X_EVENT_MASK_NONE, + ECORE_X_ATOM_WM_DELETE_WINDOW, + t, 0, 0, 0); +} + +EAPI void +ecore_x_icccm_take_focus_send(Ecore_X_Window win, + Ecore_X_Time t) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_WM_PROTOCOLS, + ECORE_X_EVENT_MASK_NONE, + ECORE_X_ATOM_WM_TAKE_FOCUS, + t, 0, 0, 0); +} + +EAPI void +ecore_x_icccm_save_yourself_send(Ecore_X_Window win, + Ecore_X_Time t) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_client_message32_send(win, ECORE_X_ATOM_WM_PROTOCOLS, + ECORE_X_EVENT_MASK_NONE, + ECORE_X_ATOM_WM_SAVE_YOURSELF, + t, 0, 0, 0); +} + +EAPI void +ecore_x_icccm_move_resize_send(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ + XEvent ev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ev.type = ConfigureNotify; + ev.xconfigure.display = _ecore_x_disp; + ev.xconfigure.event = win; + ev.xconfigure.window = win; + ev.xconfigure.x = x; + ev.xconfigure.y = y; + ev.xconfigure.width = w; + ev.xconfigure.height = h; + ev.xconfigure.border_width = 0; + ev.xconfigure.above = None; + ev.xconfigure.override_redirect = False; + XSendEvent(_ecore_x_disp, win, False, StructureNotifyMask, &ev); +} + +EAPI void +ecore_x_icccm_hints_set(Ecore_X_Window win, + Eina_Bool accepts_focus, + Ecore_X_Window_State_Hint initial_state, + Ecore_X_Pixmap icon_pixmap, + Ecore_X_Pixmap icon_mask, + Ecore_X_Window icon_window, + Ecore_X_Window window_group, + Eina_Bool is_urgent) +{ + XWMHints *hints; + + hints = XAllocWMHints(); + if (!hints) + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + hints->flags = InputHint | StateHint; + hints->input = accepts_focus; + if (initial_state == ECORE_X_WINDOW_STATE_HINT_WITHDRAWN) + hints->initial_state = WithdrawnState; + else if (initial_state == ECORE_X_WINDOW_STATE_HINT_NORMAL) + hints->initial_state = NormalState; + else if (initial_state == ECORE_X_WINDOW_STATE_HINT_ICONIC) + hints->initial_state = IconicState; + + if (icon_pixmap != 0) + { + hints->icon_pixmap = icon_pixmap; + hints->flags |= IconPixmapHint; + } + + if (icon_mask != 0) + { + hints->icon_mask = icon_mask; + hints->flags |= IconMaskHint; + } + + if (icon_window != 0) + { + hints->icon_window = icon_window; + hints->flags |= IconWindowHint; + } + + if (window_group != 0) + { + hints->window_group = window_group; + hints->flags |= WindowGroupHint; + } + + if (is_urgent) + hints->flags |= XUrgencyHint; + + XSetWMHints(_ecore_x_disp, win, hints); + XFree(hints); +} + +EAPI Eina_Bool +ecore_x_icccm_hints_get(Ecore_X_Window win, + Eina_Bool *accepts_focus, + Ecore_X_Window_State_Hint *initial_state, + Ecore_X_Pixmap *icon_pixmap, + Ecore_X_Pixmap *icon_mask, + Ecore_X_Window *icon_window, + Ecore_X_Window *window_group, + Eina_Bool *is_urgent) +{ + XWMHints *hints; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (accepts_focus) + *accepts_focus = EINA_TRUE; + + if (initial_state) + *initial_state = ECORE_X_WINDOW_STATE_HINT_NORMAL; + + if (icon_pixmap) + *icon_pixmap = 0; + + if (icon_mask) + *icon_mask = 0; + + if (icon_window) + *icon_window = 0; + + if (window_group) + *window_group = 0; + + if (is_urgent) + *is_urgent = EINA_FALSE; + + hints = XGetWMHints(_ecore_x_disp, win); + if (hints) + { + if ((hints->flags & InputHint) && (accepts_focus)) + { + if (hints->input) + *accepts_focus = EINA_TRUE; + else + *accepts_focus = EINA_FALSE; + } + + if ((hints->flags & StateHint) && (initial_state)) + { + if (hints->initial_state == WithdrawnState) + *initial_state = ECORE_X_WINDOW_STATE_HINT_WITHDRAWN; + else if (hints->initial_state == NormalState) + *initial_state = ECORE_X_WINDOW_STATE_HINT_NORMAL; + else if (hints->initial_state == IconicState) + *initial_state = ECORE_X_WINDOW_STATE_HINT_ICONIC; + } + + if ((hints->flags & IconPixmapHint) && (icon_pixmap)) + *icon_pixmap = hints->icon_pixmap; + + if ((hints->flags & IconMaskHint) && (icon_mask)) + *icon_mask = hints->icon_mask; + + if ((hints->flags & IconWindowHint) && (icon_window)) + *icon_window = hints->icon_window; + + if ((hints->flags & WindowGroupHint) && (window_group)) + *window_group = hints->window_group; + + if ((hints->flags & XUrgencyHint) && (is_urgent)) + *is_urgent = EINA_TRUE; + + XFree(hints); + return EINA_TRUE; + } + + return EINA_FALSE; +} + +EAPI void +ecore_x_icccm_size_pos_hints_set(Ecore_X_Window win, + Eina_Bool request_pos, + Ecore_X_Gravity gravity, + int min_w, + int min_h, + int max_w, + int max_h, + int base_w, + int base_h, + int step_x, + int step_y, + double min_aspect, + double max_aspect) +{ + XSizeHints hint; + long mask; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!XGetWMNormalHints(_ecore_x_disp, win, &hint, &mask)) + memset(&hint, 0, sizeof(XSizeHints)); + + hint.flags = 0; + if (request_pos) + hint.flags |= USPosition; + + if (gravity != ECORE_X_GRAVITY_NW) + { + hint.flags |= PWinGravity; + hint.win_gravity = gravity; + } + + if ((min_w > 0) || (min_h > 0)) + { + hint.flags |= PMinSize; + hint.min_width = min_w; + hint.min_height = min_h; + } + + if ((max_w > 0) || (max_h > 0)) + { + hint.flags |= PMaxSize; + hint.max_width = max_w; + hint.max_height = max_h; + } + + if ((base_w > 0) || (base_h > 0)) + { + hint.flags |= PBaseSize; + hint.base_width = base_w; + hint.base_height = base_h; + } + + if ((step_x > 1) || (step_y > 1)) + { + hint.flags |= PResizeInc; + hint.width_inc = step_x; + hint.height_inc = step_y; + } + + if ((min_aspect > 0.0) || (max_aspect > 0.0)) + { + hint.flags |= PAspect; + hint.min_aspect.x = min_aspect * 10000; + hint.min_aspect.y = 10000; + hint.max_aspect.x = max_aspect * 10000; + hint.max_aspect.y = 10000; + } + + XSetWMNormalHints(_ecore_x_disp, win, &hint); +} + +EAPI Eina_Bool +ecore_x_icccm_size_pos_hints_get(Ecore_X_Window win, + Eina_Bool *request_pos, + Ecore_X_Gravity *gravity, + int *min_w, + int *min_h, + int *max_w, + int *max_h, + int *base_w, + int *base_h, + int *step_x, + int *step_y, + double *min_aspect, + double *max_aspect) +{ + XSizeHints hint; + long mask; + + int minw = 0, minh = 0; + int maxw = 32767, maxh = 32767; + int basew = -1, baseh = -1; + int stepx = -1, stepy = -1; + double mina = 0.0, maxa = 0.0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!XGetWMNormalHints(_ecore_x_disp, win, &hint, &mask)) + return EINA_FALSE; + + if ((hint.flags & USPosition) || ((hint.flags & PPosition))) + { + if (request_pos) + *request_pos = EINA_TRUE; + } + else if (request_pos) + *request_pos = EINA_FALSE; + + if (hint.flags & PWinGravity) + { + if (gravity) + *gravity = hint.win_gravity; + } + else if (gravity) + *gravity = ECORE_X_GRAVITY_NW; + + if (hint.flags & PMinSize) + { + minw = hint.min_width; + minh = hint.min_height; + } + + if (hint.flags & PMaxSize) + { + maxw = hint.max_width; + maxh = hint.max_height; + if (maxw < minw) + maxw = minw; + + if (maxh < minh) + maxh = minh; + } + + if (hint.flags & PBaseSize) + { + basew = hint.base_width; + baseh = hint.base_height; + if (basew > minw) + minw = basew; + + if (baseh > minh) + minh = baseh; + } + + if (hint.flags & PResizeInc) + { + stepx = hint.width_inc; + stepy = hint.height_inc; + if (stepx < 1) + stepx = 1; + + if (stepy < 1) + stepy = 1; + } + + if (hint.flags & PAspect) + { + if (hint.min_aspect.y > 0) + mina = ((double)hint.min_aspect.x) / ((double)hint.min_aspect.y); + + if (hint.max_aspect.y > 0) + maxa = ((double)hint.max_aspect.x) / ((double)hint.max_aspect.y); + } + + if (min_w) + *min_w = minw; + + if (min_h) + *min_h = minh; + + if (max_w) + *max_w = maxw; + + if (max_h) + *max_h = maxh; + + if (base_w) + *base_w = basew; + + if (base_h) + *base_h = baseh; + + if (step_x) + *step_x = stepx; + + if (step_y) + *step_y = stepy; + + if (min_aspect) + *min_aspect = mina; + + if (max_aspect) + *max_aspect = maxa; + + return EINA_TRUE; +} + +EAPI void +ecore_x_icccm_title_set(Ecore_X_Window win, + const char *t) +{ + char *list[1]; + XTextProperty xprop; + int ret; + + if (!t) + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + xprop.value = NULL; +#ifdef X_HAVE_UTF8_STRING + list[0] = strdup(t); + ret = + Xutf8TextListToTextProperty(_ecore_x_disp, list, 1, XUTF8StringStyle, + &xprop); +#else /* ifdef X_HAVE_UTF8_STRING */ + list[0] = strdup(t); + ret = + XmbTextListToTextProperty(_ecore_x_disp, list, 1, XStdICCTextStyle, + &xprop); +#endif /* ifdef X_HAVE_UTF8_STRING */ + if (ret >= Success) + { + XSetWMName(_ecore_x_disp, win, &xprop); + if (xprop.value) + XFree(xprop.value); + } + else if (XStringListToTextProperty(list, 1, &xprop) >= Success) + { + XSetWMName(_ecore_x_disp, win, &xprop); + if (xprop.value) + XFree(xprop.value); + } + + free(list[0]); +} + +EAPI char * +ecore_x_icccm_title_get(Ecore_X_Window win) +{ + XTextProperty xprop; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + xprop.value = NULL; + if (XGetWMName(_ecore_x_disp, win, &xprop) >= Success) + { + if (xprop.value) + { + char **list = NULL; + char *t = NULL; + int num = 0; + int ret; + + if (xprop.encoding == ECORE_X_ATOM_UTF8_STRING) + t = strdup((char *)xprop.value); + else + { + /* convert to utf8 */ +#ifdef X_HAVE_UTF8_STRING + ret = Xutf8TextPropertyToTextList(_ecore_x_disp, &xprop, + &list, &num); +#else /* ifdef X_HAVE_UTF8_STRING */ + ret = XmbTextPropertyToTextList(_ecore_x_disp, &xprop, + &list, &num); +#endif /* ifdef X_HAVE_UTF8_STRING */ + + if ((ret == XLocaleNotSupported) || + (ret == XNoMemory) || (ret == XConverterNotFound)) + t = strdup((char *)xprop.value); + else if ((ret >= Success) && (num > 0)) + t = strdup(list[0]); + + if (list) + XFreeStringList(list); + } + + if (xprop.value) + XFree(xprop.value); + + return t; + } + } + + return NULL; +} + +/** + * Set protocol atoms explicitly + * @param win The Window + * @param protos An array of protocol atoms + * @param num the number of members of the array + */ +EAPI void +ecore_x_icccm_protocol_atoms_set(Ecore_X_Window win, + Ecore_X_Atom *protos, + int num) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (num > 0) + XSetWMProtocols(_ecore_x_disp, win, (Atom *)(protos), num); + else + XDeleteProperty(_ecore_x_disp, win, ECORE_X_ATOM_WM_PROTOCOLS); +} + +/** + * Set or unset a wm protocol property. + * @param win The Window + * @param protocol The protocol to enable/disable + * @param on On/Off + */ +EAPI void +ecore_x_icccm_protocol_set(Ecore_X_Window win, + Ecore_X_WM_Protocol protocol, + Eina_Bool on) +{ + Atom *protos = NULL; + Atom proto; + int protos_count = 0; + int already_set = 0; + int i; + + /* Check for invalid values */ + if (protocol >= ECORE_X_WM_PROTOCOL_NUM) + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + proto = _ecore_x_atoms_wm_protocols[protocol]; + + if (!XGetWMProtocols(_ecore_x_disp, win, &protos, &protos_count)) + { + protos = NULL; + protos_count = 0; + } + + for (i = 0; i < protos_count; i++) + { + if (protos[i] == proto) + { + already_set = 1; + break; + } + } + + if (on) + { + Atom *new_protos = NULL; + + if (already_set) + goto leave; + + new_protos = malloc((protos_count + 1) * sizeof(Atom)); + if (!new_protos) + goto leave; + + for (i = 0; i < protos_count; i++) + new_protos[i] = protos[i]; + new_protos[protos_count] = proto; + XSetWMProtocols(_ecore_x_disp, win, new_protos, protos_count + 1); + free(new_protos); + } + else + { + if (!already_set) + goto leave; + + for (i = 0; i < protos_count; i++) + { + if (protos[i] == proto) + { + int j; + + for (j = i + 1; j < protos_count; j++) + protos[j - 1] = protos[j]; + if (protos_count > 1) + XSetWMProtocols(_ecore_x_disp, win, protos, + protos_count - 1); + else + XDeleteProperty(_ecore_x_disp, win, + ECORE_X_ATOM_WM_PROTOCOLS); + + goto leave; + } + } + } + +leave: + if (protos) + XFree(protos); +} + +/** + * Determines whether a protocol is set for a window. + * @param win The Window + * @param protocol The protocol to query + * @return 1 if the protocol is set, else 0. + */ +EAPI Eina_Bool +ecore_x_icccm_protocol_isset(Ecore_X_Window win, + Ecore_X_WM_Protocol protocol) +{ + Atom proto, *protos = NULL; + int i, protos_count = 0; + Eina_Bool ret = EINA_FALSE; + + /* check for invalid values */ + if (protocol >= ECORE_X_WM_PROTOCOL_NUM) + return EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + proto = _ecore_x_atoms_wm_protocols[protocol]; + + if (!XGetWMProtocols(_ecore_x_disp, win, &protos, &protos_count)) + return EINA_FALSE; + + for (i = 0; i < protos_count; i++) + if (protos[i] == proto) + { + ret = EINA_TRUE; + break; + } + + if (protos) + XFree(protos); + + return ret; +} + +/** + * Set a window name & class. + * @param win The window + * @param n The name string + * @param c The class string + * + * Set a window name * class + */ +EAPI void +ecore_x_icccm_name_class_set(Ecore_X_Window win, + const char *n, + const char *c) +{ + XClassHint *xch; + + xch = XAllocClassHint(); + if (!xch) + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + xch->res_name = (char *)n; + xch->res_class = (char *)c; + XSetClassHint(_ecore_x_disp, win, xch); + XFree(xch); +} + +/** + * Get a window name & class. + * @param win The window + * @param n The name string + * @param c The class string + * + * Get a window name * class + */ +EAPI void +ecore_x_icccm_name_class_get(Ecore_X_Window win, + char **n, + char **c) +{ + XClassHint xch; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (n) + *n = NULL; + + if (c) + *c = NULL; + + xch.res_name = NULL; + xch.res_class = NULL; + if (XGetClassHint(_ecore_x_disp, win, &xch)) + { + if (n) + if (xch.res_name) + *n = strdup(xch.res_name); + + if (c) + if (xch.res_class) + *c = strdup(xch.res_class); + + XFree(xch.res_name); + XFree(xch.res_class); + } +} + +/** + * Get a window client machine string. + * @param win The window + * @return The windows client machine string + * + * Return the client machine of a window. String must be free'd when done with. + */ +EAPI char * +ecore_x_icccm_client_machine_get(Ecore_X_Window win) +{ + char *name; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + name = ecore_x_window_prop_string_get(win, ECORE_X_ATOM_WM_CLIENT_MACHINE); + return name; +} + +/** + * Sets the WM_COMMAND property for @a win. + * + * @param win The window. + * @param argc Number of arguments. + * @param argv Arguments. + */ +EAPI void +ecore_x_icccm_command_set(Ecore_X_Window win, + int argc, + char **argv) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XSetCommand(_ecore_x_disp, win, argv, argc); +} + +/** + * Get the WM_COMMAND property for @a win. + * + * Return the command of a window. String must be free'd when done with. + * + * @param win The window. + * @param argc Number of arguments. + * @param argv Arguments. + */ +EAPI void +ecore_x_icccm_command_get(Ecore_X_Window win, + int *argc, + char ***argv) +{ + int i, c; + char **v; + + if (argc) + *argc = 0; + + if (argv) + *argv = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!XGetCommand(_ecore_x_disp, win, &v, &c)) + return; + + if (c < 1) + { + if (v) + XFreeStringList(v); + + return; + } + + if (argc) + *argc = c; + + if (argv) + { + (*argv) = malloc(c * sizeof(char *)); + if (!*argv) + { + XFreeStringList(v); + if (argc) + *argc = 0; + + return; + } + + for (i = 0; i < c; i++) + { + if (v[i]) + (*argv)[i] = strdup(v[i]); + else + (*argv)[i] = strdup(""); + } + } + + XFreeStringList(v); +} + +/** + * Set a window icon name. + * @param win The window + * @param t The icon name string + * + * Set a window icon name + */ +EAPI void +ecore_x_icccm_icon_name_set(Ecore_X_Window win, + const char *t) +{ + char *list[1]; + XTextProperty xprop; + int ret; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + xprop.value = NULL; +#ifdef X_HAVE_UTF8_STRING + list[0] = strdup(t); + ret = Xutf8TextListToTextProperty(_ecore_x_disp, list, 1, + XUTF8StringStyle, &xprop); +#else /* ifdef X_HAVE_UTF8_STRING */ + list[0] = strdup(t); + ret = XmbTextListToTextProperty(_ecore_x_disp, list, 1, + XStdICCTextStyle, &xprop); +#endif /* ifdef X_HAVE_UTF8_STRING */ + if (ret >= Success) + { + XSetWMIconName(_ecore_x_disp, win, &xprop); + if (xprop.value) + XFree(xprop.value); + } + else if (XStringListToTextProperty(list, 1, &xprop) >= Success) + { + XSetWMIconName(_ecore_x_disp, win, &xprop); + if (xprop.value) + XFree(xprop.value); + } + + free(list[0]); +} + +/** + * Get a window icon name. + * @param win The window + * @return The windows icon name string + * + * Return the icon name of a window. String must be free'd when done with. + */ +EAPI char * +ecore_x_icccm_icon_name_get(Ecore_X_Window win) +{ + XTextProperty xprop; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + xprop.value = NULL; + if (XGetWMIconName(_ecore_x_disp, win, &xprop) >= Success) + { + if (xprop.value) + { + char **list = NULL; + char *t = NULL; + int num = 0; + int ret; + + if (xprop.encoding == ECORE_X_ATOM_UTF8_STRING) + t = strdup((char *)xprop.value); + else + { + /* convert to utf8 */ +#ifdef X_HAVE_UTF8_STRING + ret = Xutf8TextPropertyToTextList(_ecore_x_disp, &xprop, + &list, &num); +#else /* ifdef X_HAVE_UTF8_STRING */ + ret = XmbTextPropertyToTextList(_ecore_x_disp, &xprop, + &list, &num); +#endif /* ifdef X_HAVE_UTF8_STRING */ + + if ((ret == XLocaleNotSupported) || + (ret == XNoMemory) || (ret == XConverterNotFound)) + t = strdup((char *)xprop.value); + else if (ret >= Success) + { + if ((num >= 1) && (list)) + t = strdup(list[0]); + + if (list) + XFreeStringList(list); + } + } + + if (xprop.value) + XFree(xprop.value); + + return t; + } + } + + return NULL; +} + +/** + * Add a subwindow to the list of windows that need a different colormap installed. + * @param win The toplevel window + * @param subwin The subwindow to be added to the colormap windows list + */ +EAPI void +ecore_x_icccm_colormap_window_set(Ecore_X_Window win, + Ecore_X_Window subwin) +{ + int num = 0, i; + unsigned char *old_data = NULL; + unsigned char *data = NULL; + Window *oldset = NULL; + Window *newset = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_property_get(win, + ECORE_X_ATOM_WM_COLORMAP_WINDOWS, + XA_WINDOW, 32, &old_data, &num)) + { + newset = calloc(1, sizeof(Window)); + if (!newset) + return; + + newset[0] = subwin; + num = 1; + data = (unsigned char *)newset; + } + else + { + newset = calloc(num + 1, sizeof(Window)); + oldset = (Window *)old_data; + if (!newset) + return; + + for (i = 0; i < num; ++i) + { + if (oldset[i] == subwin) + { + if (old_data) + XFree(old_data); + + old_data = NULL; + free(newset); + return; + } + + newset[i] = oldset[i]; + } + + newset[num++] = subwin; + if (old_data) + XFree(old_data); + + data = (unsigned char *)newset; + } + + ecore_x_window_prop_property_set(win, + ECORE_X_ATOM_WM_COLORMAP_WINDOWS, + XA_WINDOW, 32, data, num); + free(newset); +} + +/** + * Remove a window from the list of colormap windows. + * @param win The toplevel window + * @param subwin The window to be removed from the colormap window list. + */ +EAPI void +ecore_x_icccm_colormap_window_unset(Ecore_X_Window win, + Ecore_X_Window subwin) +{ + int num = 0, i, j, k = 0; + unsigned char *old_data = NULL; + unsigned char *data = NULL; + Window *oldset = NULL; + Window *newset = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_prop_property_get(win, + ECORE_X_ATOM_WM_COLORMAP_WINDOWS, + XA_WINDOW, 32, &old_data, &num)) + return; + + oldset = (Window *)old_data; + for (i = 0; i < num; i++) + { + if (oldset[i] == subwin) + { + if (num == 1) + { + XDeleteProperty(_ecore_x_disp, + win, ECORE_X_ATOM_WM_COLORMAP_WINDOWS); + if (old_data) + XFree(old_data); + + old_data = NULL; + return; + } + else + { + newset = calloc(num - 1, sizeof(Window)); + data = (unsigned char *)newset; + for (j = 0; j < num; ++j) + if (oldset[j] != subwin) + newset[k++] = oldset[j]; + + ecore_x_window_prop_property_set( + win, + ECORE_X_ATOM_WM_COLORMAP_WINDOWS, + XA_WINDOW, + 32, + data, + k); + if (old_data) + XFree(old_data); + + old_data = NULL; + free(newset); + return; + } + } + } + + if (old_data) + XFree(old_data); +} + +/** + * Specify that a window is transient for another top-level window and should be handled accordingly. + * @param win the transient window + * @param forwin the toplevel window + */ +EAPI void +ecore_x_icccm_transient_for_set(Ecore_X_Window win, + Ecore_X_Window forwin) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XSetTransientForHint(_ecore_x_disp, win, forwin); +} + +/** + * Remove the transient_for setting from a window. + * @param win The window + */ +EAPI void +ecore_x_icccm_transient_for_unset(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XDeleteProperty(_ecore_x_disp, win, ECORE_X_ATOM_WM_TRANSIENT_FOR); +} + +/** + * Get the window this window is transient for, if any. + * @param win The window to check + * @return The window ID of the top-level window, or 0 if the property does not exist. + */ +EAPI Ecore_X_Window +ecore_x_icccm_transient_for_get(Ecore_X_Window win) +{ + Window forwin; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (XGetTransientForHint(_ecore_x_disp, win, &forwin)) + return (Ecore_X_Window)forwin; + else + return 0; +} + +/** + * Set the window role hint. + * @param win The window + * @param role The role string + */ +EAPI void +ecore_x_icccm_window_role_set(Ecore_X_Window win, + const char *role) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_string_set(win, ECORE_X_ATOM_WM_WINDOW_ROLE, + (char *)role); +} + +/** + * Get the window role. + * @param win The window + * @return The window's role string. + */ +EAPI char * +ecore_x_icccm_window_role_get(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return ecore_x_window_prop_string_get(win, ECORE_X_ATOM_WM_WINDOW_ROLE); +} + +/** + * Set the window's client leader. + * @param win The window + * @param l The client leader window + * + * All non-transient top-level windows created by an app other than + * the main window must have this property set to the app's main window. + */ +EAPI void +ecore_x_icccm_client_leader_set(Ecore_X_Window win, + Ecore_X_Window l) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_window_set(win, ECORE_X_ATOM_WM_CLIENT_LEADER, + &l, 1); +} + +/** + * Get the window's client leader. + * @param win The window + * @return The window's client leader window, or 0 if unset */ +EAPI Ecore_X_Window +ecore_x_icccm_client_leader_get(Ecore_X_Window win) +{ + Ecore_X_Window l; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (ecore_x_window_prop_window_get(win, ECORE_X_ATOM_WM_CLIENT_LEADER, + &l, 1) > 0) + return l; + + return 0; +} + +EAPI void +ecore_x_icccm_iconic_request_send(Ecore_X_Window win, + Ecore_X_Window root) +{ + XEvent xev; + + if (!win) + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!root) + root = DefaultRootWindow(_ecore_x_disp); + + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.display = _ecore_x_disp; + xev.xclient.window = win; + xev.xclient.format = 32; + xev.xclient.message_type = ECORE_X_ATOM_WM_CHANGE_STATE; + xev.xclient.data.l[0] = IconicState; + + XSendEvent(_ecore_x_disp, root, False, + SubstructureNotifyMask | SubstructureRedirectMask, &xev); +} + +/* FIXME: there are older E hints, gnome hints and mwm hints and new netwm */ +/* hints. each should go in their own file/section so we know which */ +/* is which. also older kde hints too. we should try support as much */ +/* as makese sense to support */ diff --git a/src/lib/ecore_x/xlib/ecore_x_image.c b/src/lib/ecore_x/xlib/ecore_x_image.c new file mode 100644 index 0000000..b8e720c --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_image.c @@ -0,0 +1,600 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include "ecore_x_private.h" +#include "Ecore_X.h" + +#include +#include + +static int _ecore_x_image_shm_can = -1; +static int _ecore_x_image_err = 0; + +static int +_ecore_x_image_error_handler(Display *d __UNUSED__, + XErrorEvent *ev __UNUSED__) +{ + _ecore_x_image_err = 1; + return 0; +} + +static void +_ecore_x_image_shm_check(void) +{ + XErrorHandler ph; + XShmSegmentInfo shminfo; + XImage *xim; + + if (_ecore_x_image_shm_can != -1) + return; + + XSync(_ecore_x_disp, False); + _ecore_x_image_err = 0; + + xim = XShmCreateImage(_ecore_x_disp, + DefaultVisual(_ecore_x_disp, + DefaultScreen(_ecore_x_disp)), + DefaultDepth(_ecore_x_disp, + DefaultScreen(_ecore_x_disp)), + ZPixmap, NULL, + &shminfo, 1, 1); + if (!xim) + { + _ecore_x_image_shm_can = 0; + return; + } + + shminfo.shmid = shmget(IPC_PRIVATE, xim->bytes_per_line * xim->height, + IPC_CREAT | 0666); + if (shminfo.shmid == -1) + { + XDestroyImage(xim); + _ecore_x_image_shm_can = 0; + return; + } + + shminfo.readOnly = False; + shminfo.shmaddr = shmat(shminfo.shmid, 0, 0); + xim->data = shminfo.shmaddr; + + if (xim->data == (char *)-1) + { + XDestroyImage(xim); + _ecore_x_image_shm_can = 0; + return; + } + + ph = XSetErrorHandler((XErrorHandler)_ecore_x_image_error_handler); + XShmAttach(_ecore_x_disp, &shminfo); + XShmGetImage(_ecore_x_disp, DefaultRootWindow(_ecore_x_disp), + xim, 0, 0, 0xffffffff); + XSync(_ecore_x_disp, False); + XSetErrorHandler((XErrorHandler)ph); + if (_ecore_x_image_err) + { + XShmDetach(_ecore_x_disp, &shminfo); + XDestroyImage(xim); + shmdt(shminfo.shmaddr); + shmctl(shminfo.shmid, IPC_RMID, 0); + _ecore_x_image_shm_can = 0; + return; + } + + XShmDetach(_ecore_x_disp, &shminfo); + XDestroyImage(xim); + shmdt(shminfo.shmaddr); + shmctl(shminfo.shmid, IPC_RMID, 0); + + _ecore_x_image_shm_can = 1; +} + +struct _Ecore_X_Image +{ + XShmSegmentInfo shminfo; + Ecore_X_Visual vis; + XImage *xim; + int depth; + int w, h; + int bpl, bpp, rows; + unsigned char *data; + Eina_Bool shm : 1; +}; + +EAPI Ecore_X_Image * +ecore_x_image_new(int w, + int h, + Ecore_X_Visual vis, + int depth) +{ + Ecore_X_Image *im; + + im = calloc(1, sizeof(Ecore_X_Image)); + if (!im) + return NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + im->w = w; + im->h = h; + im->vis = vis; + im->depth = depth; + _ecore_x_image_shm_check(); + im->shm = _ecore_x_image_shm_can; + return im; +} + +EAPI void +ecore_x_image_free(Ecore_X_Image *im) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (im->shm) + { + if (im->xim) + { + XShmDetach(_ecore_x_disp, &(im->shminfo)); + XDestroyImage(im->xim); + shmdt(im->shminfo.shmaddr); + shmctl(im->shminfo.shmid, IPC_RMID, 0); + } + } + else if (im->xim) + { + free(im->xim->data); + im->xim->data = NULL; + XDestroyImage(im->xim); + } + + free(im); +} + +static void +_ecore_x_image_shm_create(Ecore_X_Image *im) +{ + im->xim = XShmCreateImage(_ecore_x_disp, im->vis, im->depth, + ZPixmap, NULL, &(im->shminfo), + im->w, im->h); + if (!im->xim) + return; + + im->shminfo.shmid = shmget(IPC_PRIVATE, + im->xim->bytes_per_line * im->xim->height, + IPC_CREAT | 0666); + if (im->shminfo.shmid == -1) + { + XDestroyImage(im->xim); + return; + } + + im->shminfo.readOnly = False; + im->shminfo.shmaddr = shmat(im->shminfo.shmid, 0, 0); + im->xim->data = im->shminfo.shmaddr; + if ((im->xim->data == (char *)-1) || + (!im->xim->data)) + { + shmdt(im->shminfo.shmaddr); + shmctl(im->shminfo.shmid, IPC_RMID, 0); + XDestroyImage(im->xim); + return; + } + + XShmAttach(_ecore_x_disp, &im->shminfo); + + im->data = (unsigned char *)im->xim->data; + + im->bpl = im->xim->bytes_per_line; + im->rows = im->xim->height; + if (im->xim->bits_per_pixel <= 8) + im->bpp = 1; + else if (im->xim->bits_per_pixel <= 16) + im->bpp = 2; + else + im->bpp = 4; +} + +EAPI Eina_Bool +ecore_x_image_get(Ecore_X_Image *im, + Ecore_X_Drawable draw, + int x, + int y, + int sx, + int sy, + int w, + int h) +{ + Eina_Bool ret = EINA_TRUE; + XErrorHandler ph; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (im->shm) + { + if (!im->xim) + _ecore_x_image_shm_create(im); + + if (!im->xim) + return 0; + + _ecore_x_image_err = 0; + // optimised path + ph = XSetErrorHandler((XErrorHandler)_ecore_x_image_error_handler); + if ((sx == 0) && (w == im->w)) + { + im->xim->data = (char *) + im->data + (im->xim->bytes_per_line * sy) + (sx * im->bpp); + im->xim->width = w; + im->xim->height = h; + XGrabServer(_ecore_x_disp); + if (!XShmGetImage(_ecore_x_disp, draw, im->xim, x, y, 0xffffffff)) + ret = EINA_FALSE; + XUngrabServer(_ecore_x_disp); + ecore_x_sync(); + } + // unavoidable thanks to mit-shm get api - tmp shm buf + copy into it + else + { + Ecore_X_Image *tim; + unsigned char *spixels, *sp, *pixels, *p; + int bpp, bpl, rows, sbpp, sbpl, srows; + int r; + + tim = ecore_x_image_new(w, h, im->vis, im->depth); + if (tim) + { + ret = ecore_x_image_get(tim, draw, x, y, 0, 0, w, h); + if (ret) + { + spixels = ecore_x_image_data_get(tim, + &sbpl, + &srows, + &sbpp); + pixels = ecore_x_image_data_get(im, &bpl, &rows, &bpp); + if ((pixels) && (spixels)) + { + p = pixels + (sy * bpl) + (sx * bpp); + sp = spixels; + for (r = srows; r > 0; r--) + { + memcpy(p, sp, sbpl); + p += bpl; + sp += sbpl; + } + } + } + + ecore_x_image_free(tim); + } + } + + XSetErrorHandler((XErrorHandler)ph); + if (_ecore_x_image_err) + ret = EINA_FALSE; + } + else + { + printf("currently unimplemented ecore_x_image_get without shm\n"); + ret = EINA_FALSE; + } + + return ret; +} + +EAPI void +ecore_x_image_put(Ecore_X_Image *im, + Ecore_X_Drawable draw, + Ecore_X_GC gc, + int x, + int y, + int sx, + int sy, + int w, + int h) +{ + Ecore_X_GC tgc = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!gc) + { + XGCValues gcv; + memset(&gcv, 0, sizeof(gcv)); + gcv.subwindow_mode = IncludeInferiors; + tgc = XCreateGC(_ecore_x_disp, draw, GCSubwindowMode, &gcv); + gc = tgc; + } + if (!im->xim) _ecore_x_image_shm_create(im); + if (im->xim) + XShmPutImage(_ecore_x_disp, draw, gc, im->xim, sx, sy, x, y, w, h, False); + if (tgc) ecore_x_gc_free(tgc); +} + +EAPI void * +ecore_x_image_data_get(Ecore_X_Image *im, + int *bpl, + int *rows, + int *bpp) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!im->xim) _ecore_x_image_shm_create(im); + if (!im->xim) return NULL; + if (bpl) *bpl = im->bpl; + if (rows) *rows = im->rows; + if (bpp) *bpp = im->bpp; + return im->data; +} + +EAPI Eina_Bool +ecore_x_image_is_argb32_get(Ecore_X_Image *im) +{ + Visual *vis = im->vis; + if (!im->xim) _ecore_x_image_shm_create(im); + if (((vis->class == TrueColor) || + (vis->class == DirectColor)) && + (im->depth >= 24) && + (vis->red_mask == 0xff0000) && + (vis->green_mask == 0x00ff00) && + (vis->blue_mask == 0x0000ff)) + { +#ifdef WORDS_BIGENDIAN + if (im->xim->bitmap_bit_order == LSBFirst) return EINA_TRUE; +#else + if (im->xim->bitmap_bit_order == MSBFirst) return EINA_TRUE; +#endif + } + return EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_image_to_argb_convert(void *src, + int sbpp, + int sbpl, + Ecore_X_Colormap c, + Ecore_X_Visual v, + int x, + int y, + int w, + int h, + unsigned int *dst, + int dbpl, + int dx, + int dy) +{ + Visual *vis = v; + XColor *cols = NULL; + int n = 0, nret = 0, i, row; + unsigned int pal[256], r, g, b; + enum + { + rgbnone = 0, + rgb565, + bgr565, + rgbx555, + argbx888, + abgrx888, + rgba888x, + bgra888x, + argbx666 + }; + int mode = 0; + + sbpp *= 8; + + n = vis->map_entries; + if ((n <= 256) && + ((vis->class == PseudoColor) || + (vis->class == StaticColor) || + (vis->class == GrayScale) || + (vis->class == StaticGray))) + { + if (!c) + c = DefaultColormap(_ecore_x_disp, + DefaultScreen(_ecore_x_disp)); + cols = alloca(n * sizeof(XColor)); + for (i = 0; i < n; i++) + { + cols[i].pixel = i; + cols[i].flags = DoRed | DoGreen | DoBlue; + cols[i].red = 0; + cols[i].green = 0; + cols[i].blue = 0; + } + XQueryColors(_ecore_x_disp, c, cols, n); + for (i = 0; i < n; i++) + { + pal[i] = 0xff000000 | + ((cols[i].red >> 8) << 16) | + ((cols[i].green >> 8) << 8) | + ((cols[i].blue >> 8)); + } + nret = n; + } + else if ((vis->class == TrueColor) || + (vis->class == DirectColor)) + { + if ((vis->red_mask == 0x00ff0000) && + (vis->green_mask == 0x0000ff00) && + (vis->blue_mask == 0x000000ff)) + mode = argbx888; + else if ((vis->red_mask == 0x000000ff) && + (vis->green_mask == 0x0000ff00) && + (vis->blue_mask == 0x00ff0000)) + mode = abgrx888; + else if ((vis->red_mask == 0xff000000) && + (vis->green_mask == 0x00ff0000) && + (vis->blue_mask == 0x0000ff00)) + mode = rgba888x; + else if ((vis->red_mask == 0x0000ff00) && + (vis->green_mask == 0x00ff0000) && + (vis->blue_mask == 0xff000000)) + mode = bgra888x; + else if ((vis->red_mask == 0x0003f000) && + (vis->green_mask == 0x00000fc0) && + (vis->blue_mask == 0x0000003f)) + mode = argbx666; + else if ((vis->red_mask == 0x0000f800) && + (vis->green_mask == 0x000007e0) && + (vis->blue_mask == 0x0000001f)) + mode = rgb565; + else if ((vis->red_mask == 0x0000001f) && + (vis->green_mask == 0x000007e0) && + (vis->blue_mask == 0x0000f800)) + mode = bgr565; + else if ((vis->red_mask == 0x00007c00) && + (vis->green_mask == 0x000003e0) && + (vis->blue_mask == 0x0000001f)) + mode = rgbx555; + else + return EINA_FALSE; + } + for (row = 0; row < h; row++) + { + unsigned char *s8; + unsigned short *s16; + unsigned int *s32; + unsigned int *dp, *de; + + dp = ((unsigned int *)(((unsigned char *)dst) + + ((dy + row) * dbpl))) + dx; + de = dp + w; + switch (sbpp) + { + case 8: + s8 = ((unsigned char *)(((unsigned char *)src) + ((y + row) * sbpl))) + x; + if (nret > 0) + { + while (dp < de) + { + *dp = pal[*s8]; + s8++; dp++; + } + } + else + return EINA_FALSE; + break; + + case 16: + s16 = ((unsigned short *)(((unsigned char *)src) + ((y + row) * sbpl))) + x; + switch (mode) + { + case rgb565: + while (dp < de) + { + r = (*s16 & 0xf800) << 8; + g = (*s16 & 0x07e0) << 5; + b = (*s16 & 0x001f) << 3; + r |= (r >> 5) & 0xff0000; + g |= (g >> 6) & 0x00ff00; + b |= (b >> 5); + *dp = 0xff000000 | r | g | b; + s16++; dp++; + } + break; + + case bgr565: + while (dp < de) + { + r = (*s16 & 0x001f) << 19; + g = (*s16 & 0x07e0) << 5; + b = (*s16 & 0xf800) >> 8; + r |= (r >> 5) & 0xff0000; + g |= (g >> 6) & 0x00ff00; + b |= (b >> 5); + *dp = 0xff000000 | r | g | b; + s16++; dp++; + } + break; + + case rgbx555: + while (dp < de) + { + r = (*s16 & 0x7c00) << 9; + g = (*s16 & 0x03e0) << 6; + b = (*s16 & 0x001f) << 3; + r |= (r >> 5) & 0xff0000; + g |= (g >> 5) & 0x00ff00; + b |= (b >> 5); + *dp = 0xff000000 | r | g | b; + s16++; dp++; + } + break; + + default: + return EINA_FALSE; + break; + } + break; + + case 24: + case 32: + s32 = ((unsigned int *)(((unsigned char *)src) + ((y + row) * sbpl))) + x; + switch (mode) + { + case argbx888: + while (dp < de) + { + *dp = 0xff000000 | *s32; + s32++; dp++; + } + break; + + case abgrx888: + while (dp < de) + { + r = *s32 & 0x000000ff; + g = *s32 & 0x0000ff00; + b = *s32 & 0x00ff0000; + *dp = 0xff000000 | (r << 16) | (g) | (b >> 16); + s32++; dp++; + } + break; + + case rgba888x: + while (dp < de) + { + *dp = 0xff000000 | (*s32 >> 8); + s32++; dp++; + } + break; + + case bgra888x: + while (dp < de) + { + r = *s32 & 0x0000ff00; + g = *s32 & 0x00ff0000; + b = *s32 & 0xff000000; + *dp = 0xff000000 | (r << 8) | (g >> 8) | (b >> 24); + s32++; dp++; + } + break; + + case argbx666: + while (dp < de) + { + r = (*s32 & 0x3f000) << 6; + g = (*s32 & 0x00fc0) << 4; + b = (*s32 & 0x0003f) << 2; + r |= (r >> 6) & 0xff0000; + g |= (g >> 6) & 0x00ff00; + b |= (b >> 6); + *dp = 0xff000000 | r | g | b; + s32++; dp++; + } + break; + + default: + return EINA_FALSE; + break; + } + break; + break; + + default: + return EINA_FALSE; + break; + } + } + return EINA_TRUE; +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_mwm.c b/src/lib/ecore_x/xlib/ecore_x_mwm.c new file mode 100644 index 0000000..7812cc2 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_mwm.c @@ -0,0 +1,106 @@ +/* + * Various MWM related functions. + * + * This is ALL the code involving anything MWM related. for both WM and + * client. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include + +#include "Ecore.h" +#include "ecore_x_private.h" +#include "Ecore_X.h" +#include "Ecore_X_Atoms.h" + +#define ECORE_X_MWM_HINTS_FUNCTIONS (1 << 0) +#define ECORE_X_MWM_HINTS_DECORATIONS (1 << 1) +#define ECORE_X_MWM_HINTS_INPUT_MODE (1 << 2) +#define ECORE_X_MWM_HINTS_STATUS (1 << 3) + +typedef struct _mwmhints +{ + CARD32 flags; + CARD32 functions; + CARD32 decorations; + INT32 inputmode; + CARD32 status; +} +MWMHints; + +EAPI Eina_Bool +ecore_x_mwm_hints_get(Ecore_X_Window win, + Ecore_X_MWM_Hint_Func *fhint, + Ecore_X_MWM_Hint_Decor *dhint, + Ecore_X_MWM_Hint_Input *ihint) +{ + unsigned char *p = NULL; + MWMHints *mwmhints = NULL; + int num; + Eina_Bool ret; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ret = EINA_FALSE; + if (!ecore_x_window_prop_property_get(win, + ECORE_X_ATOM_MOTIF_WM_HINTS, + ECORE_X_ATOM_MOTIF_WM_HINTS, + 32, &p, &num)) + return EINA_FALSE; + + mwmhints = (MWMHints *)p; + if (mwmhints) + { + if (num >= 4) + { + if (dhint) + { + if (mwmhints->flags & ECORE_X_MWM_HINTS_DECORATIONS) + *dhint = mwmhints->decorations; + else + *dhint = ECORE_X_MWM_HINT_DECOR_ALL; + } + + if (fhint) + { + if (mwmhints->flags & ECORE_X_MWM_HINTS_FUNCTIONS) + *fhint = mwmhints->functions; + else + *fhint = ECORE_X_MWM_HINT_FUNC_ALL; + } + + if (ihint) + { + if (mwmhints->flags & ECORE_X_MWM_HINTS_INPUT_MODE) + *ihint = mwmhints->inputmode; + else + *ihint = ECORE_X_MWM_HINT_INPUT_MODELESS; + } + + ret = EINA_TRUE; + } + + free(mwmhints); + } + + return ret; +} + +EAPI void +ecore_x_mwm_borderless_set(Ecore_X_Window win, + Eina_Bool borderless) +{ + unsigned int data[5] = {0, 0, 0, 0, 0}; + + data[0] = 2; /* just set the decorations hint! */ + data[2] = !borderless; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_property_set(win, + ECORE_X_ATOM_MOTIF_WM_HINTS, + ECORE_X_ATOM_MOTIF_WM_HINTS, + 32, (void *)data, 5); +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_netwm.c b/src/lib/ecore_x/xlib/ecore_x_netwm.c new file mode 100644 index 0000000..5a23a1b --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_netwm.c @@ -0,0 +1,2083 @@ +/* + * _NET_WM... aka Extended Window Manager Hint (EWMH) functions. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "Ecore.h" +#include "ecore_x_private.h" +#include "Ecore_X.h" + +typedef struct _Ecore_X_Startup_Info Ecore_X_Startup_Info; + +struct _Ecore_X_Startup_Info +{ + Ecore_X_Window win; + + int init; + + int buffer_size; + char *buffer; + + int length; + + /* These are the sequence info fields */ + char *id; + char *name; + int screen; + char *bin; + char *icon; + int desktop; + int timestamp; + char *description; + char *wmclass; + int silent; +}; + +static void _ecore_x_window_prop_string_utf8_set(Ecore_X_Window win, + Ecore_X_Atom atom, + const char *str); +static char *_ecore_x_window_prop_string_utf8_get(Ecore_X_Window win, + Ecore_X_Atom atom); +#if 0 /* Unused */ +static int _ecore_x_netwm_startup_info_process(Ecore_X_Startup_Info *info); +static int _ecore_x_netwm_startup_info_parse(Ecore_X_Startup_Info *info, + char *data); +#endif /* if 0 */ +static void _ecore_x_netwm_startup_info_free(void *data); + +/* + * Convenience macros + */ +#define _ATOM_SET_UTF8_STRING_LIST(win, atom, string, cnt) \ + XChangeProperty(_ecore_x_disp, \ + win, \ + atom, \ + ECORE_X_ATOM_UTF8_STRING, \ + 8, \ + PropModeReplace, \ + (unsigned char *)string, \ + cnt) + +/* + * Local variables + */ + +static Eina_Hash *startup_info = NULL; + +EAPI void +ecore_x_netwm_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + startup_info = eina_hash_string_superfast_new( + _ecore_x_netwm_startup_info_free); +} + +EAPI void +ecore_x_netwm_shutdown(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (startup_info) + eina_hash_free(startup_info); + + startup_info = NULL; +} + +/* + * WM identification + */ +EAPI void +ecore_x_netwm_wm_identify(Ecore_X_Window root, + Ecore_X_Window check, + const char *wm_name) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_window_set(check, + ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK, + &check, + 1); + _ecore_x_window_prop_string_utf8_set(check, + ECORE_X_ATOM_NET_WM_NAME, + wm_name); + /* This one isn't mandatory */ + _ecore_x_window_prop_string_utf8_set(root, + ECORE_X_ATOM_NET_WM_NAME, + wm_name); + ecore_x_window_prop_window_set(root, + ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK, + &check, + 1); +} + +/* + * Set supported atoms + */ +EAPI void +ecore_x_netwm_supported_set(Ecore_X_Window root, + Ecore_X_Atom *supported, + int num) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_atom_set(root, + ECORE_X_ATOM_NET_SUPPORTED, + supported, + num); +} + +EAPI Eina_Bool +ecore_x_netwm_supported_get(Ecore_X_Window root, + Ecore_X_Atom **supported, + int *num) +{ + int num_ret; + + if (num) + *num = 0; + + if (supported) + *supported = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + num_ret = ecore_x_window_prop_atom_list_get(root, ECORE_X_ATOM_NET_SUPPORTED, + supported); + if (num_ret <= 0) + return EINA_FALSE; + + if (num) + *num = num_ret; + + return EINA_TRUE; +} + +/* + * Desktop configuration and status + */ +EAPI void +ecore_x_netwm_desk_count_set(Ecore_X_Window root, + unsigned int n_desks) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_NUMBER_OF_DESKTOPS, + &n_desks, 1); +} + +EAPI void +ecore_x_netwm_desk_roots_set(Ecore_X_Window root, + Ecore_X_Window *vroots, + unsigned int n_desks) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_window_set(root, + ECORE_X_ATOM_NET_VIRTUAL_ROOTS, + vroots, + n_desks); +} + +EAPI void +ecore_x_netwm_desk_names_set(Ecore_X_Window root, + const char **names, + unsigned int n_desks) +{ + char ss[32], *buf, *t; + const char *s; + unsigned int i; + int l, len; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + buf = NULL; + len = 0; + + for (i = 0; i < n_desks; i++) + { + s = (names) ? names[i] : NULL; + if (!s) + { + /* Default to "Desk-" */ + sprintf(ss, "Desk-%d", i); + s = ss; + } + + l = strlen(s) + 1; + t = realloc(buf, len + l); + if (t) + { + buf = t; + memcpy(buf + len, s, l); + } + len += l; + } + + _ATOM_SET_UTF8_STRING_LIST(root, ECORE_X_ATOM_NET_DESKTOP_NAMES, buf, len); + + free(buf); +} + +EAPI void +ecore_x_netwm_desk_size_set(Ecore_X_Window root, + unsigned int width, + unsigned int height) +{ + unsigned int size[2]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + size[0] = width; + size[1] = height; + ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_DESKTOP_GEOMETRY, size, + 2); +} + +EAPI void +ecore_x_netwm_desk_viewports_set(Ecore_X_Window root, + unsigned int *origins, + unsigned int n_desks) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_DESKTOP_VIEWPORT, + origins, 2 * n_desks); +} + +EAPI void +ecore_x_netwm_desk_layout_set(Ecore_X_Window root, + int orientation, + int columns, + int rows, + int starting_corner) +{ + unsigned int layout[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + layout[0] = orientation; + layout[1] = columns; + layout[2] = rows; + layout[3] = starting_corner; + ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_DESKTOP_LAYOUT, + layout, 4); +} + +EAPI void +ecore_x_netwm_desk_workareas_set(Ecore_X_Window root, + unsigned int *areas, + unsigned int n_desks) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_WORKAREA, areas, + 4 * n_desks); +} + +EAPI unsigned int * +ecore_x_netwm_desk_workareas_get(Ecore_X_Window root, unsigned int *n_desks) +{ + int ret; + unsigned int *areas = NULL; + + if (!root) root = DefaultRootWindow(_ecore_x_disp); + + ret = ecore_x_window_prop_card32_list_get(root, ECORE_X_ATOM_NET_WORKAREA, + &areas); + if (!areas) + { + if (n_desks) *n_desks = 0; + return 0; + } + if (n_desks) *n_desks = ret / 4; + return areas; +} + +EAPI void +ecore_x_netwm_desk_current_set(Ecore_X_Window root, + unsigned int desk) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_CURRENT_DESKTOP, &desk, + 1); +} + +EAPI void +ecore_x_netwm_showing_desktop_set(Ecore_X_Window root, + Eina_Bool on) +{ + unsigned int val; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + val = (on) ? 1 : 0; + ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_SHOWING_DESKTOP, &val, + 1); +} + +/* + * Client status + */ + +/* Mapping order */ +EAPI void +ecore_x_netwm_client_list_set(Ecore_X_Window root, + Ecore_X_Window *p_clients, + unsigned int n_clients) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_window_set(root, ECORE_X_ATOM_NET_CLIENT_LIST, + p_clients, n_clients); +} + +/* Stacking order */ +EAPI void +ecore_x_netwm_client_list_stacking_set(Ecore_X_Window root, + Ecore_X_Window *p_clients, + unsigned int n_clients) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_window_set(root, ECORE_X_ATOM_NET_CLIENT_LIST_STACKING, + p_clients, n_clients); +} + +EAPI void +ecore_x_netwm_client_active_set(Ecore_X_Window root, + Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_window_set(root, ECORE_X_ATOM_NET_ACTIVE_WINDOW, + &win, 1); +} + +EAPI void +ecore_x_netwm_client_active_request(Ecore_X_Window root, + Ecore_X_Window win, + int type, + Ecore_X_Window current_win) +{ + XEvent xev; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!root) + root = DefaultRootWindow(_ecore_x_disp); + + xev.xclient.type = ClientMessage; + xev.xclient.display = _ecore_x_disp; + xev.xclient.window = win; + xev.xclient.message_type = ECORE_X_ATOM_NET_ACTIVE_WINDOW; + xev.xclient.format = 32; + xev.xclient.data.l[0] = type; + xev.xclient.data.l[1] = CurrentTime; + xev.xclient.data.l[2] = current_win; + xev.xclient.data.l[3] = 0; + xev.xclient.data.l[4] = 0; + + XSendEvent(_ecore_x_disp, root, False, + SubstructureRedirectMask | SubstructureNotifyMask, &xev); +} + +EAPI void +ecore_x_netwm_name_set(Ecore_X_Window win, + const char *name) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _ecore_x_window_prop_string_utf8_set(win, ECORE_X_ATOM_NET_WM_NAME, name); +} + +EAPI int +ecore_x_netwm_name_get(Ecore_X_Window win, + char **name) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (name) + *name = _ecore_x_window_prop_string_utf8_get(win, + ECORE_X_ATOM_NET_WM_NAME); + + return 1; +} + +EAPI void +ecore_x_netwm_startup_id_set(Ecore_X_Window win, + const char *id) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _ecore_x_window_prop_string_utf8_set(win, ECORE_X_ATOM_NET_STARTUP_ID, id); +} + +EAPI int +ecore_x_netwm_startup_id_get(Ecore_X_Window win, + char **id) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (id) + *id = _ecore_x_window_prop_string_utf8_get(win, + ECORE_X_ATOM_NET_STARTUP_ID); + + return 1; +} + +EAPI void +ecore_x_netwm_visible_name_set(Ecore_X_Window win, + const char *name) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _ecore_x_window_prop_string_utf8_set(win, ECORE_X_ATOM_NET_WM_VISIBLE_NAME, + name); +} + +EAPI int +ecore_x_netwm_visible_name_get(Ecore_X_Window win, + char **name) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (name) + *name = _ecore_x_window_prop_string_utf8_get( + win, + ECORE_X_ATOM_NET_WM_VISIBLE_NAME); + + return 1; +} + +EAPI void +ecore_x_netwm_icon_name_set(Ecore_X_Window win, + const char *name) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _ecore_x_window_prop_string_utf8_set(win, ECORE_X_ATOM_NET_WM_ICON_NAME, + name); +} + +EAPI int +ecore_x_netwm_icon_name_get(Ecore_X_Window win, + char **name) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (name) + *name = _ecore_x_window_prop_string_utf8_get( + win, + ECORE_X_ATOM_NET_WM_ICON_NAME); + + return 1; +} + +EAPI void +ecore_x_netwm_visible_icon_name_set(Ecore_X_Window win, + const char *name) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _ecore_x_window_prop_string_utf8_set(win, + ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME, + name); +} + +EAPI int +ecore_x_netwm_visible_icon_name_get(Ecore_X_Window win, + char **name) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (name) + *name = _ecore_x_window_prop_string_utf8_get( + win, + ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME); + + return 1; +} + +EAPI void +ecore_x_netwm_desktop_set(Ecore_X_Window win, + unsigned int desk) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_DESKTOP, &desk, 1); +} + +EAPI Eina_Bool +ecore_x_netwm_desktop_get(Ecore_X_Window win, + unsigned int *desk) +{ + int ret; + unsigned int tmp; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ret = ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_DESKTOP, + &tmp, 1); + + if (desk) + *desk = tmp; + + return ret == 1 ? EINA_TRUE : EINA_FALSE; +} + +/* + * _NET_WM_STRUT is deprecated + */ +EAPI void +ecore_x_netwm_strut_set(Ecore_X_Window win, + int left, + int right, + int top, + int bottom) +{ + unsigned int strut[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + strut[0] = left; + strut[1] = right; + strut[2] = top; + strut[3] = bottom; + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_STRUT, strut, 4); +} + +/* + * _NET_WM_STRUT is deprecated + */ +EAPI Eina_Bool +ecore_x_netwm_strut_get(Ecore_X_Window win, + int *left, + int *right, + int *top, + int *bottom) +{ + int ret = 0; + unsigned int strut[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ret = ecore_x_window_prop_card32_get(win, + ECORE_X_ATOM_NET_WM_STRUT, + strut, + 4); + if (ret != 4) + return EINA_FALSE; + + if (left) + *left = strut[0]; + + if (right) + *right = strut[1]; + + if (top) + *top = strut[2]; + + if (bottom) + *bottom = strut[3]; + + return EINA_TRUE; +} + +EAPI void +ecore_x_netwm_strut_partial_set(Ecore_X_Window win, + int left, + int right, + int top, + int bottom, + int left_start_y, + int left_end_y, + int right_start_y, + int right_end_y, + int top_start_x, + int top_end_x, + int bottom_start_x, + int bottom_end_x) +{ + unsigned int strut[12]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + strut[0] = left; + strut[1] = right; + strut[2] = top; + strut[3] = bottom; + strut[4] = left_start_y; + strut[5] = left_end_y; + strut[6] = right_start_y; + strut[7] = right_end_y; + strut[8] = top_start_x; + strut[9] = top_end_x; + strut[10] = bottom_start_x; + strut[11] = bottom_end_x; + ecore_x_window_prop_card32_set(win, + ECORE_X_ATOM_NET_WM_STRUT_PARTIAL, + strut, + 12); +} + +EAPI Eina_Bool +ecore_x_netwm_strut_partial_get(Ecore_X_Window win, + int *left, + int *right, + int *top, + int *bottom, + int *left_start_y, + int *left_end_y, + int *right_start_y, + int *right_end_y, + int *top_start_x, + int *top_end_x, + int *bottom_start_x, + int *bottom_end_x) +{ + int ret = 0; + unsigned int strut[12]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ret = ecore_x_window_prop_card32_get(win, + ECORE_X_ATOM_NET_WM_STRUT_PARTIAL, + strut, + 12); + if (ret != 12) + return EINA_FALSE; + + if (left) + *left = strut[0]; + + if (right) + *right = strut[1]; + + if (top) + *top = strut[2]; + + if (bottom) + *bottom = strut[3]; + + if (left_start_y) + *left_start_y = strut[4]; + + if (left_end_y) + *left_end_y = strut[5]; + + if (right_start_y) + *right_start_y = strut[6]; + + if (right_end_y) + *right_end_y = strut[7]; + + if (top_start_x) + *top_start_x = strut[8]; + + if (top_end_x) + *top_end_x = strut[9]; + + if (bottom_start_x) + *bottom_start_x = strut[10]; + + if (bottom_end_x) + *bottom_end_x = strut[11]; + + return EINA_TRUE; +} + +EAPI void +ecore_x_netwm_icons_set(Ecore_X_Window win, + Ecore_X_Icon *icon, + int num) +{ + unsigned int *data, *p, *p2; + unsigned int i, size, x, y; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + size = 0; + for (i = 0; i < (unsigned int)num; i++) + { + size += 2 + (icon[i].width * icon[i].height); + } + data = malloc(size * sizeof(unsigned int)); + if (!data) return; + p = data; + for (i = 0; i < (unsigned int)num; i++) + { + p[0] = icon[i].width; + p[1] = icon[i].height; + p += 2; + p2 = icon[i].data; + for (y = 0; y < icon[i].height; y++) + { + for (x = 0; x < icon[i].width; x++) + { + unsigned int r, g, b, a; + + a = (*p2 >> 24) & 0xff; + r = (*p2 >> 16) & 0xff; + g = (*p2 >> 8 ) & 0xff; + b = (*p2 ) & 0xff; + if ((a > 0) && (a < 255)) + { + // unpremul + r = (r * 255) / a; + g = (g * 255) / a; + b = (b * 255) / a; + } + *p = (a << 24) | (r << 16) | (g << 8) | b; + p++; + p2++; + } + } + } + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_ICON, + data, size); + free(data); +} + +EAPI Eina_Bool +ecore_x_netwm_icons_get(Ecore_X_Window win, + Ecore_X_Icon **icon, + int *num) +{ + unsigned int *data, *p; + unsigned int *src; + unsigned int len, icons, i; + int num_ret; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (num) + *num = 0; + + if (icon) + *icon = NULL; + + num_ret = ecore_x_window_prop_card32_list_get(win, ECORE_X_ATOM_NET_WM_ICON, + &data); + if (num_ret <= 0) + return EINA_FALSE; + + if (!data) + return EINA_FALSE; + + if (num_ret < 2) + { + free(data); + return EINA_FALSE; + } + + /* Check how many icons there are */ + icons = 0; + p = data; + while (p) + { + len = p[0] * p[1]; + p += (len + 2); + if ((p - data) > num_ret) + { + free(data); + return EINA_FALSE; + } + + icons++; + + if ((p - data) == num_ret) + p = NULL; + } + if (num) + *num = icons; + + /* If the user doesn't want the icons, return */ + if (!icon) + { + free(data); + return EINA_TRUE; + } + + /* Allocate memory */ + *icon = malloc(icons * sizeof(Ecore_X_Icon)); + if (!(*icon)) + { + free(data); + return EINA_FALSE; + } + + /* Fetch the icons */ + p = data; + for (i = 0; i < icons; i++) + { + unsigned int *ps, *pd, *pe; + + len = p[0] * p[1]; + ((*icon)[i]).width = p[0]; + ((*icon)[i]).height = p[1]; + src = &(p[2]); + ((*icon)[i]).data = malloc(len * sizeof(unsigned int)); + if (!((*icon)[i]).data) + { + while (i) + free(((*icon)[--i]).data); + free(*icon); + free(data); + return EINA_FALSE; + } + + pd = ((*icon)[i]).data; + ps = src; + pe = ps + len; + for (; ps < pe; ps++) + { + unsigned int r, g, b, a; + + a = (*ps >> 24) & 0xff; + r = (((*ps >> 16) & 0xff) * a) / 255; + g = (((*ps >> 8) & 0xff) * a) / 255; + b = (((*ps) & 0xff) * a) / 255; + *pd = (a << 24) | (r << 16) | (g << 8) | (b); + pd++; + } + p += (len + 2); + } + + free(data); + + return EINA_TRUE; +} + +EAPI void +ecore_x_netwm_icon_geometry_set(Ecore_X_Window win, + int x, + int y, + int width, + int height) +{ + unsigned int geometry[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + geometry[0] = x; + geometry[1] = y; + geometry[2] = width; + geometry[3] = height; + ecore_x_window_prop_card32_set(win, + ECORE_X_ATOM_NET_WM_ICON_GEOMETRY, + geometry, + 4); +} + +EAPI Eina_Bool +ecore_x_netwm_icon_geometry_get(Ecore_X_Window win, + int *x, + int *y, + int *width, + int *height) +{ + int ret; + unsigned int geometry[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ret = ecore_x_window_prop_card32_get(win, + ECORE_X_ATOM_NET_WM_ICON_GEOMETRY, + geometry, + 4); + if (ret != 4) + return EINA_FALSE; + + if (x) + *x = geometry[0]; + + if (y) + *y = geometry[1]; + + if (width) + *width = geometry[2]; + + if (height) + *height = geometry[3]; + + return EINA_TRUE; +} + +EAPI void +ecore_x_netwm_pid_set(Ecore_X_Window win, + int pid) +{ + unsigned int tmp; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + tmp = pid; + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_PID, + &tmp, 1); +} + +EAPI Eina_Bool +ecore_x_netwm_pid_get(Ecore_X_Window win, + int *pid) +{ + int ret; + unsigned int tmp; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ret = ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_PID, + &tmp, 1); + if (pid) + *pid = tmp; + + return ret == 1 ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_x_netwm_handled_icons_set(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_HANDLED_ICONS, + NULL, 0); +} + +EAPI Eina_Bool +ecore_x_netwm_handled_icons_get(Ecore_X_Window win) +{ + int ret = 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ret = ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_HANDLED_ICONS, + NULL, 0); + return ret == 0 ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_x_netwm_user_time_set(Ecore_X_Window win, + unsigned int tim) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_USER_TIME, + &tim, 1); +} + +EAPI Eina_Bool +ecore_x_netwm_user_time_get(Ecore_X_Window win, + unsigned int *tim) +{ + int ret; + unsigned int tmp; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ret = ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_USER_TIME, + &tmp, 1); + if (tim) + *tim = tmp; + + return ret == 1 ? EINA_TRUE : EINA_FALSE; +} + +Ecore_X_Window_State +_ecore_x_netwm_state_get(Ecore_X_Atom a) +{ + if (a == ECORE_X_ATOM_NET_WM_STATE_MODAL) + return ECORE_X_WINDOW_STATE_MODAL; + else if (a == ECORE_X_ATOM_NET_WM_STATE_STICKY) + return ECORE_X_WINDOW_STATE_STICKY; + else if (a == ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT) + return ECORE_X_WINDOW_STATE_MAXIMIZED_VERT; + else if (a == ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ) + return ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ; + else if (a == ECORE_X_ATOM_NET_WM_STATE_SHADED) + return ECORE_X_WINDOW_STATE_SHADED; + else if (a == ECORE_X_ATOM_NET_WM_STATE_SKIP_TASKBAR) + return ECORE_X_WINDOW_STATE_SKIP_TASKBAR; + else if (a == ECORE_X_ATOM_NET_WM_STATE_SKIP_PAGER) + return ECORE_X_WINDOW_STATE_SKIP_PAGER; + else if (a == ECORE_X_ATOM_NET_WM_STATE_HIDDEN) + return ECORE_X_WINDOW_STATE_HIDDEN; + else if (a == ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN) + return ECORE_X_WINDOW_STATE_FULLSCREEN; + else if (a == ECORE_X_ATOM_NET_WM_STATE_ABOVE) + return ECORE_X_WINDOW_STATE_ABOVE; + else if (a == ECORE_X_ATOM_NET_WM_STATE_BELOW) + return ECORE_X_WINDOW_STATE_BELOW; + else if (a == ECORE_X_ATOM_NET_WM_STATE_DEMANDS_ATTENTION) + return ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION; + else + return ECORE_X_WINDOW_STATE_UNKNOWN; +} + +static Ecore_X_Atom +_ecore_x_netwm_state_atom_get(Ecore_X_Window_State s) +{ + switch (s) + { + case ECORE_X_WINDOW_STATE_MODAL: + return ECORE_X_ATOM_NET_WM_STATE_MODAL; + + case ECORE_X_WINDOW_STATE_STICKY: + return ECORE_X_ATOM_NET_WM_STATE_STICKY; + + case ECORE_X_WINDOW_STATE_MAXIMIZED_VERT: + return ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT; + + case ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ: + return ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ; + + case ECORE_X_WINDOW_STATE_SHADED: + return ECORE_X_ATOM_NET_WM_STATE_SHADED; + + case ECORE_X_WINDOW_STATE_SKIP_TASKBAR: + return ECORE_X_ATOM_NET_WM_STATE_SKIP_TASKBAR; + + case ECORE_X_WINDOW_STATE_SKIP_PAGER: + return ECORE_X_ATOM_NET_WM_STATE_SKIP_PAGER; + + case ECORE_X_WINDOW_STATE_HIDDEN: + return ECORE_X_ATOM_NET_WM_STATE_HIDDEN; + + case ECORE_X_WINDOW_STATE_FULLSCREEN: + return ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN; + + case ECORE_X_WINDOW_STATE_ABOVE: + return ECORE_X_ATOM_NET_WM_STATE_ABOVE; + + case ECORE_X_WINDOW_STATE_BELOW: + return ECORE_X_ATOM_NET_WM_STATE_BELOW; + + case ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION: + return ECORE_X_ATOM_NET_WM_STATE_DEMANDS_ATTENTION; + + default: + return 0; + } +} + +EAPI void +ecore_x_netwm_window_state_set(Ecore_X_Window win, + Ecore_X_Window_State *state, + unsigned int num) +{ + Ecore_X_Atom *set; + unsigned int i; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!num) + { + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_NET_WM_STATE); + return; + } + + set = malloc(num * sizeof(Ecore_X_Atom)); + if (!set) + return; + + for (i = 0; i < num; i++) + set[i] = _ecore_x_netwm_state_atom_get(state[i]); + + ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_NET_WM_STATE, set, num); + + free(set); +} + +EAPI Eina_Bool +ecore_x_netwm_window_state_get(Ecore_X_Window win, + Ecore_X_Window_State **state, + unsigned int *num) +{ + int num_ret, i; + Ecore_X_Atom *atoms; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (num) + *num = 0; + + if (state) + *state = NULL; + + num_ret = ecore_x_window_prop_atom_list_get(win, ECORE_X_ATOM_NET_WM_STATE, + &atoms); + if (num_ret <= 0) + return EINA_FALSE; + + if (state) + { + *state = malloc(num_ret * sizeof(Ecore_X_Window_State)); + if (*state) + for (i = 0; i < num_ret; ++i) + (*state)[i] = _ecore_x_netwm_state_get(atoms[i]); + + if (num) + *num = num_ret; + } + + free(atoms); + return EINA_TRUE; +} + +static Ecore_X_Window_Type +_ecore_x_netwm_window_type_type_get(Ecore_X_Atom atom) +{ + if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DESKTOP) + return ECORE_X_WINDOW_TYPE_DESKTOP; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DOCK) + return ECORE_X_WINDOW_TYPE_DOCK; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR) + return ECORE_X_WINDOW_TYPE_TOOLBAR; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_MENU) + return ECORE_X_WINDOW_TYPE_MENU; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_UTILITY) + return ECORE_X_WINDOW_TYPE_UTILITY; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_SPLASH) + return ECORE_X_WINDOW_TYPE_SPLASH; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DIALOG) + return ECORE_X_WINDOW_TYPE_DIALOG; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NORMAL) + return ECORE_X_WINDOW_TYPE_NORMAL; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DROPDOWN_MENU) + return ECORE_X_WINDOW_TYPE_DROPDOWN_MENU; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_POPUP_MENU) + return ECORE_X_WINDOW_TYPE_POPUP_MENU; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLTIP) + return ECORE_X_WINDOW_TYPE_TOOLTIP; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION) + return ECORE_X_WINDOW_TYPE_NOTIFICATION; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_COMBO) + return ECORE_X_WINDOW_TYPE_COMBO; + else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DND) + return ECORE_X_WINDOW_TYPE_DND; + else + return ECORE_X_WINDOW_TYPE_UNKNOWN; +} + +static Ecore_X_Atom +_ecore_x_netwm_window_type_atom_get(Ecore_X_Window_Type type) +{ + switch (type) + { + case ECORE_X_WINDOW_TYPE_DESKTOP: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DESKTOP; + + case ECORE_X_WINDOW_TYPE_DOCK: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DOCK; + + case ECORE_X_WINDOW_TYPE_TOOLBAR: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR; + + case ECORE_X_WINDOW_TYPE_MENU: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_MENU; + + case ECORE_X_WINDOW_TYPE_UTILITY: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_UTILITY; + + case ECORE_X_WINDOW_TYPE_SPLASH: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_SPLASH; + + case ECORE_X_WINDOW_TYPE_DIALOG: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DIALOG; + + case ECORE_X_WINDOW_TYPE_NORMAL: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NORMAL; + + case ECORE_X_WINDOW_TYPE_DROPDOWN_MENU: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DROPDOWN_MENU; + + case ECORE_X_WINDOW_TYPE_POPUP_MENU: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_POPUP_MENU; + + case ECORE_X_WINDOW_TYPE_TOOLTIP: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLTIP; + + case ECORE_X_WINDOW_TYPE_NOTIFICATION: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION; + + case ECORE_X_WINDOW_TYPE_COMBO: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_COMBO; + + case ECORE_X_WINDOW_TYPE_DND: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DND; + + default: + return 0; + } +} + +/* + * FIXME: We should set WM_TRANSIENT_FOR if type is ECORE_X_WINDOW_TYPE_TOOLBAR + * , ECORE_X_WINDOW_TYPE_MENU or ECORE_X_WINDOW_TYPE_DIALOG + */ +EAPI void +ecore_x_netwm_window_type_set(Ecore_X_Window win, + Ecore_X_Window_Type type) +{ + Ecore_X_Atom atom; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + atom = _ecore_x_netwm_window_type_atom_get(type); + ecore_x_window_prop_atom_set(win, ECORE_X_ATOM_NET_WM_WINDOW_TYPE, + &atom, 1); +} + +/* FIXME: Maybe return 0 on some conditions? */ +EAPI Eina_Bool +ecore_x_netwm_window_type_get(Ecore_X_Window win, + Ecore_X_Window_Type *type) +{ + int num; + Ecore_X_Atom *atoms = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (type) + *type = ECORE_X_WINDOW_TYPE_NORMAL; + + num = ecore_x_window_prop_atom_list_get(win, + ECORE_X_ATOM_NET_WM_WINDOW_TYPE, + &atoms); + if ((type) && (num >= 1) && (atoms)) + *type = _ecore_x_netwm_window_type_type_get(atoms[0]); + + free(atoms); + if (num >= 1) + return EINA_TRUE; + + return EINA_FALSE; +} + +EAPI int +ecore_x_netwm_window_types_get(Ecore_X_Window win, + Ecore_X_Window_Type **types) +{ + int num, i; + Ecore_X_Atom *atoms = NULL; + Ecore_X_Window_Type *atoms2 = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (types) + *types = NULL; + + num = ecore_x_window_prop_atom_list_get(win, + ECORE_X_ATOM_NET_WM_WINDOW_TYPE, + &atoms); + if ((num <= 0) || (!atoms)) + { + if (atoms) + free(atoms); + + return 0; + } + + atoms2 = malloc(num * sizeof(Ecore_X_Window_Type)); + if (!atoms2) + return 0; + + for (i = 0; i < num; i++) + atoms2[i] = _ecore_x_netwm_window_type_type_get(atoms[i]); + free(atoms); + if (types) + *types = atoms2; + else + free(atoms2); + + return num; +} + +static Ecore_X_Atom +_ecore_x_netwm_action_atom_get(Ecore_X_Action action) +{ + switch (action) + { + case ECORE_X_ACTION_MOVE: + return ECORE_X_ATOM_NET_WM_ACTION_MOVE; + + case ECORE_X_ACTION_RESIZE: + return ECORE_X_ATOM_NET_WM_ACTION_RESIZE; + + case ECORE_X_ACTION_MINIMIZE: + return ECORE_X_ATOM_NET_WM_ACTION_MINIMIZE; + + case ECORE_X_ACTION_SHADE: + return ECORE_X_ATOM_NET_WM_ACTION_SHADE; + + case ECORE_X_ACTION_STICK: + return ECORE_X_ATOM_NET_WM_ACTION_STICK; + + case ECORE_X_ACTION_MAXIMIZE_HORZ: + return ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_HORZ; + + case ECORE_X_ACTION_MAXIMIZE_VERT: + return ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_VERT; + + case ECORE_X_ACTION_FULLSCREEN: + return ECORE_X_ATOM_NET_WM_ACTION_FULLSCREEN; + + case ECORE_X_ACTION_CHANGE_DESKTOP: + return ECORE_X_ATOM_NET_WM_ACTION_CHANGE_DESKTOP; + + case ECORE_X_ACTION_CLOSE: + return ECORE_X_ATOM_NET_WM_ACTION_CLOSE; + + case ECORE_X_ACTION_ABOVE: + return ECORE_X_ATOM_NET_WM_ACTION_ABOVE; + + case ECORE_X_ACTION_BELOW: + return ECORE_X_ATOM_NET_WM_ACTION_BELOW; + + default: + return 0; + } +} + +/* FIXME: Get complete list */ +EAPI Eina_Bool +ecore_x_netwm_allowed_action_isset(Ecore_X_Window win, + Ecore_X_Action action) +{ + int num, i; + Ecore_X_Atom *atoms, atom; + Eina_Bool ret = EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + num = ecore_x_window_prop_atom_list_get(win, ECORE_X_ATOM_NET_WM_WINDOW_TYPE, + &atoms); + if (num <= 0) + return ret; + + atom = _ecore_x_netwm_action_atom_get(action); + + for (i = 0; i < num; ++i) + { + if (atom == atoms[i]) + { + ret = 1; + break; + } + } + + free(atoms); + return ret; +} + +/* FIXME: Set complete list */ +EAPI void +ecore_x_netwm_allowed_action_set(Ecore_X_Window win, + Ecore_X_Action *action, + unsigned int num) +{ + Ecore_X_Atom *set; + unsigned int i; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!num) + { + ecore_x_window_prop_property_del(win, + ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS); + return; + } + + set = malloc(num * sizeof(Ecore_X_Atom)); + if (!set) + return; + + for (i = 0; i < num; i++) + set[i] = _ecore_x_netwm_action_atom_get(action[i]); + + ecore_x_window_prop_atom_set(win, + ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS, + set, + num); + + free(set); +} + +EAPI Eina_Bool +ecore_x_netwm_allowed_action_get(Ecore_X_Window win, + Ecore_X_Action **action, + unsigned int *num) +{ + int num_ret, i; + Ecore_X_Atom *atoms; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (num) + *num = 0; + + if (action) + *action = NULL; + + num_ret = ecore_x_window_prop_atom_list_get( + win, + ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS, + &atoms); + if (num_ret <= 0) + return EINA_FALSE; + + if (action) + { + *action = malloc(num_ret * sizeof(Ecore_X_Action)); + if (*action) + for (i = 0; i < num_ret; ++i) + (*action)[i] = _ecore_x_netwm_action_atom_get(atoms[i]); + + if (num) + *num = num_ret; + } + + free(atoms); + return EINA_TRUE; +} + +EAPI void +ecore_x_netwm_opacity_set(Ecore_X_Window win, + unsigned int opacity) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_WINDOW_OPACITY, + &opacity, 1); +} + +EAPI Eina_Bool +ecore_x_netwm_opacity_get(Ecore_X_Window win, + unsigned int *opacity) +{ + int ret; + unsigned int tmp; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ret = ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_WINDOW_OPACITY, + &tmp, 1); + if (opacity) + *opacity = tmp; + + return ret == 1 ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_x_netwm_frame_size_set(Ecore_X_Window win, + int fl, + int fr, + int ft, + int fb) +{ + unsigned int frames[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + frames[0] = fl; + frames[1] = fr; + frames[2] = ft; + frames[3] = fb; + ecore_x_window_prop_card32_set(win, + ECORE_X_ATOM_NET_FRAME_EXTENTS, + frames, + 4); +} + +EAPI Eina_Bool +ecore_x_netwm_frame_size_get(Ecore_X_Window win, + int *fl, + int *fr, + int *ft, + int *fb) +{ + int ret = 0; + unsigned int frames[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ret = ecore_x_window_prop_card32_get(win, + ECORE_X_ATOM_NET_FRAME_EXTENTS, + frames, + 4); + if (ret != 4) + return EINA_FALSE; + + if (fl) + *fl = frames[0]; + + if (fr) + *fr = frames[1]; + + if (ft) + *ft = frames[2]; + + if (fb) + *fb = frames[3]; + + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_x_netwm_sync_counter_get(Ecore_X_Window win, + Ecore_X_Sync_Counter *counter) +{ + int ret; + unsigned int tmp; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ret = ecore_x_window_prop_card32_get( + win, + ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER, + &tmp, + 1); + + if (counter) + *counter = tmp; + + return ret == 1 ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_x_netwm_ping_send(Ecore_X_Window win) +{ + XEvent xev; + + if (!win) + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + xev.xclient.type = ClientMessage; + xev.xclient.display = _ecore_x_disp; + xev.xclient.window = win; + xev.xclient.message_type = ECORE_X_ATOM_WM_PROTOCOLS; + xev.xclient.format = 32; + xev.xclient.data.l[0] = ECORE_X_ATOM_NET_WM_PING; + xev.xclient.data.l[1] = _ecore_x_event_last_time; + xev.xclient.data.l[2] = win; + xev.xclient.data.l[3] = 0; + xev.xclient.data.l[4] = 0; + + XSendEvent(_ecore_x_disp, win, False, NoEventMask, &xev); +} + +EAPI void +ecore_x_netwm_sync_request_send(Ecore_X_Window win, + unsigned int serial) +{ + XSyncValue value; + XEvent xev; + + if (!win) + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XSyncIntToValue(&value, (int)serial); + + xev.xclient.type = ClientMessage; + xev.xclient.display = _ecore_x_disp; + xev.xclient.window = win; + xev.xclient.message_type = ECORE_X_ATOM_WM_PROTOCOLS; + xev.xclient.format = 32; + xev.xclient.data.l[0] = ECORE_X_ATOM_NET_WM_SYNC_REQUEST; + xev.xclient.data.l[1] = _ecore_x_event_last_time; + xev.xclient.data.l[2] = XSyncValueLow32(value); + xev.xclient.data.l[3] = XSyncValueHigh32(value); + xev.xclient.data.l[4] = 0; + + XSendEvent(_ecore_x_disp, win, False, NoEventMask, &xev); +} + +EAPI void +ecore_x_netwm_state_request_send(Ecore_X_Window win, + Ecore_X_Window root, + Ecore_X_Window_State s1, + Ecore_X_Window_State s2, + Eina_Bool set) +{ + XEvent xev; + + if (!win) + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!root) + root = DefaultRootWindow(_ecore_x_disp); + + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.display = _ecore_x_disp; + xev.xclient.window = win; + xev.xclient.format = 32; + xev.xclient.message_type = ECORE_X_ATOM_NET_WM_STATE; + xev.xclient.data.l[0] = !!set; + xev.xclient.data.l[1] = _ecore_x_netwm_state_atom_get(s1); + xev.xclient.data.l[2] = _ecore_x_netwm_state_atom_get(s2); + /* 1 == normal client, if someone wants to use this + * function in a pager, this should be 2 */ + xev.xclient.data.l[3] = 1; + xev.xclient.data.l[4] = 0; + + XSendEvent(_ecore_x_disp, root, False, + SubstructureNotifyMask | SubstructureRedirectMask, &xev); +} + +EAPI void +ecore_x_netwm_desktop_request_send(Ecore_X_Window win, + Ecore_X_Window root, + unsigned int desktop) +{ + XEvent xev; + + if (!win) + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!root) + root = DefaultRootWindow(_ecore_x_disp); + + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.display = _ecore_x_disp; + xev.xclient.window = win; + xev.xclient.format = 32; + xev.xclient.message_type = ECORE_X_ATOM_NET_WM_DESKTOP; + xev.xclient.data.l[0] = desktop; + + XSendEvent(_ecore_x_disp, root, False, + SubstructureNotifyMask | SubstructureRedirectMask, &xev); +} + +EAPI void +ecore_x_netwm_moveresize_request_send(Ecore_X_Window win, + int x, + int y, + Ecore_X_Netwm_Direction direction, + unsigned int button) +{ + XEvent xev; + + if (!win) + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + xev.xclient.window = win; + xev.xclient.type = ClientMessage; + xev.xclient.message_type = ECORE_X_ATOM_NET_WM_MOVERESIZE; + xev.xclient.format = 32; + xev.xclient.data.l[0] = x; + xev.xclient.data.l[1] = y; + xev.xclient.data.l[2] = direction; + xev.xclient.data.l[3] = button; + xev.xclient.data.l[4] = 1; + + XSendEvent(_ecore_x_disp, win, False, + SubstructureNotifyMask | SubstructureRedirectMask, &xev); +} + +int +_ecore_x_netwm_startup_info_begin(Ecore_X_Window win __UNUSED__, + char *data __UNUSED__) +{ +#if 0 + Ecore_X_Startup_Info *info; + unsigned char *exists = 0; + + if (!startup_info) + return 0; + + info = eina_hash_find(startup_info, (void *)win); + if (info) + { + exists = 1; + WRN("Already got info for win: 0x%x", win); + _ecore_x_netwm_startup_info_free(info); + } + + info = calloc(1, sizeof(Ecore_X_Startup_Info)); + if (!info) + return 0; + + info->win = win; + info->length = 0; + info->buffer_size = 161; + info->buffer = calloc(info->buffer_size, sizeof(char)); + if (!info->buffer) + { + _ecore_x_netwm_startup_info_free(info); + return 0; + } + + memcpy(info->buffer, data, 20); + info->length += 20; + info->buffer[info->length] = 0; + if (exists) + eina_hash_modify(startup_info, (void *)info->win, info); + else + eina_hash_add(startup_info, (void *)info->win, info); + + if (strlen(info->buffer) != 20) + /* We have a '\0' in there, the message is done */ + _ecore_x_netwm_startup_info_process(info); + +#endif /* if 0 */ + return 1; +} + +int +_ecore_x_netwm_startup_info(Ecore_X_Window win __UNUSED__, + char *data __UNUSED__) +{ +#if 0 + Ecore_X_Startup_Info *info; + char *p; + + if (!startup_info) + return 0; + + info = eina_hash_find(startup_info, (void *)win); + if (!info) + return 0; + + if ((info->length + 20) > info->buffer_size) + { + info->buffer_size += 160; + info->buffer = realloc(info->buffer, info->buffer_size * sizeof(char)); + if (!info->buffer) + { + eina_hash_del(startup_info, (void *)info->win); + _ecore_x_netwm_startup_info_free(info); + return 0; + } + } + + memcpy(info->buffer + info->length, data, 20); + p = info->buffer + info->length; + info->length += 20; + info->buffer[info->length] = 0; + if (strlen(p) != 20) + /* We have a '\0' in there, the message is done */ + _ecore_x_netwm_startup_info_process(info); + +#endif /* if 0 */ + return 1; +} + +/* + * Set UTF-8 string property + */ +static void +_ecore_x_window_prop_string_utf8_set(Ecore_X_Window win, + Ecore_X_Atom atom, + const char *str) +{ + XChangeProperty(_ecore_x_disp, win, atom, ECORE_X_ATOM_UTF8_STRING, 8, + PropModeReplace, (unsigned char *)str, strlen(str)); +} + +/* + * Get UTF-8 string property + */ +static char * +_ecore_x_window_prop_string_utf8_get(Ecore_X_Window win, + Ecore_X_Atom atom) +{ + char *str; + unsigned char *prop_ret; + Atom type_ret; + unsigned long bytes_after, num_ret; + int format_ret; + + str = NULL; + prop_ret = NULL; + XGetWindowProperty(_ecore_x_disp, win, atom, 0, 0x7fffffff, False, + ECORE_X_ATOM_UTF8_STRING, &type_ret, + &format_ret, &num_ret, &bytes_after, &prop_ret); + if (prop_ret && num_ret > 0 && format_ret == 8) + { + str = malloc(num_ret + 1); + if (str) + { + memcpy(str, prop_ret, num_ret); + str[num_ret] = '\0'; + } + } + + if (prop_ret) + XFree(prop_ret); + + return str; +} + +#if 0 /* Unused */ +/* + * Process startup info + */ +static int +_ecore_x_netwm_startup_info_process(Ecore_X_Startup_Info *info) +{ + Ecore_X_Event_Startup_Sequence *e; + int event; + char *p; + + p = strchr(info->buffer, ':'); + if (!p) + { + eina_hash_del(startup_info, (void *)info->win); + _ecore_x_netwm_startup_info_free(info); + return 0; + } + + *p = 0; + if (!strcmp(info->buffer, "new")) + { + if (info->init) + event = ECORE_X_EVENT_STARTUP_SEQUENCE_CHANGE; + else + event = ECORE_X_EVENT_STARTUP_SEQUENCE_NEW; + + info->init = 1; + } + else if (!strcmp(info->buffer, "change")) + event = ECORE_X_EVENT_STARTUP_SEQUENCE_CHANGE; + else if (!strcmp(info->buffer, "remove")) + event = ECORE_X_EVENT_STARTUP_SEQUENCE_REMOVE; + else + { + eina_hash_del(startup_info, (void *)info->win); + _ecore_x_netwm_startup_info_free(info); + return 0; + } + + p++; + + if (!_ecore_x_netwm_startup_info_parse(info, p)) + { + eina_hash_del(startup_info, (void *)info->win); + _ecore_x_netwm_startup_info_free(info); + return 0; + } + + if (info->init) + { + e = calloc(1, sizeof(Ecore_X_Event_Startup_Sequence)); + if (!e) + { + eina_hash_del(startup_info, (void *)info->win); + _ecore_x_netwm_startup_info_free(info); + return 0; + } + + e->win = info->win; + ecore_event_add(event, e, NULL, NULL); + } + + if (event == ECORE_X_EVENT_STARTUP_SEQUENCE_REMOVE) + { + eina_hash_del(startup_info, (void *)info->win); + _ecore_x_netwm_startup_info_free(info); + } + else + { + /* Discard buffer */ + info->length = 0; + info->buffer[0] = 0; + } + + return 1; +} + +/* + * Parse startup info + */ +static int +_ecore_x_netwm_startup_info_parse(Ecore_X_Startup_Info *info, + char *data) +{ + while (*data) + { + int in_quot_sing, in_quot_dbl, escaped; + char *p, *pp; + char *key; + char value[1024]; + + /* Skip space */ + while (*data == ' ') + data++; + /* Get key */ + key = data; + data = strchr(key, '='); + if (!data) + return 0; + + *data = 0; + data++; + + /* Get value */ + p = data; + pp = value; + in_quot_dbl = 0; + in_quot_sing = 0; + escaped = 0; + while (*p) + { + if ((pp - value) >= 1024) + return 0; + + if (escaped) + { + *pp = *p; + pp++; + escaped = 0; + } + else if (in_quot_sing) + { + if (*p == '\\') + escaped = 1; + else if (*p == '\'') + in_quot_sing = 0; + else + { + *pp = *p; + pp++; + } + } + else if (in_quot_dbl) + { + if (*p == '\\') + escaped = 1; + else if (*p == '\"') + in_quot_dbl = 0; + else + { + *pp = *p; + pp++; + } + } + else + { + if (*p == '\\') + escaped = 1; + else if (*p == '\'') + in_quot_sing = 1; + else if (*p == '\"') + in_quot_dbl = 1; + else if (*p == ' ') + break; + else + { + *pp = *p; + pp++; + } + } + + p++; + } + if ((in_quot_dbl) || (in_quot_sing)) + return 0; + + data = p; + *pp = 0; + + /* Parse info */ + if (!strcmp(key, "ID")) + { + if ((info->id) && (strcmp(info->id, value))) + return 0; + + info->id = strdup(value); + p = strstr(value, "_TIME"); + if (p) + info->timestamp = atoi(p + 5); + } + else if (!strcmp(key, "NAME")) + { + if (info->name) + free(info->name); + + info->name = strdup(value); + } + else if (!strcmp(key, "SCREEN")) + info->screen = atoi(value); + else if (!strcmp(key, "BIN")) + { + if (info->bin) + free(info->bin); + + info->bin = strdup(value); + } + else if (!strcmp(key, "ICON")) + { + if (info->icon) + free(info->icon); + + info->icon = strdup(value); + } + else if (!strcmp(key, "DESKTOP")) + info->desktop = atoi(value); + else if (!strcmp(key, "TIMESTAMP")) + { + if (!info->timestamp) + info->timestamp = atoi(value); + } + else if (!strcmp(key, "DESCRIPTION")) + { + if (info->description) + free(info->description); + + info->description = strdup(value); + } + else if (!strcmp(key, "WMCLASS")) + { + if (info->wmclass) + free(info->wmclass); + + info->wmclass = strdup(value); + } + else if (!strcmp(key, "SILENT")) + info->silent = atoi(value); + else + ERR("Ecore X Sequence, Unknown: %s=%s", key, value); + } + if (!info->id) + return 0; + + return 1; +} + +#endif /* if 0 */ + +/* + * Free startup info struct + */ +static void +_ecore_x_netwm_startup_info_free(void *data) +{ + Ecore_X_Startup_Info *info; + + info = data; + if (!info) + return; + + if (info->buffer) + free(info->buffer); + + if (info->id) + free(info->id); + + if (info->name) + free(info->name); + + if (info->bin) + free(info->bin); + + if (info->icon) + free(info->icon); + + if (info->description) + free(info->description); + + if (info->wmclass) + free(info->wmclass); + + free(info); +} + +/* + * Is screen composited? + */ +EAPI Eina_Bool +ecore_x_screen_is_composited(int screen) +{ + Ecore_X_Window win; + static Ecore_X_Atom atom = None; + char buf[32]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + snprintf(buf, sizeof(buf), "_NET_WM_CM_S%i", screen); + if (atom == None) + atom = XInternAtom(_ecore_x_disp, buf, False); + + if (atom == None) + return EINA_FALSE; + + win = XGetSelectionOwner(_ecore_x_disp, atom); + + return (win != None) ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_x_screen_is_composited_set(int screen, + Ecore_X_Window win) +{ + static Ecore_X_Atom atom = None; + char buf[32]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + snprintf(buf, sizeof(buf), "_NET_WM_CM_S%i", screen); + if (atom == None) + atom = XInternAtom(_ecore_x_disp, buf, False); + + if (atom == None) + return; + + XSetSelectionOwner(_ecore_x_disp, atom, win, _ecore_x_event_last_time); +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_pixmap.c b/src/lib/ecore_x/xlib/ecore_x_pixmap.c new file mode 100644 index 0000000..7b13615 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_pixmap.c @@ -0,0 +1,121 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include "Ecore.h" +#include "ecore_x_private.h" +#include "Ecore_X.h" + +/** + * @defgroup Ecore_X_Pixmap_Group X Pixmap Functions + * + * Functions that operate on pixmaps. + */ + +/** + * Creates a new pixmap. + * @param win Window used to determine which screen of the display the + * pixmap should be created on. If 0, the default root window + * is used. + * @param w Width of the new pixmap. + * @param h Height of the new pixmap. + * @param dep Depth of the pixmap. If 0, the default depth of the default + * screen is used. + * @return New pixmap. + * @ingroup Ecore_X_Pixmap_Group + */ +EAPI Ecore_X_Pixmap +ecore_x_pixmap_new(Ecore_X_Window win, + int w, + int h, + int dep) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (win == 0) + win = DefaultRootWindow(_ecore_x_disp); + + if (dep == 0) + dep = DefaultDepth(_ecore_x_disp, DefaultScreen(_ecore_x_disp)); + + return XCreatePixmap(_ecore_x_disp, win, w, h, dep); +} + +/** + * Deletes the reference to the given pixmap. + * + * If no other clients have a reference to the given pixmap, the server + * will destroy it. + * + * @param pmap The given pixmap. + * @ingroup Ecore_X_Pixmap_Group + */ +EAPI void +ecore_x_pixmap_free(Ecore_X_Pixmap pmap) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XFreePixmap(_ecore_x_disp, pmap); +} + +/** + * Pastes a rectangular area of the given pixmap onto the given drawable. + * @param pmap The given pixmap. + * @param dest The given drawable. + * @param gc The graphics context which governs which operation will + * be used to paste the area onto the drawable. + * @param sx The X position of the area on the pixmap. + * @param sy The Y position of the area on the pixmap. + * @param w The width of the area. + * @param h The height of the area. + * @param dx The X position at which to paste the area on @p dest. + * @param dy The Y position at which to paste the area on @p dest. + * @ingroup Ecore_X_Pixmap_Group + */ +EAPI void +ecore_x_pixmap_paste(Ecore_X_Pixmap pmap, + Ecore_X_Drawable dest, + Ecore_X_GC gc, + int sx, + int sy, + int w, + int h, + int dx, + int dy) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XCopyArea(_ecore_x_disp, pmap, dest, gc, sx, sy, w, h, dx, dy); +} + +/** + * Retrieves the size of the given pixmap. + * @param pmap The given pixmap. + * @param x Pointer to an integer in which to store the X position. + * @param y Pointer to an integer in which to store the Y position. + * @param w Pointer to an integer in which to store the width. + * @param h Pointer to an integer in which to store the height. + * @ingroup Ecore_X_Pixmap_Group + */ +EAPI void +ecore_x_pixmap_geometry_get(Ecore_X_Pixmap pmap, + int *x, + int *y, + int *w, + int *h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (pmap) + ecore_x_drawable_geometry_get(pmap, x, y, w, h); +} + +/** + * Retrieves the depth of the given pixmap. + * @param pmap The given pixmap. + * @return The depth of the pixmap. + * @ingroup Ecore_X_Pixmap_Group + */ +EAPI int +ecore_x_pixmap_depth_get(Ecore_X_Pixmap pmap) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return ecore_x_drawable_depth_get(pmap); +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_private.h b/src/lib/ecore_x/xlib/ecore_x_private.h new file mode 100644 index 0000000..f962ffb --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_private.h @@ -0,0 +1,379 @@ +#ifndef _ECORE_X_PRIVATE_H +#define _ECORE_X_PRIVATE_H + +#include +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 256 +#endif /* ifndef MAXHOSTNAMELEN */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef ECORE_XCURSOR +#include +#endif /* ifdef ECORE_XCURSOR */ +#ifdef ECORE_XPRINT +#include +#endif /* ifdef ECORE_XPRINT */ +#ifdef ECORE_XINERAMA +#include +#endif /* ifdef ECORE_XINERAMA */ +#ifdef ECORE_XRANDR +#include +#endif /* ifdef ECORE_XRANDR */ +#ifdef ECORE_XSS +#include +#endif /* ifdef ECORE_XSS */ +#ifdef ECORE_XRENDER +#include +#endif /* ifdef ECORE_XRENDER */ +#ifdef ECORE_XFIXES +#include +#endif /* ifdef ECORE_XFIXES */ +#ifdef ECORE_XCOMPOSITE +#include +#endif /* ifdef ECORE_XCOMPOSITE */ +#ifdef ECORE_XDAMAGE +#include +#endif /* ifdef ECORE_XDAMAGE */ +#ifdef ECORE_XGESTURE +#include +#include +#endif /* ifdef ECORE_XGESTURE */ +#ifdef ECORE_XDPMS +#include +#endif /* ifdef ECORE_XDPMS */ +#ifdef ECORE_XKB +#include +#endif /* ifdef ECORE_XKB */ +#ifdef ECORE_XI2 +#include +#endif /* ifdef ECORE_XI2 */ + +#ifndef XK_MISCELLANY +# define XK_MISCELLANY 1 +#endif + +#include "Ecore.h" +#include "ecore_private.h" +#include "Ecore_X.h" +#include "Ecore_Input.h" + +extern int _ecore_xlib_log_dom; +#ifdef ECORE_XLIB_DEFAULT_LOG_COLOR +# undef ECORE_XLIB_DEFAULT_LOG_COLOR +#endif /* ifdef ECORE_XLIB_DEFAULT_LOG_COLOR */ +#define ECORE_XLIB_DEFAULT_LOG_COLOR EINA_COLOR_BLUE + +#ifdef ERR +# undef ERR +#endif /* ifdef ERR */ +#define ERR(...) EINA_LOG_DOM_ERR(_ecore_xlib_log_dom, __VA_ARGS__) + +#ifdef DBG +# undef DBG +#endif /* ifdef DBG */ +#define DBG(...) EINA_LOG_DOM_DBG(_ecore_xlib_log_dom, __VA_ARGS__) + +#ifdef INF +# undef INF +#endif /* ifdef INF */ +#define INF(...) EINA_LOG_DOM_INFO(_ecore_xlib_log_dom, __VA_ARGS__) + +#ifdef WRN +# undef WRN +#endif /* ifdef WRN */ +#define WRN(...) EINA_LOG_DOM_WARN(_ecore_xlib_log_dom, __VA_ARGS__) + +#ifdef CRIT +# undef CRIT +#endif /* ifdef CRIT */ +#define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_xlib_log_dom, __VA_ARGS__) + +typedef struct _Ecore_X_Selection_Intern Ecore_X_Selection_Intern; + +struct _Ecore_X_Selection_Intern +{ + Ecore_X_Window win; + Ecore_X_Atom selection; + unsigned char *data; + int length; + Time time; +}; + +typedef struct _Ecore_X_Selection_Converter Ecore_X_Selection_Converter; + +struct _Ecore_X_Selection_Converter +{ + Ecore_X_Atom target; + Eina_Bool (*convert)(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *type, int *typeseize); + Ecore_X_Selection_Converter *next; +}; + +typedef struct _Ecore_X_Selection_Parser Ecore_X_Selection_Parser; + +struct _Ecore_X_Selection_Parser +{ + char *target; + void *(*parse)(const char *target, void *data, int size, int format); + Ecore_X_Selection_Parser *next; +}; + +typedef struct _Ecore_X_DND_Source +{ + int version; + Ecore_X_Window win, dest; + + enum { + ECORE_X_DND_SOURCE_IDLE, + ECORE_X_DND_SOURCE_DRAGGING, + ECORE_X_DND_SOURCE_DROPPED, + ECORE_X_DND_SOURCE_CONVERTING + } state; + + struct + { + short x, y; + unsigned short width, height; + } rectangle; + + struct + { + Ecore_X_Window window; + int x, y; + } prev; + + Time time; + + Ecore_X_Atom action, accepted_action; + + int will_accept; + int suppress; + + int await_status; +} Ecore_X_DND_Source; + +typedef struct _Ecore_X_DND_Target +{ + int version; + Ecore_X_Window win, source; + + enum { + ECORE_X_DND_TARGET_IDLE, + ECORE_X_DND_TARGET_ENTERED + } state; + + struct + { + int x, y; + } pos; + + Time time; + + Ecore_X_Atom action, accepted_action; + + int will_accept; +} Ecore_X_DND_Target; + +extern Display *_ecore_x_disp; +extern double _ecore_x_double_click_time; +extern Time _ecore_x_event_last_time; +extern Window _ecore_x_event_last_win; +extern int _ecore_x_event_last_root_x; +extern int _ecore_x_event_last_root_y; +extern Eina_Bool _ecore_x_xcursor; + +extern Ecore_X_Atom _ecore_x_atoms_wm_protocols[ECORE_X_WM_PROTOCOL_NUM]; + +extern int _ecore_window_grabs_num; +extern Window *_ecore_window_grabs; +extern Eina_Bool (*_ecore_window_grab_replay_func)(void *data, + int event_type, + void *event); +extern void *_ecore_window_grab_replay_data; + +extern Ecore_X_Window _ecore_x_private_win; + +void _ecore_x_error_handler_init(void); +void _ecore_x_event_handle_any_event(XEvent *xevent); +void _ecore_x_event_handle_key_press(XEvent *xevent); +void _ecore_x_event_handle_key_release(XEvent *xevent); +void _ecore_x_event_handle_button_press(XEvent *xevent); +void _ecore_x_event_handle_button_release(XEvent *xevent); +void _ecore_x_event_handle_motion_notify(XEvent *xevent); +void _ecore_x_event_handle_enter_notify(XEvent *xevent); +void _ecore_x_event_handle_leave_notify(XEvent *xevent); +void _ecore_x_event_handle_focus_in(XEvent *xevent); +void _ecore_x_event_handle_focus_out(XEvent *xevent); +void _ecore_x_event_handle_keymap_notify(XEvent *xevent); +void _ecore_x_event_handle_expose(XEvent *xevent); +void _ecore_x_event_handle_graphics_expose(XEvent *xevent); +void _ecore_x_event_handle_visibility_notify(XEvent *xevent); +void _ecore_x_event_handle_create_notify(XEvent *xevent); +void _ecore_x_event_handle_destroy_notify(XEvent *xevent); +void _ecore_x_event_handle_unmap_notify(XEvent *xevent); +void _ecore_x_event_handle_map_notify(XEvent *xevent); +void _ecore_x_event_handle_map_request(XEvent *xevent); +void _ecore_x_event_handle_reparent_notify(XEvent *xevent); +void _ecore_x_event_handle_configure_notify(XEvent *xevent); +void _ecore_x_event_handle_configure_request(XEvent *xevent); +void _ecore_x_event_handle_gravity_notify(XEvent *xevent); +void _ecore_x_event_handle_resize_request(XEvent *xevent); +void _ecore_x_event_handle_circulate_notify(XEvent *xevent); +void _ecore_x_event_handle_circulate_request(XEvent *xevent); +void _ecore_x_event_handle_property_notify(XEvent *xevent); +void _ecore_x_event_handle_selection_clear(XEvent *xevent); +void _ecore_x_event_handle_selection_request(XEvent *xevent); +void _ecore_x_event_handle_selection_notify(XEvent *xevent); +void _ecore_x_event_handle_colormap_notify(XEvent *xevent); +void _ecore_x_event_handle_client_message(XEvent *xevent); +void _ecore_x_event_handle_mapping_notify(XEvent *xevent); +void _ecore_x_event_handle_shape_change(XEvent *xevent); +void _ecore_x_event_handle_screensaver_notify(XEvent *xevent); +#ifdef ECORE_XGESTURE +void _ecore_x_event_handle_gesture_notify_flick(XEvent *xevent); +void _ecore_x_event_handle_gesture_notify_pan(XEvent *xevent); +void _ecore_x_event_handle_gesture_notify_pinchrotation(XEvent *xevent); +void _ecore_x_event_handle_gesture_notify_tap(XEvent *xevent); +void _ecore_x_event_handle_gesture_notify_tapnhold(XEvent *xevent); +void _ecore_x_event_handle_gesture_notify_hold(XEvent *xevent); +void _ecore_x_event_handle_gesture_notify_group(XEvent *xevent); +#endif /* ifdef ECORE_XGESTURE */ +void _ecore_x_event_handle_sync_counter(XEvent *xevent); +void _ecore_x_event_handle_sync_alarm(XEvent *xevent); +#ifdef ECORE_XRANDR +void _ecore_x_event_handle_randr_change(XEvent *xevent); +void _ecore_x_event_handle_randr_notify(XEvent *xevent); +#endif /* ifdef ECORE_XRANDR */ +#ifdef ECORE_XFIXES +void _ecore_x_event_handle_fixes_selection_notify(XEvent *xevent); +#endif /* ifdef ECORE_XFIXES */ +#ifdef ECORE_XDAMAGE +void _ecore_x_event_handle_damage_notify(XEvent *xevent); +#endif /* ifdef ECORE_XDAMAGE */ +#ifdef ECORE_XKB +void _ecore_x_event_handle_xkb(XEvent *xevent); +#endif /* ifdef ECORE_XKB */ +void _ecore_x_event_handle_generic_event(XEvent *xevent); + +void _ecore_x_selection_data_init(void); +void _ecore_x_selection_shutdown(void); +Ecore_X_Atom _ecore_x_selection_target_atom_get(const char *target); +char *_ecore_x_selection_target_get(Ecore_X_Atom target); +Ecore_X_Selection_Intern *_ecore_x_selection_get(Ecore_X_Atom selection); +Eina_Bool _ecore_x_selection_set(Window w, + const void *data, + int len, + Ecore_X_Atom selection); +int _ecore_x_selection_convert(Ecore_X_Atom selection, + Ecore_X_Atom target, + void **data_ret, + Ecore_X_Atom *targettype, + int *targetsize); +void *_ecore_x_selection_parse(const char *target, + void *data, + int size, + int format); + +void _ecore_x_sync_magic_send(int val, + Ecore_X_Window swin); +void _ecore_x_window_grab_remove(Ecore_X_Window win); +void _ecore_x_key_grab_remove(Ecore_X_Window win); + +/* from dnd */ +void _ecore_x_dnd_init(void); +Ecore_X_DND_Source *_ecore_x_dnd_source_get(void); +Ecore_X_DND_Target *_ecore_x_dnd_target_get(void); +void _ecore_x_dnd_drag(Ecore_X_Window root, + int x, + int y); +void _ecore_x_dnd_shutdown(void); + +/* from netwm */ +Ecore_X_Window_State _ecore_x_netwm_state_get(Ecore_X_Atom a); +int _ecore_x_netwm_startup_info_begin(Ecore_X_Window win, + char *data); +int _ecore_x_netwm_startup_info(Ecore_X_Window win, + char *data); + +/* Fixes * Damage * Composite * DPMS */ +void _ecore_x_fixes_init(void); +void _ecore_x_damage_init(void); +void _ecore_x_composite_init(void); +void _ecore_x_dpms_init(void); +void _ecore_x_randr_init(void); +void _ecore_x_gesture_init(void); + +void _ecore_x_atoms_init(void); + +extern int _ecore_x_xi2_opcode; + +void _ecore_x_events_init(void); +void _ecore_x_events_shutdown(void); + +void _ecore_x_input_init(void); +void _ecore_x_input_shutdown(void); +void _ecore_x_input_handler(XEvent *xevent); +/* from sync */ + +void _ecore_mouse_move(unsigned int timestamp, + unsigned int xmodifiers, + int x, + int y, + int x_root, + int y_root, + unsigned int event_window, + unsigned int window, + unsigned int root_win, + int same_screen, + int dev, + double radx, + double rady, + double pressure, + double angle, + double mx, + double my, + double mrx, + double mry); +Ecore_Event_Mouse_Button *_ecore_mouse_button(int event, + unsigned int timestamp, + unsigned int xmodifiers, + unsigned int buttons, + int x, + int y, + int x_root, + int y_root, + unsigned int event_window, + unsigned int window, + unsigned int root_win, + int same_screen, + int dev, + double radx, + double rady, + double pressure, + double angle, + double mx, + double my, + double mrx, + double mry); + +void _ecore_x_modifiers_get(void); +KeySym _ecore_x_XKeycodeToKeysym(Display *display, KeyCode keycode, int index); + +//#define LOGFNS 1 + +#ifdef LOGFNS +#include +#define LOGFN(fl, ln, fn) printf("-ECORE-X: %25s: %5i - %s\n", fl, ln, fn); +#else /* ifdef LOGFNS */ +#define LOGFN(fl, ln, fn) +#endif /* ifdef LOGFNS */ + +#endif /* ifndef _ECORE_X_PRIVATE_H */ diff --git a/src/lib/ecore_x/xlib/ecore_x_randr.c b/src/lib/ecore_x/xlib/ecore_x_randr.c new file mode 100644 index 0000000..58a2830 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_randr.c @@ -0,0 +1,103 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include "ecore_x_private.h" +#include "ecore_x_randr.h" + +static Eina_Bool _randr_available = EINA_FALSE; +#ifdef ECORE_XRANDR +static int _randr_major, _randr_minor; +int _randr_version; +#define RANDR_1_1 ((1 << 16) | 1) +#define RANDR_1_2 ((1 << 16) | 2) +#define RANDR_1_3 ((1 << 16) | 3) + +#define RANDR_VALIDATE_ROOT(screen, \ + root) ((screen = \ + XRRRootToScreen(_ecore_x_disp, \ + root)) != -1) + +#define Ecore_X_Randr_Unset -1 + +XRRScreenResources *(*_ecore_x_randr_get_screen_resources)(Display * dpy, + Window window); + +#endif /* ifdef ECORE_XRANDR */ + +void +_ecore_x_randr_init(void) +{ +#ifdef ECORE_XRANDR + _randr_major = 1; + _randr_minor = 3; + _randr_version = 0; + + _ecore_x_randr_get_screen_resources = NULL; + if (XRRQueryVersion(_ecore_x_disp, &_randr_major, &_randr_minor)) + { + _randr_version = (_randr_major << 16) | _randr_minor; + if (_randr_version >= RANDR_1_3) + _ecore_x_randr_get_screen_resources = XRRGetScreenResourcesCurrent; + else if (_randr_version == RANDR_1_2) + _ecore_x_randr_get_screen_resources = XRRGetScreenResources; + + _randr_available = EINA_TRUE; + } + else + _randr_available = EINA_FALSE; + +#else + _randr_available = EINA_FALSE; +#endif +} + +/* + * @brief Query whether randr is available or not. + * + * @return @c EINA_TRUE, if extension is available, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_x_randr_query(void) +{ + return _randr_available; +} + +/* + * @return version of the RandR extension supported by the server or, in case + * RandR extension is not available, Ecore_X_Randr_Unset (=-1). + * bit version information: 31 MAJOR 16 | 15 MINOR 0 + */ +EAPI int +ecore_x_randr_version_get(void) +{ +#ifdef ECORE_XRANDR + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (_randr_available) + { + return _randr_version; + } + else + { + return Ecore_X_Randr_Unset; + } +#else + return -1; +#endif +} + +Eina_Bool +_ecore_x_randr_root_validate(Ecore_X_Window root) +{ +#ifdef ECORE_XRANDR + Ecore_X_Randr_Screen scr = -1; + if (root && RANDR_VALIDATE_ROOT(scr, root)) + return EINA_TRUE; + else + return EINA_FALSE; + +#else + return EINA_FALSE; +#endif +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_randr.h b/src/lib/ecore_x/xlib/ecore_x_randr.h new file mode 100644 index 0000000..eca3c0c --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_randr.h @@ -0,0 +1,7 @@ +#ifndef ECORE_X_INLINE_X +#define ECORE_X_INLINE_X +Eina_Bool _ecore_x_randr_root_validate(Ecore_X_Window root); +Eina_Bool _ecore_x_randr_output_validate(Ecore_X_Window root, + Ecore_X_Randr_Output + output); +#endif diff --git a/src/lib/ecore_x/xlib/ecore_x_randr_11.c b/src/lib/ecore_x/xlib/ecore_x_randr_11.c new file mode 100644 index 0000000..7d2b3b3 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_randr_11.c @@ -0,0 +1,334 @@ +/* + * vim:ts=8:sw=3:sts=8:expandtab:cino=>5n-3f0^-2{2 + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include "ecore_x_private.h" +#include "ecore_x_randr.h" +#include +#include +#include +#include + +#define Ecore_X_Randr_None 0 +#ifdef ECORE_XRANDR + +#define RANDR_1_1 ((1 << 16) | 1) + +#define RANDR_VALIDATE_ROOT(screen, \ + root) ((screen = \ + XRRRootToScreen(_ecore_x_disp, \ + root)) != -1) +#define RANDR_CHECK_1_1_RET(ret) if (_randr_version < RANDR_1_1) \ + return ret + +extern XRRScreenResources *(*_ecore_x_randr_get_screen_resources)(Display * + dpy, + Window + window); +extern int _randr_version; +#endif /* ifdef ECORE_XRANDR */ + +/* + * @param root window which's primary output will be queried + */ +EAPI Ecore_X_Randr_Orientation +ecore_x_randr_screen_primary_output_orientations_get(Ecore_X_Window root) +{ +#ifdef ECORE_XRANDR + Rotation rot = Ecore_X_Randr_None, crot; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + rot = + XRRRotations(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp, + root), &crot); + return rot; +#else /* ifdef ECORE_XRANDR */ + return Ecore_X_Randr_None; +#endif /* ifdef ECORE_XRANDR */ +} + +/* + * @param root window which's primary output will be queried + * @return the current orientation of the root window's screen primary output + */ +EAPI Ecore_X_Randr_Orientation +ecore_x_randr_screen_primary_output_orientation_get(Ecore_X_Window root) +{ +#ifdef ECORE_XRANDR + Rotation crot = Ecore_X_Randr_None; + XRRRotations(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp, + root), &crot); + return crot; +#else /* ifdef ECORE_XRANDR */ + return Ecore_X_Randr_None; +#endif /* ifdef ECORE_XRANDR */ +} + +/* + * @brief Sets a given screen's primary output's orientation. + * + * @param root Window which's screen's primary output will be queried. + * @param orientation orientation which should be set for the root window's + * screen primary output. + * @return @c EINA_TRUE if the primary output's orientation could be + * successfully altered. + */ +EAPI Eina_Bool +ecore_x_randr_screen_primary_output_orientation_set( + Ecore_X_Window root, + Ecore_X_Randr_Orientation + orientation) +{ +#ifdef ECORE_XRANDR + XRRScreenConfiguration *xrr_screen_cfg = NULL; + int sizeid; + Rotation crot; + Eina_Bool ret = EINA_FALSE; + if (!(xrr_screen_cfg = XRRGetScreenInfo(_ecore_x_disp, root))) + return EINA_FALSE; + + sizeid = XRRConfigCurrentConfiguration(xrr_screen_cfg, &crot); + if (!XRRSetScreenConfig(_ecore_x_disp, xrr_screen_cfg, root, sizeid, + orientation, CurrentTime)) + ret = EINA_TRUE; + + if (xrr_screen_cfg) + XRRFreeScreenConfigInfo(xrr_screen_cfg); + + return ret; +#else /* ifdef ECORE_XRANDR */ + return EINA_FALSE; +#endif /* ifdef ECORE_XRANDR */ +} + +/* + * @brief gets a screen's primary output's possible sizes + * @param root window which's primary output will be queried + * @param num number of sizes reported as supported by the screen's primary output + * @return an array of sizes reported as supported by the screen's primary output or - if query failed - NULL + */ +EAPI Ecore_X_Randr_Screen_Size_MM * +ecore_x_randr_screen_primary_output_sizes_get(Ecore_X_Window root, + int *num) +{ +#ifdef ECORE_XRANDR + Ecore_X_Randr_Screen_Size_MM *ret = NULL; + XRRScreenSize *sizes; + int i, n; + + /* we don't have to free sizes, because they're hold in a cache inside X*/ + sizes = + XRRSizes(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp, + root), &n); + if ((!sizes) || (n <= 0)) return NULL; + ret = calloc(n, sizeof(Ecore_X_Randr_Screen_Size_MM)); + if (!ret) + return NULL; + + if (num) + *num = n; + + for (i = 0; i < n; i++) + { + ret[i].width = sizes[i].width; + ret[i].height = sizes[i].height; + ret[i].width_mm = sizes[i].mwidth; + ret[i].height_mm = sizes[i].mheight; + } + return ret; +#else /* ifdef ECORE_XRANDR */ + return NULL; +#endif /* ifdef ECORE_XRANDR */ +} + +EAPI void +ecore_x_randr_screen_primary_output_current_size_get(Ecore_X_Window root, + int *w, + int *h, + int *w_mm, + int *h_mm, + int *size_index) +{ +#ifdef ECORE_XRANDR + XRRScreenSize *sizes; + XRRScreenConfiguration *sc = NULL; + int idx; + Rotation orientation; + int n; + + if (!(sc = XRRGetScreenInfo(_ecore_x_disp, root))) + { + ERR("Couldn't get screen information for %d", root); + return; + } + + idx = XRRConfigCurrentConfiguration(sc, &orientation); + + sizes = + XRRSizes(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp, + root), &n); + if ((idx < n) && (idx >= 0)) + { + if (w) + *w = sizes[idx].width; + + if (h) + *h = sizes[idx].height; + + if (w_mm) + *w_mm = sizes[idx].mwidth; + + if (h_mm) + *h_mm = sizes[idx].mheight; + + if (size_index) + *size_index = idx; + } + + XRRFreeScreenConfigInfo(sc); +#endif /* ifdef ECORE_XRANDR */ +} + +/* + * @brief Sets a given screen's primary output size, but disables all other + * outputs at the same time. + * + * @param root Window which's primary output will be queried. + * @param size_index Within the list of sizes reported as supported by the root + * window's screen primary output. + * @return @c EINA_TRUE on success, @c EINA_FALSE on failure due to e.g. + * invalid times. + */ +EAPI Eina_Bool +ecore_x_randr_screen_primary_output_size_set(Ecore_X_Window root, + int size_index) +{ +#ifdef ECORE_XRANDR + XRRScreenConfiguration *sc = NULL; + Eina_Bool ret = EINA_FALSE; + int nsizes = 0; + + if (size_index >= 0 && _ecore_x_randr_root_validate(root)) + { + XRRSizes(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp, + root), &nsizes); + + if (size_index < nsizes) + { + sc = XRRGetScreenInfo(_ecore_x_disp, root); + if (!XRRSetScreenConfig(_ecore_x_disp, sc, + root, size_index, + ECORE_X_RANDR_ORIENTATION_ROT_0, CurrentTime)) + { + ret = EINA_TRUE; + } + + if (sc) + XRRFreeScreenConfigInfo(sc); + } + } + + return ret; +#else /* ifdef ECORE_XRANDR */ + return EINA_FALSE; +#endif /* ifdef ECORE_XRANDR */ +} + +/* + * @param root window which's primary output will be queried + * @return currently used refresh rate or - if request failed or RandRR is not available - 0.0 + */ +EAPI Ecore_X_Randr_Refresh_Rate +ecore_x_randr_screen_primary_output_current_refresh_rate_get( + Ecore_X_Window root) +{ +#ifdef ECORE_XRANDR + Ecore_X_Randr_Refresh_Rate ret = 0.0; + XRRScreenConfiguration *sc = NULL; + + if (!_ecore_x_randr_root_validate(root) || + !(sc = XRRGetScreenInfo(_ecore_x_disp, root))) + return ret; + + ret = XRRConfigCurrentRate(sc); + if (sc) + XRRFreeScreenConfigInfo(sc); + + return ret; +#else /* ifdef ECORE_XRANDR */ + return 0.0; +#endif /* ifdef ECORE_XRANDR */ +} + +/* + * @param root window which's primary output will be queried + * @param size_index referencing the size to query valid refresh rates for + * @return currently used refresh rate or - if request failed or RandRR is not available - NULL + */ +EAPI Ecore_X_Randr_Refresh_Rate * +ecore_x_randr_screen_primary_output_refresh_rates_get(Ecore_X_Window root, + int size_index, + int *num) +{ +#ifdef ECORE_XRANDR + Ecore_X_Randr_Refresh_Rate *ret = NULL, *rates = NULL; + Ecore_X_Randr_Screen scr; + int n; + + if (num + && RANDR_VALIDATE_ROOT(scr, root) + && (rates = XRRRates(_ecore_x_disp, scr, size_index, &n))) + { + if (rates && (ret = malloc(sizeof(Ecore_X_Randr_Refresh_Rate) * n))) + { + memcpy(ret, rates, (sizeof(Ecore_X_Randr_Refresh_Rate) * n)); + *num = n; + } + } + + return ret; +#else /* ifdef ECORE_XRANDR */ + return NULL; +#endif /* ifdef ECORE_XRANDR */ +} + +//>= 1.1 +/* + * @brief Sets the current primary output's refresh rate. + * + * @param root Window which's primary output will be queried. + * @param size_index Referencing the size to be set. + * @param rate The refresh rate to be set. + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_x_randr_screen_primary_output_refresh_rate_set( + Ecore_X_Window root, + int size_index, + Ecore_X_Randr_Refresh_Rate + rate) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_1_RET(EINA_FALSE); + Eina_Bool ret = EINA_FALSE; + XRRScreenConfiguration *sc = NULL; + + if (!(sc = XRRGetScreenInfo(_ecore_x_disp, root))) + return ret; + + if (!XRRSetScreenConfigAndRate(_ecore_x_disp, sc, + root, size_index, + RR_Rotate_0, rate, CurrentTime)) + ret = EINA_TRUE; + + XRRFreeScreenConfigInfo(sc); + return ret; +#else /* ifdef ECORE_XRANDR */ + return EINA_FALSE; +#endif /* ifdef ECORE_XRANDR */ +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_randr_12.c b/src/lib/ecore_x/xlib/ecore_x_randr_12.c new file mode 100644 index 0000000..a1fecf8 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_randr_12.c @@ -0,0 +1,2405 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "ecore_x_private.h" +#include "ecore_x_randr.h" +#include +#include +#include +#include + +#define Ecore_X_Randr_None (Ecore_X_Randr_Crtc)0 +#define Ecore_X_Randr_Unset (Ecore_X_Randr_Crtc) - 1 + +#ifdef ECORE_XRANDR + +#define RANDR_1_2 ((1 << 16) | 2) + +#define RANDR_VALIDATE_ROOT(screen, root) \ + ((screen = XRRRootToScreen(_ecore_x_disp, root)) != -1) + +#define RANDR_CHECK_1_2_RET(ret) if (_randr_version < RANDR_1_2) \ + return ret + +#define RANDR_PROPERTY_EDID "EDID" +#define RANDR_PROPERTY_BACKLIGHT "Backlight" +#define RANDR_PROPERTY_SIGNAL_FORMAT "SignalFormat" +#define RANDR_PROPERTY_SIGNAL_PROPERTIES "SignalProperties" +#define RANDR_PROPERTY_CONNECTOR_TYPE "ConnectorType" +#define RANDR_PROPERTY_CONNECTOR_NUMBER "ConnectorNumber" +#define RANDR_PROPERTY_COMPATIBILITY_LIST "CompatibilityList" +#define RANDR_PROPERTY_CLONE_LIST "CloneList" + +extern XRRScreenResources *(*_ecore_x_randr_get_screen_resources)(Display * + dpy, + Window + window); +extern int _randr_version; +#endif + +/** + * @brief Enable event selection. This enables basic interaction with + * output/crtc events and requires RandR >= 1.2. + * + * @param win Select this window's properties for RandR events. + * @param on Enable/disable selecting. + */ +EAPI void +ecore_x_randr_events_select(Ecore_X_Window win, + Eina_Bool on) +{ +#ifdef ECORE_XRANDR + int mask; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!on) + mask = 0; + else + { + mask = RRScreenChangeNotifyMask; + if (_randr_version >= RANDR_1_2) + mask |= (RRCrtcChangeNotifyMask | + RROutputChangeNotifyMask | + RROutputPropertyNotifyMask); + } + + XRRSelectInput(_ecore_x_disp, win, mask); +#endif +} + +/** + * @brief Validates a CRTC for a given root window's screen. + * + * @param root The window which's default display will be queried. + * @param crtc The CRTC to be validated. + * @return In case it is found, @c EINA_TRUE will be returned, @c EINA_FALSE + * otherwise. + */ +static inline Eina_Bool +_ecore_x_randr_crtc_validate(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + + XRRScreenResources *res = NULL; + int i; + Eina_Bool ret = EINA_FALSE; + + if ((crtc == Ecore_X_Randr_None) || + (crtc == Ecore_X_Randr_Unset)) + return ret; + + if (_ecore_x_randr_root_validate(root) && crtc && + (res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root))) + { + for (i = 0; i < res->ncrtc; i++) + { + if (res->crtcs[i] == crtc) + { + ret = EINA_TRUE; + break; + } + } + XRRFreeScreenResources(res); + } + + return ret; +#else + return EINA_FALSE; +#endif +} + +Eina_Bool +_ecore_x_randr_output_validate(Ecore_X_Window root, + Ecore_X_Randr_Output output) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + + Eina_Bool ret = EINA_FALSE; + XRRScreenResources *res = NULL; + int i; + + if (_ecore_x_randr_root_validate(root) && output && + (res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root))) + { + for (i = 0; i < res->noutput; i++) + { + if (res->outputs[i] == output) + { + ret = EINA_TRUE; + break; + } + } + XRRFreeScreenResources(res); + } + + return ret; +#else + return EINA_FALSE; +#endif +} + +static inline Eina_Bool +_ecore_x_randr_mode_validate(Ecore_X_Window root, + Ecore_X_Randr_Mode mode) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + + Eina_Bool ret = EINA_FALSE; + XRRScreenResources *res = NULL; + int i; + + if (_ecore_x_randr_root_validate(root) && mode && + (res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root))) + { + for (i = 0; i < res->nmode; i++) + { + if (res->modes[i].id == mode) + { + ret = EINA_TRUE; + break; + } + } + XRRFreeScreenResources(res); + } + + return ret; +#else + return EINA_FALSE; +#endif +} + +/* + * @param w width of screen in px + * @param h height of screen in px + */ +EAPI void +ecore_x_randr_screen_current_size_get(Ecore_X_Window root, + int *w, + int *h, + int *w_mm, + int *h_mm) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(); + Ecore_X_Randr_Screen scr; + + if (!RANDR_VALIDATE_ROOT(scr, root)) + return; + + if (w) + *w = DisplayWidth(_ecore_x_disp, scr); + + if (h) + *h = DisplayHeight(_ecore_x_disp, scr); + + if (w_mm) + *w_mm = DisplayWidthMM(_ecore_x_disp, scr); + + if (h_mm) + *h_mm = DisplayHeightMM(_ecore_x_disp, scr); + +#endif +} + +/* + * @param root window which's screen will be queried + * @param wmin minimum width the screen can be set to + * @param hmin minimum height the screen can be set to + * @param wmax maximum width the screen can be set to + * @param hmax maximum height the screen can be set to + */ +EAPI void +ecore_x_randr_screen_size_range_get(Ecore_X_Window root, + int *wmin, + int *hmin, + int *wmax, + int *hmax) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(); + int twmin, thmin, twmax, thmax; + if (XRRGetScreenSizeRange (_ecore_x_disp, root, &twmin, &thmin, &twmax, + &thmax)) + { + if (wmin) + *wmin = twmin; + + if (hmin) + *hmin = thmin; + + if (wmax) + *wmax = twmax; + + if (hmax) + *hmax = thmax; + } + +#endif +} + +/* + * @param root Window which's screen's size should be set. If invalid (e.g. + * @c NULL) no action is taken. + * @param w Width in px the screen should be set to. If out of valid + * boundaries, current value is assumed. + * @param h Height in px the screen should be set to. If out of valid + * boundaries, current value is assumed. + * @param w_mm Width in mm the screen should be set to. If @c 0, current + * aspect is assumed. + * @param h_mm Height in mm the screen should be set to. If @c 0, current + * aspect is assumed. + * @return @c EINA_TRUE if request was successfully sent or screen is already + * in requested size, @c EINA_FALSE if parameters are invalid. + */ +EAPI Eina_Bool +ecore_x_randr_screen_current_size_set(Ecore_X_Window root, + int w, + int h, + int w_mm, + int h_mm) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + + Ecore_X_Randr_Screen scr; + int w_c, h_c, w_mm_c, h_mm_c, twmin, thmin, twmax, thmax; + + if (!RANDR_VALIDATE_ROOT(scr, root)) + return EINA_FALSE; + + ecore_x_randr_screen_current_size_get(root, &w_c, &h_c, &w_mm_c, &h_mm_c); + if ((w == w_c) && (h == h_c) && (w_mm_c == w_mm) && (h_mm_c == h_mm)) + return EINA_TRUE; + + ecore_x_randr_screen_size_range_get(root, &twmin, &thmin, &twmax, &thmax); + + if (((w != Ecore_X_Randr_None) && + ((w < twmin) || + (w > twmax))) || + ((h != Ecore_X_Randr_None) && ((h < thmin) || (h > thmax)))) + return EINA_FALSE; + + if (w <= 0) + w = DisplayWidth(_ecore_x_disp, scr); + + if (h <= 0) + h = DisplayHeight(_ecore_x_disp, scr); + + if (w_mm <= 0) + w_mm = + (int)(((double)(DisplayWidthMM(_ecore_x_disp, + scr) / + (double)DisplayWidth(_ecore_x_disp, + scr))) * (double)w); + + if (h_mm <= 0) + h_mm = + (int)(((double)(DisplayHeightMM(_ecore_x_disp, + scr) / + (double)DisplayHeight(_ecore_x_disp, + scr))) * (double)h); + + XRRSetScreenSize (_ecore_x_disp, root, w, h, w_mm, h_mm); + return EINA_TRUE; +#else + return EINA_FALSE; +#endif +} + +/* + * @brief get detailed information for all modes related to a root window's screen + * @param root window which's screen's ressources are queried + * @param num number of modes returned + * @return modes' information + */ +EAPI Ecore_X_Randr_Mode_Info ** +ecore_x_randr_modes_info_get(Ecore_X_Window root, + int *num) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(NULL); + XRRScreenResources *res = NULL; + Ecore_X_Randr_Mode_Info **ret = NULL; + int i; + + if (_ecore_x_randr_root_validate(root) && + (res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root))) + { + if ((ret = + (Ecore_X_Randr_Mode_Info **)malloc(sizeof( + Ecore_X_Randr_Mode_Info *) + * + res->nmode))) + { + for (i = 0; i < res->nmode; i++) + { + if ((ret[i] = malloc(sizeof(Ecore_X_Randr_Mode_Info)))) + { + ret[i]->xid = res->modes[i].id; + ret[i]->width = res->modes[i].width; + ret[i]->height = res->modes[i].height; + ret[i]->dotClock = res->modes[i].dotClock; + ret[i]->hSyncStart = res->modes[i].hSyncStart; + ret[i]->hSyncEnd = res->modes[i].hSyncEnd; + ret[i]->hTotal = res->modes[i].hTotal; + ret[i]->hSkew = res->modes[i].hSkew; + ret[i]->vSyncStart = res->modes[i].vSyncStart; + ret[i]->vSyncEnd = res->modes[i].vSyncEnd; + ret[i]->vTotal = res->modes[i].vTotal; + if ((ret[i]->name = (malloc(res->modes[i].nameLength + 1)))) + strncpy(ret[i]->name, res->modes[i].name, + (res->modes[i].nameLength + 1)); + else + ret[i]->name = NULL; + + ret[i]->nameLength = res->modes[i].nameLength; + ret[i]->modeFlags = res->modes[i].modeFlags; + } + else + { + while (i > 0) + free(ret[--i]); + free(ret); + ret = NULL; + break; + } + } + } + + if (ret && num) + *num = res->nmode; + + XRRFreeScreenResources(res); + } + + return ret; +#else + return NULL; +#endif +} + +/* + * @brief Add a mode to a display. + * + * @param root Window to which's screen's ressources are added. + * @param mode_info + * @return Ecore_X_Randr_Mode of the added mode. Ecore_X_Randr_None if mode + * adding failed. + * @since 1.2.0 + */ +EAPI Ecore_X_Randr_Mode +ecore_x_randr_mode_info_add(Ecore_X_Window root, + Ecore_X_Randr_Mode_Info *mode_info) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + Ecore_X_Randr_Mode mode = Ecore_X_Randr_None; + + if (_ecore_x_randr_root_validate(root) && mode_info) + mode = XRRCreateMode(_ecore_x_disp, root, (XRRModeInfo*)mode_info); + + return mode; +#else + return Ecore_X_Randr_None; +#endif +} + +/* + * @brief Delete a mode from the display. + * + * @param mode_info + * @since 1.2.0 + */ +EAPI void +ecore_x_randr_mode_del(Ecore_X_Randr_Mode mode) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(); + + XRRDestroyMode(_ecore_x_disp, mode); +#else + return; +#endif +} + +/* + * @brief get detailed information for a given mode id + * @param root window which's screen's ressources are queried + * @param mode the XID which identifies the mode of interest + * @return mode's detailed information + */ +EAPI Ecore_X_Randr_Mode_Info * +ecore_x_randr_mode_info_get(Ecore_X_Window root, + Ecore_X_Randr_Mode mode) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(NULL); + XRRScreenResources *res = NULL; + Ecore_X_Randr_Mode_Info *ret = NULL; + int i; + + if (_ecore_x_randr_root_validate(root) && + (res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root))) + { + for (i = 0; i < res->nmode; i++) + { + if ((res->modes[i].id == mode) && + (ret = malloc(sizeof(Ecore_X_Randr_Mode_Info)))) + { + ret->xid = res->modes[i].id; + ret->width = res->modes[i].width; + ret->height = res->modes[i].height; + ret->dotClock = res->modes[i].dotClock; + ret->hSyncStart = res->modes[i].hSyncStart; + ret->hSyncEnd = res->modes[i].hSyncEnd; + ret->hTotal = res->modes[i].hTotal; + ret->hSkew = res->modes[i].hSkew; + ret->vSyncStart = res->modes[i].vSyncStart; + ret->vSyncEnd = res->modes[i].vSyncEnd; + ret->vTotal = res->modes[i].vTotal; + ret->name = NULL; + ret->nameLength = 0; + if (res->modes[i].nameLength > 0) + { + ret->nameLength = res->modes[i].nameLength; + ret->name = malloc(res->modes[i].nameLength + 1); + if (ret->name) + memcpy(ret->name, res->modes[i].name, + res->modes[i].nameLength + 1); + } + ret->modeFlags = res->modes[i].modeFlags; + break; + } + } + XRRFreeScreenResources(res); + } + + return ret; +#else + return NULL; +#endif +} + +/* + * @brief Free detailed mode information. The pointer handed in will be set to + * @c NULL after freeing the memory. + * + * @param mode_info The mode information that should be freed. + */ +EAPI void +ecore_x_randr_mode_info_free(Ecore_X_Randr_Mode_Info *mode_info) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(); + if (!mode_info) + return; + + if (mode_info->name) + free(mode_info->name); + + free(mode_info); + mode_info = NULL; +#endif +} + +/* + * @brief Get all known CRTCs related to a root window's screen. + * + * @param root Window which's screen's ressources are queried. + * @param num Number of CRTCs returned. + * @return CRTC IDs. + */ +EAPI Ecore_X_Randr_Crtc * +ecore_x_randr_crtcs_get(Ecore_X_Window root, + int *num) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(NULL); + XRRScreenResources *res = NULL; + Ecore_X_Randr_Crtc *ret = NULL; + + if (num && root && + (res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root))) + { + if ((ret = malloc(sizeof(Ecore_X_Randr_Crtc) * res->ncrtc))) + { + memcpy(ret, res->crtcs, (sizeof(Ecore_X_Randr_Crtc) * res->ncrtc)); + *num = res->ncrtc; + } + + XRRFreeScreenResources(res); + } + + return ret; +#else + return NULL; +#endif +} + +/* + * @deprecated bad naming. Use ecore_x_randr_window_crtcs_get instead. + * @brief get the CRTCs, which display a certain window + * @param window window the displaying crtcs shall be found for + * @param num the number of crtcs displaying the window + * @return Array of crtcs that display a certain window. @c NULL if no crtcs + * was found that displays the specified window. + */ +EAPI Ecore_X_Randr_Crtc * +ecore_x_randr_current_crtc_get(Ecore_X_Window window, + int *num) +{ + return ecore_x_randr_window_crtcs_get(window, num); +} + +/* + * @brief get the CRTCs, which display a certain window + * @param window window the displaying crtcs shall be found for + * @param num the number of crtcs displaying the window + * @return Array of crtcs that display a certain window. @c NULL if no crtcs + * was found that displays the specified window. + * @since 1.2.0 + */ +EAPI Ecore_X_Randr_Crtc * +ecore_x_randr_window_crtcs_get(Ecore_X_Window window, + int *num) +{ +#ifdef ECORE_XRANDR + Ecore_X_Window root; + Eina_Rectangle w_geo, c_geo; + Ecore_X_Randr_Crtc *crtcs; + Ecore_X_Randr_Mode mode; + Ecore_X_Randr_Output *ret = NULL; + Window tw; + int ncrtcs, i, nret = 0, rx = 0, ry = 0; + + if (_randr_version < RANDR_1_2) goto _ecore_x_randr_window_crtcs_get_fail; + + ecore_x_window_geometry_get(window, + &w_geo.x, &w_geo.y, + &w_geo.w, &w_geo.h); + + root = ecore_x_window_root_get(window); + crtcs = ecore_x_randr_crtcs_get(root, &ncrtcs); + if (!crtcs) goto _ecore_x_randr_window_crtcs_get_fail; + + /* now get window RELATIVE to root window - thats what matters. */ + XTranslateCoordinates(_ecore_x_disp, window, root, 0, 0, &rx, &ry, &tw); + w_geo.x = rx; + w_geo.y = ry; + + ret = calloc(1, ncrtcs * sizeof(Ecore_X_Randr_Crtc)); + if (!ret) + { + free(crtcs); + goto _ecore_x_randr_window_crtcs_get_fail; + } + for (i = 0, nret = 0; i < ncrtcs; i++) + { + /* if crtc is not enabled, don't bother about it any further */ + mode = ecore_x_randr_crtc_mode_get(root, crtcs[i]); + if (mode == Ecore_X_Randr_None) continue; + + ecore_x_randr_crtc_geometry_get(root, crtcs[i], + &c_geo.x, &c_geo.y, + &c_geo.w, &c_geo.h); + if (eina_rectangles_intersect(&w_geo, &c_geo)) + { + ret[nret] = crtcs[i]; + nret++; + } + } + free(crtcs); + + if (num) *num = nret; + return ret; + +_ecore_x_randr_window_crtcs_get_fail: +#endif + if (num) *num = 0; + return NULL; +} + +EAPI Ecore_X_Randr_Output * +ecore_x_randr_outputs_get(Ecore_X_Window root, + int *num) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(NULL); + XRRScreenResources *res = NULL; + Ecore_X_Randr_Output *ret = NULL; + + if (num && root && + (res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root))) + { + if ((ret = malloc(sizeof(Ecore_X_Randr_Output) * res->noutput))) + { + memcpy(ret, res->outputs, + (sizeof(Ecore_X_Randr_Output) * res->noutput)); + if (num) + *num = res->noutput; + } + + if (res) + XRRFreeScreenResources(res); + } + + return ret; +#else + return NULL; +#endif +} + +//Per Crtc +/* + * @brief get a CRTC's outputs. + * @param root the root window which's screen will be queried + * @param num number of outputs referenced by given CRTC + */ +EAPI Ecore_X_Randr_Output * +ecore_x_randr_crtc_outputs_get(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc, + int *num) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(NULL); + XRRScreenResources *res = NULL; + Ecore_X_Randr_Output *ret = NULL; + XRRCrtcInfo *crtc_info = NULL; + + if (_ecore_x_randr_crtc_validate(root, + crtc) && + (res = + _ecore_x_randr_get_screen_resources (_ecore_x_disp, + root)) && + (crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc))) + { + if ((ret = malloc(sizeof(Ecore_X_Randr_Output) * crtc_info->noutput))) + { + memcpy(ret, crtc_info->outputs, + (sizeof(Ecore_X_Randr_Output) * crtc_info->noutput)); + if (num) + *num = crtc_info->noutput; + } + + if (crtc_info) + XRRFreeCrtcInfo(crtc_info); + + if (res) + XRRFreeScreenResources(res); + } + + return ret; +#else + return NULL; +#endif +} + +/* + * @brief get a CRTC's possible outputs. + * @param root the root window which's screen will be queried + * @param num number of possible outputs referenced by given CRTC + */ +EAPI Ecore_X_Randr_Output * +ecore_x_randr_crtc_possible_outputs_get(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc, + int *num) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(NULL); + XRRScreenResources *res = NULL; + Ecore_X_Randr_Output *ret = NULL; + XRRCrtcInfo *crtc_info = NULL; + + if (_ecore_x_randr_crtc_validate(root, + crtc) && + (res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root))) + { + if ((crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc))) + { + if ((ret = + malloc(sizeof(Ecore_X_Randr_Output) * crtc_info->npossible))) + { + memcpy(ret, crtc_info->possible, + (sizeof(Ecore_X_Randr_Output) * crtc_info->npossible)); + if (num) + *num = res->ncrtc; + } + + XRRFreeCrtcInfo(crtc_info); + } + + XRRFreeScreenResources(res); + } + + return ret; +#else + return NULL; +#endif +} + +EAPI void +ecore_x_randr_crtc_geometry_get(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc, + int *x, + int *y, + int *w, + int *h) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(); + XRRScreenResources *res = NULL; + XRRCrtcInfo *crtc_info = NULL; + + if (_ecore_x_randr_crtc_validate(root, + crtc) && + (res = + _ecore_x_randr_get_screen_resources (_ecore_x_disp, + root)) && + (crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc))) + { + if (x) + *x = crtc_info->x; + + if (y) + *y = crtc_info->y; + + if (w) + *w = crtc_info->width; + + if (h) + *h = crtc_info->height; + + XRRFreeCrtcInfo(crtc_info); + XRRFreeScreenResources(res); + } + +#endif +} + +/* + * @brief Sets the position of given CRTC within root window's screen. + * + * @param root The window's screen to be queried. + * @param crtc The CRTC which's position within the mentioned screen is to be + * altered. + * @param x Position on the x-axis (0 == left) of the screen. if x < 0 current + * value will be kept. + * @param y Position on the y-ayis (0 == top) of the screen. if y < 0, current + * value will be kept. + * @return @c EINA_TRUE if position could successfully be altered. + */ +EAPI Eina_Bool +ecore_x_randr_crtc_pos_set(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc, + int x, + int y) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + int w_c, h_c, w_new = 0, h_new = 0; + Eina_Rectangle crtc_geo; + + ecore_x_randr_crtc_geometry_get(root, + crtc, + &crtc_geo.x, + &crtc_geo.y, + &crtc_geo.w, + &crtc_geo.h); + ecore_x_randr_screen_current_size_get(root, &w_c, &h_c, NULL, NULL); + if (x < 0) + x = crtc_geo.x; + + if (y < 0) + y = crtc_geo.y; + + if ((x + crtc_geo.w) > w_c) + w_new = x + crtc_geo.w; + + if ((y + crtc_geo.h) > h_c) + h_new = y + crtc_geo.h; + + if ((w_new != 0) || (h_new != 0)) + if (!ecore_x_randr_screen_current_size_set(root, w_new, h_new, 0, 0)) + return EINA_FALSE; + + return ecore_x_randr_crtc_settings_set(root, + crtc, + NULL, + Ecore_X_Randr_Unset, + x, + y, + Ecore_X_Randr_Unset, + Ecore_X_Randr_Unset); +#else + return EINA_FALSE; +#endif +} + +/** + * @brief Get the current set mode of a given CRTC + * @param root the window's screen to be queried + * @param crtc the CRTC which's should be queried + * @return currently set mode or - in case parameters are invalid - + * Ecore_X_Randr_Unset + */ +EAPI Ecore_X_Randr_Mode +ecore_x_randr_crtc_mode_get(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(Ecore_X_Randr_Unset); + XRRScreenResources *res = NULL; + XRRCrtcInfo *crtc_info = NULL; + Ecore_X_Randr_Mode ret = Ecore_X_Randr_Unset; + if (_ecore_x_randr_root_validate(root) && + _ecore_x_randr_crtc_validate(root, + crtc) && + (res = + _ecore_x_randr_get_screen_resources(_ecore_x_disp, + root)) && + (crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc))) + { + ret = crtc_info->mode; + XRRFreeCrtcInfo(crtc_info); + XRRFreeScreenResources(res); + } + + return ret; +#else + return Ecore_X_Randr_Unset; +#endif +} + +/** + * @brief Sets a mode for a CRTC and the outputs attached to it. + * + * @param root The window's screen to be queried. + * @param crtc The CRTC which shall be set. + * @param outputs Array of outputs which have to be compatible with the mode. + * If @c NULL, CRTC will be disabled. + * @param noutputs Number of outputs in array to be used. Use + * Ecore_X_Randr_Unset (or @c -1) to use currently used outputs. + * @param mode XID of the mode to be set. If set to @c 0 the CRTC will be + * disabled. If set to @c -1 the call will fail. + * @return @c EINA_TRUE if mode setting was successful, @c EINA_FALSE + * otherwise. + */ +EAPI Eina_Bool +ecore_x_randr_crtc_mode_set(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc, + Ecore_X_Randr_Output *outputs, + int noutputs, + Ecore_X_Randr_Mode mode) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + + if (mode == Ecore_X_Randr_Unset) + return EINA_FALSE; + + return ecore_x_randr_crtc_settings_set(root, + crtc, + outputs, + noutputs, + Ecore_X_Randr_Unset, + Ecore_X_Randr_Unset, + mode, + Ecore_X_Randr_Unset); +#else + return EINA_FALSE; +#endif +} + +EAPI void +ecore_x_randr_crtc_size_get(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc, + int *w, + int *h) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(); + ecore_x_randr_crtc_geometry_get(root, crtc, NULL, NULL, w, h); +#endif +} + +EAPI Ecore_X_Randr_Refresh_Rate +ecore_x_randr_crtc_refresh_rate_get(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc, + Ecore_X_Randr_Mode mode) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(0.0); + XRRScreenResources *res = NULL; + XRRCrtcInfo *crtc_info = NULL; + Ecore_X_Randr_Refresh_Rate ret = 0.0; + int i; + + if (_ecore_x_randr_crtc_validate(root, + crtc) && + (res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root))) + { + for (i = 0; i < res->nmode; i++) + if (res->modes[i].id == mode) + { + if (res->modes[i].hTotal && res->modes[i].vTotal) + ret = ((double)res->modes[i].dotClock / + ((double)res->modes[i].hTotal * + (double)res->modes[i].vTotal)); + + break; + } + } + + if (crtc_info) + XRRFreeCrtcInfo(crtc_info); + + if (res) + XRRFreeScreenResources(res); + + return ret; +#else + return 0.0; +#endif +} + +EAPI Ecore_X_Randr_Orientation +ecore_x_randr_crtc_orientations_get(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(Ecore_X_Randr_None); + XRRCrtcInfo *crtc_info = NULL; + XRRScreenResources *res = NULL; + Ecore_X_Randr_Orientation ret = Ecore_X_Randr_None; + + if (_ecore_x_randr_crtc_validate(root, + crtc) && + (res = + _ecore_x_randr_get_screen_resources (_ecore_x_disp, + root)) && + (crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc))) + { + ret = crtc_info->rotations; + } + if (crtc_info) + XRRFreeCrtcInfo(crtc_info); + + if (res) + XRRFreeScreenResources(res); + + return ret; +#else + return Ecore_X_Randr_None; +#endif +} + +EAPI Ecore_X_Randr_Orientation +ecore_x_randr_crtc_orientation_get(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(Ecore_X_Randr_None); + XRRCrtcInfo *crtc_info = NULL; + XRRScreenResources *res = NULL; + Ecore_X_Randr_Orientation ret = Ecore_X_Randr_None; + + if (_ecore_x_randr_crtc_validate(root, + crtc) && + (res = + _ecore_x_randr_get_screen_resources (_ecore_x_disp, + root)) && + (crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc))) + { + ret = crtc_info->rotation; + } + if (crtc_info) + XRRFreeCrtcInfo(crtc_info); + + if (res) + XRRFreeScreenResources(res); + + return ret; +#else + return Ecore_X_Randr_None; +#endif +} + +EAPI Eina_Bool +ecore_x_randr_crtc_orientation_set(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc, + Ecore_X_Randr_Orientation orientation) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + Eina_Bool ret = EINA_FALSE; + + if (orientation != Ecore_X_Randr_None) + { + ret = ecore_x_randr_crtc_settings_set(root, + crtc, + NULL, + Ecore_X_Randr_Unset, + Ecore_X_Randr_Unset, + Ecore_X_Randr_Unset, + Ecore_X_Randr_Unset, + orientation); + } + + return ret; +#else + return EINA_FALSE; +#endif +} + +EAPI void +ecore_x_randr_crtc_pos_get(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc, + int *x, + int *y) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(); + + ecore_x_randr_crtc_geometry_get(root, crtc, x, y, NULL, NULL); +#endif +} + +EAPI Eina_Bool +ecore_x_randr_crtc_clone_set(Ecore_X_Window root, + Ecore_X_Randr_Crtc original, + Ecore_X_Randr_Crtc clon) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + + XRRScreenResources *res = NULL; + XRRCrtcInfo *clone_crtc_info = NULL; + Ecore_X_Randr_Mode original_mode = Ecore_X_Randr_None; + Ecore_X_Randr_Orientation original_orientation = Ecore_X_Randr_None; + Eina_Bool ret = EINA_FALSE; + int x, y; + + if (_ecore_x_randr_root_validate(root) && + _ecore_x_randr_crtc_validate(root, + original) && + _ecore_x_randr_crtc_validate(root, + clon) && + (res = + _ecore_x_randr_get_screen_resources (_ecore_x_disp, + root)) && + (clone_crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, clon))) + { + ecore_x_randr_crtc_geometry_get(root, original, &x, &y, NULL, NULL); + original_mode = ecore_x_randr_crtc_mode_get(root, original); + original_orientation = ecore_x_randr_crtc_orientation_get(root, + original); + ret = ecore_x_randr_crtc_settings_set(root, + clon, + NULL, + Ecore_X_Randr_Unset, + x, + y, + original_mode, + original_orientation); + XRRFreeCrtcInfo(clone_crtc_info); + XRRFreeScreenResources(res); + } + + return ret; +#else + return EINA_FALSE; +#endif +} + +/** + * @brief Sets the demanded parameters for a given CRTC. Note that the CRTC is + * auto enabled in it's preferred mode, when it was disabled before. + * + * @param root The root window which's default display will be queried. + * @param crtc The CRTC which's configuration should be altered. + * @param outputs An array of outputs, that should display this CRTC's content. + * @param noutputs Number of outputs in the array of outputs. If set to + * Ecore_X_Randr_Unset, current outputs and number of outputs will be used. + * If set to Ecore_X_Randr_None, CRTC will be disabled. + * @param x New x coordinate. If <0 (e.g. Ecore_X_Randr_Unset) the current x + * corrdinate will be assumed. + * @param y New y coordinate. If <0 (e.g. Ecore_X_Randr_Unset) the current y + * corrdinate will be assumed. + * @param mode The new mode to be set. If Ecore_X_Randr_None is passed, the + * CRTC will be disabled. If Ecore_X_Randr_Unset is passed, the current mode is + * assumed. + * @param orientation The new orientation to be set. If Ecore_X_Randr_Unset is + * used, the current mode is assumed. + * @return @c EINA_TRUE if the configuration alteration was successful, + * @c EINA_FALSE otherwise. + */ +EAPI Eina_Bool +ecore_x_randr_crtc_settings_set(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc, + Ecore_X_Randr_Output *outputs, + int noutputs, + int x, + int y, + Ecore_X_Randr_Mode mode, + Ecore_X_Randr_Orientation orientation) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + XRRScreenResources *res = NULL; + XRRCrtcInfo *crtc_info = NULL; + Eina_Bool ret = EINA_FALSE; + + if (_ecore_x_randr_crtc_validate(root, + crtc) && + (res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root))) + { + if ((crtc_info = XRRGetCrtcInfo(_ecore_x_disp, res, crtc))) + { + if ((mode == Ecore_X_Randr_None) || + (noutputs == Ecore_X_Randr_None)) + { + outputs = NULL; + noutputs = 0; + } + else if (noutputs == (int)Ecore_X_Randr_Unset) + { + outputs = (Ecore_X_Randr_Output *)crtc_info->outputs; + noutputs = crtc_info->noutput; + } + + if (mode == Ecore_X_Randr_Unset) + mode = crtc_info->mode; + + if (x < 0) + x = crtc_info->x; + + if (y < 0) + y = crtc_info->y; + + if (orientation == Ecore_X_Randr_Unset) + orientation = crtc_info->rotation; + + if (!XRRSetCrtcConfig(_ecore_x_disp, res, crtc, CurrentTime, + x, y, mode, orientation, (RROutput *)outputs, + noutputs)) + ret = EINA_TRUE; + + XRRFreeCrtcInfo(crtc_info); + } + + XRRFreeScreenResources(res); + } + + return ret; +#else + return EINA_FALSE; +#endif +} + +/** + * @brief Sets a CRTC relative to another one. + * + * @param root The root window which's default display will be set. + * @param crtc_r1 The CRTC to be positioned. + * @param crtc_r2 The CRTC the position should be relative to. + * @param policy The relation between the crtcs. + * @param alignment In case CRTCs size differ, aligns CRTC1 accordingly at + * CRTC2's borders. + * @return @c EINA_TRUE if crtc could be successfully positioned, @c EINA_FALSE + * if repositioning failed or if position of new crtc would be out of given + * screen's min/max bounds. + */ +EAPI Eina_Bool +ecore_x_randr_crtc_pos_relative_set(Ecore_X_Window root, + Ecore_X_Randr_Crtc crtc_r1, + Ecore_X_Randr_Crtc crtc_r2, + Ecore_X_Randr_Output_Policy policy, + Ecore_X_Randr_Relative_Alignment alignment) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + + Eina_Rectangle r1_geo, r2_geo; + int w_max, h_max, cw, ch, x_n = Ecore_X_Randr_Unset, y_n = + Ecore_X_Randr_Unset; + /* + int r1_noutputs, r2_noutputs, r1_nmodes, i, j, outputs_mode_found, mode_w, mode_h; + Ecore_X_Randr_Output *r1_outputs, *r2_outputs, *r2_r1_outputs; + Ecore_X_Randr_Mode *r1_modes, r2_mode, r1_mode; + Eina_Bool ret; + */ + + if ((ecore_x_randr_crtc_mode_get(root, crtc_r1) == Ecore_X_Randr_None) + || (ecore_x_randr_crtc_mode_get(root, crtc_r2) == Ecore_X_Randr_None)) + return EINA_FALSE; + + if (!_ecore_x_randr_crtc_validate(root, crtc_r1) || + (!(crtc_r1 != crtc_r2) && + !_ecore_x_randr_crtc_validate(root, crtc_r2))) + return EINA_FALSE; + + ecore_x_randr_crtc_geometry_get(root, + crtc_r1, + &r1_geo.x, + &r1_geo.y, + &r1_geo.w, + &r1_geo.h); + ecore_x_randr_crtc_geometry_get(root, + crtc_r2, + &r2_geo.x, + &r2_geo.y, + &r2_geo.w, + &r2_geo.h); + ecore_x_randr_screen_size_range_get(root, NULL, NULL, &w_max, &h_max); + ecore_x_randr_screen_current_size_get(root, &cw, &ch, NULL, NULL); + + switch (policy) + { + case ECORE_X_RANDR_OUTPUT_POLICY_RIGHT: + //set r1 right of r2 + x_n = r2_geo.x + r2_geo.w; + + switch (alignment) + { + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE: + y_n = Ecore_X_Randr_Unset; + break; + + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL: + y_n = + ((int)(((double)r2_geo.h / + 2.0) + (double)r2_geo.y - ((double)r1_geo.h / 2.0))); + break; + + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR: + y_n = ((int)((double)ch / 2.0) - ((double)r1_geo.h / 2.0)); + break; + } + break; + + case ECORE_X_RANDR_OUTPUT_POLICY_LEFT: + //set r1 left of r2 + x_n = r2_geo.x - r1_geo.w; + + switch (alignment) + { + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE: + y_n = Ecore_X_Randr_Unset; + break; + + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL: + y_n = + ((int)(((double)r2_geo.h / + 2.0) + r2_geo.y - ((double)r1_geo.h / 2.0))); + break; + + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR: + y_n = ((int)(((double)ch / 2.0) - ((double)r1_geo.h / 2.0))); + break; + } + break; + + case ECORE_X_RANDR_OUTPUT_POLICY_BELOW: + //set r1 below r2 + y_n = r2_geo.y + r2_geo.h; + + switch (alignment) + { + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE: + x_n = Ecore_X_Randr_Unset; + break; + + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL: + x_n = + ((int)((((double)r2_geo.x + + (double)r2_geo.w) / 2.0) - ((double)r1_geo.w / 2.0))); + break; + + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR: + x_n = ((int)((double)cw / 2.0)); + break; + } + break; + + case ECORE_X_RANDR_OUTPUT_POLICY_ABOVE: + y_n = r2_geo.y - r1_geo.h; + + //set r1 above r2 + switch (alignment) + { + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_NONE: + x_n = Ecore_X_Randr_Unset; + break; + + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_REL: + x_n = + ((int)((((double)r2_geo.x + + (double)r2_geo.w) / 2.0) - ((double)r1_geo.w / 2.0))); + break; + + case ECORE_X_RANDR_RELATIVE_ALIGNMENT_CENTER_SCR: + x_n = ((int)((double)cw / 2.0)); + break; + } + break; + + case ECORE_X_RANDR_OUTPUT_POLICY_CLONE: + return ecore_x_randr_crtc_pos_set(root, crtc_r1, r2_geo.x, r2_geo.y); + + /* entire cloning (including modesetting) + //all outputs of crtc1 capable of crtc2's current mode? + r2_mode = ecore_x_randr_crtc_mode_get(root, crtc_r2); + if (!(r1_outputs = + ecore_x_randr_crtc_outputs_get(root, crtc_r1, + &r1_noutputs)) || + (r1_noutputs == 0)) + return EINA_FALSE; + + for (i = 0, outputs_mode_found = 0; i < r1_noutputs; i++) + { + if (!(r1_modes = + ecore_x_randr_output_modes_get(root, r1_outputs[i], + &r1_nmodes, NULL))) + { + free(r1_outputs); + return EINA_FALSE; + } + + for (j = 0; j < r1_nmodes; j++) + { + ecore_x_randr_mode_size_get(root, + r1_modes[j], + &mode_w, + &mode_h); + if ((mode_w == r2_geo.w) && (mode_h == r2_geo.h)) + { + r1_mode = r1_modes[j]; + ++outputs_mode_found; + free(r1_modes); + r1_modes = NULL; + break; + } + } + if (r1_modes) + free(r1_modes); + + if (outputs_mode_found <= i) + { + //an output doesn't support the set mode, cancel! + free(r1_outputs); + return EINA_FALSE; + } + } + free (r1_outputs); + //CRTC 1's outputs support a mode of same geometry as CRTC 2. + ret = + (ecore_x_randr_crtc_mode_set(root, crtc_r1, Ecore_X_Randr_None, + Ecore_X_Randr_None, + r1_mode) && + ecore_x_randr_crtc_pos_set(root, crtc_r1, r2_geo.x, r2_geo.y)); + return ret; + */ + + /* entire cloning on same CRTC + //all outputs of crtc1 capable of crtc2's current mode? + r2_mode = ecore_x_randr_crtc_mode_get(root, crtc_r2); + if (!(r1_outputs = + ecore_x_randr_crtc_outputs_get(root, crtc_r1, + &r1_noutputs)) || + (r1_noutputs == 0)) + return EINA_FALSE; + + for (i = 0, outputs_mode_found = 0; i < r1_noutputs; i++) + { + if (!(r1_modes = + ecore_x_randr_output_modes_get(root, r1_outputs[i], + &r1_nmodes, NULL))) + { + free(r1_outputs); + return EINA_FALSE; + } + + for (j = 0; j < r1_nmodes; j++) + { + if (r1_modes[j] == r2_mode) + { + ++outputs_mode_found; + free(r1_modes); + r1_modes = NULL; + break; + } + } + if (r1_modes) + free(r1_modes); + + if (outputs_mode_found <= i) + { + //an output doesn't support the set mode, cancel! + free(r1_outputs); + return EINA_FALSE; + } + } + //check whether crtc r2 can use all outputs of r1. + if (!(r2_outputs = + ecore_x_randr_crtc_possible_outputs_get(root, crtc_r2, + &r2_noutputs)) || + (r2_noutputs == 0)) + { + free(r1_outputs); + return EINA_FALSE; + } + + for (i = 0; i < r1_noutputs; i++) + { + for (j = 0; j < r2_noutputs; ) + { + if (r1_outputs[i] == r2_outputs[j]) + break; + + j++; + } + if (j == r2_noutputs) + { + //didn't find the output! + free (r1_outputs); + free (r2_outputs); + return EINA_FALSE; + } + } + + //apparently crtc2 supports all outputs of r1 + //TODO: check with the compatible list of outputs (property in RR1.3) + r2_r1_outputs = + malloc(sizeof(Ecore_X_Randr_Output) * (r1_noutputs + r2_noutputs)); + for (i = 0; i < r1_noutputs; i++) + { + r2_r1_outputs[i] = r1_outputs[i]; + } + free(r1_outputs); + for (; i < r2_noutputs; i++) + { + r2_r1_outputs[i] = r2_outputs[i]; + } + free(r2_outputs); + ret = + ecore_x_randr_crtc_mode_set(root, crtc_r2, r2_r1_outputs, + (r1_noutputs + r1_noutputs), r2_mode); + free (r2_r1_outputs); + return ret; + */ + case ECORE_X_RANDR_OUTPUT_POLICY_NONE: + break; + default: + return EINA_FALSE; + } + if ((x_n == r1_geo.x) && (y_n == r1_geo.x)) + return EINA_TRUE; + + //out of possible bounds? + if (((y_n + r1_geo.h) > h_max) || ((x_n + r1_geo.w) > w_max)) + return EINA_FALSE; + + return ecore_x_randr_crtc_pos_set(root, crtc_r1, x_n, y_n); +#else + return EINA_FALSE; +#endif +} + +/* + * @brief Add given mode to given output. + * + * @param output The output the mode is added to. + * @param mode The mode added to the output. + * @return @c EINA_FALSE if output or mode equal Ecore_X_Randr_None, else + * @c EINA_TRUE. + * Additionally, if xcb backend is used, the success of the addition is + * reported back directly. + * @since 1.2.0 + */ +EAPI Eina_Bool +ecore_x_randr_output_mode_add(Ecore_X_Randr_Output output, + Ecore_X_Randr_Mode mode) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + + if ((output == Ecore_X_Randr_None) || (mode == Ecore_X_Randr_None)) + return EINA_FALSE; + + XRRAddOutputMode(_ecore_x_disp, output, mode); + return EINA_TRUE; +#else + return EINA_FALSE; +#endif +} + +/* + * @brief delete given mode from given output + * @param output the output the mode is removed from + * @param mode the mode removed from the output + * @since 1.2.0 + */ +EAPI void +ecore_x_randr_output_mode_del(Ecore_X_Randr_Output output, + Ecore_X_Randr_Mode mode) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(); + + if ((output == Ecore_X_Randr_None) || (mode == Ecore_X_Randr_None)) + return; + + XRRDeleteOutputMode(_ecore_x_disp, output, mode); +#else + return; +#endif +} + +EAPI Ecore_X_Randr_Mode * +ecore_x_randr_output_modes_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *num, + int *npreferred) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(NULL); + XRRScreenResources *res = NULL; + XRROutputInfo *output_info = NULL; + Ecore_X_Randr_Mode *modes = NULL; + + if ((output != Ecore_X_Randr_None) + && (res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root)) + && (output_info = + XRRGetOutputInfo(_ecore_x_disp, res, (RROutput)output))) + { + if ((modes = malloc(sizeof(Ecore_X_Randr_Mode) * output_info->nmode))) + { + memcpy(modes, output_info->modes, + (sizeof(Ecore_X_Randr_Mode) * output_info->nmode)); + if (num) + *num = output_info->nmode; + + if (npreferred) + *npreferred = output_info->npreferred; + } + } + + if (output_info) + XRRFreeOutputInfo(output_info); + + if (res) + XRRFreeScreenResources(res); + + return modes; +#else + return NULL; +#endif +} + +EAPI Ecore_X_Randr_Crtc * +ecore_x_randr_output_possible_crtcs_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *num) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(NULL); + XRRScreenResources *res = NULL; + XRROutputInfo *output_info = NULL; + Ecore_X_Randr_Crtc *crtcs = NULL; + + if ((output != Ecore_X_Randr_None)) + { + if ((res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root))) + { + if ((output_info = XRRGetOutputInfo(_ecore_x_disp, res, output))) + { + if ((crtcs = malloc(sizeof(Ecore_X_Randr_Crtc) * output_info->ncrtc))) + { + memcpy(crtcs, output_info->crtcs, (sizeof(Ecore_X_Randr_Crtc) * output_info->ncrtc)); + if (num) *num = output_info->ncrtc; + } + XRRFreeOutputInfo(output_info); + } + XRRFreeScreenResources(res); + } + } + return crtcs; +#else + return Ecore_X_Randr_None; +#endif +} + +/** + * @brief gets the the outputs which might be used simultenously on the same + * CRTC. + * @param root window that this information should be queried for. + * @param output the output which's clones we concern + * @param num number of possible clones + */ +EAPI Ecore_X_Randr_Output * +ecore_x_randr_output_clones_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *num) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(NULL); + XRRScreenResources *res = NULL; + XRROutputInfo *output_info = NULL; + Ecore_X_Randr_Output *outputs = NULL; + + if ((output != Ecore_X_Randr_None)) + { + if ((res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root))) + { + if ((output_info = XRRGetOutputInfo(_ecore_x_disp, res, output))) + { + if ((outputs = malloc(sizeof(Ecore_X_Randr_Output) * output_info->nclone))) + { + memcpy(outputs, output_info->clones, (sizeof(Ecore_X_Randr_Output) * output_info->nclone)); + if (num) *num = output_info->nclone; + } + XRRFreeOutputInfo(output_info); + } + XRRFreeScreenResources(res); + } + } + return outputs; +#else + return Ecore_X_Randr_None; +#endif +} + +EAPI Ecore_X_Randr_Crtc +ecore_x_randr_output_crtc_get(Ecore_X_Window root, + Ecore_X_Randr_Output output) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(Ecore_X_Randr_None); + XRRScreenResources *res = NULL; + XRROutputInfo *output_info = NULL; + Ecore_X_Randr_Crtc ret = Ecore_X_Randr_None; + + if ((output != Ecore_X_Randr_None)) + { + if ((res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root))) + { + if ((output_info = XRRGetOutputInfo(_ecore_x_disp, res, output))) + { + ret = output_info->crtc; + XRRFreeOutputInfo(output_info); + } + XRRFreeScreenResources(res); + } + } + + return ret; +#else + return Ecore_X_Randr_None; +#endif +} + +/** + * @brief gets the given output's name as reported by X + * @param root the window which's screen will be queried + * @param output The output for which the name will be reported. + * @param len length of returned c-string. + * @return name of the output as reported by X + */ +EAPI char * +ecore_x_randr_output_name_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *len) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(NULL); + XRRScreenResources *res = NULL; + XRROutputInfo *output_info = NULL; + char *ret = NULL; + + if ((output != Ecore_X_Randr_None) + && (res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root)) + && (output_info = XRRGetOutputInfo(_ecore_x_disp, res, output))) + { + /* + * Actually the below command is correct, but due to a bug in libXrandr + * it doesn't work. Therefore we stick with strlen(). + * Replace the line below with the following once this bug is + * fixed within libXrandr. + * + * *len = output_info->nameLen; + * + */ + if ((ret = strdup(output_info->name)) && len) + *len = strlen(ret); + + XRRFreeOutputInfo(output_info); + } + + if (res) + XRRFreeScreenResources(res); + + return ret; +#else + return NULL; +#endif +} + +/** + * @brief gets the width and hight of a given mode + * @param mode the mode which's size is to be looked up + * @param w width of given mode in px + * @param h height of given mode in px + */ +EAPI void +ecore_x_randr_mode_size_get(Ecore_X_Window root, + Ecore_X_Randr_Mode mode, + int *w, + int *h) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(); + XRRScreenResources *res = NULL; + int i; + + if ((mode != Ecore_X_Randr_None) + && (w || h) + && (res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root))) + { + for (i = 0; i < res->nmode; i++) + { + if (res->modes[i].id == mode) + { + if (w) + *w = res->modes[i].width; + + if (h) + *h = res->modes[i].height; + + break; + } + } + } + + if (res) + XRRFreeScreenResources(res); + +#endif +} + +/** + * @brief gets the EDID information of an attached output if available. + * Note that this information is not to be compared using ordinary string + * comparison functions, since it includes 0-bytes. + * @param root window this information should be queried from + * @param output the XID of the output + * @param length length of the byte-array. If NULL, request will fail. + */ +EAPI unsigned char * +ecore_x_randr_output_edid_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + unsigned long *length) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(NULL); + Atom name = XInternAtom (_ecore_x_disp, RANDR_PROPERTY_EDID, False); + unsigned char *prop_data, *ret = NULL; + int actual_format; + unsigned long nitems, bytes_after; + Atom actual_type; + + if (!length || !_ecore_x_randr_output_validate(root, output)) + return NULL; + + if (XRRGetOutputProperty (_ecore_x_disp, output, name, + 0, 100, False, False, + AnyPropertyType, + &actual_type, &actual_format, + &nitems, &bytes_after, &prop_data) == Success) + { + if (actual_type == XA_INTEGER && actual_format == 8) + { + if ((ret = malloc(nitems * sizeof(unsigned char)))) + { + if (length && + (memcpy(ret, prop_data, (nitems * sizeof(unsigned char))))) + *length = nitems; + + return ret; + } + } + } + + return NULL; +#else + return NULL; +#endif +} + +EAPI Ecore_X_Randr_Connection_Status +ecore_x_randr_output_connection_status_get(Ecore_X_Window root, + Ecore_X_Randr_Output output) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN); + XRRScreenResources *res = NULL; + XRROutputInfo *output_info = NULL; + Ecore_X_Randr_Connection_Status ret = + ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN; + + if ((output != Ecore_X_Randr_None) + && (res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root)) + && (output_info = XRRGetOutputInfo(_ecore_x_disp, res, output))) + { + ret = output_info->connection; + } + + if (output_info) + XRRFreeOutputInfo(output_info); + + if (res) + XRRFreeScreenResources(res); + + return ret; +#else + return ECORE_X_RANDR_CONNECTION_STATUS_UNKNOWN; +#endif +} + +EAPI void +ecore_x_randr_output_size_mm_get(Ecore_X_Window root, + Ecore_X_Randr_Output output, + int *w_mm, + int *h_mm) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(); + XRRScreenResources *res = NULL; + XRROutputInfo *output_info = NULL; + + if ((output != Ecore_X_Randr_None) + && (res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root))) + { + if ((output_info = + XRRGetOutputInfo(_ecore_x_disp, res, (RROutput)output))) + { + if (w_mm) + *w_mm = output_info->mm_width; + + if (h_mm) + *h_mm = output_info->mm_height; + + XRRFreeOutputInfo(output_info); + } + + XRRFreeScreenResources(res); + } + +#endif +} + +EAPI Eina_Bool +ecore_x_randr_move_all_crtcs_but(Ecore_X_Window root, + const Ecore_X_Randr_Crtc *not_moved, + int nnot_moved, + int dx, + int dy) +{ +#ifdef ECORE_XRANDR + Ecore_X_Randr_Crtc *crtcs_to_be_moved = NULL; + XRRScreenResources *res = NULL; + int i, j, k, n; + Eina_Bool ret; + + if ((nnot_moved <= 0) || (!not_moved) + || !_ecore_x_randr_root_validate(root) + || !(res = + _ecore_x_randr_get_screen_resources (_ecore_x_disp, root))) + return EINA_FALSE; + + n = (res->ncrtc - nnot_moved); + if ((crtcs_to_be_moved = malloc(sizeof(Ecore_X_Randr_Crtc) * n))) + { + for (i = 0, k = 0; (i < res->ncrtc) && (k < n); i++) + { + for (j = 0; j < nnot_moved; j++) + { + if (res->crtcs[i] == not_moved[j]) + break; + } + if (j == nnot_moved) + //crtcs[i] is not in the 'not to move'-list + crtcs_to_be_moved[k++] = res->crtcs[i]; + } + } + + XRRFreeScreenResources(res); + ret = ecore_x_randr_move_crtcs(root, crtcs_to_be_moved, n, dx, dy); + free(crtcs_to_be_moved); + return ret; +#else + return EINA_FALSE; +#endif +} + +/* + * @brief Move given CRTCs belonging to the given root window's screen dx/dy + * pixels relative to their current position. The screen size will be + * automatically adjusted if necessary and possible. + * + * @param root Window which's screen's resources are used. + * @param crtcs List of CRTCs to be moved. + * @param ncrtc Number of CRTCs in array. + * @param dx Amount of pixels the CRTCs should be moved in x direction. + * @param dy Amount of pixels the CRTCs should be moved in y direction. + * @return @c EINA_TRUE if all crtcs could be moved successfully. + */ +EAPI Eina_Bool +ecore_x_randr_move_crtcs(Ecore_X_Window root, + const Ecore_X_Randr_Crtc *crtcs, + int ncrtc, + int dx, + int dy) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + XRRScreenResources *res = NULL; + XRRCrtcInfo **crtc_info = NULL; + Eina_Bool ret = EINA_TRUE; + int i, cw, ch, w_max, h_max, nw, nh; + + crtc_info = alloca(sizeof(XRRCrtcInfo *) * ncrtc); + memset(crtc_info, 0, sizeof(XRRCrtcInfo *) * ncrtc); + if (_ecore_x_randr_root_validate(root) + && (res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root))) + { + ecore_x_randr_screen_size_range_get(root, NULL, NULL, &w_max, &h_max); + ecore_x_randr_screen_current_size_get(root, &cw, &ch, NULL, NULL); + nw = cw; + nh = ch; + + for (i = 0; + (i < ncrtc) && + (crtc_info[i] = XRRGetCrtcInfo(_ecore_x_disp, res, crtcs[i])); + i++) + { + if (((crtc_info[i]->x + dx) < 0) || + ((int)(crtc_info[i]->x + crtc_info[i]->width + dx) > w_max) + || ((crtc_info[i]->y + dy) < 0) || + ((int)(crtc_info[i]->y + crtc_info[i]->height + dy) > h_max) + ) + goto _ecore_x_randr_move_crtcs_fail_free_crtc_info; + + nw = MAX((int)(crtc_info[i]->x + crtc_info[i]->width + dx), nw); + nh = MAX((int)(crtc_info[i]->y + crtc_info[i]->height + dy), nh); + } + //not out of bounds + + //resize if necessary + if (!(((nw > cw) || + (nh > ch)) || + ecore_x_randr_screen_current_size_set(root, nw, nh, + Ecore_X_Randr_Unset, + Ecore_X_Randr_Unset))) + goto _ecore_x_randr_move_crtcs_fail_free_crtc_info; + + //actually move all the crtcs, keep their rotation and mode. + for (i = 0; (i < ncrtc) && crtc_info[i]; i++) + { + if ((crtc_info[i]) && + (!ecore_x_randr_crtc_settings_set(root, crtcs[i], NULL, + Ecore_X_Randr_Unset, + (crtc_info[i]->x + dx), + (crtc_info[i]->y + dy), + crtc_info[i]->mode, + crtc_info[i]->rotation))) + { + ret = EINA_FALSE; + break; + } + } + if (i < ncrtc) + { + //something went wrong, let's try to move the already moved crtcs + //back. + while ((i--) >= 0) + { + if (crtc_info[i]) + ecore_x_randr_crtc_settings_set(root, + crtcs[i], + NULL, + Ecore_X_Randr_Unset, + (crtc_info[i]->x - dx), + (crtc_info[i]->y - dy), + crtc_info[i]->mode, + crtc_info[i]->rotation); + } + } + + for (i = 0; i < ncrtc; i++) + { + if (crtc_info[i]) XRRFreeCrtcInfo(crtc_info[i]); + } + } + + XRRFreeScreenResources(res); + + return ret; +_ecore_x_randr_move_crtcs_fail_free_crtc_info: + while (i-- > 0) + XRRFreeCrtcInfo(crtc_info[i]); + XRRFreeScreenResources(res); + return EINA_FALSE; +#else + return EINA_FALSE; +#endif +} + +/** + * @brief removes unused screen space. The most upper left CRTC is set to 0x0 + * and all other CRTCs dx,dy respectively. + * @param root the window's screen which will be reset. + */ +EAPI void +ecore_x_randr_screen_reset(Ecore_X_Window root) +{ +#ifdef ECORE_XRANDR + XRRCrtcInfo *crtc_info = NULL; + XRRScreenResources *res = NULL; + //the 100000 are just a random huge number. + int i, dx_min = 100000, dy_min = 100000, w_n = 0, h_n = 0, nenabled_crtcs = 0; + + if (!_ecore_x_randr_root_validate(root) || + !(res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root))) + return; + + Ecore_X_Randr_Crtc enabled_crtcs[res->ncrtc]; + + for (i = 0; i < res->ncrtc; i++) + { + if (!(crtc_info = + XRRGetCrtcInfo(_ecore_x_disp, res, + res->crtcs[i])) || + (crtc_info->mode == Ecore_X_Randr_None) || + (crtc_info->mode == Ecore_X_Randr_Unset) + || ((crtc_info->noutput == 0))) + continue; + + enabled_crtcs[nenabled_crtcs++] = res->crtcs[i]; + + if ((int)(crtc_info->x + crtc_info->width) > w_n) + w_n = (crtc_info->x + crtc_info->width); + + if ((int)(crtc_info->y + crtc_info->height) > h_n) + h_n = (crtc_info->y + crtc_info->height); + + if (crtc_info->x < dx_min) + dx_min = crtc_info->x; + if (crtc_info->y < dy_min) + dy_min = crtc_info->y; + + XRRFreeCrtcInfo(crtc_info); + } + if ((dx_min > 0) || (dy_min > 0)) + { + if (ecore_x_randr_move_crtcs(root, enabled_crtcs, nenabled_crtcs, -dx_min, -dy_min)) + { + w_n -= dx_min; + h_n -= dy_min; + } + } + ecore_x_randr_screen_current_size_set(root, + w_n, + h_n, + Ecore_X_Randr_Unset, + Ecore_X_Randr_Unset); +#endif +} + +/** + * @brief Set up the backlight level to the given level. + * + * @param root The window's screen which will be set. + * @param level Of the backlight between @c 0 and @c 1. + */ + +EAPI void +ecore_x_randr_screen_backlight_level_set(Ecore_X_Window root, + double level) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(); + Atom _backlight; + XRRScreenResources *resources = NULL; + Ecore_X_Randr_Output output; + int o; + + if ((level < 0) || (level > 1)) + { + ERR("Wrong value for the backlight level. It should be between 0 and 1."); + return; + } + + /* + * To make sure that the _backlight atomic property still exists. + */ + _backlight = XInternAtom(_ecore_x_disp, RANDR_PROPERTY_BACKLIGHT, True); + if (_backlight == None) + { + WRN("Backlight setting is not supported on this server or driver"); + return; + } + + /* get the ressources */ + resources = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root); + if (!resources) return; + + for (o = 0; o < resources->noutput; o++) + { + output = resources->outputs[o]; + if (ecore_x_randr_output_backlight_level_get(root, output) >= 0) + { + ecore_x_randr_output_backlight_level_set(root, output, level); + } + } + XRRFreeScreenResources(resources); +#endif +} + +/* + * @brief Check if a backlight is available. + * @return Whether a backlight is available. + */ + +EAPI Eina_Bool +ecore_x_randr_output_backlight_available(void) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(-1); + Atom _backlight; + + _backlight = XInternAtom(_ecore_x_disp, RANDR_PROPERTY_BACKLIGHT, True); + + return (_backlight == None) ? EINA_FALSE : EINA_TRUE; + +#endif + return EINA_FALSE; +} + +/* + * @brief Get the backlight level of the given output. + * + * @param root Window which's screen should be queried. + * @param output From which the backlight level should be retrieved. + * @return The backlight level. + */ + +EAPI double +ecore_x_randr_output_backlight_level_get(Ecore_X_Window root, + Ecore_X_Randr_Output output) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(-1); + Atom actual_type; + Atom _backlight; + XRRPropertyInfo *info = NULL; + double dvalue; + int actual_format; + long value, max, min; + unsigned long nitems; + unsigned long bytes_after; + unsigned char *prop = NULL; + + /* set backlight variable if not already done */ + + _backlight = XInternAtom(_ecore_x_disp, RANDR_PROPERTY_BACKLIGHT, True); + if (_backlight == None) + { + ERR("Backlight property is not suppported on this server or driver"); + return -1; + } + + if (!_ecore_x_randr_output_validate(root, output)) + { + ERR("Invalid output"); + return -1; + } + + if (XRRGetOutputProperty(_ecore_x_disp, output, _backlight, + 0, 4, False, False, None, + &actual_type, &actual_format, + &nitems, &bytes_after, &prop) != Success) + { + WRN("Backlight not supported on this output"); + return -1; + } + + if ((actual_type != XA_INTEGER) || (nitems != 1) || (actual_format != 32)) return -1; + + value = *((long *)prop); + free (prop); + + /* I have the current value of the backlight */ + /* Now retrieve the min and max intensities of the output */ + info = XRRQueryOutputProperty(_ecore_x_disp, output, _backlight); + if (info) + { + dvalue = -1; + if ((info->range) && (info->num_values == 2)) + { + /* finally convert the current value in the interval [0..1] */ + min = info->values[0]; + max = info->values[1]; + dvalue = ((double)(value - min)) / ((double)(max - min)); + } + free(info); + return dvalue; + } +#endif + return -1; +} + +/* + * @brief Set the backlight level of a given output. + * + * @param root Window which's screen should be queried. + * @param output That should be set. + * @param level For which the backlight should be set. + * @return @c EINA_TRUE in case of success. + */ + +EAPI Eina_Bool +ecore_x_randr_output_backlight_level_set(Ecore_X_Window root, + Ecore_X_Randr_Output output, + double level) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_2_RET(EINA_FALSE); + Atom _backlight; + XRRPropertyInfo *info = NULL; + double min, max, tmp; + long new; + + if ((level < 0) || (level > 1)) + { + ERR("Backlight level should be between 0 and 1"); + return EINA_FALSE; + } + + if (!_ecore_x_randr_output_validate(root, output)) + { + ERR("Wrong output value"); + return EINA_FALSE; + } + + _backlight = XInternAtom(_ecore_x_disp, RANDR_PROPERTY_BACKLIGHT, True); + if (_backlight == None) + { + WRN("Backlight property is not suppported on this server or driver"); + return EINA_FALSE; + } + + info = XRRQueryOutputProperty(_ecore_x_disp, output, _backlight); + if (info) + { + if ((info->range) && (info->num_values == 2)) + { + min = info->values[0]; + max = info->values[1]; + tmp = (level * (max - min)) + min; + new = tmp; + if (new > max) new = max; + if (new < min) new = min; + XRRChangeOutputProperty(_ecore_x_disp, output, _backlight, XA_INTEGER, 32, + PropModeReplace, (unsigned char *)&new, 1); + XFlush(_ecore_x_disp); + } + free(info); + return EINA_TRUE; + } +#endif + return EINA_FALSE; +} + +/* + * @brief Get the outputs, which display a certain window. + * + * @param window Window the displaying outputs shall be found for + * @param num The number of outputs displaying the window + * @return Array of outputs that display a certain window. @c NULL if no + * outputs was found that displays the specified window. + */ + +EAPI Ecore_X_Randr_Output * +ecore_x_randr_window_outputs_get(Ecore_X_Window window, + int *num) +{ +#ifdef ECORE_XRANDR + Ecore_X_Window root; + Ecore_X_Randr_Crtc *crtcs; + Ecore_X_Randr_Output *outputs, *ret = NULL, *tret; + int ncrtcs, noutputs, i, nret = 0; + + if (_randr_version < RANDR_1_2) goto _ecore_x_randr_current_output_get_fail; + + root = ecore_x_window_root_get(window); + if (!(crtcs = ecore_x_randr_window_crtcs_get(window, &ncrtcs))) + goto _ecore_x_randr_current_output_get_fail; + + for (i = 0, nret = 0; i < ncrtcs; i++) + { + + outputs = ecore_x_randr_crtc_outputs_get(root, crtcs[i], + &noutputs); + if (!outputs) + goto _ecore_x_randr_current_output_get_fail_free; + tret = realloc(ret, ((nret + noutputs) * sizeof(Ecore_X_Randr_Output))); + if (!tret) goto _ecore_x_randr_current_output_get_fail_free; + ret = tret; + memcpy(&ret[nret], outputs, (noutputs * sizeof(Ecore_X_Randr_Output))); + nret += noutputs; + free(outputs); + outputs = NULL; + } + free(crtcs); + + if (num) + *num = nret; + + return ret; + +_ecore_x_randr_current_output_get_fail_free: + free(outputs); + free(crtcs); + free(ret); +_ecore_x_randr_current_output_get_fail: +#endif + if (num) *num = 0; + return NULL; +} + +/* + * @deprecated bad naming. Use ecore_x_randr_window_outputs_get instead. + * @brief Get the outputs, which display a certain window. + * + * @param window Window the displaying outputs shall be found for. + * @param num The number of outputs displaying the window. + * @return Array of outputs that display a certain window. @c NULL if no + * outputs was found that displays the specified window. + */ + +EAPI Ecore_X_Randr_Output * +ecore_x_randr_current_output_get(Ecore_X_Window window, + int *num) +{ + return ecore_x_randr_window_outputs_get(window, num); +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_randr_12_edid.c b/src/lib/ecore_x/xlib/ecore_x_randr_12_edid.c new file mode 100644 index 0000000..5bda332 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_randr_12_edid.c @@ -0,0 +1,463 @@ +/* + * Copyright 2006-2009 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +/* Original Author: Adam Jackson */ +/* Heavily modified by: Leif Middelschulte */ + +#include "Ecore_X.h" +#include +#include +#include +#include + +/* TODO: + * - see other TODO's within this file. + */ + +#define ECORE_X_RANDR_EDID_VERSION_10 ((1 << 8) | 0) +#define ECORE_X_RANDR_EDID_VERSION_11 ((1 << 8) | 1) +#define ECORE_X_RANDR_EDID_VERSION_12 ((1 << 8) | 2) +#define ECORE_X_RANDR_EDID_VERSION_13 ((1 << 8) | 3) +#define ECORE_X_RANDR_EDID_VERSION_14 ((1 << 8) | 4) + +#define _ECORE_X_RANDR_EDID_OFFSET_MANUFACTURER 0x08 +#define _ECORE_X_RANDR_EDID_OFFSET_TYPE 0x14 +#define _ECORE_X_RANDR_EDID_OFFSET_VERSION_MAJOR 0x12 +#define _ECORE_X_RANDR_EDID_OFFSET_VERSION_MINOR 0x13 +#define _ECORE_X_RANDR_EDID_OFFSET_DPMS 0x18 +#define _ECORE_X_RANDR_EDID_OFFSET_COLORSPACE 0x18 +#define _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK 0x36 +#define _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE 3 +#define _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_CONTENT 5 +#define _ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO_PREFERRED 15 +#define _ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO 14 + +#define _ECORE_X_RANDR_EDID_MASK_DIGITAL 0x80 +#define _ECORE_X_RANDR_EDID_MASK_DIGITAL_INTERFACE 0x0f +#define _ECORE_X_RANDR_EDID_MASK_DIGITAL_TMDS_DFP_10 0x01 +#define _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_ANALOGOUS 0x18 +#define _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_DIGITAL_YCRCB_444 0x10 +#define _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_DIGITAL_YCRCB_422 0x08 +#define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_PREFERRED 0xe0 +#define _ECORE_X_RANDR_EDID_MASK_DPMS 0xE0 +#define _ECORE_X_RANDR_EDID_MASK_DPMS_STANDBY 0x80 +#define _ECORE_X_RANDR_EDID_MASK_DPMS_SUSPEND 0x40 +#define _ECORE_X_RANDR_EDID_MASK_DPMS_OFF 0x20 +#define _ECORE_X_RANDR_EDID_MASK_INTERFACE_TYPE 0x0f +#define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_4_3 0x80 +#define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_16_9 0x40 +#define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_16_10 0x20 +#define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_5_4 0x10 +#define _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_15_9 0x08 + +#define _ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX 13 + +typedef enum _Ecore_X_Randr_Edid_Aspect_Ratio_Preferred { + ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_4_3 = 0x00, + ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_16_9 = 0x01, + ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_16_10 = 0x02, + ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_5_4 = 0x03, + ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_15_9 = 0x04 +} Ecore_X_Randr_Edid_Aspect_Ratio_Preferred; + +/* Some convenience loops */ +#define _ECORE_X_RANDR_EDID_FOR_EACH_EXTENSION_BLOCK(edid, edid_length, extension_block_iter) \ + for (extension_block_iter = edid; extension_block_iter < (edid + edid_length); extension_block_iter += 128) + +#define _ECORE_X_RANDR_EDID_FOR_EACH_CEA_BLOCK(edid, edid_length, cea_block_iter) \ + _ECORE_X_RANDR_EDID_FOR_EACH_EXTENSION_BLOCK(edid, edid_length, cea_block_iter) \ + if (cea_block_iter[0] == 0x02) + +/* The following macro is to be used with caution as it inherits another loop. + * Therefore using a 'break;' statement will lead to continuation in the + * inherent 'Extension block'-loop. + */ +#define _ECORE_X_RANDR_EDID_FOR_EACH_CEA_DETAILED_BLOCK(edid, edid_length, cea_block_iter, detailed_block_iter) \ + _ECORE_X_RANDR_EDID_FOR_EACH_CEA_BLOCK(edid, edid_length, cea_block_iter) \ + for (detailed_block_iter = cea_block_iter + cea_block_iter[2]; detailed_block_iter + 18 < cea_block_iter + 127; detailed_block_iter += 18) \ + if (detailed_block_iter[0]) + +#define _ECORE_X_RANDR_EDID_FOR_EACH_DESCRIPTOR_BLOCK(edid, block) \ + for (block = edid + _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK; block <= (edid + _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK + (3 * 18)); block += 18) + +#define _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block) \ + _ECORE_X_RANDR_EDID_FOR_EACH_DESCRIPTOR_BLOCK(edid, block) \ + if ((block[0] == 0) && (block[1] == 0)) + +EAPI Eina_Bool +ecore_x_randr_edid_has_valid_header(unsigned char *edid, + unsigned long edid_length) +{ + const unsigned char header[] = + { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; + if (!edid) return EINA_FALSE; + if (edid_length < 8) return EINA_FALSE; + if (!memcmp(edid, header, 8)) return EINA_TRUE; + return EINA_FALSE; +} + +EAPI int +ecore_x_randr_edid_version_get(unsigned char *edid, + unsigned long edid_length) +{ + if ((edid_length > _ECORE_X_RANDR_EDID_OFFSET_VERSION_MINOR) && + (ecore_x_randr_edid_has_valid_header(edid, edid_length))) + return (edid[_ECORE_X_RANDR_EDID_OFFSET_VERSION_MAJOR] << 8) | + edid[_ECORE_X_RANDR_EDID_OFFSET_VERSION_MINOR]; + return ECORE_X_RANDR_EDID_UNKNOWN_VALUE; +} + +EAPI int +ecore_x_randr_edid_manufacturer_model_get(unsigned char *edid, + unsigned long edid_length) +{ + if ((edid_length > 0x0b) && + (ecore_x_randr_edid_has_valid_header(edid, edid_length))) + return (int)(edid[0x0a] + (edid[0x0b] << 8)); + return ECORE_X_RANDR_EDID_UNKNOWN_VALUE; +} + +EAPI int +ecore_x_randr_edid_manufacturer_serial_number_get(unsigned char *edid, + unsigned long edid_length) +{ + if ((edid_length > 0x0f) && + (ecore_x_randr_edid_has_valid_header(edid, edid_length))) + return (int)(edid[0x0c] + (edid[0x0d] << 8) + + (edid[0x0e] << 16) + (edid[0x0f] << 24)); + return ECORE_X_RANDR_EDID_UNKNOWN_VALUE; +} + +EAPI char * +ecore_x_randr_edid_manufacturer_name_get(unsigned char *edid, + unsigned long edid_length) +{ + if ((edid_length > (_ECORE_X_RANDR_EDID_OFFSET_MANUFACTURER + 1)) && + (ecore_x_randr_edid_has_valid_header(edid, edid_length))) + { + unsigned char *x; + char *name; + + x = (edid + _ECORE_X_RANDR_EDID_OFFSET_MANUFACTURER); + name = malloc(sizeof(char) * 4); + if (!name) return NULL; + name[0] = ((x[0] & 0x7c) >> 2) + '@'; + name[1] = ((x[0] & 0x03) << 3) + ((x[1] & 0xe0) >> 5) + '@'; + name[2] = (x[1] & 0x1f) + '@'; + name[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] = 0; + return name; + } + return NULL; +} + +EAPI char * +ecore_x_randr_edid_display_name_get(unsigned char *edid, + unsigned long edid_length) +{ + unsigned char *block = NULL; + int version = ecore_x_randr_edid_version_get(edid, edid_length); + + if (version < ECORE_X_RANDR_EDID_VERSION_13) return NULL; + _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block) + { + if (block[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] == 0xfc) + { + char *name, *p; + const char *edid_name; + + edid_name = (const char *)block + _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_CONTENT; + name = malloc(sizeof(char) * _ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX); + if (!name) return NULL; + strncpy(name, edid_name, (_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX - 1)); + name[_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX] = 0; + for (p = name; *p; p++) + { + if ((*p < ' ') || (*p > '~')) *p = 0; + } + return name; + } + } + return NULL; +} + +EAPI Ecore_X_Randr_Edid_Aspect_Ratio +ecore_x_randr_edid_display_aspect_ratio_preferred_get(unsigned char *edid, + unsigned long edid_length) +{ + unsigned char *block = NULL; + int version = ecore_x_randr_edid_version_get(edid, edid_length); + + if (version < ECORE_X_RANDR_EDID_VERSION_13) return ECORE_X_RANDR_EDID_UNKNOWN_VALUE; + _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block) + { + if ((block[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] == 0xfd) && + (block[10] == 0x04)) + { + Ecore_X_Randr_Edid_Aspect_Ratio_Preferred preferred_ratio = + (Ecore_X_Randr_Edid_Aspect_Ratio_Preferred) + ((block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO_PREFERRED] & + _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_PREFERRED) >> 5); + switch (preferred_ratio) + { + case ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_4_3: + return ECORE_X_RANDR_EDID_ASPECT_RATIO_4_3; + + case ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_16_9: + return ECORE_X_RANDR_EDID_ASPECT_RATIO_16_9; + + case ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_16_10: + return ECORE_X_RANDR_EDID_ASPECT_RATIO_16_10; + + case ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_5_4: + return ECORE_X_RANDR_EDID_ASPECT_RATIO_5_4; + + case ECORE_X_RANDR_EDID_ASPECT_RATIO_PREFERRED_15_9: + return ECORE_X_RANDR_EDID_ASPECT_RATIO_15_9; + + default: + return ECORE_X_RANDR_EDID_UNKNOWN_VALUE; + } + } + } + return ECORE_X_RANDR_EDID_UNKNOWN_VALUE; +} + +EAPI Ecore_X_Randr_Edid_Aspect_Ratio +ecore_x_randr_edid_display_aspect_ratios_get(unsigned char *edid, + unsigned long edid_length) +{ + Ecore_X_Randr_Edid_Aspect_Ratio ret = ECORE_X_RANDR_EDID_UNKNOWN_VALUE; + unsigned char *block = NULL; + int version = ecore_x_randr_edid_version_get(edid, edid_length); + + if (version < ECORE_X_RANDR_EDID_VERSION_13) return ECORE_X_RANDR_EDID_UNKNOWN_VALUE; + _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block) + { + if ((block[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] == 0xfd) && + (block[10] == 0x04)) + { + if (block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO] & _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_4_3) + ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_4_3; + if (block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO] & _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_16_9) + ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_16_9; + if (block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO] & _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_16_10) + ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_16_10; + if (block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO] & _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_5_4) + ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_5_4; + if (block[_ECORE_X_RANDR_EDID_OFFSET_ASPECT_RATIO] & _ECORE_X_RANDR_EDID_MASK_ASPECT_RATIO_15_9) + ret |= ECORE_X_RANDR_EDID_ASPECT_RATIO_15_9; + } + } + return ret; +} + +EAPI char * +ecore_x_randr_edid_display_ascii_get(unsigned char *edid, + unsigned long edid_length) +{ + unsigned char *block = NULL; + int version = ecore_x_randr_edid_version_get(edid, edid_length); + + if (version < ECORE_X_RANDR_EDID_VERSION_13) return NULL; + _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block) + { + if (block[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] == 0xfe) + { + char *ascii, *p; + const char *edid_ascii = (const char *)block + + _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_CONTENT; + /* + * TODO: Two of these in a row, in the third and fourth slots, + * seems to be specified by SPWG: http://www.spwg.org/ + */ + ascii = malloc(sizeof(char) * _ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX); + if (!ascii) return NULL; + strncpy(ascii, edid_ascii, (_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX - 1)); + ascii[_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX] = 0; + for (p = ascii; *p; p++) + { + if ((*p < ' ') || (*p > '~')) *p = 0; + } + return ascii; + } + } + return NULL; +} + +EAPI char * +ecore_x_randr_edid_display_serial_get(unsigned char *edid, + unsigned long edid_length) +{ + unsigned char *block = NULL; + int version = ecore_x_randr_edid_version_get(edid, edid_length); + + if (version < ECORE_X_RANDR_EDID_VERSION_13) return NULL; + _ECORE_X_RANDR_EDID_FOR_EACH_NON_PIXEL_DESCRIPTOR_BLOCK(edid, block) + { + if (block[_ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_TYPE] == 0xff) + { + char *serial, *p; + const char *edid_serial = (const char *)block + + _ECORE_X_RANDR_EDID_OFFSET_DESCRIPTOR_BLOCK_CONTENT; + /* + * TODO: Two of these in a row, in the third and fourth slots, + * seems to be specified by SPWG: http://www.spwg.org/ + */ + serial = malloc(sizeof(char) * _ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX); + if (!serial) return NULL; + strncpy(serial, edid_serial, (_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX - 1)); + serial[_ECORE_X_RANDR_EDID_DISPLAY_DESCRIPTOR_BLOCK_CONTENT_LENGTH_MAX] = 0; + for (p = serial; *p; p++) + { + if ((*p < ' ') || (*p > '~')) *p = 0; + } + return serial; + } + } + return NULL; +} + +EAPI Eina_Bool +ecore_x_randr_edid_info_has_valid_checksum(unsigned char *edid, + unsigned long edid_length) +{ + unsigned char *cea_block_iter = NULL; + char sum = 0; + int i; + int version = ecore_x_randr_edid_version_get(edid, edid_length); + + if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE; + if (edid_length < 128) return EINA_FALSE; + + /* Check the EDID block itself */ + for (i = 0; i < 128; i++) + sum += edid[i]; + if (sum) return EINA_FALSE; + + /* Check the cea extension blocks */ + _ECORE_X_RANDR_EDID_FOR_EACH_CEA_BLOCK(edid, edid_length, cea_block_iter) + { + for (i = 0, sum = 0; i < 128; i++) + sum += cea_block_iter[i]; + } + if (sum) return EINA_FALSE; + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_x_randr_edid_dpms_available_get(unsigned char *edid, + unsigned long edid_length) +{ + int version = ecore_x_randr_edid_version_get(edid, edid_length); + + if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE; + return !!(edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] & + _ECORE_X_RANDR_EDID_MASK_DPMS); +} + +EAPI Eina_Bool +ecore_x_randr_edid_dpms_standby_available_get(unsigned char *edid, + unsigned long edid_length) +{ + int version = ecore_x_randr_edid_version_get(edid, edid_length); + + if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE; + if (edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] & _ECORE_X_RANDR_EDID_MASK_DPMS) + return !!(edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] & + _ECORE_X_RANDR_EDID_MASK_DPMS_STANDBY); + return EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_randr_edid_dpms_suspend_available_get(unsigned char *edid, + unsigned long edid_length) +{ + int version = ecore_x_randr_edid_version_get(edid, edid_length); + + if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE; + if (edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] & _ECORE_X_RANDR_EDID_MASK_DPMS) + return !!(edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] & + _ECORE_X_RANDR_EDID_MASK_DPMS_SUSPEND); + return EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_randr_edid_dpms_off_available_get(unsigned char *edid, + unsigned long edid_length) +{ + int version = ecore_x_randr_edid_version_get(edid, edid_length); + + if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE; + if (edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] & _ECORE_X_RANDR_EDID_MASK_DPMS) + return !!(edid[_ECORE_X_RANDR_EDID_OFFSET_DPMS] & + _ECORE_X_RANDR_EDID_MASK_DPMS_OFF); + return EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_randr_edid_display_type_digital_get(unsigned char *edid, + unsigned long edid_length) +{ + int version = ecore_x_randr_edid_version_get(edid, edid_length); + + if (version < ECORE_X_RANDR_EDID_VERSION_13) return EINA_FALSE; + return !!(edid[_ECORE_X_RANDR_EDID_OFFSET_TYPE] & + _ECORE_X_RANDR_EDID_MASK_DIGITAL); +} + +EAPI Ecore_X_Randr_Edid_Display_Colorscheme +ecore_x_randr_edid_display_colorscheme_get(unsigned char *edid, + unsigned long edid_length) +{ + Ecore_X_Randr_Edid_Display_Colorscheme colorscheme = ECORE_X_RANDR_EDID_UNKNOWN_VALUE; + int version = ecore_x_randr_edid_version_get(edid, edid_length); + + if (version < ECORE_X_RANDR_EDID_VERSION_13) return colorscheme; + if (ecore_x_randr_edid_display_type_digital_get(edid, edid_length)) + { + colorscheme = ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_4_4_4; + if (edid[_ECORE_X_RANDR_EDID_OFFSET_COLORSPACE] & + _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_DIGITAL_YCRCB_444) + colorscheme |= ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_YCRCB_4_4_4; + if (edid[_ECORE_X_RANDR_EDID_OFFSET_COLORSPACE] & + _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_DIGITAL_YCRCB_422) + colorscheme |= ECORE_X_RANDR_EDID_DISPLAY_COLORSCHEME_COLOR_RGB_YCRCB_4_2_2; + } + else + colorscheme = edid[_ECORE_X_RANDR_EDID_OFFSET_COLORSPACE] & _ECORE_X_RANDR_EDID_MASK_COLORSCHEME_ANALOGOUS; + return colorscheme; +} + +EAPI Ecore_X_Randr_Edid_Display_Interface_Type +ecore_x_randr_edid_display_interface_type_get(unsigned char *edid, + unsigned long edid_length) +{ + Ecore_X_Randr_Edid_Display_Interface_Type type = ECORE_X_RANDR_EDID_UNKNOWN_VALUE; + int version = ecore_x_randr_edid_version_get(edid, edid_length); + + if (version < ECORE_X_RANDR_EDID_VERSION_13) return type; + type = edid[_ECORE_X_RANDR_EDID_OFFSET_TYPE] & + _ECORE_X_RANDR_EDID_MASK_INTERFACE_TYPE; + if (type > ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_DISPLAY_PORT) + type = ECORE_X_RANDR_EDID_UNKNOWN_VALUE; + return type; +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_randr_13.c b/src/lib/ecore_x/xlib/ecore_x_randr_13.c new file mode 100644 index 0000000..5d1c8e9 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_randr_13.c @@ -0,0 +1,68 @@ +/* + * vim:ts=8:sw=3:sts=8:expandtab:cino=>5n-3f0^-2{2 + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "ecore_x_private.h" +#include "ecore_x_randr.h" +#include +#include +#include +#include + +#define Ecore_X_Randr_None 0 +#define Ecore_X_Randr_Unset -1 + +#ifdef ECORE_XRANDR + +#define RANDR_1_3 ((1 << 16) | 3) +#define RANDR_CHECK_1_3_RET(ret) if (_randr_version < RANDR_1_3) \ + return ret + +extern XRRScreenResources *(*_ecore_x_randr_get_screen_resources)(Display * + dpy, + Window + window); +extern int _randr_version; +#endif + +/* + * @param root window which's screen should be queried + * @return Ecore_X_Randr_Ouptut_Id or - if query failed or none is set - Ecore_X_Randr_None + */ +EAPI Ecore_X_Randr_Output +ecore_x_randr_primary_output_get(Ecore_X_Window root) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_3_RET(Ecore_X_Randr_None); + if (!_ecore_x_randr_root_validate(root)) + return Ecore_X_Randr_None; + + return XRRGetOutputPrimary(_ecore_x_disp, root); +#else + return Ecore_X_Randr_None; +#endif +} + +/* + * @param root window which's screen should be queried + * @param output that should be set as given root window's screen primary output + */ +EAPI void +ecore_x_randr_primary_output_set(Ecore_X_Window root, + Ecore_X_Randr_Output output) +{ +#ifdef ECORE_XRANDR + RANDR_CHECK_1_3_RET(); + + if (_ecore_x_randr_output_validate(root, output)) + { + XRRSetOutputPrimary(_ecore_x_disp, root, output); + } + +#endif +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_region.c b/src/lib/ecore_x/xlib/ecore_x_region.c new file mode 100644 index 0000000..81d7eea --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_region.c @@ -0,0 +1,158 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include "ecore_x_private.h" + +/* + * [x] XCreateRegion + * [ ] XPolygonRegion + * [x] XSetRegion + * [x] XDestroyRegion + * + * [x] XOffsetRegion + * [ ] XShrinkRegion + * + * [ ] XClipBox + * [x] XIntersectRegion + * [x] XUnionRegion + * [x] XUnionRectWithRegion + * [x] XSubtractRegion + * [ ] XXorRegion + * + * [x] XEmptyRegion + * [x] XEqualRegion + * + * [x] XPointInRegion + * [x] XRectInRegion + */ + +EAPI Ecore_X_XRegion * +ecore_x_xregion_new() +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return (Ecore_X_XRegion *)XCreateRegion(); +} + +EAPI void +ecore_x_xregion_free(Ecore_X_XRegion *region) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!region) + return; + + XDestroyRegion((Region)region); +} + +EAPI Eina_Bool +ecore_x_xregion_set(Ecore_X_XRegion *region, + Ecore_X_GC gc) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return XSetRegion(_ecore_x_disp, gc, (Region)region) ? EINA_TRUE : EINA_FALSE; +} + +EAPI void +ecore_x_xregion_translate(Ecore_X_XRegion *region, + int x, + int y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!region) + return; + + /* return value not used */ + XOffsetRegion((Region)region, x, y); +} + +EAPI Eina_Bool +ecore_x_xregion_intersect(Ecore_X_XRegion *dst, + Ecore_X_XRegion *r1, + Ecore_X_XRegion *r2) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return XIntersectRegion((Region)r1, (Region)r2, (Region)dst) ? EINA_TRUE : EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_xregion_union(Ecore_X_XRegion *dst, + Ecore_X_XRegion *r1, + Ecore_X_XRegion *r2) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return XUnionRegion((Region)r1, (Region)r2, (Region)dst) ? EINA_TRUE : EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_xregion_union_rect(Ecore_X_XRegion *dst, + Ecore_X_XRegion *src, + Ecore_X_Rectangle *rect) +{ + XRectangle xr; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + xr.x = rect->x; + xr.y = rect->y; + xr.width = rect->width; + xr.height = rect->height; + + return XUnionRectWithRegion(&xr, (Region)src, (Region)dst) ? EINA_TRUE : EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_xregion_subtract(Ecore_X_XRegion *dst, + Ecore_X_XRegion *rm, + Ecore_X_XRegion *rs) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return XSubtractRegion((Region)rm, (Region)rs, (Region)dst) ? EINA_TRUE : EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_xregion_is_empty(Ecore_X_XRegion *region) +{ + if (!region) + return EINA_TRUE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return XEmptyRegion((Region)region) ? EINA_TRUE : EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_xregion_is_equal(Ecore_X_XRegion *r1, + Ecore_X_XRegion *r2) +{ + if (!r1 || !r2) + return EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return XEqualRegion((Region)r1, (Region)r1) ? EINA_TRUE : EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_xregion_point_contain(Ecore_X_XRegion *region, + int x, + int y) +{ + if (!region) + return EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return XPointInRegion((Region)region, x, y) ? EINA_TRUE : EINA_FALSE; +} + +EAPI Eina_Bool +ecore_x_xregion_rect_contain(Ecore_X_XRegion *region, + Ecore_X_Rectangle *rect) +{ + if (!region || !rect) + return EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return XRectInRegion((Region)region, + rect->x, + rect->y, + rect->width, + rect->height) ? EINA_TRUE : EINA_FALSE; +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_screensaver.c b/src/lib/ecore_x/xlib/ecore_x_screensaver.c new file mode 100644 index 0000000..3688a44 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_screensaver.c @@ -0,0 +1,204 @@ +/* + * Screensaver code + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include "Ecore.h" +#include "ecore_x_private.h" +#include "Ecore_X.h" +#include "Ecore_X_Atoms.h" + +static int _screensaver_available = -1; + +EAPI Eina_Bool +ecore_x_screensaver_event_available_get(void) +{ + if (_screensaver_available >= 0) + return _screensaver_available; + +#ifdef ECORE_XSS + int _screensaver_major, _screensaver_minor; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _screensaver_major = 1; + _screensaver_minor = 0; + + if (XScreenSaverQueryVersion(_ecore_x_disp, &_screensaver_major, + &_screensaver_minor)) + _screensaver_available = 1; + else + _screensaver_available = 0; + +#else /* ifdef ECORE_XSS */ + _screensaver_available = 0; +#endif /* ifdef ECORE_XSS */ + return _screensaver_available; +} + +EAPI int +ecore_x_screensaver_idle_time_get(void) +{ +#ifdef ECORE_XSS + XScreenSaverInfo *xss; + int idle; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + xss = XScreenSaverAllocInfo(); + XScreenSaverQueryInfo(_ecore_x_disp, + RootWindow(_ecore_x_disp, DefaultScreen( + _ecore_x_disp)), xss); + idle = xss->idle / 1000; + XFree(xss); + + return idle; +#else + return 0; +#endif /* ifdef ECORE_XSS */ +} + +EAPI void +ecore_x_screensaver_set(int timeout, + int interval, + int prefer_blanking, + int allow_exposures) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XSetScreenSaver(_ecore_x_disp, + timeout, + interval, + prefer_blanking, + allow_exposures); +} + +EAPI void +ecore_x_screensaver_timeout_set(int timeout) +{ + int pto, pint, pblank, pexpo; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XGetScreenSaver(_ecore_x_disp, &pto, &pint, &pblank, &pexpo); + XSetScreenSaver(_ecore_x_disp, timeout, pint, pblank, pexpo); +} + +EAPI int +ecore_x_screensaver_timeout_get(void) +{ + int pto, pint, pblank, pexpo; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XGetScreenSaver(_ecore_x_disp, &pto, &pint, &pblank, &pexpo); + return pto; +} + +EAPI void +ecore_x_screensaver_blank_set(int blank) +{ + int pto, pint, pblank, pexpo; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XGetScreenSaver(_ecore_x_disp, &pto, &pint, &pblank, &pexpo); + XSetScreenSaver(_ecore_x_disp, pto, pint, blank, pexpo); +} + +EAPI int +ecore_x_screensaver_blank_get(void) +{ + int pto, pint, pblank, pexpo; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XGetScreenSaver(_ecore_x_disp, &pto, &pint, &pblank, &pexpo); + return pblank; +} + +EAPI void +ecore_x_screensaver_expose_set(int expose) +{ + int pto, pint, pblank, pexpo; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XGetScreenSaver(_ecore_x_disp, &pto, &pint, &pblank, &pexpo); + XSetScreenSaver(_ecore_x_disp, pto, pint, pblank, expose); +} + +EAPI int +ecore_x_screensaver_expose_get(void) +{ + int pto, pint, pblank, pexpo; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XGetScreenSaver(_ecore_x_disp, &pto, &pint, &pblank, &pexpo); + return pexpo; +} + +EAPI void +ecore_x_screensaver_interval_set(int interval) +{ + int pto, pint, pblank, pexpo; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XGetScreenSaver(_ecore_x_disp, &pto, &pint, &pblank, &pexpo); + XSetScreenSaver(_ecore_x_disp, pto, interval, pblank, pexpo); +} + +EAPI int +ecore_x_screensaver_interval_get(void) +{ + int pto, pint, pblank, pexpo; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XGetScreenSaver(_ecore_x_disp, &pto, &pint, &pblank, &pexpo); + return pint; +} + +EAPI void +ecore_x_screensaver_event_listen_set(Eina_Bool on) +{ +#ifdef ECORE_XSS + Ecore_X_Window root; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + root = DefaultRootWindow(_ecore_x_disp); + if (on) + XScreenSaverSelectInput(_ecore_x_disp, root, + ScreenSaverNotifyMask | ScreenSaverCycle); + else + XScreenSaverSelectInput(_ecore_x_disp, root, 0); +#else + return; + on = EINA_FALSE; +#endif /* ifdef ECORE_XSS */ +} + + +EAPI Eina_Bool +ecore_x_screensaver_custom_blanking_enable(void) +{ +#ifdef ECORE_XSS + XSetWindowAttributes attr; + + XScreenSaverSetAttributes(_ecore_x_disp, + DefaultRootWindow(_ecore_x_disp), + -9999, -9999, 1, 1, 0, + CopyFromParent, InputOnly, CopyFromParent, + 0, &attr); + return EINA_TRUE; +#else + return EINA_FALSE; +#endif /* ifdef ECORE_XSS */ +} + +EAPI Eina_Bool +ecore_x_screensaver_custom_blanking_disable(void) +{ +#ifdef ECORE_XSS + XScreenSaverUnsetAttributes(_ecore_x_disp, + DefaultRootWindow(_ecore_x_disp)); + return EINA_TRUE; +#else + return EINA_FALSE; +#endif /* ifdef ECORE_XSS */ +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_selection.c b/src/lib/ecore_x/xlib/ecore_x_selection.c new file mode 100644 index 0000000..fa177c3 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_selection.c @@ -0,0 +1,1002 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include +#include + +#include "Ecore.h" +#include "ecore_private.h" +#include "ecore_x_private.h" +#include "Ecore_X.h" +#include "Ecore_X_Atoms.h" + +static Ecore_X_Selection_Intern selections[4]; +static Ecore_X_Selection_Converter *converters = NULL; +static Ecore_X_Selection_Parser *parsers = NULL; + +static Eina_Bool _ecore_x_selection_converter_text(char *target, + void *data, + int size, + void **data_ret, + int *size_ret, + Ecore_X_Atom *tprop, + int *); +static int _ecore_x_selection_data_default_free(void *data); +static void *_ecore_x_selection_parser_files(const char *target, + void *data, + int size, + int format); +static int _ecore_x_selection_data_files_free(void *data); +static void *_ecore_x_selection_parser_text(const char *target, + void *data, + int size, + int format); +static int _ecore_x_selection_data_text_free(void *data); +static void *_ecore_x_selection_parser_targets(const char *target, + void *data, + int size, + int format); +static int _ecore_x_selection_data_targets_free(void *data); + +#define ECORE_X_SELECTION_DATA(x) ((Ecore_X_Selection_Data *)(x)) + +void +_ecore_x_selection_data_init(void) +{ + /* Initialize global data */ + memset(selections, 0, sizeof(selections)); + + /* Initialize converters */ + ecore_x_selection_converter_atom_add(ECORE_X_ATOM_TEXT, + _ecore_x_selection_converter_text); +#ifdef X_HAVE_UTF8_STRING + ecore_x_selection_converter_atom_add(ECORE_X_ATOM_UTF8_STRING, + _ecore_x_selection_converter_text); +#endif /* ifdef X_HAVE_UTF8_STRING */ + ecore_x_selection_converter_atom_add(ECORE_X_ATOM_COMPOUND_TEXT, + _ecore_x_selection_converter_text); + ecore_x_selection_converter_atom_add(ECORE_X_ATOM_STRING, + _ecore_x_selection_converter_text); + + /* Initialize parsers */ + ecore_x_selection_parser_add("text/plain", + _ecore_x_selection_parser_text); + ecore_x_selection_parser_add(ECORE_X_SELECTION_TARGET_UTF8_STRING, + _ecore_x_selection_parser_text); + ecore_x_selection_parser_add("text/uri-list", + _ecore_x_selection_parser_files); + ecore_x_selection_parser_add("_NETSCAPE_URL", + _ecore_x_selection_parser_files); + ecore_x_selection_parser_add(ECORE_X_SELECTION_TARGET_TARGETS, + _ecore_x_selection_parser_targets); +} + +void +_ecore_x_selection_shutdown(void) +{ + Ecore_X_Selection_Converter *cnv; + Ecore_X_Selection_Parser *prs; + + /* free the selection converters */ + cnv = converters; + while (cnv) + { + Ecore_X_Selection_Converter *tmp; + + tmp = cnv->next; + free(cnv); + cnv = tmp; + } + converters = NULL; + + /* free the selection parsers */ + prs = parsers; + while (prs) + { + Ecore_X_Selection_Parser *tmp; + + tmp = prs; + prs = prs->next; + free(tmp->target); + free(tmp); + } + parsers = NULL; +} + +Ecore_X_Selection_Intern * +_ecore_x_selection_get(Ecore_X_Atom selection) +{ + if (selection == ECORE_X_ATOM_SELECTION_PRIMARY) + return &selections[0]; + else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY) + return &selections[1]; + else if (selection == ECORE_X_ATOM_SELECTION_XDND) + return &selections[2]; + else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD) + return &selections[3]; + else + return NULL; +} + +Eina_Bool +_ecore_x_selection_set(Window w, + const void *data, + int size, + Ecore_X_Atom selection) +{ + int in; + unsigned char *buf = NULL; + + XSetSelectionOwner(_ecore_x_disp, selection, w, _ecore_x_event_last_time); + if (XGetSelectionOwner(_ecore_x_disp, selection) != w) + return EINA_FALSE; + + if (selection == ECORE_X_ATOM_SELECTION_PRIMARY) + in = 0; + else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY) + in = 1; + else if (selection == ECORE_X_ATOM_SELECTION_XDND) + in = 2; + else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD) + in = 3; + else + return EINA_FALSE; + + if (data) + { + selections[in].win = w; + selections[in].selection = selection; + selections[in].length = size; + selections[in].time = _ecore_x_event_last_time; + + buf = malloc(size); + if (!buf) return EINA_FALSE; + memcpy(buf, data, size); + selections[in].data = buf; + } + else if (selections[in].data) + { + free(selections[in].data); + memset(&selections[in], 0, sizeof(Ecore_X_Selection_Data)); + } + + return EINA_TRUE; +} + +/** + * Claim ownership of the PRIMARY selection and set its data. + * @param w The window to which this selection belongs + * @param data The data associated with the selection + * @param size The size of the data buffer in bytes + * @return Returns 1 if the ownership of the selection was successfully + * claimed, or 0 if unsuccessful. + */ +EAPI Eina_Bool +ecore_x_selection_primary_set(Ecore_X_Window w, + const void *data, + int size) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return _ecore_x_selection_set(w, data, size, ECORE_X_ATOM_SELECTION_PRIMARY); +} + +/** + * Release ownership of the primary selection + * @return Returns 1 if the selection was successfully cleared, + * or 0 if unsuccessful. + * + */ +EAPI Eina_Bool +ecore_x_selection_primary_clear(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return _ecore_x_selection_set(None, NULL, 0, ECORE_X_ATOM_SELECTION_PRIMARY); +} + +/** + * Claim ownership of the SECONDARY selection and set its data. + * @param w The window to which this selection belongs + * @param data The data associated with the selection + * @param size The size of the data buffer in bytes + * @return Returns 1 if the ownership of the selection was successfully + * claimed, or 0 if unsuccessful. + */ +EAPI Eina_Bool +ecore_x_selection_secondary_set(Ecore_X_Window w, + const void *data, + int size) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return _ecore_x_selection_set(w, + data, + size, + ECORE_X_ATOM_SELECTION_SECONDARY); +} + +/** + * Release ownership of the secondary selection + * @return Returns 1 if the selection was successfully cleared, + * or 0 if unsuccessful. + * + */ +EAPI Eina_Bool +ecore_x_selection_secondary_clear(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return _ecore_x_selection_set(None, + NULL, + 0, + ECORE_X_ATOM_SELECTION_SECONDARY); +} + +/** + * Claim ownership of the XDND selection and set its data. + * @param w The window to which this selection belongs + * @param data The data associated with the selection + * @param size The size of the data buffer in bytes + * @return Returns 1 if the ownership of the selection was successfully + * claimed, or 0 if unsuccessful. + */ +EAPI Eina_Bool +ecore_x_selection_xdnd_set(Ecore_X_Window w, + const void *data, + int size) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return _ecore_x_selection_set(w, data, size, ECORE_X_ATOM_SELECTION_XDND); +} + +/** + * Release ownership of the XDND selection + * @return Returns 1 if the selection was successfully cleared, + * or 0 if unsuccessful. + * + */ +EAPI Eina_Bool +ecore_x_selection_xdnd_clear(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return _ecore_x_selection_set(None, NULL, 0, ECORE_X_ATOM_SELECTION_XDND); +} + +/** + * Claim ownership of the CLIPBOARD selection and set its data. + * @param w The window to which this selection belongs + * @param data The data associated with the selection + * @param size The size of the data buffer in bytes + * @return Returns 1 if the ownership of the selection was successfully + * claimed, or 0 if unsuccessful. + * + * Get the converted data from a previous CLIPBOARD selection + * request. The buffer must be freed when done with. + */ +EAPI Eina_Bool +ecore_x_selection_clipboard_set(Ecore_X_Window w, + const void *data, + int size) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return _ecore_x_selection_set(w, + data, + size, + ECORE_X_ATOM_SELECTION_CLIPBOARD); +} + +/** + * Release ownership of the clipboard selection + * @return Returns 1 if the selection was successfully cleared, + * or 0 if unsuccessful. + * + */ +EAPI Eina_Bool +ecore_x_selection_clipboard_clear(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return _ecore_x_selection_set(None, + NULL, + 0, + ECORE_X_ATOM_SELECTION_CLIPBOARD); +} + +Ecore_X_Atom +_ecore_x_selection_target_atom_get(const char *target) +{ + Ecore_X_Atom x_target; + + if (!strcmp(target, ECORE_X_SELECTION_TARGET_TEXT)) + x_target = ECORE_X_ATOM_TEXT; + else if (!strcmp(target, ECORE_X_SELECTION_TARGET_COMPOUND_TEXT)) + x_target = ECORE_X_ATOM_COMPOUND_TEXT; + else if (!strcmp(target, ECORE_X_SELECTION_TARGET_STRING)) + x_target = ECORE_X_ATOM_STRING; + else if (!strcmp(target, ECORE_X_SELECTION_TARGET_UTF8_STRING)) + x_target = ECORE_X_ATOM_UTF8_STRING; + else if (!strcmp(target, ECORE_X_SELECTION_TARGET_FILENAME)) + x_target = ECORE_X_ATOM_FILE_NAME; + else + x_target = ecore_x_atom_get(target); + + return x_target; +} + +char * +_ecore_x_selection_target_get(Ecore_X_Atom target) +{ + /* FIXME: Should not return mem allocated with strdup or X mixed, + * one should use free to free, the other XFree */ + if (target == ECORE_X_ATOM_FILE_NAME) + return strdup(ECORE_X_SELECTION_TARGET_FILENAME); + else if (target == ECORE_X_ATOM_STRING) + return strdup(ECORE_X_SELECTION_TARGET_STRING); + else if (target == ECORE_X_ATOM_UTF8_STRING) + return strdup(ECORE_X_SELECTION_TARGET_UTF8_STRING); + else if (target == ECORE_X_ATOM_TEXT) + return strdup(ECORE_X_SELECTION_TARGET_TEXT); + else + return XGetAtomName(_ecore_x_disp, target); +} + +static void +_ecore_x_selection_request(Ecore_X_Window w, + Ecore_X_Atom selection, + const char *target_str) +{ + Ecore_X_Atom target, prop; + + target = _ecore_x_selection_target_atom_get(target_str); + + if (selection == ECORE_X_ATOM_SELECTION_PRIMARY) + prop = ECORE_X_ATOM_SELECTION_PROP_PRIMARY; + else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY) + prop = ECORE_X_ATOM_SELECTION_PROP_SECONDARY; + else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD) + prop = ECORE_X_ATOM_SELECTION_PROP_CLIPBOARD; + else + return; + + XConvertSelection(_ecore_x_disp, selection, target, prop, + w, CurrentTime); +} + +EAPI void +ecore_x_selection_primary_request(Ecore_X_Window w, + const char *target) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _ecore_x_selection_request(w, ECORE_X_ATOM_SELECTION_PRIMARY, target); +} + +EAPI void +ecore_x_selection_secondary_request(Ecore_X_Window w, + const char *target) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _ecore_x_selection_request(w, ECORE_X_ATOM_SELECTION_SECONDARY, target); +} + +EAPI void +ecore_x_selection_xdnd_request(Ecore_X_Window w, + const char *target) +{ + Ecore_X_Atom atom; + Ecore_X_DND_Target *_target; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _target = _ecore_x_dnd_target_get(); + atom = _ecore_x_selection_target_atom_get(target); + XConvertSelection(_ecore_x_disp, ECORE_X_ATOM_SELECTION_XDND, atom, + ECORE_X_ATOM_SELECTION_PROP_XDND, w, + _target->time); +} + +EAPI void +ecore_x_selection_clipboard_request(Ecore_X_Window w, + const char *target) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _ecore_x_selection_request(w, ECORE_X_ATOM_SELECTION_CLIPBOARD, target); +} + +EAPI void +ecore_x_selection_converter_atom_add(Ecore_X_Atom target, + Eina_Bool (*func)(char *target, + void *data, + int size, + void **data_ret, + int *size_ret, + Ecore_X_Atom *ttype, + int *tsize)) +{ + Ecore_X_Selection_Converter *cnv; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + cnv = converters; + if (converters) + { + while (1) + { + if (cnv->target == target) + { + cnv->convert = func; + return; + } + + if (cnv->next) + cnv = cnv->next; + else + break; + } + + cnv->next = calloc(1, sizeof(Ecore_X_Selection_Converter)); + if (!cnv->next) return; + cnv = cnv->next; + } + else + { + converters = calloc(1, sizeof(Ecore_X_Selection_Converter)); + if (!converters) return; + cnv = converters; + } + + cnv->target = target; + cnv->convert = func; +} + +EAPI void +ecore_x_selection_converter_add(char *target, + Eina_Bool (*func)(char *target, + void *data, + int size, + void **data_ret, + int *size_ret, + Ecore_X_Atom *, + int *)) +{ + Ecore_X_Atom x_target; + + if (!func || !target) + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + x_target = _ecore_x_selection_target_atom_get(target); + + ecore_x_selection_converter_atom_add(x_target, func); +} + +EAPI void +ecore_x_selection_converter_atom_del(Ecore_X_Atom target) +{ + Ecore_X_Selection_Converter *cnv, *prev_cnv; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + prev_cnv = NULL; + cnv = converters; + + while (cnv) + { + if (cnv->target == target) + { + if (prev_cnv) + prev_cnv->next = cnv->next; + else + { + converters = cnv->next; /* This was the first converter */ + } + + free(cnv); + + return; + } + + prev_cnv = cnv; + cnv = cnv->next; + } +} + +EAPI void +ecore_x_selection_converter_del(char *target) +{ + Ecore_X_Atom x_target; + + if (!target) + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + x_target = _ecore_x_selection_target_atom_get(target); + ecore_x_selection_converter_atom_del(x_target); +} + +EAPI Eina_Bool +ecore_x_selection_notify_send(Ecore_X_Window requestor, + Ecore_X_Atom selection, + Ecore_X_Atom target, + Ecore_X_Atom property, + Ecore_X_Time tim) +{ + XEvent xev; + XSelectionEvent xnotify; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + xnotify.type = SelectionNotify; + xnotify.display = _ecore_x_disp; + xnotify.requestor = requestor; + xnotify.selection = selection; + xnotify.target = target; + xnotify.property = property; + xnotify.time = tim; + xnotify.send_event = True; + xnotify.serial = 0; + + xev.xselection = xnotify; + return (XSendEvent(_ecore_x_disp, requestor, False, 0, &xev) > 0) ? EINA_TRUE : EINA_FALSE; +} + +/* Locate and run conversion callback for specified selection target */ +EAPI Eina_Bool +ecore_x_selection_convert(Ecore_X_Atom selection, + Ecore_X_Atom target, + void **data_ret, + int *size, + Ecore_X_Atom *targtype, + int *typesize) +{ + Ecore_X_Selection_Intern *sel; + Ecore_X_Selection_Converter *cnv; + void *data; + char *tgt_str; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + sel = _ecore_x_selection_get(selection); + tgt_str = _ecore_x_selection_target_get(target); + + for (cnv = converters; cnv; cnv = cnv->next) + { + if (cnv->target == target) + { + int r; + r = cnv->convert(tgt_str, sel->data, sel->length, &data, size, + targtype, typesize); + free(tgt_str); + if (r) + { + *data_ret = data; + return r; + } + else + return EINA_FALSE; + } + } + + /* ICCCM says "If the selection cannot be converted into a form based on the target (and parameters, if any), the owner should refuse the SelectionRequest as previously described." */ + return EINA_FALSE; + + /* Default, just return the data + * data_ret = malloc(sel->length); + memcpy(*data_ret, sel->data, sel->length); + free(tgt_str); + return 1; + */ +} + +/* TODO: We need to work out a mechanism for automatic conversion to any requested + * locale using Ecore_Txt functions */ +/* Converter for standard non-utf8 text targets */ +static Eina_Bool +_ecore_x_selection_converter_text(char *target, + void *data, + int size, + void **data_ret, + int *size_ret, + Ecore_X_Atom *targprop __UNUSED__, + int *s __UNUSED__) +{ + XTextProperty text_prop; + char *mystr; + XICCEncodingStyle style; + + if (!data || !size) + return EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!strcmp(target, ECORE_X_SELECTION_TARGET_TEXT)) + style = XTextStyle; + else if (!strcmp(target, ECORE_X_SELECTION_TARGET_COMPOUND_TEXT)) + style = XCompoundTextStyle; + else if (!strcmp(target, ECORE_X_SELECTION_TARGET_STRING)) + style = XStringStyle; + +#ifdef X_HAVE_UTF8_STRING + else if (!strcmp(target, ECORE_X_SELECTION_TARGET_UTF8_STRING)) + style = XUTF8StringStyle; +#endif /* ifdef X_HAVE_UTF8_STRING */ + else + return EINA_FALSE; + + mystr = alloca(size + 1); + memcpy(mystr, data, size); + mystr[size] = '\0'; + +#ifdef X_HAVE_UTF8_STRING + if (Xutf8TextListToTextProperty(_ecore_x_disp, &mystr, 1, style, + &text_prop) == Success) + { + int bufsize = strlen((char *)text_prop.value) + 1; + *data_ret = malloc(bufsize); + if (!*data_ret) + { + return EINA_FALSE; + } + memcpy(*data_ret, text_prop.value, bufsize); + *size_ret = bufsize; + XFree(text_prop.value); + return EINA_TRUE; + } + +#else /* ifdef X_HAVE_UTF8_STRING */ + if (XmbTextListToTextProperty(_ecore_x_disp, &mystr, 1, style, + &text_prop) == Success) + { + int bufsize = strlen(text_prop.value) + 1; + *data_ret = malloc(bufsize); + if (!*data_ret) return EINA_FALSE; + memcpy(*data_ret, text_prop.value, bufsize); + *size_ret = bufsize; + XFree(text_prop.value); + return EINA_TRUE; + } + +#endif /* ifdef X_HAVE_UTF8_STRING */ + else + { + return EINA_TRUE; + } +} + +EAPI void +ecore_x_selection_parser_add(const char *target, + void *(*func)(const char *target, void *data, + int size, + int format)) +{ + Ecore_X_Selection_Parser *prs; + + if (!target) + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + prs = parsers; + if (parsers) + { + while (prs->next) + { + if (!strcmp(prs->target, target)) + { + prs->parse = func; + return; + } + + prs = prs->next; + } + + prs->next = calloc(1, sizeof(Ecore_X_Selection_Parser)); + if (!prs->next) return; + prs = prs->next; + } + else + { + parsers = calloc(1, sizeof(Ecore_X_Selection_Parser)); + if (!parsers) return; + prs = parsers; + } + + prs->target = strdup(target); + prs->parse = func; +} + +EAPI void +ecore_x_selection_parser_del(const char *target) +{ + Ecore_X_Selection_Parser *prs, *prev_prs; + + if (!target) + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + prev_prs = NULL; + prs = parsers; + + while (prs) + { + if (!strcmp(prs->target, target)) + { + if (prev_prs) + prev_prs->next = prs->next; + else + { + parsers = prs->next; /* This was the first parser */ + } + + free(prs->target); + free(prs); + + return; + } + + prev_prs = prs; + prs = prs->next; + } +} + +/** + * Change the owner and last-change time for the specified selection. + * @param win The owner of the specified atom. + * @param atom The selection atom + * @param tim Specifies the time + * @since 1.1.0 + */ +EAPI void +ecore_x_selection_owner_set(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Time tim) +{ + XSetSelectionOwner(_ecore_x_disp, atom, win, tim); +} + +/** + * Return the window that currently owns the specified selection. + * + * @param atom The specified selection atom. + * + * @return The window that currently owns the specified selection. + * @since 1.1.0 + */ +EAPI Ecore_X_Window +ecore_x_selection_owner_get(Ecore_X_Atom atom) +{ + return XGetSelectionOwner(_ecore_x_disp, atom); +} + +/* Locate and run conversion callback for specified selection target */ +void * +_ecore_x_selection_parse(const char *target, + void *data, + int size, + int format) +{ + Ecore_X_Selection_Parser *prs; + Ecore_X_Selection_Data *sel; + + for (prs = parsers; prs; prs = prs->next) + { + if (!strcmp(prs->target, target)) + { + sel = prs->parse(target, data, size, format); + if (sel) return sel; + } + } + + /* Default, just return the data */ + sel = calloc(1, sizeof(Ecore_X_Selection_Data)); + if (!sel) return NULL; + sel->free = _ecore_x_selection_data_default_free; + sel->length = size; + sel->format = format; + sel->data = data; + return sel; +} + +static int +_ecore_x_selection_data_default_free(void *data) +{ + Ecore_X_Selection_Data *sel; + + sel = data; + free(sel->data); + free(sel); + return 1; +} + +static void * +_ecore_x_selection_parser_files(const char *target, + void *_data, + int size, + int format __UNUSED__) +{ + Ecore_X_Selection_Data_Files *sel; + char *t, *data = _data; + int i, is; + char *tmp; + char **t2; + + if (strcmp(target, "text/uri-list") && + strcmp(target, "_NETSCAPE_URL")) + return NULL; + + sel = calloc(1, sizeof(Ecore_X_Selection_Data_Files)); + if (!sel) return NULL; + ECORE_X_SELECTION_DATA(sel)->free = _ecore_x_selection_data_files_free; + + if (data[size - 1]) + { + /* Isn't nul terminated */ + size++; + t = realloc(data, size); + if (!t) + { + free(sel); + return NULL; + } + data = t; + data[size - 1] = 0; + } + + tmp = malloc(size); + if (!tmp) + { + free(sel); + return NULL; + } + i = 0; + is = 0; + while ((is < size) && (data[is])) + { + if ((i == 0) && (data[is] == '#')) + for (; ((data[is]) && (data[is] != '\n')); is++) ; + else + { + if ((data[is] != '\r') && + (data[is] != '\n')) + tmp[i++] = data[is++]; + else + { + while ((data[is] == '\r') || (data[is] == '\n')) + is++; + tmp[i] = 0; + sel->num_files++; + t2 = realloc(sel->files, sel->num_files * sizeof(char *)); + if (t2) + { + sel->files = t2; + sel->files[sel->num_files - 1] = strdup(tmp); + } + tmp[0] = 0; + i = 0; + } + } + } + if (i > 0) + { + tmp[i] = 0; + sel->num_files++; + t2 = realloc(sel->files, sel->num_files * sizeof(char *)); + if (t2) + { + sel->files = t2; + sel->files[sel->num_files - 1] = strdup(tmp); + } + } + + free(tmp); + free(data); + + ECORE_X_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_FILES; + ECORE_X_SELECTION_DATA(sel)->length = sel->num_files; + + return ECORE_X_SELECTION_DATA(sel); +} + +static int +_ecore_x_selection_data_files_free(void *data) +{ + Ecore_X_Selection_Data_Files *sel; + int i; + + sel = data; + if (sel->files) + { + for (i = 0; i < sel->num_files; i++) + free(sel->files[i]); + free(sel->files); + } + + free(sel); + return 0; +} + +static void * +_ecore_x_selection_parser_text(const char *target __UNUSED__, + void *_data, + int size, + int format __UNUSED__) +{ + Ecore_X_Selection_Data_Text *sel; + unsigned char *data = _data; + void *t; + + sel = calloc(1, sizeof(Ecore_X_Selection_Data_Text)); + if (!sel) return NULL; + if (data[size - 1]) + { + /* Isn't nul terminated */ + size++; + t = realloc(data, size); + if (!t) + { + free(sel); + return NULL; + } + data = t; + data[size - 1] = 0; + } + + sel->text = (char *)data; + ECORE_X_SELECTION_DATA(sel)->length = size; + ECORE_X_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_TEXT; + ECORE_X_SELECTION_DATA(sel)->data = data; + ECORE_X_SELECTION_DATA(sel)->free = _ecore_x_selection_data_text_free; + return sel; +} + +static int +_ecore_x_selection_data_text_free(void *data) +{ + Ecore_X_Selection_Data_Text *sel; + + sel = data; + free(sel->text); + free(sel); + return 1; +} + +static void * +_ecore_x_selection_parser_targets(const char *target __UNUSED__, + void *data, + int size, + int format __UNUSED__) +{ + Ecore_X_Selection_Data_Targets *sel; + unsigned long *targets; + int i; + + sel = calloc(1, sizeof(Ecore_X_Selection_Data_Targets)); + if (!sel) return NULL; + targets = (unsigned long *)data; + + sel->num_targets = size - 2; + sel->targets = malloc((size - 2) * sizeof(char *)); + if (!sel->targets) + { + free(sel); + return NULL; + } + for (i = 2; i < size; i++) + sel->targets[i - 2] = XGetAtomName(_ecore_x_disp, targets[i]); + + ECORE_X_SELECTION_DATA(sel)->free = _ecore_x_selection_data_targets_free; + ECORE_X_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_TARGETS; + ECORE_X_SELECTION_DATA(sel)->length = size; + ECORE_X_SELECTION_DATA(sel)->data = data; + return sel; +} + +static int +_ecore_x_selection_data_targets_free(void *data) +{ + Ecore_X_Selection_Data_Targets *sel; + int i; + + sel = data; + + if (sel->targets) + { + for (i = 0; i < sel->num_targets; i++) + XFree(sel->targets[i]); + free(sel->targets); + } + + free(ECORE_X_SELECTION_DATA(sel)->data); + free(sel); + return 1; +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_sync.c b/src/lib/ecore_x/xlib/ecore_x_sync.c new file mode 100644 index 0000000..0c7f546 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_sync.c @@ -0,0 +1,159 @@ +/* + * XSync code + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include "Ecore.h" +#include "ecore_x_private.h" +#include "Ecore_X.h" +#include "Ecore_X_Atoms.h" + +EAPI Ecore_X_Sync_Alarm +ecore_x_sync_alarm_new(Ecore_X_Sync_Counter counter) +{ + Ecore_X_Sync_Alarm alarm; + XSyncAlarmAttributes values; + XSyncValue init; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XSyncIntToValue(&init, 0); + XSyncSetCounter(_ecore_x_disp, counter, init); + + values.trigger.counter = counter; + values.trigger.value_type = XSyncAbsolute; + XSyncIntToValue(&values.trigger.wait_value, 1); + values.trigger.test_type = XSyncPositiveComparison; + + XSyncIntToValue(&values.delta, 1); + + values.events = True; + + alarm = XSyncCreateAlarm(_ecore_x_disp, + XSyncCACounter | + XSyncCAValueType | + XSyncCAValue | + XSyncCATestType | + XSyncCADelta | + XSyncCAEvents, + &values); + + ecore_x_sync(); + return alarm; +} + +EAPI Eina_Bool +ecore_x_sync_alarm_free(Ecore_X_Sync_Alarm alarm) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return XSyncDestroyAlarm(_ecore_x_disp, alarm); +} + +EAPI Eina_Bool +ecore_x_sync_counter_query(Ecore_X_Sync_Counter counter, + unsigned int *val) +{ + XSyncValue value; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (XSyncQueryCounter(_ecore_x_disp, counter, &value)) + { + *val = (unsigned int)XSyncValueLow32(value); + return EINA_TRUE; + } + + return EINA_FALSE; +} + +EAPI Ecore_X_Sync_Counter +ecore_x_sync_counter_new(int val) +{ + XSyncCounter counter; + XSyncValue v; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XSyncIntToValue(&v, val); + counter = XSyncCreateCounter(_ecore_x_disp, v); + return counter; +} + +EAPI void +ecore_x_sync_counter_free(Ecore_X_Sync_Counter counter) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XSyncDestroyCounter(_ecore_x_disp, counter); +} + +EAPI void +ecore_x_sync_counter_inc(Ecore_X_Sync_Counter counter, + int by) +{ + XSyncValue v; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XSyncIntToValue(&v, by); + XSyncChangeCounter(_ecore_x_disp, counter, v); +} + +EAPI void +ecore_x_sync_counter_val_wait(Ecore_X_Sync_Counter counter, + int val) +{ + XSyncWaitCondition cond; + XSyncValue v, v2; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XSyncQueryCounter(_ecore_x_disp, counter, &v); + XSyncIntToValue(&v, val); + XSyncIntToValue(&v2, val + 1); + cond.trigger.counter = counter; + cond.trigger.value_type = XSyncAbsolute; + cond.trigger.wait_value = v; + cond.trigger.test_type = XSyncPositiveComparison; + cond.event_threshold = v2; + XSyncAwait(_ecore_x_disp, &cond, 1); +// XSync(_ecore_x_disp, False); // dont need this +} + +EAPI void +ecore_x_sync_counter_set(Ecore_X_Sync_Counter counter, + int val) +{ + XSyncValue v; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XSyncIntToValue(&v, val); + XSyncSetCounter(_ecore_x_disp, counter, v); +} + +EAPI void +ecore_x_sync_counter_2_set(Ecore_X_Sync_Counter counter, + int val_hi, + unsigned int val_lo) +{ + XSyncValue v; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XSyncIntsToValue(&v, val_lo, val_hi); + XSyncSetCounter(_ecore_x_disp, counter, v); +} + +EAPI Eina_Bool +ecore_x_sync_counter_2_query(Ecore_X_Sync_Counter counter, + int *val_hi, + unsigned int *val_lo) +{ + XSyncValue value; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (XSyncQueryCounter(_ecore_x_disp, counter, &value)) + { + *val_lo = (unsigned int)XSyncValueLow32(value); + *val_hi = (int)XSyncValueHigh32(value); + return EINA_TRUE; + } + return EINA_FALSE; +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_test.c b/src/lib/ecore_x/xlib/ecore_x_test.c new file mode 100644 index 0000000..a4d40f6 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_test.c @@ -0,0 +1,167 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include + +#ifdef ECORE_XTEST +# include +#endif /* ifdef ECORE_XTEST */ + +#include "ecore_x_private.h" +#include "Ecore_X.h" +#include + +EAPI Eina_Bool +#ifdef ECORE_XTEST +ecore_x_test_fake_key_down(const char *key) +#else +ecore_x_test_fake_key_down(const char *key __UNUSED__) +#endif +{ +#ifdef ECORE_XTEST + KeyCode keycode = 0; + KeySym keysym; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!strncmp(key, "Keycode-", 8)) + keycode = atoi(key + 8); + else + { + keysym = XStringToKeysym(key); + if (keysym == NoSymbol) + return EINA_FALSE; + + keycode = XKeysymToKeycode(_ecore_x_disp, keysym); + } + + if (keycode == 0) + return EINA_FALSE; + + return XTestFakeKeyEvent(_ecore_x_disp, keycode, 1, 0) ? EINA_TRUE : EINA_FALSE; +#else /* ifdef ECORE_XTEST */ + return EINA_FALSE; +#endif /* ifdef ECORE_XTEST */ +} + +EAPI Eina_Bool +#ifdef ECORE_XTEST +ecore_x_test_fake_key_up(const char *key) +#else +ecore_x_test_fake_key_up(const char *key __UNUSED__) +#endif +{ +#ifdef ECORE_XTEST + KeyCode keycode = 0; + KeySym keysym; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!strncmp(key, "Keycode-", 8)) + keycode = atoi(key + 8); + else + { + keysym = XStringToKeysym(key); + if (keysym == NoSymbol) + return EINA_FALSE; + + keycode = XKeysymToKeycode(_ecore_x_disp, keysym); + } + + if (keycode == 0) + return EINA_FALSE; + + return XTestFakeKeyEvent(_ecore_x_disp, keycode, 0, 0) ? EINA_TRUE : EINA_FALSE; +#else /* ifdef ECORE_XTEST */ + return EINA_FALSE; +#endif /* ifdef ECORE_XTEST */ +} + +EAPI Eina_Bool +#ifdef ECORE_XTEST +ecore_x_test_fake_key_press(const char *key) +#else +ecore_x_test_fake_key_press(const char *key __UNUSED__) +#endif +{ +#ifdef ECORE_XTEST + KeyCode keycode = 0; + KeySym keysym = 0; + int shift = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!strncmp(key, "Keycode-", 8)) + keycode = atoi(key + 8); + else + { + keysym = XStringToKeysym(key); + if (keysym == NoSymbol) + return EINA_FALSE; + + keycode = XKeysymToKeycode(_ecore_x_disp, keysym); + if (_ecore_x_XKeycodeToKeysym(_ecore_x_disp, keycode, 0) != keysym) + { + if (_ecore_x_XKeycodeToKeysym(_ecore_x_disp, keycode, 1) == keysym) + shift = 1; + else + keycode = 0; + } + else + shift = 0; + } + + if (keycode == 0) + { + static int mod = 0; + KeySym *keysyms; + int keycode_min, keycode_max, keycode_num; + int i; + + XDisplayKeycodes(_ecore_x_disp, &keycode_min, &keycode_max); + keysyms = XGetKeyboardMapping(_ecore_x_disp, keycode_min, + keycode_max - keycode_min + 1, + &keycode_num); + mod = (mod + 1) & 0x7; + i = (keycode_max - keycode_min - mod - 1) * keycode_num; + + keysyms[i] = keysym; + XChangeKeyboardMapping(_ecore_x_disp, keycode_min, keycode_num, + keysyms, (keycode_max - keycode_min)); + XFree(keysyms); + XSync(_ecore_x_disp, False); + keycode = keycode_max - mod - 1; + } + + if (shift) + XTestFakeKeyEvent(_ecore_x_disp, + XKeysymToKeycode(_ecore_x_disp, XK_Shift_L), 1, 0); + + XTestFakeKeyEvent(_ecore_x_disp, keycode, 1, 0); + XTestFakeKeyEvent(_ecore_x_disp, keycode, 0, 0); + if (shift) + XTestFakeKeyEvent(_ecore_x_disp, + XKeysymToKeycode(_ecore_x_disp, XK_Shift_L), 0, 0); + + return EINA_TRUE; +#else /* ifdef ECORE_XTEST */ + return EINA_FALSE; +#endif /* ifdef ECORE_XTEST */ +} + +EAPI const char * +ecore_x_keysym_string_get(int keysym) +{ + return XKeysymToString(keysym); +} + +EAPI int +ecore_x_keysym_keycode_get(const char *keyname) +{ + int keycode = 0; + + if (!strncmp(keyname, "Keycode-", 8)) + keycode = atoi(keyname + 8); + else + keycode = XKeysymToKeycode(_ecore_x_disp, XStringToKeysym(keyname)); + + return keycode; +} diff --git a/src/lib/ecore_x/xlib/ecore_x_vsync.c b/src/lib/ecore_x/xlib/ecore_x_vsync.c new file mode 100644 index 0000000..4296bb2 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_vsync.c @@ -0,0 +1,351 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include "Ecore.h" +#include "ecore_x_private.h" +#include "Ecore_X.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define ECORE_X_VSYNC_DRI2 1 + +#ifdef ECORE_X_VSYNC_DRI2 +// relevant header bits of dri/drm inlined here to avoid needing external +// headers to build +/// drm +typedef unsigned int drm_magic_t; + +typedef enum +{ + DRM_VBLANK_ABSOLUTE = 0x00000000, + DRM_VBLANK_RELATIVE = 0x00000001, + DRM_VBLANK_EVENT = 0x04000000, + DRM_VBLANK_FLIP = 0x08000000, + DRM_VBLANK_NEXTONMISS = 0x10000000, + DRM_VBLANK_SECONDARY = 0x20000000, + DRM_VBLANK_SIGNAL = 0x40000000 +} +drmVBlankSeqType; + +typedef struct _drmVBlankReq +{ + drmVBlankSeqType type; + unsigned int sequence; + unsigned long signal; +} drmVBlankReq; + +typedef struct _drmVBlankReply +{ + drmVBlankSeqType type; + unsigned int sequence; + long tval_sec; + long tval_usec; +} drmVBlankReply; + +typedef union _drmVBlank +{ + drmVBlankReq request; + drmVBlankReply reply; +} drmVBlank; + +#define DRM_EVENT_CONTEXT_VERSION 2 + +typedef struct _drmEventContext +{ + int version; + void (*vblank_handler)(int fd, + unsigned int sequence, + unsigned int tv_sec, + unsigned int tv_usec, + void *user_data); + void (*page_flip_handler)(int fd, + unsigned int sequence, + unsigned int tv_sec, + unsigned int tv_usec, + void *user_data); +} drmEventContext; + +static int (*sym_drmClose)(int fd) = NULL; +static int (*sym_drmGetMagic)(int fd, + drm_magic_t *magic) = NULL; +static int (*sym_drmWaitVBlank)(int fd, + drmVBlank *vbl) = NULL; +static int (*sym_drmHandleEvent)(int fd, + drmEventContext *evctx) = NULL; + +//// dri + +static Bool (*sym_DRI2QueryExtension)(Display *display, + int *eventBase, + int *errorBase) = NULL; +static Bool (*sym_DRI2QueryVersion)(Display *display, + int *major, + int *minor) = NULL; +static Bool (*sym_DRI2Connect)(Display *display, + XID window, + char **driverName, + char **deviceName) = NULL; +static Bool (*sym_DRI2Authenticate)(Display *display, + XID window, + drm_magic_t magic) = NULL; + +//// dri/drm data needed +static int dri2_event = 0; +static int dri2_error = 0; +static int dri2_major = 0; +static int dri2_minor = 0; +static char *device_name = 0; +static char *driver_name = 0; +static drm_magic_t drm_magic; + +static int drm_fd = -1; +static int drm_event_is_busy = 0; +static int drm_animators_interval = 1; +static drmEventContext drm_evctx; +static Ecore_Fd_Handler *dri_drm_fdh = NULL; + +static void *dri_lib = NULL; +static void *drm_lib = NULL; + +static Window dri_drm_vsync_root = 0; + +static void +_dri_drm_tick_schedule(void) +{ + drmVBlank vbl; + + vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT; + vbl.request.sequence = drm_animators_interval; + vbl.request.signal = 0; + sym_drmWaitVBlank(drm_fd, &vbl); +} + +static void +_dri_drm_tick_begin(void *data __UNUSED__) +{ + drm_event_is_busy = 1; + _dri_drm_tick_schedule(); +} + +static void +_dri_drm_tick_end(void *data __UNUSED__) +{ + drm_event_is_busy = 0; +} + +static void +_dri_drm_vblank_handler(int fd __UNUSED__, + unsigned int frame __UNUSED__, + unsigned int sec __UNUSED__, + unsigned int usec __UNUSED__, + void *data __UNUSED__) +{ + ecore_animator_custom_tick(); + if (drm_event_is_busy) _dri_drm_tick_schedule(); +} + +static Eina_Bool +_dri_drm_cb(void *data __UNUSED__, + Ecore_Fd_Handler *fd_handler __UNUSED__) +{ + sym_drmHandleEvent(drm_fd, &drm_evctx); + return ECORE_CALLBACK_RENEW; +} + +// yes. most evil. we dlopen libdrm and libGL etc. to manually find smbols +// so we can be as compatible as possible given the whole mess of the +// gl/dri/drm etc. world. and handle graceful failure at runtime not +// compile time +static int +_dri_drm_link(void) +{ + const char *drm_libs[] = + { + "libdrm.so.2", + "libdrm.so.1", + "libdrm.so.0", + "libdrm.so", + NULL, + }; + const char *dri_libs[] = + { + "libdri2.so.2", + "libdri2.so.1", + "libdri2.so.0", + "libdri2.so", + "libGL.so.4", + "libGL.so.3", + "libGL.so.2", + "libGL.so.1", + "libGL.so.0", + "libGL.so", + NULL, + }; + int i, fail; +#define SYM(lib, xx) \ + do { \ + sym_ ## xx = dlsym(lib, #xx); \ + if (!(sym_ ## xx)) { \ + fprintf(stderr, "%s\n", dlerror()); \ + fail = 1; \ + } \ + } while (0) + + if (dri_lib) return 1; + for (i = 0; drm_libs[i]; i++) + { + drm_lib = dlopen(drm_libs[i], RTLD_LOCAL | RTLD_LAZY); + if (drm_lib) + { + fail = 0; + SYM(drm_lib, drmClose); + SYM(drm_lib, drmWaitVBlank); + SYM(drm_lib, drmHandleEvent); + if (fail) + { + dlclose(drm_lib); + drm_lib = NULL; + } + else break; + } + } + if (!drm_lib) return 0; + for (i = 0; dri_libs[i]; i++) + { + dri_lib = dlopen(dri_libs[i], RTLD_LOCAL | RTLD_LAZY); + if (dri_lib) + { + fail = 0; + SYM(dri_lib, DRI2QueryExtension); + SYM(dri_lib, DRI2QueryVersion); + SYM(dri_lib, DRI2Connect); + SYM(dri_lib, DRI2Authenticate); + if (fail) + { + dlclose(dri_lib); + dri_lib = NULL; + } + else break; + } + } + if (!dri_lib) + { + dlclose(drm_lib); + drm_lib = NULL; + return 0; + } + return 1; +} + +static int +_dri_drm_init(void) +{ + if (!sym_DRI2QueryExtension(_ecore_x_disp, &dri2_event, &dri2_error)) + return 0; + if (!sym_DRI2QueryVersion(_ecore_x_disp, &dri2_major, &dri2_minor)) + return 0; + if (dri2_major < 2) + return 0; + if (!sym_DRI2Connect(_ecore_x_disp, dri_drm_vsync_root, &driver_name, &device_name)) + return 0; + drm_fd = open(device_name, O_RDWR); + if (drm_fd < 0) + return 0; + sym_drmGetMagic(drm_fd, &drm_magic); + if (!sym_DRI2Authenticate(_ecore_x_disp, dri_drm_vsync_root, drm_magic)) + { + close(drm_fd); + drm_fd = -1; + return 0; + } + memset(&drm_evctx, 0, sizeof(drm_evctx)); + drm_evctx.version = DRM_EVENT_CONTEXT_VERSION; + drm_evctx.vblank_handler = _dri_drm_vblank_handler; + drm_evctx.page_flip_handler = NULL; + + dri_drm_fdh = ecore_main_fd_handler_add(drm_fd, ECORE_FD_READ, + _dri_drm_cb, NULL, NULL, NULL); + if (!dri_drm_fdh) + { + close(drm_fd); + drm_fd = -1; + return 0; + } + return 1; +} + +static void +_dri_drm_shutdown(void) +{ + if (drm_fd >= 0) + { + close(drm_fd); + drm_fd = -1; + } + if (dri_drm_fdh) + { + ecore_main_fd_handler_del(dri_drm_fdh); + dri_drm_fdh = NULL; + } +} + +#endif + +EAPI Eina_Bool +ecore_x_vsync_animator_tick_source_set(Ecore_X_Window win) +{ +#ifdef ECORE_X_VSYNC_DRI2 + Ecore_X_Window root; + + root = ecore_x_window_root_get(win); + if (root != dri_drm_vsync_root) + { + dri_drm_vsync_root = root; + if (dri_drm_vsync_root) + { + if (!_dri_drm_link()) + { + ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER); + return EINA_FALSE; + } + _dri_drm_shutdown(); + if (!_dri_drm_init()) + { + dri_drm_vsync_root = 0; + ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER); + return EINA_FALSE; + } + ecore_animator_custom_source_tick_begin_callback_set + (_dri_drm_tick_begin, NULL); + ecore_animator_custom_source_tick_end_callback_set + (_dri_drm_tick_end, NULL); + ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_CUSTOM); + } + else + { + if (drm_fd >= 0) + { + _dri_drm_shutdown(); + ecore_animator_custom_source_tick_begin_callback_set + (NULL, NULL); + ecore_animator_custom_source_tick_end_callback_set + (NULL, NULL); + ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER); + } + } + } + return EINA_TRUE; +#else + return EINA_FALSE; + win = 0; +#endif +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_window.c b/src/lib/ecore_x/xlib/ecore_x_window.c new file mode 100644 index 0000000..f16f5b1 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_window.c @@ -0,0 +1,1727 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include +#include +#include + +#include "Ecore.h" +#include "ecore_x_private.h" +#include "Ecore_X.h" +#include "Ecore_X_Atoms.h" + +static int ignore_num = 0; +static Ecore_X_Window *ignore_list = NULL; + +/** + * @defgroup Ecore_X_Window_Create_Group X Window Creation Functions + * + * Functions that can be used to create an X window. + */ + +/** + * Creates a new window. + * @param parent The parent window to use. If @p parent is @c 0, the root + * window of the default display is used. + * @param x X position. + * @param y Y position. + * @param w Width. + * @param h Height. + * @return The new window handle. + * @ingroup Ecore_X_Window_Create_Group + */ +EAPI Ecore_X_Window +ecore_x_window_new(Ecore_X_Window parent, + int x, + int y, + int w, + int h) +{ + Window win; + XSetWindowAttributes attr; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (parent == 0) + parent = DefaultRootWindow(_ecore_x_disp); + + attr.backing_store = NotUseful; + attr.override_redirect = False; + attr.border_pixel = 0; + attr.background_pixmap = None; + attr.bit_gravity = NorthWestGravity; + attr.win_gravity = NorthWestGravity; + attr.save_under = False; + attr.do_not_propagate_mask = NoEventMask; + attr.event_mask = KeyPressMask | + KeyReleaseMask | + ButtonPressMask | + ButtonReleaseMask | + EnterWindowMask | + LeaveWindowMask | + PointerMotionMask | + ExposureMask | + VisibilityChangeMask | + StructureNotifyMask | + FocusChangeMask | + PropertyChangeMask | + ColormapChangeMask; + win = XCreateWindow(_ecore_x_disp, parent, + x, y, w, h, 0, + CopyFromParent, /*DefaultDepth(_ecore_x_disp, DefaultScreen(_ecore_x_disp)),*/ + InputOutput, + CopyFromParent, /*DefaultVisual(_ecore_x_disp, DefaultScreen(_ecore_x_disp)),*/ + CWBackingStore | + CWOverrideRedirect | +/* CWColormap | */ + CWBorderPixel | + CWBackPixmap | + CWSaveUnder | + CWDontPropagate | + CWEventMask | + CWBitGravity | + CWWinGravity, + &attr); + + if (parent == DefaultRootWindow(_ecore_x_disp)) + ecore_x_window_defaults_set(win); + + return win; +} + +/** + * Creates a window with the override redirect attribute set to @c True. + * @param parent The parent window to use. If @p parent is @c 0, the root + * window of the default display is used. + * @param x X position. + * @param y Y position. + * @param w Width. + * @param h Height. + * @return The new window handle. + * @ingroup Ecore_X_Window_Create_Group + */ +EAPI Ecore_X_Window +ecore_x_window_override_new(Ecore_X_Window parent, + int x, + int y, + int w, + int h) +{ + Window win; + XSetWindowAttributes attr; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (parent == 0) + parent = DefaultRootWindow(_ecore_x_disp); + + attr.backing_store = NotUseful; + attr.override_redirect = True; + attr.border_pixel = 0; + attr.background_pixmap = None; + attr.bit_gravity = NorthWestGravity; + attr.win_gravity = NorthWestGravity; + attr.save_under = False; + attr.do_not_propagate_mask = NoEventMask; + attr.event_mask = KeyPressMask | + KeyReleaseMask | + ButtonPressMask | + ButtonReleaseMask | + EnterWindowMask | + LeaveWindowMask | + PointerMotionMask | + ExposureMask | + VisibilityChangeMask | + StructureNotifyMask | + FocusChangeMask | + PropertyChangeMask | + ColormapChangeMask; + win = XCreateWindow(_ecore_x_disp, parent, + x, y, w, h, 0, + CopyFromParent, /*DefaultDepth(_ecore_x_disp, DefaultScreen(_ecore_x_disp)),*/ + InputOutput, + CopyFromParent, /*DefaultVisual(_ecore_x_disp, DefaultScreen(_ecore_x_disp)),*/ + CWBackingStore | + CWOverrideRedirect | +/* CWColormap | */ + CWBorderPixel | + CWBackPixmap | + CWSaveUnder | + CWDontPropagate | + CWEventMask | + CWBitGravity | + CWWinGravity, + &attr); + return win; +} + +/** + * Creates a new input window. + * @param parent The parent window to use. If @p parent is @c 0, the root + * window of the default display is used. + * @param x X position. + * @param y Y position. + * @param w Width. + * @param h Height. + * @return The new window. + * @ingroup Ecore_X_Window_Create_Group + */ +EAPI Ecore_X_Window +ecore_x_window_input_new(Ecore_X_Window parent, + int x, + int y, + int w, + int h) +{ + Window win; + XSetWindowAttributes attr; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (parent == 0) + parent = DefaultRootWindow(_ecore_x_disp); + + attr.override_redirect = True; + attr.do_not_propagate_mask = NoEventMask; + attr.event_mask = KeyPressMask | + KeyReleaseMask | + ButtonPressMask | + ButtonReleaseMask | + EnterWindowMask | + LeaveWindowMask | + PointerMotionMask | + ExposureMask | + VisibilityChangeMask | + StructureNotifyMask | + FocusChangeMask | + PropertyChangeMask | + ColormapChangeMask; + win = XCreateWindow(_ecore_x_disp, parent, + x, y, w, h, 0, + CopyFromParent, + InputOnly, + CopyFromParent, /*DefaultVisual(_ecore_x_disp, DefaultScreen(_ecore_x_disp)),*/ + CWOverrideRedirect | + CWDontPropagate | + CWEventMask, + &attr); + + if (parent == DefaultRootWindow(_ecore_x_disp)) + { + } + + return win; +} + +/** + * @defgroup Ecore_X_Window_Properties_Group X Window Property Functions + * + * Functions that set window properties. + */ + +/** + * Sets the default properties for the given window. + * + * The default properties set for the window are @c WM_CLIENT_MACHINE and + * @c _NET_WM_PID. + * + * @param win The given window. + * @ingroup Ecore_X_Window_Properties_Group + */ +EAPI void +ecore_x_window_defaults_set(Ecore_X_Window win) +{ + long pid; + char buf[MAXHOSTNAMELEN]; + char *hostname[1]; + int argc; + char **argv; + XTextProperty xprop; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + /* + * Set WM_CLIENT_MACHINE. + */ + gethostname(buf, MAXHOSTNAMELEN); + buf[MAXHOSTNAMELEN - 1] = '\0'; + hostname[0] = buf; + /* The ecore function uses UTF8 which Xlib may not like (especially + * with older clients) */ + /* ecore_x_window_prop_string_set(win, ECORE_X_ATOM_WM_CLIENT_MACHINE, + (char *)buf); */ + if (XStringListToTextProperty(hostname, 1, &xprop)) + { + XSetWMClientMachine(_ecore_x_disp, win, &xprop); + XFree(xprop.value); + } + + /* + * Set _NET_WM_PID + */ + pid = getpid(); + ecore_x_netwm_pid_set(win, pid); + + ecore_x_netwm_window_type_set(win, ECORE_X_WINDOW_TYPE_NORMAL); + + ecore_app_args_get(&argc, &argv); + ecore_x_icccm_command_set(win, argc, argv); +} + +EAPI void +ecore_x_window_configure(Ecore_X_Window win, + Ecore_X_Window_Configure_Mask mask, + int x, + int y, + int w, + int h, + int border_width, + Ecore_X_Window sibling, + int stack_mode) +{ + XWindowChanges xwc; + + if (!win) + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + xwc.x = x; + xwc.y = y; + xwc.width = w; + xwc.height = h; + xwc.border_width = border_width; + xwc.sibling = sibling; + xwc.stack_mode = stack_mode; + + XConfigureWindow(_ecore_x_disp, win, mask, &xwc); +} + +/** + * @defgroup Ecore_X_Window_Destroy_Group X Window Destroy Functions + * + * Functions to destroy X windows. + */ + +/** + * Deletes the given window. + * @param win The given window. + * @ingroup Ecore_X_Window_Destroy_Group + */ +EAPI void +ecore_x_window_free(Ecore_X_Window win) +{ + /* sorry sir, deleting the root window doesn't sound like + * a smart idea. + */ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (win) + XDestroyWindow(_ecore_x_disp, win); +} + +/** + * Set if a window should be ignored. + * @param win The given window. + * @param ignore if to ignore + */ +EAPI void +ecore_x_window_ignore_set(Ecore_X_Window win, + int ignore) +{ + int i, j, cnt; + Ecore_X_Window *t; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (ignore) + { + if (ignore_list) + { + for (i = 0; i < ignore_num; i++) + { + if (win == ignore_list[i]) + return; + } + t = realloc(ignore_list, (ignore_num + 1) * sizeof(Ecore_X_Window)); + if (!t) return; + ignore_list = t; + ignore_list[ignore_num++] = win; + } + else + { + ignore_num = 0; + ignore_list = malloc(sizeof(Ecore_X_Window)); + if (ignore_list) + ignore_list[ignore_num++] = win; + } + } + else + { + if (!ignore_list) + return; + + for (cnt = ignore_num, i = 0, j = 0; i < cnt; i++) + { + if (win != ignore_list[i]) + ignore_list[j++] = ignore_list[i]; + else + ignore_num--; + } + + if (ignore_num <= 0) + { + free(ignore_list); + ignore_list = NULL; + return; + } + t = realloc(ignore_list, ignore_num * sizeof(Ecore_X_Window)); + if (t) ignore_list = t; + } +} + +/** + * Get the ignore list + * @param num number of windows in the list + * @return list of windows to ignore + */ +EAPI Ecore_X_Window * +ecore_x_window_ignore_list(int *num) +{ + if (num) + *num = ignore_num; + + return ignore_list; +} + +/** + * Sends a delete request to the given window. + * @param win The given window. + * @ingroup Ecore_X_Window_Destroy_Group + */ +EAPI void +ecore_x_window_delete_request_send(Ecore_X_Window win) +{ + XEvent xev; + + /* sorry sir, deleting the root window doesn't sound like + * a smart idea. + */ + if (!win) + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + xev.xclient.type = ClientMessage; + xev.xclient.display = _ecore_x_disp; + xev.xclient.window = win; + xev.xclient.message_type = ECORE_X_ATOM_WM_PROTOCOLS; + xev.xclient.format = 32; + xev.xclient.data.l[0] = ECORE_X_ATOM_WM_DELETE_WINDOW; + xev.xclient.data.l[1] = CurrentTime; + + XSendEvent(_ecore_x_disp, win, False, NoEventMask, &xev); +} + +/** + * @defgroup Ecore_X_Window_Visibility_Group X Window Visibility Functions + * + * Functions to access and change the visibility of X windows. + */ + +/** + * Shows a window. + * + * Synonymous to "mapping" a window in X Window System terminology. + * + * @param win The window to show. + * @ingroup Ecore_X_Window_Visibility + */ +EAPI void +ecore_x_window_show(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XMapWindow(_ecore_x_disp, win); +} + +/** + * Hides a window. + * + * Synonymous to "unmapping" a window in X Window System terminology. + * + * @param win The window to hide. + * @ingroup Ecore_X_Window_Visibility + */ +EAPI void +ecore_x_window_hide(Ecore_X_Window win) +{ + XEvent xev; + Window root; + int idum; + unsigned int uidum; + + /* ICCCM: SEND unmap event... */ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + root = win; + if (ScreenCount(_ecore_x_disp) == 1) + root = DefaultRootWindow(_ecore_x_disp); + else + XGetGeometry(_ecore_x_disp, + win, + &root, + &idum, + &idum, + &uidum, + &uidum, + &uidum, + &uidum); + + xev.xunmap.type = UnmapNotify; + xev.xunmap.serial = 0; + xev.xunmap.send_event = True; + xev.xunmap.display = _ecore_x_disp; + xev.xunmap.event = root; + xev.xunmap.window = win; + xev.xunmap.from_configure = False; + XSendEvent(_ecore_x_disp, xev.xunmap.event, False, + SubstructureRedirectMask | SubstructureNotifyMask, &xev); + XUnmapWindow(_ecore_x_disp, win); +} + +/** + * @defgroup Ecore_X_Window_Geometry_Group X Window Geometry Functions + * + * Functions that change or retrieve the geometry of X windows. + */ + +/** + * Moves a window to the position @p x, @p y. + * + * The position is relative to the upper left hand corner of the + * parent window. + * + * @param win The window to move. + * @param x X position. + * @param y Y position. + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI void +ecore_x_window_move(Ecore_X_Window win, + int x, + int y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XMoveWindow(_ecore_x_disp, win, x, y); +} + +/** + * Resizes a window. + * @param win The window to resize. + * @param w New width of the window. + * @param h New height of the window. + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI void +ecore_x_window_resize(Ecore_X_Window win, + int w, + int h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (w < 1) + w = 1; + + if (h < 1) + h = 1; + + XResizeWindow(_ecore_x_disp, win, w, h); +} + +/** + * Moves and resizes a window. + * @param win The window to move and resize. + * @param x New X position of the window. + * @param y New Y position of the window. + * @param w New width of the window. + * @param h New height of the window. + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI void +ecore_x_window_move_resize(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (w < 1) + w = 1; + + if (h < 1) + h = 1; + + XMoveResizeWindow(_ecore_x_disp, win, x, y, w, h); +} + +/** + * @defgroup Ecore_X_Window_Focus_Functions X Window Focus Functions + * + * Functions that give the focus to an X Window. + */ + +/** + * Sets the focus to the window @p win. + * @param win The window to focus. + * @ingroup Ecore_X_Window_Focus_Functions + */ +EAPI void +ecore_x_window_focus(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (win == 0) + win = DefaultRootWindow(_ecore_x_disp); // XSetInputFocus(_ecore_x_disp, win, RevertToNone, CurrentTime); + +// XSetInputFocus(_ecore_x_disp, win, RevertToPointerRoot, CurrentTime); + XSetInputFocus(_ecore_x_disp, win, RevertToParent, CurrentTime); +} + +/** + * Sets the focus to the given window at a specific time. + * @param win The window to focus. + * @param t When to set the focus to the window. + * @ingroup Ecore_X_Window_Focus_Functions + */ +EAPI void +ecore_x_window_focus_at_time(Ecore_X_Window win, + Ecore_X_Time t) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (win == 0) + win = DefaultRootWindow(_ecore_x_disp); // XSetInputFocus(_ecore_x_disp, win, RevertToNone, t); + +// XSetInputFocus(_ecore_x_disp, win, PointerRoot, t); + XSetInputFocus(_ecore_x_disp, win, RevertToParent, t); +} + +/** + * gets the window that has focus. + * @return The window that has focus. + * @ingroup Ecore_X_Window_Focus_Functions + */ +EAPI Ecore_X_Window +ecore_x_window_focus_get(void) +{ + Window win; + int revert_mode; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + win = 0; + XGetInputFocus(_ecore_x_disp, &win, &revert_mode); + return win; +} + +/** + * @defgroup Ecore_X_Window_Z_Order_Group X Window Z Order Functions + * + * Functions that change the Z order of X windows. + */ + +/** + * Raises the given window. + * @param win The window to raise. + * @ingroup Ecore_X_Window_Z_Order_Group + */ +EAPI void +ecore_x_window_raise(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XRaiseWindow(_ecore_x_disp, win); +} + +/** + * Lowers the given window. + * @param win The window to lower. + * @ingroup Ecore_X_Window_Z_Order_Group + */ +EAPI void +ecore_x_window_lower(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XLowerWindow(_ecore_x_disp, win); +} + +/** + * @defgroup Ecore_X_Window_Parent_Group X Window Parent Functions + * + * Functions that retrieve or changes the parent window of a window. + */ + +/** + * Moves a window to within another window at a given position. + * @param win The window to reparent. + * @param new_parent The new parent window. + * @param x X position within new parent window. + * @param y Y position within new parent window. + * @ingroup Ecore_X_Window_Parent_Group + */ +EAPI void +ecore_x_window_reparent(Ecore_X_Window win, + Ecore_X_Window new_parent, + int x, + int y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (new_parent == 0) + new_parent = DefaultRootWindow(_ecore_x_disp); + + XReparentWindow(_ecore_x_disp, win, new_parent, x, y); +} + +/** + * Retrieves the size of the given window. + * @param win The given window. + * @param w Pointer to an integer into which the width is to be stored. + * @param h Pointer to an integer into which the height is to be stored. + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI void +ecore_x_window_size_get(Ecore_X_Window win, + int *w, + int *h) +{ + int dummy_x, dummy_y; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (win == 0) + win = DefaultRootWindow(_ecore_x_disp); + + ecore_x_drawable_geometry_get(win, &dummy_x, &dummy_y, w, h); +} + +/** + * Retrieves the geometry of the given window. + * + * Note that the x & y coordinates are relative to your parent. In + * particular for reparenting window managers - relative to you window border. + * If you want screen coordinates either walk the window tree to the root, + * else for ecore_evas applications see ecore_evas_geometry_get(). Elementary + * applications can use elm_win_screen_position_get(). + * + * @param win The given window. + * @param x Pointer to an integer in which the X position is to be stored. + * @param y Pointer to an integer in which the Y position is to be stored. + * @param w Pointer to an integer in which the width is to be stored. + * @param h Pointer to an integer in which the height is to be stored. + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI void +ecore_x_window_geometry_get(Ecore_X_Window win, + int *x, + int *y, + int *w, + int *h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!win) + win = DefaultRootWindow(_ecore_x_disp); + + ecore_x_drawable_geometry_get(win, x, y, w, h); +} + +/** + * Retrieves the width of the border of the given window. + * @param win The given window. + * @return Width of the border of @p win. + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI int +ecore_x_window_border_width_get(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + /* doesn't make sense to call this on a root window */ + if (!win) + return 0; + + return ecore_x_drawable_border_width_get(win); +} + +/** + * Sets the width of the border of the given window. + * @param win The given window. + * @param width The new border width. + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI void +ecore_x_window_border_width_set(Ecore_X_Window win, + int width) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + /* doesn't make sense to call this on a root window */ + if (!win) + return; + + XSetWindowBorderWidth (_ecore_x_disp, win, width); +} + +/** + * Retrieves the depth of the given window. + * @param win The given window. + * @return Depth of the window. + */ +EAPI int +ecore_x_window_depth_get(Ecore_X_Window win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return ecore_x_drawable_depth_get(win); +} + +/** + * @brief Show the cursor on a window of type Ecore_X_Window. + * @param win The window for which the cursor will be showed. + * @param show Enables the show of the cursor on the window if equals EINA_TRUE, disables if equals EINA_FALSE. + */ +EAPI void +ecore_x_window_cursor_show(Ecore_X_Window win, + Eina_Bool show) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (win == 0) + win = DefaultRootWindow(_ecore_x_disp); + + if (!show) + { + Cursor c; + XColor cl; + Pixmap p, m; + GC gc; + XGCValues gcv; + + p = XCreatePixmap(_ecore_x_disp, win, 1, 1, 1); + m = XCreatePixmap(_ecore_x_disp, win, 1, 1, 1); + gc = XCreateGC(_ecore_x_disp, m, 0, &gcv); + XSetForeground(_ecore_x_disp, gc, 0); + XDrawPoint(_ecore_x_disp, m, gc, 0, 0); + XFreeGC(_ecore_x_disp, gc); + c = XCreatePixmapCursor(_ecore_x_disp, p, m, &cl, &cl, 0, 0); + XDefineCursor(_ecore_x_disp, win, c); + XFreeCursor(_ecore_x_disp, c); + XFreePixmap(_ecore_x_disp, p); + XFreePixmap(_ecore_x_disp, m); + } + else + XDefineCursor(_ecore_x_disp, win, 0); +} + +EAPI void +ecore_x_window_cursor_set(Ecore_X_Window win, + Ecore_X_Cursor c) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (c == 0) + XUndefineCursor(_ecore_x_disp, win); + else + XDefineCursor(_ecore_x_disp, win, c); +} + +/** + * Finds out whether the given window is currently visible. + * @param win The given window. + * @return 1 if the window is visible, otherwise 0. + * @ingroup Ecore_X_Window_Visibility_Group + */ +EAPI int +ecore_x_window_visible_get(Ecore_X_Window win) +{ + XWindowAttributes attr; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return XGetWindowAttributes(_ecore_x_disp, win, &attr) && + (attr.map_state == IsViewable); +} + +typedef struct _Shadow Shadow; +struct _Shadow +{ + Shadow *parent; + Shadow **children; + Window win; + int children_num; + short x, y; + unsigned short w, h; +}; + +static Shadow **shadow_base = NULL; +static int shadow_num = 0; + +static Shadow * +_ecore_x_window_tree_walk(Window win) +{ + Window *list = NULL; + Window parent_win = 0, root_win = 0; + unsigned int num; + Shadow *s, **sl; + XWindowAttributes att; + + if (!XGetWindowAttributes(_ecore_x_disp, win, &att)) + return NULL; // if (att.class == InputOnly) return NULL; + + if (att.map_state != IsViewable) + return NULL; + + s = calloc(1, sizeof(Shadow)); + if (!s) + return NULL; + + s->win = win; + s->x = att.x; + s->y = att.y; + s->w = att.width; + s->h = att.height; + if (XQueryTree(_ecore_x_disp, s->win, &root_win, &parent_win, + &list, &num)) + { + s->children = calloc(1, sizeof(Shadow *) * num); + if (s->children) + { + size_t i, j; + s->children_num = num; + for (i = 0; i < num; i++) + { + s->children[i] = _ecore_x_window_tree_walk(list[i]); + if (s->children[i]) + s->children[i]->parent = s; + } + /* compress list down */ + j = 0; + for (i = 0; i < num; i++) + { + if (s->children[i]) + { + s->children[j] = s->children[i]; + j++; + } + } + if (j == 0) + { + free(s->children); + s->children = NULL; + s->children_num = 0; + } + else + { + s->children_num = j; + sl = realloc(s->children, sizeof(Shadow *) * j); + if (sl) + s->children = sl; + } + } + } + + if (list) + XFree(list); + + return s; +} + +static void +_ecore_x_window_tree_shadow_free1(Shadow *s) +{ + int i; + + if (!s) + return; + + if (s->children) + { + for (i = 0; i < s->children_num; i++) + { + if (s->children[i]) + _ecore_x_window_tree_shadow_free1(s->children[i]); + } + free(s->children); + } + + free(s); +} + +static void +_ecore_x_window_tree_shadow_free(void) +{ + int i; + + if (!shadow_base) + return; + + for (i = 0; i < shadow_num; i++) + { + if (!shadow_base[i]) + continue; + + _ecore_x_window_tree_shadow_free1(shadow_base[i]); + } + free(shadow_base); + shadow_base = NULL; + shadow_num = 0; +} + +static void +_ecore_x_window_tree_shadow_populate(void) +{ + Ecore_X_Window *roots; + int i, num; + + roots = ecore_x_window_root_list(&num); + if (roots) + { + shadow_base = calloc(1, sizeof(Shadow *) * num); + if (shadow_base) + { + shadow_num = num; + for (i = 0; i < num; i++) + shadow_base[i] = _ecore_x_window_tree_walk(roots[i]); + } + + free(roots); + } +} + +/* + static int shadow_count = 0; + + static void + _ecore_x_window_tree_shadow_start(void) + { + shadow_count++; + if (shadow_count > 1) return; + _ecore_x_window_tree_shadow_populate(); + } + + static void + _ecore_x_window_tree_shadow_stop(void) + { + shadow_count--; + if (shadow_count != 0) return; + _ecore_x_window_tree_shadow_free(); + } + */ + +static Shadow * +_ecore_x_window_shadow_tree_find_shadow(Shadow *s, + Window win) +{ + Shadow *ss; + int i; + + if (s->win == win) + return s; + + if (s->children) + for (i = 0; i < s->children_num; i++) + { + if (!s->children[i]) + continue; + + if ((ss = + _ecore_x_window_shadow_tree_find_shadow(s->children[i], win))) + return ss; + } + + return NULL; +} + +static Shadow * +_ecore_x_window_shadow_tree_find(Window base) +{ + Shadow *s; + int i; + + for (i = 0; i < shadow_num; i++) + { + if (!shadow_base[i]) + continue; + + if ((s = _ecore_x_window_shadow_tree_find_shadow(shadow_base[i], base))) + return s; + } + return NULL; +} + +static int +_inside_rects(Shadow *s, + int x, + int y, + int bx, + int by, + Ecore_X_Rectangle *rects, + int num) +{ + int i, inside; + + if (!rects) return 0; + inside = 0; + for (i = 0; i < num; i++) + { + if ((x >= s->x + bx + rects[i].x) && + (y >= s->y + by + rects[i].y) && + (x < (int)(s->x + bx + rects[i].x + rects[i].width)) && + (y < (int)(s->y + by + rects[i].y + rects[i].height))) + { + inside = 1; + break; + } + } + free(rects); + return inside; +} + +static Window +_ecore_x_window_shadow_tree_at_xy_get_shadow(Shadow *s, + int bx, + int by, + int x, + int y, + Ecore_X_Window *skip, + int skip_num) +{ + Window child; + int i, j; + int wx, wy; + + wx = s->x + bx; + wy = s->y + by; + if (!((x >= wx) && (y >= wy) && (x < (wx + s->w)) && (y < (wy + s->h)))) + return 0; + + /* FIXME: get shape */ + { + int num; + Ecore_X_Rectangle *rects; + + num = 0; + rects = ecore_x_window_shape_rectangles_get(s->win, &num); + if (!_inside_rects(s, x, y, bx, by, rects, num)) return 0; + num = 0; + rects = ecore_x_window_shape_input_rectangles_get(s->win, &num); + if (!_inside_rects(s, x, y, bx, by, rects, num)) return 0; + } + + if (s->children) + { + int skipit = 0; + + for (i = s->children_num - 1; i >= 0; --i) + { + if (!s->children[i]) + continue; + + skipit = 0; + if (skip) + for (j = 0; j < skip_num; j++) + { + if (s->children[i]->win == skip[j]) + { + skipit = 1; + goto onward; + } + } + +onward: + if (!skipit) + if ((child = + _ecore_x_window_shadow_tree_at_xy_get_shadow(s-> + children[i + ], wx, wy, + x, y, skip, + skip_num))) + return child; + } + } + + return s->win; +} + +static Window +_ecore_x_window_shadow_tree_at_xy_get(Window base, + int bx, + int by, + int x, + int y, + Ecore_X_Window *skip, + int skip_num) +{ + Shadow *s; + + if (!shadow_base) + { + _ecore_x_window_tree_shadow_populate(); + if (!shadow_base) + return 0; + } + + s = _ecore_x_window_shadow_tree_find(base); + if (!s) + return 0; + + return _ecore_x_window_shadow_tree_at_xy_get_shadow(s, + bx, + by, + x, + y, + skip, + skip_num); +} + +/** + * Retrieves the top, visible window at the given location, + * but skips the windows in the list. This uses a shadow tree built from the + * window tree that is only updated the first time + * ecore_x_window_shadow_tree_at_xy_with_skip_get() is called, or the next time + * it is called after a ecore_x_window_shadow_tree_flush() + * @param base The base window to start searching from (normally root). + * @param x The given X position. + * @param y The given Y position. + * @param skip The list of windows to be skipped. + * @param skip_num The number of windows to be skipped. + * @return The window at that position. + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI Ecore_X_Window +ecore_x_window_shadow_tree_at_xy_with_skip_get(Ecore_X_Window base, + int x, + int y, + Ecore_X_Window *skip, + int skip_num) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return _ecore_x_window_shadow_tree_at_xy_get(base, + 0, + 0, + x, + y, + skip, + skip_num); +} + +/** + * Retrieves the parent window a given window has. This uses the shadow window + * tree. + * @param root The root window of @p win - if 0, this will be automatically determined with extra processing overhead + * @param win The window to get the parent window of + * @return The parent window of @p win + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI Ecore_X_Window +ecore_x_window_shadow_parent_get(Ecore_X_Window root __UNUSED__, + Ecore_X_Window win) +{ + Shadow *s; + int i; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!shadow_base) + { + _ecore_x_window_tree_shadow_populate(); + if (!shadow_base) + return 0; + } + + for (i = 0; i < shadow_num; i++) + { + if (!shadow_base[i]) + continue; + + s = _ecore_x_window_shadow_tree_find_shadow(shadow_base[i], win); + if (s) + { + if (!s->parent) + return 0; + + return s->parent->win; + } + } + return 0; +} + +/** + * Flushes the window shadow tree so nothing is stored. + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI void +ecore_x_window_shadow_tree_flush(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + _ecore_x_window_tree_shadow_free(); +} + +/** + * Retrieves the root window a given window is on. + * @param win The window to get the root window of + * @return The root window of @p win + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI Ecore_X_Window +ecore_x_window_root_get(Ecore_X_Window win) +{ + XWindowAttributes att; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!XGetWindowAttributes(_ecore_x_disp, win, &att)) + return 0; + + return att.root; +} + +static Window +_ecore_x_window_at_xy_get(Window base, + int bx, + int by, + int x, + int y, + Ecore_X_Window *skip, + int skip_num) +{ + Window *list = NULL; + Window parent_win = 0, child = 0, root_win = 0; + int i, j, wx, wy, ww, wh; + unsigned int num; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!ecore_x_window_visible_get(base)) + return 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_geometry_get(base, &wx, &wy, &ww, &wh); + wx += bx; + wy += by; + + if (!((x >= wx) && (y >= wy) && (x < (wx + ww)) && (y < (wy + wh)))) + return 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!XQueryTree(_ecore_x_disp, base, &root_win, &parent_win, &list, &num)) + return base; + + if (list) + { + int skipit = 0; + + for (i = num - 1; i >= 0; --i) + { + skipit = 0; + + if (skip) + for (j = 0; j < skip_num; j++) + { + if (list[i] == skip[j]) + { + skipit = 1; + goto onward; + } + } + +onward: + if (!skipit) + if ((child = + _ecore_x_window_at_xy_get(list[i], wx, wy, x, y, skip, + skip_num))) + { + XFree(list); + return child; + } + } + XFree(list); + } + + return base; +} + +/** + * Retrieves the top, visible window at the given location. + * @param x The given X position. + * @param y The given Y position. + * @return The window at that position. + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI Ecore_X_Window +ecore_x_window_at_xy_get(int x, + int y) +{ + Ecore_X_Window win, root; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + /* FIXME: Proper function to determine current root/virtual root + * window missing here */ + root = DefaultRootWindow(_ecore_x_disp); + + ecore_x_grab(); + win = _ecore_x_window_at_xy_get(root, 0, 0, x, y, NULL, 0); + ecore_x_ungrab(); + + return win ? win : root; +} + +/** + * Retrieves the top, visible window at the given location, + * but skips the windows in the list. + * @param x The given X position. + * @param y The given Y position. + * @param skip The list of windows to be skipped. + * @param skip_num The number of windows to be skipped. + * @return The window at that position. + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI Ecore_X_Window +ecore_x_window_at_xy_with_skip_get(int x, + int y, + Ecore_X_Window *skip, + int skip_num) +{ + Ecore_X_Window win, root; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + /* FIXME: Proper function to determine current root/virtual root + * window missing here */ + root = DefaultRootWindow(_ecore_x_disp); + + ecore_x_grab(); + win = _ecore_x_window_at_xy_get(root, 0, 0, x, y, skip, skip_num); + ecore_x_ungrab(); + + return win ? win : root; +} + +EAPI Ecore_X_Window +ecore_x_window_at_xy_begin_get(Ecore_X_Window begin, + int x, + int y) +{ + Ecore_X_Window win; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_grab(); + win = _ecore_x_window_at_xy_get(begin, 0, 0, x, y, NULL, 0); + ecore_x_ungrab(); + + return win ? win : begin; +} + +/** + * Retrieves the parent window of the given window. + * @param win The given window. + * @return The parent window of @p win. + * @ingroup Ecore_X_Window_Parent_Group + */ +EAPI Ecore_X_Window +ecore_x_window_parent_get(Ecore_X_Window win) +{ + Window root, parent, *children = NULL; + unsigned int num; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!XQueryTree(_ecore_x_disp, win, &root, &parent, &children, &num)) + return 0; + + if (children) + XFree(children); + + return parent; +} + +/** + * Sets the background color of the given window. + * @param win The given window + * @param r red value (0...65536, 16 bits) + * @param g green value (0...65536, 16 bits) + * @param b blue value (0...65536, 16 bits) + */ +EAPI void +ecore_x_window_background_color_set(Ecore_X_Window win, + unsigned short r, + unsigned short g, + unsigned short b) +{ + XSetWindowAttributes attr; + Colormap map; + XColor col; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + col.red = r; + col.green = g; + col.blue = b; + + map = DefaultColormap(_ecore_x_disp, DefaultScreen(_ecore_x_disp)); + XAllocColor(_ecore_x_disp, map, &col); + + attr.background_pixel = col.pixel; + XChangeWindowAttributes(_ecore_x_disp, win, CWBackPixel, &attr); +} + +EAPI void +ecore_x_window_gravity_set(Ecore_X_Window win, + Ecore_X_Gravity grav) +{ + XSetWindowAttributes att; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + att.win_gravity = grav; + XChangeWindowAttributes(_ecore_x_disp, win, CWWinGravity, &att); +} + +EAPI void +ecore_x_window_pixel_gravity_set(Ecore_X_Window win, + Ecore_X_Gravity grav) +{ + XSetWindowAttributes att; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + att.bit_gravity = grav; + XChangeWindowAttributes(_ecore_x_disp, win, CWBitGravity, &att); +} + +EAPI void +ecore_x_window_pixmap_set(Ecore_X_Window win, + Ecore_X_Pixmap pmap) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XSetWindowBackgroundPixmap(_ecore_x_disp, win, pmap); +} + +EAPI void +ecore_x_window_area_clear(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XClearArea(_ecore_x_disp, win, x, y, w, h, False); +} + +EAPI void +ecore_x_window_area_expose(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XClearArea(_ecore_x_disp, win, x, y, w, h, True); +} + +EAPI void +ecore_x_window_override_set(Ecore_X_Window win, + Eina_Bool override) +{ + XSetWindowAttributes att; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + att.override_redirect = override; + XChangeWindowAttributes(_ecore_x_disp, win, CWOverrideRedirect, &att); +} + +#ifdef ECORE_XRENDER +static Ecore_X_Window +_ecore_x_window_argb_internal_new(Ecore_X_Window parent, + int x, + int y, + int w, + int h, + Eina_Bool override, + Eina_Bool saveunder) +{ + Window win; + XSetWindowAttributes attr; + XWindowAttributes att; + XVisualInfo *xvi; + XVisualInfo vi_in; + int nvi, i, scr = 0; + XRenderPictFormat *fmt; + Visual *vis; + + if (parent == 0) + { + parent = DefaultRootWindow(_ecore_x_disp); + scr = DefaultScreen(_ecore_x_disp); + } + else + { + /* ewww - round trip */ + XGetWindowAttributes(_ecore_x_disp, parent, &att); + for (i = 0; i < ScreenCount(_ecore_x_disp); i++) + { + if (att.screen == ScreenOfDisplay(_ecore_x_disp, i)) + { + scr = i; + break; + } + } + } + + vi_in.screen = scr; + vi_in.depth = 32; + vi_in.class = TrueColor; + xvi = XGetVisualInfo(_ecore_x_disp, + VisualScreenMask | + VisualDepthMask | + VisualClassMask, + &vi_in, + &nvi); + if (!xvi) + return 0; + + vis = NULL; + for (i = 0; i < nvi; i++) + { + fmt = XRenderFindVisualFormat(_ecore_x_disp, xvi[i].visual); + if ((fmt->type == PictTypeDirect) && (fmt->direct.alphaMask)) + { + vis = xvi[i].visual; + break; + } + } + XFree (xvi); + + attr.backing_store = NotUseful; + attr.override_redirect = override; + attr.colormap = XCreateColormap(_ecore_x_disp, parent, + vis, AllocNone); + attr.border_pixel = 0; + attr.background_pixmap = None; + attr.bit_gravity = NorthWestGravity; + attr.win_gravity = NorthWestGravity; + attr.save_under = saveunder; + attr.do_not_propagate_mask = NoEventMask; + attr.event_mask = KeyPressMask | + KeyReleaseMask | + ButtonPressMask | + ButtonReleaseMask | + EnterWindowMask | + LeaveWindowMask | + PointerMotionMask | + ExposureMask | + VisibilityChangeMask | + StructureNotifyMask | + FocusChangeMask | + PropertyChangeMask | + ColormapChangeMask; + win = XCreateWindow(_ecore_x_disp, parent, + x, y, w, h, 0, + 32, + InputOutput, + vis, + CWBackingStore | + CWOverrideRedirect | + CWColormap | + CWBorderPixel | + CWBackPixmap | + CWSaveUnder | + CWDontPropagate | + CWEventMask | + CWBitGravity | + CWWinGravity, + &attr); + XFreeColormap(_ecore_x_disp, attr.colormap); + + if (parent == DefaultRootWindow(_ecore_x_disp)) + ecore_x_window_defaults_set(win); + + return win; +} + +#endif /* ifdef ECORE_XRENDER */ + +EAPI int +ecore_x_window_argb_get(Ecore_X_Window win) +{ +#ifdef ECORE_XRENDER + XWindowAttributes att; + XRenderPictFormat *fmt; + + att.visual = 0; + if (!XGetWindowAttributes(_ecore_x_disp, win, &att)) + return 0; + + fmt = XRenderFindVisualFormat(_ecore_x_disp, att.visual); + if (!fmt) + return 0; + + if ((fmt->type == PictTypeDirect) && (fmt->direct.alphaMask)) + return 1; + + return 0; +#else /* ifdef ECORE_XRENDER */ + return 0; +#endif /* ifdef ECORE_XRENDER */ +} + +/** + * Creates a new window. + * @param parent The parent window to use. If @p parent is @c 0, the root + * window of the default display is used. + * @param x X position. + * @param y Y position. + * @param w Width. + * @param h Height. + * @return The new window handle. + * @ingroup Ecore_X_Window_Create_Group + */ +EAPI Ecore_X_Window +ecore_x_window_manager_argb_new(Ecore_X_Window parent, + int x, + int y, + int w, + int h) +{ +#ifdef ECORE_XRENDER + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return _ecore_x_window_argb_internal_new(parent, x, y, w, h, 1, 0); +#else /* ifdef ECORE_XRENDER */ + return 0; +#endif /* ifdef ECORE_XRENDER */ +} + +/** + * Creates a new window. + * @param parent The parent window to use. If @p parent is @c 0, the root + * window of the default display is used. + * @param x X position. + * @param y Y position. + * @param w Width. + * @param h Height. + * @return The new window handle. + * @ingroup Ecore_X_Window_Create_Group + */ +EAPI Ecore_X_Window +ecore_x_window_argb_new(Ecore_X_Window parent, + int x, + int y, + int w, + int h) +{ +#ifdef ECORE_XRENDER + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return _ecore_x_window_argb_internal_new(parent, x, y, w, h, 0, 0); +#else /* ifdef ECORE_XRENDER */ + return 0; +#endif /* ifdef ECORE_XRENDER */ +} + +/** + * Creates a window with the override redirect attribute set to @c True. + * @param parent The parent window to use. If @p parent is @c 0, the root + * window of the default display is used. + * @param x X position. + * @param y Y position. + * @param w Width. + * @param h Height. + * @return The new window handle. + * @ingroup Ecore_X_Window_Create_Group + */ +EAPI Ecore_X_Window +ecore_x_window_override_argb_new(Ecore_X_Window parent, + int x, + int y, + int w, + int h) +{ +#ifdef ECORE_XRENDER + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return _ecore_x_window_argb_internal_new(parent, x, y, w, h, 1, 0); +#else /* ifdef ECORE_XRENDER */ + return 0; +#endif /* ifdef ECORE_XRENDER */ +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_window_prop.c b/src/lib/ecore_x/xlib/ecore_x_window_prop.c new file mode 100644 index 0000000..a582453 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_window_prop.c @@ -0,0 +1,760 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include +#include + +#include "Ecore.h" +#include "ecore_x_private.h" +#include "Ecore_X.h" +#include "Ecore_X_Atoms.h" +#include +#include + +#define _ATOM_SET_CARD32(win, atom, p_val, cnt) \ + XChangeProperty(_ecore_x_disp, win, atom, XA_CARDINAL, 32, PropModeReplace, \ + (unsigned char *)p_val, cnt) + +/* + * Set CARD32 (array) property + */ +EAPI void +ecore_x_window_prop_card32_set(Ecore_X_Window win, + Ecore_X_Atom atom, + unsigned int *val, + unsigned int num) +{ +#if SIZEOF_INT == SIZEOF_LONG + _ATOM_SET_CARD32(win, atom, val, num); +#else /* if SIZEOF_INT == SIZEOF_LONG */ + long *v2; + unsigned int i; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + v2 = malloc(num * sizeof(long)); + if (!v2) + return; + + for (i = 0; i < num; i++) + v2[i] = val[i]; + _ATOM_SET_CARD32(win, atom, v2, num); + free(v2); +#endif /* if SIZEOF_INT == SIZEOF_LONG */ +} + +/* + * Get CARD32 (array) property + * + * At most len items are returned in val. + * If the property was successfully fetched the number of items stored in + * val is returned, otherwise -1 is returned. + * Note: Return value 0 means that the property exists but has no elements. + */ +EAPI int +ecore_x_window_prop_card32_get(Ecore_X_Window win, + Ecore_X_Atom atom, + unsigned int *val, + unsigned int len) +{ + unsigned char *prop_ret; + Atom type_ret; + unsigned long bytes_after, num_ret; + int format_ret; + unsigned int i; + int num; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + prop_ret = NULL; + if (XGetWindowProperty(_ecore_x_disp, win, atom, 0, 0x7fffffff, False, + XA_CARDINAL, &type_ret, &format_ret, &num_ret, + &bytes_after, &prop_ret) != Success) + return -1; + + if (type_ret != XA_CARDINAL || format_ret != 32) + num = -1; + else if (num_ret == 0 || !prop_ret) + num = 0; + else + { + if (num_ret < len) + len = num_ret; + + for (i = 0; i < len; i++) + val[i] = ((unsigned long *)prop_ret)[i]; + num = len; + } + + if (prop_ret) + XFree(prop_ret); + + return num; +} + +/* + * Get CARD32 (array) property of any length + * + * If the property was successfully fetched the number of items stored in + * val is returned, otherwise -1 is returned. + * Note: Return value 0 means that the property exists but has no elements. + */ +EAPI int +ecore_x_window_prop_card32_list_get(Ecore_X_Window win, + Ecore_X_Atom atom, + unsigned int **plst) +{ + unsigned char *prop_ret; + Atom type_ret; + unsigned long bytes_after, num_ret; + int format_ret; + unsigned int i, *val; + int num; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + *plst = NULL; + prop_ret = NULL; + if (XGetWindowProperty(_ecore_x_disp, win, atom, 0, 0x7fffffff, False, + XA_CARDINAL, &type_ret, &format_ret, &num_ret, + &bytes_after, &prop_ret) != Success) + return -1; + + if ((type_ret != XA_CARDINAL) || (format_ret != 32)) + num = -1; + else if ((num_ret == 0) || (!prop_ret)) + num = 0; + else + { + val = malloc(num_ret * sizeof(unsigned int)); + if (!val) + { + if (prop_ret) XFree(prop_ret); + return -1; + } + for (i = 0; i < num_ret; i++) + val[i] = ((unsigned long *)prop_ret)[i]; + num = num_ret; + *plst = val; + } + + if (prop_ret) + XFree(prop_ret); + + return num; +} + +/* + * Set X ID (array) property + */ +EAPI void +ecore_x_window_prop_xid_set(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Atom type, + Ecore_X_ID *lst, + unsigned int num) +{ +#if SIZEOF_INT == SIZEOF_LONG + XChangeProperty(_ecore_x_disp, win, atom, type, 32, PropModeReplace, + (unsigned char *)lst, num); +#else /* if SIZEOF_INT == SIZEOF_LONG */ + unsigned long *pl; + unsigned int i; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + pl = malloc(num * sizeof(long)); + if (!pl) + return; + + for (i = 0; i < num; i++) + pl[i] = lst[i]; + XChangeProperty(_ecore_x_disp, win, atom, type, 32, PropModeReplace, + (unsigned char *)pl, num); + free(pl); +#endif /* if SIZEOF_INT == SIZEOF_LONG */ +} + +/* + * Get X ID (array) property + * + * At most len items are returned in val. + * If the property was successfully fetched the number of items stored in + * val is returned, otherwise -1 is returned. + * Note: Return value 0 means that the property exists but has no elements. + */ +EAPI int +ecore_x_window_prop_xid_get(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Atom type, + Ecore_X_ID *lst, + unsigned int len) +{ + unsigned char *prop_ret; + Atom type_ret; + unsigned long bytes_after, num_ret; + int format_ret; + int num; + unsigned i; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + prop_ret = NULL; + if (XGetWindowProperty(_ecore_x_disp, win, atom, 0, 0x7fffffff, False, + type, &type_ret, &format_ret, &num_ret, + &bytes_after, &prop_ret) != Success) + return -1; + + if (type_ret != type || format_ret != 32) + num = -1; + else if (num_ret == 0 || !prop_ret) + num = 0; + else + { + if (num_ret < len) + len = num_ret; + + for (i = 0; i < len; i++) + lst[i] = ((unsigned long *)prop_ret)[i]; + num = len; + } + + if (prop_ret) + XFree(prop_ret); + + return num; +} + +/* + * Get X ID (array) property + * + * If the property was successfully fetched the number of items stored in + * val is returned, otherwise -1 is returned. + * The returned array must be freed with free(). + * Note: Return value 0 means that the property exists but has no elements. + */ +EAPI int +ecore_x_window_prop_xid_list_get(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Atom type, + Ecore_X_ID **val) +{ + unsigned char *prop_ret; + Atom type_ret; + unsigned long bytes_after, num_ret; + int format_ret; + Ecore_X_Atom *alst; + int num; + unsigned i; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + *val = NULL; + prop_ret = NULL; + if (XGetWindowProperty(_ecore_x_disp, win, atom, 0, 0x7fffffff, False, + type, &type_ret, &format_ret, &num_ret, + &bytes_after, &prop_ret) != Success) + return -1; + + if (type_ret != type || format_ret != 32) + num = -1; + else if (num_ret == 0 || !prop_ret) + num = 0; + else + { + alst = malloc(num_ret * sizeof(Ecore_X_ID)); + for (i = 0; i < num_ret; i++) + alst[i] = ((unsigned long *)prop_ret)[i]; + num = num_ret; + *val = alst; + } + + if (prop_ret) + XFree(prop_ret); + + return num; +} + +/* + * Remove/add/toggle X ID list item. + */ +EAPI void +ecore_x_window_prop_xid_list_change(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Atom type, + Ecore_X_ID item, + int op) +{ + Ecore_X_ID *lst; + int i, num; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + num = ecore_x_window_prop_xid_list_get(win, atom, type, &lst); + if (num < 0) + { + return; /* Error - assuming invalid window */ + } + + /* Is it there? */ + for (i = 0; i < num; i++) + { + if (lst[i] == item) + break; + } + + if (i < num) + { + /* Was in list */ + if (op == ECORE_X_PROP_LIST_ADD) + goto done; /* Remove it */ + + num--; + for (; i < num; i++) + lst[i] = lst[i + 1]; + } + else + { + /* Was not in list */ + if (op == ECORE_X_PROP_LIST_REMOVE) + goto done; /* Add it */ + + num++; + lst = realloc(lst, num * sizeof(Ecore_X_ID)); + lst[i] = item; + } + + ecore_x_window_prop_xid_set(win, atom, type, lst, num); + +done: + if (lst) + free(lst); +} + +/* + * Set Atom (array) property + */ +EAPI void +ecore_x_window_prop_atom_set(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Atom *lst, + unsigned int num) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_xid_set(win, atom, XA_ATOM, lst, num); +} + +/* + * Get Atom (array) property + * + * At most len items are returned in val. + * If the property was successfully fetched the number of items stored in + * val is returned, otherwise -1 is returned. + * Note: Return value 0 means that the property exists but has no elements. + */ +EAPI int +ecore_x_window_prop_atom_get(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Atom *lst, + unsigned int len) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return ecore_x_window_prop_xid_get(win, atom, XA_ATOM, lst, len); +} + +/* + * Get Atom (array) property + * + * If the property was successfully fetched the number of items stored in + * val is returned, otherwise -1 is returned. + * The returned array must be freed with free(). + * Note: Return value 0 means that the property exists but has no elements. + */ +EAPI int +ecore_x_window_prop_atom_list_get(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Atom **plst) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return ecore_x_window_prop_xid_list_get(win, atom, XA_ATOM, plst); +} + +/* + * Remove/add/toggle atom list item. + */ +EAPI void +ecore_x_window_prop_atom_list_change(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Atom item, + int op) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_xid_list_change(win, atom, XA_ATOM, item, op); +} + +/* + * Set Window (array) property + */ +EAPI void +ecore_x_window_prop_window_set(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Window *lst, + unsigned int num) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_xid_set(win, atom, XA_WINDOW, lst, num); +} + +/* + * Get Window (array) property + * + * At most len items are returned in val. + * If the property was successfully fetched the number of items stored in + * val is returned, otherwise -1 is returned. + * Note: Return value 0 means that the property exists but has no elements. + */ +EAPI int +ecore_x_window_prop_window_get(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Window *lst, + unsigned int len) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return ecore_x_window_prop_xid_get(win, atom, XA_WINDOW, lst, len); +} + +/* + * Get Window (array) property + * + * If the property was successfully fetched the number of items stored in + * val is returned, otherwise -1 is returned. + * The returned array must be freed with free(). + * Note: Return value 0 means that the property exists but has no elements. + */ +EAPI int +ecore_x_window_prop_window_list_get(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Window **plst) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return ecore_x_window_prop_xid_list_get(win, atom, XA_WINDOW, plst); +} + +EAPI Ecore_X_Atom +ecore_x_window_prop_any_type(void) +{ + return AnyPropertyType; +} + +/** + * @brief Set a property of Ecore_X_Window. + * @param win The window for which the property will be set. + * @param property The property of the window to be set. + * @param type The type of the property that will be set. + * @param size The size of the property that will be set. + * @param data The data of the property that will be set. + * @param number The size of data. + */ +EAPI void +ecore_x_window_prop_property_set(Ecore_X_Window win, + Ecore_X_Atom property, + Ecore_X_Atom type, + int size, + void *data, + int number) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (win == 0) + win = DefaultRootWindow(_ecore_x_disp); + + if (size != 32) + XChangeProperty(_ecore_x_disp, + win, + property, + type, + size, + PropModeReplace, + (unsigned char *)data, + number); + else + { + unsigned long *dat; + int i, *ptr; + + dat = malloc(sizeof(unsigned long) * number); + if (dat) + { + for (ptr = (int *)data, i = 0; i < number; i++) + dat[i] = ptr[i]; + XChangeProperty(_ecore_x_disp, win, property, type, size, + PropModeReplace, (unsigned char *)dat, number); + free(dat); + } + } +} + +/** + * @brief Get a property of Ecore_X_Window. + * @note If there aren't any data to be got the function return NULL. + * If the function can't allocate the memory then 0 is returned. + * @param win The window for which the property will be got. + * @param property The property of the window that will be gotten. + * @param type The type of the property that will be gotten. + * @param size This parameter isn't in use. + * @param data The data of the property that will be gotten. + * @param num The size of property. + * @return size_ret The size of array that contains the property. + */ +EAPI int +ecore_x_window_prop_property_get(Ecore_X_Window win, + Ecore_X_Atom property, + Ecore_X_Atom type, + int size __UNUSED__, + unsigned char **data, + int *num) +{ + Atom type_ret = 0; + int ret, size_ret = 0; + unsigned long num_ret = 0, bytes = 0, i; + unsigned char *prop_ret = NULL; + + /* make sure these are initialized */ + if (num) + *num = 0; + + if (data) + *data = NULL; + else /* we can't store the retrieved data, so just return */ + return 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!win) + win = DefaultRootWindow(_ecore_x_disp); + + ret = XGetWindowProperty(_ecore_x_disp, win, property, 0, LONG_MAX, + False, type, &type_ret, &size_ret, + &num_ret, &bytes, &prop_ret); + + if (ret != Success) + return 0; + + if (!num_ret) + { + XFree(prop_ret); + return 0; + } + + if (!(*data = malloc(num_ret * size_ret / 8))) + { + XFree(prop_ret); + return 0; + } + + switch (size_ret) { + case 8: + for (i = 0; i < num_ret; i++) + (*data)[i] = prop_ret[i]; + break; + + case 16: + for (i = 0; i < num_ret; i++) + ((unsigned short *)*data)[i] = ((unsigned short *)prop_ret)[i]; + break; + + case 32: + for (i = 0; i < num_ret; i++) + ((unsigned int *)*data)[i] = ((unsigned long *)prop_ret)[i]; + break; + } + + XFree(prop_ret); + + if (num) + *num = num_ret; + + return size_ret; +} + +EAPI void +ecore_x_window_prop_property_del(Ecore_X_Window win, + Ecore_X_Atom property) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XDeleteProperty(_ecore_x_disp, win, property); +} + +EAPI Ecore_X_Atom * +ecore_x_window_prop_list(Ecore_X_Window win, + int *num_ret) +{ + Ecore_X_Atom *atoms; + Atom *atom_ret; + int num = 0, i; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (num_ret) + *num_ret = 0; + + atom_ret = XListProperties(_ecore_x_disp, win, &num); + if (!atom_ret) + return NULL; + + atoms = malloc(num * sizeof(Ecore_X_Atom)); + if (atoms) + { + for (i = 0; i < num; i++) + atoms[i] = atom_ret[i]; + if (num_ret) + *num_ret = num; + } + + XFree(atom_ret); + return atoms; +} + +/** + * Set a window string property. + * @param win The window + * @param type The property + * @param str The string + * + * Set a window string property + */ +EAPI void +ecore_x_window_prop_string_set(Ecore_X_Window win, + Ecore_X_Atom type, + const char *str) +{ + XTextProperty xtp; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (win == 0) + win = DefaultRootWindow(_ecore_x_disp); + + xtp.value = (unsigned char *)str; + xtp.format = 8; + xtp.encoding = ECORE_X_ATOM_UTF8_STRING; + xtp.nitems = strlen(str); + XSetTextProperty(_ecore_x_disp, win, &xtp, type); +} + +/** + * Get a window string property. + * @param win The window + * @param type The property + * @return Window string property of a window. String must be free'd when done. + */ +EAPI char * +ecore_x_window_prop_string_get(Ecore_X_Window win, + Ecore_X_Atom type) +{ + XTextProperty xtp; + char *str = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (win == 0) + win = DefaultRootWindow(_ecore_x_disp); + + if (XGetTextProperty(_ecore_x_disp, win, &xtp, type)) + { + int items; + char **list = NULL; + Status s; + + if (xtp.encoding == ECORE_X_ATOM_UTF8_STRING) + str = strdup((char *)xtp.value); + else + { +#ifdef X_HAVE_UTF8_STRING + s = Xutf8TextPropertyToTextList(_ecore_x_disp, &xtp, + &list, &items); +#else /* ifdef X_HAVE_UTF8_STRING */ + s = XmbTextPropertyToTextList(_ecore_x_disp, &xtp, + &list, &items); +#endif /* ifdef X_HAVE_UTF8_STRING */ + if ((s == XLocaleNotSupported) || + (s == XNoMemory) || (s == XConverterNotFound)) + str = strdup((char *)xtp.value); + else if ((s >= Success) && (items > 0)) + str = strdup(list[0]); + + if (list) + XFreeStringList(list); + } + + XFree(xtp.value); + } + + return str; +} + +EAPI Eina_Bool +ecore_x_window_prop_protocol_isset(Ecore_X_Window win, + Ecore_X_WM_Protocol protocol) +{ + Atom proto, *protos = NULL; + int i, protos_count = 0; + Eina_Bool ret = EINA_FALSE; + + /* check for invalid values */ + if (protocol >= ECORE_X_WM_PROTOCOL_NUM) + return EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + proto = _ecore_x_atoms_wm_protocols[protocol]; + + if (!XGetWMProtocols(_ecore_x_disp, win, &protos, &protos_count)) + return ret; + + for (i = 0; i < protos_count; i++) + if (protos[i] == proto) + { + ret = EINA_TRUE; + break; + } + + XFree(protos); + + return ret; +} + +/** + * @brief Get a array containing the protocols of @a win + * @note If there aren't any properties to be counted or any protocols to get + * then the function returns NULL. + * @param win The window for which protocol list will be got. + * @param num_ret Contains the number of elements of the array to be returned. + * @return The array that contains the protocols. + */ +EAPI Ecore_X_WM_Protocol * +ecore_x_window_prop_protocol_list_get(Ecore_X_Window win, + int *num_ret) +{ + Atom *protos = NULL; + int i, protos_count = 0; + Ecore_X_WM_Protocol *prot_ret = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!XGetWMProtocols(_ecore_x_disp, win, &protos, &protos_count)) + return NULL; + + if ((!protos) || (protos_count <= 0)) + return NULL; + + prot_ret = calloc(1, protos_count * sizeof(Ecore_X_WM_Protocol)); + if (!prot_ret) + { + XFree(protos); + return NULL; + } + + for (i = 0; i < protos_count; i++) + { + Ecore_X_WM_Protocol j; + + prot_ret[i] = -1; + for (j = 0; j < ECORE_X_WM_PROTOCOL_NUM; j++) + { + if (_ecore_x_atoms_wm_protocols[j] == protos[i]) + prot_ret[i] = j; + } + } + XFree(protos); + *num_ret = protos_count; + return prot_ret; +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_window_shape.c b/src/lib/ecore_x/xlib/ecore_x_window_shape.c new file mode 100644 index 0000000..71718cf --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_window_shape.c @@ -0,0 +1,658 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include + +#include "Ecore.h" +#include "ecore_x_private.h" +#include "Ecore_X.h" + +/** + * @defgroup Ecore_X_Window_Shape X Window Shape Functions + * + * These functions use the shape extension of the X server to change + * shape of given windows. + */ + +/** + * Sets the shape of the given window to that given by the pixmap @p mask. + * @param win The given window. + * @param mask A 2-bit depth pixmap that provides the new shape of the + * window. + * @ingroup Ecore_X_Window_Shape + */ +EAPI void +ecore_x_window_shape_mask_set(Ecore_X_Window win, + Ecore_X_Pixmap mask) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XShapeCombineMask(_ecore_x_disp, win, ShapeBounding, 0, 0, mask, ShapeSet); +} + +/** + * Sets the input shape of the given window to that given by the pixmap @p mask. + * @param win The given window. + * @param mask A 1-bit depth pixmap that provides the new input shape of the + * window. + * @ingroup Ecore_X_Window_Shape + */ +EAPI void +ecore_x_window_shape_input_mask_set(Ecore_X_Window win, + Ecore_X_Pixmap mask) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); +#ifdef ShapeInput + XShapeCombineMask(_ecore_x_disp, win, ShapeInput, 0, 0, mask, ShapeSet); +#else /* ifdef ShapeInput */ + return; + win = mask = 0; +#endif /* ifdef ShapeInput */ +} + +EAPI void +ecore_x_window_shape_window_set(Ecore_X_Window win, + Ecore_X_Window shape_win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XShapeCombineShape(_ecore_x_disp, + win, + ShapeBounding, + 0, + 0, + shape_win, + ShapeBounding, + ShapeSet); +} + +EAPI void +ecore_x_window_shape_input_window_set(Ecore_X_Window win, + Ecore_X_Window shape_win) +{ +#ifdef ShapeInput + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XShapeCombineShape(_ecore_x_disp, + win, + ShapeInput, + 0, + 0, + shape_win, + ShapeInput, + ShapeSet); +#else + return; + win = shape_win = 0; +#endif +} + +EAPI void +ecore_x_window_shape_window_set_xy(Ecore_X_Window win, + Ecore_X_Window shape_win, + int x, + int y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XShapeCombineShape(_ecore_x_disp, + win, + ShapeBounding, + x, + y, + shape_win, + ShapeBounding, + ShapeSet); +} + +EAPI void +ecore_x_window_shape_input_window_set_xy(Ecore_X_Window win, + Ecore_X_Window shape_win, + int x, + int y) +{ +#ifdef ShapeInput + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XShapeCombineShape(_ecore_x_disp, + win, + ShapeInput, + x, + y, + shape_win, + ShapeInput, + ShapeSet); +#else + return; + win = shape_win = x = y = 0; +#endif +} + +EAPI void +ecore_x_window_shape_rectangle_set(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ + XRectangle rect; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + XShapeCombineRectangles(_ecore_x_disp, + win, + ShapeBounding, + 0, + 0, + &rect, + 1, + ShapeSet, + Unsorted); +} + +EAPI void +ecore_x_window_shape_input_rectangle_set(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ +#ifdef ShapeInput + XRectangle rect; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + XShapeCombineRectangles(_ecore_x_disp, + win, + ShapeInput, + 0, + 0, + &rect, + 1, + ShapeSet, + Unsorted); +#else + return; + win = x = y = w = h = 0; +#endif +} + +EAPI void +ecore_x_window_shape_rectangles_set(Ecore_X_Window win, + Ecore_X_Rectangle *rects, + int num) +{ +#ifdef ShapeInput + XRectangle *rect = NULL; + int i; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!rects) return; + if (num > 0) + { + rect = malloc(sizeof(XRectangle) * num); + if (!rect) return; + for (i = 0; i < num; i++) + { + rect[i].x = rects[i].x; + rect[i].y = rects[i].y; + rect[i].width = rects[i].width; + rect[i].height = rects[i].height; + } + } + XShapeCombineRectangles(_ecore_x_disp, + win, + ShapeBounding, + 0, + 0, + rect, + num, + ShapeSet, + Unsorted); + if (rect) free(rect); +#else + return; + win = rects = num = 0; +#endif +} + +EAPI void +ecore_x_window_shape_input_rectangles_set(Ecore_X_Window win, + Ecore_X_Rectangle *rects, + int num) +{ +#ifdef ShapeInput + XRectangle *rect = NULL; + int i; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!rects) return; + if (num > 0) + { + rect = malloc(sizeof(XRectangle) * num); + if (!rect) return; + for (i = 0; i < num; i++) + { + rect[i].x = rects[i].x; + rect[i].y = rects[i].y; + rect[i].width = rects[i].width; + rect[i].height = rects[i].height; + } + } + XShapeCombineRectangles(_ecore_x_disp, + win, + ShapeInput, + 0, + 0, + rect, + num, + ShapeSet, + Unsorted); + if (rect) free(rect); +#else + return; + win = rects = num = 0; +#endif +} + +EAPI void +ecore_x_window_shape_rectangle_subtract(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ + XRectangle rect; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + XShapeCombineRectangles(_ecore_x_disp, + win, + ShapeBounding, + 0, + 0, + &rect, + 1, + ShapeSubtract, + Unsorted); +} + +EAPI void +ecore_x_window_shape_input_rectangle_subtract(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ +#ifdef ShapeInput + XRectangle rect; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + XShapeCombineRectangles(_ecore_x_disp, + win, + ShapeInput, + 0, + 0, + &rect, + 1, + ShapeSubtract, + Unsorted); +#else + return; + win = x = y = w = h = 0; +#endif +} + +EAPI void +ecore_x_window_shape_window_add(Ecore_X_Window win, + Ecore_X_Window shape_win) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XShapeCombineShape(_ecore_x_disp, + win, + ShapeBounding, + 0, + 0, + shape_win, + ShapeBounding, + ShapeUnion); +} + +EAPI void +ecore_x_window_shape_window_add_xy(Ecore_X_Window win, + Ecore_X_Window shape_win, + int x, + int y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XShapeCombineShape(_ecore_x_disp, + win, + ShapeBounding, + x, + y, + shape_win, + ShapeBounding, + ShapeUnion); +} + +EAPI void +ecore_x_window_shape_input_window_add_xy(Ecore_X_Window win, + Ecore_X_Window shape_win, + int x, + int y) +{ +#ifdef ShapeInput + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XShapeCombineShape(_ecore_x_disp, + win, + ShapeInput, + x, + y, + shape_win, + ShapeInput, + ShapeUnion); +#else + return; + win = shape_win = x = y = 0; +#endif +} + +EAPI void +ecore_x_window_shape_rectangle_add(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ + XRectangle rect; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + XShapeCombineRectangles(_ecore_x_disp, + win, + ShapeBounding, + 0, + 0, + &rect, + 1, + ShapeUnion, + Unsorted); +} + +EAPI void +ecore_x_window_shape_input_rectangle_add(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ +#ifdef ShapeInput + XRectangle rect; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + XShapeCombineRectangles(_ecore_x_disp, + win, + ShapeInput, + 0, + 0, + &rect, + 1, + ShapeUnion, + Unsorted); +#else + return; + win = x = y = w = h = 0; +#endif +} + +EAPI void +ecore_x_window_shape_rectangle_clip(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ + XRectangle rect; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + XShapeCombineRectangles(_ecore_x_disp, + win, + ShapeBounding, + 0, + 0, + &rect, + 1, + ShapeIntersect, + Unsorted); +} + +EAPI void +ecore_x_window_shape_input_rectangle_clip(Ecore_X_Window win, + int x, + int y, + int w, + int h) +{ +#ifdef ShapeInput + XRectangle rect; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + XShapeCombineRectangles(_ecore_x_disp, + win, + ShapeInput, + 0, + 0, + &rect, + 1, + ShapeIntersect, + Unsorted); +#else + return; + win = x = y = w = h = 0; +#endif +} + +EAPI void +ecore_x_window_shape_rectangles_add(Ecore_X_Window win, + Ecore_X_Rectangle *rects, + int num) +{ + XRectangle *rect = NULL; + int i; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (num > 0) + { + rect = malloc(sizeof(XRectangle) * num); + if (!rect) return; + for (i = 0; i < num; i++) + { + rect[i].x = rects[i].x; + rect[i].y = rects[i].y; + rect[i].width = rects[i].width; + rect[i].height = rects[i].height; + } + } + + XShapeCombineRectangles(_ecore_x_disp, + win, + ShapeBounding, + 0, + 0, + rect, + num, + ShapeUnion, + Unsorted); + if (rect) free(rect); +} + +EAPI void +ecore_x_window_shape_input_rectangles_add(Ecore_X_Window win, + Ecore_X_Rectangle *rects, + int num) +{ +#ifdef ShapeInput + XRectangle *rect = NULL; + int i; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (num > 0) + { + rect = malloc(sizeof(XRectangle) * num); + if (!rect) return; + for (i = 0; i < num; i++) + { + rect[i].x = rects[i].x; + rect[i].y = rects[i].y; + rect[i].width = rects[i].width; + rect[i].height = rects[i].height; + } + } + + XShapeCombineRectangles(_ecore_x_disp, + win, + ShapeInput, + 0, + 0, + rect, + num, + ShapeUnion, + Unsorted); + if (rect) free(rect); +#else + return; + win = rects = num = 0; +#endif +} + +EAPI Ecore_X_Rectangle * +ecore_x_window_shape_rectangles_get(Ecore_X_Window win, + int *num_ret) +{ + XRectangle *rect; + Ecore_X_Rectangle *rects = NULL; + int i, num = 0, ord; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + rect = XShapeGetRectangles(_ecore_x_disp, win, ShapeBounding, &num, &ord); + if (rect) + { + if (num < 1) + { + XFree(rect); + if (num_ret) *num_ret = 0; + return NULL; + } + rects = malloc(sizeof(Ecore_X_Rectangle) * num); + if (!rects) + { + XFree(rect); + if (num_ret) *num_ret = 0; + return NULL; + } + for (i = 0; i < num; i++) + { + rects[i].x = rect[i].x; + rects[i].y = rect[i].y; + rects[i].width = rect[i].width; + rects[i].height = rect[i].height; + } + XFree(rect); + } + if (num_ret) *num_ret = num; + return rects; +} + +EAPI Ecore_X_Rectangle * +ecore_x_window_shape_input_rectangles_get(Ecore_X_Window win, + int *num_ret) +{ + Ecore_X_Rectangle *rects = NULL; +#ifdef ShapeInput + XRectangle *rect; + int i, num = 0, ord; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + rect = XShapeGetRectangles(_ecore_x_disp, win, ShapeInput, &num, &ord); + if (rect) + { + if (num < 1) + { + XFree(rect); + if (num_ret) *num_ret = 0; + return NULL; + } + rects = malloc(sizeof(Ecore_X_Rectangle) * num); + if (!rects) + { + XFree(rect); + if (num_ret) *num_ret = 0; + return NULL; + } + for (i = 0; i < num; i++) + { + rects[i].x = rect[i].x; + rects[i].y = rect[i].y; + rects[i].width = rect[i].width; + rects[i].height = rect[i].height; + } + XFree(rect); + } + if (num_ret) *num_ret = num; + return rects; +#else + // have to return fake shape input rect of size of window + Window dw; + unsigned int di; + + if (num_ret) *num_ret = 0; + rects = malloc(sizeof(Ecore_X_Rectangle)); + if (!rects) return NULL; + if (!XGetGeometry(_ecore_x_disp, win, &dw, + &(rects[0].x), &(rects[0].y), + &(rects[0].width), &(rects[0].height), + &di, &di)) + { + free(rects); + return NULL; + } + if (num_ret) *num_ret = 1; + return rects; +#endif +} + +EAPI void +ecore_x_window_shape_events_select(Ecore_X_Window win, + Eina_Bool on) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (on) + XShapeSelectInput(_ecore_x_disp, win, ShapeNotifyMask); + else + XShapeSelectInput(_ecore_x_disp, win, 0); +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_xi2.c b/src/lib/ecore_x/xlib/ecore_x_xi2.c new file mode 100644 index 0000000..fbfbd43 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_xi2.c @@ -0,0 +1,283 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include + +#include "Ecore.h" +#include "ecore_x_private.h" +#include "Ecore_X.h" + +#ifdef ECORE_XI2 +#include "Ecore_Input.h" +#endif /* ifdef ECORE_XI2 */ + +int _ecore_x_xi2_opcode = -1; + +#ifndef XIPointerEmulated +#define XIPointerEmulated (1 << 16) +#endif + +#ifdef ECORE_XI2 +static XIDeviceInfo *_ecore_x_xi2_devs = NULL; +static int _ecore_x_xi2_num = 0; +#endif /* ifdef ECORE_XI2 */ + +void +_ecore_x_input_init(void) +{ +#ifdef ECORE_XI2 + int event, error; + int major = 2, minor = 0; + + if (!XQueryExtension(_ecore_x_disp, "XInputExtension", + &_ecore_x_xi2_opcode, &event, &error)) + { + _ecore_x_xi2_opcode = -1; + return; + } + + if (XIQueryVersion(_ecore_x_disp, &major, &minor) == BadRequest) + { + _ecore_x_xi2_opcode = -1; + return; + } + + _ecore_x_xi2_devs = XIQueryDevice(_ecore_x_disp, XIAllDevices, + &_ecore_x_xi2_num); +#endif /* ifdef ECORE_XI2 */ +} + +void +_ecore_x_input_shutdown(void) +{ +#ifdef ECORE_XI2 + if (_ecore_x_xi2_devs) + { + XIFreeDeviceInfo(_ecore_x_xi2_devs); + _ecore_x_xi2_devs = NULL; + } + + _ecore_x_xi2_num = 0; + _ecore_x_xi2_opcode = -1; +#endif /* ifdef ECORE_XI2 */ +} + +void +_ecore_x_input_handler(XEvent *xevent) +{ +#ifdef ECORE_XI2 + XIDeviceEvent *evd = (XIDeviceEvent *)(xevent->xcookie.data); + int devid = evd->deviceid; + int i; + + if (_ecore_x_xi2_devs) + { + for (i = 0; i < _ecore_x_xi2_num; i++) + { + XIDeviceInfo *dev = &(_ecore_x_xi2_devs[i]); + + if (devid == dev->deviceid) + { + if (dev->use == XIMasterPointer) return; + if ((dev->use == XISlavePointer) && + (evd->flags & XIPointerEmulated)) return; + } + } + } + switch (xevent->xcookie.evtype) + { + case XI_Motion: + _ecore_mouse_move + (evd->time, + 0, // state + evd->event_x, evd->event_y, + evd->root_x, evd->root_y, + evd->event, + (evd->child ? evd->child : evd->event), + evd->root, + 1, // same_screen + devid, 1, 1, + 1.0, // pressure + 0.0, // angle + evd->event_x, evd->event_y, + evd->root_x, evd->root_y); + break; + + case XI_ButtonPress: + _ecore_mouse_button + (ECORE_EVENT_MOUSE_BUTTON_DOWN, + evd->time, + 0, // state + 0, // button + evd->event_x, evd->event_y, + evd->root_x, evd->root_y, + evd->event, + (evd->child ? evd->child : evd->event), + evd->root, + 1, // same_screen + devid, 1, 1, + 1.0, // pressure + 0.0, // angle + evd->event_x, evd->event_y, + evd->root_x, evd->root_y); + break; + + case XI_ButtonRelease: + _ecore_mouse_button + (ECORE_EVENT_MOUSE_BUTTON_UP, + evd->time, + 0, // state + 0, // button + evd->event_x, evd->event_y, + evd->root_x, evd->root_y, + evd->event, + (evd->child ? evd->child : evd->event), + evd->root, + 1, // same_screen + devid, 1, 1, + 1.0, // pressure + 0.0, // angle + evd->event_x, evd->event_y, + evd->root_x, evd->root_y); + break; + +#ifdef XI_TouchUpdate + case XI_TouchUpdate: + _ecore_mouse_move + (evd->time, + 0, // state + evd->event_x, evd->event_y, + evd->root_x, evd->root_y, + evd->event, + (evd->child ? evd->child : evd->event), + evd->root, + 1, // same_screen + devid, 1, 1, + 1.0, // pressure + 0.0, // angle + evd->event_x, evd->event_y, + evd->root_x, evd->root_y); + break; + +#endif +#ifdef XI_TouchBegin + case XI_TouchBegin: + _ecore_mouse_button + (ECORE_EVENT_MOUSE_BUTTON_DOWN, + evd->time, + 0, // state + 0, // button + evd->event_x, evd->event_y, + evd->root_x, evd->root_y, + evd->event, + (evd->child ? evd->child : evd->event), + evd->root, + 1, // same_screen + devid, 1, 1, + 1.0, // pressure + 0.0, // angle + evd->event_x, evd->event_y, + evd->root_x, evd->root_y); + break; + +#endif +#ifdef XI_TouchEnd + case XI_TouchEnd: + _ecore_mouse_button + (ECORE_EVENT_MOUSE_BUTTON_UP, + evd->time, + 0, // state + 0, // button + evd->event_x, evd->event_y, + evd->root_x, evd->root_y, + evd->event, + (evd->child ? evd->child : evd->event), + evd->root, + 1, // same_screen + devid, 1, 1, + 1.0, // pressure + 0.0, // angle + evd->event_x, evd->event_y, + evd->root_x, evd->root_y); + break; + +#endif + default: + break; + } +#endif /* ifdef ECORE_XI2 */ +} + +EAPI Eina_Bool +ecore_x_input_multi_select(Ecore_X_Window win) +{ +#ifdef ECORE_XI2 + int i; + Eina_Bool find = EINA_FALSE; + + if (!_ecore_x_xi2_devs) + return 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + for (i = 0; i < _ecore_x_xi2_num; i++) + { + XIDeviceInfo *dev = &(_ecore_x_xi2_devs[i]); + + if (dev->use == XIFloatingSlave) + { + XIEventMask eventmask; + unsigned char mask[4] = { 0 }; + + eventmask.deviceid = dev->deviceid; + eventmask.mask_len = sizeof(mask); + eventmask.mask = mask; + XISetMask(mask, XI_ButtonPress); + XISetMask(mask, XI_ButtonRelease); + XISetMask(mask, XI_Motion); + XISelectEvents(_ecore_x_disp, win, &eventmask, 1); + find = EINA_TRUE; + } + else if (dev->use == XISlavePointer) + { + XIDeviceInfo *atdev = NULL; + int j; + + for (j = 0; j < _ecore_x_xi2_num; j++) + { + if (_ecore_x_xi2_devs[j].deviceid == dev->attachment) + atdev = &(_ecore_x_xi2_devs[j]); + } + if (((atdev) && (atdev->use != XIMasterPointer)) || + (!atdev)) + { + XIEventMask eventmask; + unsigned char mask[4] = { 0 }; + + eventmask.deviceid = dev->deviceid; + eventmask.mask_len = sizeof(mask); + eventmask.mask = mask; + XISetMask(mask, XI_ButtonPress); + XISetMask(mask, XI_ButtonRelease); + XISetMask(mask, XI_Motion); +# ifdef XI_TouchUpdate + XISetMask(mask, XI_TouchUpdate); +# endif +# ifdef XI_TouchBegin + XISetMask(mask, XI_TouchBegin); +# endif +# ifdef XI_TouchEnd + XISetMask(mask, XI_TouchEnd); +# endif + XISelectEvents(_ecore_x_disp, win, &eventmask, 1); + find = EINA_TRUE; + } + } + } + + return find; +#else /* ifdef ECORE_XI2 */ + return EINA_FALSE; +#endif /* ifdef ECORE_XI2 */ +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_xinerama.c b/src/lib/ecore_x/xlib/ecore_x_xinerama.c new file mode 100644 index 0000000..f49a4d3 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_xinerama.c @@ -0,0 +1,91 @@ +/* + * Xinerama code + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include "Ecore.h" +#include "ecore_x_private.h" +#include "Ecore_X.h" +#include "Ecore_X_Atoms.h" + +#ifdef ECORE_XINERAMA +static XineramaScreenInfo *_xin_info = NULL; +static int _xin_scr_num = 0; +#endif /* ifdef ECORE_XINERAMA */ + +EAPI int +ecore_x_xinerama_screen_count_get(void) +{ +#ifdef ECORE_XINERAMA + int event_base, error_base; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (_xin_info) + XFree(_xin_info); + + _xin_info = NULL; + if (XineramaQueryExtension(_ecore_x_disp, &event_base, &error_base)) + { + _xin_info = XineramaQueryScreens(_ecore_x_disp, &_xin_scr_num); + if (_xin_info) + return _xin_scr_num; + } + +#endif /* ifdef ECORE_XINERAMA */ + return 0; +} + +EAPI Eina_Bool +ecore_x_xinerama_screen_geometry_get(int screen, + int *x, + int *y, + int *w, + int *h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); +#ifdef ECORE_XINERAMA + if (_xin_info) + { + int i; + + for (i = 0; i < _xin_scr_num; i++) + { + if (_xin_info[i].screen_number == screen) + { + if (x) + *x = _xin_info[i].x_org; + + if (y) + *y = _xin_info[i].y_org; + + if (w) + *w = _xin_info[i].width; + + if (h) + *h = _xin_info[i].height; + + return EINA_TRUE; + } + } + } + +#endif /* ifdef ECORE_XINERAMA */ + if (x) + *x = 0; + + if (y) + *y = 0; + + if (w) + *w = DisplayWidth(_ecore_x_disp, 0); + + if (h) + *h = DisplayHeight(_ecore_x_disp, 0); + + return EINA_FALSE; + screen = 0; +} + diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am new file mode 100644 index 0000000..99a1469 --- /dev/null +++ b/src/modules/Makefile.am @@ -0,0 +1,3 @@ +MAINTAINERCLEANFILES = Makefile.in + +SUBDIRS = immodules diff --git a/src/modules/immodules/Makefile.am b/src/modules/immodules/Makefile.am new file mode 100644 index 0000000..22b6496 --- /dev/null +++ b/src/modules/immodules/Makefile.am @@ -0,0 +1,15 @@ +MAINTAINERCLEANFILES = Makefile.in + +SUBDIRS = + +if BUILD_ECORE_IMF_XIM +SUBDIRS += xim +endif + +if BUILD_ECORE_IMF_SCIM +SUBDIRS += scim +endif + +if BUILD_ECORE_IMF_IBUS +SUBDIRS += ibus +endif diff --git a/src/modules/immodules/ibus/Makefile.am b/src/modules/immodules/ibus/Makefile.am new file mode 100644 index 0000000..a59b5e8 --- /dev/null +++ b/src/modules/immodules/ibus/Makefile.am @@ -0,0 +1,36 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CFLAGS = \ +-I$(top_srcdir) \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore_input \ +-I$(top_srcdir)/src/lib/ecore_x \ +-I$(top_srcdir)/src/lib/ecore_imf \ +-I$(top_srcdir)/src/lib/ecore_evas \ +-I$(top_builddir)/src/lib/ecore \ +-I$(top_builddir)/src/lib/ecore_input \ +-I$(top_builddir)/src/lib/ecore_x \ +-I$(top_builddir)/src/lib/ecore_imf \ +-I$(top_builddir)/src/lib/ecore_evas \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \ +@IBUS_CFLAGS@ \ +@EVAS_CFLAGS@ \ +@EINA_CFLAGS@ + +pkgdir = $(libdir)/ecore/immodules + +pkg_LTLIBRARIES = ibus.la +ibus_la_SOURCES = \ +ibus_module.c \ +ibus_imcontext.c \ +ibus_imcontext.h + +ibus_la_LIBADD = \ + $(top_builddir)/src/lib/ecore_imf/libecore_imf.la \ + $(top_builddir)/src/lib/ecore_x/libecore_x.la \ + @IBUS_LIBS@ \ + @EVAS_LIBS@ \ + @EINA_LIBS@ +ibus_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version +ibus_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/src/modules/immodules/ibus/ibus_imcontext.c b/src/modules/immodules/ibus/ibus_imcontext.c new file mode 100644 index 0000000..2c2e180 --- /dev/null +++ b/src/modules/immodules/ibus/ibus_imcontext.c @@ -0,0 +1,820 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include "ibus_imcontext.h" + +struct _IBusIMContext +{ + /* instance members */ + Ecore_IMF_Context *ctx; + + /* enabled */ + Eina_Bool enable; + IBusInputContext *ibuscontext; + + /* preedit status */ + char *preedit_string; + Eina_List *preedit_attrs; + int preedit_cursor_pos; + Eina_Bool preedit_visible; + + int cursor_x; + int cursor_y; + int cursor_w; + int cursor_h; + + Eina_Bool has_focus; + + Ecore_X_Window client_window; + Evas *client_canvas; + + int caps; +}; + +typedef struct _KeyEvent KeyEvent; + +struct _KeyEvent +{ + int keysym; + int state; +}; + +static Eina_Bool _use_sync_mode = EINA_FALSE; + +static Ecore_IMF_Context *_focus_im_context = NULL; +static IBusBus *_bus = NULL; + +/* functions prototype */ +/* static methods*/ +static void _create_input_context (IBusIMContext *context); +static void _set_cursor_location_internal +(Ecore_IMF_Context *ctx); +static void _bus_connected_cb (IBusBus *bus, + IBusIMContext *context); +static XKeyEvent createXKeyEvent (Window win, Eina_Bool press, int keysym, int modifiers); + +static void +_window_to_screen_geometry_get(Ecore_X_Window client_win, int *x, int *y) +{ + Ecore_X_Window root_window, win; + int win_x, win_y; + int sum_x = 0, sum_y = 0; + + root_window = ecore_x_window_root_get(client_win); + win = client_win; + + while (root_window != win) + { + ecore_x_window_geometry_get(win, &win_x, &win_y, NULL, NULL); + sum_x += win_x; + sum_y += win_y; + win = ecore_x_window_parent_get(win); + } + + if (x) + *x = sum_x; + if (y) + *y = sum_y; +} + +static unsigned int +_ecore_imf_modifier_to_ibus_modifier(unsigned int modifier) +{ + unsigned int state = 0; + + /**< "Control" is pressed */ + if (modifier & ECORE_IMF_KEYBOARD_MODIFIER_CTRL) + state |= IBUS_CONTROL_MASK; + + /**< "Alt" is pressed */ + if (modifier & ECORE_IMF_KEYBOARD_MODIFIER_ALT) + state |= IBUS_MOD1_MASK; + + /**< "Shift" is pressed */ + if (modifier & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT) + state |= IBUS_SHIFT_MASK; + + /**< "Win" (between "Ctrl" and "Alt") */ + if (modifier & ECORE_IMF_KEYBOARD_MODIFIER_WIN) + state |= IBUS_SUPER_MASK; + + /**< "AltGr" is pressed */ + if (modifier & ECORE_IMF_KEYBOARD_MODIFIER_ALTGR) + state |= IBUS_MOD5_MASK; + + return state; +} + +static void +key_event_put(int keysym, int state) +{ + // Find the window which has the current keyboard focus. + Window winFocus = 0; + int revert = RevertToParent; + + XGetInputFocus(ecore_x_display_get(), &winFocus, &revert); + + XKeyEvent event; + if (state & IBUS_RELEASE_MASK) + { + event = createXKeyEvent(winFocus, EINA_FALSE, keysym, state); + XSendEvent(event.display, event.window, True, KeyReleaseMask, (XEvent *)&event); + } + else + { + event = createXKeyEvent(winFocus, EINA_TRUE, keysym, state); + XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event); + } +} + +static KeyEvent * +key_event_copy(int keysym, int state) +{ + KeyEvent *kev = calloc(1, sizeof(KeyEvent)); + kev->keysym = keysym; + kev->state = state; + + return kev; +} + +IBusIMContext * +ibus_im_context_new(void) +{ + EINA_LOG_DBG("%s", __FUNCTION__); + + IBusIMContext *context = calloc(1, sizeof(IBusIMContext)); + + /* init bus object */ + if (_bus == NULL) + { + char *display_name = NULL; + + if ((display_name = getenv("DISPLAY"))) + ibus_set_display(display_name); + else + ibus_set_display(":0.0"); + + _bus = ibus_bus_new(); + } + + return context; +} + +static void +_process_key_event_done (GObject *object, + GAsyncResult *res, + gpointer user_data) +{ + IBusInputContext *context = (IBusInputContext *)object; + KeyEvent *event = (KeyEvent *)user_data; + + GError *error = NULL; + Eina_Bool retval = ibus_input_context_process_key_event_async_finish(context, + res, + &error); + + if (error != NULL) + { + g_warning("Process Key Event failed: %s.", error->message); + g_error_free(error); + } + + if (retval == EINA_FALSE) + { + key_event_put(event->keysym, event->state); + } + free(event); +} + +EAPI void +ibus_im_context_add(Ecore_IMF_Context *ctx) +{ + EINA_LOG_DBG("%s", __FUNCTION__); + + char *s = NULL; + IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(ibusimcontext); + + ibusimcontext->client_window = 0; + + // Init ibus status + ibusimcontext->enable = EINA_FALSE; + + // Init preedit status + ibusimcontext->preedit_string = NULL; + ibusimcontext->preedit_attrs = NULL; + ibusimcontext->preedit_cursor_pos = 0; + ibusimcontext->preedit_visible = EINA_FALSE; + + // Init cursor area + ibusimcontext->cursor_x = -1; + ibusimcontext->cursor_y = -1; + ibusimcontext->cursor_w = 0; + ibusimcontext->cursor_h = 0; + + ibusimcontext->ibuscontext = NULL; + ibusimcontext->has_focus = EINA_FALSE; + ibusimcontext->caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS | IBUS_CAP_SURROUNDING_TEXT; + ibusimcontext->ctx = ctx; + + s = getenv("IBUS_ENABLE_SYNC_MODE"); + if (s) + _use_sync_mode = !!atoi(s); + + if (ibus_bus_is_connected(_bus)) + _create_input_context (ibusimcontext); + + g_signal_connect(_bus, "connected", G_CALLBACK (_bus_connected_cb), ctx); +} + +EAPI void +ibus_im_context_del(Ecore_IMF_Context *ctx) +{ + EINA_LOG_DBG("%s", __FUNCTION__); + + IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(ibusimcontext); + + g_signal_handlers_disconnect_by_func(_bus, G_CALLBACK(_bus_connected_cb), ctx); + + if (ibusimcontext->ibuscontext) + ibus_proxy_destroy((IBusProxy *)ibusimcontext->ibuscontext); + + // release preedit + if (ibusimcontext->preedit_string) + free(ibusimcontext->preedit_string); +} + +EAPI Eina_Bool +ibus_im_context_filter_event(Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event) +{ + IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN_VAL(ibusimcontext, EINA_FALSE); + + if (type != ECORE_IMF_EVENT_KEY_UP && type != ECORE_IMF_EVENT_KEY_DOWN) + return EINA_FALSE; + + EINA_LOG_DBG("%s", __FUNCTION__); + + if (G_LIKELY(ibusimcontext->ibuscontext && ibusimcontext->has_focus)) + { + /* If context does not have focus, ibus will process key event in sync mode. + * It is a workaround for increase search in treeview. + */ + Eina_Bool retval = EINA_FALSE; + int keycode; + int keysym; + unsigned int state = 0; + + if (type == ECORE_IMF_EVENT_KEY_UP) + { + Ecore_IMF_Event_Key_Up *ev = (Ecore_IMF_Event_Key_Up *)event; + if (ev->timestamp == 0) + return EINA_FALSE; + + keycode = ecore_x_keysym_keycode_get(ev->key); + keysym = XStringToKeysym(ev->key); + state = _ecore_imf_modifier_to_ibus_modifier(ev->modifiers) | IBUS_RELEASE_MASK; + + if (_use_sync_mode) + { + retval = ibus_input_context_process_key_event(ibusimcontext->ibuscontext, + keysym, + keycode - 8, + state); + } + else + { + ibus_input_context_process_key_event_async(ibusimcontext->ibuscontext, + keysym, + keycode - 8, + state, + -1, + NULL, + _process_key_event_done, + key_event_copy(keysym, state)); + retval = EINA_TRUE; + } + } + else if (type == ECORE_IMF_EVENT_KEY_DOWN) + { + Ecore_IMF_Event_Key_Down *ev = (Ecore_IMF_Event_Key_Down *)event; + if (ev->timestamp == 0) + return EINA_FALSE; + + keycode = ecore_x_keysym_keycode_get(ev->key); + keysym = XStringToKeysym(ev->key); + state = _ecore_imf_modifier_to_ibus_modifier(ev->modifiers); + if (_use_sync_mode) + { + retval = ibus_input_context_process_key_event(ibusimcontext->ibuscontext, + keysym, + keycode - 8, + state); + } + else + { + ibus_input_context_process_key_event_async(ibusimcontext->ibuscontext, + keysym, + keycode - 8, + state, + -1, + NULL, + _process_key_event_done, + key_event_copy(keysym, state)); + retval = EINA_TRUE; + } + } + else + retval = EINA_FALSE; + + if (retval) + return EINA_TRUE; + else + return EINA_FALSE; + } + else + return EINA_FALSE; +} + +EAPI void +ibus_im_context_focus_in(Ecore_IMF_Context *ctx) +{ + EINA_LOG_DBG("ctx : %p", ctx); + + IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(ibusimcontext); + + if (ibusimcontext->has_focus) + return; + + if (_focus_im_context != NULL) + ecore_imf_context_focus_out(_focus_im_context); + + ibusimcontext->has_focus = EINA_TRUE; + if (ibusimcontext->ibuscontext) + ibus_input_context_focus_in(ibusimcontext->ibuscontext); + + if (_focus_im_context != ctx) + _focus_im_context = ctx; +} + +EAPI void +ibus_im_context_focus_out(Ecore_IMF_Context *ctx) +{ + EINA_LOG_DBG("ctx : %p", ctx); + + IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(ibusimcontext); + + if (ibusimcontext->has_focus == EINA_FALSE) + return; + + if (_focus_im_context == ctx) + _focus_im_context = NULL; + + ibusimcontext->has_focus = EINA_FALSE; + if (ibusimcontext->ibuscontext) + ibus_input_context_focus_out(ibusimcontext->ibuscontext); +} + +EAPI void +ibus_im_context_reset(Ecore_IMF_Context *ctx) +{ + IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(ibusimcontext); + + if (ibusimcontext->ibuscontext) + ibus_input_context_reset(ibusimcontext->ibuscontext); +} + +EAPI void +ibus_im_context_preedit_string_get(Ecore_IMF_Context *ctx, + char **str, + int *cursor_pos) +{ + IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(ibusimcontext); + + if (ibusimcontext->enable && ibusimcontext->preedit_visible) + { + if (str) + *str = strdup(ibusimcontext->preedit_string ? ibusimcontext->preedit_string: ""); + + if (cursor_pos) + *cursor_pos = ibusimcontext->preedit_cursor_pos; + } + else + { + if (str) + *str = strdup(""); + + if (cursor_pos) + *cursor_pos = 0; + } + EINA_LOG_DBG("str : %s, cursor_pos : %d", *str, *cursor_pos); +} + +EAPI void +ibus_im_context_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx, + char **str, + Eina_List **attr __UNUSED__, + int *cursor_pos) +{ + IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(ibusimcontext); + + if (ibusimcontext->enable && ibusimcontext->preedit_visible) + { + if (str) + *str = strdup(ibusimcontext->preedit_string ? ibusimcontext->preedit_string: ""); + + if (cursor_pos) + *cursor_pos = ibusimcontext->preedit_cursor_pos; + } + else + { + if (str) + *str = strdup(""); + + if (cursor_pos) + *cursor_pos = 0; + } + EINA_LOG_DBG("str : %s, cursor_pos : %d", *str, *cursor_pos); +} + +EAPI void +ibus_im_context_client_window_set(Ecore_IMF_Context *ctx, void *window) +{ + EINA_LOG_DBG("canvas : %p", window); + IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(ibusimcontext); + + if (window != NULL) + ibusimcontext->client_window = (Ecore_X_Window)(Ecore_Window)window; +} + +EAPI void +ibus_im_context_client_canvas_set(Ecore_IMF_Context *ctx, void *canvas) +{ + EINA_LOG_DBG("canvas : %p", canvas); + IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(ibusimcontext); + + if (canvas != NULL) + ibusimcontext->client_canvas = canvas; +} + +static void +_set_cursor_location_internal(Ecore_IMF_Context *ctx) +{ + IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx); + Ecore_Evas *ee; + int canvas_x, canvas_y; + + EINA_SAFETY_ON_NULL_RETURN(ibusimcontext); + + if (ibusimcontext->ibuscontext == NULL) + return; + + if (ibusimcontext->client_canvas) + { + ee = ecore_evas_ecore_evas_get(ibusimcontext->client_canvas); + if (!ee) return; + + ecore_evas_geometry_get(ee, &canvas_x, &canvas_y, NULL, NULL); + } + else + { + if (ibusimcontext->client_window) + _window_to_screen_geometry_get(ibusimcontext->client_window, &canvas_x, &canvas_y); + else + return; + } + + ibus_input_context_set_cursor_location(ibusimcontext->ibuscontext, + ibusimcontext->cursor_x + canvas_x, + ibusimcontext->cursor_y + canvas_y, + ibusimcontext->cursor_w, + ibusimcontext->cursor_h); +} + +EAPI void +ibus_im_context_cursor_location_set(Ecore_IMF_Context *ctx, int x, int y, int w, int h) +{ + EINA_LOG_DBG("x : %d, y : %d, w, %d, h :%d", x, y, w, h); + IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(ibusimcontext); + + if (ibusimcontext->cursor_x != x || + ibusimcontext->cursor_y != y || + ibusimcontext->cursor_w != w || + ibusimcontext->cursor_h != h) + { + ibusimcontext->cursor_x = x; + ibusimcontext->cursor_y = y; + ibusimcontext->cursor_w = w; + ibusimcontext->cursor_h = h; + + _set_cursor_location_internal(ctx); + } +} + +EAPI void +ibus_im_context_use_preedit_set(Ecore_IMF_Context *ctx, Eina_Bool use_preedit) +{ + EINA_LOG_DBG("preedit : %d", use_preedit); + IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(ibusimcontext); + + if (ibusimcontext->ibuscontext) + { + if (use_preedit) + ibusimcontext->caps |= IBUS_CAP_PREEDIT_TEXT; + else + ibusimcontext->caps &= ~IBUS_CAP_PREEDIT_TEXT; + + ibus_input_context_set_capabilities(ibusimcontext->ibuscontext, ibusimcontext->caps); + } +} + +static void +_bus_connected_cb(IBusBus *bus __UNUSED__, + IBusIMContext *ibusimcontext) +{ + EINA_LOG_DBG("ibus is connected"); + + if (ibusimcontext) + _create_input_context(ibusimcontext); +} + +static void +_ibus_context_commit_text_cb(IBusInputContext *ibuscontext __UNUSED__, + IBusText *text, + IBusIMContext *ibusimcontext) +{ + if (!ibusimcontext || !text) return; + char *commit_str = text->text ? text->text : ""; + + EINA_LOG_DBG("commit string : %s", commit_str); + + if (ibusimcontext->ctx) + { + ecore_imf_context_commit_event_add(ibusimcontext->ctx, text->text); + ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)commit_str); + } +} + +static XKeyEvent createXKeyEvent(Window win, Eina_Bool press, int keysym, int modifiers) +{ + XKeyEvent event; + Display *display = ecore_x_display_get(); + + event.display = display; + event.window = win; + event.root = ecore_x_window_root_get(win); + event.subwindow = None; + event.time = 0; + event.x = 1; + event.y = 1; + event.x_root = 1; + event.y_root = 1; + event.same_screen = EINA_TRUE; + event.state = modifiers; + event.keycode = XKeysymToKeycode(display, keysym); + if (press) + event.type = KeyPress; + else + event.type = KeyRelease; + event.send_event = EINA_FALSE; + event.serial = 0; + + return event; +} + +static void +_ibus_context_forward_key_event_cb(IBusInputContext *ibuscontext __UNUSED__, + guint keyval, + guint state, + IBusIMContext *ibusimcontext __UNUSED__) +{ + EINA_LOG_DBG("keyval : %d, state : %d", keyval, state); + + key_event_put(keyval, state); +} + +static void +_ibus_context_update_preedit_text_cb(IBusInputContext *ibuscontext __UNUSED__, + IBusText *text, + gint cursor_pos, + gboolean visible, + IBusIMContext *ibusimcontext) +{ + if (!ibusimcontext || !text) return; + + const char *str; + gboolean flag; + + if (ibusimcontext->preedit_string) + free (ibusimcontext->preedit_string); + + str = text->text; + + if (str) + ibusimcontext->preedit_string = strdup(str); + else + ibusimcontext->preedit_string = strdup(""); + + ibusimcontext->preedit_cursor_pos = cursor_pos; + + EINA_LOG_DBG("string : %s, cursor : %d", ibusimcontext->preedit_string, ibusimcontext->preedit_cursor_pos); + + flag = ibusimcontext->preedit_visible != visible; + ibusimcontext->preedit_visible = visible; + + if (ibusimcontext->preedit_visible) + { + if (flag) + { + ecore_imf_context_preedit_start_event_add(ibusimcontext->ctx); + ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL); + } + + ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx); + ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL); + } + else + { + if (flag) + { + ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx); + ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL); + } + + ecore_imf_context_preedit_end_event_add(ibusimcontext->ctx); + ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL); + } +} + +static void +_ibus_context_show_preedit_text_cb(IBusInputContext *ibuscontext __UNUSED__, + IBusIMContext *ibusimcontext) +{ + EINA_LOG_DBG("preedit visible : %d", ibusimcontext->preedit_visible); + EINA_SAFETY_ON_NULL_RETURN(ibusimcontext); + + if (ibusimcontext->preedit_visible == EINA_TRUE) + return; + + ibusimcontext->preedit_visible = EINA_TRUE; + + // call preedit start + ecore_imf_context_preedit_start_event_add(ibusimcontext->ctx); + ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL); + + // call preedit changed + ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx); + ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL); +} + +static void +_ibus_context_hide_preedit_text_cb(IBusInputContext *ibuscontext __UNUSED__, + IBusIMContext *ibusimcontext) +{ + EINA_LOG_DBG("%s", __FUNCTION__); + EINA_SAFETY_ON_NULL_RETURN(ibusimcontext); + + if (ibusimcontext->preedit_visible == EINA_FALSE) + return; + + ibusimcontext->preedit_visible = EINA_FALSE; + + // call preedit changed + ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx); + ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL); + + // call preedit end + ecore_imf_context_preedit_end_event_add(ibusimcontext->ctx); + ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL); +} + +static void +_ibus_context_enabled_cb(IBusInputContext *ibuscontext __UNUSED__, + IBusIMContext *ibusimcontext) +{ + EINA_LOG_DBG("%s", __FUNCTION__); + EINA_SAFETY_ON_NULL_RETURN(ibusimcontext); + + ibusimcontext->enable = EINA_TRUE; +} + +static void +_ibus_context_disabled_cb(IBusInputContext *ibuscontext __UNUSED__, + IBusIMContext *ibusimcontext) +{ + EINA_LOG_DBG("%s", __FUNCTION__); + EINA_SAFETY_ON_NULL_RETURN(ibusimcontext); + + ibusimcontext->enable = EINA_FALSE; + + /* clear preedit */ + ibusimcontext->preedit_visible = EINA_FALSE; + ibusimcontext->preedit_cursor_pos = 0; + free (ibusimcontext->preedit_string); + ibusimcontext->preedit_string = NULL; + + // call preedit changed + ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx); + ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL); + + // call preedit end + ecore_imf_context_preedit_end_event_add(ibusimcontext->ctx); + ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL); +} + +static void +_ibus_context_destroy_cb(IBusInputContext *ibuscontext __UNUSED__, + IBusIMContext *ibusimcontext) +{ + EINA_LOG_DBG("%s", __FUNCTION__); + EINA_SAFETY_ON_NULL_RETURN(ibusimcontext); + + ibusimcontext->ibuscontext = NULL; + ibusimcontext->enable = EINA_FALSE; + + /* clear preedit */ + ibusimcontext->preedit_visible = EINA_FALSE; + ibusimcontext->preedit_cursor_pos = 0; + free (ibusimcontext->preedit_string); + ibusimcontext->preedit_string = NULL; + + // call preedit changed + ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx); + ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL); + + // call preedit end + ecore_imf_context_preedit_end_event_add(ibusimcontext->ctx); + ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL); +} + +static void +_create_input_context(IBusIMContext *ibusimcontext) +{ + EINA_LOG_DBG("%s", __FUNCTION__); + EINA_SAFETY_ON_NULL_RETURN(ibusimcontext); + + ibusimcontext->ibuscontext = ibus_bus_create_input_context(_bus, "ecore"); + + g_return_if_fail(ibusimcontext->ibuscontext != NULL); + + g_signal_connect(ibusimcontext->ibuscontext, + "commit-text", + G_CALLBACK (_ibus_context_commit_text_cb), + ibusimcontext); + g_signal_connect(ibusimcontext->ibuscontext, + "forward-key-event", + G_CALLBACK (_ibus_context_forward_key_event_cb), + ibusimcontext); + g_signal_connect(ibusimcontext->ibuscontext, + "update-preedit-text", + G_CALLBACK (_ibus_context_update_preedit_text_cb), + ibusimcontext); + g_signal_connect(ibusimcontext->ibuscontext, + "show-preedit-text", + G_CALLBACK (_ibus_context_show_preedit_text_cb), + ibusimcontext); + g_signal_connect(ibusimcontext->ibuscontext, + "hide-preedit-text", + G_CALLBACK (_ibus_context_hide_preedit_text_cb), + ibusimcontext); + g_signal_connect(ibusimcontext->ibuscontext, + "enabled", + G_CALLBACK (_ibus_context_enabled_cb), + ibusimcontext); + g_signal_connect(ibusimcontext->ibuscontext, + "disabled", + G_CALLBACK (_ibus_context_disabled_cb), + ibusimcontext); + g_signal_connect(ibusimcontext->ibuscontext, "destroy", + G_CALLBACK (_ibus_context_destroy_cb), + ibusimcontext); + + ibus_input_context_set_capabilities(ibusimcontext->ibuscontext, ibusimcontext->caps); + + if (ibusimcontext->has_focus) + ibus_input_context_focus_in(ibusimcontext->ibuscontext); +} diff --git a/src/modules/immodules/ibus/ibus_imcontext.h b/src/modules/immodules/ibus/ibus_imcontext.h new file mode 100644 index 0000000..ce5c075 --- /dev/null +++ b/src/modules/immodules/ibus/ibus_imcontext.h @@ -0,0 +1,36 @@ +#ifndef __IBUS_IM_CONTEXT_H_ +#define __IBUS_IM_CONTEXT_H_ + +#include + +typedef struct _IBusIMContext IBusIMContext; + +EAPI void ibus_im_context_add (Ecore_IMF_Context *ctx); +EAPI void ibus_im_context_del (Ecore_IMF_Context *ctx); +EAPI void ibus_im_context_reset (Ecore_IMF_Context *context); +EAPI void ibus_im_context_focus_in(Ecore_IMF_Context *context); +EAPI void ibus_im_context_focus_out(Ecore_IMF_Context *context); +EAPI void ibus_im_context_preedit_string_get + (Ecore_IMF_Context *context, + char **str, + int *cursor_pos); +EAPI void ibus_im_context_preedit_string_with_attributes_get + (Ecore_IMF_Context *context, + char **str, + Eina_List **attr, + int *cursor_pos); + +EAPI void ibus_im_context_cursor_location_set(Ecore_IMF_Context *context, + int x, int y, int w, int h); +EAPI void ibus_im_context_use_preedit_set(Ecore_IMF_Context *context, + Eina_Bool use_preedit); +EAPI void +ibus_im_context_client_window_set(Ecore_IMF_Context *context, void *window); +EAPI void +ibus_im_context_client_canvas_set(Ecore_IMF_Context *context, void *canvas); +EAPI Eina_Bool +ibus_im_context_filter_event(Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event); + +IBusIMContext + *ibus_im_context_new (void); +#endif diff --git a/src/modules/immodules/ibus/ibus_module.c b/src/modules/immodules/ibus/ibus_module.c new file mode 100644 index 0000000..3e3493e --- /dev/null +++ b/src/modules/immodules/ibus/ibus_module.c @@ -0,0 +1,103 @@ +#include +#include "ibus_imcontext.h" +#include +#include +#include + +#define IBUS_LOCALDIR "" +static const Ecore_IMF_Context_Info ibus_im_info = { + "ibus", + "IBus (Intelligent Input Bus)", + "*", + NULL, + 0 +}; + +static Ecore_IMF_Context_Class ibus_imf_class = { + ibus_im_context_add, /* add */ + ibus_im_context_del, /* del */ + ibus_im_context_client_window_set, /* client_window_set */ + ibus_im_context_client_canvas_set, /* client_canvas_set */ + NULL, /* input_panel_show */ + NULL, /* input_panel_hide */ + ibus_im_context_preedit_string_get, /* get_preedit_string */ + ibus_im_context_focus_in, /* focus_in */ + ibus_im_context_focus_out, /* focus_out */ + ibus_im_context_reset, /* reset */ + NULL, /* cursor_position_set */ + ibus_im_context_use_preedit_set, /* use_preedit_set */ + NULL, /* input_mode_set */ + ibus_im_context_filter_event, /* filter_event */ + ibus_im_context_preedit_string_with_attributes_get, /* preedit_string_with_attribute_get */ + NULL, /* prediction_allow_set */ + NULL, /* autocapital_type_set */ + NULL, /* control panel show */ + NULL, /* control panel hide */ + NULL, /* input_panel_layout_set */ + NULL, /* ibus_im_context_input_panel_layout_get, */ + NULL, /* ibus_im_context_input_panel_language_set, */ + NULL, /* ibus_im_context_input_panel_language_get, */ + ibus_im_context_cursor_location_set, /* cursor_location_set */ + NULL, /* input_panel_imdata_set */ + NULL, /* input_panel_imdata_get */ + NULL, /* input_panel_return_key_type_set */ + NULL, /* input_panel_return_key_disabled_set */ + NULL, /* input_panel_caps_lock_mode_set */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +static Ecore_IMF_Context *im_module_create (void); +static Ecore_IMF_Context *im_module_exit (void); + +static Eina_Bool +im_module_init(void) +{ + ecore_main_loop_glib_integrate(); + ibus_init(); + ecore_imf_module_register(&ibus_im_info, im_module_create, im_module_exit); + + return EINA_TRUE; +} + +static void im_module_shutdown(void) +{ +} + +static Ecore_IMF_Context * +im_module_exit(void) +{ + return NULL; +} + +static Ecore_IMF_Context * +im_module_create() +{ + Ecore_IMF_Context *ctx = NULL; + IBusIMContext *ctxd = NULL; + + ctxd = ibus_im_context_new(); + if (!ctxd) + { + return NULL; + } + + ctx = ecore_imf_context_new(&ibus_imf_class); + if (!ctx) + { + free(ctxd); + return NULL; + } + + ecore_imf_context_data_set(ctx, ctxd); + + return ctx; +} + +EINA_MODULE_INIT(im_module_init); +EINA_MODULE_SHUTDOWN(im_module_shutdown); + diff --git a/src/modules/immodules/scim/Makefile.am b/src/modules/immodules/scim/Makefile.am new file mode 100644 index 0000000..40579ca --- /dev/null +++ b/src/modules/immodules/scim/Makefile.am @@ -0,0 +1,36 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_srcdir) \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore_input \ +-I$(top_srcdir)/src/lib/ecore_x \ +-I$(top_srcdir)/src/lib/ecore_imf \ +-I$(top_srcdir)/src/lib/ecore_evas \ +-I$(top_builddir)/src/lib/ecore \ +-I$(top_builddir)/src/lib/ecore_input \ +-I$(top_builddir)/src/lib/ecore_x \ +-I$(top_builddir)/src/lib/ecore_imf \ +-I$(top_builddir)/src/lib/ecore_evas \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \ +@SCIM_CFLAGS@ \ +@EVAS_CFLAGS@ \ +@EINA_CFLAGS@ + +pkgdir = $(libdir)/ecore/immodules + +pkg_LTLIBRARIES = scim.la +scim_la_SOURCES = \ +scim_imcontext.cpp \ +scim_module.cpp \ +scim_imcontext.h + +scim_la_LIBADD = \ + $(top_builddir)/src/lib/ecore_imf/libecore_imf.la \ + $(top_builddir)/src/lib/ecore_x/libecore_x.la \ + @SCIM_LIBS@ \ + @EVAS_LIBS@ \ + @EINA_LIBS@ +scim_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version +scim_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/src/modules/immodules/scim/scim_imcontext.cpp b/src/modules/immodules/scim/scim_imcontext.cpp new file mode 100644 index 0000000..d4d20b1 --- /dev/null +++ b/src/modules/immodules/scim/scim_imcontext.cpp @@ -0,0 +1,2900 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#define Uses_SCIM_DEBUG +#define Uses_SCIM_BACKEND +#define Uses_SCIM_IMENGINE_MODULE +#define Uses_SCIM_HOTKEY +#define Uses_SCIM_PANEL_CLIENT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include "scim_imcontext.h" + +using namespace scim; + +struct _EcoreIMFContextISFImpl +{ + EcoreIMFContextISF *parent; + IMEngineInstancePointer si; + Ecore_X_Window client_window; + Evas *client_canvas; + Ecore_IMF_Input_Mode input_mode; + WideString preedit_string; + AttributeList preedit_attrlist; + Ecore_IMF_Autocapital_Type autocapital_type; + int preedit_caret; + int cursor_x; + int cursor_y; + int cursor_pos; + bool use_preedit; + bool is_on; + bool shared_si; + bool preedit_started; + bool preedit_updating; + bool need_commit_preedit; + bool uppercase; + bool prediction_allow; + + EcoreIMFContextISFImpl *next; +}; + +/* Input Context handling functions. */ +static EcoreIMFContextISFImpl *new_ic_impl (EcoreIMFContextISF *parent); +static void delete_ic_impl (EcoreIMFContextISFImpl *impl); +static void delete_all_ic_impl (void); + +static EcoreIMFContextISF *find_ic (int id); + + +/* private functions */ +static void panel_slot_reload_config (int context); +static void panel_slot_exit (int context); +static void panel_slot_update_lookup_table_page_size(int context, + int page_size); +static void panel_slot_lookup_table_page_up (int context); +static void panel_slot_lookup_table_page_down (int context); +static void panel_slot_trigger_property (int context, + const String &property); +static void panel_slot_process_helper_event (int context, + const String &target_uuid, + const String &helper_uuid, + const Transaction &trans); +static void panel_slot_move_preedit_caret (int context, + int caret_pos); +static void panel_slot_select_candidate (int context, + int cand_index); +static void panel_slot_process_key_event (int context, + const KeyEvent &key); +static void panel_slot_commit_string (int context, + const WideString &wstr); +static void panel_slot_forward_key_event (int context, + const KeyEvent &key); +static void panel_slot_request_help (int context); +static void panel_slot_request_factory_menu (int context); +static void panel_slot_change_factory (int context, + const String &uuid); + +static void panel_req_focus_in (EcoreIMFContextISF *ic); +static void panel_req_update_factory_info (EcoreIMFContextISF *ic); +static void panel_req_update_spot_location (EcoreIMFContextISF *ic); +static void panel_req_show_help (EcoreIMFContextISF *ic); +static void panel_req_show_factory_menu (EcoreIMFContextISF *ic); + +/* Panel iochannel handler*/ +static bool panel_initialize (void); +static void panel_finalize (void); +static Eina_Bool panel_iochannel_handler (void *data, + Ecore_Fd_Handler *fd_handler); + +/* utility functions */ +static bool filter_hotkeys (EcoreIMFContextISF *ic, + const KeyEvent &key); +static void turn_on_ic (EcoreIMFContextISF *ic); +static void turn_off_ic (EcoreIMFContextISF *ic); +static void set_ic_capabilities (EcoreIMFContextISF *ic); + +static void initialize (void); +static void finalize (void); + +static void open_next_factory (EcoreIMFContextISF *ic); +static void open_previous_factory (EcoreIMFContextISF *ic); +static void open_specific_factory (EcoreIMFContextISF *ic, + const String &uuid); +static void initialize_modifier_bits (Display *display); +static unsigned int scim_x11_keymask_scim_to_x11 (Display *display, uint16 scimkeymask); +static XKeyEvent createKeyEvent (Display *display, Window &win, + Window &winRoot, bool press, + int keycode, int modifiers); +static void _x_send_key_event (const KeyEvent &key); + +static void attach_instance (const IMEngineInstancePointer &si); + +/* slot functions */ +static void slot_show_preedit_string (IMEngineInstanceBase *si); +static void slot_show_aux_string (IMEngineInstanceBase *si); +static void slot_show_lookup_table (IMEngineInstanceBase *si); + +static void slot_hide_preedit_string (IMEngineInstanceBase *si); +static void slot_hide_aux_string (IMEngineInstanceBase *si); +static void slot_hide_lookup_table (IMEngineInstanceBase *si); + +static void slot_update_preedit_caret (IMEngineInstanceBase *si, + int caret); +static void slot_update_preedit_string (IMEngineInstanceBase *si, + const WideString &str, + const AttributeList &attrs); +static void slot_update_aux_string (IMEngineInstanceBase *si, + const WideString &str, + const AttributeList &attrs); +static void slot_commit_string (IMEngineInstanceBase *si, + const WideString &str); +static void slot_forward_key_event (IMEngineInstanceBase *si, + const KeyEvent &key); +static void slot_update_lookup_table (IMEngineInstanceBase *si, + const LookupTable &table); + +static void slot_register_properties (IMEngineInstanceBase *si, + const PropertyList &properties); +static void slot_update_property (IMEngineInstanceBase *si, + const Property &property); +static void slot_beep (IMEngineInstanceBase *si); +static void slot_start_helper (IMEngineInstanceBase *si, + const String &helper_uuid); +static void slot_stop_helper (IMEngineInstanceBase *si, + const String &helper_uuid); +static void slot_send_helper_event (IMEngineInstanceBase *si, + const String &helper_uuid, + const Transaction &trans); +static bool slot_get_surrounding_text (IMEngineInstanceBase *si, + WideString &text, + int &cursor, + int maxlen_before, + int maxlen_after); +static bool slot_delete_surrounding_text (IMEngineInstanceBase *si, + int offset, + int len); + +static void reload_config_callback (const ConfigPointer &config); + +static void fallback_commit_string_cb (IMEngineInstanceBase *si, + const WideString &str); + +static void caps_mode_check (Ecore_IMF_Context *ctx, Eina_Bool force); + +/* Local variables declaration */ +static String _language; +static EcoreIMFContextISFImpl *_used_ic_impl_list = 0; +static EcoreIMFContextISFImpl *_free_ic_impl_list = 0; +static EcoreIMFContextISF *_ic_list = 0; + +static KeyboardLayout _keyboard_layout = SCIM_KEYBOARD_Default; +static int _valid_key_mask = SCIM_KEY_AllMasks; + +static FrontEndHotkeyMatcher _frontend_hotkey_matcher; +static IMEngineHotkeyMatcher _imengine_hotkey_matcher; + +static IMEngineInstancePointer _default_instance; + +static ConfigModule *_config_module = 0; +static ConfigPointer _config; +static BackEndPointer _backend; + +static EcoreIMFContextISF *_focused_ic = 0; + +static bool _scim_initialized = false; + +static int _instance_count = 0; +static int _context_count = 0; + +static IMEngineFactoryPointer _fallback_factory; +static IMEngineInstancePointer _fallback_instance; +static PanelClient _panel_client; + +static Ecore_Fd_Handler *_panel_iochannel_read_handler = 0; +static Ecore_Fd_Handler *_panel_iochannel_err_handler = 0; + +static Ecore_X_Window _client_window = 0; + +static bool _on_the_spot = true; +static bool _shared_input_method = false; + +static Eina_Bool autocap_allow = EINA_FALSE; + +static Display *__current_display = 0; +static int __current_alt_mask = Mod1Mask; +static int __current_meta_mask = 0; +static int __current_super_mask = 0; +static int __current_hyper_mask = 0; +static int __current_numlock_mask = Mod2Mask; + +// A hack to shutdown the immodule cleanly even if im_module_exit() is not called when exiting. +class FinalizeHandler +{ +public: + FinalizeHandler() + { + SCIM_DEBUG_FRONTEND(1) << "FinalizeHandler::FinalizeHandler()\n"; + } + ~FinalizeHandler() + { + SCIM_DEBUG_FRONTEND(1) << "FinalizeHandler::~FinalizeHandler()\n"; + isf_imf_context_shutdown(); + } +}; + +static FinalizeHandler _finalize_handler; + +static unsigned int +utf8_offset_to_index(const char *str, int offset) +{ + int index = 0; + int i; + for (i = 0; i < offset; i++) + { + eina_unicode_utf8_get_next(str, &index); + } + + return index; +} + +static unsigned int +get_time(void) +{ + unsigned int tint; + struct timeval tv; + struct timezone tz; /* is not used since ages */ + gettimeofday(&tv, &tz); + tint = tv.tv_sec * 1000; + tint = tint / 1000 * 1000; + tint = tint + tv.tv_usec / 1000; + return tint; +} + +/* Function Implementations */ +static EcoreIMFContextISFImpl * +new_ic_impl(EcoreIMFContextISF *parent) +{ + EcoreIMFContextISFImpl *impl = NULL; + + if (_free_ic_impl_list != NULL) + { + impl = _free_ic_impl_list; + _free_ic_impl_list = _free_ic_impl_list->next; + } + else + { + impl = new EcoreIMFContextISFImpl; + if (impl == NULL) + return NULL; + } + + impl->uppercase = false; + impl->autocapital_type = ECORE_IMF_AUTOCAPITAL_TYPE_NONE; + impl->next = _used_ic_impl_list; + _used_ic_impl_list = impl; + + impl->parent = parent; + + return impl; +} + +static void +delete_ic_impl(EcoreIMFContextISFImpl *impl) +{ + EcoreIMFContextISFImpl *rec = _used_ic_impl_list, *last = 0; + + for (; rec != 0; last = rec, rec = rec->next) + { + if (rec == impl) + { + if (last != 0) + last->next = rec->next; + else + _used_ic_impl_list = rec->next; + + rec->next = _free_ic_impl_list; + _free_ic_impl_list = rec; + + rec->parent = 0; + rec->si.reset(); + rec->client_window = 0; + rec->preedit_string = WideString(); + rec->preedit_attrlist.clear(); + + return; + } + } +} + +static void +delete_all_ic_impl(void) +{ + EcoreIMFContextISFImpl *it = _used_ic_impl_list; + + while (it != 0) + { + _used_ic_impl_list = it->next; + delete it; + it = _used_ic_impl_list; + } + + it = _free_ic_impl_list; + while (it != 0) + { + _free_ic_impl_list = it->next; + delete it; + it = _free_ic_impl_list; + } +} + +static EcoreIMFContextISF * +find_ic(int id) +{ + EcoreIMFContextISFImpl *rec = _used_ic_impl_list; + + while (rec != 0) + { + if (rec->parent && rec->parent->id == id) + return rec->parent; + rec = rec->next; + } + + return 0; +} + +static Eina_Bool +analyze_surrounding_text(Ecore_IMF_Context *ctx) +{ + char *plain_str = NULL; + char *markup_str = NULL; + const char *puncs[] = {". ", "! ", "? "}; + Eina_Bool ret = EINA_FALSE; + int cursor_pos = 0; + int i = 0; + Eina_Unicode *tail = NULL; + Eina_Unicode *ustr = NULL; + const int punc_num = sizeof(puncs) / sizeof(puncs[0]); + Eina_Unicode *uni_puncs[punc_num]; + EcoreIMFContextISF *context_scim; + + if (!ctx) return EINA_FALSE; + context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx); + if (!context_scim || !context_scim->impl) return EINA_FALSE; + + switch (context_scim->impl->autocapital_type) + { + case ECORE_IMF_AUTOCAPITAL_TYPE_NONE: + return EINA_FALSE; + case ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER: + return EINA_TRUE; + default: + break; + } + + for (i = 0; i < punc_num; i++) + uni_puncs[i] = eina_unicode_utf8_to_unicode(puncs[i], NULL); + + ecore_imf_context_surrounding_get(ctx, &markup_str, &cursor_pos); + if (!markup_str) goto done; + + if (cursor_pos == 0) + { + ret = EINA_TRUE; + goto done; + } + + // Convert into plain string + plain_str = evas_textblock_text_markup_to_utf8(NULL, markup_str); + if (!plain_str) goto done; + + // Convert string from UTF-8 to unicode + ustr = eina_unicode_utf8_to_unicode(plain_str, NULL); + if (!ustr) goto done; + + if (cursor_pos >= 1) + { + if (context_scim->impl->autocapital_type == ECORE_IMF_AUTOCAPITAL_TYPE_WORD) + { + if (ustr[cursor_pos-1] == ' ') + { + ret = EINA_TRUE; + goto done; + } + } + + // Check paragraph separator and carriage return
+ if ((ustr[cursor_pos-1] == 0x2029) || (ustr[cursor_pos-1] == '\n')) + { + ret = EINA_TRUE; + goto done; + } + } + + // check punctuation + if (cursor_pos >= 2) + { + tail = eina_unicode_strndup(ustr+cursor_pos-2, 2); + + if (tail) + { + for (i = 0; i < punc_num; i++) + { + if (!eina_unicode_strcmp(tail, uni_puncs[i])) + { + ret = EINA_TRUE; + break; + } + } + free(tail); + tail = NULL; + } + } + +done: + if (ustr) free(ustr); + if (markup_str) free(markup_str); + if (plain_str) free(plain_str); + + for (i = 0; i < punc_num; i++) + if (uni_puncs[i]) free(uni_puncs[i]); + + return ret; +} + +static void +caps_mode_check(Ecore_IMF_Context *ctx, Eina_Bool force) +{ + Eina_Bool uppercase; + EcoreIMFContextISF *context_scim; + + if (!ctx) return; + context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx); + + if (autocap_allow == EINA_FALSE) + return; + + // Check autocapital type + if (!context_scim || !context_scim->impl) + return; + + if (analyze_surrounding_text(ctx)) + uppercase = EINA_TRUE; + else + uppercase = EINA_FALSE; + + if (force) + context_scim->impl->uppercase = uppercase; + else + if (context_scim->impl->uppercase != uppercase) + context_scim->impl->uppercase = uppercase; +} + +static void +feed_key_event(Evas *evas, const char *str, Eina_Bool fake) +{ + char key_string[128] = {0}; + unsigned int timestamp = 0; + + if (!fake) + timestamp = get_time(); + + if (strncmp(str, "KeyRelease+", 11) == 0) + { + strncpy(key_string, str + 11, strlen(str)-11); + evas_event_feed_key_up(evas, key_string, key_string, NULL, NULL, timestamp, NULL); + SCIM_DEBUG_FRONTEND(1) << " evas_event_feed_key_up()...\n"; + } + else + { + strncpy(key_string, str, strlen(str)); + evas_event_feed_key_down(evas, key_string, key_string, NULL, NULL, timestamp, NULL); + SCIM_DEBUG_FRONTEND(1) << " evas_event_feed_key_down()...\n"; + } +} + +static void +window_to_screen_geometry_get(Ecore_X_Window client_win, int *x, int *y) +{ + Ecore_X_Window root_window, win; + int win_x, win_y; + int sum_x = 0, sum_y = 0; + + root_window = ecore_x_window_root_get(client_win); + win = client_win; + + while (root_window != win) + { + ecore_x_window_geometry_get(win, &win_x, &win_y, NULL, NULL); + sum_x += win_x; + sum_y += win_y; + win = ecore_x_window_parent_get(win); + } + + if (x) + *x = sum_x; + if (y) + *y = sum_y; +} + +/* Public functions */ +/** + * isf_imf_context_new + * + * This function will be called by Ecore IMF. + * Create a instance of type EcoreIMFContextISF. + * + * Return value: A pointer to the newly created EcoreIMFContextISF instance + */ +EAPI EcoreIMFContextISF * +isf_imf_context_new(void) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + char *env; + + EcoreIMFContextISF *context_scim = new EcoreIMFContextISF; + if (context_scim == NULL) + { + std::cerr << "memory allocation failed in " << __FUNCTION__ << "\n"; + return NULL; + } + + context_scim->id = _context_count++; + + if (!_scim_initialized) + { + initialize(); + _scim_initialized = true; + } + + env = getenv("ECORE_IMF_AUTOCAPITAL_ALLOW"); + if (env) + autocap_allow = !!atoi(env); + + return context_scim; +} + +/** + * isf_imf_context_shutdown + * + * It will be called when the scim im module is unloaded by ecore. It will do some + * cleanup job. + */ +EAPI void +isf_imf_context_shutdown(void) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + if (_scim_initialized) + { + _scim_initialized = false; + finalize(); + } +} + +EAPI void +isf_imf_context_add(Ecore_IMF_Context *ctx) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx); + + if (!context_scim) return; + + context_scim->impl = NULL; + + if (_backend.null()) + return; + + IMEngineInstancePointer si; + + // Use the default instance if "shared input method" mode is enabled. + if (_shared_input_method && !_default_instance.null()) + { + si = _default_instance; + SCIM_DEBUG_FRONTEND(2) << "use default instance: " << si->get_id() << " " << si->get_factory_uuid() << "\n"; + } + + // Not in "shared input method" mode, or no default instance, create an instance. + if (si.null()) + { + IMEngineFactoryPointer factory = _backend->get_default_factory(_language, "UTF-8"); + if (factory.null()) return; + si = factory->create_instance("UTF-8", _instance_count++); + if (si.null()) return; + attach_instance(si); + SCIM_DEBUG_FRONTEND(2) << "create new instance: " << si->get_id() << " " << si->get_factory_uuid() << "\n"; + } + + // If "shared input method" mode is enabled, and there is no default instance, + // then store this instance as default one. + if (_shared_input_method && _default_instance.null()) + { + SCIM_DEBUG_FRONTEND(2) << "update default instance.\n"; + _default_instance = si; + } + + context_scim->ctx = ctx; + context_scim->impl = new_ic_impl(context_scim); + if (context_scim->impl == NULL) + { + std::cerr << "memory allocation failed in " << __FUNCTION__ << "\n"; + return; + } + + context_scim->impl->si = si; + context_scim->impl->client_window = 0; + context_scim->impl->client_canvas = NULL; + context_scim->impl->preedit_caret = 0; + context_scim->impl->cursor_x = 0; + context_scim->impl->cursor_y = 0; + context_scim->impl->cursor_pos = -1; + context_scim->impl->is_on = false; + context_scim->impl->shared_si = _shared_input_method; + context_scim->impl->use_preedit = _on_the_spot; + context_scim->impl->preedit_started = false; + context_scim->impl->preedit_updating = false; + context_scim->impl->need_commit_preedit = false; + + if (!_ic_list) + context_scim->next = NULL; + else + context_scim->next = _ic_list; + _ic_list = context_scim; + + if (_shared_input_method) + context_scim->impl->is_on = _config->read(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), context_scim->impl->is_on); + + _panel_client.prepare(context_scim->id); + _panel_client.register_input_context(context_scim->id, si->get_factory_uuid()); + set_ic_capabilities(context_scim); + _panel_client.send(); + + SCIM_DEBUG_FRONTEND(2) << "input context created: id = " << context_scim->id << "\n"; +} + +EAPI void +isf_imf_context_del(Ecore_IMF_Context *ctx) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + if (!_ic_list) return; + + EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx); + + if (context_scim) + { + if (context_scim->id != _ic_list->id) + { + EcoreIMFContextISF * pre = _ic_list; + EcoreIMFContextISF * cur = _ic_list->next; + while (cur != NULL) + { + if (cur->id == context_scim->id) + { + pre->next = cur->next; + break; + } + pre = cur; + cur = cur->next; + } + } + else + _ic_list = _ic_list->next; + } + + if (context_scim && context_scim->impl) + { + _panel_client.prepare(context_scim->id); + + if (context_scim == _focused_ic) + context_scim->impl->si->focus_out(); + + // Delete the instance. + EcoreIMFContextISF *old_focused = _focused_ic; + _focused_ic = context_scim; + context_scim->impl->si.reset(); + _focused_ic = old_focused; + + if (context_scim == _focused_ic) + { + _panel_client.turn_off(context_scim->id); + _panel_client.focus_out(context_scim->id); + } + + _panel_client.remove_input_context(context_scim->id); + _panel_client.send(); + + if (context_scim->impl->client_window) + isf_imf_context_client_window_set(ctx, NULL); + + if (context_scim->impl) + { + delete_ic_impl(context_scim->impl); + context_scim->impl = 0; + } + } + + if (context_scim == _focused_ic) + _focused_ic = 0; + + if (context_scim) + { + delete context_scim; + context_scim = 0; + } +} + +/** + * isf_imf_context_client_canvas_set + * @ctx: a #Ecore_IMF_Context + * @canvas: the client canvas + * + * This function will be called by Ecore IMF. + * + * Set the client canvas for the Input Method Context; this is the canvas + * in which the input appears. + * + * The canvas type can be determined by using the context canvas type. + * Actually only canvas with type "evas" (Evas *) is supported. This canvas + * may be used in order to correctly position status windows, and may also + * be used for purposes internal to the Input Method Context. + */ +EAPI void +isf_imf_context_client_canvas_set(Ecore_IMF_Context *ctx, void *canvas) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx); + + if (context_scim && context_scim->impl && context_scim->impl->client_canvas != (Evas*) canvas) + context_scim->impl->client_canvas = (Evas*)canvas; +} + +/** + * isf_imf_context_client_window_set + * @ctx: a #Ecore_IMF_Context + * @window: the client window + * + * This function will be called by Ecore IMF. + * + * Set the client window for the Input Method Context; this is the Ecore_X_Window + * when using X11, Ecore_Win32_Window when using Win32, etc. + * + * This window is used in order to correctly position status windows, + * and may also be used for purposes internal to the Input Method Context. + */ +EAPI void +isf_imf_context_client_window_set(Ecore_IMF_Context *ctx, void *window) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx); + + if (context_scim && context_scim->impl && context_scim->impl->client_window != (Ecore_X_Window)((Ecore_Window)window)) + { + context_scim->impl->client_window = (Ecore_X_Window)((Ecore_Window)window); + + if ((context_scim->impl->client_window != 0) && + (context_scim->impl->client_window != _client_window)) + _client_window = context_scim->impl->client_window; + } +} + +/** + * isf_imf_context_reset + * @ctx: a #Ecore_IMF_Context + * + * This function will be called by Ecore IMF. + * + * Notify the Input Method Context that a change such as a change in cursor + * position has been made. This will typically cause the Input Method Context + * to clear the preedit state. + */ +EAPI void +isf_imf_context_reset(Ecore_IMF_Context *ctx) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx); + + if (context_scim && context_scim->impl && context_scim == _focused_ic) + { + WideString wstr = context_scim->impl->preedit_string; + + _panel_client.prepare(context_scim->id); + context_scim->impl->si->reset(); + _panel_client.send(); + + if (context_scim->impl->need_commit_preedit) + { + if (wstr.length()) + { + ecore_imf_context_commit_event_add(context_scim->ctx, utf8_wcstombs(wstr).c_str()); + ecore_imf_context_event_callback_call(context_scim->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(wstr).c_str()); + } + _panel_client.prepare(context_scim->id); + _panel_client.send(); + } + } +} + +/** + * isf_imf_context_focus_in + * @ctx: a #Ecore_IMF_Context + * + * This function will be called by Ecore IMF. + * + * Notify the Input Method Context that the widget to which its correspond has gained focus. + */ +EAPI void +isf_imf_context_focus_in(Ecore_IMF_Context *ctx) +{ + EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx); + + if (!context_scim) + return; + + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__<< "(" << context_scim->id << ")...\n"; + + if (_focused_ic) + { + if (_focused_ic == context_scim) + { + SCIM_DEBUG_FRONTEND(1) << "It's already focused.\n"; + return; + } + SCIM_DEBUG_FRONTEND(1) << "Focus out previous IC first: " << _focused_ic->id << "\n"; + if (_focused_ic->ctx) + isf_imf_context_focus_out(_focused_ic->ctx); + } + + bool need_cap = false; + bool need_reset = false; + bool need_reg = false; + + if (context_scim && context_scim->impl) + { + _focused_ic = context_scim; + _panel_client.prepare(context_scim->id); + + // Handle the "Shared Input Method" mode. + if (_shared_input_method) + { + SCIM_DEBUG_FRONTEND(2) << "shared input method.\n"; + IMEngineFactoryPointer factory = _backend->get_default_factory(_language, "UTF-8"); + if (!factory.null()) + { + if (_default_instance.null() || _default_instance->get_factory_uuid() != factory->get_uuid()) + { + _default_instance = factory->create_instance("UTF-8", _default_instance.null() ? _instance_count++ : _default_instance->get_id()); + attach_instance(_default_instance); + SCIM_DEBUG_FRONTEND(2) << "create new default instance: " << _default_instance->get_id() << " " << _default_instance->get_factory_uuid() << "\n"; + } + + context_scim->impl->shared_si = true; + context_scim->impl->si = _default_instance; + + context_scim->impl->is_on = _config->read(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), context_scim->impl->is_on); + context_scim->impl->preedit_string.clear(); + context_scim->impl->preedit_attrlist.clear(); + context_scim->impl->preedit_caret = 0; + context_scim->impl->preedit_started = false; + need_cap = true; + need_reset = true; + need_reg = true; + } + } + else if (context_scim->impl->shared_si) + { + SCIM_DEBUG_FRONTEND(2) << "exit shared input method.\n"; + IMEngineFactoryPointer factory = _backend->get_default_factory(_language, "UTF-8"); + if (!factory.null()) + { + context_scim->impl->si = factory->create_instance("UTF-8", _instance_count++); + context_scim->impl->preedit_string.clear(); + context_scim->impl->preedit_attrlist.clear(); + context_scim->impl->preedit_caret = 0; + context_scim->impl->preedit_started = false; + attach_instance(context_scim->impl->si); + need_cap = true; + need_reg = true; + context_scim->impl->shared_si = false; + SCIM_DEBUG_FRONTEND(2) << "create new instance: " << context_scim->impl->si->get_id() << " " << context_scim->impl->si->get_factory_uuid() << "\n"; + } + } + + context_scim->impl->si->set_frontend_data(static_cast (context_scim)); + + if (need_reg) _panel_client.register_input_context(context_scim->id, context_scim->impl->si->get_factory_uuid()); + if (need_cap) set_ic_capabilities(context_scim); + if (need_reset) context_scim->impl->si->reset(); + + panel_req_focus_in(context_scim); + panel_req_update_spot_location(context_scim); + panel_req_update_factory_info(context_scim); + + if (context_scim->impl->is_on) + { + _panel_client.turn_on(context_scim->id); + _panel_client.hide_preedit_string(context_scim->id); + _panel_client.hide_aux_string(context_scim->id); + _panel_client.hide_lookup_table(context_scim->id); + context_scim->impl->si->focus_in(); + } + else + { + _panel_client.turn_off(context_scim->id); + } + + _panel_client.send(); + } + + if (ecore_imf_context_input_panel_enabled_get(ctx)) + ecore_imf_context_input_panel_show(ctx); +} + +/** + * isf_imf_context_focus_out + * @ctx: a #Ecore_IMF_Context + * + * This function will be called by Ecore IMF. + * + * Notify the Input Method Context that the widget to which its correspond has lost focus. + */ +EAPI void +isf_imf_context_focus_out(Ecore_IMF_Context *ctx) +{ + EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx); + + if (!context_scim) return; + + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "(" << context_scim->id << ")...\n"; + + if (context_scim && context_scim->impl && context_scim == _focused_ic) + { + WideString wstr = context_scim->impl->preedit_string; + + if (context_scim->impl->need_commit_preedit) + { + if (wstr.length()) + { + ecore_imf_context_commit_event_add(context_scim->ctx, utf8_wcstombs(wstr).c_str()); + ecore_imf_context_event_callback_call(context_scim->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(wstr).c_str()); + } + _panel_client.prepare(context_scim->id); + _panel_client.send(); + } + + _panel_client.prepare(context_scim->id); + context_scim->impl->si->focus_out(); + context_scim->impl->si->reset(); + _panel_client.turn_off(context_scim->id); + _panel_client.focus_out(context_scim->id); + _panel_client.send(); + _focused_ic = 0; + } + + if (ecore_imf_context_input_panel_enabled_get(ctx)) + ecore_imf_context_input_panel_hide(ctx); +} + +/** + * isf_imf_context_cursor_location_set + * @ctx: a #Ecore_IMF_Context + * @x: x position of New cursor. + * @y: y position of New cursor. + * @w: the width of New cursor. + * @h: the height of New cursor. + * + * This function will be called by Ecore IMF. + * + * Notify the Input Method Context that a change in the cursor location has been made. + */ +EAPI void +isf_imf_context_cursor_location_set(Ecore_IMF_Context *ctx, int cx, int cy, int cw, int ch) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx); + Ecore_Evas *ee; + int canvas_x, canvas_y; + int new_cursor_x, new_cursor_y; + + if (cw == 0 && ch == 0) + return; + + if (context_scim && context_scim->impl && context_scim == _focused_ic) + { + if (context_scim->impl->client_canvas) + { + ee = ecore_evas_ecore_evas_get(context_scim->impl->client_canvas); + if (!ee) return; + + ecore_evas_geometry_get(ee, &canvas_x, &canvas_y, NULL, NULL); + } + else + { + if (context_scim->impl->client_window) + window_to_screen_geometry_get(context_scim->impl->client_window, &canvas_x, &canvas_y); + else + return; + } + + new_cursor_x = canvas_x + cx; + new_cursor_y = canvas_y + cy + ch; + + // Don't update spot location while updating preedit string. + if (context_scim->impl->preedit_updating && (context_scim->impl->cursor_y == new_cursor_y)) + return; + + if (context_scim->impl->cursor_x != new_cursor_x || context_scim->impl->cursor_y != new_cursor_y) + { + context_scim->impl->cursor_x = new_cursor_x; + context_scim->impl->cursor_y = new_cursor_y; + _panel_client.prepare(context_scim->id); + panel_req_update_spot_location(context_scim); + _panel_client.send(); + SCIM_DEBUG_FRONTEND(2) << "new cursor location = " << context_scim->impl->cursor_x << "," << context_scim->impl->cursor_y << "\n"; + } + } +} + +/** + * isf_imf_context_use_preedit_set + * @ctx: a #Ecore_IMF_Context + * @use_preedit: Whether the IM context should use the preedit string. + * + * This function will be called by Ecore IMF. + * + * Set whether the IM context should use the preedit string to display feedback. + * If is 0 (default is 1), then the IM context may use some other method to + * display feedback, such as displaying it in a child of the root window. + */ +EAPI void +isf_imf_context_use_preedit_set(Ecore_IMF_Context* ctx, Eina_Bool use_preedit) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " = " << (use_preedit ? "true" : "false") << "...\n"; + + EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx); + + if (!_on_the_spot) return; + + if (context_scim && context_scim->impl) + { + bool old = context_scim->impl->use_preedit; + context_scim->impl->use_preedit = use_preedit; + if (context_scim == _focused_ic) + { + _panel_client.prepare(context_scim->id); + + if (old != use_preedit) + set_ic_capabilities(context_scim); + + if (context_scim->impl->preedit_string.length()) + slot_show_preedit_string(context_scim->impl->si); + + _panel_client.send(); + } + } +} + +EAPI void +isf_imf_context_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx, char** str, Eina_List **attrs, int *cursor_pos) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx); + + if (context_scim && context_scim->impl && context_scim->impl->is_on) + { + String mbs = utf8_wcstombs(context_scim->impl->preedit_string); + + if (str) + { + if (mbs.length()) + *str = strdup(mbs.c_str()); + else + *str = strdup(""); + } + + if (cursor_pos) + { + *cursor_pos = context_scim->impl->preedit_caret; + } + + if (attrs) + { + if (mbs.length()) + { + int start_index, end_index; + int wlen = context_scim->impl->preedit_string.length(); + + Ecore_IMF_Preedit_Attr *attr = NULL; + AttributeList::const_iterator i; + bool *attrs_flag = new bool [mbs.length()]; + memset(attrs_flag, 0, mbs.length() *sizeof(bool)); + + for (i = context_scim->impl->preedit_attrlist.begin(); + i != context_scim->impl->preedit_attrlist.end(); ++i) + { + start_index = i->get_start(); + end_index = i->get_end(); + + if (end_index <= wlen && start_index < end_index && i->get_type() != SCIM_ATTR_DECORATE_NONE) + { + start_index = utf8_offset_to_index(mbs.c_str(), i->get_start()); + end_index = utf8_offset_to_index(mbs.c_str(), i->get_end()); + + if (i->get_type() == SCIM_ATTR_DECORATE) + { + attr = (Ecore_IMF_Preedit_Attr *)calloc(1, sizeof(Ecore_IMF_Preedit_Attr)); + if (attr == NULL) + continue; + attr->start_index = start_index; + attr->end_index = end_index; + + if (i->get_value() == SCIM_ATTR_DECORATE_UNDERLINE) + { + attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB1; + *attrs = eina_list_append(*attrs, (void *)attr); + } + else if (i->get_value() == SCIM_ATTR_DECORATE_REVERSE) + { + attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2; + *attrs = eina_list_append(*attrs, (void *)attr); + } + else if (i->get_value() == SCIM_ATTR_DECORATE_HIGHLIGHT) + { + attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB3; + *attrs = eina_list_append(*attrs, (void *)attr); + } + else + { + free(attr); + } + + switch(i->get_value()) + { + case SCIM_ATTR_DECORATE_UNDERLINE: + case SCIM_ATTR_DECORATE_REVERSE: + case SCIM_ATTR_DECORATE_HIGHLIGHT: + // Record which character has attribute. + for (int pos = start_index; pos < end_index; ++pos) + attrs_flag [pos] = 1; + break; + default: + break; + } + } + else if (i->get_type() == SCIM_ATTR_FOREGROUND) + { + SCIM_DEBUG_FRONTEND(4) << "SCIM_ATTR_FOREGROUND\n"; + } + else if (i->get_type() == SCIM_ATTR_BACKGROUND) + { + SCIM_DEBUG_FRONTEND(4) << "SCIM_ATTR_BACKGROUND\n"; + } + } + } + + // Add underline for all characters which don't have attribute. + for (unsigned int pos = 0; pos < mbs.length(); ++pos) + { + if (!attrs_flag [pos]) + { + int begin_pos = pos; + + while (pos < mbs.length() && !attrs_flag[pos]) + ++pos; + + // use REVERSE style as default + attr = (Ecore_IMF_Preedit_Attr *)calloc(1, sizeof(Ecore_IMF_Preedit_Attr)); + if (attr == NULL) + continue; + attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2; + attr->start_index = begin_pos; + attr->end_index = pos; + *attrs = eina_list_append(*attrs, (void *)attr); + } + } + + delete [] attrs_flag; + } + } + } + else + { + if (str) + *str = strdup(""); + + if (cursor_pos) + *cursor_pos = 0; + + if (attrs) + *attrs = NULL; + } +} + +/** + * isf_imf_context_preedit_string_get + * @ctx: a #Ecore_IMF_Context + * @str: the preedit string + * @cursor_pos: the cursor position + * + * This function will be called by Ecore IMF. + * + * To get the preedit string of the input method. + */ +EAPI void +isf_imf_context_preedit_string_get(Ecore_IMF_Context *ctx, char** str, int *cursor_pos) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx); + + if (context_scim && context_scim->impl && context_scim->impl->is_on) + { + String mbs = utf8_wcstombs(context_scim->impl->preedit_string); + + if (str) + { + if (mbs.length()) + *str = strdup(mbs.c_str()); + else + *str = strdup(""); + } + + if (cursor_pos) + *cursor_pos = context_scim->impl->preedit_caret; + } + else + { + if (str) + *str = strdup(""); + + if (cursor_pos) + *cursor_pos = 0; + } +} + +/** + * isf_imf_context_cursor_position_set + * @ctx: a #Ecore_IMF_Context + * @cursor_pos: New cursor position in characters. + * + * This function will be called by Ecore IMF. + * + * Notify the Input Method Context that a change in the cursor position has been made. + */ +EAPI void +isf_imf_context_cursor_position_set(Ecore_IMF_Context *ctx, int cursor_pos) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx); + + if (context_scim && context_scim->impl && context_scim == _focused_ic) + { + // Don't update spot location while updating preedit string. + if (context_scim->impl->preedit_updating) + return; + + if (context_scim->impl->cursor_pos != cursor_pos) + { + context_scim->impl->cursor_pos = cursor_pos; + caps_mode_check(ctx, EINA_FALSE); + } + } +} + +/** + * isf_imf_context_input_mode_set + * @ctx: a #Ecore_IMF_Context + * @input_mode: the input mode + * + * This function will be called by Ecore IMF. + * + * To set the input mode of input method. The definition of Ecore_IMF_Input_Mode + * is in Ecore_IMF.h. + */ +EAPI void +isf_imf_context_input_mode_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Mode input_mode) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx); + if (context_scim && context_scim->impl) + context_scim->impl->input_mode = input_mode; +} + +/** + * isf_imf_context_prediction_allow_set + * @ctx: a #Ecore_IMF_Context + * @use_prediction: Whether the IM context should use the prediction. + * + * This function will be called by Ecore IMF. + * + * Set whether the IM context should use the prediction. + */ +EAPI void +isf_imf_context_prediction_allow_set(Ecore_IMF_Context* ctx, Eina_Bool prediction) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " = " << (prediction ? "true" : "false") << "...\n"; + + EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx); + + if (context_scim && context_scim->impl && context_scim->impl->prediction_allow != prediction) + context_scim->impl->prediction_allow = prediction; +} + +EAPI void +isf_imf_context_autocapital_type_set(Ecore_IMF_Context* ctx, Ecore_IMF_Autocapital_Type autocapital_type) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " = " << autocapital_type << "...\n"; + + EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx); + + if (context_scim && context_scim->impl && context_scim->impl->autocapital_type != autocapital_type) + context_scim->impl->autocapital_type = autocapital_type; +} + +/** + * isf_imf_context_filter_event + * @ctx: a #Ecore_IMF_Context + * @type: The type of event defined by Ecore_IMF_Event_Type. + * @event: The event itself. + * Return value: %TRUE if the input method handled the key event. + * + * This function will be called by Ecore IMF. + * + * Allow an Ecore Input Context to internally handle an event. If this function + * returns 1, then no further processing should be done for this event. Input + * methods must be able to accept all types of events (simply returning 0 if + * the event was not handled), but there is no obligation of any events to be + * submitted to this function. + */ +EAPI Eina_Bool +isf_imf_context_filter_event(Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *ic = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx); + Eina_Bool ret = EINA_FALSE; + + if (ic == NULL || ic->impl == NULL) + return ret; + + KeyEvent key; + + if (type == ECORE_IMF_EVENT_KEY_DOWN) + { + Ecore_IMF_Event_Key_Down *ev = (Ecore_IMF_Event_Key_Down *)event; + scim_string_to_key(key, ev->key); + if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT) key.mask |=SCIM_KEY_ShiftMask; + if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_CTRL) key.mask |=SCIM_KEY_ControlMask; + if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALT) key.mask |=SCIM_KEY_AltMask; + if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALTGR) key.mask |=SCIM_KEY_Mod5Mask; + if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_CAPS) key.mask |=SCIM_KEY_CapsLockMask; + if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_NUM) key.mask |=SCIM_KEY_NumLockMask; + } + else if (type == ECORE_IMF_EVENT_KEY_UP) + { + Ecore_IMF_Event_Key_Up *ev = (Ecore_IMF_Event_Key_Up *)event; + scim_string_to_key(key, ev->key); + key.mask = SCIM_KEY_ReleaseMask; + if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT) key.mask |=SCIM_KEY_ShiftMask; + if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_CTRL) key.mask |=SCIM_KEY_ControlMask; + if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALT) key.mask |=SCIM_KEY_AltMask; + if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALTGR) key.mask |=SCIM_KEY_Mod5Mask; + if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_CAPS) key.mask |=SCIM_KEY_CapsLockMask; + if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_NUM) key.mask |=SCIM_KEY_NumLockMask; + } + else + { + return ret; + } + + key.mask &= _valid_key_mask; + + _panel_client.prepare(ic->id); + + ret = EINA_TRUE; + if (!filter_hotkeys(ic, key)) + { + if (!_focused_ic || !_focused_ic->impl->is_on || + !_focused_ic->impl->si->process_key_event(key)) + ret = EINA_FALSE; + } + + _panel_client.send(); + + return ret; +} + +EAPI void +isf_imf_context_input_panel_show(Ecore_IMF_Context *ctx) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *ic = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx); + if (ic == NULL || ic->impl == NULL) + return; + + ecore_x_e_virtual_keyboard_state_set + (ic->impl->client_window, ECORE_X_VIRTUAL_KEYBOARD_STATE_ON); +} + +EAPI void +isf_imf_context_input_panel_hide(Ecore_IMF_Context *ctx) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *ic = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx); + if (ic == NULL || ic->impl == NULL) + return; + + ecore_x_e_virtual_keyboard_state_set + (ic->impl->client_window, ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF); +} + +/* Panel Slot functions */ +static void +panel_slot_reload_config(int context __UNUSED__) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + _config->reload(); +} + +static void +panel_slot_exit(int /* context */) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + finalize(); +} + +static void +panel_slot_update_lookup_table_page_size(int context, int page_size) +{ + EcoreIMFContextISF *ic = find_ic(context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " page_size=" << page_size << " ic=" << ic << "\n"; + if (ic && ic->impl) + { + _panel_client.prepare(ic->id); + ic->impl->si->update_lookup_table_page_size(page_size); + _panel_client.send(); + } +} + +static void +panel_slot_lookup_table_page_up(int context) +{ + EcoreIMFContextISF *ic = find_ic(context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n"; + if (ic && ic->impl) + { + _panel_client.prepare(ic->id); + ic->impl->si->lookup_table_page_up(); + _panel_client.send(); + } +} + +static void +panel_slot_lookup_table_page_down(int context) +{ + EcoreIMFContextISF *ic = find_ic(context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n"; + if (ic && ic->impl) + { + _panel_client.prepare(ic->id); + ic->impl->si->lookup_table_page_down(); + _panel_client.send(); + } +} + +static void +panel_slot_trigger_property(int context, const String &property) +{ + EcoreIMFContextISF *ic = find_ic(context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " property=" << property << " ic=" << ic << "\n"; + if (ic && ic->impl) + { + _panel_client.prepare(ic->id); + ic->impl->si->trigger_property(property); + _panel_client.send(); + } +} + +static void +panel_slot_process_helper_event(int context, const String &target_uuid, const String &helper_uuid, const Transaction &trans) +{ + EcoreIMFContextISF *ic = find_ic(context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " target=" << target_uuid + << " helper=" << helper_uuid << " ic=" << ic << " ic->impl=" << (ic ? ic->impl : 0) << " ic-uuid=" + << ((ic && ic->impl) ? ic->impl->si->get_factory_uuid() : "" ) << "\n"; + if (ic && ic->impl && ic->impl->si->get_factory_uuid() == target_uuid) + { + _panel_client.prepare(ic->id); + SCIM_DEBUG_FRONTEND(2) << "call process_helper_event\n"; + ic->impl->si->process_helper_event(helper_uuid, trans); + _panel_client.send(); + } +} + +static void +panel_slot_move_preedit_caret(int context, int caret_pos) +{ + EcoreIMFContextISF *ic = find_ic(context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " caret=" << caret_pos << " ic=" << ic << "\n"; + if (ic && ic->impl) + { + _panel_client.prepare(ic->id); + ic->impl->si->move_preedit_caret(caret_pos); + _panel_client.send(); + } +} + +static void +panel_slot_select_candidate(int context, int cand_index) +{ + EcoreIMFContextISF *ic = find_ic(context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " candidate=" << cand_index << " ic=" << ic << "\n"; + if (ic && ic->impl) + { + _panel_client.prepare(ic->id); + ic->impl->si->select_candidate(cand_index); + _panel_client.send(); + } +} + +static void +panel_slot_process_key_event(int context, const KeyEvent &key) +{ + EcoreIMFContextISF *ic = find_ic(context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " key=" << key.get_key_string() << " ic=" << ic << "\n"; + + if (key.is_key_press()) + ecore_x_test_fake_key_press(key.get_key_string().c_str()); +} + +static void +panel_slot_commit_string(int context, const WideString &wstr) +{ + EcoreIMFContextISF *ic = find_ic(context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " str=" << utf8_wcstombs(wstr) << " ic=" << ic << "\n"; + + if (ic && ic->impl) + { + if (_focused_ic != ic) + return; + + ecore_imf_context_commit_event_add(ic->ctx, utf8_wcstombs(wstr).c_str()); + ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(wstr).c_str()); + } +} + +static void +panel_slot_forward_key_event(int context, const KeyEvent &key) +{ + EcoreIMFContextISF *ic = find_ic(context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " key=" << key.get_key_string() << " ic=" << ic << "\n"; + + if (ic && ic->impl && ic->impl->client_canvas) + feed_key_event(ic->impl->client_canvas, key.get_key_string().c_str(), EINA_TRUE); +} + +static void +panel_slot_request_help(int context) +{ + EcoreIMFContextISF *ic = find_ic(context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n"; + + if (ic && ic->impl) + { + _panel_client.prepare(ic->id); + panel_req_show_help(ic); + _panel_client.send(); + } +} + +static void +panel_slot_request_factory_menu(int context) +{ + EcoreIMFContextISF *ic = find_ic(context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n"; + + if (ic && ic->impl) + { + _panel_client.prepare(ic->id); + panel_req_show_factory_menu(ic); + _panel_client.send(); + } +} + +static void +panel_slot_change_factory(int context, const String &uuid) +{ + EcoreIMFContextISF *ic = find_ic(context); + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " factory=" << uuid << " ic=" << ic << "\n"; + + if (ic && ic->impl) + { + ic->impl->si->reset(); + _panel_client.prepare(ic->id); + open_specific_factory(ic, uuid); + _panel_client.send(); + } +} + +/* Panel Requestion functions. */ +static void +panel_req_show_help(EcoreIMFContextISF *ic) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + String help; + + help = String("Smart Common Input Method platform ") + + //String(SCIM_VERSION) + + String("\n(C) 2002-2005 James Su \n\n"); + + if (ic && ic->impl) + { + IMEngineFactoryPointer sf = _backend->get_factory(ic->impl->si->get_factory_uuid()); + if (sf) + { + help += utf8_wcstombs(sf->get_name()); + help += String(":\n\n"); + + help += utf8_wcstombs(sf->get_help()); + help += String("\n\n"); + + help += utf8_wcstombs(sf->get_credits()); + } + _panel_client.show_help(ic->id, help); + } +} + +static void +panel_req_show_factory_menu(EcoreIMFContextISF *ic) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + std::vector factories; + std::vector menu; + + _backend->get_factories_for_encoding(factories, "UTF-8"); + + for (size_t i = 0; i < factories.size(); ++ i) + { + menu.push_back(PanelFactoryInfo( + factories [i]->get_uuid(), + utf8_wcstombs(factories [i]->get_name()), + factories [i]->get_language(), + factories [i]->get_icon_file())); + } + + if (menu.size()) + _panel_client.show_factory_menu(ic->id, menu); +} + +static void +panel_req_update_factory_info(EcoreIMFContextISF *ic) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + if (ic && ic->impl && ic == _focused_ic) + { + PanelFactoryInfo info; + if (ic->impl->is_on) + { + IMEngineFactoryPointer sf = _backend->get_factory(ic->impl->si->get_factory_uuid()); + if (sf) + info = PanelFactoryInfo(sf->get_uuid(), utf8_wcstombs(sf->get_name()), sf->get_language(), sf->get_icon_file()); + } + else + { + info = PanelFactoryInfo(String(""), String("English/Keyboard"), String("C"), ""); + } + _panel_client.update_factory_info(ic->id, info); + } +} + +static void +panel_req_focus_in(EcoreIMFContextISF *ic) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + _panel_client.focus_in(ic->id, ic->impl->si->get_factory_uuid()); +} + +static void +panel_req_update_spot_location(EcoreIMFContextISF *ic) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + _panel_client.update_spot_location(ic->id, ic->impl->cursor_x, ic->impl->cursor_y); +} + +static bool +filter_hotkeys(EcoreIMFContextISF *ic, const KeyEvent &key) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + bool ret = false; + + _frontend_hotkey_matcher.push_key_event(key); + _imengine_hotkey_matcher.push_key_event(key); + + FrontEndHotkeyAction hotkey_action = _frontend_hotkey_matcher.get_match_result(); + + if (hotkey_action == SCIM_FRONTEND_HOTKEY_TRIGGER) + { + if (!ic->impl->is_on) + turn_on_ic(ic); + else + turn_off_ic(ic); + ret = true; + } + else if (hotkey_action == SCIM_FRONTEND_HOTKEY_ON) + { + if (!ic->impl->is_on) + turn_on_ic(ic); + ret = true; + } + else if (hotkey_action == SCIM_FRONTEND_HOTKEY_OFF) + { + if (ic->impl->is_on) + turn_off_ic(ic); + ret = true; + } + else if (hotkey_action == SCIM_FRONTEND_HOTKEY_NEXT_FACTORY) + { + open_next_factory(ic); + ret = true; + } + else if (hotkey_action == SCIM_FRONTEND_HOTKEY_PREVIOUS_FACTORY) + { + open_previous_factory(ic); + ret = true; + } + else if (hotkey_action == SCIM_FRONTEND_HOTKEY_SHOW_FACTORY_MENU) + { + panel_req_show_factory_menu(ic); + ret = true; + } + else if (_imengine_hotkey_matcher.is_matched()) + { + String sfid = _imengine_hotkey_matcher.get_match_result(); + open_specific_factory(ic, sfid); + ret = true; + } + return ret; +} + +static bool +panel_initialize(void) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + String display_name; + { + const char *p = getenv("DISPLAY"); + if (p) display_name = String(p); + } + + if (_panel_client.open_connection(_config->get_name(), display_name) >= 0) + { + int fd = _panel_client.get_connection_number(); + + _panel_iochannel_read_handler = ecore_main_fd_handler_add(fd, ECORE_FD_READ, panel_iochannel_handler, NULL, NULL, NULL); + + SCIM_DEBUG_FRONTEND(2) << " Panel FD= " << fd << "\n"; + + return true; + } + std::cerr << "panel_initialize() failed!!!\n"; + return false; +} + +static void +panel_finalize(void) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + _panel_client.close_connection(); + + if (_panel_iochannel_read_handler) + { + ecore_main_fd_handler_del(_panel_iochannel_read_handler); + _panel_iochannel_read_handler = 0; + } + + if (_panel_iochannel_err_handler) + { + ecore_main_fd_handler_del(_panel_iochannel_err_handler); + _panel_iochannel_err_handler = 0; + } +} + +static Eina_Bool +panel_iochannel_handler(void *data __UNUSED__, Ecore_Fd_Handler *fd_handler) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + if (fd_handler == _panel_iochannel_read_handler) + { + if (!_panel_client.filter_event()) + { + panel_finalize(); + panel_initialize(); + return ECORE_CALLBACK_CANCEL; + } + } + else if (fd_handler == _panel_iochannel_err_handler) + { + panel_finalize(); + panel_initialize(); + return ECORE_CALLBACK_CANCEL; + } + return ECORE_CALLBACK_RENEW; +} + +static void +turn_on_ic(EcoreIMFContextISF *ic) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + if (ic && ic->impl && !ic->impl->is_on) + { + ic->impl->is_on = true; + + if (ic == _focused_ic) + { + panel_req_focus_in(ic); + panel_req_update_spot_location(ic); + panel_req_update_factory_info(ic); + _panel_client.turn_on(ic->id); + _panel_client.hide_preedit_string(ic->id); + _panel_client.hide_aux_string(ic->id); + _panel_client.hide_lookup_table(ic->id); + ic->impl->si->focus_in(); + } + + //Record the IC on/off status + if (_shared_input_method) + _config->write(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), true); + + if (ic->impl->use_preedit && ic->impl->preedit_string.length()) + { + ecore_imf_context_preedit_start_event_add(ic->ctx); + ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL); + ecore_imf_context_preedit_changed_event_add(ic->ctx); + ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL); + ic->impl->preedit_started = true; + } + } +} + +static void +turn_off_ic(EcoreIMFContextISF *ic) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + if (ic && ic->impl && ic->impl->is_on) + { + ic->impl->is_on = false; + + if (ic == _focused_ic) + { + ic->impl->si->focus_out(); + + panel_req_update_factory_info(ic); + _panel_client.turn_off(ic->id); + } + + //Record the IC on/off status + if (_shared_input_method) + _config->write(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), false); + + if (ic->impl->use_preedit && ic->impl->preedit_string.length()) + { + ecore_imf_context_preedit_changed_event_add(ic->ctx); + ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL); + ecore_imf_context_preedit_end_event_add(ic->ctx); + ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL); + ic->impl->preedit_started = false; + } + } +} + +static void +set_ic_capabilities(EcoreIMFContextISF *ic) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + if (ic && ic->impl) + { + unsigned int cap = SCIM_CLIENT_CAP_ALL_CAPABILITIES; + + if (!_on_the_spot || !ic->impl->use_preedit) + cap -= SCIM_CLIENT_CAP_ONTHESPOT_PREEDIT; + + ic->impl->si->update_client_capabilities(cap); + } +} + +static bool +check_socket_frontend(void) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + SocketAddress address; + SocketClient client; + + uint32 magic; + + address.set_address(scim_get_default_socket_frontend_address()); + + if (!client.connect(address)) + return false; + + if (!scim_socket_open_connection(magic, + String("ConnectionTester"), + String("SocketFrontEnd"), + client, + 1000)) + return false; + + return true; +} + +void +initialize(void) +{ + std::vector config_list; + std::vector engine_list; + std::vector load_engine_list; + + std::vector::iterator it; + + bool manual = false; + + bool socket = true; + + String config_module_name = "simple"; + + printf("Initializing Ecore SCIM IMModule...\n"); + + SCIM_DEBUG_FRONTEND(1) << "Initializing Ecore SCIM IMModule...\n"; + + // Get system language. + _language = scim_get_locale_language(scim_get_current_locale()); + + if (socket) + { + // If no Socket FrontEnd is running, then launch one. + // And set manual to false. + bool check_result = check_socket_frontend(); + if (!check_result) + { + std::cerr << "Launching a SCIM daemon with Socket FrontEnd...\n"; + //get modules list + scim_get_imengine_module_list(engine_list); + + for (it = engine_list.begin(); it != engine_list.end(); it++) + { + if (*it != "socket") + load_engine_list.push_back(*it); + } + + const char *new_argv [] = { "--no-stay", 0 }; + scim_launch(true, + config_module_name, + (load_engine_list.size() ? scim_combine_string_list(load_engine_list, ',') : "none"), + "socket", + (char **)new_argv); + manual = false; + } + + // If there is one Socket FrontEnd running and it's not manual mode, + // then just use this Socket Frontend. + if (!manual) + { + for (int i = 0; i < 200; ++i) + { + if (check_result) + { + config_module_name = "socket"; + load_engine_list.clear(); + load_engine_list.push_back("socket"); + break; + } + scim_usleep(50000); + check_result = check_socket_frontend(); + } + } + } + + if (config_module_name != "dummy") + { + //load config module + SCIM_DEBUG_FRONTEND(1) << "Loading Config module: " << config_module_name << "...\n"; + _config_module = new ConfigModule(config_module_name); + + //create config instance + if (_config_module != NULL && _config_module->valid()) + _config = _config_module->create_config(); + } + + if (_config.null()) + { + SCIM_DEBUG_FRONTEND(1) << "Config module cannot be loaded, using dummy Config.\n"; + + if (_config_module) delete _config_module; + _config_module = NULL; + + _config = new DummyConfig(); + config_module_name = "dummy"; + } + + reload_config_callback(_config); + _config->signal_connect_reload(slot(reload_config_callback)); + + // create backend + _backend = new CommonBackEnd(_config, load_engine_list.size() ? load_engine_list : engine_list); + + if (_backend.null()) + std::cerr << "Cannot create BackEnd Object!\n"; + else + _fallback_factory = _backend->get_factory(SCIM_COMPOSE_KEY_FACTORY_UUID); + + if (_fallback_factory.null()) + _fallback_factory = new DummyIMEngineFactory(); + + _fallback_instance = _fallback_factory->create_instance(String("UTF-8"), 0); + _fallback_instance->signal_connect_commit_string(slot(fallback_commit_string_cb)); + + // Attach Panel Client signal. + _panel_client.signal_connect_reload_config (slot(panel_slot_reload_config)); + _panel_client.signal_connect_exit (slot(panel_slot_exit)); + _panel_client.signal_connect_update_lookup_table_page_size(slot(panel_slot_update_lookup_table_page_size)); + _panel_client.signal_connect_lookup_table_page_up (slot(panel_slot_lookup_table_page_up)); + _panel_client.signal_connect_lookup_table_page_down (slot(panel_slot_lookup_table_page_down)); + _panel_client.signal_connect_trigger_property (slot(panel_slot_trigger_property)); + _panel_client.signal_connect_process_helper_event (slot(panel_slot_process_helper_event)); + _panel_client.signal_connect_move_preedit_caret (slot(panel_slot_move_preedit_caret)); + _panel_client.signal_connect_select_candidate (slot(panel_slot_select_candidate)); + _panel_client.signal_connect_process_key_event (slot(panel_slot_process_key_event)); + _panel_client.signal_connect_commit_string (slot(panel_slot_commit_string)); + _panel_client.signal_connect_forward_key_event (slot(panel_slot_forward_key_event)); + _panel_client.signal_connect_request_help (slot(panel_slot_request_help)); + _panel_client.signal_connect_request_factory_menu (slot(panel_slot_request_factory_menu)); + _panel_client.signal_connect_change_factory (slot(panel_slot_change_factory)); + + if (!panel_initialize()) + std::cerr << "Ecore IM Module: Cannot connect to Panel!\n"; +} + +static void +finalize(void) +{ + SCIM_DEBUG_FRONTEND(1) << "Finalizing Ecore ISF IMModule...\n"; + + // Reset this first so that the shared instance could be released correctly afterwards. + _default_instance.reset(); + + SCIM_DEBUG_FRONTEND(2) << "Finalize all IC partially.\n"; + while (_used_ic_impl_list) + { + // In case in "shared input method" mode, + // all contexts share only one instance, + // so we need point the reference pointer correctly before finalizing. + _used_ic_impl_list->si->set_frontend_data(static_cast (_used_ic_impl_list->parent)); + isf_imf_context_del(_used_ic_impl_list->parent->ctx); + } + + delete_all_ic_impl(); + + _fallback_instance.reset(); + _fallback_factory.reset(); + + SCIM_DEBUG_FRONTEND(2) << " Releasing BackEnd...\n"; + _backend.reset(); + + SCIM_DEBUG_FRONTEND(2) << " Releasing Config...\n"; + _config.reset(); + + if (_config_module) + { + SCIM_DEBUG_FRONTEND(2) << " Deleting _config_module...\n"; + delete _config_module; + _config_module = 0; + } + + _focused_ic = NULL; + _ic_list = NULL; + + _scim_initialized = false; + + panel_finalize(); +} + +static void +open_next_factory(EcoreIMFContextISF *ic) +{ + SCIM_DEBUG_FRONTEND(2) << __FUNCTION__ << " context=" << ic->id << "\n"; + IMEngineFactoryPointer sf = _backend->get_next_factory("", "UTF-8", ic->impl->si->get_factory_uuid()); + + if (!sf.null()) + { + turn_off_ic(ic); + ic->impl->si = sf->create_instance("UTF-8", ic->impl->si->get_id()); + ic->impl->si->set_frontend_data(static_cast (ic)); + ic->impl->preedit_string = WideString(); + ic->impl->preedit_caret = 0; + attach_instance(ic->impl->si); + _backend->set_default_factory(_language, sf->get_uuid()); + _panel_client.register_input_context(ic->id, sf->get_uuid()); + set_ic_capabilities(ic); + turn_on_ic(ic); + + if (_shared_input_method) + { + _default_instance = ic->impl->si; + ic->impl->shared_si = true; + } + } +} + +static void +open_previous_factory(EcoreIMFContextISF *ic) +{ + if (ic == NULL) + return; + + SCIM_DEBUG_FRONTEND(2) << __FUNCTION__ << " context=" << ic->id << "\n"; + IMEngineFactoryPointer sf = _backend->get_previous_factory("", "UTF-8", ic->impl->si->get_factory_uuid()); + + if (!sf.null()) + { + turn_off_ic(ic); + ic->impl->si = sf->create_instance("UTF-8", ic->impl->si->get_id()); + ic->impl->si->set_frontend_data(static_cast (ic)); + ic->impl->preedit_string = WideString(); + ic->impl->preedit_caret = 0; + attach_instance(ic->impl->si); + _backend->set_default_factory(_language, sf->get_uuid()); + _panel_client.register_input_context(ic->id, sf->get_uuid()); + set_ic_capabilities(ic); + turn_on_ic(ic); + + if (_shared_input_method) + { + _default_instance = ic->impl->si; + ic->impl->shared_si = true; + } + } +} + +static void +open_specific_factory(EcoreIMFContextISF *ic, + const String &uuid) +{ + if (ic == NULL) + return; + + SCIM_DEBUG_FRONTEND(2) << __FUNCTION__ << " context=" << ic->id << "\n"; + + // The same input method is selected, just turn on the IC. + if (ic->impl->si->get_factory_uuid() == uuid) + { + turn_on_ic(ic); + return; + } + + IMEngineFactoryPointer sf = _backend->get_factory(uuid); + + if (uuid.length() && !sf.null()) + { + turn_off_ic(ic); + ic->impl->si = sf->create_instance("UTF-8", ic->impl->si->get_id()); + ic->impl->si->set_frontend_data(static_cast (ic)); + ic->impl->preedit_string = WideString(); + ic->impl->preedit_caret = 0; + attach_instance(ic->impl->si); + _backend->set_default_factory(_language, sf->get_uuid()); + _panel_client.register_input_context(ic->id, sf->get_uuid()); + set_ic_capabilities(ic); + turn_on_ic(ic); + + if (_shared_input_method) + { + _default_instance = ic->impl->si; + ic->impl->shared_si = true; + } + } + else + { + // turn_off_ic comment out panel_req_update_factory_info() + turn_off_ic(ic); + if (ic && ic->impl->is_on) + { + ic->impl->is_on = false; + + if (ic == _focused_ic) + { + ic->impl->si->focus_out(); + + panel_req_update_factory_info(ic); + _panel_client.turn_off(ic->id); + } + + //Record the IC on/off status + if (_shared_input_method) + _config->write(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), false); + + if (ic->impl->use_preedit && ic->impl->preedit_string.length()) + { + ecore_imf_context_preedit_changed_event_add(ic->ctx); + ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL); + ecore_imf_context_preedit_end_event_add(ic->ctx); + ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL); + ic->impl->preedit_started = false; + } + } + } +} + +static void initialize_modifier_bits(Display *display) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + if (__current_display == display) + return; + + __current_display = display; + + if (display == 0) + { + __current_alt_mask = Mod1Mask; + __current_meta_mask = ShiftMask | Mod1Mask; + __current_super_mask = 0; + __current_hyper_mask = 0; + __current_numlock_mask = Mod2Mask; + return; + } + + XModifierKeymap *mods = NULL; + + ::KeyCode ctrl_l = XKeysymToKeycode(display, XK_Control_L); + ::KeyCode ctrl_r = XKeysymToKeycode(display, XK_Control_R); + ::KeyCode meta_l = XKeysymToKeycode(display, XK_Meta_L); + ::KeyCode meta_r = XKeysymToKeycode(display, XK_Meta_R); + ::KeyCode alt_l = XKeysymToKeycode(display, XK_Alt_L); + ::KeyCode alt_r = XKeysymToKeycode(display, XK_Alt_R); + ::KeyCode super_l = XKeysymToKeycode(display, XK_Super_L); + ::KeyCode super_r = XKeysymToKeycode(display, XK_Super_R); + ::KeyCode hyper_l = XKeysymToKeycode(display, XK_Hyper_L); + ::KeyCode hyper_r = XKeysymToKeycode(display, XK_Hyper_R); + ::KeyCode numlock = XKeysymToKeycode(display, XK_Num_Lock); + + int i, j; + + mods = XGetModifierMapping(display); + if (mods == NULL) + return; + + __current_alt_mask = 0; + __current_meta_mask = 0; + __current_super_mask = 0; + __current_hyper_mask = 0; + __current_numlock_mask = 0; + + /* We skip the first three sets for Shift, Lock, and Control. The + remaining sets are for Mod1, Mod2, Mod3, Mod4, and Mod5. */ + for (i = 3; i < 8; i++) + { + for (j = 0; j < mods->max_keypermod; j++) + { + ::KeyCode code = mods->modifiermap [i * mods->max_keypermod + j]; + if (! code) continue; + if (code == alt_l || code == alt_r) + __current_alt_mask |= (1 << i); + else if (code == meta_l || code == meta_r) + __current_meta_mask |= (1 << i); + else if (code == super_l || code == super_r) + __current_super_mask |= (1 << i); + else if (code == hyper_l || code == hyper_r) + __current_hyper_mask |= (1 << i); + else if (code == numlock) + __current_numlock_mask |= (1 << i); + } + } + + /* Check whether there is a combine keys mapped to Meta */ + if (__current_meta_mask == 0) + { + char buf [32]; + XKeyEvent xkey; + KeySym keysym_l, keysym_r; + + xkey.type = KeyPress; + xkey.display = display; + xkey.serial = 0L; + xkey.send_event = False; + xkey.x = xkey.y = xkey.x_root = xkey.y_root = 0; + xkey.time = 0; + xkey.same_screen = False; + xkey.subwindow = None; + xkey.window = None; + xkey.root = DefaultRootWindow(display); + xkey.state = ShiftMask; + + xkey.keycode = meta_l; + XLookupString(&xkey, buf, 32, &keysym_l, 0); + xkey.keycode = meta_r; + XLookupString(&xkey, buf, 32, &keysym_r, 0); + + if ((meta_l == alt_l && keysym_l == XK_Meta_L) || (meta_r == alt_r && keysym_r == XK_Meta_R)) + __current_meta_mask = ShiftMask + __current_alt_mask; + else if ((meta_l == ctrl_l && keysym_l == XK_Meta_L) || (meta_r == ctrl_r && keysym_r == XK_Meta_R)) + __current_meta_mask = ShiftMask + ControlMask; + } + + XFreeModifiermap(mods); +} + +static unsigned int scim_x11_keymask_scim_to_x11(Display *display, uint16 scimkeymask) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + unsigned int state = 0; + + initialize_modifier_bits(display); + + if (scimkeymask & SCIM_KEY_ShiftMask) state |= ShiftMask; + if (scimkeymask & SCIM_KEY_CapsLockMask) state |= LockMask; + if (scimkeymask & SCIM_KEY_ControlMask) state |= ControlMask; + if (scimkeymask & SCIM_KEY_AltMask) state |= __current_alt_mask; + if (scimkeymask & SCIM_KEY_MetaMask) state |= __current_meta_mask; + if (scimkeymask & SCIM_KEY_SuperMask) state |= __current_super_mask; + if (scimkeymask & SCIM_KEY_HyperMask) state |= __current_hyper_mask; + if (scimkeymask & SCIM_KEY_NumLockMask) state |= __current_numlock_mask; + + return state; +} + +static XKeyEvent createKeyEvent(Display *display, Window &win, + Window &winRoot, bool press, + int keycode, int modifiers) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + XKeyEvent event; + + event.display = display; + event.window = win; + event.root = winRoot; + event.subwindow = None; + event.time = CurrentTime; + event.x = 1; + event.y = 1; + event.x_root = 1; + event.y_root = 1; + event.same_screen = EINA_TRUE; + event.state = modifiers; + event.keycode = XKeysymToKeycode(display, keycode); + if (press) + event.type = KeyPress; + else + event.type = KeyRelease; + event.send_event = EINA_FALSE; + event.serial = 0; + + return event; +} + +static void _x_send_key_event(const KeyEvent &key) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + // Obtain the X11 display. + Display *display = XOpenDisplay(NULL); + if (display == NULL) + { + std::cerr << "XOpenDisplay failed\n"; + return; + } + + // Get the root window for the current display. + Window winRoot = 0; + + // Find the window which has the current keyboard focus. + Window winFocus = 0; + int revert = RevertToParent; + + XGetInputFocus(display, &winFocus, &revert); + + // Send a fake key press event to the window. + XSelectInput(display, winFocus, FocusChangeMask|KeyPressMask|KeyReleaseMask); + XMapWindow(display, winFocus); + + unsigned int modifier = scim_x11_keymask_scim_to_x11(display, key.mask); + XKeyEvent event; + if (key.is_key_press()) + { + event = createKeyEvent(display, winFocus, winRoot, true, key.code, modifier); + XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event); + } + else + { + event = createKeyEvent(display, winFocus, winRoot, false, key.code, modifier); + XSendEvent(event.display, event.window, True, KeyReleaseMask, (XEvent *)&event); + } + + XCloseDisplay(display); +} + +static void +attach_instance(const IMEngineInstancePointer &si) +{ + si->signal_connect_show_preedit_string( + slot(slot_show_preedit_string)); + si->signal_connect_show_aux_string( + slot(slot_show_aux_string)); + si->signal_connect_show_lookup_table( + slot(slot_show_lookup_table)); + + si->signal_connect_hide_preedit_string( + slot(slot_hide_preedit_string)); + si->signal_connect_hide_aux_string( + slot(slot_hide_aux_string)); + si->signal_connect_hide_lookup_table( + slot(slot_hide_lookup_table)); + + si->signal_connect_update_preedit_caret( + slot(slot_update_preedit_caret)); + si->signal_connect_update_preedit_string( + slot(slot_update_preedit_string)); + si->signal_connect_update_aux_string( + slot(slot_update_aux_string)); + si->signal_connect_update_lookup_table( + slot(slot_update_lookup_table)); + + si->signal_connect_commit_string( + slot(slot_commit_string)); + + si->signal_connect_forward_key_event( + slot(slot_forward_key_event)); + + si->signal_connect_register_properties( + slot(slot_register_properties)); + + si->signal_connect_update_property( + slot(slot_update_property)); + + si->signal_connect_beep( + slot(slot_beep)); + + si->signal_connect_start_helper( + slot(slot_start_helper)); + + si->signal_connect_stop_helper( + slot(slot_stop_helper)); + + si->signal_connect_send_helper_event( + slot(slot_send_helper_event)); + + si->signal_connect_get_surrounding_text( + slot(slot_get_surrounding_text)); + + si->signal_connect_delete_surrounding_text( + slot(slot_delete_surrounding_text)); +} + +// Implementation of slot functions +static void +slot_show_preedit_string(IMEngineInstanceBase *si) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *ic = static_cast(si->get_frontend_data()); + + if (ic && ic->impl && _focused_ic == ic) + { + if (ic->impl->use_preedit) + { + if (!ic->impl->preedit_started) + { + ecore_imf_context_preedit_start_event_add(_focused_ic->ctx); + ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL); + ic->impl->preedit_started = true; + } + } + else + _panel_client.show_preedit_string(ic->id); + } +} + +static void +slot_show_aux_string(IMEngineInstanceBase *si) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *ic = static_cast(si->get_frontend_data()); + + if (ic && ic->impl && _focused_ic == ic) + _panel_client.show_aux_string(ic->id); +} + +static void +slot_show_lookup_table(IMEngineInstanceBase *si) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *ic = static_cast(si->get_frontend_data()); + + if (ic && ic->impl && _focused_ic == ic) + _panel_client.show_lookup_table(ic->id); +} + +static void +slot_hide_preedit_string(IMEngineInstanceBase *si) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *ic = static_cast(si->get_frontend_data()); + + if (ic && ic->impl && _focused_ic == ic) + { + bool emit = false; + if (ic->impl->preedit_string.length()) + { + ic->impl->preedit_string = WideString(); + ic->impl->preedit_caret = 0; + ic->impl->preedit_attrlist.clear(); + emit = true; + } + if (ic->impl->use_preedit) + { + if (emit) + { + ecore_imf_context_preedit_changed_event_add(ic->ctx); + ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL); + } + if (ic->impl->preedit_started) + { + ecore_imf_context_preedit_end_event_add(ic->ctx); + ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL); + ic->impl->preedit_started = false; + } + } + else + _panel_client.hide_preedit_string(ic->id); + } +} + +static void +slot_hide_aux_string(IMEngineInstanceBase *si) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *ic = static_cast(si->get_frontend_data()); + + if (ic && ic->impl && _focused_ic == ic) + _panel_client.hide_aux_string(ic->id); +} + +static void +slot_hide_lookup_table(IMEngineInstanceBase *si) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *ic = static_cast(si->get_frontend_data()); + + if (ic && ic->impl && _focused_ic == ic) + _panel_client.hide_lookup_table(ic->id); +} + +static void +slot_update_preedit_caret(IMEngineInstanceBase *si, int caret) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *ic = static_cast(si->get_frontend_data()); + + if (ic && ic->impl && _focused_ic == ic && ic->impl->preedit_caret != caret) + { + ic->impl->preedit_caret = caret; + if (ic->impl->use_preedit) + { + if (!ic->impl->preedit_started) + { + ecore_imf_context_preedit_start_event_add(ic->ctx); + ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL); + ic->impl->preedit_started = true; + } + ecore_imf_context_preedit_changed_event_add(ic->ctx); + ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL); + } + else + _panel_client.update_preedit_caret(ic->id, caret); + } +} + +static void +slot_update_preedit_string(IMEngineInstanceBase *si, + const WideString & str, + const AttributeList & attrs) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *ic = static_cast(si->get_frontend_data()); + + if (ic && ic->impl && _focused_ic == ic && (ic->impl->preedit_string != str || str.length())) + { + ic->impl->preedit_string = str; + ic->impl->preedit_attrlist = attrs; + if (ic->impl->use_preedit) + { + if (!ic->impl->preedit_started) + { + ecore_imf_context_preedit_start_event_add(_focused_ic->ctx); + ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL); + ic->impl->preedit_started = true; + } + ic->impl->preedit_caret = str.length(); + ic->impl->preedit_updating = true; + ecore_imf_context_preedit_changed_event_add(ic->ctx); + ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL); + ic->impl->preedit_updating = false; + } + else + { + _panel_client.update_preedit_string(ic->id, str, attrs); + } + } +} + +static void +slot_update_aux_string(IMEngineInstanceBase *si, + const WideString & str, + const AttributeList & attrs) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *ic = static_cast(si->get_frontend_data()); + + if (ic && ic->impl && _focused_ic == ic) + _panel_client.update_aux_string(ic->id, str, attrs); +} + +static void +slot_commit_string(IMEngineInstanceBase *si, + const WideString & str) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *ic = static_cast(si->get_frontend_data()); + + if (ic && ic->ctx) + { + ecore_imf_context_commit_event_add(ic->ctx, utf8_wcstombs(str).c_str()); + ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(str).c_str()); + } +} + +static void +slot_forward_key_event(IMEngineInstanceBase *si, + const KeyEvent & key) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *ic = static_cast(si->get_frontend_data()); + + if (ic && _focused_ic == ic) + { + if (!_fallback_instance->process_key_event(key)) + _x_send_key_event(key); + } +} + +static void +slot_update_lookup_table(IMEngineInstanceBase *si, + const LookupTable & table) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *ic = static_cast(si->get_frontend_data()); + + if (ic && ic->impl && _focused_ic == ic) + _panel_client.update_lookup_table(ic->id, table); +} + +static void +slot_register_properties(IMEngineInstanceBase *si, + const PropertyList & properties) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *ic = static_cast(si->get_frontend_data()); + + if (ic && ic->impl && _focused_ic == ic) + _panel_client.register_properties(ic->id, properties); +} + +static void +slot_update_property(IMEngineInstanceBase *si, + const Property & property) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *ic = static_cast(si->get_frontend_data()); + + if (ic && ic->impl && _focused_ic == ic) + _panel_client.update_property(ic->id, property); +} + +static void +slot_beep(IMEngineInstanceBase *si __UNUSED__) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; +} + +static void +slot_start_helper(IMEngineInstanceBase *si, + const String &helper_uuid) +{ + EcoreIMFContextISF *ic = static_cast(si->get_frontend_data()); + + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " helper= " << helper_uuid << " context=" + << (ic ? ic->id : -1) << " ic=" << ic + << " ic-uuid=" << ((ic ) ? ic->impl->si->get_factory_uuid() : "") << "...\n"; + + if (ic && ic->impl) + _panel_client.start_helper(ic->id, helper_uuid); +} + +static void +slot_stop_helper(IMEngineInstanceBase *si, + const String &helper_uuid) +{ + EcoreIMFContextISF *ic = static_cast(si->get_frontend_data()); + + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " helper= " << helper_uuid << " context=" << (ic ? ic->id : -1) << " ic=" << ic << "...\n"; + + if (ic && ic->impl) + _panel_client.stop_helper(ic->id, helper_uuid); +} + +static void +slot_send_helper_event(IMEngineInstanceBase *si, + const String &helper_uuid, + const Transaction &trans) +{ + EcoreIMFContextISF *ic = static_cast(si->get_frontend_data()); + + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " helper= " << helper_uuid << " context=" + << (ic ? ic->id : -1) << " ic=" << ic + << " ic-uuid=" << ((ic) ? ic->impl->si->get_factory_uuid() : "") << "...\n"; + + if (ic && ic->impl) + _panel_client.send_helper_event(ic->id, helper_uuid, trans); +} + +static bool +slot_get_surrounding_text(IMEngineInstanceBase *si, + WideString &text, + int &cursor, + int maxlen_before, + int maxlen_after) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *ic = static_cast(si->get_frontend_data()); + + if (ic && ic->impl && _focused_ic == ic) + { + char *surrounding = NULL; + int cursor_index; + if (ecore_imf_context_surrounding_get(_focused_ic->ctx, &surrounding, &cursor_index)) + { + SCIM_DEBUG_FRONTEND(2) << "Surrounding text: " << surrounding <<"\n"; + SCIM_DEBUG_FRONTEND(2) << "Cursor Index : " << cursor_index <<"\n"; + WideString before(utf8_mbstowcs(String(surrounding, surrounding + cursor_index))); + WideString after(utf8_mbstowcs(String(surrounding + cursor_index))); + if (maxlen_before > 0 && ((unsigned int)maxlen_before) < before.length()) + before = WideString(before.begin() + (before.length() - maxlen_before), before.end()); + else if (maxlen_before == 0) before = WideString(); + if (maxlen_after > 0 && ((unsigned int)maxlen_after) < after.length()) + after = WideString(after.begin(), after.begin() + maxlen_after); + else if (maxlen_after == 0) after = WideString(); + text = before + after; + cursor = before.length(); + return true; + } + } + return false; +} + +static bool +slot_delete_surrounding_text(IMEngineInstanceBase *si, + int offset, + int len) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + EcoreIMFContextISF *ic = static_cast(si->get_frontend_data()); + + if (ic && ic->impl && _focused_ic == ic) + { + Ecore_IMF_Event_Delete_Surrounding ev; + ev.ctx = _focused_ic->ctx; + ev.n_chars = len; + ev.offset = offset; + ecore_imf_context_delete_surrounding_event_add(_focused_ic->ctx, offset, len); + ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, &ev); + return true; + } + return false; +} + +static void +reload_config_callback(const ConfigPointer &config) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + _frontend_hotkey_matcher.load_hotkeys(config); + _imengine_hotkey_matcher.load_hotkeys(config); + + KeyEvent key; + + scim_string_to_key(key, + config->read(String(SCIM_CONFIG_HOTKEYS_FRONTEND_VALID_KEY_MASK), + String("Shift+Control+Alt+Lock"))); + + _valid_key_mask = (key.mask > 0)?(key.mask):0xFFFF; + _valid_key_mask |= SCIM_KEY_ReleaseMask; + // Special treatment for two backslash keys on jp106 keyboard. + _valid_key_mask |= SCIM_KEY_QuirkKanaRoMask; + + _on_the_spot = config->read(String(SCIM_CONFIG_FRONTEND_ON_THE_SPOT), _on_the_spot); + _shared_input_method = config->read(String(SCIM_CONFIG_FRONTEND_SHARED_INPUT_METHOD), _shared_input_method); + + // Get keyboard layout setting + // Flush the global config first, in order to load the new configs from disk. + scim_global_config_flush(); + + _keyboard_layout = scim_get_default_keyboard_layout(); +} + +static void +fallback_commit_string_cb(IMEngineInstanceBase *si __UNUSED__, + const WideString &str) +{ + SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n"; + + if (_focused_ic && _focused_ic->impl) + { + ecore_imf_context_commit_event_add(_focused_ic->ctx, utf8_wcstombs(str).c_str()); + ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(str).c_str()); + } +} + diff --git a/src/modules/immodules/scim/scim_imcontext.h b/src/modules/immodules/scim/scim_imcontext.h new file mode 100644 index 0000000..72533e2 --- /dev/null +++ b/src/modules/immodules/scim/scim_imcontext.h @@ -0,0 +1,42 @@ +#ifndef __ISF_IMF_CONTEXT_H +#define __ISF_IMF_CONTEXT_H + +#include + +typedef struct _EcoreIMFContextISF EcoreIMFContextISF; +typedef struct _EcoreIMFContextISFImpl EcoreIMFContextISFImpl; + +struct _EcoreIMFContextISF { + Ecore_IMF_Context *ctx; + + EcoreIMFContextISFImpl *impl; + + int id; /* Input Context id*/ + struct _EcoreIMFContextISF *next; +}; + +void isf_imf_context_add (Ecore_IMF_Context *ctx); +void isf_imf_context_del (Ecore_IMF_Context *ctx); +void isf_imf_context_client_window_set (Ecore_IMF_Context *ctx, void *window); +void isf_imf_context_client_canvas_set (Ecore_IMF_Context *ctx, void *window); +void isf_imf_context_focus_in (Ecore_IMF_Context *ctx); +void isf_imf_context_focus_out (Ecore_IMF_Context *ctx); +void isf_imf_context_reset (Ecore_IMF_Context *ctx); +void isf_imf_context_cursor_position_set (Ecore_IMF_Context *ctx, int cursor_pos); +void isf_imf_context_cursor_location_set (Ecore_IMF_Context *ctx, int x, int y, int w, int h); +void isf_imf_context_input_mode_set (Ecore_IMF_Context *ctx, Ecore_IMF_Input_Mode input_mode); +void isf_imf_context_preedit_string_get (Ecore_IMF_Context *ctx, char** str, int *cursor_pos); +void isf_imf_context_preedit_string_with_attributes_get (Ecore_IMF_Context *ctx, char** str, Eina_List **attrs, int *cursor_pos); +void isf_imf_context_use_preedit_set (Ecore_IMF_Context* ctx, Eina_Bool use_preedit); +Eina_Bool isf_imf_context_filter_event (Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event); +void isf_imf_context_prediction_allow_set (Ecore_IMF_Context* ctx, Eina_Bool prediction); +void isf_imf_context_autocapital_type_set (Ecore_IMF_Context* ctx, Ecore_IMF_Autocapital_Type autocapital_type); +void isf_imf_context_input_panel_layout_set (Ecore_IMF_Context* ctx, Ecore_IMF_Input_Panel_Layout layout); +void isf_imf_context_input_panel_show(Ecore_IMF_Context *ctx); +void isf_imf_context_input_panel_hide(Ecore_IMF_Context *ctx); + +EcoreIMFContextISF* isf_imf_context_new (void); +void isf_imf_context_shutdown (void); + +#endif /* __ISF_IMF_CONTEXT_H */ + diff --git a/src/modules/immodules/scim/scim_module.cpp b/src/modules/immodules/scim/scim_module.cpp new file mode 100644 index 0000000..d77fb11 --- /dev/null +++ b/src/modules/immodules/scim/scim_module.cpp @@ -0,0 +1,104 @@ +#include +#include "scim_imcontext.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + static const Ecore_IMF_Context_Info isf_imf_info = { + "scim", /* ID */ + "SCIM immodule for Ecore", /* Description */ + "*", /* Default locales */ + NULL, /* Canvas type */ + 0 /* Canvas required */ + }; + + static Ecore_IMF_Context_Class isf_imf_class = { + isf_imf_context_add, /* add */ + isf_imf_context_del, /* del */ + isf_imf_context_client_window_set, /* client_window_set */ + isf_imf_context_client_canvas_set, /* client_canvas_set */ + isf_imf_context_input_panel_show, /* input_panel_show, - show */ + isf_imf_context_input_panel_hide, /* input_panel_hide, - hide */ + isf_imf_context_preedit_string_get, /* get_preedit_string */ + isf_imf_context_focus_in, /* focus_in */ + isf_imf_context_focus_out, /* focus_out */ + isf_imf_context_reset, /* reset */ + isf_imf_context_cursor_position_set, /* cursor_position_set */ + isf_imf_context_use_preedit_set, /* use_preedit_set */ + isf_imf_context_input_mode_set, /* input_mode_set */ + isf_imf_context_filter_event, /* filter_event */ + isf_imf_context_preedit_string_with_attributes_get, /* preedit_string_with_attribute_get */ + isf_imf_context_prediction_allow_set, /* prediction_allow_set */ + isf_imf_context_autocapital_type_set, /* autocapital_type_set */ + NULL, /* control panel show */ + NULL, /* control panel hide */ + NULL, /* input_panel_layout_set */ + NULL, /* isf_imf_context_input_panel_layout_get, */ + NULL, /* isf_imf_context_input_panel_language_set, */ + NULL, /* isf_imf_context_input_panel_language_get, */ + isf_imf_context_cursor_location_set, /* cursor_location_set */ + NULL, /* input_panel_imdata_set */ + NULL, /* input_panel_imdata_get */ + NULL, /* input_panel_return_key_type_set */ + NULL, /* input_panel_return_key_disabled_set */ + NULL, /* input_panel_caps_lock_mode_set */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL + }; + + static Ecore_IMF_Context *imf_module_create (void); + static Ecore_IMF_Context *imf_module_exit (void); + + static Eina_Bool imf_module_init (void) + { + ecore_imf_module_register (&isf_imf_info, imf_module_create, imf_module_exit); + return EINA_TRUE; + } + + static void imf_module_shutdown (void) + { + isf_imf_context_shutdown (); + } + + static Ecore_IMF_Context *imf_module_create (void) + { + Ecore_IMF_Context *ctx = NULL; + EcoreIMFContextISF *ctxd = NULL; + + ctxd = isf_imf_context_new (); + if (!ctxd) + { + printf ("isf_imf_context_new () failed!!!\n"); + return NULL; + } + + ctx = ecore_imf_context_new (&isf_imf_class); + if (!ctx) + { + delete ctxd; + return NULL; + } + + ecore_imf_context_data_set (ctx, ctxd); + + return ctx; + } + + static Ecore_IMF_Context *imf_module_exit (void) + { + return NULL; + } + + EINA_MODULE_INIT(imf_module_init); + EINA_MODULE_SHUTDOWN(imf_module_shutdown); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + diff --git a/src/modules/immodules/xim/Makefile.am b/src/modules/immodules/xim/Makefile.am new file mode 100644 index 0000000..57a9068 --- /dev/null +++ b/src/modules/immodules/xim/Makefile.am @@ -0,0 +1,29 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_srcdir) \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore_input \ +-I$(top_srcdir)/src/lib/ecore_x \ +-I$(top_srcdir)/src/lib/ecore_imf \ +-I$(top_builddir)/src/lib/ecore \ +-I$(top_builddir)/src/lib/ecore_input \ +-I$(top_builddir)/src/lib/ecore_x \ +-I$(top_builddir)/src/lib/ecore_imf \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \ +@x_cflags@ \ +@EINA_CFLAGS@ + +pkgdir = $(libdir)/ecore/immodules + +pkg_LTLIBRARIES = xim.la +xim_la_SOURCES = \ +ecore_imf_xim.c +xim_la_LIBADD = \ + $(top_builddir)/src/lib/ecore_imf/libecore_imf.la \ + $(top_builddir)/src/lib/ecore_x/libecore_x.la \ + @x_libs@ \ + @EINA_LIBS@ +xim_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version +xim_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/src/modules/immodules/xim/ecore_imf_xim.c b/src/modules/immodules/xim/ecore_imf_xim.c new file mode 100644 index 0000000..bab1aa7 --- /dev/null +++ b/src/modules/immodules/xim/ecore_imf_xim.c @@ -0,0 +1,1555 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CLAMP(x, low, high) (x > high) ? high : (x < low) ? low : x +#define _(x) x + +#ifdef ENABLE_XIM +static Eina_List *open_ims = NULL; +#endif + +#define FEEDBACK_MASK (XIMReverse | XIMUnderline | XIMHighlight) + +typedef struct _XIM_Im_Info XIM_Im_Info; + +typedef struct _Ecore_IMF_Context_Data Ecore_IMF_Context_Data; + +struct _XIM_Im_Info +{ + Ecore_X_Window win; + Ecore_IMF_Context_Data *user; + char *locale; + XIM im; + Eina_List *ics; + Eina_Bool reconnecting; + XIMStyles *xim_styles; + Eina_Bool supports_string_conversion : 1; + Eina_Bool supports_cursor : 1; +}; + +struct _Ecore_IMF_Context_Data +{ + Ecore_X_Window win; + long mask; + XIC ic; /* Input context for composed characters */ + char *locale; + XIM_Im_Info *im_info; + int preedit_length; + int preedit_cursor; + Eina_Unicode *preedit_chars; + Eina_Bool use_preedit; + Eina_Bool finalizing; + Eina_Bool has_focus; + Eina_Bool in_toplevel; + XIMFeedback *feedbacks; + + XIMCallback destroy_cb; + + XIMCallback preedit_start_cb; + XIMCallback preedit_done_cb; + XIMCallback preedit_draw_cb; + XIMCallback preedit_caret_cb; +}; + +/* prototype */ +Ecore_IMF_Context_Data *imf_context_data_new(); +void imf_context_data_destroy(Ecore_IMF_Context_Data *imf_context_data); + +#ifdef ENABLE_XIM +static void add_feedback_attr(Eina_List **attrs, + const char *str, + XIMFeedback feedback, + int start_pos, + int end_pos); + +static void reinitialize_ic(Ecore_IMF_Context *ctx); +static void set_ic_client_window(Ecore_IMF_Context *ctx, + Ecore_X_Window window); +static int preedit_start_callback(XIC xic, + XPointer client_data, + XPointer call_data); +static void preedit_done_callback(XIC xic, + XPointer client_data, + XPointer call_data); +static int xim_text_to_utf8(Ecore_IMF_Context *ctx, + XIMText *xim_text, + char **text); +static void preedit_draw_callback(XIC xic, + XPointer client_data, + XIMPreeditDrawCallbackStruct *call_data); +static void preedit_caret_callback(XIC xic, + XPointer client_data, + XIMPreeditCaretCallbackStruct *call_data); +static XVaNestedList preedit_callback_set(Ecore_IMF_Context *ctx); +static XIC get_ic(Ecore_IMF_Context *ctx); +static XIM_Im_Info *get_im(Ecore_X_Window window, + char *locale); +static void xim_info_try_im(XIM_Im_Info *info); +static void xim_info_display_closed(Ecore_X_Display *display, + int is_error, + XIM_Im_Info *info); +static void xim_instantiate_callback(Display *display, + XPointer client_data, + XPointer call_data); +static void setup_im(XIM_Im_Info *info); +static void xim_destroy_callback(XIM xim, + XPointer client_data, + XPointer call_data); +#endif + +#ifdef ENABLE_XIM +static unsigned int +utf8_offset_to_index(const char *str, int offset) +{ + int idx = 0; + int i; + for (i = 0; i < offset; i++) + { + eina_unicode_utf8_get_next(str, &idx); + } + + return idx; +} + +#endif + +static void +_ecore_imf_context_xim_add(Ecore_IMF_Context *ctx) +{ + EINA_LOG_DBG("in"); +#ifdef ENABLE_XIM + Ecore_IMF_Context_Data *imf_context_data = NULL; + + imf_context_data = imf_context_data_new(); + EINA_SAFETY_ON_NULL_RETURN(imf_context_data); + + imf_context_data->use_preedit = EINA_TRUE; + imf_context_data->finalizing = EINA_FALSE; + imf_context_data->has_focus = EINA_FALSE; + imf_context_data->in_toplevel = EINA_FALSE; + + ecore_imf_context_data_set(ctx, imf_context_data); +#else + (void)ctx; +#endif +} + +static void +_ecore_imf_context_xim_del(Ecore_IMF_Context *ctx) +{ + EINA_LOG_DBG("in"); +#ifdef ENABLE_XIM + Ecore_IMF_Context_Data *imf_context_data; + imf_context_data = ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(imf_context_data); + + imf_context_data->finalizing = EINA_TRUE; + if (imf_context_data->im_info && !imf_context_data->im_info->ics->next) + { + if (imf_context_data->im_info->reconnecting == EINA_TRUE) + { + Ecore_X_Display *dsp; + dsp = ecore_x_display_get(); + XUnregisterIMInstantiateCallback(dsp, + NULL, NULL, NULL, + xim_instantiate_callback, + (XPointer)imf_context_data->im_info); + } + else if (imf_context_data->im_info->im) + { + XIMCallback im_destroy_callback; + im_destroy_callback.client_data = NULL; + im_destroy_callback.callback = NULL; + XSetIMValues(imf_context_data->im_info->im, + XNDestroyCallback, &im_destroy_callback, + NULL); + } + } + + set_ic_client_window(ctx, 0); + + imf_context_data_destroy(imf_context_data); +#else + (void)ctx; +#endif +} + +static void +_ecore_imf_context_xim_client_window_set(Ecore_IMF_Context *ctx, + void *window) +{ + EINA_LOG_DBG("in"); +#ifdef ENABLE_XIM + set_ic_client_window(ctx, (Ecore_X_Window)((Ecore_Window)window)); +#else + (void)ctx; + (void)window; +#endif +} + +static void +_ecore_imf_context_xim_preedit_string_get(Ecore_IMF_Context *ctx, + char **str, + int *cursor_pos) +{ + EINA_LOG_DBG("in"); +#ifdef ENABLE_XIM + Ecore_IMF_Context_Data *imf_context_data; + char *utf8; + int len; + imf_context_data = ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(imf_context_data); + + if (imf_context_data->preedit_chars) + { + utf8 = eina_unicode_unicode_to_utf8(imf_context_data->preedit_chars, + &len); + if (str) + *str = utf8; + else + free(utf8); + } + else + { + if (str) + *str = NULL; + if (cursor_pos) + *cursor_pos = 0; + } + + if (cursor_pos) + *cursor_pos = imf_context_data->preedit_cursor; +#else + (void)ctx; + if (str) + *str = NULL; + if (cursor_pos) + *cursor_pos = 0; +#endif +} + +static void +_ecore_imf_context_xim_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx, + char **str, + Eina_List **attrs, + int *cursor_pos) +{ + EINA_LOG_DBG("in"); + +#ifdef ENABLE_XIM + Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx); + + _ecore_imf_context_xim_preedit_string_get(ctx, str, cursor_pos); + + if (!attrs) return; + if (!imf_context_data || !imf_context_data->feedbacks) return; + + int i = 0; + XIMFeedback last_feedback = 0; + int start = -1; + + for (i = 0; i < imf_context_data->preedit_length; i++) + { + XIMFeedback new_feedback = imf_context_data->feedbacks[i] & FEEDBACK_MASK; + + if (new_feedback != last_feedback) + { + if (start >= 0) + add_feedback_attr(attrs, *str, last_feedback, start, i); + + last_feedback = new_feedback; + start = i; + } + } + + if (start >= 0) + add_feedback_attr(attrs, *str, last_feedback, start, i); +#else + (void)ctx; + if (str) + *str = NULL; + if (attrs) + *attrs = NULL; + if (cursor_pos) + *cursor_pos = 0; +#endif +} + +static void +_ecore_imf_context_xim_focus_in(Ecore_IMF_Context *ctx) +{ + EINA_LOG_DBG("in"); +#ifdef ENABLE_XIM + XIC ic; + Ecore_IMF_Context_Data *imf_context_data; + imf_context_data = ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(imf_context_data); + + ic = imf_context_data->ic; + imf_context_data->has_focus = EINA_TRUE; + + if (ecore_imf_context_input_panel_enabled_get(ctx)) + ecore_imf_context_input_panel_show(ctx); + + if (ic) + { + char *str; + +#ifdef X_HAVE_UTF8_STRING + if ((str = Xutf8ResetIC(ic))) +#else + if ((str = XmbResetIC(ic))) +#endif + XFree(str); + + XSetICFocus(ic); + } +#else + (void)ctx; +#endif +} + +static void +_ecore_imf_context_xim_focus_out(Ecore_IMF_Context *ctx) +{ + EINA_LOG_DBG("%s in", __FUNCTION__); +#ifdef ENABLE_XIM + XIC ic; + Ecore_IMF_Context_Data *imf_context_data; + imf_context_data = ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(imf_context_data); + + if (imf_context_data->has_focus == EINA_TRUE) + { + imf_context_data->has_focus = EINA_FALSE; + ic = imf_context_data->ic; + if (ic) + XUnsetICFocus(ic); + + if (ecore_imf_context_input_panel_enabled_get(ctx)) + ecore_imf_context_input_panel_hide(ctx); + } +#else + (void)ctx; +#endif +} + +static void +_ecore_imf_context_xim_reset(Ecore_IMF_Context *ctx) +{ + EINA_LOG_DBG("%s in", __FUNCTION__); +#ifdef ENABLE_XIM + XIC ic; + Ecore_IMF_Context_Data *imf_context_data; + char *result; + + /* restore conversion state after resetting ic later */ + XIMPreeditState preedit_state = XIMPreeditUnKnown; + XVaNestedList preedit_attr; + Eina_Bool have_preedit_state = EINA_FALSE; + + imf_context_data = ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(imf_context_data); + + ic = imf_context_data->ic; + if (!ic) + return; + + if (imf_context_data->preedit_length == 0) + return; + + preedit_attr = XVaCreateNestedList(0, + XNPreeditState, &preedit_state, + NULL); + if (!XGetICValues(ic, + XNPreeditAttributes, preedit_attr, + NULL)) + have_preedit_state = EINA_TRUE; + + XFree(preedit_attr); + + result = XmbResetIC(ic); + + preedit_attr = XVaCreateNestedList(0, + XNPreeditState, preedit_state, + NULL); + if (have_preedit_state) + XSetICValues(ic, + XNPreeditAttributes, preedit_attr, + NULL); + + XFree(preedit_attr); + + if (imf_context_data->feedbacks) + { + free(imf_context_data->feedbacks); + imf_context_data->feedbacks = NULL; + } + + if (imf_context_data->preedit_length) + { + imf_context_data->preedit_length = 0; + free(imf_context_data->preedit_chars); + imf_context_data->preedit_chars = NULL; + + ecore_imf_context_preedit_changed_event_add(ctx); + ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL); + } + + if (result) + { + char *result_utf8 = strdup(result); + if (result_utf8) + { + ecore_imf_context_commit_event_add(ctx, result_utf8); + ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_COMMIT, result_utf8); + free(result_utf8); + } + } + + XFree(result); +#else + (void)ctx; +#endif +} + +static void +_ecore_imf_context_xim_use_preedit_set(Ecore_IMF_Context *ctx, + Eina_Bool use_preedit) +{ + EINA_LOG_DBG("in"); +#ifdef ENABLE_XIM + Ecore_IMF_Context_Data *imf_context_data; + imf_context_data = ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(imf_context_data); + + use_preedit = use_preedit != EINA_FALSE; + + if (imf_context_data->use_preedit != use_preedit) + { + imf_context_data->use_preedit = use_preedit; + reinitialize_ic(ctx); + } +#else + (void)ctx; + (void)use_preedit; +#endif +} + +#ifdef ENABLE_XIM +static void +add_feedback_attr(Eina_List **attrs, + const char *str, + XIMFeedback feedback, + int start_pos, + int end_pos) +{ + Ecore_IMF_Preedit_Attr *attr = NULL; + + unsigned int start_index = utf8_offset_to_index(str, start_pos); + unsigned int end_index = utf8_offset_to_index(str, end_pos); + + if (feedback & FEEDBACK_MASK) + { + attr = (Ecore_IMF_Preedit_Attr *)calloc(1, sizeof(Ecore_IMF_Preedit_Attr)); + attr->start_index = start_index; + attr->end_index = end_index; + *attrs = eina_list_append(*attrs, (void *)attr); + } + + if (feedback & XIMUnderline) + attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB1; + + if (feedback & XIMReverse) + attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2; + + if (feedback & XIMHighlight) + attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB3; +} + +#endif + +static void +_ecore_imf_context_xim_cursor_location_set(Ecore_IMF_Context *ctx, + int x, int y, int w, int h) +{ + EINA_LOG_DBG("%s in", __FUNCTION__); + +#ifdef ENABLE_XIM + Ecore_IMF_Context_Data *imf_context_data; + XIC ic; + XVaNestedList preedit_attr; + XPoint spot; + + imf_context_data = ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(imf_context_data); + ic = imf_context_data->ic; + if (!ic) + return; + + spot.x = x; + spot.y = y + h; + + preedit_attr = XVaCreateNestedList(0, + XNSpotLocation, &spot, + NULL); + XSetICValues(ic, + XNPreeditAttributes, preedit_attr, + NULL); + + XFree(preedit_attr); +#else + (void)ctx; + (void)x; + (void)y; + (void)h; +#endif + (void)(w); // yes w is unused, but only a bi-product of the algorithm +} + +static void +_ecore_imf_context_xim_input_panel_show(Ecore_IMF_Context *ctx) +{ + EINA_LOG_DBG("%s in", __FUNCTION__); + +#ifdef ENABLE_XIM + Ecore_IMF_Context_Data *imf_context_data; + imf_context_data = ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(imf_context_data); + + ecore_x_e_virtual_keyboard_state_set + (imf_context_data->win, ECORE_X_VIRTUAL_KEYBOARD_STATE_ON); +#else + (void)ctx; +#endif +} + +static void +_ecore_imf_context_xim_input_panel_hide(Ecore_IMF_Context *ctx) +{ + EINA_LOG_DBG("%s in", __FUNCTION__); + +#ifdef ENABLE_XIM + Ecore_IMF_Context_Data *imf_context_data; + imf_context_data = ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(imf_context_data); + + ecore_x_e_virtual_keyboard_state_set + (imf_context_data->win, ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF); +#else + (void)ctx; +#endif +} + +#ifdef ENABLE_XIM +static unsigned int +_ecore_x_event_reverse_modifiers(unsigned int state) +{ + unsigned int modifiers = 0; + + /**< "Control" is pressed */ + if (state & ECORE_IMF_KEYBOARD_MODIFIER_CTRL) + modifiers |= ECORE_X_MODIFIER_CTRL; + + /**< "Alt" is pressed */ + if (state & ECORE_IMF_KEYBOARD_MODIFIER_ALT) + modifiers |= ECORE_X_MODIFIER_ALT; + + /**< "Shift" is pressed */ + if (state & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT) + modifiers |= ECORE_X_MODIFIER_SHIFT; + + /**< "Win" (between "Ctrl" and "Alt") is pressed */ + if (state & ECORE_IMF_KEYBOARD_MODIFIER_WIN) + modifiers |= ECORE_X_MODIFIER_WIN; + + /**< "AltGr" is pressed */ + if (state & ECORE_IMF_KEYBOARD_MODIFIER_ALTGR) + modifiers |= ECORE_X_MODIFIER_ALTGR; + + return modifiers; +} + +static unsigned int +_ecore_x_event_reverse_locks(unsigned int state) +{ + unsigned int locks = 0; + + /**< "Num" lock is active */ + if (state & ECORE_IMF_KEYBOARD_LOCK_NUM) + locks |= ECORE_X_LOCK_NUM; + + if (state & ECORE_IMF_KEYBOARD_LOCK_CAPS) + locks |= ECORE_X_LOCK_CAPS; + + if (state & ECORE_IMF_KEYBOARD_LOCK_SCROLL) + locks |= ECORE_X_LOCK_SCROLL; + + return locks; +} + +static KeyCode +_keycode_get(Ecore_X_Display *dsp, + const char *keyname) +{ + KeyCode keycode; + + // EINA_LOG_DBG("keyname:%s keysym:%lu", keyname, XStringToKeysym(keyname)); + if (strcmp(keyname, "Keycode-0") == 0) + keycode = 0; + else + keycode = XKeysymToKeycode(dsp, XStringToKeysym(keyname)); + + return keycode; +} + +#endif + +static Eina_Bool +_ecore_imf_context_xim_filter_event(Ecore_IMF_Context *ctx, + Ecore_IMF_Event_Type type, + Ecore_IMF_Event *event) +{ + EINA_LOG_DBG("%s in", __FUNCTION__); +#ifdef ENABLE_XIM + Ecore_IMF_Context_Data *imf_context_data; + XIC ic; + + Ecore_X_Display *dsp; + Ecore_X_Window win; + + int val; + char compose_buffer[256]; + KeySym sym; + char *compose = NULL; + char *tmp = NULL; + Eina_Bool result = EINA_FALSE; + + imf_context_data = ecore_imf_context_data_get(ctx); + if (!imf_context_data) return EINA_FALSE; + ic = imf_context_data->ic; + if (!ic) + ic = get_ic(ctx); + + if (type == ECORE_IMF_EVENT_KEY_DOWN) + { + XKeyPressedEvent xev; + Ecore_IMF_Event_Key_Down *ev = (Ecore_IMF_Event_Key_Down *)event; + EINA_LOG_DBG("ECORE_IMF_EVENT_KEY_DOWN"); + + dsp = ecore_x_display_get(); + win = imf_context_data->win; + + xev.type = KeyPress; + xev.serial = 0; /* hope it doesn't matter */ + xev.send_event = 0; + xev.display = dsp; + xev.window = win; + xev.root = ecore_x_window_root_get(win); + xev.subwindow = win; + xev.time = ev->timestamp; + xev.x = xev.x_root = 0; + xev.y = xev.y_root = 0; + xev.state = 0; + xev.state |= _ecore_x_event_reverse_modifiers(ev->modifiers); + xev.state |= _ecore_x_event_reverse_locks(ev->locks); + xev.keycode = _keycode_get(dsp, ev->keyname); + xev.same_screen = True; + + if (ic) + { + Status mbstatus; +#ifdef X_HAVE_UTF8_STRING + val = Xutf8LookupString(ic, + &xev, + compose_buffer, + sizeof(compose_buffer) - 1, + &sym, + &mbstatus); +#else /* ifdef X_HAVE_UTF8_STRING */ + val = XmbLookupString(ic, + &xev, + compose_buffer, + sizeof(compose_buffer) - 1, + &sym, + &mbstatus); +#endif /* ifdef X_HAVE_UTF8_STRING */ + if (mbstatus == XBufferOverflow) + { + tmp = malloc(sizeof (char) * (val + 1)); + if (!tmp) + return EINA_FALSE; + + compose = tmp; + +#ifdef X_HAVE_UTF8_STRING + val = Xutf8LookupString(ic, + &xev, + tmp, + val, + &sym, + &mbstatus); +#else /* ifdef X_HAVE_UTF8_STRING */ + val = XmbLookupString(ic, + &xev, + tmp, + val, + &sym, + &mbstatus); +#endif /* ifdef X_HAVE_UTF8_STRING */ + if (val > 0) + { + tmp[val] = '\0'; +#ifndef X_HAVE_UTF8_STRING + compose = eina_str_convert(nl_langinfo(CODESET), + "UTF-8", tmp); + free(tmp); + tmp = compose; +#endif /* ifndef X_HAVE_UTF8_STRING */ + } + else + compose = NULL; + } + else if (val > 0) + { + compose_buffer[val] = '\0'; +#ifdef X_HAVE_UTF8_STRING + compose = strdup(compose_buffer); +#else /* ifdef X_HAVE_UTF8_STRING */ + compose = eina_str_convert(nl_langinfo(CODESET), "UTF-8", + compose_buffer); +#endif /* ifdef X_HAVE_UTF8_STRING */ + } + } + else + { + compose = strdup(ev->compose); + } + + if (compose) + { + Eina_Unicode *unicode; + int len; + unicode = eina_unicode_utf8_to_unicode(compose, &len); + if (!unicode) abort(); + if (unicode[0] >= 0x20 && unicode[0] != 0x7f) + { + ecore_imf_context_commit_event_add(ctx, compose); + ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_COMMIT, compose); + result = EINA_TRUE; + } + free(compose); + free(unicode); + } + } + + return result; +#else + (void)ctx; + (void)type; + (void)event; + return EINA_FALSE; +#endif +} + +static const Ecore_IMF_Context_Info xim_info = { + .id = "xim", + .description = _("X input method"), + .default_locales = "ko:ja:th:zh", + .canvas_type = "evas", + .canvas_required = 1, +}; + +static Ecore_IMF_Context_Class xim_class = { + .add = _ecore_imf_context_xim_add, + .del = _ecore_imf_context_xim_del, + .client_window_set = _ecore_imf_context_xim_client_window_set, + .client_canvas_set = NULL, + .show = _ecore_imf_context_xim_input_panel_show, + .hide = _ecore_imf_context_xim_input_panel_hide, + .preedit_string_get = _ecore_imf_context_xim_preedit_string_get, + .focus_in = _ecore_imf_context_xim_focus_in, + .focus_out = _ecore_imf_context_xim_focus_out, + .reset = _ecore_imf_context_xim_reset, + .cursor_position_set = NULL, + .use_preedit_set = _ecore_imf_context_xim_use_preedit_set, + .input_mode_set = NULL, + .filter_event = _ecore_imf_context_xim_filter_event, + .preedit_string_with_attributes_get = _ecore_imf_context_xim_preedit_string_with_attributes_get, + .prediction_allow_set = NULL, + .autocapital_type_set = NULL, + .control_panel_show = NULL, + .control_panel_hide = NULL, + .input_panel_layout_set = NULL, + .input_panel_layout_get = NULL, + .input_panel_language_set = NULL, + .input_panel_language_get = NULL, + .cursor_location_set = _ecore_imf_context_xim_cursor_location_set, + .input_panel_imdata_set = NULL, + .input_panel_imdata_get = NULL, + .input_panel_return_key_type_set = NULL, + .input_panel_return_key_disabled_set = NULL, + .input_panel_caps_lock_mode_set = NULL +}; + +static Ecore_IMF_Context * +xim_imf_module_create(void) +{ + EINA_LOG_DBG("%s in", __FUNCTION__); + Ecore_IMF_Context *ctx = NULL; + + ctx = ecore_imf_context_new(&xim_class); + if (!ctx) + goto error; + + return ctx; + +error: + free(ctx); + return NULL; +} + +static Ecore_IMF_Context * +xim_imf_module_exit(void) +{ + return NULL; +} + +Eina_Bool +ecore_imf_xim_init(void) +{ + EINA_LOG_DBG("%s in", __FUNCTION__); + eina_init(); + ecore_x_init(NULL); + ecore_imf_module_register(&xim_info, + xim_imf_module_create, + xim_imf_module_exit); + + return EINA_TRUE; +} + +void +ecore_imf_xim_shutdown(void) +{ +#ifdef ENABLE_XIM + while (open_ims) + { + XIM_Im_Info *info = open_ims->data; + Ecore_X_Display *display = ecore_x_display_get(); + + xim_info_display_closed(display, EINA_FALSE, info); + } +#endif + + ecore_x_shutdown(); + eina_shutdown(); +} + +EINA_MODULE_INIT(ecore_imf_xim_init); +EINA_MODULE_SHUTDOWN(ecore_imf_xim_shutdown); + +#ifdef ENABLE_XIM +/* + * internal functions + */ +Ecore_IMF_Context_Data * +imf_context_data_new() +{ + Ecore_IMF_Context_Data *imf_context_data = NULL; + char *locale; + + locale = setlocale(LC_CTYPE, ""); + if (!locale) return NULL; + + if (!XSupportsLocale()) return NULL; + + imf_context_data = calloc(1, sizeof(Ecore_IMF_Context_Data)); + EINA_SAFETY_ON_NULL_RETURN_VAL(imf_context_data, NULL); + + imf_context_data->locale = strdup(locale); + if (!imf_context_data->locale) goto error; + + return imf_context_data; +error: + imf_context_data_destroy(imf_context_data); + return NULL; +} + +void +imf_context_data_destroy(Ecore_IMF_Context_Data *imf_context_data) +{ + if (!imf_context_data) + return; + + if (imf_context_data->ic) + XDestroyIC(imf_context_data->ic); + + free(imf_context_data->preedit_chars); + + if (imf_context_data->feedbacks) + { + free(imf_context_data->feedbacks); + imf_context_data->feedbacks = NULL; + } + + free(imf_context_data->locale); + free(imf_context_data); +} + +static int +preedit_start_callback(XIC xic __UNUSED__, + XPointer client_data, + XPointer call_data __UNUSED__) +{ + EINA_LOG_DBG("in"); + Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data; + Ecore_IMF_Context_Data *imf_context_data; + imf_context_data = ecore_imf_context_data_get(ctx); + if (!imf_context_data) return -1; + + if (imf_context_data->finalizing == EINA_FALSE) + { + ecore_imf_context_preedit_start_event_add(ctx); + ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL); + } + return -1; +} + +static void +preedit_done_callback(XIC xic __UNUSED__, + XPointer client_data, + XPointer call_data __UNUSED__) +{ + EINA_LOG_DBG("in"); + Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data; + Ecore_IMF_Context_Data *imf_context_data; + imf_context_data = ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(imf_context_data); + + if (imf_context_data->preedit_length) + { + imf_context_data->preedit_length = 0; + free(imf_context_data->preedit_chars); + imf_context_data->preedit_chars = NULL; + ecore_imf_context_preedit_changed_event_add(ctx); + ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL); + } + + if (imf_context_data->finalizing == EINA_FALSE) + { + ecore_imf_context_preedit_end_event_add(ctx); + ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL); + } +} + +/* FIXME */ +static int +xim_text_to_utf8(Ecore_IMF_Context *ctx __UNUSED__, + XIMText *xim_text, + char **text) +{ + int text_length = 0; + char *result = NULL; + + if (xim_text && xim_text->string.multi_byte) + { + if (xim_text->encoding_is_wchar) + { + EINA_LOG_WARN("Wide character return from Xlib not currently supported"); + *text = NULL; + return 0; + } + + /* XXX Convert to UTF-8 */ + result = strdup(xim_text->string.multi_byte); + if (result) + { + text_length = eina_unicode_utf8_get_len(result); + if (text_length != xim_text->length) + { + EINA_LOG_WARN("Size mismatch when converting text from input method: supplied length = %d\n, result length = %d", xim_text->length, text_length); + } + } + else + { + EINA_LOG_WARN("Error converting text from IM to UCS-4"); + *text = NULL; + return 0; + } + + *text = result; + return text_length; + } + else + { + *text = NULL; + return 0; + } +} + +static void +preedit_draw_callback(XIC xic __UNUSED__, + XPointer client_data, + XIMPreeditDrawCallbackStruct *call_data) +{ + EINA_LOG_DBG("in"); + Eina_Bool ret = EINA_FALSE; + Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data; + Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx); + XIMText *t = call_data->text; + char *tmp; + Eina_Unicode *new_text = NULL; + Eina_UStrbuf *preedit_bufs = NULL; + int new_text_length; + int i = 0; + + EINA_SAFETY_ON_NULL_RETURN(imf_context_data); + + preedit_bufs = eina_ustrbuf_new(); + if (imf_context_data->preedit_chars) + { + ret = eina_ustrbuf_append(preedit_bufs, imf_context_data->preedit_chars); + if (ret == EINA_FALSE) goto done; + } + + new_text_length = xim_text_to_utf8(ctx, t, &tmp); + if (tmp) + { + int tmp_len; + new_text = eina_unicode_utf8_to_unicode((const char *)tmp, &tmp_len); + free(tmp); + } + + if (t == NULL) + { + /* delete string */ + ret = eina_ustrbuf_remove(preedit_bufs, + call_data->chg_first, call_data->chg_length); + } + else if (call_data->chg_length == 0) + { + /* insert string */ + ret = eina_ustrbuf_insert(preedit_bufs, new_text, call_data->chg_first); + } + else if (call_data->chg_length > 0) + { + /* replace string */ + ret = eina_ustrbuf_remove(preedit_bufs, + call_data->chg_first, call_data->chg_length); + if (ret == EINA_FALSE) goto done; + + ret = eina_ustrbuf_insert_n(preedit_bufs, new_text, + new_text_length, call_data->chg_first); + if (ret == EINA_FALSE) goto done; + } + else + { + ret = EINA_FALSE; + } + +done: + if (ret == EINA_TRUE) + { + free(imf_context_data->preedit_chars); + imf_context_data->preedit_chars = + eina_ustrbuf_string_steal(preedit_bufs); + imf_context_data->preedit_length = + eina_unicode_strlen(imf_context_data->preedit_chars); + + if (imf_context_data->feedbacks) + { + free(imf_context_data->feedbacks); + imf_context_data->feedbacks = NULL; + } + + if (imf_context_data->preedit_length > 0) + { + imf_context_data->feedbacks = calloc(imf_context_data->preedit_length, sizeof(XIMFeedback)); + + for (i = 0; i < imf_context_data->preedit_length; i++) + imf_context_data->feedbacks[i] = t->feedback[i]; + } + + ecore_imf_context_preedit_changed_event_add(ctx); + ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL); + } + + free(new_text); + eina_ustrbuf_free(preedit_bufs); +} + +static void +preedit_caret_callback(XIC xic __UNUSED__, + XPointer client_data, + XIMPreeditCaretCallbackStruct *call_data) +{ + EINA_LOG_DBG("in"); + Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data; + Ecore_IMF_Context_Data *imf_context_data; + imf_context_data = ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(imf_context_data); + + if (call_data->direction == XIMAbsolutePosition) + { + // printf("call_data->position:%d\n", call_data->position); + imf_context_data->preedit_cursor = call_data->position; + if (imf_context_data->finalizing == EINA_FALSE) + { + ecore_imf_context_preedit_changed_event_add(ctx); + ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL); + } + } +} + +static XVaNestedList +preedit_callback_set(Ecore_IMF_Context *ctx) +{ + Ecore_IMF_Context_Data *imf_context_data; + imf_context_data = ecore_imf_context_data_get(ctx); + + imf_context_data->preedit_start_cb.client_data = (XPointer)ctx; + imf_context_data->preedit_start_cb.callback = (XIMProc)preedit_start_callback; + + imf_context_data->preedit_done_cb.client_data = (XPointer)ctx; + imf_context_data->preedit_done_cb.callback = (XIMProc)preedit_done_callback; + + imf_context_data->preedit_draw_cb.client_data = (XPointer)ctx; + imf_context_data->preedit_draw_cb.callback = (XIMProc)preedit_draw_callback; + + imf_context_data->preedit_caret_cb.client_data = (XPointer)ctx; + imf_context_data->preedit_caret_cb.callback = (XIMProc)preedit_caret_callback; + + return XVaCreateNestedList(0, + XNPreeditStartCallback, + &imf_context_data->preedit_start_cb, + XNPreeditDoneCallback, + &imf_context_data->preedit_done_cb, + XNPreeditDrawCallback, + &imf_context_data->preedit_draw_cb, + XNPreeditCaretCallback, + &imf_context_data->preedit_caret_cb, + NULL); +} + +static XIC +get_ic(Ecore_IMF_Context *ctx) +{ + Ecore_IMF_Context_Data *imf_context_data; + XIC ic; + imf_context_data = ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN_VAL(imf_context_data, NULL); + + ic = imf_context_data->ic; + if (!ic) + { + XIM_Im_Info *im_info = imf_context_data->im_info; + XVaNestedList preedit_attr = NULL; + XIMStyle im_style = 0; + XPoint spot = { 0, 0 }; + char *name = NULL; + + if (!im_info) + { + EINA_LOG_WARN("Doesn't open XIM."); + return NULL; + } + + // supported styles +#if 0 + int i; + if (im_info->xim_styles) + { + for (i = 0; i < im_info->xim_styles->count_styles; i++) + { + printf("%i: ", i); + if (im_info->xim_styles->supported_styles[i] & XIMPreeditCallbacks) + printf("XIMPreeditCallbacks | "); + if (im_info->xim_styles->supported_styles[i] & XIMPreeditPosition) + printf("XIMPreeditPosition | "); + if (im_info->xim_styles->supported_styles[i] & XIMPreeditArea) + printf("XIMPreeditArea | "); + if (im_info->xim_styles->supported_styles[i] & XIMPreeditNothing) + printf("XIMPreeditNothing | "); + if (im_info->xim_styles->supported_styles[i] & XIMPreeditNone) + printf("XIMPreeditNone | "); + if (im_info->xim_styles->supported_styles[i] & XIMStatusArea) + printf("XIMStatusArea | "); + if (im_info->xim_styles->supported_styles[i] & XIMStatusCallbacks) + printf("XIMStatusCallbacks | "); + if (im_info->xim_styles->supported_styles[i] & XIMStatusNothing) + printf("XIMStatusNothing | "); + if (im_info->xim_styles->supported_styles[i] & XIMStatusNone) + printf("XIMStatusNone | "); + printf("\n"); + } + } +#endif + // "OverTheSpot" = XIMPreeditPosition | XIMStatusNothing + // "OffTheSpot" = XIMPreeditArea | XIMStatusArea + // "Root" = XIMPreeditNothing | XIMStatusNothing + + if (imf_context_data->use_preedit == EINA_TRUE) + { + if (im_info->supports_cursor) + { + // kinput2 DOES do this... + XFontSet fs; + char **missing_charset_list; + int missing_charset_count; + char *def_string; + + im_style |= XIMPreeditPosition; + im_style |= XIMStatusNothing; + fs = XCreateFontSet(ecore_x_display_get(), + "fixed", + &missing_charset_list, + &missing_charset_count, + &def_string); + preedit_attr = XVaCreateNestedList(0, + XNSpotLocation, &spot, + XNFontSet, fs, + NULL); + } + else + { + im_style |= XIMPreeditCallbacks; + im_style |= XIMStatusNothing; + preedit_attr = preedit_callback_set(ctx); + } + name = XNPreeditAttributes; + } + else + { + im_style |= XIMPreeditNothing; + im_style |= XIMStatusNothing; + } + + if (!im_info->xim_styles) + { + EINA_LOG_WARN("No XIM styles supported! Wanted %#llx", + (unsigned long long)im_style); + im_style = 0; + } + else + { + XIMStyle fallback = 0; + int i; + + for (i = 0; i < im_info->xim_styles->count_styles; i++) + { + XIMStyle cur = im_info->xim_styles->supported_styles[i]; + if (cur == im_style) + break; + else if (cur == (XIMPreeditNothing | XIMStatusNothing)) + /* TODO: fallback is just that or the anyone? */ + fallback = cur; + } + + if (i == im_info->xim_styles->count_styles) + { + if (fallback) + { + EINA_LOG_WARN("Wanted XIM style %#llx not found, " + "using fallback %#llx instead.", + (unsigned long long)im_style, + (unsigned long long)fallback); + im_style = fallback; + } + else + { + EINA_LOG_WARN("Wanted XIM style %#llx not found, " + "no fallback supported.", + (unsigned long long)im_style); + im_style = 0; + } + } + } + + if ((im_info->im) && (im_style)) + { + ic = XCreateIC(im_info->im, + XNInputStyle, im_style, + XNClientWindow, imf_context_data->win, + name, preedit_attr, NULL); + } + XFree(preedit_attr); + if (ic) + { + unsigned long mask = 0xaaaaaaaa; + XGetICValues(ic, + XNFilterEvents, &mask, + NULL); + imf_context_data->mask = mask; + ecore_x_event_mask_set(imf_context_data->win, mask); + } + + imf_context_data->ic = ic; + if (ic && imf_context_data->has_focus == EINA_TRUE) + XSetICFocus(ic); + } + + return ic; +} + +static void +reinitialize_ic(Ecore_IMF_Context *ctx) +{ + Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx); + EINA_SAFETY_ON_NULL_RETURN(imf_context_data); + + XIC ic = imf_context_data->ic; + if (ic) + { + XDestroyIC(ic); + imf_context_data->ic = NULL; + if (imf_context_data->preedit_length) + { + imf_context_data->preedit_length = 0; + free(imf_context_data->preedit_chars); + imf_context_data->preedit_chars = NULL; + ecore_imf_context_preedit_changed_event_add(ctx); + ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL); + } + } +} + +static void +set_ic_client_window(Ecore_IMF_Context *ctx, + Ecore_X_Window window) +{ + EINA_LOG_DBG("in"); + Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx); + Ecore_X_Window old_win; + + EINA_SAFETY_ON_NULL_RETURN(imf_context_data); + + /* reinitialize IC */ + reinitialize_ic(ctx); + + old_win = imf_context_data->win; + EINA_LOG_DBG("old_win:%d window:%d ", old_win, window); + if (old_win != 0 && old_win != window) /* XXX how do check window... */ + { + XIM_Im_Info *info; + info = imf_context_data->im_info; + info->ics = eina_list_remove(info->ics, imf_context_data); + if (imf_context_data->im_info) + imf_context_data->im_info->user = NULL; + imf_context_data->im_info = NULL; + } + + imf_context_data->win = window; + + if (window) /* XXX */ + { + XIM_Im_Info *info = NULL; + info = get_im(window, imf_context_data->locale); + imf_context_data->im_info = info; + imf_context_data->im_info->ics = + eina_list_prepend(imf_context_data->im_info->ics, + imf_context_data); + if (imf_context_data->im_info) + imf_context_data->im_info->user = imf_context_data; + } +} + +static XIM_Im_Info * +get_im(Ecore_X_Window window, + char *locale) +{ + EINA_LOG_DBG("in"); + + Eina_List *l; + XIM_Im_Info *im_info = NULL; + XIM_Im_Info *info = NULL; + EINA_LIST_FOREACH (open_ims, l, im_info) + { + if (strcmp(im_info->locale, locale) == 0) + { + if (im_info->im) + { + return im_info; + } + else + { + info = im_info; + break; + } + } + } + + if (!info) + { + info = calloc(1, sizeof(XIM_Im_Info)); + if (!info) return NULL; + open_ims = eina_list_prepend(open_ims, info); + info->win = window; + info->locale = strdup(locale); + info->reconnecting = EINA_FALSE; + } + + xim_info_try_im(info); + return info; +} + +/* initialize info->im */ +static void +xim_info_try_im(XIM_Im_Info *info) +{ + Ecore_X_Display *dsp; + + assert(info->im == NULL); + if (info->reconnecting == EINA_TRUE) + return; + + if (XSupportsLocale()) + { + if (!XSetLocaleModifiers("")) + EINA_LOG_WARN("Unable to set locale modifiers with XSetLocaleModifiers()"); + dsp = ecore_x_display_get(); + info->im = XOpenIM(dsp, NULL, NULL, NULL); + if (!info->im) + { + XRegisterIMInstantiateCallback(dsp, + NULL, NULL, NULL, + xim_instantiate_callback, + (XPointer)info); + info->reconnecting = EINA_TRUE; + return; + } + setup_im(info); + } +} + +static void +xim_info_display_closed(Ecore_X_Display *display __UNUSED__, + int is_error __UNUSED__, + XIM_Im_Info *info) +{ + Eina_List *ics, *tmp_list; + Ecore_IMF_Context *ctx; + + open_ims = eina_list_remove(open_ims, info); + + ics = info->ics; + info->ics = NULL; + + EINA_LIST_FOREACH (ics, tmp_list, ctx) + set_ic_client_window(ctx, 0); + + EINA_LIST_FREE (ics, ctx) + { + Ecore_IMF_Context_Data *imf_context_data; + imf_context_data = ecore_imf_context_data_get(ctx); + imf_context_data_destroy(imf_context_data); + } + + free(info->locale); + + if (info->im) + XCloseIM(info->im); + + free(info); +} + +static void +xim_instantiate_callback(Display *display, + XPointer client_data, + XPointer call_data __UNUSED__) +{ + XIM_Im_Info *info = (XIM_Im_Info *)client_data; + XIM im = NULL; + + im = XOpenIM(display, NULL, NULL, NULL); + + if (!im) + { + fprintf(stderr, "Failed to connect to IM\n"); + return; + } + + info->im = im; + setup_im(info); + + XUnregisterIMInstantiateCallback(display, NULL, NULL, NULL, + xim_instantiate_callback, + (XPointer)info); + info->reconnecting = EINA_FALSE; +} + +static void +setup_im(XIM_Im_Info *info) +{ + XIMValuesList *ic_values = NULL; + XIMCallback im_destroy_callback; + + if (!info->im) + return; + + im_destroy_callback.client_data = (XPointer)info; + im_destroy_callback.callback = (XIMProc)xim_destroy_callback; + XSetIMValues(info->im, + XNDestroyCallback, &im_destroy_callback, + NULL); + + XGetIMValues(info->im, + XNQueryInputStyle, &info->xim_styles, + XNQueryICValuesList, &ic_values, + NULL); + + if (ic_values) + { + int i; + + for (i = 0; i < ic_values->count_values; i++) + { + if (!strcmp(ic_values->supported_values[i], + XNStringConversionCallback)) + info->supports_string_conversion = EINA_TRUE; + if (!strcmp(ic_values->supported_values[i], + XNCursor)) + info->supports_cursor = EINA_TRUE; + } +#if 0 + printf("values........\n"); + for (i = 0; i < ic_values->count_values; i++) + printf("%s\n", ic_values->supported_values[i]); + printf("styles........\n"); + for (i = 0; i < info->xim_styles->count_styles; i++) + printf("%lx\n", info->xim_styles->supported_styles[i]); +#endif + XFree(ic_values); + } +} + +static void +xim_destroy_callback(XIM xim __UNUSED__, + XPointer client_data, + XPointer call_data __UNUSED__) +{ + XIM_Im_Info *info = (XIM_Im_Info *)client_data; + + if (info->user) info->user->ic = NULL; + info->im = NULL; +// reinitialize_ic(ctx); + xim_info_try_im(info); + + return; +} + +#endif /* ENABLE_XIM */ diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am new file mode 100644 index 0000000..bfd20d9 --- /dev/null +++ b/src/tests/Makefile.am @@ -0,0 +1,37 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_srcdir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore_con \ +-I$(top_srcdir)/src/lib/ecore_x \ +@EINA_CFLAGS@ \ +@CHECK_CFLAGS@ + +if EFL_ENABLE_TESTS + +noinst_PROGRAMS = ecore_suite + +check_PROGRAMS = ecore_suite + +ecore_suite_SOURCES = \ +ecore_suite.c \ +ecore_test_ecore.c \ +ecore_test_ecore_con.c \ +ecore_test_ecore_x.c \ +ecore_suite.h + +ecore_suite_LDADD = \ +@CHECK_LIBS@ \ +@EINA_LIBS@ \ +$(top_builddir)/src/lib/ecore/libecore.la \ +$(top_builddir)/src/lib/ecore_con/libecore_con.la + +if BUILD_ECORE_X +ecore_suite_LDADD += \ +$(top_builddir)/src/lib/ecore_x/libecore_x.la +endif + +endif + +clean-local: + rm -rf *.gcno *.gcda diff --git a/src/tests/ecore_suite.c b/src/tests/ecore_suite.c new file mode 100644 index 0000000..fd51750 --- /dev/null +++ b/src/tests/ecore_suite.c @@ -0,0 +1,103 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + +#include "ecore_suite.h" + +typedef struct _Ecore_Test_Case Ecore_Test_Case; + +struct _Ecore_Test_Case +{ + const char *test_case; + void (*build)(TCase *tc); +}; + +static const Ecore_Test_Case etc[] = { + { "Ecore", ecore_test_ecore }, + { "Ecore_Con", ecore_test_ecore_con }, + { "Ecore_X", ecore_test_ecore_x }, + { NULL, NULL } +}; + +static void +_list_tests(void) +{ + const Ecore_Test_Case *itr; + + itr = etc; + fputs("Available Test Cases:\n", stderr); + for (; itr->test_case; itr++) + fprintf(stderr, "\t%s\n", itr->test_case); +} +static Eina_Bool +_use_test(int argc, const char **argv, const char *test_case) +{ + if (argc < 1) + return 1; + + for (; argc > 0; argc--, argv++) + if (strcmp(test_case, *argv) == 0) + return 1; + return 0; +} + +static Suite * +ecore_suite_build(int argc, const char **argv) +{ + TCase *tc; + Suite *s; + int i; + + s = suite_create("Ecore"); + + for (i = 0; etc[i].test_case; ++i) + { + if (!_use_test(argc, argv, etc[i].test_case)) continue; + tc = tcase_create(etc[i].test_case); + + etc[i].build(tc); + + suite_add_tcase(s, tc); + tcase_set_timeout(tc, 0); + } + + return s; +} + +int +main(int argc, char **argv) +{ + Suite *s; + SRunner *sr; + int i, failed_count; + + for (i = 1; i < argc; i++) + if ((strcmp(argv[i], "-h") == 0) || + (strcmp(argv[i], "--help") == 0)) + { + fprintf(stderr, "Usage:\n\t%s [test_case1 .. [test_caseN]]\n", + argv[0]); + _list_tests(); + return 0; + } + else if ((strcmp(argv[i], "-l") == 0) || + (strcmp(argv[i], "--list") == 0)) + { + _list_tests(); + return 0; + } + + s = ecore_suite_build(argc - 1, (const char **)argv + 1); + sr = srunner_create(s); + + srunner_run_all(sr, CK_ENV); + failed_count = srunner_ntests_failed(sr); + srunner_free(sr); + + return (failed_count == 0) ? 0 : 255; +} diff --git a/src/tests/ecore_suite.h b/src/tests/ecore_suite.h new file mode 100644 index 0000000..0c7dfef --- /dev/null +++ b/src/tests/ecore_suite.h @@ -0,0 +1,11 @@ +#ifndef _ECORE_SUITE_H +#define _ECORE_SUITE_H + +#include + +void ecore_test_ecore(TCase *tc); +void ecore_test_ecore_con(TCase *tc); +void ecore_test_ecore_x(TCase *tc); + + +#endif /* _ECORE_SUITE_H */ diff --git a/src/tests/ecore_test_ecore.c b/src/tests/ecore_test_ecore.c new file mode 100644 index 0000000..a37b00d --- /dev/null +++ b/src/tests/ecore_test_ecore.c @@ -0,0 +1,366 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include +#include + +#include "ecore_suite.h" + +static int _log_dom; +#define INF(...) EINA_LOG_DOM_INFO(_log_dom, __VA_ARGS__) + +static Eina_Bool +_quit_cb(void *data) +{ + Eina_Bool *val = data; + *val = EINA_TRUE; + ecore_main_loop_quit(); + return EINA_FALSE; +} + +static Eina_Bool +_dummy_cb(void *data) +{ + return !!data; +} + +START_TEST(ecore_test_ecore_init) +{ + int ret; + + ret = ecore_init(); + fail_if(ret != 1); + + ret = ecore_shutdown(); + fail_if(ret != 0); +} +END_TEST + +START_TEST(ecore_test_ecore_main_loop) +{ + Eina_Bool did = EINA_FALSE; + Ecore_Timer *timer; + int ret; + + ret = ecore_init(); + fail_if(ret != 1); + + timer = ecore_timer_add(0.0, _quit_cb, &did); + fail_if(timer == NULL); + + ecore_main_loop_begin(); + + fail_if(did == EINA_FALSE); + + ret = ecore_shutdown(); + fail_if(ret != 0); +} +END_TEST + +START_TEST(ecore_test_ecore_main_loop_idler) +{ + Eina_Bool did = EINA_FALSE; + Ecore_Idler *idler; + int ret; + + ret = ecore_init(); + fail_if(ret != 1); + + idler = ecore_idler_add(_quit_cb, &did); + fail_if(idler == NULL); + + ecore_main_loop_begin(); + + fail_if(did == EINA_FALSE); + + ret = ecore_shutdown(); + fail_if(ret != 0); +} +END_TEST + +START_TEST(ecore_test_ecore_main_loop_idle_enterer) +{ + Eina_Bool did = EINA_FALSE; + Ecore_Idle_Enterer *idle_enterer; + int ret; + + ret = ecore_init(); + fail_if(ret != 1); + + idle_enterer = ecore_idle_enterer_add(_quit_cb, &did); + fail_if(idle_enterer == NULL); + + ecore_main_loop_begin(); + + fail_if(did == EINA_FALSE); + + ret = ecore_shutdown(); + fail_if(ret != 0); +} +END_TEST + +START_TEST(ecore_test_ecore_main_loop_idle_exiter) +{ + Eina_Bool did = EINA_FALSE; + Ecore_Timer *timer; + Ecore_Idle_Exiter *idle_exiter; + int ret; + + ret = ecore_init(); + fail_if(ret != 1); + + /* make system exit idle */ + timer = ecore_timer_add(0.0, _dummy_cb, (void *)(long)0); + fail_if(timer == NULL); + + idle_exiter = ecore_idle_exiter_add(_quit_cb, &did); + fail_if(idle_exiter == NULL); + + ecore_main_loop_begin(); + + fail_if(did == EINA_FALSE); + + ret = ecore_shutdown(); + fail_if(ret != 0); +} +END_TEST + +START_TEST(ecore_test_ecore_main_loop_timer) +{ + Eina_Bool did = EINA_FALSE; + Ecore_Timer *timer; + double start, end, elapsed; + int ret; + + ret = ecore_init(); + fail_if(ret != 1); + + timer = ecore_timer_add(2.0, _quit_cb, &did); + fail_if(timer == NULL); + + start = ecore_time_get(); + ecore_main_loop_begin(); + end = ecore_time_get(); + elapsed = end - start; + + fail_if(did == EINA_FALSE); + fail_if(elapsed < 2.0); + fail_if(elapsed > 3.0); /* 1 second "error margin" */ + + ret = ecore_shutdown(); + fail_if(ret != 0); +} +END_TEST + +static Eina_Bool _timer3(void *data __UNUSED__) +{ + /* timer 3, do nothing */ + return EINA_FALSE; +} + +static Eina_Bool _timer2(void *data __UNUSED__) +{ + /* timer 2, quit inner mainloop */ + ecore_main_loop_quit(); + return EINA_FALSE; +} + +static Eina_Bool _timer1(void *data) +{ + /* timer 1, begin inner mainloop */ + int *times = data; + (*times)++; + + ecore_timer_add(0.3, _timer2, NULL); + ecore_timer_add(0.1, _timer3, NULL); + ecore_main_loop_begin(); + + ecore_main_loop_quit(); + + return EINA_FALSE; +} + +START_TEST(ecore_test_ecore_main_loop_timer_inner) +{ + Ecore_Timer *timer; + int ret; + int times = 0; + + ret = ecore_init(); + fail_if(ret != 1); + + timer = ecore_timer_add(1.0, _timer1, ×); + fail_if(timer == NULL); + + /* BEGIN: outer mainloop */ + ecore_main_loop_begin(); + /*END: outer mainloop */ + + fail_if(times != 1); +} +END_TEST + +static Eina_Bool +_fd_handler_cb(void *data, Ecore_Fd_Handler *handler __UNUSED__) +{ + /* FIXME: why setting val if it is overwritten just after and what is its purpose ??? */ + Eina_Bool *val = data; + + *val = EINA_TRUE; + ecore_main_loop_quit(); + return EINA_FALSE; +} + +START_TEST(ecore_test_ecore_main_loop_fd_handler) +{ + Eina_Bool did = EINA_FALSE; + Ecore_Fd_Handler *fd_handler; + int comm[2]; + int ret; + + ret = ecore_init(); + fail_if(ret != 1); + + ret = pipe(comm); + fail_if(ret != 0); + + fd_handler = ecore_main_fd_handler_add + (comm[0], ECORE_FD_READ, _fd_handler_cb, &did, NULL, NULL); + fail_if(fd_handler == NULL); + + ret = write(comm[1], &did, 1); + fail_if(ret != 1); + + ecore_main_loop_begin(); + + close(comm[0]); + close(comm[1]); + + fail_if(did == EINA_FALSE); + + ret = ecore_shutdown(); + fail_if(ret != 0); +} +END_TEST + +static Eina_Bool +_event_handler_cb(void *data, int type __UNUSED__, void *event __UNUSED__) +{ + /* FIXME: why setting val if it is overwritten just after and what is its purpose ??? */ + Eina_Bool *val = data; + + *val = EINA_TRUE; + ecore_main_loop_quit(); + return EINA_FALSE; +} + +START_TEST(ecore_test_ecore_main_loop_event) +{ + Eina_Bool did = EINA_FALSE; + Ecore_Event_Handler *handler; + Ecore_Event *event; + int ret, type; + + ret = ecore_init(); + fail_if(ret != 1); + + type = ecore_event_type_new(); + fail_if(type < 1); + + handler = ecore_event_handler_add(type, _event_handler_cb, &did); + fail_if(handler == NULL); + + event = ecore_event_add(type, NULL, NULL, NULL); + fail_if(event == NULL); + + ecore_main_loop_begin(); + + fail_if(did == EINA_FALSE); + + ret = ecore_shutdown(); + fail_if(ret != 0); +} +END_TEST + +static Eina_Bool +_timer_quit_recursive(void *data __UNUSED__) +{ + INF(" _timer_quit_recursive: begin"); + ecore_main_loop_quit(); /* quits inner main loop */ + INF(" _timer_quit_recursive: end"); + return EINA_FALSE; +} + +static Eina_Bool +_event_recursive_cb(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__) +{ + static int guard = 0; + + /* If we enter this callback more than once, it's wrong! */ + fail_if(guard != 0); + guard++; + + INF(" event_recursive_cb: begin"); + + ecore_timer_add(1.0, _timer_quit_recursive, NULL); + INF(" add 1.0s timer (once) to trigger _timer_quit_recursive"); + + INF(" inner main loop begin (recurse)"); + ecore_main_loop_begin(); + INF(" inner main loop end (recurse)"); + + ecore_main_loop_quit(); /* quits outer main loop */ + + INF(" guard = %d", guard); + INF(" event_recursive_cb: end"); + return EINA_FALSE; +} + + +START_TEST(ecore_test_ecore_main_loop_event_recursive) +{ + /* This test tests if the event handlers are really called only once when + * recursive main loops are used and any number of events may have occurred + * between the beginning and the end of recursive main loop. + */ + Ecore_Event *e; + int type; + int ret; + + _log_dom = eina_log_domain_register("test", EINA_COLOR_CYAN); + + INF("main: begin"); + ret = ecore_init(); + fail_if(ret != 1); + + + type = ecore_event_type_new(); + ecore_event_handler_add(type, _event_recursive_cb, NULL); + e = ecore_event_add(type, NULL, NULL, NULL); + INF(" add event to trigger cb1: event=%p", e); + INF(" main loop begin"); + ecore_main_loop_begin(); + INF(" main loop end"); + + INF("main: end"); + ecore_shutdown(); +} +END_TEST + +void ecore_test_ecore(TCase *tc) +{ + tcase_add_test(tc, ecore_test_ecore_init); + tcase_add_test(tc, ecore_test_ecore_main_loop); + tcase_add_test(tc, ecore_test_ecore_main_loop_idler); + tcase_add_test(tc, ecore_test_ecore_main_loop_idle_enterer); + tcase_add_test(tc, ecore_test_ecore_main_loop_idle_exiter); + tcase_add_test(tc, ecore_test_ecore_main_loop_timer); + tcase_add_test(tc, ecore_test_ecore_main_loop_fd_handler); + tcase_add_test(tc, ecore_test_ecore_main_loop_event); + tcase_add_test(tc, ecore_test_ecore_main_loop_timer_inner); + tcase_add_test(tc, ecore_test_ecore_main_loop_event_recursive); +} diff --git a/src/tests/ecore_test_ecore_con.c b/src/tests/ecore_test_ecore_con.c new file mode 100644 index 0000000..45c1f69 --- /dev/null +++ b/src/tests/ecore_test_ecore_con.c @@ -0,0 +1,258 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "ecore_suite.h" + +#include +#include +#include + +Eina_Bool +_add(void *data, int type __UNUSED__, void *ev) +{ + fail_if (type != ECORE_CON_EVENT_CLIENT_ADD && + type != ECORE_CON_EVENT_SERVER_ADD); + + /* Server */ + if (type == ECORE_CON_EVENT_CLIENT_ADD) + { + Ecore_Con_Event_Client_Add *event = ev; + + fail_if (data != (void *) 1); + fail_if (!event->client); + + printf("Client with ip %s, port %d, connected = %d!\n", + ecore_con_client_ip_get(event->client), + ecore_con_client_port_get(event->client), + ecore_con_client_connected_get(event->client)); + + ecore_con_client_timeout_set(event->client, 10); + + } + else if (type == ECORE_CON_EVENT_SERVER_ADD) + { + Ecore_Con_Event_Server_Add *event = ev; + const char ping[] = "PING"; + int ret; + + fail_if (data != (void *) 2); + fail_if (!event->server); + printf("Server with ip %s, name %s, port %d, connected = %d!\n", + ecore_con_server_ip_get(event->server), + ecore_con_server_name_get(event->server), + ecore_con_server_port_get(event->server), + ecore_con_server_connected_get(event->server)); + ret = ecore_con_server_send(event->server, ping, sizeof(ping)); + fail_if (ret != sizeof(ping)); + ecore_con_server_flush(event->server); + } + + return ECORE_CALLBACK_RENEW; +} + +Eina_Bool +_del(void *data , int type __UNUSED__, void *ev) +{ + fail_if (type != ECORE_CON_EVENT_CLIENT_DEL && + type != ECORE_CON_EVENT_SERVER_DEL); + + /* Server */ + if (type == ECORE_CON_EVENT_CLIENT_DEL) + { + Ecore_Con_Event_Client_Del *event = ev; + + fail_if (data != (void *) 1); + fail_if (!event->client); + + printf("Lost client with ip %s!\n", ecore_con_client_ip_get(event->client)); + printf("Client was connected for %0.3f seconds.\n", + ecore_con_client_uptime_get(event->client)); + + ecore_con_client_del(event->client); + } + else if (type == ECORE_CON_EVENT_SERVER_DEL) + { + Ecore_Con_Event_Server_Del *event = ev; + + fail_if (!event->server); + + fail_if (data != (void *) 2); + + printf("Lost server with ip %s!\n", ecore_con_server_ip_get(event->server)); + + ecore_con_server_del(event->server); + } + fail (); + + return ECORE_CALLBACK_RENEW; +} + +Eina_Bool +_data(void *data, int type __UNUSED__, void *ev) +{ + + fail_if (type != ECORE_CON_EVENT_CLIENT_DATA && + type != ECORE_CON_EVENT_SERVER_DATA); + + /* Server */ + if (type == ECORE_CON_EVENT_CLIENT_DATA) + { + Ecore_Con_Event_Client_Data *event = ev; + const char pong[] = "PONG"; + int ret; + + char fmt[128]; + fail_if (data != (void *) 1); + + snprintf(fmt, sizeof(fmt), + "Received %i bytes from client %s port %d:\n" + ">>>>>\n" + "%%.%is\n" + ">>>>>\n", + event->size, ecore_con_client_ip_get(event->client), + ecore_con_client_port_get(event->client), event->size); + + printf(fmt, event->data); + fail_if (event->size != sizeof("PING")); + fail_if (memcmp (event->data, "PING", sizeof("PING")) != 0); + + ret = ecore_con_client_send(event->client, pong, sizeof(pong)); + fail_if (ret != sizeof(pong)); + ecore_con_client_flush(event->client); + } + else if (type == ECORE_CON_EVENT_SERVER_DATA) + { + Ecore_Con_Event_Server_Data *event = ev; + char fmt[128]; + + fail_if (data != (void *) 2); + + snprintf(fmt, sizeof(fmt), + "Received %i bytes from server:\n" + ">>>>>\n" + "%%.%is\n" + ">>>>>\n", + event->size, event->size); + + printf(fmt, event->data); + fail_if (event->size != sizeof("PONG")); + fail_if (memcmp (event->data, "PONG", sizeof("PONG")) != 0); + ecore_main_loop_quit(); + } + + return ECORE_CALLBACK_RENEW; +} + +START_TEST(ecore_test_ecore_con_server) +{ + Ecore_Con_Server *server; + Ecore_Con_Server *client; + Ecore_Con_Client *cl; + const Eina_List *clients, *l; + Ecore_Event_Handler *handlers[6]; + void *server_data = malloc (1); + void *client_data = malloc (1); + int ret; + void *del_ret; + + ret = eina_init(); + fail_if(ret != 1); + ret = ecore_init(); + fail_if(ret != 1); + ret = ecore_con_init(); + fail_if(ret != 1); + + handlers[0] = ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_ADD, + _add, (void *) 1); + fail_if(handlers[0] == NULL); + handlers[1] = ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DEL, + _del, (void *) 1); + fail_if(handlers[1] == NULL); + handlers[2] = ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DATA, + _data, (void *) 1); + fail_if(handlers[2] == NULL); + + handlers[3] = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_ADD, + _add, (void *) 2); + fail_if(handlers[3] == NULL); + handlers[4] = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DEL, + _del, (void *) 2); + fail_if(handlers[4] == NULL); + handlers[5] = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DATA, + _data, (void *) 2); + fail_if(handlers[5] == NULL); + + server = ecore_con_server_add(ECORE_CON_REMOTE_TCP, "::1", 8080, + server_data); + fail_if (server == NULL); + + ecore_con_server_timeout_set(server, 10); + ecore_con_server_client_limit_set(server, 1, 0); + + client = ecore_con_server_connect(ECORE_CON_REMOTE_TCP, "::1", 8080, + client_data); + fail_if (client == NULL); + + ecore_main_loop_begin(); + + clients = ecore_con_server_clients_get(server); + printf("Clients connected to this server when exiting: %d\n", + eina_list_count(clients)); + EINA_LIST_FOREACH(clients, l, cl) + { + printf("%s\n", ecore_con_client_ip_get(cl)); + } + + printf("Server was up for %0.3f seconds\n", + ecore_con_server_uptime_get(server)); + + del_ret = ecore_con_server_del(server); + fail_if (del_ret != server_data); + free (server_data); + del_ret = ecore_con_server_del(client); + fail_if (del_ret != client_data); + free (client_data); + + del_ret = ecore_event_handler_del (handlers[0]); + fail_if (del_ret != (void *) 1); + del_ret = ecore_event_handler_del (handlers[1]); + fail_if (del_ret != (void *) 1); + del_ret = ecore_event_handler_del (handlers[2]); + fail_if (del_ret != (void *) 1); + + del_ret = ecore_event_handler_del (handlers[3]); + fail_if (del_ret != (void *) 2); + del_ret = ecore_event_handler_del (handlers[4]); + fail_if (del_ret != (void *) 2); + del_ret = ecore_event_handler_del (handlers[5]); + fail_if (del_ret != (void *) 2); + + ret = ecore_con_shutdown(); + fail_if(ret != 0); + ret = ecore_shutdown(); + fail_if(ret != 0); + ret = eina_shutdown(); + fail_if(ret != 0); +} +END_TEST + +START_TEST(ecore_test_ecore_con_init) +{ + int ret; + + ret = ecore_con_init(); + fail_if(ret != 1); + + ret = ecore_con_shutdown(); + fail_if(ret != 0); +} +END_TEST + +void ecore_test_ecore_con(TCase *tc) +{ + tcase_add_test(tc, ecore_test_ecore_con_init); + tcase_add_test(tc, ecore_test_ecore_con_server); +} diff --git a/src/tests/ecore_test_ecore_x.c b/src/tests/ecore_test_ecore_x.c new file mode 100644 index 0000000..db74092 --- /dev/null +++ b/src/tests/ecore_test_ecore_x.c @@ -0,0 +1,60 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "ecore_suite.h" + +/* FIXME: Currently disable these tests. They are useless ATM and they just + * make buildbot complain. Once we add useful tests here we'll also bother + * with getting X on the server. */ +#undef HAVE_ECORE_X_XLIB + +/* TODO: change to HAVE_ECORE_X when xcb implementation is done */ +#ifdef HAVE_ECORE_X_XLIB + +START_TEST(ecore_test_ecore_x_init) +{ + int ret; + + ret = ecore_x_init(NULL); + fail_if(ret != 1); + + ret = ecore_x_shutdown(); + fail_if(ret != 0); +} +END_TEST + +START_TEST(ecore_test_ecore_x_bell) +{ + int i; + int ret; + + ret = ecore_x_init(NULL); + fail_if(ret != 1); + + printf("You should hear 3 beeps now.\n"); + for (i = 0; i < 3; i++) + { + ret = ecore_x_bell(0); + fail_if(ret != EINA_TRUE); + ecore_x_sync(); + sleep(1); + } + + ecore_x_shutdown(); +} +END_TEST + +#endif + +void ecore_test_ecore_x(TCase *tc __UNUSED__) +{ + +/* TODO: change to HAVE_ECORE_X when xcb implementation is done */ +#ifdef HAVE_ECORE_X_XLIB + tcase_add_test(tc, ecore_test_ecore_x_init); + tcase_add_test(tc, ecore_test_ecore_x_bell); +#endif +} diff --git a/src/util/Makefile.am b/src/util/Makefile.am new file mode 100644 index 0000000..38ebc12 --- /dev/null +++ b/src/util/Makefile.am @@ -0,0 +1,17 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-DPACKAGE_BIN_DIR=\"$(bindir)\" \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \ +@EINA_CFLAGS@ + +noinst_PROGRAMS=makekeys + +makekeys_SOURCES = \ + makekeys.c + +makekeys_LDADD = \ + @EINA_LIBS@ + +EXTRA_DIST = mkks.sh diff --git a/src/util/makekeys.c b/src/util/makekeys.c new file mode 100644 index 0000000..a057fa2 --- /dev/null +++ b/src/util/makekeys.c @@ -0,0 +1,326 @@ +/* Portions of this code are Copyright 1990, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +#include +#include +#include +#include + +#define TBLNUM 4000 +#define MIN_REHASH 15 +#define MATCHES 10 + +typedef struct _Info Info; +static struct _Info +{ + char *name; + long unsigned int val; +} info[TBLNUM]; + +/* local function prototypes */ +static int _parseline(const char *buf, char *key, long unsigned int *val, char *prefix); + +/* local variables */ +static char tab[TBLNUM]; +static unsigned short offsets[TBLNUM]; +static unsigned short indexes[TBLNUM]; +static long unsigned int values[TBLNUM]; +static char buf[1024]; +static int ksnum = 0; + +int +main(int argc, char **argv) +{ + int max_rehash = 0; + unsigned long sig; + int i = 0, j = 0, k = 0, l = 0, z = 0; + FILE *fptr; + char *name = NULL, c; + int first = 0, num_found = 0; + int best_max_rehash = 0, best_z = 0; + long unsigned int val; + char key[128], prefix[128]; + + for (l = 1; l < argc; l++) + { + if (!(fptr = fopen(argv[l], "r"))) + { + fprintf(stderr, "Could not open %s\n", argv[l]); + continue; + } + + while (fgets(buf, sizeof(buf), fptr)) + { + if (!_parseline(buf, key, &val, prefix)) + continue; + + if (val == XK_VoidSymbol) val = 0; + if (val > 0x1fffffff) + { + fprintf(stderr, "Ignoring illegal keysym (%s %lx)\n", + key, val); + continue; + } + + if (!(name = malloc(strlen(prefix) + strlen(key) + 1))) + { + fprintf(stderr, "Makekeys: Out Of Memory !!\n"); + exit(EXIT_FAILURE); + } + + sprintf(name, "%s%s", prefix, key); + info[ksnum].name = name; + info[ksnum].val = val; + ksnum++; + if (ksnum == TBLNUM) + { + fprintf(stderr, "Makekeys: Too Many Keysyms!!\n"); + exit(EXIT_FAILURE); + } + } + + fclose(fptr); + } + + printf("/* This file is generated from keysymdef.h. */\n"); + printf("/* Do Not Edit !! */\n\n"); + + best_max_rehash = ksnum; + num_found = 0; + for (z = ksnum; z < TBLNUM; z++) + { + max_rehash = 0; + for (name = tab, i = z; --i >= 0;) + *name++ = 0; + for (i = 0; i < ksnum; i++) + { + name = info[i].name; + sig = 0; + while ((c = *name++)) + sig = (sig << 1) + c; + first = j = sig % z; + for (k = 0; tab[j]; k++) + { + j += (first + 1); + if (j >= z) j -= z; + if (j == first) goto next1; + } + tab[j] = 1; + if (k > max_rehash) max_rehash = k; + } + if (max_rehash < MIN_REHASH) + { + if (max_rehash < best_max_rehash) + { + best_max_rehash = max_rehash; + best_z = z; + } + num_found++; + if (num_found >= MATCHES) + break; + } +next1: ; + } + + z = best_z; + if (z == 0) + { + fprintf(stderr, "Makekeys: Failed to find small enough hash !!\n" + "Try increasing TBLNUM in makekeys.c\n"); + exit(EXIT_FAILURE); + } + + printf("#ifdef NEED_KEYSYM_TABLE\n"); + printf("const unsigned char _ecore_xcb_keytable[] = {\n"); + printf("0,\n"); + k = 1; + for (i = 0; i < ksnum; i++) + { + name = info[i].name; + sig = 0; + while ((c = *name++)) + sig = (sig << 1) + c; + first = j = sig % z; + while (offsets[j]) + { + j += (first + 1); + if (j >= z) j -= z; + } + offsets[j] = k; + indexes[i] = k; + val = info[i].val; + printf("0x%.2lx, 0x%.2lx, 0x%.2lx, 0x%.2lx, 0x%.2lx, 0x%.2lx, ", + (sig >> 8) & 0xff, sig & 0xff, + (val >> 24) & 0xff, (val >> 16) & 0xff, + (val >> 8) & 0xff, val & 0xff); + for (name = info[i].name, k += 7; (c = *name++); k++) + printf("'%c',", c); + printf((i == (ksnum - 1)) ? "0\n" : "0,\n"); + } + + printf("};\n\n"); + printf("#define KTABLESIZE %d\n", z); + printf("#define KMAXHASH %d\n", (best_max_rehash + 1)); + printf("\n"); + printf("static const unsigned short hashString[KTABLESIZE] = {\n"); + + for (i = 0; i < z;) + { + printf("0x%.4x", offsets[i]); + i++; + if (i == z) break; + printf((i & 7) ? ", " : ",\n"); + } + + printf("\n"); + printf("};\n"); + printf("#endif\n"); + + best_max_rehash = ksnum; + num_found = 0; + for (z = ksnum; z < TBLNUM; z++) + { + max_rehash = 0; + for (name = tab, i = z; --i >= 0;) + *name++ = 0; + for (i = 0; i < ksnum; i++) + { + val = info[i].val; + first = j = val % z; + for (k = 0; tab[j]; k++) + { + if (values[j] == val) goto skip1; + j += (first + 1); + if (j >= z) j -= z; + if (j == first) goto next2; + } + tab[j] = 1; + values[j] = val; + if (k > max_rehash) max_rehash = k; +skip1: ; + } + if (max_rehash < MIN_REHASH) + { + if (max_rehash < best_max_rehash) + { + best_max_rehash = max_rehash; + best_z = z; + } + num_found++; + if (num_found >= MATCHES) break; + } +next2: ; + } + + z = best_z; + if (z == 0) + { + fprintf(stderr, "Makekeys: Failed to find small enough hash !!\n" + "Try increasing TBLNUM in makekeys.c\n"); + exit(EXIT_FAILURE); + } + for (i = z; --i >= 0;) + offsets[i] = 0; + + for (i = 0; i < ksnum; i++) + { + val = info[i].val; + first = j = val % z; + while (offsets[j]) + { + if (values[j] == val) goto skip2; + j += (first + 1); + if (j >= z) j -= z; + } + offsets[j] = indexes[i] + 2; + values[j] = val; +skip2: ; + } + + printf("\n"); + printf("#ifdef NEED_VTABLE\n"); + printf("#define VTABLESIZE %d\n", z); + printf("#define VMAXHASH %d\n", best_max_rehash + 1); + printf("\n"); + printf("static const unsigned short hashKeysym[VTABLESIZE] = {\n"); + for (i = 0; i < z;) + { + printf("0x%.4x", offsets[i]); + i++; + if (i == z) break; + printf((i & 7) ? ", " : ",\n"); + } + printf("\n"); + printf("};\n"); + printf("#endif\n"); + + return 0; +} + +/* local functions */ +static int +_parseline(const char *buf, char *key, long unsigned int *val, char *prefix) +{ + int i = 0; + char alias[128]; + char *tmp = NULL, *tmpa = NULL; + + /* try to match XK_foo first */ + i = sscanf(buf, "#define %127s 0x%lx", key, val); + if ((i == 2) && (tmp = strstr(key, "XK_"))) + { + memcpy(prefix, key, (tmp - key)); + prefix[tmp - key] = '\0'; + tmp += 3; + memmove(key, tmp, strlen(tmp) + 1); + return 1; + } + + /* try to match an alias */ + i = sscanf(buf, "#define %127s %127s", key, alias); + if (((i == 2) && (tmp = strstr(key, "XK_"))) && + (tmpa = strstr(alias, "XK_"))) + { + memcpy(prefix, key, (tmp - key)); + prefix[tmp - key] = '\0'; + tmp += 3; + memmove(key, tmp, strlen(tmp) + 1); + memmove(tmpa, tmpa + 3, strlen(tmpa + 3) + 1); + + for (i = ksnum - 1; i >= 0; i--) + { + if (!strcmp(info[i].name, alias)) + { + *val = info[i].val; + return 1; + } + } + fprintf(stderr, "Cannot find matching definition %s for keysym %s%s\n", + alias, prefix, key); + } + + return 0; +} diff --git a/src/util/mkks.sh b/src/util/mkks.sh new file mode 100755 index 0000000..6669242 --- /dev/null +++ b/src/util/mkks.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +cat $* | awk 'BEGIN { \ + printf "/*\n * This file is generated from %s. Do not edit.\n */\n", \ + "$(INCLUDESRC)/keysymdef.h";\ +} \ +/^#define/ { \ + len = length($2)-3; \ + printf("{ \"%s\", %s },\n", substr($2,4,len), $3); \ +}' -- 2.7.4

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 literal 0 HcmV?d00001 diff --git a/doc/img/ecore_thread_feedback.eps b/doc/img/ecore_thread_feedback.eps new file mode 100644 index 0000000..4d2d2d0 --- /dev/null +++ b/doc/img/ecore_thread_feedback.eps @@ -0,0 +1,18387 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: (ImageMagick) +%%Title: (ecore_thread_feedback.eps) +%%CreationDate: (2011-07-19T13:34:32-03:00) +%%BoundingBox: -0 -0 635 657 +%%HiResBoundingBox: 0 0 635.271 657 +%%DocumentData: Clean7Bit +%%LanguageLevel: 1 +%%Pages: 1 +%%EndComments + +%%BeginDefaults +%%EndDefaults + +%%BeginProlog +% +% Display a color image. The image is displayed in color on +% Postscript viewers or printers that support color, otherwise +% it is displayed as grayscale. +% +/DirectClassPacket +{ + % + % Get a DirectClass packet. + % + % Parameters: + % red. + % green. + % blue. + % length: number of pixels minus one of this color (optional). + % + currentfile color_packet readhexstring pop pop + compression 0 eq + { + /number_pixels 3 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add 3 mul def + } ifelse + 0 3 number_pixels 1 sub + { + pixels exch color_packet putinterval + } for + pixels 0 number_pixels getinterval +} bind def + +/DirectClassImage +{ + % + % Display a DirectClass image. + % + systemdict /colorimage known + { + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { DirectClassPacket } false 3 colorimage + } + { + % + % No colorimage operator; convert to grayscale. + % + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { GrayDirectClassPacket } image + } ifelse +} bind def + +/GrayDirectClassPacket +{ + % + % Get a DirectClass packet; convert to grayscale. + % + % Parameters: + % red + % green + % blue + % length: number of pixels minus one of this color (optional). + % + currentfile color_packet readhexstring pop pop + color_packet 0 get 0.299 mul + color_packet 1 get 0.587 mul add + color_packet 2 get 0.114 mul add + cvi + /gray_packet exch def + compression 0 eq + { + /number_pixels 1 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add def + } ifelse + 0 1 number_pixels 1 sub + { + pixels exch gray_packet put + } for + pixels 0 number_pixels getinterval +} bind def + +/GrayPseudoClassPacket +{ + % + % Get a PseudoClass packet; convert to grayscale. + % + % Parameters: + % index: index into the colormap. + % length: number of pixels minus one of this color (optional). + % + currentfile byte readhexstring pop 0 get + /offset exch 3 mul def + /color_packet colormap offset 3 getinterval def + color_packet 0 get 0.299 mul + color_packet 1 get 0.587 mul add + color_packet 2 get 0.114 mul add + cvi + /gray_packet exch def + compression 0 eq + { + /number_pixels 1 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add def + } ifelse + 0 1 number_pixels 1 sub + { + pixels exch gray_packet put + } for + pixels 0 number_pixels getinterval +} bind def + +/PseudoClassPacket +{ + % + % Get a PseudoClass packet. + % + % Parameters: + % index: index into the colormap. + % length: number of pixels minus one of this color (optional). + % + currentfile byte readhexstring pop 0 get + /offset exch 3 mul def + /color_packet colormap offset 3 getinterval def + compression 0 eq + { + /number_pixels 3 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add 3 mul def + } ifelse + 0 3 number_pixels 1 sub + { + pixels exch color_packet putinterval + } for + pixels 0 number_pixels getinterval +} bind def + +/PseudoClassImage +{ + % + % Display a PseudoClass image. + % + % Parameters: + % class: 0-PseudoClass or 1-Grayscale. + % + currentfile buffer readline pop + token pop /class exch def pop + class 0 gt + { + currentfile buffer readline pop + token pop /depth exch def pop + /grays columns 8 add depth sub depth mul 8 idiv string def + columns rows depth + [ + columns 0 0 + rows neg 0 rows + ] + { currentfile grays readhexstring pop } image + } + { + % + % Parameters: + % colors: number of colors in the colormap. + % colormap: red, green, blue color packets. + % + currentfile buffer readline pop + token pop /colors exch def pop + /colors colors 3 mul def + /colormap colors string def + currentfile colormap readhexstring pop pop + systemdict /colorimage known + { + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { PseudoClassPacket } false 3 colorimage + } + { + % + % No colorimage operator; convert to grayscale. + % + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { GrayPseudoClassPacket } image + } ifelse + } ifelse +} bind def + +/DisplayImage +{ + % + % Display a DirectClass or PseudoClass image. + % + % Parameters: + % x & y translation. + % x & y scale. + % label pointsize. + % image label. + % image columns & rows. + % class: 0-DirectClass or 1-PseudoClass. + % compression: 0-none or 1-RunlengthEncoded. + % hex color packets. + % + gsave + /buffer 512 string def + /byte 1 string def + /color_packet 3 string def + /pixels 768 string def + + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + x y translate + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + currentfile buffer readline pop + token pop /pointsize exch def pop + /Times-Roman findfont pointsize scalefont setfont + x y scale + currentfile buffer readline pop + token pop /columns exch def + token pop /rows exch def pop + currentfile buffer readline pop + token pop /class exch def pop + currentfile buffer readline pop + token pop /compression exch def pop + class 0 gt { PseudoClassImage } { DirectClassImage } ifelse +} bind def +%%EndProlog +%%Page: 1 1 +%%PageBoundingBox: 0 0 635 657 +userdict begin +DisplayImage +0 0 +635.271 656.873 +12 +794 821 +1 +1 +1 +8 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6A87FFFFDB33FFFFFF3EC6 +FFFF975CFFFFFF24FFFFFF638FFFFFC63EFFFFFF33D0FFFF876AFFFFFF24FFFFFF56A0FF +FFB24AFFFFFF2EE7FFFF7878FFFFF329FFFFFF4AB2FFFFA950FFFFFF24FFFFFF6A7FFFFF +DB33FFFFFF3EC6FFFF975CFFFFFF24FFFFFF638FFFFFC63EFFFFFF39D0FFFF876AFFFFFF +20FFFFFF56A0FFFFB24AFFFFFF2EE7FFFF7878FFFFF329FFFFFF4AB2FFFFA950FFFFFF24 +FFFFFF717FFFFFDB33FFFFFF3EBCFFFF975CFFFFFF24FFFFFF638FFFFFC63EFFFFFF39D0 +FFFF876AFFFFFF24FFFFFF56A0FFFFB244FFFFFF2EE7FFFF7878FFFFF329FFFFFF4AB2FF +FFA950FFFFFF24FFFFFF717FFFFFDB33FFFFFF44BCFFFF975CFFFFFF20FFFFFF638FFFFF +C63EFFFFFF39D0FFFF876AFFFFFF24FFFFFF56A0FFFFBC44FFFFFF2EE7FFFF7871FFFFF3 +29FFFFFF4AB2FFFFA950FFFFFF24FFFFFF717FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8EAFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF73DAFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3AC5FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF24FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7D7 +D7F1FFFFFFFFFFFFF6D7D7E2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD53365FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFECD7D7D7D7D7D7D7D7D7D7D7DBFFA3338AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF384CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +4400004EFFFFFFFFFFFF6F000029FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC30037FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF65000000000000000000000011FF810064FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF051CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF4400020DF8FFFFFFFFFF1F020029FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDA4675FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF99464646463000124646464655FF810064FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF051CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF79DBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF56FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF440032008EFFFFFFFFB900310029FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF990031FFFFFFFFFFFF8100 +64FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF051CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFA0E8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF44007F0635FFFFFFFF4F01880029FFFFFFFFB967463A5181FDFFFFFFFFE3 +6A93FFFFFF946AE2CF7140509BFFFFFFFFFFFFFFFFFFFFFFFFFFFF990031FFFFFFFFFFFF +810064F1844B4575F8FFFFFFFF956AE0CD74425BFFFFFFAE643F4B78F3FFFFFFFFFFB665 +463A5285FDFFFFFFFFFFFFC0613D62B1FF051CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF44008F3D03DFFFFFF80D28B10029FFFFFF9400000D15030024E7FFFF +FFC30037FFFFFF3900880D020700005FFFFFFFFFFFFFFFFFFFFFFFFFFF990031FFFFFFFF +FFFF81005A2B0009000024F8FFFFFF3B00850D000826FFF8530101130A001AC2FFFFFF89 +00000D15020027EDFFFFFFFF8F07000C0A0286051CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF44008F9E006DFFFF8E007BB10029FFFFFFB170DFFFFFE84A0051 +FFFFFFC30037FFFFFF3900066BF4F17B0A04D4FFFFFFFFFFFFFFFFFFFFFFFF990031FFFF +FFFFFFFF81000436DAFFA0220079FFFFFF3B000558E5FFDBFF670034D8FFFF810324FFFF +FFAA74E2FFFFE5440059FFFFFFDD070791FFFD8407011CFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFD0F4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBCFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF44008FFD131EFFFF3307ECB10029FFFFFFFFFFFFFFFFFFFD +180CFFFFFFC30037FFFFFF390046FFFFFFFF3A0084FFFFFFFFFFFFFFFFFFFFFFFF990031 +FFFFFFFFFFFF810013F3FFFFFF83003AFFFFFF3B0037FFFFFFFFDD0716F3FFFFFFFF4C00 +97FFFFFFFFFFFFFFFFFB1312FFFFFF550064FFFFFFFF55001CFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF57D0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF44008FFF5B00B8DB0340FFB10029FFFFFFFFFFDB9F7D +72721E00EAFFFFC30037FFFFFF390096FFFFFFFF730067FFFFFFFFFFFFFFFFFFFFFFFF99 +0031FFFFFFFFFFFF810047FFFFFFFFD70026FFFFFF3B008DFFFFFFFF910054FFFFFFFFFF +910067FFFFFFFFD89E7C72721B01F6FFFF2600D8FFFFFFFFBC001CFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44008FFFCA01506A00A0FFB10029FFFFFFF14003 +000000000000C6FFFFC30037FFFFFF3900BDFFFFFFFF95005BFFFFFFFFFFFFFFFFFFFFFF +FF990031FFFFFFFFFFFF810062FFFFFFFFFF031EFFFFFF3B00B1FFFFFFFF670005090909 +0909070048FFFFEC3D02000000000000D4FFFF1004FFFFFFFFFFF1011CFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44008FFFFF290D1A13FDFFB10029FFFFFF42 +003FB0E0FBFF3700C5FFFFC30037FFFFFF3900C0FFFFFFFF95005BFFFFFFFFFFFFFFFFFF +FFFFFF990031FFFFFFFFFFFF810064FFFFFFFFFF031EFFFFFF3B00BCFFFFFFFF60003662 +62626262626295FFFF3B0044B2E2FBFF3000D2FFFF0E05FFFFFFFFFFF4011CFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44008FFFFF7D00005BFFFFB10029FFFF +FD0715FDFFFFFFFF1D00C5FFFFC30037FFFFFF3900C0FFFFFFFF95005BFFFFFFFFFFFFFF +FFFFFFFFFF990031FFFFFFFFFFFF810064FFFFFFFFFF031EFFFFFF3B00BCFFFFFFFF8D00 +51FFFFFFFFFFFFFFFFFFF8041AFFFFFFFFFF1700D2FFFF2400E0FFFFFFFFC3001CFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51CDFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2EFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44008FFFFFED3533CAFFFFB10029 +FFFFE70018FFFFFFFFBB0100C5FFFFC30037FFFFFF3900C0FFFFFFFF95005BFFFFFFFFFF +FFFFFFFFFFFFFF990031FFFFFFFFFFFF810064FFFFFFFFFF031EFFFFFF3B00BCFFFFFFFF +D50411E8FFFFFFFFFFFFFFFFD8001DFFFFFFFFB10100D2FFFF4E006FFFFFFFFF5E001CFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8F6FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44008FFFFFFFFFFFFFFFFFB1 +0029FFFFFF110085FDFFC71D0200C5FFFFC30037FFFFFF3900C0FFFFFFFF95005BFFFFFF +FFFFFFFFFFFFFFFFFF990031FFFFFFFFFFFF810064FFFFFFFFFF031EFFFFFF3B00BCFFFF +FFFFFF5D002CD0FFFFFFD25ECCFFFF0C008EFDFFC21A0200D2FFFFD4050BADFFFF9F0901 +1CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44008FFFFFFFFFFFFFFF +FFB10029FFFFFF850100101C02393900C5FFFFC30037FFFFFF3900C0FFFFFFFF95005BFF +FFFFFFFFFFFFFFFFFFFFFF990031FFFFFFFFFFFF810064FFFFFFFFFF031EFFFFFF3B00BC +FFFFFFFFFFF449010317200E0100BCFFFF7C0000111B023E3300D2FFFFFF8004011B1801 +70051CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F5AC2FFFFFFFFFF +FFFFFFD55A7CFFFFFFFFA63F29477CFB8A5AE0FFFFE05A86FFFFFF875ADFFFFFFFFFC55A +A0FFFFFFFFFFFFFFFFFFFFFFFFC75A81FFFFFFFFFFFFB95AA5FFFFFFFFFF5E73FFFFFF89 +5ADBFFFFFFFFFFFFFFAA5735293D64C2FFFFFFFFA03E29487FFD855AE8FFFFFFFFB1502C +4C96FF5F72FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF99E5FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7EDDFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF71FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF3EC6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF29FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFB4CFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFD5CCFFFFFFFFFFE3CAE3FFFFFFFFFFCAD5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF7033FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF8633D7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA833AEFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF784646A4FFFFFFFFFFFFAD464671FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB20041 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF3800C2FFFFFFFF39003AFFFFFFFFBF003AFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF4300F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF883FDBFFFFFFFF5F00C5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF880090FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3A000031FFFFFFFFFFFF3A000032FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2 +0041FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF6DD8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF710075FFFFFFFF0E040FFFFFFFFF720075FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF4300F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5500C9FFFFFFFF5F00C5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF880090FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3A001202DAFFFFFFFFE304120032FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFF8D7E7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0ECFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFBD003BFFFFFFC0004B00C3FFFFFF3A00C3FFFFFFFFEFFBFFFFFFFF +FFFFFFFFFFFFF4EFFF4300F8FFFFFFFFFFFFFFFFFFFFFFECFFFFFFFFFFFFFFFFFFFFFFE7 +FFFFFFFFFFFFFF5500C9FFFFFFFF5F00C5FFFFEDFFFFFFFFFFFFFFFFFFFFF3F1FFFFFFFF +FBEFFFFFFFFFFFFFFFFFFFE5FFFFFFFFFFFFFFFFFFFFEFFFFF880090FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF933FB1FFFFFFFFFFCF3F7BFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3A005A0068FFFFFFFF7200590032FFFFFFFFFFFBD7C0EDFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFC9ECFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF0D10FFFFFF7302D00276FFFFFF0E10FFFFFF6F17010523A9 +FFFFFFF4175A9E220427FF4300F8FFFFFD57187AFFFFC7330B001256F4FFFFFF4524DD33 +0B00E2FFFFFFFFFF450B001417177AFF5F00C04F1000148AFFFFFFEC175F9922032BFFFF +A0250601187AFFFFFFFF782405000629B9FFFFFFFFFF7715001563880090FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF64008AFFFFFFFFFFB60045FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3A009C141BFFFFFFFF21129F0032FFFFFFBC33070000001A +9FFFFFFFFFB60949FFFFFF3809D24E0B00012AD0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3800C5FFFF3A20FF1E3CFFFFC2003DFFFF4C002E7E6A +120297FFFFF3001E0B4E7376FF4300F8FFF43B0272FFFFA906146C7D29002EFFFFFF2E08 +1C346D60ECFFFFFFFFFF942E005E7272B6FF5F00262874510901BCFFFFE8001F0B4F7378 +FF730126776F1A005DFFFFFF31417384430B07D5FFFFFF6D00267C7117220090FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF64008AFFFFFFFFFFB60045 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3A009E5D00B2FFFFBC0058A10032FFFFFF84104C727E +510801ACFFFFFFB20041FFFFFF30002E155A5B120022FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7F3FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF710077FFFF0F50FF4E10FFFF740077FFBF022BFB +FFFFD5071CFDFFF30000A1FFFFFFFF4300F8E328068FFFFFFB1E12E5FFFFFF540095FFFF +2E004DFFFFFFFFFFFFFFFFFFFF5500C9FFFFFFFF5F002DFDFFFF9B004DFFFFE80000A8FF +FFFFD8082EFDFFFFFF2705D5FFFFFBFFFFFFFF9A0051FFFFE80B1FF6FFFFE00A0090FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF64008AFFFFFFFFFFB6 +0045FFFFFFEC76535068A6FBFFFFFFFFB06D517ADAFFFFFFFF9F8EFFB16C4EF6FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A009ECD014BFFFF5100C5A10032FFFFFFE8FBFF +FFFFFFB6042AFFFFFFB20041FFFFFF30001CECFFFFFB1900ADFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5CD2FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD003DFFC3008FFF8C00C6FF3B00C7FF6500 +9EFFFFFFFF4600C7FFF30022FFFFFFFFFF4300C71A0DACFFFFFFB8005CFFFFFFFFBC0052 +FFFF2E00D4FFFFFFFFFFFFFFFFFFFF5500C9FFFFFFFF5F0095FFFFFFF10531FFFFE80025 +FFFFFFFF740099FFFFFFFF77008CFFFFFFFFE8BBA9A90D2DFFFF90007BFFFFFFFF4E0090 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF64008AFFFFFFFF +FFB60045FFFFC70E000B1C0B00C7FFFFED44000B13000B94FFFFFF2A106D000A06ECFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A009EFF2B0BF6FA0E25FFA10032FFFFFFFF +FFFFFFFFFFFF2409FFFFFFB20041FFFFFF300085FFFFFFFF4A0080FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0D11FF7501E2FFDF0178FF1011FFFF +4700D8FFFFFFFF6E0096FFF3003DFFFFFFFFFF43000E0BC7FFFFFFFF8A001521201F1E1D +0136FFFF2E06FFFFFFFFFFFFFFFFFFFFFF5500C9FFFFFFFF5F00C0FFFFFFFF1A25FFFFE8 +0041FFFFFFFF51001C21201F1E180067FFFFA825000000000018FFFF6B00ACFFFFFFFF75 +0090FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF64008AFFFF +FFFFFFB60045FFFF3D019FFFFFFFA6E5FFFF510172FDFFA01A0BE2FFFF2A0218B9FFF4FD +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A009EFF7F008A900077FFA10032FFFF +FFFFC04A26130D0D0400E5FFFFB20041FFFFFF3000BFFFFFFFFF7F0069FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3800C73C1CFFFFFF1B3DC5003E +FFFF4200E0FFFFFFFF73008EFFF30046FFFFFFFFFF43003A005FFFFFFFFF7E003C626262 +62626287FFFF2E0DFFFFFFFFFFFFFFFFFFFFFF5500C9FFFFFFFF5F00C5FFFFFFFF1A24FF +FFE8004BFFFFFFFF480055626262626262A6FFD40A1073A1D7E31C17FFFF6500B2FFFFFF +FF7B0090FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF64008A +FFFFFFFFFFB60045FFFF300CF6FFFFFFFFFFFFD7033DFFFFFFFF7D006CFFFF2A009CFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A009EFFEF09323606E7FFA10032 +FFFFFF930106324B595A1800D7FFFFB20041FFFFFF3000D2FFFFFFFF870067FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF710079104BFFFFFF491276 +007AFFFF5F00ADFFFFFFFF5100BDFFF30046FFFFFFFFFF4300F4440057FFFFFFB0005DFF +FFFFFFFFFFFFFFFF2E0DFFFFFFFFFFFFFFFFFFFFFF5600C6FFFFFFFF5F00C5FFFFFFFF1A +24FFFFE8004BFFFFFFFF6E009AFFFFFFFFFFFFFFFF7F0074FFFFFFFF0B17FFFF880088FF +FFFFFF590090FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF64 +008AFFFFFFFFFFB60045FFFF80002272D0FFFFFFFF99004D9491908F7F0148FFFF2A02FA +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A009EFFFF4503033DFFFFA1 +0032FFFFFF1008C6FFFFFFFF2200D7FFFFB20041FFFFFF3000D2FFFFFFFF870067FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF48CAFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD00240088FFFFFF86 +002400CAFFFFA50044FFFFFFF10E11F6FFF30046FFFFFFFFFF4300F8FF4D0050FFFFF112 +10E7FFFFFFFFFFFFFFFF2E0DFFFFFFFFFFFFFFFFFFFFFF6B0095FFFFFFFF5F00C5FFFFFF +FF1A24FFFFE8004BFFFFFFFFBF032DFFFFFFFFFFFFFFFF740089FFFFFF840017FFFFD504 +2DFFFFFFF4120090FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF29FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF670084FFFFFFFFFFAE0048FFFFF6741700013096FFFF74000304040404040439FFFF2A +0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A009EFFFFA900009BFF +FFA10032FFFFDA002BFFFFFFFFEF0800D7FFFFB20041FFFFFF3000D2FFFFFFFF870067FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFECFBFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0D0000DBFFFF +FFD8000013FFFFFFFF34004FB09B26007BFFFFF30046FFFFFFFFFF4300F8FFFF570048FD +FF94011880B9AC7F308AFFFF2E0DFFFFFFFFFFFFFFFFFFFFFFAA00226E83C0FF5F00C5FF +FFFFFF1A24FFFFE8004BFFFFFFFFFF5A002B93BDA37020D2FFBD021A86BD6D0C0D17FFFF +FF4E0045B6A82C100090FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF86006BFFFFFFFFFF8F0063FFFFFFFFFDAE531000B9FF8E007FFFFFFFFFFFFFFFFF +FF2A10FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A009EFFFFFFB5B4 +FBFFFFA10032FFFFED0108ECFFFFFF590000D7FFFFB20041FFFFFF3000D2FFFFFFFF8700 +67FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF380018FF +FFFFFFFF170040FFFFFFFFF14A0300000A7EFFFFFFF30046FFFFFFFFFF4300F8FFFFFF61 +0041FBFFA61C0000000125B6FFFF2E0DFFFFFFFFFFFFFFFFFFFFFFFF6A18050069FF5F00 +C5FFFFFFFF1A24FFFFE8004BFFFFFFFFFFFF7E0E0000000532E7FFFF750700000EA02217 +FFFFFFF84A0200023A830090FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFB50035FFFFFFFFFF510089FFFFFFFFFFFFFFB90051FFC7003DFFFFFFFFFFFF +FFFFFF2A10FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A009EFFFFFF +FFFFFFFFFFA10032FFFFFF2E002878893C091800D7FFFFB20041FFFFFF3000D2FFFFFFFF +870067FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4B5C9FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFE5ADBCE7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8AAC3F1FFFFFFFFFFEDB2D0FFFF +FFFFFFFFFFFFFFECB1EAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF290184FFFFFFA00717F4FFFF8DEDFFFFFF87005BFFFF3E017AFFFFFF +FFACC3FFFF2A10FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A009EFF +FFFFFFFFFFFFFFA10032FFFFFFD52800000016B43300D7FFFFB20041FFFFFF3000D2FFFF +FFFF870067FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF8CE2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF71FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFC31700172C1A010EA6FFFFFF14092A3D200212DAFFFFE02B0018 +362E15008EFFFF2A10FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7A4DDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF85E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFF36F462E4165E5FFFFFFFFAE603B2C3A67E5FFFFFFFFFF +894D2F37519EFAFFFF7C69FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFF6FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF43C9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2EFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62D4FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFF1FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF8EBDFFFFFFFFFFFFFFA4C5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBCFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC98F96CCFD +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5844FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C46C5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D09000000 +001979FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2812FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B00A3FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF82B002381 +B8B47A2B00E8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2812FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B00A3FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB6EDFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF97FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6B0041 +FAFFFFFFFFFF77EFFFFFFFFFFFEAFFFFFFFFFFFFFFFFFFFBF4FFFF2812FFFFFFFFFFFFFF +EDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B00A3FFFFFFFFFFFFFFFFFF +FFFFE5CAFDFFFFFFFFFFFFFFFFFFF1C5F6FFFFFFFFFFFFFFFFFFFFFFCCEFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67D5FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF7CB2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE509 +0AE3FFFFFFFFFFFFFFFFFFFFEA460E000B38D8FFFFFFFFE339070426B82812FFFFFFFFB9 +2D09011463FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B00A3FFFFFFFFFFFFFF +FFFF7B120000073ADFFFFFFFFFFFA91E02000324BBFFFFFFFF4709B8510C00022BDAFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF94C2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +A30044FFFFFFFFFFFFFFFFFFFFF61A014D8555030EE0FFFFF61A025385500E1412FFFFFF +94031A717823003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B00A3FFFFFFFFFF +FFFFFF5300126278350010E0FFFFFF8D0205547C4C0204A5FFFFFF3F0029106079380013 +EAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF533335353535353535353535353535353535353535353535353535 +353535353535353535353535353535353535353535353535353535353535353535353535 +353535353535353535353535353535353535353535353535353535353535353535353535 +353535353535353535353535353535353535353535353535353535353535353535353535 +353535353535353535353535353535353535353535353535353535353535353535353535 +3535353535353535353535353535353535353524BCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF750064FFFFFFFFFFFFFFFFFFFF6D0065FFFFFF860051FFFF740075FFFFFF6D0012FF +FFF1131BF3FFFFFF4101B0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B00A3FFFFFF +FFFFFFFFC3030FD7FFFFFF4D004DFFFFF41401A4FFFFFF880020FDFFFF3F000BD2FFFFFF +4C0061FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF5A007CFFFFFFFFFFFFFFFFFFFF2908F1FFFFFFFD1316FFFF2D0AF6FFFFFFF307 +12FFFF9B0072FFFFFFFFA00067FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B00A3FF +FFFFFFFFFFFF560066FFFFFFFFE20607FFFF940033FFFFFFFFFF2000B4FFFF3F0058FFFF +FFFFDD0413FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF3EC6FFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF24FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF7A0060FFFFFFFFFFFFFFFFFFFF131DFFFFFFFFFF3002F8FF1520FFFFFFFF +FF1C12FFFF73001821201F1E1C0047FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B00 +A3FFFFFFFFFFFFFF3700A9FFFFFFFFFF2100D5FF6C0066FFFFFFFFFF4E0086FFFF3F0091 +FFFFFFFFFF1C01F4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7CB2FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFA80040FFFFFFFFFFFFFFFFFFFF1020FFFFFFFFFF3301F1FF1224FFFF +FFFFFF1F12FFFF68004662626262626293FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +2B00A3FFFFFFFFFFFFFF2200CCFFFFFFFFFF3300ACFF51007FFFFFFFFFFF660068FFFF3F +00ACFFFFFFFFFF2D00CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94C2FFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFEC0D06D7FFFFFFFFFFFFFFFFFF250BFBFFFFFFFF1B12FFFF280E +FFFFFFFFFD0B12FFFF940073FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF2B00A3FFFFFFFFFFFFFF3600ACFFFFFFFFFF2200D0FF6A0068FFFFFFFFFF510083FF +FF3F0094FFFFFFFFFF1E01F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF790034ECFFFFFFFFF458ECFF580089FFFFFFAA0040FFFF +5D0090FFFFFF880012FFFFE00A19F4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF2B00A3FFFFFFFFFFFFFF53006DFFFFFFFFEA0805FDFF900038FFFFFFFFFF2600 +B0FFFF3F0060FFFFFFFFE70610FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF85E0FFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD3D0015618F8C5A1800E8FFE70D0774B8830E04CA +FFFFE70B0A81C27D0B0D12FFFFFF7D001F88BCA87A2AA3FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF2B00A3FFFFFFFFFFFFFFB90213E7FFFFFF5C0046FFFFEF1002B9FFFFFF9C +001CFBFFFF3F000EE2FFFFFF5B0057FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF93E3FFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8617010000012A9BFFFFFFCC270000001C +B5FFFFFFFFBD1700000A8E2812FFFFFFFF9717000000022AC9FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF2B0029393939393939A9FF48001A738942000BD8FFFFFF80010A658E +5A04029AFFFFFF3F001E1878944B000EE3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6E +B4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7CB2FFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1B5BDF3FFFFFFFFFFFFFFE5AE +DDFFFFFFFFFFFFFFFFCCBFFDFFFFFFFFFFFFFFFFFFE0ACBFECFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF2B000000000000000086FFFD660600000129CFFFFFFFFFFF940F +00000015A6FFFFFFFF3F00AE3D03000020CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94C2FFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC0A9E7FFFFFFFFFFFFFF +FFFFD0A4D8FFFFFFFFFFFF3F00B5FFF1AAD5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2FAFFFFFFFFFFFFFFFF45EBFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF3F00B5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4DCCFFFFFFFFFFFFFFFF45EBFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF39FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F00B5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F00B5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45 +EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF7CB2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD5BFF3FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF94C2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5CD2FFFFFFFFFF +FFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF39FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7F3FFFFFF +FFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFD0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF7CB2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFCA000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFA8EAFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94C2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF73DAFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF63FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFCFC9FFFFFFEBC6E4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFC05A5A5A5A6789CBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF220BFFFFFF98007CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7CB2FFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF3EC6FFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF980000000000000255FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF220BFFFFFF98007CFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94C2FFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF980052F5F5CB7110007BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF220BFFFFFFF5E2F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF980055FFFFFFFF760021FFFFFFFFFFF6D4F6FFFFFFFFFFFFFFFF +FFFFFDD6F5FFFFFFFFFFFFFFFFFED7F8FFFF220BFFFFFFFFFFFFFFFFFFFFFFFFFFFBD5F6 +FFFFFFFFFFFFFFFFFDD7F9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6E +B4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF980055FFFFFFFFD70003FAFFFFB32502000230CAFFFFFFFF +310FF6510B000249EAFFFFFFFFFE6D0C000638E0220BFFFFFF9E0C83FFFFFF2817F34C0B +00024FEEFFFFFFFFFA600A00063CE62420FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF79DBFFFFFFFFFFFFFFFF45EBFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF980055FFFFFFFFAD000EFFFF8901157598700C06C5FF +FFFF25013C28776912004AFFFFFFFF590024808A3720150BFFFFFF98007CFFFFFF1C0735 +2C78650F0054FFFFFFFF480031868B3B251014FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7CB2 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF56FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0E8FFFFFFFFFFFFFFFF45EBFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF980055FFFFFFFA470039FFDF0A1EEDFFFFFFCA03 +34FFFFFF25003BF9FFFFF60D01E0FFFFCB0223EFFFFFFB45000BFFFFFF98007CFFFFFF1C +0043FBFFFFF10703EAFFFFB70036F9FFFFFD460014FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +94C2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF98002B7979570F0004C6FF6F0097FFFFFFFF +FF4200E8FFFF2500BDFFFFFFFF4200B8FFFF640094FFFFFFFFC6000BFFFFFF98007CFFFF +FF1C00C9FFFFFFFF3900C5FFFF5500ADFFFFFFFFC60014FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA +1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45 +EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF980000000000083BC2FFFF46006B8181 +8181813600BEFFFF2500F1FFFFFFFF78009FFFFF4200D2FFFFFFFFFF070BFFFFFF98007C +FFFFFF1C03FAFFFFFFFF6D00ABFFFF3400E3FFFFFFFFFB0314FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0F4FFFFFFFFFFFFFF +FF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF980049D8D8E8FFFFFFFFFF280006 +06060606060606A8FFFF2502FFFFFFFFFF7F009DFFFF2A00EBFFFFFFFFFF1B0BFFFFFF98 +007CFFFFFF1C0BFFFFFFFFFF7400A9FFFF2000F9FFFFFFFFFF1214FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51CDFFFFFFFFFF +FFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF980055FFFFFFFFFFFFFFFF41 +00D6FFFFFFFFFFFFFFFFFFFF2502FFFFFFFFFF7F009DFFFF3F00D5FFFFFFFFFF090BFFFF +FF98007CFFFFFF1C0BFFFFFFFFFF7400A9FFFF3A00DCFFFFFFFFF80114FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF7CB2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF44FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF980055FFFFFFFFFFFFFF +FF6A008FFFFFFFFFFFFFFFFFFFFF2502FFFFFFFFFF7F009DFFFF5F009EFFFFFFFFD0000B +FFFFFF98007CFFFFFF1C0BFFFFFFFFFF7400A9FFFF5E0098FFFFFFFFAE0014FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF94C2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF980055FFFFFFFFFF +FFFFFFD40615E4FFFFFFFFFFE6FFFFFF2502FFFFFFFFFF7F009DFFFFC1002CF8FFFFFF53 +000BFFFFFF98007CFFFFFF1C0BFFFFFFFFFF7400A9FFFFD00222E3FFFFED2E0014FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF980055FFFFFF +FFFFFFFFFFFF7E001078A3A0803E1EFFFFFF2502FFFFFFFFFF7F009DFFFFFF4D003299A3 +4A16120BFFFFFF98007CFFFFFF1C0BFFFFFFFFFF7400A9FFFFFF6D0013545918471516FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF51CDFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF980055FF +FFFFFFFFFFFFFFFFFFAD1F000000001B72FFFFFF2502FFFFFFFFFF7F009DFFFFFFFA5D03 +000023D2220BFFFFFF98007CFFFFFF1C0BFFFFFFFFFF7400A9FFFFFFFF90310B2B69F90A +2CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF2EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFD8F6FFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFEABCC0DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFF3BDE3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +D9004AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7CB2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFE7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6FFFFFF +FFFD4F0097FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94C2FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6938 +7A997B2C002BFDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF99E5FFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +981E0000001466F4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF7EDDFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFF4D9EDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +5EF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7CB2FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6E +B4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94C2FFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3EC6FFFFFFFFFFFFFFFF45EBFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5A2FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFCDBAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF29FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7C6F9FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8EB3FFFFFFB807FFFF +FFFFFFFFFFEF66320A50FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7946FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC5A5A5A5A5A5A +5A5A5A5A5A5AE3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4200DBFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF7CB2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA +1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF407FFFFFFFB807 +FFFFFFFFFFFFFFE55687374AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2D7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45 +EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC500000000 +0000000000000000D1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4200DBFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF94C2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB8264B9797F5 +B807F9A275A6FEFFFFFFFFFF554AFFFFFFFFFFFFFFFFFF97E6BA7CBEDDA0FFFFFFEE97F7 +FFDCA1F59E75ACFFFFFFD1ACEE9877B9FFFFFFC9B4FFFFBAC3DC8A7ED1FFFFFFFFC77C8F +E1B5C5FFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6DD8FFFFFFFFFFFFFF +FF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAE2E2 +E2E2E20006E2E2E2E2E2FBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4200DBFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9D1C376F +6FF2B8054B3A590772FFFFFFFFFF554AFFFFFFFFFFFFFFFFFE004E1768AEAC13FFFFFFD4 +00EBFFA8114041540482FFFF8D22304C49029DFFFF7946FFFF543E1C5E3206D0FFFF9F02 +385A1E2B6FFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0ECFFFFFFFFFF +FFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFE0007FFFFFFFFFFFEE5CFEFFFFFFFFFFFFFFFFFFEE4CDDCF6FFFFFFFF4200DB +FFFFFFFFFFFFFFFFFFFFFEE5CDDBF5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFCC3968CAFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40 +7FFFFFFFB80086FFFF900BFEFFFFFFFF554AFFFFFFFFFFFFFFFFFE003EFAFFFFAC13FFFF +FFD400EBFFA80096FFFF8019FFFF8D00B1FFFF6534FFFF7946FFFF5404E6FFFF2C6DFFF9 +1677FFFFC0006FFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFA9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFE0007FFFFFFDF4D0E000000199EFFFFFFFFFF84140000000642FFFFFF42 +00DBFFFFFFD22414B0FFFF8C170000000438FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7D7D7D7D7D7D7D7FFFFD9FE +FFD9D7D7D7D7D7D7D7FEFFD9FEFFD9D7D7D7D7D7D7D7FEFFD9FEFFD9D7D7D7D7D7D7D7FE +FFD9FEFFD9D7D7D7A31B09224B97EDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF407FFFFFFFB800E1FFFFD100E6FFFFFFFF554AFFFFFFFFFFFFFFFFFE008DFFFFFFAC13 +FFFFFFD400EBFFA804EDFFFFC100F5FF8D12FBFFFFA611FFFF7946FFFF5446FFFFFF6D4A +FFD500C6FFFFFD116FFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFE0007FFFFFFBE105B85986F13009EFFFFFF99001E6796895E20FFFF +FF4200DBFFFFBC1010BDFFFFA4001A64948B6119FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF7CB2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2727272727272727FFFF +2EF9FF2E27272727272727F9FF2EF9FF2E27272727272727F9FF2EF9FF2E272727272727 +27F9FF2EF9FF2E272727270E000002152ABDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF407FFFFFFFB807FFFFFFE000DFFFFFFFFF554AFFFFFFFFFFFFFFFFFE00BFFFFFFF +AC13FFFFFFD400EBFFA817FFFFFFD000EFFF8D32FFFFFFB50AFFFF7946FFFF546BFFFFFF +7C43FFC200ECFFFFFF356FFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7 +F3FFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFE0007FFFFFFF4F8FFFFFFFFDE0F1DFFFFFF4600C2FFFFFFFFFB +FFFFFF4200DBFFA1071DD2FFFFFF5000B6FFFFFFFFFBFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF94C2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF7B112E529AEDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF437DFFFFFFB807FFFFFFE000DFFFFFFFFF554AFFFFFFFFFFFFFFFFFE00C1FF +FFFFB606F6FFFFA400EBFFA817FFFFFFD000EFFF8D32FFFFFFB50AFFFF7946FFFF546BFF +FFFF7C43FFE100AFFFFFF3056FFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFA9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5CD2FFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFE0007FFFFFFFFFFFFFFFFFFFF4E00EDFFFF5600B9FFFFFF +FFFFFFFFFF4200DB83022DE4FFFFFFFF6100ADFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFC572CAFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF7554FFFFFFB807FFFFFFE000DFFFFFFFFF554AFFFFFFFFFFFFFFFFFE00 +C1FFFFFFDD00AFFFF44400EBFFA817FFFFFFD000EFFF8D32FFFFFFB50AFFFF7946FFFF54 +6BFFFFFF7C43FFFF3842DDF377016FFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF50FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0007FFFFFFFFDD69371E13130800C7FFFFB8000541 +91E2FFFFFFFFFF42004C0042F3FFFFFFFFFFC500033D8EDFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFC5181B2FEBB807FFFFFFE000DFFFFF2B1707071721FFFFFFFFFFFF +FE00C1FFFFFFFF5B013B0E6E00EBFFA817FFFFFFD000EFFF8D32FFFFFFB50AFFFF7946FF +FF546BFFFFFF7C43FFFFD524030F533B77FFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0007FFFFFFC307043B5E6E712F00BDFFFFFFAF +3F01000132C0FFFFFF42000C009FFFFFFFFFFFFFFFB5430200012EB9FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFD6BFF9EEC1FFFFFFF8BFF7FFFFC5BFBFBFBFC2FFFFFFFF +FFFFFFBFF0FFFFFFFFFEB69ED4F5BFFAFFEAC5FFFFFFF4BFFBFFE3CCFFFFFFEDC2FFFFDE +D1FFFFD5DAFFFFFFDFD0FFFFFFFDD4E6F40896FFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0007FFFFFF3102BEFFFFFFFF4C00BDFFFF +FFFFFFDB84300109D6FFFF4200B51A0399FFFFFFFFFFFFFFFFDE88330106CDFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7CB2FFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFDADEFFE17008E3FFFFFFFFFFFFFFFFFFFFFFFF0000FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF48CAFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0007FFFFFE081EFFFFFFFFFE1E00BD +FFFFFFFFFFFFFFFF520086FFFF4200DBDD1F028FFFFFFFFFFFFFFFFFFFFF5C007BFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94C2FFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB30A120117AEFFFFFFFFFFFFFFFFFFFFFFFFFF00 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF29FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFECFBFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0007FFFFFF1302D9FFFFFF9000 +00BDFFFFE6FFFFFFFFFF60008FFFFF4200DBFFE2240186FFFFFFE6FFFFFFFFFF6B0083FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAE2E8FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0007FFFFFF5B002A85A65D +072A00BDFFFF213E86AA9F64040FDDFFFF4200DBFFFFE82A007BFFFF2B3984A8A167070B +D5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0007FFFFFFEF470000 +0016AE6200BDFFFF5A0F0000000030BEFFFFFF4200DBFFFFFFEB2F0071FF621100000000 +2BB7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6E +B4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF93E3FFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +DDB8DEFFFFFFFFFFFFFFFFFED8B9BDDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED9BC +BADDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7CB2FFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85E0FFFFFFFFFFFFFFFF45EBFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94C2 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA +1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6FDFFFFFFFFFFFFFFFF45 +EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43C9FFFFFFFFFFFFFF +FF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF7CB2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF94C2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62 +D4FFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF44FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFB6EDFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7CB2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94C2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD364FFFFFFFFFFFFFFFFECB8A9CBFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAB +8CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFB6EDFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5E93FFFFFFB807FFFFFFFFFFFFFF88031622003CF2FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF7D4CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF67D5FFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF407FFFFFFFB807FFFFFFFFFFFFFFADCBFFFFCD0574 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF56FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7CB2FFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8D162B5757EFB807E3623566EAFFFFFFFFFFFFFF +4B46FFFFFFFFFFFFFE57D07A3CA1C964FFFFFFE357F2FFC667DB5E356CF0FFFFB479CD58 +3779F7FFFFA786FFFF8F9EAD4A3E98FFFFFFFD8A3C4FB587A1FFFFFFFFFFFFFFFFFFFFFF +FF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EB4FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94C2FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCCD2FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC92C57AFAFF8B803367A99244DFFFFFFFFFF +FFFC276DFFFFFFFFFFFFFE002751A8CCAC13FFFFFFD400EBFFA80B3381941E5DFFFF8D16 +318C891478FFFF7946FFFF54233A9E7204B1FFFF710E789A2B196FFFFFFFFFFFFFFFFFFF +FFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6E +B4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF83625519FF2FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF407FFFFFFFB800A1FFFFA203FAFFFF +FFFFFF7C11E6FFFFFFFFFFFFFE0057FFFFFFAC13FFFFFFD400EBFFA800B1FFFF920EFFFF +8D00CDFFFF7629FFFF7946FFFF540EF8FFFF3D62FFF20793FFFFDC006FFFFFFFFFFFFFFF +FFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3EC6FFFFFFFFFFFFFFFF45EBFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF6F6F6F6F6F6F6F6F6F6F6F6FFB746F6F6F6F6F6F6F6F6F6F6FFB +746F6F6F6F6F6F6F6F6F6F6FFB746F6F6F6F6F6F6F6F6F6F6FFB746F6F6F6C1E00000D1B +69D2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF407FFFFFFFB802F0FFFFDB00E1 +FFFFFFFF9907BAFFFFFFFFFFFFFFFE009FFFFFFFAC13FFFFFFD400EBFFA80AF8FFFFCA00 +F1FF8D1FFFFFFFAF0DFFFF7946FFFF5457FFFFFF7646FFCD00D7FFFFFF206FFFFFFFFFFF +FFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF8F8F8F8F8F8F8F8F8F8F8F8FFC938F8F8F8F8F8F8F8F8F8F +8FFC938F8F8F8F8F8F8F8F8F8F8FFC938F8F8F8F8F8F8F8F8F8F8FFC938F8F8F871E0006 +172A8EEAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF407FFFFFFFB807FFFFFFE0 +00DFFFFFFFA106ACFFFFFFFFFFFFFFFFFE00C1FFFFFFAC13FFFFFFD000EBFFA817FFFFFF +D000EFFF8D32FFFFFFB50AFFFF7946FFFF546BFFFFFF7C43FFC700E2FFFFFF2C6FFFFFFF +FFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45EBFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF6EB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +7CB2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF12A35 +66C3FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4A77FFFFFFB807FFFF +FFE000DFFFFFA806A7FFFFFFFFFFFFFFFFFFFE00C1FFFFFFBE01EBFFFF8E00EBFFA817FF +FFFFD000EFFF8D32FFFFFFB50AFFFF7946FFFF546BFFFFFF7C43FFEC029EFFFFE7006FFF +FFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45D9EB +EBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEB +EBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEB +EBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEB +EBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEB +EBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBEB +EBEBEBEBEBEBEB66B4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF94C2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA +1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD5 +E9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8639DBEFFEB807 +FFFFFFE000DFFFB1047AD7D7D7DEFFFFFFFFFFFFFE00C1FFFFFFEB077CF6C12C00EBFFA8 +17FFFFFFD000EFFF8D32FFFFFFB50AFFFF7946FFFF546BFFFFFF7C43FFFF5821A0C2440E +6FFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85E0FFFFFFFFFFFFFFFF73 +3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E +3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E +3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E +3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E +3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E +3E3E3E3E3E3E3E3E3E3DCCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDD581600E7 +B807FFFFFFE000DFFF5D00000000002AFFFFFFFFFFFFFE00C1FFFFFFFF920305179F00EB +FFA817FFFFFFD000EFFF8D32FFFFFFB50AFFFF7946FFFF546BFFFFFF7C43FFFFF3621427 +92347DFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF93E3FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2DEFEFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFE701A2FFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +C29ED2A23D19F5FFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF7CB2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFCB44222857DDFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2FAFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF94C2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFD0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D +CCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF39FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61B1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFECF6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0A2BFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7CB2FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5CD2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC0006F4FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94C2FFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF39FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFAD7FBFFFFFF445DFFFFFFFFFFFFFFF8B67762C6FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFC7F3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF57000086FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFBF00D8FFFFFF334DFFFFFFFFFFFFFF51000D0090FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1400002DFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +5EF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFBF00D8FFFFFF334DFFFAF4FFFFFFFFCADBDF0090FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9000000 +01CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDB0B000C0D40FF334B4907033BF3FFFFFFFFDF0090 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8EAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4B00 +0000005DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77AEFFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8FFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDAD00C2E3EDFF330651CA8D0675FFFFFFFFDF +0090FFFFFFFFFFFFFFFFC7464646464646464688FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF73DAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA +0D0000000013FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9AC6FFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF00D8FFFFFF3313FFFFFF2F3EFFFFFF +FFDF0090FFFFFFFFFFFFFFFFCC535353535353535391FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF970000000000009CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF00D8FFFFFF3346FFFFFF522EFF +FFFFFFDF0090FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF3F0000000000003CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF00D8FFFFFF334DFFFFFF53 +2EFFFFFFFFDF0090FFFFFFFFFFFFFFFFB51C1C1C1C1C1C1C1C68FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFF1082C664239723D07E3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA +1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDD01C0FFFFFF334DFFFF +FF532EFFFFFFFFDF0090FFFFFFFFFFFFFFFFDD8383838383838383B4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3EC6FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFBFA3FFFF684FFFFFCAC6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF77AEFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFEDEAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E5FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1C3C87ACFF334D +FFFFFF532EFFFFC77267004872A9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF6D4BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF9AC6FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFCA7EDFFFFFF6C53FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFB9D8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF902FFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2582B58FF +576FFFFFFF7452FFFFA1272727272771FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF7147FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFF400CBFFFFFF6C53FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF338CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF902FFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7544FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFDD2B5E1FFFFFFCF00ABD7E0FF6C53FDD0BAF1FFFFFFFFFFD9B3D3FFFFFFFDD7F8 +EEB9E0FFFFFFFFE22B76D7D7FEFFF2BFB1D3FFFFFFFFFFF6BBB6E0FFFF902FFFFFFFEBD7 +FBFFFFD6AFC7FBFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF79DBFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7A41FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFE43902250067FDFF3100262F59FF6C48431B0B18D9FFFFEF4C022F034DF6FFEF +008106299DFFFFFFFF66091A2F2FF6D30C3031014BFAFFFF850F33370BD7FF902FFFFFC1 +128BFFDE1D1E3F1F68FFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0 +E8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E3DFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF77AEFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFC558A7F5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF5927D5FFB203A0FFF400CBFFFFFF6C009AFCF02D66FFFF652FE5FFE11F80 +FFEF002FD7FFFFFFFFFFFFFF338CFFFFFFEFE9FFFFDE0C9BFFEF0CC8FFFFF3F6FF902FFF +A90EA7FFFF6A59FFFFFFEAFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF97FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF833AFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9AC6FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF96111F4074D8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFD067FFFFFFF3848FFF400CBFFFFFF6C1AFEFFFF7838FFFB05A0FFFFFF +7B35FFEF008AFFFFFFFFFFFFFFFF338CFFFFFFFFFDCEAFA73B63FFF50E84EFFFFFFFFF90 +2F8D11BFFFFFFF7235CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8836FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF07070707 +070707070707070707070707070707070707070707070707070707070707070707070707 +0707070707070707070707070707070707030000000021BDFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFE500BFFFFFFF7826FFF400CBFFFFFF6C51FFFFFF942BFFDC000607 +07070720FFEF00C8FFFFFFFFFFFFFFFF338CFFFFFFDD24113B57274DFFFFAA2A0549B7FF +FF900B0099FFFFFFFFE45B052187EDFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4FDFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFD8F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8D33FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F7 +F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7 +F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7A71519375FB6FBFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFF6019AFFFFFF533BFFF400CBFFFFFF6C53FFFFFF942BFFEE00 +A9FFFFFFFFFFFFEF00D0FFFFFFFFFFFFFFFF338CFFFFFF622EFEFFFF434CFFFFFFFFCF77 +02C2FF902F960BBAFFFFFFFFFFED9F2A53FFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58F8FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFEA7AECFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFB591FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDAE7BD8 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD8AFFFFA8A1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC28AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8CD521B6FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF51CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9130FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC64889E4FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF2F4EFFFFF61076FFFF19AFFFFFFF6C53FFFFFF942BFF +FF2E45FFFFFFFFFDFFEF00D0FFFFFFFFFFFFFFFF5770FFFFFF565FFFFFE8034CFFFDFFFF +FFFF2A86FF902FFFA00AB3FFFFFDFFFFFF9919FFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66FAFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF7F78FFFFFFC900CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C21FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD171A +39BDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C17FFFF443BFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7417FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB90BEF1CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF972DFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77AEFFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBA07347E191DEBFFFF5D23678CFF6C53FFFFFF94 +2BFFFFCA112B808D5B6EFFEF00D0FFFFFFFFFFFFFFFF9B125E6FF9B508717C1B334CFFBA +38859B640EECFF902FFFFFA80AABFF3C6C9983208CFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF453AFFFFFFC900CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C21FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6 +08F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C17FFFF443BFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7417FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A55FF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C2AFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9AC6FFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD1755B83EEFFFFFFFAC48999FFB6A9FFFF +FFCA95FFFFFFE7825C5F88DEFFF77FE8FFFFFFFFFFFFFFFFFFD4937FFAFEC36D74C7B9A6 +FFEE97675D9BE1FFFFC897FFFFFFBA83F1BA77597DC2FCFFFFFFFFFFFFFFFFFFFFFFFFFF +FF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1FFFFEA77516BDBFFFFFFFFBD684D6BCDFFFFFA815269CAFFFFFF91ACBC656FFFFF97 +595AA8FFFFFFFFFFFFFFFFFFAA25207272D5C900CD8C5273F4FFFFD772F48151CCFFD770 +5073EDFFFFFFA9614C66CAFFFFFFFFCD635DB45C21FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +9E3B0D7279FFFFDB715071E8FFFFFFFFAA605595FFFFFFFFD5675AAC6C17FFFF443BC766 +5AB5FFFFFFDA7851568EFFFFFFFFFFAE634E72DAFF7417FFFFFF9E79F6FFFFFFFFFFFFFF +D075F37F50D2A39AFFFFFFB887FFFFA09CCF6957ADFFFFFFC503D4FF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA126 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFCA15154B1A0DC5FFFF710319543755FFF423044115079AFFFF2B290B3A60FF +41063C35036DFFFFFFFFFFFFFFFF8F1A174C4CC6C900331A410730FFFFA300321A48BBAA +0B1C4C1217E3FFF41247541F06B1FFFFB90B12450B2821FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF80290A4C55FFB20E1A4C1314DDFFFF5E04323F054CFFFFC70F0E460B2A17FFFF441F +0E3D1D0495FFFF4D3357380746FFFFFF59012056306DFF7417FFFF6B0A9CFFFFFFFFFFFF +FFFF99022E1C47C34639FFFFFF6B1CFFFF4322133B2302A3FFFF7413FFFFF4FDFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +A824FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2EFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF58F8FF3327FFFFFF2A36FFCC0460FFFFFFFDFF6E02C7FFF83318FFFF2B04DAFF +FF8C01C7FFFF7C05DDFFFFFFFFFFFFFFFF453AFFFFFFC90041FFFF9400D0FFA30051FFFF +FD1B42FFFFFA1355FFFFFBFFFFFF2D38FFFF3426F6FFDB0521FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF7218FFFFFF203AFFFFFB194CFFB6019AFFFFA801B5FF411DF1FFE50B17FFFF +4400B0FFFD4117FDFFFBFFFFFF9501D2FFAD017CFFFFFFFDFF7417FD4F10B8FFFFFFFFFF +FFFFFFFF990058FFFFFF4639FFFFFF6B1CFFFF4300C2FFFF253DFFFF4A2CFFFF21B6FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFAD21FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDBFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF66FAFB04539F9F9F4D11FF7C01D2FFFFFFFFFF3622FFFFFF7E00D5FF2B2C +FFFFFF431D9F9F9F91019EFFFFFFFFFFFFFFFF453AFFFFFFC9009BFFFFEC01A0FFA300AC +FFFFCD006D9F9F9F3629FFFFDF735046261AFFFF0A64FFFFFF2A21FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF7218FFFFDB00669F9F9F3C22FF640C9F9F9F9F0B75FF1354FFFFFF3617 +FFFF4410FFFFFF8D00CFFFFD975C4746029AFF6006F1FFFFFFFFFF7413381AD0FFFFFFFF +FFFFFFFFFFFF9900B6FFFFFF4639FFFFFF6B1CFFFF4320FFFFFF5923FFFF2947FFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFB21EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77AE +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1DA00212D2D2D2D32FF6311FFFFFFFFFFFF2646FFFFFFB900B0FF +2B54FFFFFF2E102D2D2D2D2DA1FFFFFFFFFFFFFFFF453AFFFFFFC900CDFFFFFF0397FFA3 +00F8FFFFA600282D2D2D2D46FFC70926506F3C12FFF40094FFFFFF4D21FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF7218FFFFB200262D2D2D2D41FF4A0A2D2D2D2D2D83FF0680FFFFFF +5B17FFFF442EFFFFFFC700ADFF3E0E4165720489FF4923FFFFFFFFFFFF74090956FFFFFF +FFFFFFFFFFFFFFFF9902FFFFFFFF4639FFFFFF6B1CFFFF433CFFFFFF671FFFFF323FFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFB91BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +9AC6FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1FD055DFFFFFFFFFFFF8300C6FFFFFFFFFF3A1CFFFFFF7500 +DDFF2B56FFFFFF4515FDFFFFFFFFFFFFFFFFFFFFFFFFFF4639FFFFFFC900CDFFFFFF0397 +FFA300FBFFFFCF0081FFFFFFFFFFFF5E14F8FFFF3D12FFFF0C5BFFFFFF2421FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF7218FFFFDF0078FFFFFFFFFFFF6506E8FFFFFFFFFFFF174DFF +FFFF3017FFFF440CFDFFFF8400D5E80189FFFFB10089FF6503E7FFFFFFFFFF7417B40B56 +FFFFFFFFFFFFFFFFFFFF9903FFFFFFFF4F28FFFFFF401CFFFF433CFFFFFF671FFFFF5624 +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF99E5FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFBF18FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA +1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FF3F12D2FFFFFDC7FFDD094BEDFFFFE7FF8001A3FFE2 +2824FFFF2B56FFFFFF9C0081FDFFFFC9FBFFFFFFFFFFFFFFFF761CFFFFFFC900CDFFFFFF +0397FFA300FBFFFFFF2424E0FFFFF6CCFF7412FAFFC60812FFFF401EDFFFBB0321FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF7218FFFFFF2B1FDDFFFFFACAFFC30460F8FFFFDAE8FF4D +17D8FFC60717FFFF44008FFFEF3320FFF10A86FFF4410089FFC20360F6FFFFE7FF7417FF +BC0E4EFFFFFFFFFFFFFFFFFF9903FFFFFFFF7504DFFFD0091CFFFF433CFFFFFF671FFFFF +810EFFFFF4FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF79DBFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFC516FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF58F8FFE02A012533133EFFFF8A0909351F4FFFFD3B00 +240811B5FFFF2B56FFFFFFFF640311372304F6FFFFFFFFFFFFFFFFCD130B1CB1C900CDFF +FFFF0397FFA300FBFFFFFFC71C032B300E5DFFE80F142E094112FFFFCD17072C0B3621FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7218FFFFFFCD20022A300F55FFFF81080B362804C2 +FFDA1C052D093A17FFFF442915250E0BACFFFF5706300E3F0989FFFF74040D361969FF74 +17FFFFC51146FDFFFFFFFFFFFFFF9903FFFFFFFFEA1506250C3E1CFFFF433CFFFFFF671F +FFFFE509B1FF21B6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFCC13FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66FAFFFFFFA87979A5FBFFFFFFDA8C7396F1FFFF +FFAA778FE5FFFFFFB6C9FFFFFFFFFFCC87728DE3FFFFFFFFFFFFFFFFFFFFFFC99FE5F19F +F3FFFFFFA1E2FFE59FFFFFFFFFFFF89E757CB2FFFFFFFA9986D4D8A9FFFFFFEA8D84D5CC +B1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4ADFFFFFFFFFAA0767BAEFDFFFFFFD88E7286 +D7FFFFFFEF9180CFD2ACFFFFC2BDE38D83DAFFFFFFFFCC7BA9FDA5DDFFFFFFCF86759FF8 +FFD5ACFFFFFFD79FE5FFFFFFFFFFFFFFE2A1FFFFFFFFFFE78483D5D2AEFFFFC2BDFFFFFF +D0B0FFFFFF573DFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFD210FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF77AEFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFDD0AD21CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD80EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF9AC6FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86A6A6A6A6A6A6AD8FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFF16A6A6A6A6A6A665F6A6A6A6A6A6ADDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF906A6A6A6A6A6AA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFE0F31CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3EC6FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE00BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF29FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44C4C4C4C4C4C4CCFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFED4C4C4C4C4C4C49434C4C4C4C4C4CD4FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF784C4C4C4C4C4C8AFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFF4FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE709FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58F8FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21B6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED06FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66FAFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF603FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77AEFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF6DD8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD01FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9AC6FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF50FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2EAFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF792E13B1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF425FFFFFFFFFFFFFFFFFFFFFFFFFFFFD6262626262 +62B1FFE262D2FFFB626AFDFFFFFF8F87FFFFFFFFFB6583FFFFFFFFFFFFFFFFFFFFFFFF68 +626262626CFFFFFF9062EAFFFFFFFF967DFFFFFFFFFFFFFF9A56455688E8FFFF6E626262 +6262A0FFD51AE8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFB0ECFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02FDFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E53FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD50286BFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3050FFFFFFFFFFFFFFFFFFFFFFFFFFFA001C2D +2D2D2D8FFFC200A8FFF8000085FFFFFF3C30FFFFFFFF960005E7FFFFFFFFFFFFFFFFFFFF +FF06182D2D2D39FFFFFA0E0078FFFFFFFF4622FFFFFFFFFFFF4A052E57410F88FFFF0E17 +2D2D2D2D79FFFF3062FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4FDFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F4FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58F8 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFDFFFFFFFFFFFFFFFFFFFFFFFFFF2E53FFFF +FFFFFFFFFFFFFFFFFFFFFFEDFDFFFFFFFF7918FFFFFFFFFFFFFFFFFFFFFFFFFFF4FAFFFF +FFFFFFFFFBF1FFFFFFFFFFFFFFEDFFFFFFFFFF3050FFFFFFFFFFFFFFFFFFFFFFFFFFFA00 +7EFFFFFFFFFFFFC200A8FFF8001817F8FFFF3C30FFFFFFFF39380E74FFFFFFFFFFFFFFFF +FFFFFF0670FFFFFFFFFFFF91064524FFFFFFFF4622FFFFFFFFFFD70067FFFFFFFAE8FFFF +0E62FFFFFFFFFFFFFF9A0CEDFFFFFFFFFFFFFFFFFFFFFFFFFFFF21B6FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF06EDFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +66FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA01C01073EE3FFFF3763FFFFFF5543FF460306 +0D0DCFFFFFFFFFFFFFFFFF9919010743E8FF4707020D1AFFFFFFFFFFFFFFFF345F3A0506 +4DFAFFFFDB37060220ADFFFFFF8F17010949EDFFFF3050FFFFFFFFFFFFFFFFFFFFFFFFFF +FA007EFFFFFFFFFFFFC200A8FFF800770A75FFFF3C30FFFFFFE204965122FFFFFFFFFFFF +FFFFFFFFFF0670FFFFFFFFFFFF363CB900C0FFFFFF4622FFFFFFFFFFC90094FFFFFFFFFF +FFFF0E62FFFFFFFFFFFFFFFF0C7FFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFC7F3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09 +E7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77AEFFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFCF043AC5871336FFFF2A58FFFFFF4936FFED +2A4DE3E3FBFFFFFFFFFFFFFFC5033EC981113DFFED631AE3E7FFFFFFFFFFFFFFFF270451 +D2760B65FFFF2A1891BD3208DFFFB60145CD7B0E48FFFF3050FFFF764646464646464646 +E0FFFA005195959595E3FFC200A8FFF800886410F1FF3C30FFFFFF6F0FFBBB00BCFFFFFF +FFFFFFFFFFFFFF0649959595C7FFDF0397FF1E53FFFFFF4622FFFFFFFFFFFF241364BBFF +FFFFFFFF0E4195959595D7FFFFFF2653FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5CD2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF0BE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9AC6FFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF5904EFFFFF7100D4FF2A58FFFFFF4936 +FFFF2E53FFFFFFFFFFFFFFFFFFFF5108F8FFFF6701E0FF6C1CFFFFFFFFFFFFFFFFFFFF27 +13FFFFFF4712FFBF0081FFFFDF0168FF460DFDFFFF5A03F1FF3050FFFF81535353535353 +5353E3FFFA000B12121212AEFFC200A8FFF80088EF0F66FF3C30FFFFFF1F52FFFF1E50FF +FFFFFFFFFFFFFFFFFF060A1212126FFF6C10FBFF6B0EFAFFFF4622FFFFFFFFFFFFCD4F09 +001A79F6FFFF0E09121212128FFFFFFF4331FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE3A18AC2FDFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF0ED8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF3B2BFFFFFFC6009CFF2A58FFFFFF +4936FFFF2E53FFFFFFFFFFFFFFFFFFFF3333FFFFFFB800A9FF6C1CFFFFFFFFFFFFFFFFFF +FF2742FFFFFF8601EF8F01DDFFFFFF2043FF2A3DFFFFFFA600BBFF3050FFFFFFFFFFFFFF +FFFFFFFFFFFFFA007EFFFFFFFFFFFFC200A8FFF80088FF740AE53C30FFFFB800B1F1F166 +0DF8FFFFFFFFFFFFFFFFFF0670FFFFFFFFFF1D4FF1F1CF0290FFFF4622FFFFFFFFFFFFFF +FFF1A13A0173FFFF0E62FFFFFFFFFFFFFFFF5720FFFFFFFFFFFFFFFFFFFFFFFFFFFFF4FD +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD670313220525CD +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF11D2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF58F8FFFFFFFFFFFFFFFFFFFFFFFFFFFF3E25FFFFFFB900A3FF2B54FF +FFFF3E36FFFF2E53FFFFFFFFFFFFFFFFFFFF362CFFFFFFAC00B0FF6C1CFFFFFFFFFFFFFF +FFFFFF273CFFFFFF7D01F49500D0FFFFFF1A47FF2D36FFFFFF9B00C2FF3050FFFF531C1C +1C1C1C1C1C1CD5FFFA007EFFFFFFFFFFFFC200A8FFF80088FFF816583C30FFFF4E000000 +0000008CFFFFFFFFFFFFFFFFFF0670FFFFFFFFB400000000000035FFFF4622FFFFFFFFFF +FFFFFFFFFFFF2B25FFFF0E62FFFFFFFFFFFFFFFF3A3BFFFFFFFFFFFFFFFFFFFFFFFFFFFF +21B6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61068DFFFFE2 +2913F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF13CCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF66FAFFFFFFFFFFFFFFFFFFFFFFFFFFFF6302E7FFFF6802DFFF3E +2BFFFFFA0C36FFFF3D46FFFFFFFFFFFFFFFFFFFF5905F1FFFF5E04EAFF6C1CFFFFFFFFFF +FFFFFFFFFF270EFFFFFF4017FFCC0178FFFFD40073FF4E09FAFFFF5207F8FF3050FFFFA8 +8383838383838383EDFFFA007EFFFFFFFFFFFFC200A8FFF80088FFFF85062B30FFF60C5A +CACACACA3032FFFFFFFFFFFFFFFFFF0670FFFFFFFF4B1BCACACACA7803DBFF4622FFFFFF +FFFFF8FFFFFFFFFF2A1CFFFF0E62FFFFFFFFFFFFFFFF1F5EFFFFFFFFFFFFFFFFFFFFFFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF48CAFFFFFFFFFFFFD80656FFFF +FFFFD80560FFEC39CDFFFFFF45A9FFFFFA682C2251E8FFFF7D66FFFFFF9B4EFFFFFFBD3F +203296FFFFFFFFFFFF16C5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF77AEFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA +1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF29FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFE20A2493620B48FF +FF7F046595350E36FFFF7A12758CEDFFFFFFFFFFFFFFDA0828965D0951FFFF6C1CFFFFFF +FFFFFFFFFFFFFF270B37A6570678FFFF3B0E6A8D1F10EFFFCD052D9A58075CFFFF3050FF +FFFFFFFFFFFFFFFFFFFFFFFFFA004172727272A8FFC200A8FFF80088FFFFFD1E0030FF8C +01D4FFFFFFFF8702D7FFFFFFFFFFFFFFFF0670FFFFFFF40B64FFFFFFFFF30969FF461372 +7272728FAE1C6D9C8F4D0064FFFF0E33727272729AFFFFF30799FFFFFFFFFFFFFFFFFFFF +FFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFECFBFFFFFFFFFFFF8F00C2 +FFFFFFFFFF332BFFE200B6FFFFFF0D85FFFF3517677C1F21FBFF4D33FFFFFF7317FFFFAE +063D894D068CFFFFFFFFFF19BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF9AC6FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC533121C5B +F8FFFFFB57141C6B6B5AFFFFE8753927D7FFFFFFFFFFFFFFFFBF30111D61FBFFFF8941FF +FFFFFFFFFFFFFFFFFF275955181C71FFFFFFF3531A1337CFFFFFFFB52E101E69FDFFFF55 +71FFFFFFFFFFFFFFFFFFFFFFFFFFFB27272727272771FFD027BBFFFA27A1FFFFFF9E2755 +FF5E47FFFFFFFFFFF12B8DFFFFFFFFFFFFFFFF2E8CFFFFFFAD27D0FFFFFFFFFF5E48FF68 +27272727274DE2592511112677FDFFFF3527272727275CFFFF791CFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF69 +01F4FFFFFFFFFF4E12FFE200B6FFFFFF0D85FF9E00B5FFFFD20191FF4D33FFFFFF7317FF +FF2931FFFFFF471EFFFFFFFFFF1CB9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF275BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1C86FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFF4FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF7000ECFFFFFFFFFF4912FFE200B6FFFFFF0D85FF610A5A5A5A5A0C65FF4D33FFFFFF73 +17FFFD06335A5A5A3904FDFFFFFFFF1EB2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF275BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD74FFBFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF21B6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF93E3FFFFFF +FFFFFF9900B2FFFFFFFFFF2B26FFE200B6FFFFFF0A85FF520D6262626262A3FF4D33FFFF +FF6F17FFF3013A6262626262FBFFFFFFFF22ADFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF71FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66FAFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF410909090909094EFFFFFFFFFFFF +FFFFFFFFFFFFC209090909090909DB5C88FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C09090909090929FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85E0FF +FFFFFFFFFFEC0F42FFFFFFFFBF0176FFF80287FFFFB50085FF7701C7FFFFFFFFFFFF5D18 +FFFFFF3617FFFF123CFFFFFFFFFFFFFFFFFFFF24A8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF77AEFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF83025BE0F8A81523F8FFFF202ED8C3340285FFEA1233B1FFFA8FD2FF +95008DF3860817FFFF70047CE5FFD28CFFFFFFFFFF27A3FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF9AC6FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF99160103003DE2FFFFFFA50B0205730D85FFFFBF24000B0217 +C9FFFF3D00031F5E17FFFFFD660604090556FFFFFFFFFF2B9CFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5B71E0FFFFFFFFFFFFFFFFFFFFFFFFF4FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFF6FDFFFFFFFFFFFFFFFFFFFFE7B41C27F1FFFFFFFFF4C6F4FFFFFFFFFFFFFFE7BF +DAFFFFFFFFFFDBD4FFFFFFFFFFFFFFFBCAC7F1FFFFFFFFFFFF2E97FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFE7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58F8FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFA90003358DF6FFFFFFFFFFFFFFFFFF21B6FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF43C9FFFFFFFFFFFFFFFFFFFFFFFFD52659FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3093FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA1AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF2EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66FAFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1A0000000B49ACFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF348DFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77AEFFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA00000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF38000000000000175FCCFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3788FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9AC6FFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1 +FFFF7A000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000016BFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A84FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF37000000000000226FDFFFFFFFFFF4FDFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFDDD7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7 +D7D7D7D7D7D7D7D7D7D7D7D7D75AB6D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7 +D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D737 +7EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF58F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF180000001257C0FFFFFFFFFFFFFF21B6FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF250D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D +0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0B0C0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D +0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D +0D0D85FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBCFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF66FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3000841A0FDFFFFFFFFFFFFFFFFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77AEFFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6381EFFFFFFFFFFFFFFFFFFFFFFFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9AC6 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB6EDFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFF4FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67D5FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF56FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF58F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF21B6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF66FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF77AEFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF9AC6FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3EC6FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF24FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFF4FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6FDFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58F8FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF21B6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66FAFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77AEFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF85E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9AC6FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF63FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF93E3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4FDFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58F8FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDAE2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21B6FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66FA +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFE883F1FFFFFF334DFFFFFFFFFFFFFF7C361A204BD8FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFE2FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77AEFFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFBF00D8FFFFFF334DFFFFFFFFFFFFFF0D4F81611319EF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF4DCCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9AC6FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF39FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9400A4BFD2FF334DF8AC9EEFFFFFFFEDFFFFFF97 +009BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDF18001A1C4EFF333C1D130315DBFFFFFFFFFF +FFCF0099FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4FDFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF58F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF00D8FFFFFF330091FDDA0D5EFFFFFF +FFFFFF5010EAFFFFFFFFFFFFB2171717171717171763FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21B6 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF66FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF00D8FFFFFF3320FFFFFF3C37FF +FFFFFFFF840297FFFFFFFFFFFFFFE39595959595959595C0FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5CD2FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +77AEFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF39FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF00D8FFFFFF334BFFFFFF53 +2EFFFFFFFF8E037AFFFFFFFFFFFFFFFFFAE3E3E3E3E3E3E3E3F1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7F3FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF9AC6FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF00D8FFFFFF334DFFFF +FF532EFFFFFF950471FFFFFFFFFFFFFFFFFFA600000000000000004FFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED03B0FFFFFF334D +FFFFFF532EFFFF9C056BFFFFFFFFFFFFFFFFFFFFF6D7D7D7D7D7D7D7D7E8FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFF4FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF281B4978FF +334DFFFFFF532EFFF1060B3939393997FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF21B6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8EAFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF19B60 +84FF8396FFFFFF9A7FFFF65A5A5A5A5A5AACFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF73DAFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF77AEFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF63FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF9AC6FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58F8FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21B6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF3EC6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF24FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66FAFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77AEFFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9AC6FFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFDB3FE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8D5DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC266 +40C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9954FFFF7A73FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9F54FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4EC91CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5950FFFFFFC900CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C21FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1 +064672D5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C17FFFF443BFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7417FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9317FDF4FDFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF79DBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +58F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF453AFFFFFFC900CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C21FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF8F0EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C17FFFF443BFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7417FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2371FF21B6FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFA0E8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF66FAFFFFB43D2033A0FFFFFFFD76311D339EFFFFD045213287FFFFFF60847C2F44FF +EC55262763F8FFFFFFFFFFFFFFFF8015123939BFC900B94C213AC6FFFFBF39D04520B6FF +9A371F3AB9FFFFFD622C1C3087FFFFFFFF902E29725C21FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF7120073941FFFFA0381F38B4FFFFFFF8642B2353ECFFFFFF9B3027686B17FFFF443B +8C302772FFFFFFA53D20244EE2FFFFFFF8682E1E39B1FF7417FFFFFB5B52F6FFFFFFFFFF +FFFFB83CCD431FC0776CFFFFFF9453FFFF756E94322469FBFFFFA604EDFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77AEFFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF04F1FFA006418A48059BFFFF400747967077FFDA0A1A7C40026CFFFF2B152074 +91F41B22766D143FFFFFFFFFFFFFFFFFBB2C268C8CDFC9001D497C2018FDFFA3001E4886 +D07C094C8C3C05C2FFF63D8596500487FFFF90023A81221221FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFB146108C93FF85074A8C3F04B8FFFF2F18697A1D25FDFFA1033483281317FFFF +441118774B0467FFFF6E6B9A711D24FFFFFF2B0B51996789FF7417FFF1351CD4FFFFFFFF +FFFFFFFF99011D4B85D74639FFFFFF6B1CFFFF4313207555047CFFFF6919FFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9AC6FFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FF1F3CFFFFFF3D26FFB00085FFFFFFFFFF5606F3FFFF4B0AFAFF2B0B +FBFFFF6D06E5FFFF9900CAFFFFFFFFFFFFFFFF453AFFFFFFC90058FFFFA900C0FFA3006E +FFFFF60C5AFFFFFF2242FFFFFFFFFFFF432DFFFF2339FFFFFD0B21FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF7218FFFFFD0F52FFFFFF283BFF9500BDFFFFC9009AFF2E2DFFFFFF1417 +FFFF4401DAFFFF590AF4FFFFFFFFFFB900BFFF8D00A8FFFFFFFFFF7417E0242BE8FFFFFF +FFFFFFFFFFFF990076FFFFFF4639FFFFFF6B1CFFFF4303E3FFFF3234FFFF4133FFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBCFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1F402385A5A5A330CFF7304E8FFFFFFFFFF302FFFFFFF9300C6FF +2B3AFFFFFF3C175A5A5A590194FFFFFFFFFFFFFFFF453AFFFFFFC900B1FFFFFA029BFFA3 +00C5FFFFBF00465A5A5A2623FFFF993A1F170E16FFFF0574FFFFFF3621FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF7218FFFFCD00425A5A5A291DFF5A0B5A5A5A5A0A6CFF0E64FFFFFF +4317FFFF441AFFFFFFA000C2FFD8552918170191FF570EFDFFFFFFFFFF740D173DF6FFFF +FFFFFFFFFFFFFFFF9900D0FFFFFF4639FFFFFF6B1CFFFF432DFFFFFF6220FFFF254BFFFF +F4FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51CDFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF58F8DF00406262626266FF660DFDFFFFFFFFFF2941FFFFFFB000 +B4FF2B56FFFFFF301C6262626262BFFFFFFFFFFFFFFFFF453AFFFFFFC900CDFFFFFF0397 +FFA300FBFFFFA900506262626277FFA3015690BB5712FFF6018CFFFFFF4821FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF7218FFFFB6004B6262626273FF4C0F6262626262A8FF077AFF +FFFF5617FFFF442AFFFFFFBF00B2FF20227CADB80489FF4C1EFFFFFFFFFFFF740F1D2FF1 +FFFFFFFFFFFFFFFFFFFF9903FFFFFFFF4639FFFFFF671CFFFF433CFFFFFF671FFFFF3A38 +FFFF21B6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF66FAFF0A47FFFFFFFFFFFF8F00AAFFFFFFFFFF4212FFFFFF +6301ECFF2B56FFFFFF4D0AF3FFFFFFFFFFFFFFFFFFFFFFFFFF4C35FFFFFFC900CDFFFFFF +0397FFA300FBFFFFDF0068FFFFFFFFFFFF571EFFFFFF2D12FFFF134DFFFFFF1921FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF7218FFFFEC015FFFFFFFFFFFFF7001CFFFFFFFFFFFFF1D +40FFFFFF2417FFFF4406F4FFFF7201E3DD00A3FFFF950089FF7001D0FFFFFFFFFF7417E3 +2229ECFFFFFFFFFFFFFFFFFF9903FFFFFFFF561DFFFFFF301CFFFF433CFFFFFF671FFFFF +601FFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF77AEFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FF620881EAFFCC90FFF6172AA6FFE5B2FFA9005E +E89B153DFFFF2B56FFFFFFC6064BC6FFEF7BFAFFFFFFFFFFFFFFFF8812BBE3FAC900CDFF +FFFF0397FFA300FBFFFFFF42138FF4FFB9A0FF8F07C9F47A0412FFFF5A1097F4720221FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7218FFFFFF4A108CF1FFBD9BFFE50F36B5FFF88CD7 +FF6A0B8EF87B0417FFFF440253E7B21D36FFFD1559FAB6260189FFE30B36B5FFD8BCFF74 +17FFE82625E7FFFFFFFFFFFFFFFF9903FFFFFFFF8A0195F181061CFFFF433CFFFFFF671F +FFFF9109FBFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF9AC6FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4CAE2FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFF33374FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7433F3FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFA5D0504090660FFFFC023000A0468FFFF +7507040031DFFFFF2B56FFFFFFFFA017000C0220F8FFFFFFFFFFFFFFFFE5411200A1C900 +CDFFFFFF0397FFA300FBFFFFFFEC480207060A7EFFFA3905091E6212FFFFED3B0107234D +21FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7218FFFFFFEF4D0306070976FFFFB921000B02 +18D0FFF44401071C5617FFFF443636070026D8FFFF85140906770A89FFFFAD1A000B0681 +FF7417FFFFED2B20E2FFFFFFFFFFFFFF9903FFFFFFFFFB37000322591CFFFF433CFFFFFF +671FFFFFF8148EFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51CDFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2004EFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFEC0049FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4800EDFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD43F8EFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF33FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFAC9C9F4FFFFFFFFFFE2C0ECFF +FFFFFFFAC6E7FFFFFFFFFFFFFFFFFFFFFFFFDDBFE3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C3CDF8FFFFFFFFE8DBFFFFFFFFFFFFFFE3D8 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8C5CCF8FFFFFFFFFFE5 +BFDBFFFFFFFFFFE7D4FFFFFFFFFFFFFFFFE3D7FFFFFFFFFFFFCCFAFFFFFFFFFFFFFFDBC3 +F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8D7FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF7527FFF4FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8F6FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2004EFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFEC0049FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4800 +EDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC005DFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFDBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58F8FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFF423C621B6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2004EFFFFFFFFFF +FFFFF1FDFFFFFFFFFFFFFFFFF1FDFFEC0049FFFFFFFFFFFFF6F4FFFFFFFFFFFFFFFFFFFF +EFFFFFFFFFFFFFFFFFFFFFECFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFF1FFFF +4800EDFFFFFFFFFFFFECFFFFFFFFFFFFFFFFFFFFFDEFFFFFFFFFFFBC005DFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66FAFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF333333333333333C5FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFEA333333333333302B333333333333CAFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF6233333333333377FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF71AAFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2004EFFFFF1 +175CA02102073FE8FFFFFFFFB122020B3CDA0049FFFFFFFF811E03032099FFFFFFDF1767 +851C010E53FAFFFFFFFFDB3E0F000E46E7FFFFFF5E17E2420D01189CFFFFFFFFF64C0C02 +1F944800EDFFFFFFD43A0D000F4BECFFFFFF5318EC3D0B011CA6FFFF9013000B171735FF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8C8C8C8C8C8C8C +E3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFF68C8C8C8C8C8C88808C8C8C8C8C8CE7FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAC8C8C8C8C8C8CB8FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFA0E8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0C9FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2004EFF +FFED001F0F5B74210045FFFFFFB506106C7F30220049FFFFFF4E00357D61110085FFFFD8 +001E0B64833B003DFFFFFFCA0C0C628334021AF8FFFF4A00263177490604D5FFFFFF3400 +41845F0B1C00EDFFFFBD0A0F6680300121FBFFFF3E01253678440408E2FFC55900317272 +88FFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF79DBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB200 +4EFFFFED0002B4FFFFFF1B03F4FFFF3203CAFFFFFD2E0049FFFFB0014EFFFFFFF81011F6 +FFD80000ACFFFFFF4201B4FFFF3507CAFFFFFF750070FFFF4A003DFFFFFF7F0063FFFFA4 +004CFFFFFF9C0000EDFFFF2B0BD7FFFFFF67007DFFFF3E0049FFFFFF710071FFFFBC005D +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF71FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4FDFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +B2004EFFFFED002BFFFFFFFF4F00C5FFF4013AFFFFFFFF970049FFFF4E00CFFFFFFFFF51 +00BFFFD80025FFFFFFFFBC0059FFEC003FFFFFFFFFE50436FFFF4A00B4FFFFFFD80044FF +FF4E00CFFFFFFFFF1C00EDFFD7004AFFFFFFFFD70241FFFF3E00C6FFFFFFC50050FFFFBC +005DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58F8FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0E5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7D5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFE3E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21B6FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFB2004EFFFFED0045FFFFFFFF7800ADFFC2005CFFFFFFFFCF0049FFFF30012220201F +1E130093FFD80044FFFFFFFFF8023CFFB5001021201F1E1D041EFFFF4A00E5FFFFFFFF0B +36FFFF3306FFFFFFFFFF3A00EDFFA3001221201F1E1D0326FFFF3E00FBFFFFFFFF0341FF +FFBC005DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66FAFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD9AFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6B100B6EFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6620FFFFFFFFFFFFFFFFFFFFFFFFFFFF4F +2D2D2D2D2D60FFFF3A85FFFF4E2DB5FFFFFF9435FFFFFFFFFF4930EFFFFFFFFFFFFFFFFF +FFDA2D2D2D2D2D2D2D2D7ED22D2D2E3A5FE2FFFFFF7249FFFFFFFFD82DB8FFD22D2D2D2D +2D2DADFF9B17FBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71AAFFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFB2004EFFFFED0048FFFFFFFF7800ADFFB90061FFFFFFFFD80049FFFF29046262 +6262626262C0FFD80049FFFFFFFFFD0337FFA6002E62626262626276FFFF4A00EAFFFFFF +FF0B36FFFF2E09FFFFFFFFFF3E00EDFF9600336262626262627CFFFF3E01FFFFFFFFFF03 +41FFFFBC005DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6123 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0C8EFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6620FFFFFFFFFFFFFFFFFFFFFFFFFF +FF2420626262628CFFFF0E62FFFF23002EFFFFFF7408FFFFFFFFC701067FFFFFFFFFFFFF +FFFFFFE76262622B09626262A4C2004C6A460E15EAFFFF4C1DFFFFFFFFCA00A0FFC20047 +62626262C7FFFF1981FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF3EC6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0C9FFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFB2004EFFFFED0048FFFFFFFF7800ADFFEC0043FFFFFFFFA60049FFFF4800 +D0FFFFFFFFFFFFFFFFD8002EFFFFFFFFCD0053FFE20040FFFFFFFFFFFFFFFFFF4A00EAFF +FFFFFF0B36FFFF4900E2FFFFFFFF2500EDFFCC004BFFFFFFFFFFFFFFFFFF3E01FFFFFFFF +FF0341FFFFBD005CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEAA39EE5FFFFFFDFCDFFFFFFE8C5FFE3 +4E1DBFBFE7FFFFFFFFFFFFFFFFFFE8A0A0E8FFFFE39000ACBFF4FFFFFFFFFFFFFFDDCFFB +B69AE8FFFFFFFFFBB991CAFFFFFFFFFFE59EA4ECFFFFFF6620FFFFFFFFFFFFFFFFFFFFFF +FFFFFF2444FFFFFFFFFFFFFF0E62FFFF232B02A1FFFF7408FFFFFFFF591F4A29FFFFFFFF +FFFFFFFFFFFFFFFFFF5C12FFFFFFFFC200A8FFFF930089FFFF4C1DFFFFFFFFCA00A0FFC2 +00A8FFFFFFFFFFFFFF731AFDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCAF3FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFECCFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFB2004EFFFFED0048FFFFFFFF7800ADFFFF2209E3FFFFFF400049FFFF +91004CFFFFFFFFFFFFFFFFD80002CAFFFFFF580099FFFF2206CAFFFFFFFFFFFFFFFF4A00 +EAFFFFFFFF0B36FFFF890064FFFFFFBC0100EDFFFD1A0AD7FFFFFFFFFFFFFFFF3E01FFFF +FFFFFF0341FFFFDF003DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF950B0A0D0885FFFF5D26FFFFFF860C +FF860E061C1C90FFFFFFFFFFFFFFFF8D0A0B0B0A8DFF8717001A1CCAFFFFFFFFFFFFFF59 +232C10070DB0FFFFD72501160042FAFFFF83070D090C97FFFF6620FFFFFFFFFFFFFFFFFF +FFFFFFFFFF2444FFFFFFFFFFFFFF0E62FFFF234B4124FFFF7408FFFFFFFB126DAE01C9FF +FFFFFFFFFFFFFFFFFFFFFF5C12FFFFFFFFC200A8FFFFC30081FFFF4C1DFFFFFFFFCA00A0 +FFC200A8FFFFFFFFFFFFFFCF00BCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4FDFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD54C211726 +4FDAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD9AFFFFFFFF00A0FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7D0CFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFB2004EFFFFED0048FFFFFFFF7800ADFFFF970020A1BB53100049 +FFFFFF39003D9BBF9C631EFFFFD800101797BF640226FFFFFFB9041075B4B1873A6BFFFF +4A00EAFFFFFFFF0B36FFFFFD1E036BC091131000EDFFFFAA021379B6AE853676FFFF3E01 +FFFFFFFFFF0341FFFFFF150B598397FFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF58F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE70B3EE5ED4B06D7FF5D26FFFFFF +860CFFFF6123FFFFFFFFFFFFFFFFFFFFDF0945E8E84409E0FFB500E3FFFFFFFFFFFFFFFF +FF59005AF4E0331BFDFF3F15B8FF940375FFD4054DEDE33D0DEAFF6620FFFF8117171717 +171717178DFFFF241C535353539EFFFF0E62FFFF234BCF048FFF7408FFFFFF9903DDFF19 +59FFFFFFFFFFFFFFFFFFFFFFFF5C12FFFFFFFFC200A8FFD24103DBFFFF4C1DFFFFFFFFCA +00A0FFC2003D53535353E8FFFFFD0687FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25B8FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF181A6B +9B7830B0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6222FFFFFFFF00A0FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7D0CFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFB2004EFFFFED0048FFFFFFFF7800ADFFFFFF810700001ABD +0049FFFFFFF865080000000941FFFFD80053590400002DE2FFFFFFFFBD27010000001E9A +FFFF4A00EAFFFFFFFF0B36FFFFFFDA27000006684800EDFFFFFFB5230100000121A5FFFF +3E01FFFFFFFFFF0341FFFFFFAA280B001EFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF6EFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8E00B8FFFFD40076FF5D26FF +FFFF860CFFFF6123FFFFFFFFFFFFFFFFFFFF8300C6FFFFC60080FFB500E3FFFFFFFFFFFF +FFFFFF5902E5FFFF9500B9FF0655FFFFFF2629FF7501D8FFFFB4008FFF6620FFFFCF9595 +959595959595D4FFFF24163F3F3F3F90FFFF0E62FFFF234BFF4E1BFB7408FFFFFF3A33FF +FF6312FBFFFFFFFFFFFFFFFFFFFFFF5C12FFFFFFFFC2000709010AB2FFFFFF4C1DFFFFFF +FFCA00A0FFC2002F3F3F3F3FE3FFFFFF1D5CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6DD8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA000 +A6FFFFFFFFFFFFF8BFF6DA95C6FFFFFFFFF1A48CB2FBFFFFECC2FFFFFFC2D8FFFFE8C3FF +F4BFFADA94C2FFFFFFFFFFC28CA8F4FFFFFFFFFFE34F1CBFBFE7FF00A0E797B4FFFFFFF8 +BFF6DF96D2FFFFC591B6FDFFFFFFFBAE8CA8EFFFFFFFFFFDB59BEA7D0CFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71AA +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAB8D7 +FFFFFFFFFFFFFFFFFFFDCDAAC9F8FFFFFFD80053FFF6B4DDFFFFFFFFFFFFFFFFEDB2B6E0 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDAB6F8FFFFFFFFFFFFFFFFFFEAB0B9E3FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6E0AFFFFFFFF1654FF5D +26FFFFFF860CFFFF6123FFFFFFFFFFFFFFFFFFFF6410FFFFFFFF105EFFB500E3FFFFFFFF +FFFFFFFFFF591CFFFFFFE80090DD0097FFFFFF5913FF5818FFFFFFFD096BFF6620FFFFF4 +E3E3E3E3E3E3E3E3F6FFFF2444FFFFFFFFFFFFFF0E62FFFF234BFFDD087E7408FFFFE504 +519595780099FFFFFFFFFFFFFFFFFFFFFF5C12FFFFFFFFC2007CB1770E46FFFFFF4E18FF +FFFFFFBF00A4FFC200A8FFFFFFFFFFFFFFFF2255FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8EAFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +BC009AFFFFFFFFFFFFD2005904150058FFFFDF071A210222E3FFC500D0FFD0002AFFFF5F +1FFFBD006404130161FFFFD5131027143EFFFFFFFFFF860E061C1C8FFF005B0716003FFF +FFD0005F031984E836011C022CE8FFFF1815240413BCFFFFF13300180A4B0CFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +A0C9FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD80053FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8001DBFFFFF10568 +FF621EFFFFFF690CFFFF6123FFFFFFFFFFFFFFFFFFFF7602E8FFFFE70272FFB500E3FFFF +FFFFFFFFFFFFFF5909FAFFFFB500A6F6026FFFFFFF3A20FF6906F4FFFFD8017FFF6620FF +FF7000000000000000007DFFFF2444FFFFFFFFFFFFFF0E62FFFF234BFFFF5C136F08FFFF +720312121212083AFFFFFFFFFFFFFFFFFFFFFF5C12FFFFFFFFC200A8FFFF99019AFFFF69 +01E2FFFFFF7A00CAFFC200A8FFFFFFFFFFFFFFFF0A7DFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF25043675E0FFFFFFD2001FCAFD8000A6FFF3CDFFFFDB1159FFFF127BFF7C1805F3 +FF2952FFBD002BD8FF6404EAFF5133FFFFFFDBFFFFFFFFFFFF6222FFFFFFFF0018C5FF8D +00B9FFD00022C5FFFF4D17CFFFD21751FFFFC2FFFFEC2B30FFFF6B0BACFFAA0A0CFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD80053FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC3017BFFFF91 +00ACFF8102E5FFFF240CFFFF8611FFFFFFFFFFFFFFFFFFFFB80186FFFF8601B8FFB500E3 +FFFFFFFFFFFFFFFFFF5900A9FFFF6607E7FF212EFFFFF30B4DFFA80095FFFF7802C6FF66 +20FFFFEFD7D7D7D7D7D7D7D7F1FFFF2444FFFFFFFFFFFFFF0E62FFFF234BFFFFEA0D1D08 +FFFF2143FFFFFFFF8004E2FFFFFFFFFFFFFFFFFFFF5C12FFFFFFFFC200A8FFFFFF3420FF +FFA60087FFFFFF3B0FFBFFC200A8FFFFFFFFFFFFFFDD00B0FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFE8FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFF68126040649EAFFD20068FFFFFF124AFFFFFFBB8E83322CFFFF413DFF3E61 +179CEF0497FFBD008AFFFFCF00B2FF581CB0FFFFFFFFFFFFFFFFFF6222FFFFFFFF0061FF +FFFA0881FFD00071FFFFFF0770FFFFFF6119FFFFFFCA95834C0BFFFF2439FFFFFF360CFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE22774FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF51F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4C023D +44033DFFFFE70A1C591E250CFFFFDF01304CADFFFFFFFFFFFFFFFF440241410245FFFFB5 +00E3FFFFFFFFFFFFFFFFFF591412513C0267FFFF9F041E591010D8FFFF3A03463B0250FF +FF6620FFFFFFFFFFFFFFFFFFFFFFFFFFFF24143939393956FFFF0E62FFFF234BFFFFFF6C +0008FFBC00A0FFFFFFFFED0670FFFFFFFFFFFFFFFFFFFF5C12FFFFFFFFC200A8FFFFFFB5 +0191FFFF3B012A52170388FFFFC2002B3939393999FFFF8E0EF3FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF25B8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7F3FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFE5660178FFD200AAFFFFFF3A31FFDF1E0721371E1CFFFF7F10FF +10AC48569A03EDFFBD00D7FFFFFD00A1FFD83F03125EDDFFFFFFFFFFFF6222FFFFFFFF00 +9FFFFFFF1773FFD000BBFFFFD80003040404040CFFFA36041C352900FBFF106EFFFFFF6A +0CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +8546437BFDFFFFFFC24B4285BC65FFFFFFDA835BB5FFFFFFFFFFFFFFFFFF80444480FFFF +FFD85AF1FFFFFFFFFFFFFFFFFF5929B951428DFFFFFFFFBB523C5DDFFFFFFFFD7A424687 +FFFFFFA675FFFFFFFFFFFFFFFFFFFFFFFFFFFF785A5A5A5A5A75FFFF67A4FFFF7795FFFF +FFF45D62FFA85FFDFFFFFFFFFF7D80FFFFFFFFFFFFFFFFFFFFA06AFFFFFFFFDF5AD0FFFF +FFFF7387FFFFFF8A4C3B57BCFFFFFFDF5A5A5A5A5A5AAEFFFF2B66FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5CD2FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF262EFFD20081FFFFFF213FFF5A0EEFFFFF401CFFFFD5 +008C09FA89225427FFFFBD00DAFFFFFD00A1FFFFFFE37E1C2EFFFFFFFFFFFF6222FFFFFF +FF00A0FFFFFF1773FFD000C6FFFFF10179FFFFFFFFFFFF8E02C2FFFF6D00FBFF1C4DFFFF +FF4A0CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF71AAFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF50FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5929FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBB0BECFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFD7E3FFFFFFED0B39FFD20040FFFFE00274FF5129FFFFF30A1CFF +FFFF191A33FFE203185DFFFFBD00DAFFFFFD00A1FFFBFFFFFF7E0AFAFFFFFFFFFF8710FF +FFFFFF00A0FFFFFF1773FFD000C6FFFFFF2424FFFFFFFFFBFF810CF6FFFF2400FBFF451A +FDFFFB180CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFA0C9FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFB4B4B4B4B4B4BFFFFFFFFF +FFFFFFFFFFFFFFFFFFB9B4B4B4B4B4B4E55929FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEDB4B4B4B4B4B4B4FDFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFA9FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF8C063A5C491804AEFFD200202A5D0D1BF4FFB901465F1222 +1CFFFFFF4B006FFFFF2000A6FFFFBD00DAFFFFFD00A1FF2B477361155CFFFFFFFFFFFFE0 +01304CADFF00A0FFFFFF1773FFD000C6FFFFFFB80B1759693E43FFED0931681C2400FBFF +C60A1A631A200CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF861C1C1C1C1C1C34FFFF +FFFFFFFFFFFFFFFFFFFFFF281C1C1C1C1C1C9AAE8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB81C1C1C1C1C1C1CF4FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFE8FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFF194533B405FD0FFFFD200BC693E60E8FFFFFFB2514B +97AA72FFFFFFB45AD0FFFF905BF8FFFFDD5AECFFFFFF5ACCFF9F553B569FF8FFFFFFFFFF +FFFFDA835BB5FF5ACCFFFFFF6EB0FFE75AE2FFFFFFFFDD603D3E60C3FFFFCA61447CCC5A +FDFFFFCA544281B665FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7BBFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFD4B4FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51F8FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25B8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF48CAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD200C5FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7D0FFFFFFFFFF2E0DFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF4D00E3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF29FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EFAFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF5A72E2FFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFECFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD200C5FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71AAFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF260EFFFFFFFFFF2E0DFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF4D00E3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFA60004368FF8FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC72E7FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0C9FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF260EFFFFFFFFFF2E +0DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF4D00E3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF180000000D4CB2FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF7E5ECCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF88180A838383E0 +FF2E0DFFB5675795FFFFFFFFD583CFE086529BFFFFED8A595E99FFFFFFFFFFE3875C4E6E +C0FFFFFFFFFFFFCF71558EF14D00E3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF370000000000001A66D5FFFFFFFFFFE8FAFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF93E3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE20801287AEAFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1503010D0D +0DB4FF2E0D75021201004AFFFFFF95006715030D5CFFA915021607002EE5FFFFFF040213 +12000370FFFFFFFF9B09021807294500E3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51F8 +FF7A00000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000016BFFFFFFFF25B8FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF85E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41000000063D9AFBFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF260E +FFFFFFFFFF2E021CC7FFC22501BBFFFF95000268F6FFF1E50C1BC2FFE767004DFFFFFF75 +E5FFFFB82404CAFFFFEC0D14C5FFF63D0200E3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +6EFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF380000000000001C67D7FFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71AAFFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF680000000000001054BFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +260EFFFFFFFFFF2E00ACFFFFFF7D0074FFFF95002FFFFFFFFF5900B0FFFFFFFF1F03F6FF +FFFFFFFFFFFF950070FFFF6F0088FFFFFFEA0A00E3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1A0000000E50B6FFFFFFFFFFFFFFFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFF1700000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000004AF3FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF260EFFFFFFFFFF2E05FDFFFFFFCF0058FFFF950069FFFFFFFF30049493918F8E3A00 +C0FFFFF67E49332D2C004EFFFF4500EDFFFFFFFF3300E3FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA800063B96FAFFFFFFFFFFFFFFFFFFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF690000000000001256C0FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF260EFFFFFFFFFF2E0DFFFFFFFFE50053FFFF950083FFFFFFFF19010404040404 +0404A3FFE7190113304A4B0042FFFF2E09FFFFFFFFFF4600E3FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6079E8FFFFFFFFFFFFFFFFFFFFFFFFFFE8FA +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43C9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4200000007409EFDFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF260EFFFFFFFFFF2E0DFFFFFFFFE50053FFFF950084FFFFFFFF290BFFFFFF +FFFFFFFFFFFF5C006FFFFFFFDA0042FFFF3F01F4FFFFFFFF3700E3FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2EFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF51F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +25B8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE309012C7FEDFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF2C07FDFFFFFFFF2E0DFFFFFFFFE50053FFFF950084FFFFFFFF4C00AD +FFFFFFFFFFFFFFFF3A03EFFFFFFF8C0042FFFF61009FFFFFFFF81100E3FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF6EFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF71AAFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8165D4FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF4500ACFFFFFFFF2E0DFFFFFFFFE50053FFFF950084FFFFFFFFCF +071CCAFFFFFFEC8CFFFF50008FFFFFCD150042FFFFD80621E7FFFF5C0000E3FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFA0C9FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFAD04001117B8FF2E0DFFFFFFFFE50053FFFF950084FFFFFF +FFFF8D0B052738240712FFFFC707012632095D0042FFFFFF7302103A21153600E3FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67D5FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD07A5F5AD2FF7F66FFFFFFFFF35A9AFFFFC55ABBFF +FFFFFFFFFFDB643E2E406CCDFFFFFFC94D304C8DFD5A8EFFFFFFFF9F48335FD4965AF1FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFE8FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB6EDFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF25B8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EFAFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF71AAFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB6 +EDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFA0C9FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF67D5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF56FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51F8FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25B8FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EFAFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71AAFFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3BCFFFFFFFFFFFFFFFFA6B8FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF43C9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0C9FFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFF6FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8FAFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF51F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25B8FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80A3FFFFFFFFFFFFFFFF4C6A +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF6EFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71AAFFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3BCFFFFFFFFFFFFFFFF +4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF93E3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0C9 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFF +FFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFF +FFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFE8FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFF +FFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF51F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF25B8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2FAFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80A3 +FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF6EFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF48CAFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF71AAFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +A3BCFFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF39 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFA0C9FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF4672FFFFFFFFFFFFFFFF869CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFE8FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF4672FFFFFFFFFFFFFFFFA6B8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51F8FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF25B8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C +D2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF80A3FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF39FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EFAFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFC7F3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71AAFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFA3BCFFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFD0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0C9FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8FAFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFA8EAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51F8FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25B8FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF73DAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80A3FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EFA +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71AAFFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3BCFFFFFFFFFFFFFFFF4C6AFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0C9FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6A +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8FAFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3EC6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF +4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF51F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25B8 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80A3FFFFFFFFFFFF +FFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF6EFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +71AAFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3BCFFFFFFFF +FFFFFFFF869CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFA0C9FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFF +FFFFFFFFFFFFA6B8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF79DBFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672 +FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5CFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFE8FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0E8FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF25B8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF80A3FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF71AAFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFA3BCFFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8F6FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFA0C9FFFFFFFFFFF6FF3F7AFFF6FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51 +CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFF7EB23F7A74C5FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF44FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFC50B303B12FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51F8FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25B8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF1F070737FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF80A3FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EFAFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71AAFFFFFFFFFFFF3A000185FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFA3BCFFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF51CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0C9FFFFFFFFFFFF8A010BEFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFD8F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFEF0719FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8FAFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF16 +3BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF869CFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +51F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25B8FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF +FF5EC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80A3FFFFFFFFFFFFFFFFA6B8FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF6EFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0E8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71AAFFFFFFFF +FFFFFFDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3BCFFFFFFFFFFFFFFFF4C6A +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF79DBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF8A58C2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0C9FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF +4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFEF0E002270E0FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFF +FFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +E8FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5000000003348AF4FFFFFFFFFFFFFFFFFFFFFF +3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFF +FFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF51F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF25B8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF790000000000000A48AAFFFFFFFFFFFFFF +FFFF3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80A3FFFF +FFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF6EFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3EC6FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF330000000000 +000000000000000000000000000000000000000000000000000000000000003BE8FFFFFF +FFFFFFFF71AAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3BC +FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF780000000000001256BFFFFFFF +FFFFFFFFFFFFA0C9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4E00000007419EFDFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFE8FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC0C022D80EDFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFA4C5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51F8FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF25B8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF73DAFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F67D5FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF80A3FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF50FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EFAFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8 +EAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3291FFFFFFFF7943FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF71AAFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFA3BCFFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFA9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0472FFFFFFFF5417FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0C9FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF869CFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0472FFFFFFFF5417FFFF +D5D7FAB09BECFFFFFFFFED9EB2FBD2D8FFFFC2ECFFFFFFCCE0FFFFFFF4B093D2FFFFFFE2 +CAFFFFFFECC2FFFFFFFFD495AAF4FFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFFA6B8FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8FAFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFC7F3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0472FFFFFFFF5417 +FFFF3C3622120412D0FFFFBB120512252A46FFFF0790FFFFFF2066FFFFB21506180263FF +FF6A1DFFFFFF9504FFFFFD510118061AC7FFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFA9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51F8FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25B8FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5CD2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0472FFFFFFFF +5417FFFF3C0086FDDF1353FFFF262CD8F8670046FFFF0790FFFFFF2066FFF31546EDFF96 +01A9FF6A1DFFFFFF9504FFFF7A06B5FFE72E2CFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80A3FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EFAFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0472FFFF +FFFF5417FFFF3C18FFFFFF462EFFD80086FFFFF30546FFFF0790FFFFFF2066FF9602D2FF +FFFF1E59FF6A1DFFFFFF9504FFFF2444FFFFFF9301F3FFFF71AAFFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3BCFFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF066A +FFFFFFFF4D18FFFF3C42FFFFFF5E25FFAC00D4FFFFFF2646FFFF0790FFFFFF2066FF6F01 +040404040445FF6A1DFFFFFF9504FFFF0D030404040404CAFFFFA0C9FFFFFFFFFFFFFF76 +A4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1739FFFFFFFF222CFFFF3C43FFFFFF5E25FFC500A3FFFFFF0F46FFFF0A84FFFFFD0E66FF +8103DDFFFFFFFFFFFF6E17FFFFFF7504FFFF184CFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8FAFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF48CAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3F0DF6FFFFE20259FFFF3C43FFFFFF5E25FFF80E59FFFFBC0046FFFF1D48FFFFA400 +66FFCA0468FFFFFFFFFBFF9000D5FFFF2C04FFFF470AF3FFFFFFFBFFFFFF3983FFFFFFFF +FFFFFFA4C5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6A +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF29FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF51F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25B8FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFECFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFC90C0A463D0716E8FFFF3C43FFFFFF5E25FFFF76013457111746FFFF68044146 +1A1266FFFF6C032A6A60278CFFEF0F1959212504FFFFE2180E4B6E4A27FFFFFF3983FFFF +FFFFFFFFFF76A4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80A3FFFFFFFFFFFFFFFF +4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF6EFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFE26540446EEFFFFFFF898FFFFFFFA179FFFFFF99454FB13346FFFFFF77 +3D57CA75A6FFFFFFAA52394578E7FFFFCA4C417EC55FFFFFFFF16D423B55ACFFFFFF6CA8 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3BCFFFFFFFFFFFF +FFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3346FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +A8CDFFFFFFFFFFFFFFA4C5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFF +FFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF93E3FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFE2DAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFD0EAFFFFFFFFFFFFFFFFFFFFFFE2D2FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFD4E7FFFFCAF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFD5E7FFFFFFFFFFFFFFFFD8ECFFFFFFFFFFFFFFDAE2FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFCAFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3346 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFF +FFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFE8FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85E0FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF83DBFFFFFF532EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF0F78FFFFFFFFFFFFFFFFFFB6220825FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1869FFFD00A1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF1E69FFFFFFFFFFFFFFE20ACDFFE583F4FFFFFF2F51FFFFFFFFFFFFFF79 +341A204CDBFFFFFF2184FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +96A3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672 +FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF51F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF25B8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00A0FFFFFF532EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF0F78FFFFFFFFFFFFFFFFFF4E38F8FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1869FFFD00A1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF1E69FFFFFFFFFFFFFF5A37FFFFB800E0FFFFFF2F51FFFFFFFFFFFF +FD0B51835F121CF3FFFF7F1BFDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +80A3FFFFFFFFFFFFFFFF869CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6EFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFF1AC95D7FFFFFFFFFFDB9A96DAFFFFFFFAB494D2FFFFFFF6BFF8DD95D5FFFFC390B8FF +FFFFFFFFFFFFFFFFFFC3007DBFC9FF532EFDB897E3FFFFFFD5D7FAB49CFFFFE8A39AE2FF +FFFFFFD79793CCFFFFFFFFFFDF96C5FF0F78FFFFFFFFFFFFFFFDBF1A54BFDBFFFFEAA599 +E0FFFFFFFFFFCF94AEF8FFFFFFFFE397BFFF1869FFFD00A1E297BDFFFFFFFFF6A98CADF6 +FFFFFFFFFFD4959AE3FFFF1E69FFFFFFC6CFFFE80AA8FFF88E00AABFD4FF2F51F8A99FF1 +FFFFFFEFFFFFFF9000A3FFFFF60E8CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF6CA8FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFA3BCFFFFFFFFFFFFFFFFA6B8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFA61108170370FFFFFF58020E2005C6FFC91E0215014FFFFFCA0060021984E533011C +022EECFFFFFFFFFFFFFFFF2500151C33FF5328300E070BB8FFFF3C36200D2BFF8A090D11 +098EFFFF7B0922150157FFFFFF8F070D0A450E78FFFFFFFFFFFFFFF41C050F1C6CFF900B +0C120787FFFFF847001A0420D4FFFF9C090A0D3A1769FFFD005405170043FDFFFF0A1823 +031ACFFFFFF64601131D04F1FF1E69FFFD5110B6FF8809FFFFD717001A1C51FF2F3F1B13 +0317E0FFFFFFFFFFFFC7009FFFFFFF3D3BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFA8CDFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFE7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFEA0F51F1FF8502BBFF800183F6FFDDECFF301CC3FD840089FFCA0024C6FF433E19 +D0FFD01555FFFFFFFFFFFFFFFFFF00A0FFFFFF53006BF8EA203CFFFF3C007AF8FFCC0570 +FAFA6209DFFFD0EDFFFF9001B6FFEC0B4BEDE8400078FFFFFFFFFFFFFFFFFF1D6AFFFFD4 +0768F8FB6907D7FF6A0AC0FFE02638FFF61141E8ED4A0069FFFD0015BCFF990287FFFFC2 +FFFFE51E42FFFF620794FBFFD0FAFF1E69F33A1ACFFFFF5B20FFFFFFB800E0FFFFFF2F01 +96FFD80B63FFFFFFFFFFFF4B12EDFFFFFF5F1DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF2EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFDFF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF8406E2FFFFFF1568FF2B22FFFFFFFFFFED0068FFFFFF1A38FFCA0076FFFFFD +0574FFFFFF5D1CFFFFFFFFFFFFFFFFFF00A0FFFFFF530AF8FFFF5E1BFFFF3C12FFFFFF5F +12FAFFFFEA068FFFFFEFA887830D76FF9000CAFFFFB00078FFFFFFFFFFFFFFFFFF1D6AFF +FF670EF6FFFFF10985FF1952FFFFFF8007FFA300B5FFFFC50069FFFD0050FFFFFF2236FF +FFFFC391833F1AFFFF1738FFFFFFFFFFFF1E592727E3FFFFFF363AFFFFFFB800E0FFFFFF +2F24FFFFFF373CFFFFFFFFFF7E039EFFFFFFFF8705FBFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4AF8FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2ABBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF6001040404040451FF145CFFFFFFFFFFC000B1FFFFFF4820FFCA00C0FF +FFD00003040404040EFFFFFFFFFFFFFFFFFF00A0FFFFFF532DFFFFFF7A13FFFF3C3DFFFF +FF4001040404040473FF940B0F2B390B60FF6F0FFFFFFFFB0678FFFFFFFFFFFFFFFFFF1D +6AFFFF460104040404046BFF04030404040404E37E07FDFFFFFF0D69FFFD008CFFFFFF50 +1FFFEF29061E36240CFFFF037AFFFFFFFFFFFF1E0608DBFFFFFFFF303FFFFFFFB800E0FF +FFFF2F51FFFFFF4F31FFFFFFFF88037EFFFFFFFFFF8F02F6FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF76A4FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF80A3FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF76FAFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8 +A1FFFFFFFBA57AE5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67AE0FFFFFF +FFFFFFFFFFD28EFFFFFFFFFFFFFFE07AF6FFFFFFFFFFFFFFFFF4D8FBFFFFFFFFBBA1FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF7107ECFFFFFFFFFFFF2139FFFFFFFFFFDB0083FFFFFF2B2EFFCA00 +CCFFFFEC017DFFFFFFFFFFFFFFFFFFFFFFFFFFFF00A0FFFFFF532EFFFFFF7A13FFFF3C43 +FFFFFF4F17FFFFFFFFFFFFFF1943FFFFF6095FFF8102EAFFFFD20078FFFFFFFFFFFFFFFF +FF1D6AFFFF5613FDFFFFFFFFFFFF0E5AFFFFFFFFFFFF9300D8FFFFE50269FFFD0067FFFF +FF332BFF7406DBFFFF560CFFFF0E51FFFFFFFFFFFF1E5E2B20E2FFFFFF5325FFFFFFB800 +E0FFFFFF2F51FFFFFF4F31FFFFFF900476FFFFFFFFFFFF6718FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6CA8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFA3BCFFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE746D8FFFF +FF453AFFFFED0D1F39D2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE700B2FF +FFFFFFFFFFFFFF4158FFFF7681FFFFFFB400E5FFFFFFFFFFFF9A220100044BF6FFFFBD0A +E8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFB90278FFFFFFFFFBFF5107ECFFFFFFFFFF143DFFFFE7045FFF +CA00CCFFFF671D26FFFFFFFFFBFFFFFFFFFFFFFFFFFF157FFFFFFF532EFFFFFF7A13FFFF +3C43FFFFFF8F00A1FFFFFFFFFBFF1272FFFF90005FFFC5018FFFFF7A0078FFFFFFFFFFFF +FFFFFF1D6AFFFF990097FFFFFFFFFBFF3A12FBFFFFFFFBFFD7037EFFFF8A0069FFFD002D +FFFFF60A5AFF6918FFFFFB160CFFFF3915F8FFFFFFFFFF1E69F1301CDBFFFF7E0EFFFFFF +E802B6FFFFFF2F51FFFFFF4F31FFFF970470FFFFFFFFFFFFFF4534FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8CDFFFFFFFFFFFFFFA4C5FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF44FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD500C2 +FFFFFFC9C5FFFF8C13FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE700 +B2FFFFFFFFFFFFFFCC06D5FFFF3946FFFFFFB400E5FFFFFFFFFFFF735CB8D5750257FFFF +FF2B63FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF5E032E6C5E229EFFE3160A4B6B33C5FF8C0324570C15 +E8FFCA00CCFFFFB6A80B1859693D46FFFFFFFFFFFFFFFFFF46134561FF532EFFFFFF7A13 +FFFF3C43FFFFFFFF3F06376F5919D0FF590F5E4313135FFFFF46044944190978FFFFFFFF +FFFFFFFFFF1D6AFFFFFF4604356F591BC5FFD51312506D4630FFFF5203434A160D69FFFD +002022611312E2FFD8023B6516240CFFFFC90E0E54682AEFFF1E69FFF63619D5FFD003C9 +FFFFFF241C497BFF2F51FFFFFF4F31FFEC050C393939399BFFFFFF1A71FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF76A4FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA499D06A56AAFFFFFFFFCC6A5280F8FFFA64 +005B728FFFA19BFF933116728381B1FFFFFFFF7DB6FFFFFFFFFFFFFFFFFFDB734F5FB1FF +E700B18E5474F1FFFFFF493CFFFFA11F267272DFB400E2855278F8FFFFFFFFFFFFFF351F +FFFFFF8E0DF1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFF8FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA15139467DEDFFFFED693F416EEFFFFFAE503D +62E8FFFFE35AE5FFFFFFFFDA5F3D3F61C6FFFFFFFFFFFFFFFFFFF8A9656FFF9A7FFFFFFF +B46BFFFF898FFFFFFFFFFF8C4B394A8AF8FFF48D425ACA78A3FFFFFD7A3F59D268B2FFFF +FFFFFFFFFFFFFF73A9FFFFFFFF904D394987F6FFFFEC68413D59B4FFFFFF814157C96FA9 +FFFF5ACA723F59DAFFFFFFBF594789BC65FFFFFFE0603D4377FBFF73A9FFFFFA697FFFFF +434DFFFFFFEF9A5F86FF8099FFFFFF9781FFF15A5A5A5A5A5AB0FFFF9F0EF1FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4AF8 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4820143A24029CFFFF9E0715410421F1 +F644003E4C6FFF453AFF7422104C604B24FFFFFFB900BCFFFFFFFFFFFFFFFFA50B0D4D43 +2FFFE7002D13440622F6FFFF176FFFFF86171B4C4CD4B400331E3E063CFFFFFFFFFFFFFF +352CFFFFFFDF00ADFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2ABBFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFC60AE7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3368FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFA4 +C5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80A3FFFFFFFFFFFFFFFF4C6AFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +76FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4800BBFFFF2939FFFF1A30F8FFCC +0269FFD500C2FFFFFF453AFFFF5C26FFFFBD01BBFFFF4B26FFFFFFFFFFFFFFFFFB1732F4 +FFFFFDFFE7002BF8FFD50373FFF10197FFFFFF3946FFFFFFB4004CFFFF8301E5FFFFFFFF +FFA00294FFFFFFFF0A7CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8696CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFB6EDFFFFFFFFFFFFDBB4B4B4B4B4B4C2FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFDAB4B4B4B4B4B4C3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF97D4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86EDFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6CA8FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3BCFFFFFFFFFFFFFFFF4C6AFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF481DFFFFFF5E20FFE0007AFF +FFFF2531FFD500C2FFFFFF453AFFFF5C26FFFFFF284BFFF10A7FFFFFFFFFFFFFFFFFC900 +85FFFFFFFFFFE7006BFFFFFF2538FFB200C6FFFFFF3946FFFFFFB400AEFFFFD800B4FFFF +FFFFBF0D4FFFFFFFFFFF2254FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFF386300203CAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67D5FFFFFFFFFFFF7E1C1C1C1C1C1C3AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF781C1C1C1C1C1C3EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8CDFFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6A +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF56FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4837FFFFFF6D1BFFBF00 +B4FFFFFF4A1FFFD500C2FFFFFF453AFFFF5C26FFFFFF850AEF7E0BF3FFFFFFFFFFFFFFFF +A500CCFFFFFFFFFFE7009CFFFFFF4726FFC500B8FFFFFF3946FFFFFFB400E5FFFFF100AA +FFFFFFC60F3EFDFFFFFFFFFF1C5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFA645090000002FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF +869CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4837FFFFFF6D1BFF +E80071FFFFFF1F35FFDA00BDFFFFFF453AFFFF5C26FFFFFFF60E7C264FFFFFFFFFFFFFFF +FFFFD0007AFFFFFFFFFFE70063FFFFFF1F3BFFFB058AFFFFFF3A45FFFFFFB400E5FFFFF1 +00AAFFFFCC123AFAFFFFFFFFFFFD0589FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFF8 +FFFFFFFFFFFFFFFFFFFFFFFFFFC359150000000000004BF1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1377D +F1F1F1F1F1F1F13D75F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFF +FFFFA6B8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF4AF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4837FFFFFF6D +1BFFFF2626E0FFA6017CFFFF108AFFFFFF453AFFFF5C26FFFFFFFF581501C2FFFFFFFFFF +FFFFFFFFFF2226D8FFFFE7FFE70022E2FFB50183FFFF1F66FFFFFF6726FFFFFFB400E5FF +FFF100AAFFD21436F8FFFFFFFFFFFFCD00BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +2ABBFFFFFFFFFFFFFFFFFFFFFFFA59000000000000000000020404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +010304040404040404010204040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +04040404040404040404040404D8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80A3FFFFFFFF +FFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF76FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4837FFFF +FF6D1BFFFFB91207240039FBFFFF57061843FF453AFFFF5C26FFFFFFFFCF0229FFFFFFFF +FFFFFFFFFFFFFFBC16032E2924FFE70044092B0136FBFFFF6728FFFFFFBD120D1CC2B400 +E5FFFFF100AAFF51000B0D0D0D19FFFFFF721CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFCC5F170000000000004DFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43C9FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF6CA8FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3BCFFFF +FFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC3BC +FFFFFFD2AEFFFFFFE79077A9FFFFFFFFFFF1A9B5FFC2BDFFFFCCB4FFFFFFFFE80684FFFF +FFFFFFFFFFFFFFFFFFFFEF967389DFFFFA9FEAB879A1FDFFFFFFEC0BB2FFFFFFFFC59FEC +EA9FFAFFFFFB9FE8FFC69F9F9F9F9FA6FFFFFD1887FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAA480B0000002EFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6FDFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFA8CDFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672 +FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF581AF8 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F3DFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9718FBFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF48C340302C6FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3983FFFFFFFFFFFFFF76A4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA90D0B +9EFFFFFFDD6A6A6A6A6A6A6AF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6DBFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEAE8FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFDFF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0706EFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4AF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED +C2FAFFFFFFFFD44C4C4C4C4C4C4CEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF2ABBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85E0FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFA4C5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF80A3FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF76FAFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF93E3FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF6CA8FFFFFFFFFFFFFF76A4FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFA3BCFFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF87FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFA8CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFDA +F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFA4C5FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFF386 +302DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFECFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFD0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4AF8FFFFFFFFA846 +090000A6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2ABBFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF48CAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF80A3FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF39FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF76FAFFCA5D16 +0000000006FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6CA8FFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3BCFFFFFFFFFFFFFFFF869CFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04541601 +000000000000117272727272727272727272727272727272727272727272727272727272 +727272727272727272727272727272727272727272727272727272727272727272727272 +727272727272727272727272727272727272727272727272727272727272727272727272 +727272727272727272727272727272727272727272727272727272727272727272727272 +727272727272727272727272727272727272727272727272727272727272727272727272 +72727272727272727272727272727272A3FFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8CDFFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFFA6B8FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0327 +03000000000000000D464646464646464646464646464646464646464646464646464646 +464646464646464646464646464646464646464646464646464646464646464646464646 +464646464646464646464646464646464646464646464646464646464646464646464646 +464646464646464646464646464646464646464646464646464646464646464646464646 +464646464646464646464646464646464646464646464646464646464646464646464646 +46464646464646464646464646464646464680FFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1EC7E2B010000000008FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFF8FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5CD2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF39FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF4AF8FFFFFFD4651A000000BBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2ABBFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7F3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80A3FFFFFFFFFFFFFFFF4C6A +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC6FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF76FAFFFFFFFFFFFFB24E0D3CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6CA8FFFF +FFFFFFFFFF76A4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3BCFFFFFFFFFFFFFFFF +4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFF896F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8CD +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFF +FFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8EAFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3983FFFFFFFFFFFFFFA4C5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFF +FFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8FFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFDFF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6DD8FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3983FFFFFFFFFFFFFF76A4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFF +FFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF4AF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF2ABBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B9E +FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF76FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7DB6FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF6CA8FFFFFFFFFFFFFFA4C5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +A8C0FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF89BD +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFA8CDFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3EC6FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF24FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFDFF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF4672FFFFFFFFFFFFFFFF8097FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4AF8FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF2ABBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF7B9EFFFFFFFFFFFFFFFFACBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF76FAFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6CA8FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFA8C0FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF79DBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8CDFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFA0E8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF97FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFF8FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF76A4FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4AF8FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2ABBFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B9EFFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF76FA +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFD8F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6CA8FFFFFFFFFFFFFFA4 +C5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8C0FFFFFFFFFFFFFFFF4C6AFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF51CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8CDFFFFFFFFFFFF +FF76A4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6A +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFF8FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7DB6FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFF +FFFFFFFFFFA4C5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF +4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF4AF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2ABB +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF89BDFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B9EFFFFFFFFFFFF +FFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF76FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51CDFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +6CA8FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8C0FFFFFFFF +FFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8F6FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFA8CDFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFF +FFFFFFFFFFFF8097FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDBFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672 +FFFFFFFFFFFFFFFFACBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFDFF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4AF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF2ABBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0E8FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF7B9EFFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF76FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF79DBFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF6CA8FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFA8C0FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF71FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFA8CDFFFFFFFFFFFFFF76A4FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFA4C5FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4AF8FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2ABBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF3EC6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF76A4FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF7B9EFFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF24FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF76FAFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6CA8FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFA8C0FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF7DB6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8CDFFFFFFFFFFFFFFA4C5FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB09AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85C5FFFF +FFFFFFFFFFFFFFFFE88D8AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8CBC +FFFF7AD8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8FBCFFFFFFFFFFFFFF +FF8FD0FFFFFFFFFFFFFF9AB0FFFFFFFFFFFFFFFFFFDDECFFFFFFFFFF7EEAFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF89BDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFF8FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF73DAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF46C3FFFFFF532EFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0F78 +FFFFFFFFFFFFFFFFFF93082D4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1869FFFD00A1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E69FFFFFFFFFF +FFFFC20AE8FFD246EDFFFFFF2F51FFFFFFFFFFFFFF3E0A00001CA6FFFFFF3564FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +4AF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2ABBFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFA8EAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00A0FFFFFF53 +2EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +0F78FFFFFFFFFFFFFFFFFF3D4EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF1869FFFD00A1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E69FFFFFF +FFFFFFFF404EFFFFB800E0FFFFFF2F51FFFFFFFFFFFFFD2F91D7A5290AE0FFFFA00DEFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B9EFFFFFFFFFFFFFFFF8097FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF76FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFA8A1FFFFFFFBA57AE5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFF67AE0FFFFFFFFFFFFFFFFD28EFFFFFFFFFFFFFFE07AF6FFFFFFFFFFFFFF +FFF4D8FBFFFFFFFFBBA1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB564538AFFFFFFFFFD8C575487 +F6FFFFCC6A5280F8FFFFE872E88A53B5FFE575506DE0FFFFFFFFFFFFFFFFFF79004F7284 +FF532ED86D55A3FFFFFF9CA0C76A63FFFFA35D579CFFFFFFE88455517DF8FFFFFFFF9654 +76E70F78FFFFFFFFFFFFFFFA72103772AAFFFFA65F5699FFFFFFFFF47D5266CCFFFFFFFF +9E5572DF1869FFFD00A1935571ECFFFFFFAD624C65C6FFFFFFFFF681535791FDFF1E69FF +FFF177A3FFCD03CAFFEA5800687299FF2F51C2625ABCFFFFFFFFFFFFFFB10096FFFFFF1A +6DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6CA8FFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8C0FFFFFFFFFFFFFFFFACBC +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFE746D8FFFFFF453AFFFFED0D1F39D2FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFE700B2FFFFFFFFFFFFFFFF4158FFFF7681FFFFFFB400E5FFFFFFFFFF +FF9A220100044BF6FFFFBD0AE8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF72042C44073BFFFFF1260236 +511EC0FF9E0715410421F1FFCA00321348A1C312164C180FCCFFFFFFFFFFFFFFFF540036 +4C61FF531C173628018EFFFF3C240E3654FF5204363B0459FFFF6F2A53420C28FDFFFF5B +00302B200A78FFFFFFFFFFFFFFF84C0C264C90FF5904333D0452FFFFE01D104A2108AAFF +FF6A012B301A1069FFFD002D1145071DEDFFFF1246552006A9FFFFDB1A043E4D17EFFF1E +69FFE0252AE7FF7C0EFFFFE33D00464C7BFF2F2910401C04C0FFFFFFFFFFFFB100AEFFFF +FF4633FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8CDFFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF +4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFD500C2FFFFFFC9C5FFFF8C13FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFE700B2FFFFFFFFFFFFFFCC06D5FFFF3946FFFFFFB400E5FFFFFF +FFFFFF735CB8D5750257FFFFFF2B63FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD0480FFFFC5009AFF5D04 +D0FFFFFFFDFF1A30F8FFCC0269FFCA003BFBFFC72C2CFFFFFF243DFFFFFFFFFFFFFFFFFF +00A0FFFFFF5300A9FFFF332FFFFF3C01C3FFFFA500ACFFFF9502C6FFFBFFFFFFC7029CFF +D2037AFFFF680078FFFFFFFFFFFFFFFFFF1D6AFFFFAE01A1FFFF9F01BCFF4A16FBFFFF3E +23FFE2076BFFFF770069FFFD0024F4FFDF0667FFFFFBFFFFFF3332FFFF4310E0FFFFFFFF +FF1E69CA183DF6FFFF5126FFFFFFB800E0FFFFFF2F04DFFFFF1453FFFFFFFFFFFB2926FD +FFFFFF6817FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFF +FFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA499D06A56AA +FFFFFFFFCC6A5280F8FFFA64005B728FFFA19BFF933116728381B1FFFFFFFF7DB6FFFFFF +FFFFFFFFFFFFDB734F5FB1FFE700B18E5474F1FFFFFF493CFFFFA11F267272DFB400E285 +5278F8FFFFFFFFFFFFFF351FFFFFFF8E0DF1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +DFF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7A06999F9F9F155FFF +2431FFFFFFFFFFE0007AFFFFFF2530FFCA0089FFFF5A01599F9F9F4816FFFFFFFFFFFFFF +FFFF00A0FFFFFF5315FFFFFF6B17FFFF3C1DFFFFFF56129F9F9F9B0684FFFFAC6149460B +6DFF8601E0FFFFC60078FFFFFFFFFFFFFFFFFF1D6AFFFF5D0E9F9F9F9E097BFF13419F9F +9F5F03FA9700CCFFFFDB0169FFFD005FFFFFFF2E2FFFFFE27551462815FFFF1148FFFFFF +FFFFFF1E3E0E54FDFFFFFF2E41FFFFFFB800E0FFFFFF2F33FFFFFF4236FFFFFFFFFF480E +CAFFFFFFFF9002F4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFF +FFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4AFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF4AF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4820143A +24029CFFFF9E0715410421F1F644003E4C6FFF453AFF7422104C604B24FFFFFFB900BCFF +FFFFFFFFFFFFFFA50B0D4D432FFFE7002D13440622F6FFFF176FFFFF86171B4C4CD4B400 +331E3E063CFFFFFFFFFFFFFF352CFFFFFFDF00ADFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF2ABBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D062D2D2D2D2D +72FF135FFFFFFFFFFFBF00B4FFFFFF4A1EFFCA00CAFFFFCD00222D2D2D2D36FFFFFFFFFF +FFFFFFFF00A0FFFFFF532EFFFFFF7A13FFFF3C41FFFFFF3E0C2D2D2D2D2D8FFF61073B5F +72125FFF6E10FFFFFFFF0678FFFFFFFFFFFFFFFFFF1D6AFFFF450B2D2D2D2D2D88FF031C +2D2D2D2D2DE87D07FFFFFFFF0E69FFFD008EFFFFFF511EFFCF0B244F6F410CFFFF027CFF +FFFFFFFFFF1E1308B9FFFFFFFF3839FFFFFFB800E0FFFFFF2F51FFFFFF4F31FFFFFFFF50 +0AB5FFFFFFFFFF8506FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3983FFFFFFFFFFFFFF76A4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B9EFFFF +FFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF76FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4800 +BBFFFF2939FFFF1A30F8FFCC0269FFD500C2FFFFFF453AFFFF5C26FFFFBD01BBFFFF4B26 +FFFFFFFFFFFFFFFFFB1732F4FFFFFDFFE7002BF8FFD50373FFF10197FFFFFF3946FFFFFF +B4004CFFFF8301E5FFFFFFFFFFA00294FFFFFFFF0A7CFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B02D4FFFF +FFFFFFFF282AFFFFFFFFFFE80071FFFFFF1F35FFCA00CCFFFFF60264FFFFFFFFFFFFFFFF +FFFFFFFFFFFF019EFFFFFF532EFFFFFF7A13FFFF3C43FFFFFF580BF4FFFFFFFFFFFF105F +FFFFE3035FFF8C00D7FFFFBB0078FFFFFFFFFFFFFFFFFF1D6AFFFF5F09EDFFFFFFFFFFFF +1445FFFFFFFFFFFF9E00C0FFFFD00069FFFD0057FFFFFF2832FF6710F3FFFF440CFFFF14 +40FFFFFFFFFFFF1E69570BB2FFFFFF5D1FFFFFFFBC00DDFFFFFF2F51FFFFFF4F31FFFFFF +5709AEFFFFFFFFFFFF5E1EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF6CA8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8C0 +FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +481DFFFFFF5E20FFE0007AFFFFFF2531FFD500C2FFFFFF453AFFFF5C26FFFFFF284BFFF1 +0A7FFFFFFFFFFFFFFFFFC90085FFFFFFFFFFE7006BFFFFFF2538FFB200C6FFFFFF3946FF +FFFFB400AEFFFFD800B4FFFFFFFFBF0D4FFFFFFFFFFF2254FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7094E +F4FFFFE2E0FF6F02A8FFFFF4F3FF2726E0FFA8017CFFCA00CCFFFFFF3916D5FFFFFBC7FF +FFFFFFFFFFFFFFFF2070FFFFFF532EFFFFFF7A13FFFF3C43FFFFFFB4026DFBFFFFD4EFFF +1E5CFFFD61005FFFDF0762FDFB520078FFFFFFFFFFFFFFFFFF1D6AFFFFBC0365FAFFFFD7 +ECFF5607C3FFFFFFC6FFEC0B55FBFD5E0069FFFD001CDDFFBF0476FF7C0DF6FFCA0B0CFF +FF530BBBFFFFEAFBFF1E69FF6109A9FFFF8A09FFFFFFF607A3FFFFFF2F51FFFFFF4F31FF +FF5D07A9FFFFFFFFFFFFFF3D3CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFA8CDFFFFFFFFFFFFFFA4C5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF4837FFFFFF6D1BFFBF00B4FFFFFF4A1FFFD500C2FFFFFF453AFFFF5C26FFFFFF850A +EF7E0BF3FFFFFFFFFFFFFFFFA500CCFFFFFFFFFFE7009CFFFFFF4726FFC500B8FFFFFF39 +46FFFFFFB400E5FFFFF100AAFFFFFFC60F3EFDFFFFFFFFFF1C5FFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +930B09342A06A5FFFA3C001B330DC0FFB91207240039FBFFCA00CCFFFF48B02601263212 +45FFFFFFFFFFFFFFFFFF6B071733FF532EFFFFFF7A13FFFF3C43FFFFFFFF76060E362604 +D5FF7C042A17281C5FFFFF77021B18330D78FFFFFFFFFFFFFFFFFF1D6AFFFFFF7C070D36 +2604C9FFF336001F35182AFFFF8404171C2A1469FFFD0042072C012FF8FFEF12122F0843 +0CFFFFEA2D00223109EFFF1E69FFFF6B07A1FFEA0BA6FFFFFF47061A51FF2F51FFFFFF4F +31FFE300040D0D0D0D7DFFFFF40E90FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF76A4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF29FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF4837FFFFFF6D1BFFE80071FFFFFF1F35FFDA00BDFFFFFF453AFFFF5C26FFFFFF +F60E7C264FFFFFFFFFFFFFFFFFFFD0007AFFFFFFFFFFE70063FFFFFF1F3BFFFB058AFFFF +FF3A45FFFFFFB400E5FFFFF100AAFFFFCC123AFAFFFFFFFFFFFD0589FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFDFF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFE0917283CDFFFFFFFFB27A7CB9FFFFFFE79077A9FFFFFFF19FF3FFFFE2FAFDA578 +7AA8FBFFFFFFFFFFFFFFFFFFFFF6ADADFFC7B8FFFFFFD7AAFFFFBDC2FFFFFFFFFFD48A72 +88DBFFFFFFDD7E9FF4B2CDFFFFFFC37A9EF6A8D7FFFFFFFFFFFFFFFFFFB0D0FFFFFFFFD7 +8D7287DAFFFFFFFFB17C779CF6FFFFFFCA7C9AF3ADD0FFFF9FE5BC7A9EFBFFFFFFFB9C85 +D0DBA6FFFFFFFFA6777FC6FFFFB0D0FFFFFFB1ADFFFF5E36FFFFFFFFEDA5BCFFB8C7FFFF +FFC6B9FFF89F9F9F9F9F9FD5FFFF7E1DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4AF8FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF4837FFFFFF6D1BFFFF2626E0FFA6017CFFFF108AFFFFFF453AFFFF5C26FF +FFFFFF581501C2FFFFFFFFFFFFFFFFFFFF2226D8FFFFE7FFE70022E2FFB50183FFFF1F66 +FFFFFF6726FFFFFFB400E5FFFFF100AAFFD21436F8FFFFFFFFFFFFCD00BFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF2ABBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE50AC9FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2088FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF7DB6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFAAC9FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF7B9EFFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF76FAFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF4837FFFFFF6D1BFFFFB91207240039FBFFFF57061843FF453AFFFF5C +26FFFFFFFFCF0229FFFFFFFFFFFFFFFFFFFFFFBC16032E2924FFE70044092B0136FBFFFF +6728FFFFFFBD120D1CC2B400E5FFFFF100AAFF51000B0D0D0D19FFFFFF721CFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFB26A6A6A6A6A6A80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAE6A6A6A6A6A6A84FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2F1FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF89BDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF6CA8FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFA8C0FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFC3BCFFFFFFD2AEFFFFFFE79077A9FFFFFFFFFFF1A9B5FFC2BDFF +FFCCB4FFFFFFFFE80684FFFFFFFFFFFFFFFFFFFFFFFFEF967389DFFFFA9FEAB879A1FDFF +FFFFEC0BB2FFFFFFFFC59FECEA9FFAFFFFFB9FE8FFC69F9F9F9F9FA6FFFFFD1887FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFD8696CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF93E3FFFFFFFFFFFFA04C4C4C4C4C4C66FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9A4C4C4C4C4C4C6BFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8CDFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF71FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF581AF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5F3DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9718FBFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFF386300203CAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF85E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF8097FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF78FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFA90D0B9EFFFFFFDD6A6A6A6A6A6A6AF3FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFF6DBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEAE8 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFF8FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFA645090000002FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFFACBCFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4AF8FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFEDC2FAFFFFFFFFD44C4C4C4C4C4C4CEFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2ABBFFFFFFFFFFFFFFFFFFFFFFFF +FFC359150000000000004BF1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1377DF1F1F1F1F1F1F13D75F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B9EFFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF76FAFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFF +FFFA59000000000000000000020404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404020304040404040404010204 +040404040404040404040404040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +04D8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8C0FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFCC5F170000000000004DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF43C9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8CDFFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1FFFFFFFFFFFFFFFFFFFFFFDAF6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFAA480B0000002EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF +FF71A0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFFFFFFFFFFFFFFFF386302BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFF8FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFF48C340302C6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6A +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF4AF8FFFFFFFFFFFFA8460900009EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2ABBFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0706EFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFF +FFFFFFFFFFAAC9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B9EFFFFFFFFFFFFFFFF +4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF76FAFFFFFFCA5D160000000004FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67D5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6CA8 +FFFFFFFFFFFFFF71A0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8C0FFFFFFFFFFFF +FFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1E858160100000000000010727272727272727272727272727272 +727272727272727272727272727272727272727272727272727272727272727272727272 +727272727272727272727272727272727272727272727272727272727272727272727272 +727272727272727272727272727272727272727272727272727272727272727272727272 +727272727272727272727272727272727272727272727272727272727272727272727272 +727272727272727272727272727272727272727272727272727272727272A3FFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB6EDFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +A8CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFF +FFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBCFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1A62903000000000000000D46464646464646464646464646 +464646464646464646464646464646464646464646464646464646464646464646464646 +464646464646464646464646464646464646464646464646464646464646464646464646 +464646464646464646464646464646464646464646464646464646464646464646464646 +464646464646464646464646464646464646464646464646464646464646464646464646 +464646464646464646464646464646464646464646464646464646464646464680FFFFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF83B9FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3983FFFFFFFFFFFFFFAAC9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFF +FFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFEC7E2B010000000008FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFDFF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF83B9FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672 +FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF4AF8FFFFFFFFFFD4651A000000BBFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF2ABBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB6EDFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +7B9EFFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF76FAFFFFFFFFFFFFFFFFB24E0D3CFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67D5FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF6CA8FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFA8C0FFFFFFFFFFFFFFFF8097FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF56FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFF896F6FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFA8CDFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF4672FFFFFFFFFFFFFFFFACBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFDFF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4AF8FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2ABBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF43C9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF7B9EFFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF24FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF76FAFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFF6FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF83B9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67A4FFFFFFFFFFFFFF71A0FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFA8C0FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAED2FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFAAC9FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFF8FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF85E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF71A0FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4AF8 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2ABBFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF93E3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B9EFFFFFFFFFFFFFFFF4C6AFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +76FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67A4FFFFFFFFFFFF +FFAAC9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8C0FFFFFFFFFFFFFFFF4C6AFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAED2FFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6A +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFECFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF +4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4F4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF48CAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFF +FFFF8097FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF39FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF43F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +2EBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B9EFFFFFFFF +FFFFFFFFACBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF7DFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF67A4FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8C0FFFF +FFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFAED2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672 +FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5CD2FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFD4F4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7F3FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF71A0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFC6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF2EBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF7B9EFFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7DFAFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF67A4FFFFFFFFFFFFFFAAC9FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFA8C0FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0 +ECFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFAED2FFFFFFFFFFFFFF71A0FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF6DD8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF63FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4F4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFAAC9FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43F6FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2EBCFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF7B9EFFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7DFAFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67A4FFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8C0FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF3EC6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAED2FFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF8097FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFFACBCFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4F4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF43F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2EBCFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B9EFFFFFFFFFFFFFFFF4C6A +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF7DFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF79DBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67A4FFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8C0FFFFFFFFFFFFFFFF +4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5CFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF99E5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAED2 +FFFFFFFFFFFFFF71A0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFF +FFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFF +FFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFD4F4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3983FFFFFFFFFFFFFFAAC9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFF +FFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF43F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF2EBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8F6FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3983FFFFFFFFFFFFFF71A0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B9E +FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBCFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF7DFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51CDFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF67A4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +A8C0FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFAED2FFFFFFFFFFFFFFAAC9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFD4F4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43F6FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF2EBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51 +CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF7B9EFFFFFFFFFFFFFFFF8097FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF33FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7DFAFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFD8F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67A4FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFA8C0FFFFFFFFFFFFFFFFACBCFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFDBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAED2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4F4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFA0E8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43F6FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2EBCFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF79DBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF71A0FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF779AFFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7DFA +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67A4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAEC6FFFFFFFFFFFFFFFF4C6AFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAED2FFFFFFFFFFFF +FFAAC9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFF +FFFFFF71A0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6A +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4F4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3EC6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF +4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF43F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2EBC +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983 +FFFFFFFFFFFFFFAAC9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF779AFFFFFFFFFFFF +FFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF7DFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE3D8FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFD4E8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFDBDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +67A4FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAEC6FFFFFFFF +FFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86D7FFFFFF5929FFFF +FFFFFFFFFF963E1E1C3DBFFFFFFFFFFFFFFFE283F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1871FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF3544FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFAED2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFF +FFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDCAF3FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFE3D8FFFFFFFFFFFFFFFFFFDBE8FFFFFFFFFFFFFFDDDFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFCDF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF73DAFFFF0397FFFFFF5929 +FFFFFFFFFFFFFF24417A70200ACDFFFFFFFFFFFFAE00ECFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1871FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF3544FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672 +FFFFFFFFFFFFFFFF7C94FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE500A9FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF5929FFFFFFFFFFFFFFFFEF0DB9FFEF83EAFFFFFF3B44FFFF +FFFFFFFFFF83371B1E47D2FFFFFF2D72FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFD4F4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8EAFFC50377BFC7FF +5929FDBB96E2FFFFFFEDFFFFFFD00269FFFFFFFFFFF68800B1BFD5FFFFC5919ADBFFFFFF +FFFFCD8CA0EDFFFF1871FFFFFFC3D2FFFFFFFFFFFFFFE29E9FE8FFFFFFD5D7FAB09BECFF +FFFFFFED9EB1FA3544FFFFFFE89496D7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +4672FFFFFFFFFFFFFFFFB2C2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE500A9FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF5929FFFFFFFFFFFFFFFF6B2BFFFFD000C6FFFFFF3B44 +FFFFFFFFFFFFFF124C7F651615E8FFFF9313F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF2EBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2901141C +30FF5924330D090AB1FFFFFFFFFFFFFD0A66FFFFFFFFFFCF17001B1C56FF4F0C240D067E +FFFFEF1C0D261826FFFF1871FFFB4B12BCFFFFFFFFFFFF7906100E0D9FFFFF3D35231104 +12CFFFFFBD130412242B44FFFF4A09222004E8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF779AFFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7DFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFC591B6FDFFFFFFBFEFE597B4FFFFFFFFFFD094D2E500A9 +FFFFFFFFFFFFFFFFFFFFE8A490C7FFFF5929FBB69AE8FFFFFFF31093FFFB9F0099BFCFFF +3B44FAAE9BECFFFFFFEDFFFFFFA5008EFFFFFD167AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03 +97FFFFFF590065F6EC2436FFFFFFFFFFFF7C04C0FFFFFFFFFFFFAE00ECFFFFFFC7FAFFFB +6108EAFF701DFDFFFFDBFFFF1871F1351CD4FFFFFFFFFFFFB50284FDF65110EFFF3D0083 +FBE01351FFFF282BD7FA690044FFC704CAFFFFE0FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF67A4FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFAEC6FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFEA37011C022BE7FFFA005C07150041FFFFFF6D0212055A +00A9FFFFFFFFFFFFFFFFFF7B090723088CFF59232C10070DB0FFFF9C02F8FFED1900181C +46FF3B3622120412D0FFFFFFFFFFFFE0008AFFFFFF4B2EFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7F3FF +FF0397FFFFFF5908F3FFFF6517FFFFFFFFFFB00669FFFFFFFFFFFFFFAE00ECFFFFFFFFE2 +A0857801AEFF7710A1FDFFFFFFFF185E242BE8FFFFFFFFFFFFFF4C1EFFFFFFD501A9FF3D +17FFFFFF472DFFDD0083FFFFF40644FFD20275ECFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFAED2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFB2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4F17CDFFD41850FFFA0019C6FF8900BDFFC5026CFA +D72900A9FFFFFFFFFFFFFFFFB5025DEAFFEDDBFF59005AF4E0331BFDFF6B15FFFFFFD000 +C6FFFFFF3B0086FDDF1254FFFFFFFFFFFF590CE0FFFFFF7012FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C +D2FFFF0397FFFFFF5928FFFFFF810EFFFFFFFFB80A4EFFFFFFFFFFFFFFFFAE00ECFFFFFF +6C06142F390291FFEC4B070C51CDFFFF18060AE2FFFFFFFFFFFFFFFF3002040404040489 +FF3D40FFFFFF6024FFB000D0FFFFFF2744FFFF74130436A5FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF71A0FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF4AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF086EFFFFFF6318FFFA0063FFFFF80784FF6507 +F8FFFF7D00A9FFFFFFFFFFFFFFFF5009F6FFFFFFFFFF5902E5FFFF9500B9FF432EFFFFFF +D000C6FFFFFF3B19FFFFFF452FFFFFFFFFFF8F028DFFFFFFFF9A01ECFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4F4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF0397FFFFFF5929FFFFFF810EFFFFFFBD0D47FFFFFFFFFFFFFFFFFFAE00ECFF +FFEF026FFFFFC50091FFFFFFEC8A2618FFFF18642624E7FFFFFFFFFFFFFF3D24FFFFFFFF +FFFFFF3D41FFFFFF6024FFC900A0FFFFFF1044FFFFFFFBA94601C6FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43F6FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDB0003040404040BFFFA00A1FFFFFF1576FF +482BFFFFFFC900A9FFFFFFFFFFFFFFFF3435FFFFFFFFFFFF591CFFFFFFE80091FF3D33FF +FFFFD000C6FFFFFF3B42FFFFFF5D26FFFFFFFF97046FFFFFFFFFFFA400E2FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2EBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF1978FFFFFF5929FFFFFF810EFFFFC30E42FDFFFFFFFFFFFFFFFFFFE001 +C0FFFFDD02A9FFFF5F0091FFFBFFFFFFA402DBFF1871ED2C20E0FFFFFFFFFFFF7800BDFF +FFFFFBFFFF3D41FFFFFF6024FFFA0E56FFFFBF0044FFFBFFFFFFFB0A7DFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFAAC9FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF779AFFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7DFAFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF30177FFFFFFFFFFFFFA00A4FFFFFF15 +76FF5813FFFFFF9A00A9FFFFFFFFFFFFFFFF4418FFFFFFFFFFFF5909FAFFFFB500A8FF62 +1AFFFFFFD000C6FFFFFF3B44FFFFFF5D26FFFFFF9F0666FFFFFFFFFFFF780DFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF4C12445DFF5929FFFFFF810EFFFF1E033739393975FFFFFFFFFFFF +FF201E4A7EFF321A6733200491FF3D3F6F681E41FFFF1871FFF3321CDAFFFFFFFFFFFD30 +073D705514F3FF3D41FFFFFF6024FFFF78013358111844FF7A2B65743711F3FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67A4FFFFFFFFFFFFFF71A0FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFAEC6FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2422FFFFFFFFFBFFFA00A4FFFF +FF1576FF9100C6FFFF5200A9FFFFFFFFFFFFFFFF7F00B9FFFFFFFFFF5900A9FFFF6507E7 +FF9005FDFFFFF607A1FFFFFF3B44FFFFFF5D26FFFFA60760FFFFFFFFFFFFFF5328FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF4DCCFFFFFAAA666BFF9F7BFFFFFFB967FFFF6C5A5A5A5A5A8FFFFFFFFF +FFFFFFED975F8AFFE77A4064E760C3FFAE5A3D4E94EFFFFF6FAEFFFFF66784FFFFFFFFFF +FFFD8149394D91FFFF8A8EFFFFFFA378FFFFFF9A454FB0858FFFD56B43417DD8FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAED2FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF29FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB90C1758693F42FFFA00A4 +FFFFFF1576FFFD260A58332100A9FFFFFFFFFFFFFFFFFD2C043C6F418FFF591412513B01 +67FFFFE207B2FFFFFF30184771FF3B44FFFFFF5D26FFFF0809393939398EFFFFFF2560FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFE2FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFAAC9FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFFFF4C6AFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDD603D3E5FC3FFFD +5ACDFFFFFF6DB1FFFFF4693E62DF5AD0FFFFFFFFFFFFFFFFFFFB7A443D61D8FF9E7CB951 +428DFFFFFFFF513FFFFFFFF39F617DFF898FFFFFFFA179FFFF5A5A5A5A5A5AA5FFFFB409 +E5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4F4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFF3FF4C6AFFF3FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +43F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFD809D7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +4058FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2EBCFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF779AFFFFFFFFFFFF8C9C4C6A7AB2 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF7DFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCDB4B4B4B4B4B4CFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF9FCAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF8CE3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2716EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF93E3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67A4FFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAEC6FFFFFFFFFFFFDD0B514C +0FFDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF78FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF571C1C1C1C1C1C5BFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF88F360402C6FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAED2FFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFFFF25 +0E0C31FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF78FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB14B0C0000002EFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFFFFFF +FF46000071FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +D4F4FFFFFFFFFFFFFFFFFFFFFFFFFFD4651A0000000000004EFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4672FFFFFFFF +FFFFFFA90308E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF43F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF2EBCFFFFFFFFFFFFFFFFFFFFFFFA5900000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000D7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF779AFFFF +FFFFFFFFFFFB0A14FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF7DFAFFFFFFFFFFFFFFFFFFFFFFF8914AF6FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFC258120000000000004EFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3EC6FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF67A4FFFFFFFFFFFFFF71A0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1E32FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2EFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFB44E0D0066FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDA041080000002FFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFAED2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF72AAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFD7671C00000000E5FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF832E0203CAFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFAAC9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFE5FBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFF1832E02000000000011FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFD4F4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7686B +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF71A0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43F6FFFF950600000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000046FFFFFF2EBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67D5FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF44FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7DFAFFFFFFE37424000000000000 +12FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB6 +EDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF67A4FFFFFFFFFFFFFFAAC9FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFB2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFC65B1500 +000001E8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAED2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFA54509006AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFF38745F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4F4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFB6EDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43F6FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2EBCFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF67D5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF56FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7DFAFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67A4FFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAED2FFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4F4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43C9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFF +FFFFFF6C9CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF43F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2EBCFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF7DFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67A4 +FFFFFFFFFFFFFFB1CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +AED2FFFFFFFFFFFFFF6C9CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85E0FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6AFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFD4F4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF93E3FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3983FFFFFFFFFFFFFFB1CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF43F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF2EBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7DFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF67A4FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFECFBFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFAED2FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFD0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF48CAFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF39FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFD4F4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43F6FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2EBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7DFAFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67A4FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5CD2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAED2FFFFFFFFFFFFFF6C9CFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF3EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFC7F3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFA8A1FFFFFFFBA57AE5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +F67AE0FFFFFFFFFFFFFFFFD28EFFFFFFFFFFFFFFE07AF6FFFFFFFFFFFFFFFFF4D8FBFFFF +FFFFBBA1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4F4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFB1CDFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43F6 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFE746D8FFFFFF453AFFFFED0D1F39D2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFE700B2FFFFFFFFFFFFFFFF4158FFFF7681FFFFFFB400E5FFFFFFFFFFFF9A22010004 +4BF6FFFFBD0AE8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2EBCFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF6C +9CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +7DFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFD500C2FFFFFFC9C5FFFF8C13FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFE700B2FFFFFFFFFFFFFFCC06D5FFFF3946FFFFFFB400E5FFFFFFFFFFFF735CB8 +D5750257FFFFFF2B63FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFB0ECFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0 +9AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +85C5FFFFFFFFFFFFFFFFFFFFE88D8AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF8CBCFFFF7AD8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8FBCFFFFFF +FFFFFFFFFF8FD0FFFFFFFFFFFFFF9AB0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7EEAFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67A4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA499D06A56AAFFFFFFFFCC6A +5280F8FFFA64005B728FFFA19BFF933116728381B1FFFFFFFF7DB6FFFFFFFFFFFFFFFFFF +DB734F5FB1FFE700B18E5474F1FFFFFF493CFFFFA11F267272DFB400E2855278F8FFFFFF +FFFFFFFF351FFFFFFF8E0DF1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6DD8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF46C3FFFF +FF532EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF0F78FFFFFFFFFFFFFFFFFF93082D4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1869FFFD00A1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E69FF +FFFFFFFFFFFFC20AE8FFD246EDFFFFFF2F51FFFFFFFFFFFFFF903310049AFFFFFFFF3564 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5D7FFFFFFFF +FFFFFFB1CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4820143A24029CFFFF9E +0715410421F1F644003E4C6FFF453AFF7422104C604B24FFFFFFB900BCFFFFFFFFFFFFFF +FFA50B0D4D432FFFE7002D13440622F6FFFF176FFFFF86171B4C4CD4B400331E3E063CFF +FFFFFFFFFFFF352CFFFFFFDF00ADFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00A0 +FFFFFF532EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF0F78FFFFFFFFFFFFFFFFFF3D4EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1869FFFD00A1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E +69FFFFFFFFFFFFFF404EFFFFB800E0FFFFFF2F51FFFFFFFFFFFFFF7149650097FFFFFFFF +A00DEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4800BBFFFF2939FF +FF1A30F8FFCC0269FFD500C2FFFFFF453AFFFF5C26FFFFBD01BBFFFF4B26FFFFFFFFFFFF +FFFFFB1732F4FFFFFDFFE7002BF8FFD50373FFF10197FFFFFF3946FFFFFFB4004CFFFF83 +01E5FFFFFFFFFFA00294FFFFFFFF0A7CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4F4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB564538AFFFFFFFFFD +8C575487F6FFFFCC6A5280F8FFFFE872E88A53B5FFE575506DE0FFFFFFFFFFFFFFFFFF79 +004F7284FF532ED86D55A3FFFFFF9CA0C76A63FFFFA35D579CFFFFFFE88455517DF8FFFF +FFFF965476E70F78FFFFFFFFFFFFFFFA72103772AAFFFFA65F5699FFFFFFFFF47D5266CC +FFFFFFFF9E5572DF1869FFFD00A1935571ECFFFFFFAD624C65C6FFFFFFFFF681535791FD +FF1E69FFFFF177A3FFCD03CAFFEA5800687299FF2F51C2625ABCFFFFFFFFFFD50097FFFF +FFFFFF1A6DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF43F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF481DFFFFFF5E +20FFE0007AFFFFFF2531FFD500C2FFFFFF453AFFFF5C26FFFFFF284BFFF10A7FFFFFFFFF +FFFFFFFFC90085FFFFFFFFFFE7006BFFFFFF2538FFB200C6FFFFFF3946FFFFFFB400AEFF +FFD800B4FFFFFFFFBF0D4FFFFFFFFFFF2254FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +2EBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF72042C44073BFFFF +F1260236511EC0FF9E0715410421F1FFCA00321348A1C312164C180FCCFFFFFFFFFFFFFF +FF5400364C61FF531C173628018EFFFF3C240E3654FF5204363B0459FFFF6F2A53420C28 +FDFFFF5B00302B200A78FFFFFFFFFFFFFFF84C0C264C90FF5904333D0452FFFFE01D104A +2108AAFFFF6A012B301A1069FFFD002D1145071DEDFFFF1246552006A9FFFFDB1A043E4D +17EFFF1E69FFE0252AE7FF7C0EFFFFE33D00464C7BFF2F2910401C04C0FFFFFFFFD50097 +FFFFFFFFFF4633FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF7DFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4837FFFF +FF6D1BFFBF00B4FFFFFF4A1FFFD500C2FFFFFF453AFFFF5C26FFFFFF850AEF7E0BF3FFFF +FFFFFFFFFFFFA500CCFFFFFFFFFFE7009CFFFFFF4726FFC500B8FFFFFF3946FFFFFFB400 +E5FFFFF100AAFFFFFFC60F3EFDFFFFFFFFFF1C5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD0480FFFFC500 +9AFF5D04D0FFFFFFFDFF1A30F8FFCC0269FFCA003BFBFF3E272CFFFFFF243DFFFFFFFFFF +FFFFFFFF00A0FFFFFF5300A9FFFF332FFFFF3C01C3FFFFA500ACFFFF9502C6FFFBFFFFFF +C7029CFFD2037AFFFF680078FFFFFFFFFFFFFFFFFF1D6AFFFFAE01A1FFFF9F01BCFF4A16 +FBFFFF3E23FFE2076BFFFF770069FFFD0024F4FFDF0667FFFFFBFFFFFF3332FFFF4310E0 +FFFFFFFFFF1E69CA183DF6FFFF5126FFFFFFB800E0FFFFFF2F04DFFFFF1453FFFFFFFFD5 +0097FFFFFFFFFF6817FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF62A0FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4837 +FFFFFF6D1BFFE80071FFFFFF1F35FFDA00BDFFFFFF453AFFFF5C26FFFFFFF60E7C264FFF +FFFFFFFFFFFFFFFFD0007AFFFFFFFFFFE70063FFFFFF1F3BFFFB058AFFFFFF3A45FFFFFF +B400E5FFFFF100AAFFFFCC123AFAFFFFFFFFFFFD0589FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7A06999F9F +9F155FFF2431FFFFFFFFFFE0007AFFFFFF2530FFCA0089FFFFF602599F9F9F4816FFFFFF +FFFFFFFFFFFF00A0FFFFFF5315FFFFFF6B17FFFF3C1DFFFFFF56129F9F9F9B0684FFFFAC +6149460B6DFF8601E0FFFFC60078FFFFFFFFFFFFFFFFFF1D6AFFFF5D0E9F9F9F9E097BFF +13419F9F9F5F03FA9700CCFFFFDB0169FFFD005FFFFFFF2E2FFFFFE27551462815FFFF11 +48FFFFFFFFFFFF1E3E0E54FDFFFFFF2E41FFFFFFB800E0FFFFFF2F33FFFFFF4236FFFFFF +FFD50097FFFFFFFFFF9002F4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFB5D7FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +4837FFFFFF6D1BFFFF2626E0FFA6017CFFFF108AFFFFFF453AFFFF5C26FFFFFFFF581501 +C2FFFFFFFFFFFFFFFFFFFF2226D8FFFFE7FFE70022E2FFB50183FFFF1F66FFFFFF6726FF +FFFFB400E5FFFFF100AAFFD21436F8FFFFFFFFFFFFCD00BFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D062D +2D2D2D2D72FF135FFFFFFFFFFFBF00B4FFFFFF4A1EFFCA00CAFFFFCD00222D2D2D2D36FF +FFFFFFFFFFFFFFFF00A0FFFFFF532EFFFFFF7A13FFFF3C41FFFFFF3E0C2D2D2D2D2D8FFF +61073B5F72125FFF6E10FFFFFFFF0678FFFFFFFFFFFFFFFFFF1D6AFFFF450B2D2D2D2D2D +88FF031C2D2D2D2D2DE87D07FFFFFFFF0E69FFFD008EFFFFFF511EFFCF0B244F6F410CFF +FF027CFFFFFFFFFFFF1E1308B9FFFFFFFF3839FFFFFFB800E0FFFFFF2F51FFFFFF4F31FF +FFFFFFD50097FFFFFFFFFF8506FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF4837FFFFFF6D1BFFFFB91207240039FBFFFF57061843FF453AFFFF5C26FFFFFFFFCF +0229FFFFFFFFFFFFFFFFFFFFFFBC16032E2924FFE70044092B0136FBFFFF6728FFFFFFBD +120D1CC2B400E5FFFFF100AAFF51000B0D0D0D19FFFFFF721CFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFD4F4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B +02D4FFFFFFFFFFFF282AFFFFFFFFFFE80071FFFFFF1F35FFCA00CCFFFFF60264FFFFFFFF +FFFFFFFFFFFFFFFFFFFF019EFFFFFF532EFFFFFF7A13FFFF3C43FFFFFF580BF4FFFFFFFF +FFFF105FFFFFE3035FFF8C00D7FFFFBB0078FFFFFFFFFFFFFFFFFF1D6AFFFF5F09EDFFFF +FFFFFFFF1445FFFFFFFFFFFF9E00C0FFFFD00069FFFD0057FFFFFF2832FF6710F3FFFF44 +0CFFFF1440FFFFFFFFFFFF1E69570BB2FFFFFF5D1FFFFFFFBC00DDFFFFFF2F51FFFFFF4F +31FFFFFFFFD50097FFFFFFFFFF5E1EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFC3BCFFFFFFD2AEFFFFFFE79077A9FFFFFFFFFFF1A9B5FFC2BDFFFFCCB4FFFFFF +FFE80684FFFFFFFFFFFFFFFFFFFFFFFFEF967389DFFFFA9FEAB879A1FDFFFFFFEC0BB2FF +FFFFFFC59FECEA9FFAFFFFFB9FE8FFC69F9F9F9F9FA6FFFFFD1887FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF2EBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFD7094EF4FFFFE2E0FF6F02A8FFFFF4F3FF2726E0FFA8017CFFCA00CCFFFF7E3416D5FF +FFFBC7FFFFFFFFFFFFFFFFFF2070FFFFFF532EFFFFFF7A13FFFF3C43FFFFFFB4026DFBFF +FFD4EFFF1E5CFFFD61005FFFDF0762FDFB520078FFFFFFFFFFFFFFFFFF1D6AFFFFBC0365 +FAFFFFD7ECFF5607C3FFFFFFC6FFEC0B55FBFD5E0069FFFD001CDDFFBF0476FF7C0DF6FF +CA0B0CFFFF530BBBFFFFEAFBFF1E69FF6109A9FFFF8A09FFFFFFF607A3FFFFFF2F51FFFF +FF4F31FFFFFFFFD50097FFFFFFFFFF3D3CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF6C9CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7DFAFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF581AF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F +3DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9718FBFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF930B09342A06A5FFFA3C001B330DC0FFB91207240039FBFFCA00CCFFFF99C626 +0126321245FFFFFFFFFFFFFFFFFF6B071733FF532EFFFFFF7A13FFFF3C43FFFFFFFF7606 +0E362604D5FF7C042A17281C5FFFFF77021B18330D78FFFFFFFFFFFFFFFFFF1D6AFFFFFF +7C070D362604C9FFF336001F35182AFFFF8404171C2A1469FFFD0042072C012FF8FFEF12 +122F08430CFFFFEA2D00223109EFFF1E69FFFF6B07A1FFEA0BA6FFFFFF47061A51FF2F51 +FFFFFF4F31FFFF8C0D0C000A0D60FFFFF40E90FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF62A0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF97FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFA90D0B9EFFFFFFDD6A6A6A6A6A6A6AF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFF6DBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEAE8FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFE0917283CDFFFFFFFFB27A7CB9FFFFFFE79077A9FFFFFFF19FF3FFFFFF +FFFDA5787AA8FBFFFFFFFFFFFFFFFFFFFFF6ADADFFC7B8FFFFFFD7AAFFFFBDC2FFFFFFFF +FFD48A7288DBFFFFFFDD7E9FF4B2CDFFFFFFC37A9EF6A8D7FFFFFFFFFFFFFFFFFFB0D0FF +FFFFFFD78D7287DAFFFFFFFFB17C779CF6FFFFFFCA7C9AF3ADD0FFFF9FE5BC7A9EFBFFFF +FFFB9C85D0DBA6FFFFFFFFA6777FC6FFFFB0D0FFFFFFB1ADFFFF5E36FFFFFFFFEDA5BCFF +B8C7FFFFFFC6B9FFFFDA9F9F9F9F9FC9FFFF7E1DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFB5D7FFFFFFFFFFFFFFB1CDFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFEDC2FAFFFFFFFFD44C4C4C4C4C4C4CEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE50AC9FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2088FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF6C9CFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCAF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFD8F6FFFFFFFFFFFFB26A6A6A6A6A6A80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAE6A6A6A6A6A6A84 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2F1FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7FDFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFBCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3DF6FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33BFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF51CDFFFFFFFFFFFFA04C4C4C4C4C4C66FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9A4C4C4C4C4C +4C6BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFB1CDFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF3EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86FBFFFFFFFF +FFFFFFFFFFFFFFFFFFFFDAF6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFD8696CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62A0FFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFF +FFFFFFFFFFFFFFFFFFF386302BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFF386300203CAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5D7FFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1 +FFFFFFFFFFFFFFFFFFA8460900009EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFA645090000002FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1FFFFFFFFFFFFCA5D160000000004FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCAF3FFFFFFFFFFFF +FFFFFFFFFFFFFFC359150000000000004BF1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F14EC3F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1317DF1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3DF6FFFFFFE858160100000000000010727272727272727272727272727272727272 +727272727272727272727272727272727272727272727272727272727272727272727272 +727272727272727272727272727272727272727272727272727272727272727272727272 +727272727272727272727272727272727272727272727272727272727272727272727272 +727272727272727272727272727272727272727272727272727272727272727272727272 +727272727272727272727272727272727272727272727272727272A3FFFF33BFFFFFFFFF +FFFFFFFFFFFFFFFA59000000000000000000020404040404040404040404040404040404 +040404040404040404040404040404030404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040401030404040404040404040404040404 +040404F3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDBFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF86FBFFFFFFA62903000000000000000D46464646464646464646464646464646 +464646464646464646464646464646464646464646464646464646464646464646464646 +464646464646464646464646464646464646464646464646464646464646464646464646 +464646464646464646464646464646464646464646464646464646464646464646464646 +464646464646464646464646464646464646464646464646464646464646464646464646 +464646464646464646464646464646464646464646464646464646464680FFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFCC5F170000000000004DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62A0FFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FFFFFFFFFFEC7E2B010000000008FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAA480B0000002EFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5D7 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFD4651A000000BBFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF48C340302C6FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0E8FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3983FFFFFFFFFFFFFF6C9CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFB24E0D3CFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFCAF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0706EFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF79DBFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3DF6FFFFFFFFFFFFFFFFFFFFFFFFFFF896F6FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF33BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3983FFFFFFFFFFFFFFB1CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF86FBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF62A0FFFFFFFFFFFFFF6C9CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFB5D7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3EC6FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFB1CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF24FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFCAF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3DF6FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF33BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86FBFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62A0FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF73DAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5D7FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF50FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFA8EAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFA9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCAF3FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3DF6FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33BFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86FB +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFC7F3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62A0FFFFFFFFFFFFFF6C +9CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5CD2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5D7FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4AFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFF +FFFFFFB1CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCAF3FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFF +FFFFFFFFFF6C9CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3DF6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33BF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF86FBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4DCCFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +62A0FFFFFFFFFFFFFFB1CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF29FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2FAFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFB5D7FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFCAF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3DF6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF33BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF93E3FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF78FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86FBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85E0FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF62A0FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF78FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFB5D7FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCAF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF6C9CFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFE7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3DF6FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF3EC6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF2EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86FBFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62A0FFFFFFFFFFFFFFB1CDFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5D7FFFFFFFFFFFFFF6C9CFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCAF3FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF67D5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFB1 +CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3DF6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33BFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFB6EDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF86FBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62A0FFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5D7FFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB6EDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +CAF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62D4FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF56FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3DF6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF33BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE3D8FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFD4E8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFDBDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF86FBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86D7FFFFFF5929 +FFFFFFFFFFFFFFD875452E83FFFFFFFFFFFFFFFFE283F8FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1871FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF3544FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF62A0FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0397FFFFFF +5929FFFFFFFFFFFFFF7E14350660FFFFFFFFFFFFFFFFAE00ECFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1871FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF3544FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFB5D7FFFFFFFFFFFFFF6C9CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43C9FFC50377BF +C7FF5929FDBB96E2FFFFFFFFFFFF0F60FFFFFFFFFFFFFFF68800B1BFD5FFFFC5919ADBFF +FFFFFFFFCD8CA0EDFFFF1871FFFFFFC3D2FFFFFFFFFFFFFFE29E9FE8FFFFFFD5D7FAB09B +ECFFFFFFFFED9EB1FA3544FFFFFFE89496D7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF24FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFCAF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6FDFF2901 +141C30FF5924330D090AB1FFFFFFFFFF0F60FFFFFFFFFFFFFFCF17001B1C56FF4F0C240D +067EFFFFEF1C0D261826FFFF1871FFFB4B12BCFFFFFFFFFFFF7906100E0D9FFFFF3D3523 +110412CFFFFFBD130412242B44FFFF4A09222004E8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFB1CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3DF6FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF33BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF0397FFFFFF590065F6EC2436FFFFFFFFFF0F60FFFFFFFFFFFFFFFFAE00ECFFFFFFC7FA +FFFB6108EAFF701DFDFFFFDBFFFF1871F1351CD4FFFFFFFFFFFFB50284FDF65110EFFF3D +0083FBE01351FFFF282BD7FA690044FFC704CAFFFFE0FAFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFF6FF6C9CFFF6FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86FBFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF0397FFFFFF5908F3FFFF6517FFFFFFFFFF0F60FFFFFFFFFFFFFFFFAE00ECFFFFFF +FFE2A0857801AEFF7710A1FDFFFFFFFF185E242BE8FFFFFFFFFFFFFF4C1EFFFFFFD501A9 +FF3D17FFFFFF472DFFDD0083FFFFF40644FFD20275ECFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF62A0FFFFFFFFFF7EB2FFFF74C5FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF85E0FFFF0397FFFFFF5928FFFFFF810EFFFFFFFFFF0F60FFFFFFFFFFFFFFFFAE00ECFF +FFFF6C06142F390291FFEC4B070C51CDFFFF18060AE2FFFFFFFFFFFFFFFF300204040404 +0489FF3D40FFFFFF6024FFB000D0FFFFFF2744FFFF74130436A5FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5D7FFFFFFFFFFC50B7D5A12FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF93E3FFFF0397FFFFFF5929FFFFFF810EFFFFFFFFFF0F60FFFFFFFFFFFFFFFFAE00 +ECFFFFEF026FFFFFC50091FFFFFFEC8A2618FFFF18642624E7FFFFFFFFFFFFFF3D24FFFF +FFFFFFFFFF3D41FFFFFF6024FFC900A0FFFFFF1044FFFFFFFBA94601C6FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF1F070737FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF87FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCAF3FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF1978FFFFFF5929FFFFFF810EFFFFFFFFFF0F60FFFFFFFFFFFFFFFF +E001C0FFFFDD02A9FFFF5F0091FFFBFFFFFFA402DBFF1871ED2C20E0FFFFFFFFFFFF7800 +BDFFFFFFFBFFFF3D41FFFFFF6024FFFA0E56FFFFBF0044FFFBFFFFFFFB0A7DFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF3A000185FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3DF6FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33BFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF4C12445DFF5929FFFFFF810EFFFFD73939051B3960FFFFFFFF +FFFFFF201E4A7EFF321A6733200491FF3D3F6F681E41FFFF1871FFF3321CDAFFFFFFFFFF +FD30073D705514F3FF3D41FFFFFF6024FFFF78013358111844FF7A2B65743711F3FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF8A010BEFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86FBFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFDCAF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE3D8FFFFFFFFFF +FFFFFFFFDBE8FFFFFFFFFFFFFFDDDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCDF8FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFECFBFFFFFAAA666BFF9F7BFFFFFFB967FFFFE05A5A5A5A5A7DFFFF +FFFFFFFFFFED975F8AFFE77A4064E760C3FFAE5A3D4E94EFFFFF6FAEFFFFF66784FFFFFF +FFFFFFFD8149394D91FFFF8A8EFFFFFFA378FFFFFF9A454FB0858FFFD56B43417DD8FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62A0FFFFFFFFFFFFEF0719FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFE500A9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5929FFFFFF +FFFFFFFFFFEF0DB9FFED83ECFFFFFF3B44FFFFFFFFFFFFFFC76E3E2DA1FFFFFFFF2D72FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF48CAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5D7FFFFFFFFFFFFFF16 +3BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF39FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFE500A9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5929FF +FFFFFFFFFFFFFF6B2BFFFFCF00C7FFFFFF3B44FFFFFFFFFFFFFF5D18370084FFFFFFFF93 +13F8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF +FF5EC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC591B6FD +FFFFFFBFEFE597B4FFFFFFFFFFD094D2E500A9FFFFFFFFFFFFFFFFFFFFE8A490C9FFFF59 +29FBB69AE8FFFFFFF31093FFFB9F0099BFCFFF3B44FAAE9BECFFFFFFFFFFF10084FFFFFF +FFFD167AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCAF3FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFF +FFFFFFDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3DF6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEA36011C +022BE7FFFA005C07150041FFFFFF6D0212055A00A9FFFFFFFFFFFFFFFFFF7B080723088C +FF59232C10070DB0FFFF9C02F8FFED1900181C46FF3B3622120412D2FFFFFFFFF10084FF +FFFFFFFF4B2EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33BFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE87972FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF86FBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4F17 +CDFFD41850FFFA0019C6FF8900BDFFC5026CFAD72900A9FFFFFFFFFFFFFFFFB5025DEAFF +EDDBFF59005AF4E0331BFDFF6B15FFFFFFCF00C7FFFFFF3B0086FDDF1254FFFFFFFFF100 +84FFFFFFFFFF6F12FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB993C0602C2FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5CD2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62A0 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3EFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +076EFFFFFF6318FFFA0063FFFFF80785FF6407F8FFFF7D00A9FFFFFFFFFFFFFFFF5009F6 +FFFFFFFFFF5902E5FFFF9500B9FF432EFFFFFFCF00C7FFFFFF3B19FFFFFF452FFFFFFFFF +F10084FFFFFFFFFF9A01ECFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC52100000002CFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7F3FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +B5D7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC6FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFDA0003040404040BFFFA00A3FFFFFF1576FF482BFFFFFFC900A9FFFFFFFFFFFFFFFF34 +35FFFFFFFFFFFF591CFFFFFFE80091FF3D33FFFFFFCF00C7FFFFFF3B42FFFFFF5D26FFFF +FFFFF10084FFFFFFFFFFA300E2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFDD6D1F0000000000004DFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFF30177FFFFFFFFFFFFFA00A4FFFFFF1576FF5813FFFFFF9A00A9FFFFFFFFFFFFFF +FF4418FFFFFFFFFFFF5909FAFFFFB500A8FF621AFFFFFFCF00C7FFFFFF3B44FFFFFF5D26 +FFFFFFFFF10084FFFFFFFFFF780DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFCAF3FFFFFFFFFFFFFFFFFFFFFFFA590100000000000000000204040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404040404040404 +040404040404040404040404040404040404040404040404040404040404010304040404 +04040404040404040404040404F3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3DF6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF2422FFFFFFFFFBFFFA00A4FFFFFF1576FF9100C6FFFF5100A9FFFFFFFFFF +FFFFFF7F00B9FFFFFFFFFF5900A9FFFF6507E7FF9005FDFFFFF607A1FFFFFF3B44FFFFFF +5D26FFFFFFFFF10084FFFFFFFFFF5328FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF33BFFFFFFFFFFFFFFFFFFFFFFFFFFFB04D0E0000000000004CF1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1A7DFF1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1317DF1F1 +F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86FBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFB90C1758693F42FFFA00A4FFFFFF1576FFFD260A58332100A9FFFFFF +FFFFFFFFFFFD2B043C6F418FFF591412513B0168FFFFE207B4FFFFFF30184771FF3B44FF +FFFF5D26FFFFB5393600243977FFFFFF2560FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA963B0600000030FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6DD8FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF62A0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF63FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFDD603D3E5FC3FFFD5ACDFFFFFF6DB1FFFFF4693E62DF5AD0FF +FFFFFFFFFFFFFFFFFB7A443D61D8FF9E7CB951428DFFFFFFFF513FFFFFFFF39F617DFF89 +8FFFFFFFA179FFFFC55A5A5A5A5A91FFFFB409E5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE87A290104CF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFB5D7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD809D7FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4058FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD +6068FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFCDB4B4B4B4B4B4CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FCAFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8CE3FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFCAF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3DF6FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF571C1C1C1C1C1C5BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF3EC6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF24FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86FBFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62A0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5D7FFFFFFFFFFFFFF5087FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCAF3FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF7EDDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3DF6 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33BFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF99E5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +86FBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62A0FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFFFFFFFFFFFFFFFFFFFF8914AF6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFC9F4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5D7FFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF04F1FFFFFFFFFFFFFFFFB44E0D0066FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFA90A48A9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC6FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FFFFFFFFFFD7671C00000000E5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCAF3 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51CDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B0000175ECAFFFFFFFFFFFFFFFFFFFFFFFFFF3983 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3EFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3DF6FFFFF1832E02000000000011FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +33BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3383FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6200000000012677E7FFFFFFFFFFFFFFFFFFFF +3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF86FBFF9506000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000046FFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF333E6A6A6A6A6A6A +6A6A6A6A6A6A6A6A6A6A6A6A6A6A6A6A6A6A6A4200000000000000031E90FAFFFFFFFFFF +FFFF62A0FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFE3742400000000000012FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF774C4C4C4C4C +4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C320000000000000000127EEFFFFFFF +FFFFFFFFB5D7FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFC65B1500000001E8FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF57D0FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6600000000001A65D4FFFFFFFF +FFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFA54509006AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFCAF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0F4FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3200000C4BB1FFFFFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFDBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3DF6FFFFFFFFFFFFFFFFFFFFF38745F6FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF33BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB804368FF6FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86FBFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB9E2FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF5C9CFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0 +E8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0975FFFFFFFF581CFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFBCDAFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF79DBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0472FFFFFFFF5417FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCAF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0472FFFFFFFF5417FFFF +9CA0CA6758B2FFFFFFFFB25969CD96A3FFFF77CDFFFFFF89B5FFFFFFBD675184FDFFFFB8 +87FFFFFFCF76FFFFFFFA835363C3FFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3DF6FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33BFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0472FFFFFFFF5417 +FFFF3C24123D2002ADFFFF8D031E3C101C46FFFF0790FFFFFF2066FFFF7E0529470930FD +FF6A1DFFFFFF9504FFFFEC230D4725069BFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86FBFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0472FFFFFFFF +5417FFFF3C01CCFFFF1F45FFFB1449FFFFA30046FFFF0790FFFFFF2066FFDB0870FFFFD7 +0287FF6A1DFFFFFF9504FFFF580EF4FFFF4B18FFFFFF5C9CFFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF3AC5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0472FFFF +FFFF5417FFFF3C27FFFFFF512AFFCC0099FFFFFD0B46FFFF0790FFFFFF2066FF8A02919F +9F9F1C51FF6A1DFFFFFF9504FFFF1E389F9F9F6B00E7FFFFBCDAFFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0960 +FFFFFFFF451BFFFF3C43FFFFFF5E25FFAA00D7FFFFFF2746FFFF0790FFFFFF2066FF6D04 +2D2D2D2D2D67FF6A1DFFFFFF9404FFFF0C192D2D2D2D2DD5FFFF3983FFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCAF3FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1D2DFFFFFFFF1833FFFF3C43FFFFFF5E25FFD2008FFFFFF80746FFFF0D77FFFFF10766FF +8D00C0FFFFFFFFFFFF740FFFFFFF6204FFFF1E38FFFFFFFFFFFFFFFF3983FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3DF6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33BFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF5707B1FFFD9A0077FFFF3C43FFFFFF5E25FFFF1C3AF1FF840046FFFF2634FDFF7400 +66FFE30E43EFFFFFE8DAFFA100B0FFE21B04FFFF6503B6FFFFFFC5FFFFFF3983FFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF86FBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF73DAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFE82A001712003DFBFFFF3C43FFFFFF5E25FFFFA50A0E24192446FFFF94031518 +2B1A66FFFFA00E07332B0793FFFD270226084804FFFFFA3F001C361A1EFFFFFF5C9CFFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8EAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFAD7B80B9FFFFFFFFBDC2FFFFFFCCB4FFFFFFD8818FE73346FFFFFFBD +789AF3B1CFFFFFFFE7947281C7FFFFFFF68C7CC6E0A3FFFFFFFFB87E7597F3FFFFFFBCDA +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3346FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFC0EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3346 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF37F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF38C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7F3FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF8FFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5CD2FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF5C9CFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4A +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFBCDAFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFC0EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37F6FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF38C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D +CCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF29FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8FFBFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFE2FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C9CFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBCDAFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0EFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF93E3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF78FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37F6FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF38C0FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF85E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF78FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8FFB +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C9CFFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBCDAFFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0EFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3EC6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2EFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF37F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF38C0 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF8FFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +5C9CFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFBCDAFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67D5FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4AFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFC0EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB6EDFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF38C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8FFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF5C9CFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFF1FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFBCDAFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62 +D4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF56FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37F6FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF38C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8FFBFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C9CFFFFFFFFFFFFFF3F7AFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF43C9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBCDAFFFFFFFFFFFFFF3F7AFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFF6FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0EFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F +7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +37F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF38C0FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF +FF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF8FFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C9CFFFFFFFF +FFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6AFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8CE2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBCDAFFFF +FFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983 +FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +C0EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF37F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF38C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFECFBFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF8FFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF48CAFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF5C9CFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF39FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFBCDAFFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFC0EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37F6FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF38C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5CD2FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFFFF3F7AFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF3EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8FFBFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7 +F3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF5C9CFFFFFFFFFFB2FF3F7AE2CAFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFC6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBCDAFFFFFFFFFF8F343F701CEFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFEF10121424FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0EFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFB0ECFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF2B010052FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37F6FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF38C0FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF6DD8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3983FFFFFFFFFFFF570006C2FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8FFBFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C9CFFFFFFFFFFFFC50411FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0A +21FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF2F7CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0EFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3EC6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF9CEDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF37F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF38C0FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF8FFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7EDDFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5CFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFC0EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF99E5FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF37F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF38C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8FFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8F6FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFC6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51CDFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF3EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFC0EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37F6FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF38C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8FFBFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF57D0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF33FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFD0F4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0EFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37F6 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF38C0FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +8FFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFA0E8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF79DBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6AFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0EF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF37F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +38C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF8FFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3EC6FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFC0EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF38C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF73DAFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF50FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8FFBFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8EAFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFC7F3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFB2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37F6FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF38C0FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF57D0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF4AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8FFBFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0EFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF4DCCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF29FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF37F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF38C0FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF8FFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF93E3FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF78FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFC0EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85E0FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF78FFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF37F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF38C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF8FFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFE7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3EC6FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF2EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFC0EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37F6FFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF38C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8FFBFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04F1FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF67D5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF4AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5EF8FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFB6EDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFB2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB8EDFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3DC3FFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1CB4FFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFBFF1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF62D4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF56FFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43C9FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24FFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6FDFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8CE2FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF6AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8CE2FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF87FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFECFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFD0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF48CAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFF33FFFFDD7EFFFFFF76EAFFFFB49FFFFFFF6AFFFFFF90C5FFFF +D087FFFFFF6EF1FFFFA9A9FFFFF172FFFFFF87D0FFFFC590FFFFFF6AFFFFFF9FB4FFFFEA +76FFFFFF7EDDFFFFBF95FFFFFF6AFFFFFF95B9FFFFDD7EFFFFFF76EAFFFFB49FFFFFFF6A +FFFFFF90C5FFFFD087FFFFFF72F1FFFFA9A9FFFFF16EFFFFFF87D0FFFFC590FFFFFF6AFF +FFFF9FB4FFFFEA76FFFFFF7EDDFFFFBF95FFFFFF6AFFFFFF9AB9FFFFDD7EFFFFFF76E3FF +FFB49FFFFFFF6AFFFFFF90C5FFFFD087FFFFFF72F1FFFFA9A9FFFFF86EFFFFFF87D0FFFF +C58CFFFFFF6AFFFFFF9FB4FFFFEA76FFFFFF7EDDFFFFBF95FFFFFF6AFFFFFF9AB9FFFFDD +7EFFFFFF7AE3FFFFB49FFFFFFF66FFFFFF90C5FFFFD087FFFFFF72F1FFFFA9A9FFFFF86E +FFFFFF87D0FFFFCA8CFFFFFF6AFFFFFF9FAEFFFFEA76FFFFFF7EDDFFFFBF95FFFFFF6AFF +FFFF9AB9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE393FFFFFF8AEFFFFFC0AEFFFFFF7FFFFFFFA3CF +FFFFDA9AFFFFFF84F4FFFFB8B8FFFFF487FFFFFF9ADAFFFFCFA3FFFFFF7FFFFFFFAEC0FF +FFEF8AFFFFFF93E3FFFFCAA6FFFFFF7FFFFFFFA6C6FFFFE393FFFFFF8AEFFFFFC0AEFFFF +FF7FFFFFFFA3CFFFFFDA9AFFFFFF87F4FFFFB8B8FFFFF484FFFFFF9ADAFFFFCFA3FFFFFF +7FFFFFFFAEC0FFFFEF8AFFFFFF93E3FFFFCAA6FFFFFF7FFFFFFFAAC6FFFFE393FFFFFF8A +E8FFFFC0AEFFFFFF7FFFFFFFA3CFFFFFDA9AFFFFFF87F4FFFFB8B8FFFFFA84FFFFFF9ADA +FFFFCF9EFFFFFF7FFFFFFFAEC0FFFFEF8AFFFFFF93E3FFFFCAA6FFFFFF7FFFFFFFAAC6FF +FFE393FFFFFF8EE8FFFFC0AEFFFFFF7CFFFFFFA3CFFFFFDA9AFFFFFF87F4FFFFB8B8FFFF +FA84FFFFFF9ADAFFFFD49EFFFFFF7FFFFFFFAEBCFFFFEF8AFFFFFF93E3FFFFCAA6FFFFFF +7FFFFFFFAAC6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5200FF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFF5200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +end +%%PageTrailer +%%Trailer +%%EOF diff --git a/doc/img/ecore_thread_feedback.png b/doc/img/ecore_thread_feedback.png new file mode 100644 index 0000000000000000000000000000000000000000..4d75dbbf3ecfe0ba350d2d9eca2f468653533151 GIT binary patch literal 116002 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 OY5cTt5o7-N`~Lx`-az;O literal 0 HcmV?d00001 diff --git a/doc/img/edoxy.css b/doc/img/edoxy.css new file mode 100644 index 0000000..311ca23 --- /dev/null +++ b/doc/img/edoxy.css @@ -0,0 +1,486 @@ +/* + * This file contain a custom doxygen style to match e.org graphics + */ + + + +/* BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV { + font-family: Geneva, Arial, Helvetica, sans-serif; +}*/ +BODY, TD { + font-size: 12px; +} +H1 { + text-align: center; + font-size: 160%; +} +H2 { + font-size: 120%; +} +H3 { + font-size: 100%; +} +CAPTION { + font-weight: bold +} +DIV.qindex { + width: 100%; + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + padding: 2px; + line-height: 140%; +} +DIV.navpath { + width: 100%; + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + padding: 2px; + line-height: 140%; +} +DIV.navtab { + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} +TD.navtab { + font-size: 70%; +} +A.qindex { + text-decoration: none; + font-weight: bold; + color: #1A419D; +} +A.qindex:visited { + text-decoration: none; + font-weight: bold; + color: #1A419D +} +A.qindex:hover { + text-decoration: none; + background-color: #ddddff; +} +A.qindexHL { + text-decoration: none; + font-weight: bold; + background-color: #6666cc; + color: #ffffff; + border: 1px double #9295C2; +} +A.qindexHL:hover { + text-decoration: none; + background-color: #6666cc; + color: #ffffff; +} +A.qindexHL:visited { + text-decoration: none; + background-color: #6666cc; + color: #ffffff +} +A.el { + text-decoration: none; + font-weight: bold +} +A.elRef { + font-weight: bold +} +A.code:link { + text-decoration: none; + font-weight: normal; + color: #0000FF +} +A.code:visited { + text-decoration: none; + font-weight: normal; + color: #0000FF +} +A.codeRef:link { + font-weight: normal; + color: #0000FF +} +A.codeRef:visited { + font-weight: normal; + color: #0000FF +} +A:hover, A:visited:hover { + text-decoration: none; + /* background-color: #f2f2ff; */ + color: #000055; +} +A.anchor { + color: #000; +} +DL.el { + margin-left: -1cm +} +.fragment { + font-family: monospace, fixed; + font-size: 95%; +} +PRE.fragment { + border: 1px solid #CCCCCC; + background-color: #f5f5f5; + margin-top: 4px; + margin-bottom: 4px; + margin-left: 2px; + margin-right: 8px; + padding-left: 6px; + padding-right: 6px; + padding-top: 4px; + padding-bottom: 4px; +} +DIV.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px +} + +DIV.groupHeader { + margin-left: 16px; + margin-top: 12px; + margin-bottom: 6px; + font-weight: bold; +} +DIV.groupText { + margin-left: 16px; + font-style: italic; + font-size: 90% +} +/*BODY { + background: white; + color: black; + margin-right: 20px; + margin-left: 20px; +}*/ +TD.indexkey { + background-color: #e8eef2; + font-weight: bold; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #CCCCCC; +} +TD.indexvalue { + background-color: #e8eef2; + font-style: italic; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #CCCCCC; +} +TR.memlist { + background-color: #f0f0f0; +} +P.formulaDsp { + text-align: center; +} +IMG.formulaDsp { +} +IMG.formulaInl { + vertical-align: middle; +} +SPAN.keyword { color: #008000 } +SPAN.keywordtype { color: #604020 } +SPAN.keywordflow { color: #e08000 } +SPAN.comment { color: #800000 } +SPAN.preprocessor { color: #806020 } +SPAN.stringliteral { color: #002080 } +SPAN.charliteral { color: #008080 } +SPAN.vhdldigit { color: #ff00ff } +SPAN.vhdlchar { color: #000000 } +SPAN.vhdlkeyword { color: #700070 } +SPAN.vhdllogic { color: #ff0000 } + +.mdescLeft { + padding: 0px 8px 4px 8px; + font-size: 80%; + font-style: italic; + background-color: #FAFAFA; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.mdescRight { + padding: 0px 8px 4px 8px; + font-size: 80%; + font-style: italic; + background-color: #FAFAFA; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.memItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplParams { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + color: #606060; + background-color: #FAFAFA; + font-size: 80%; +} +.search { + color: #003399; + font-weight: bold; +} +FORM.search { + margin-bottom: 0px; + margin-top: 0px; +} +INPUT.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +TD.tiny { + font-size: 75%; +} +a { + color: #1A41A8; +} +a:visited { + color: #2A3798; +} +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #84b0c7; +} +TH.dirtab { + background: #e8eef2; + font-weight: bold; +} +HR { + height: 1px; + border: none; + border-top: 1px solid black; +} + +/* Style for detailed member documentation */ +.memtemplate { + font-size: 80%; + color: #606060; + font-weight: normal; + margin-left: 3px; +} +.memnav { + background-color: #eeeeee; + border: 1px solid #dddddd; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} +.memitem { + padding: 4px; + background-color: #eeeeee; + border-width: 1px; + border-style: solid; + border-color: #dddddd; + -moz-border-radius: 4px 4px 4px 4px; +} +.memname { + white-space: nowrap; + font-weight: bold; + color: #ffffff; +} +.memdoc{ + padding-left: 10px; +} +.memproto { + background-color: #111111; + width: 100%; + border-width: 1px; + border-style: solid; + border-color: #000000; + font-weight: bold; + -moz-border-radius: 4px 4px 4px 4px; +} +.paramkey { + text-align: right; + color: #ffffff; +} +.paramtype { + white-space: nowrap; + color: #aaaaaa; +} +.paramname { + color: #ff0000; + font-style: italic; + white-space: nowrap; +} +/* End Styling for detailed member documentation */ + +/* for the tree view */ +.ftvtree { + font-family: sans-serif; + margin:0.5em; +} +/* these are for tree view when used as main index */ +.directory { + font-size: 9pt; + font-weight: bold; +} +.directory h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +/* The following two styles can be used to replace the root node title */ +/* with an image of your choice. Simply uncomment the next two styles, */ +/* specify the name of your image and be sure to set 'height' to the */ +/* proper pixel height of your image. */ + +/* .directory h3.swap { */ +/* height: 61px; */ +/* background-repeat: no-repeat; */ +/* background-image: url("yourimage.gif"); */ +/* } */ +/* .directory h3.swap span { */ +/* display: none; */ +/* } */ + +.directory > h3 { + margin-top: 0; +} +.directory p { + margin: 0px; + white-space: nowrap; +} +.directory div { + display: none; + margin: 0px; +} +.directory img { + vertical-align: -30%; +} +/* these are for tree view when not used as main index */ +.directory-alt { + font-size: 100%; + font-weight: bold; +} +.directory-alt h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} +.directory-alt > h3 { + margin-top: 0; +} +.directory-alt p { + margin: 0px; + white-space: nowrap; +} +.directory-alt div { + display: none; + margin: 0px; +} +.directory-alt img { + vertical-align: -30%; +} + diff --git a/doc/img/foot_bg.png b/doc/img/foot_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..b24f3a48b4e076b88cf1e802b46087ffbb3fabd5 GIT binary patch literal 173 zcmeAS@N?(olHy`uVBq!ia0vp^j6iJ9!3HE1Qx}DR1d4;)ofy`glX(f`uqAoByD;nl zL8a%*b^=8>3p^r=85p>QL70(Y)*K0-AbW|YuPgga7CvEi%SZD}LFVdux;TbNTu#2R zIsJTn+kYTPulo1Ll3AD;2!xfDmD#wLvj}>v&@k-CVP=T_%(cphxuXQAk-^i|&t;uc GLK6Ub>Mc;VkfoEM{Qf z76xHPhFNnYfP(BLp1!W^H+WcuRXD>A=l%i;Wq7(chG?8W+i%Esz<`6f_y7NWHH!5o z63R1{^0cb0vMSkFaE_%x<+7O{*?Xs&Ff%xKT5jO&GtAqcqoa~}b>qg&H07ky z617wnX2HUfTT*8{kPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iOZ8 z6%`IG`XD&~00I3;L_t(o!^Kz8j>8}fODg_+AF{uksuh}hxC0rJP`W$mkkHl^jB%XM z>f`Y+`Dtd>`gxwMmr`2KIk$cshdiH8N#}XW6$o}5WA?p%5)sKc%eHO9fR!#HlFUqU z&XQ6Z1~3DUmCHm#rjx?$lu|lm24QA+Eh4g2CJ}X<;QbGo;J_$CohD|s1Tu}z3KIrH zRtpQ8-Z|UyQP4caCB~&Z3QG0mMzcQLYIcQ!(sFW-xf9knF@|(?iY~XAOhHzd%#8OD2m>x}XSSsVf@;^obfpX48<@ZgFF$M4@xtjbM#B=Ojp!9yfFNKXj22K7STvD?00000NkvXXu0mjfB76)l literal 0 HcmV?d00001 diff --git a/doc/img/header_menu_current_background.png b/doc/img/header_menu_current_background.png new file mode 100644 index 0000000000000000000000000000000000000000..de97c9268e4ac68310c8b92d6ab6bd8a245611da GIT binary patch literal 1200 zcmV;h1W)^kP)002J-1^@s6XaB>y00001b5ch_0Itp) z=>Px#32;bRa{vGf6951U69E94oEQKA00(qQO+^RT3Fc5TrKj#zpOzs?z2=A0p@aw&u*pMn|G)ug+?Vh;0+zHe5dVLoF=!DBW&zJ?E zp99|S_j0@4%Io#|xG+sqdB5NP{rn5Cj%O+78UIn|DpKcsK9>`B2V6JsOB3oD&r;4a z{-e%Sw9ela{A&{jdu5*U-Tgr1~ zQc-ZvZCmQQrCnTG+COg8zWQ3Lv1sjNIKQPlR|Xsq_}(oT0MbDS91lPg3>xeBFKokrh3I+f~!N36>5GNtP zFb=56FWNP#oK=?bNEQ~!rtXW9X1GX=k~FL`OjOeF$R)LGB-wAZi(5xddgID^{pUl5 z$!2zVWE!iC5c%CAFL=jfl{TW1M$7Wjcr9z}SyPKmlC20r0B}G6Q80PClsJ^eQ9Rdb zuHflIJ5saoBdvW)J5o7`LrQ$sb0li*FS@pt^@$vLe#kJ^<1ntHwKLacEE8!V_VYY{ z^jk0Fa-9o0ILfhhgnDcg*`~%yk#UNgFLkMLQ1xp&>oHLMt>=krgKLZ9aoj&)eVyWk z+VI9yb#%knV zBgOT1iW^1q->g9a$6utrxv^4Ql-s5#yS%xS5>LwpJyaYZ1w-06F426k%%gi2p;YTL zn*Zi$*TU&q<}Gq{z5F%GPa}Dt9$}k233)sorIb>h&nNZ+VE-)`LNtIN1b_p=0f8Pk zSwvore6GJZg3A%uh&UU`%8A$z3ApNcvGym`^9BW5y;mkO7OVYaI#wj=im2;bzSt*w z8j*3rXhhk-tiA%ik?Y6P7yM_$}>d^Cl%aa8a!%A!J=gv)gqCjA%RAmjShY zk&jin$jBj)wrhPzE#o_v^@kLW;DnK~k;Uxogc+{8mlL+=3tKP%4hR4$2Lynj z95C}RO)LJ$<@I?2i7h|tH#%lcU&}tk-(ol0<1_foFDdWsgqjV%=7cRA;M<%KLNw4f z2!R6vT{&RuTk7799C>JZ4;!>{ThW;;ZOYD_SA%VO2ZR&C3B68;Eg1NXEf@e0gaF^` zfS#=57JO;X{zkCF($|*uL^8|wn48N;fkQ7R9I3CpA0+QRH%LYRy5b)R!`g7p731Il O0000002J-1^@s6XaB>y00001b5ch_0Itp) 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/PUT + }ifelse + pdfmark_5 + }forall +}bdf +/lmt{ + dup 2 index le{exch}if pop dup 2 index ge{exch}if pop +}bdf +/int{ + dup 2 index sub 3 index 5 index sub div 6 -2 roll sub mul exch pop add exch pop +}bdf +/ds{ + Adobe_AGM_Utils begin +}bdf +/dt{ + currentdict Adobe_AGM_Utils eq{ + end + }if +}bdf +systemdict/setpacking known +{setpacking}if +%%EndResource +%%BeginResource: procset Adobe_AGM_Core 2.0 0 +%%Version: 2.0 0 +%%Copyright: Copyright(C)1997-2007 Adobe Systems, Inc. All Rights Reserved. +systemdict/setpacking known +{ + currentpacking + true setpacking +}if +userdict/Adobe_AGM_Core 209 dict dup begin put +/Adobe_AGM_Core_Id/Adobe_AGM_Core_2.0_0 def +/AGMCORE_str256 256 string def +/AGMCORE_save nd +/AGMCORE_graphicsave nd +/AGMCORE_c 0 def +/AGMCORE_m 0 def +/AGMCORE_y 0 def +/AGMCORE_k 0 def +/AGMCORE_cmykbuf 4 array def +/AGMCORE_screen[currentscreen]cvx def +/AGMCORE_tmp 0 def +/AGMCORE_&setgray nd +/AGMCORE_&setcolor nd +/AGMCORE_&setcolorspace nd +/AGMCORE_&setcmykcolor nd +/AGMCORE_cyan_plate nd +/AGMCORE_magenta_plate nd +/AGMCORE_yellow_plate nd +/AGMCORE_black_plate nd +/AGMCORE_plate_ndx nd +/AGMCORE_get_ink_data nd +/AGMCORE_is_cmyk_sep nd +/AGMCORE_host_sep nd +/AGMCORE_avoid_L2_sep_space nd +/AGMCORE_distilling nd +/AGMCORE_composite_job nd +/AGMCORE_producing_seps nd +/AGMCORE_ps_level -1 def +/AGMCORE_ps_version -1 def +/AGMCORE_environ_ok nd +/AGMCORE_CSD_cache 0 dict def +/AGMCORE_currentoverprint false def +/AGMCORE_deltaX nd +/AGMCORE_deltaY nd +/AGMCORE_name nd +/AGMCORE_sep_special nd +/AGMCORE_err_strings 4 dict def +/AGMCORE_cur_err nd +/AGMCORE_current_spot_alias false def +/AGMCORE_inverting false def +/AGMCORE_feature_dictCount nd +/AGMCORE_feature_opCount nd +/AGMCORE_feature_ctm nd +/AGMCORE_ConvertToProcess false def +/AGMCORE_Default_CTM matrix def +/AGMCORE_Default_PageSize nd +/AGMCORE_Default_flatness nd +/AGMCORE_currentbg nd +/AGMCORE_currentucr nd +/AGMCORE_pattern_paint_type 0 def +/knockout_unitsq nd +currentglobal true setglobal +[/CSA/Gradient/Procedure] +{ + /Generic/Category findresource dup length dict copy/Category defineresource pop +}forall +setglobal +/AGMCORE_key_known +{ + where{ + /Adobe_AGM_Core_Id known + }{ + false + }ifelse +}ndf +/flushinput +{ + save + 2 dict begin + /CompareBuffer 3 -1 roll def + /readbuffer 256 string def + mark + { + currentfile readbuffer{readline}stopped + {cleartomark mark} + { + not + {pop exit} + if + CompareBuffer eq + {exit} + if + }ifelse + }loop + cleartomark + end + restore +}bdf +/getspotfunction +{ + AGMCORE_screen exch pop exch pop + dup type/dicttype eq{ + dup/HalftoneType get 1 eq{ + /SpotFunction get + }{ + dup/HalftoneType get 2 eq{ + /GraySpotFunction get + }{ + pop + { + abs exch abs 2 copy add 1 gt{ + 1 sub dup mul exch 1 sub dup mul add 1 sub + }{ + dup mul exch dup mul add 1 exch sub + }ifelse + }bind + }ifelse + }ifelse + }if +}def +/np +{newpath}bdf +/clp_npth +{clip np}def +/eoclp_npth +{eoclip np}def +/npth_clp +{np clip}def +/graphic_setup +{ + /AGMCORE_graphicsave save store + concat + 0 setgray + 0 setlinecap + 0 setlinejoin + 1 setlinewidth + []0 setdash + 10 setmiterlimit + np + false setoverprint + false setstrokeadjust + //Adobe_AGM_Core/spot_alias gx + /Adobe_AGM_Image where{ + pop + Adobe_AGM_Image/spot_alias 2 copy known{ + gx + }{ + pop pop + }ifelse + }if + /sep_colorspace_dict null AGMCORE_gput + 100 dict begin + /dictstackcount countdictstack def + /showpage{}def + mark +}def +/graphic_cleanup +{ + cleartomark + dictstackcount 1 countdictstack 1 sub{end}for + end + AGMCORE_graphicsave restore +}def +/compose_error_msg +{ + grestoreall initgraphics + /Helvetica findfont 10 scalefont setfont + /AGMCORE_deltaY 100 def + /AGMCORE_deltaX 310 def + clippath pathbbox np pop pop 36 add exch 36 add exch moveto + 0 AGMCORE_deltaY rlineto AGMCORE_deltaX 0 rlineto + 0 AGMCORE_deltaY neg rlineto AGMCORE_deltaX neg 0 rlineto closepath + 0 AGMCORE_&setgray + gsave 1 AGMCORE_&setgray fill grestore + 1 setlinewidth gsave stroke grestore + currentpoint AGMCORE_deltaY 15 sub add exch 8 add exch moveto + /AGMCORE_deltaY 12 def + /AGMCORE_tmp 0 def + AGMCORE_err_strings exch get + { + dup 32 eq + { + pop + AGMCORE_str256 0 AGMCORE_tmp getinterval + stringwidth pop currentpoint pop add AGMCORE_deltaX 28 add gt + { + currentpoint AGMCORE_deltaY sub exch pop + clippath pathbbox pop pop pop 44 add exch moveto + }if + AGMCORE_str256 0 AGMCORE_tmp getinterval show( )show + 0 1 AGMCORE_str256 length 1 sub + { + AGMCORE_str256 exch 0 put + }for + /AGMCORE_tmp 0 def + }{ + AGMCORE_str256 exch AGMCORE_tmp xpt + /AGMCORE_tmp AGMCORE_tmp 1 add def + }ifelse + }forall +}bdf +/AGMCORE_CMYKDeviceNColorspaces[ + [/Separation/None/DeviceCMYK{0 0 0}] + [/Separation(Black)/DeviceCMYK{0 0 0 4 -1 roll}bind] + [/Separation(Yellow)/DeviceCMYK{0 0 3 -1 roll 0}bind] + [/DeviceN[(Yellow)(Black)]/DeviceCMYK{0 0 4 2 roll}bind] + [/Separation(Magenta)/DeviceCMYK{0 exch 0 0}bind] + [/DeviceN[(Magenta)(Black)]/DeviceCMYK{0 3 1 roll 0 exch}bind] + [/DeviceN[(Magenta)(Yellow)]/DeviceCMYK{0 3 1 roll 0}bind] + [/DeviceN[(Magenta)(Yellow)(Black)]/DeviceCMYK{0 4 1 roll}bind] + [/Separation(Cyan)/DeviceCMYK{0 0 0}] + [/DeviceN[(Cyan)(Black)]/DeviceCMYK{0 0 3 -1 roll}bind] + [/DeviceN[(Cyan)(Yellow)]/DeviceCMYK{0 exch 0}bind] + [/DeviceN[(Cyan)(Yellow)(Black)]/DeviceCMYK{0 3 1 roll}bind] + [/DeviceN[(Cyan)(Magenta)]/DeviceCMYK{0 0}] + [/DeviceN[(Cyan)(Magenta)(Black)]/DeviceCMYK{0 exch}bind] + [/DeviceN[(Cyan)(Magenta)(Yellow)]/DeviceCMYK{0}] + [/DeviceCMYK] +]def +/ds{ + Adobe_AGM_Core begin + /currentdistillerparams where + { + pop currentdistillerparams/CoreDistVersion get 5000 lt + {<>setdistillerparams}if + }if + /AGMCORE_ps_version xdf + /AGMCORE_ps_level xdf + errordict/AGM_handleerror known not{ + errordict/AGM_handleerror errordict/handleerror get put + errordict/handleerror{ + Adobe_AGM_Core begin + $error/newerror get AGMCORE_cur_err null ne and{ + $error/newerror false put + AGMCORE_cur_err compose_error_msg + }if + $error/newerror true put + end + errordict/AGM_handleerror get exec + }bind put + }if + /AGMCORE_environ_ok + ps_level AGMCORE_ps_level ge + ps_version AGMCORE_ps_version ge and + AGMCORE_ps_level -1 eq or + def + AGMCORE_environ_ok not + {/AGMCORE_cur_err/AGMCORE_bad_environ def}if + /AGMCORE_&setgray systemdict/setgray get def + level2{ + /AGMCORE_&setcolor systemdict/setcolor get def + /AGMCORE_&setcolorspace systemdict/setcolorspace get def + }if + /AGMCORE_currentbg currentblackgeneration def + /AGMCORE_currentucr currentundercolorremoval def + /AGMCORE_Default_flatness currentflat def + /AGMCORE_distilling + /product where{ + pop systemdict/setdistillerparams known product(Adobe PostScript Parser)ne and + }{ + false + }ifelse + def + /AGMCORE_GSTATE AGMCORE_key_known not{ + /AGMCORE_GSTATE 21 dict def + /AGMCORE_tmpmatrix matrix def + /AGMCORE_gstack 32 array def + /AGMCORE_gstackptr 0 def + /AGMCORE_gstacksaveptr 0 def + /AGMCORE_gstackframekeys 14 def + /AGMCORE_&gsave/gsave ldf + /AGMCORE_&grestore/grestore ldf + /AGMCORE_&grestoreall/grestoreall ldf + /AGMCORE_&save/save ldf + /AGMCORE_&setoverprint/setoverprint ldf + /AGMCORE_gdictcopy{ + begin + {def}forall + end + }def + /AGMCORE_gput{ + AGMCORE_gstack AGMCORE_gstackptr get + 3 1 roll + put + }def + /AGMCORE_gget{ + AGMCORE_gstack AGMCORE_gstackptr get + exch + get + }def + /gsave{ + AGMCORE_&gsave + AGMCORE_gstack AGMCORE_gstackptr get + AGMCORE_gstackptr 1 add + dup 32 ge{limitcheck}if + /AGMCORE_gstackptr exch store + AGMCORE_gstack AGMCORE_gstackptr get + AGMCORE_gdictcopy + }def + /grestore{ + AGMCORE_&grestore + AGMCORE_gstackptr 1 sub + dup AGMCORE_gstacksaveptr lt{1 add}if + dup AGMCORE_gstack exch get dup/AGMCORE_currentoverprint known + {/AGMCORE_currentoverprint get setoverprint}{pop}ifelse + /AGMCORE_gstackptr exch store + }def + /grestoreall{ + AGMCORE_&grestoreall + /AGMCORE_gstackptr AGMCORE_gstacksaveptr store + }def + /save{ + AGMCORE_&save + AGMCORE_gstack AGMCORE_gstackptr get + AGMCORE_gstackptr 1 add + dup 32 ge{limitcheck}if + /AGMCORE_gstackptr exch store + /AGMCORE_gstacksaveptr AGMCORE_gstackptr store + AGMCORE_gstack AGMCORE_gstackptr get + AGMCORE_gdictcopy + }def + /setoverprint{ + dup/AGMCORE_currentoverprint exch AGMCORE_gput AGMCORE_&setoverprint + }def + 0 1 AGMCORE_gstack length 1 sub{ + AGMCORE_gstack exch AGMCORE_gstackframekeys dict put + }for + }if + level3/AGMCORE_&sysshfill AGMCORE_key_known not and + { + /AGMCORE_&sysshfill systemdict/shfill get def + /AGMCORE_&sysmakepattern systemdict/makepattern get def + /AGMCORE_&usrmakepattern/makepattern load def + }if + /currentcmykcolor[0 0 0 0]AGMCORE_gput + /currentstrokeadjust false AGMCORE_gput + /currentcolorspace[/DeviceGray]AGMCORE_gput + /sep_tint 0 AGMCORE_gput + /devicen_tints[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]AGMCORE_gput + /sep_colorspace_dict null AGMCORE_gput + /devicen_colorspace_dict null AGMCORE_gput + /indexed_colorspace_dict null AGMCORE_gput + /currentcolor_intent()AGMCORE_gput + /customcolor_tint 1 AGMCORE_gput + /absolute_colorimetric_crd null AGMCORE_gput + /relative_colorimetric_crd null AGMCORE_gput + /saturation_crd null AGMCORE_gput + /perceptual_crd null AGMCORE_gput + currentcolortransfer cvlit/AGMCore_gray_xfer xdf cvlit/AGMCore_b_xfer xdf + cvlit/AGMCore_g_xfer xdf cvlit/AGMCore_r_xfer xdf + << + /MaxPatternItem currentsystemparams/MaxPatternCache get + >> + setuserparams + end +}def +/ps +{ + /setcmykcolor where{ + pop + Adobe_AGM_Core/AGMCORE_&setcmykcolor/setcmykcolor load put + }if + Adobe_AGM_Core begin + /setcmykcolor + { + 4 copy AGMCORE_cmykbuf astore/currentcmykcolor exch AGMCORE_gput + 1 sub 4 1 roll + 3{ + 3 index add neg dup 0 lt{ + pop 0 + }if + 3 1 roll + }repeat + setrgbcolor pop + }ndf + /currentcmykcolor + { + /currentcmykcolor AGMCORE_gget aload pop + }ndf + /setoverprint + {pop}ndf + /currentoverprint + {false}ndf + /AGMCORE_cyan_plate 1 0 0 0 test_cmyk_color_plate def + /AGMCORE_magenta_plate 0 1 0 0 test_cmyk_color_plate def + /AGMCORE_yellow_plate 0 0 1 0 test_cmyk_color_plate def + /AGMCORE_black_plate 0 0 0 1 test_cmyk_color_plate def + /AGMCORE_plate_ndx + AGMCORE_cyan_plate{ + 0 + }{ + AGMCORE_magenta_plate{ + 1 + }{ + AGMCORE_yellow_plate{ + 2 + }{ + AGMCORE_black_plate{ + 3 + }{ + 4 + }ifelse + }ifelse + }ifelse + }ifelse + def + /AGMCORE_have_reported_unsupported_color_space false def + /AGMCORE_report_unsupported_color_space + { + AGMCORE_have_reported_unsupported_color_space false eq + { + (Warning: Job contains content that cannot be separated with on-host methods. This content appears on the black plate, and knocks out all other plates.)== + Adobe_AGM_Core/AGMCORE_have_reported_unsupported_color_space true ddf + }if + }def + /AGMCORE_composite_job + AGMCORE_cyan_plate AGMCORE_magenta_plate and AGMCORE_yellow_plate and AGMCORE_black_plate and def + /AGMCORE_in_rip_sep + /AGMCORE_in_rip_sep where{ + pop AGMCORE_in_rip_sep + }{ + AGMCORE_distilling + { + false + }{ + userdict/Adobe_AGM_OnHost_Seps known{ + false + }{ + level2{ + currentpagedevice/Separations 2 copy known{ + get + }{ + pop pop false + }ifelse + }{ + false + }ifelse + }ifelse + }ifelse + }ifelse + def + /AGMCORE_producing_seps AGMCORE_composite_job not AGMCORE_in_rip_sep or def + /AGMCORE_host_sep AGMCORE_producing_seps AGMCORE_in_rip_sep not and def + /AGM_preserve_spots + /AGM_preserve_spots where{ + pop AGM_preserve_spots + }{ + AGMCORE_distilling AGMCORE_producing_seps or + }ifelse + def + /AGM_is_distiller_preserving_spotimages + { + currentdistillerparams/PreserveOverprintSettings known + { + currentdistillerparams/PreserveOverprintSettings get + { + currentdistillerparams/ColorConversionStrategy known + { + currentdistillerparams/ColorConversionStrategy get + /sRGB ne + }{ + true + }ifelse + }{ + false + }ifelse + }{ + false + }ifelse + }def + /convert_spot_to_process where{pop}{ + /convert_spot_to_process + { + //Adobe_AGM_Core begin + dup map_alias{ + /Name get exch pop + }if + dup dup(None)eq exch(All)eq or + { + pop false + }{ + AGMCORE_host_sep + { + gsave + 1 0 0 0 setcmykcolor currentgray 1 exch sub + 0 1 0 0 setcmykcolor currentgray 1 exch sub + 0 0 1 0 setcmykcolor currentgray 1 exch sub + 0 0 0 1 setcmykcolor currentgray 1 exch sub + add add add 0 eq + { + pop false + }{ + false setoverprint + current_spot_alias false set_spot_alias + 1 1 1 1 6 -1 roll findcmykcustomcolor 1 setcustomcolor + set_spot_alias + currentgray 1 ne + }ifelse + grestore + }{ + AGMCORE_distilling + { + pop AGM_is_distiller_preserving_spotimages not + }{ + //Adobe_AGM_Core/AGMCORE_name xddf + false + //Adobe_AGM_Core/AGMCORE_pattern_paint_type get 0 eq + AGMUTIL_cpd/OverrideSeparations known and + { + AGMUTIL_cpd/OverrideSeparations get + { + /HqnSpots/ProcSet resourcestatus + { + pop pop pop true + }if + }if + }if + { + AGMCORE_name/HqnSpots/ProcSet findresource/TestSpot gx not + }{ + gsave + [/Separation AGMCORE_name/DeviceGray{}]AGMCORE_&setcolorspace + false + AGMUTIL_cpd/SeparationColorNames 2 copy known + { + get + {AGMCORE_name eq or}forall + not + }{ + pop pop pop true + }ifelse + grestore + }ifelse + }ifelse + }ifelse + }ifelse + end + }def + }ifelse + /convert_to_process where{pop}{ + /convert_to_process + { + dup length 0 eq + { + pop false + }{ + AGMCORE_host_sep + { + dup true exch + { + dup(Cyan)eq exch + dup(Magenta)eq 3 -1 roll or exch + dup(Yellow)eq 3 -1 roll or exch + dup(Black)eq 3 -1 roll or + {pop} + {convert_spot_to_process and}ifelse + } + forall + { + true exch + { + dup(Cyan)eq exch + dup(Magenta)eq 3 -1 roll or exch + dup(Yellow)eq 3 -1 roll or exch + (Black)eq or and + }forall + not + }{pop false}ifelse + }{ + false exch + { + /PhotoshopDuotoneList where{pop false}{true}ifelse + { + dup(Cyan)eq exch + dup(Magenta)eq 3 -1 roll or exch + dup(Yellow)eq 3 -1 roll or exch + dup(Black)eq 3 -1 roll or + {pop} + {convert_spot_to_process or}ifelse + } + { + convert_spot_to_process or + } + ifelse + } + forall + }ifelse + }ifelse + }def + }ifelse + /AGMCORE_avoid_L2_sep_space + version cvr 2012 lt + level2 and + AGMCORE_producing_seps not and + def + /AGMCORE_is_cmyk_sep + AGMCORE_cyan_plate AGMCORE_magenta_plate or AGMCORE_yellow_plate or AGMCORE_black_plate or + def + /AGM_avoid_0_cmyk where{ + pop AGM_avoid_0_cmyk + }{ + AGM_preserve_spots + userdict/Adobe_AGM_OnHost_Seps known + userdict/Adobe_AGM_InRip_Seps known or + not and + }ifelse + { + /setcmykcolor[ + { + 4 copy add add add 0 eq currentoverprint and{ + pop 0.0005 + }if + }/exec cvx + /AGMCORE_&setcmykcolor load dup type/operatortype ne{ + /exec cvx + }if + ]cvx def + }if + /AGMCORE_IsSeparationAProcessColor + { + dup(Cyan)eq exch dup(Magenta)eq exch dup(Yellow)eq exch(Black)eq or or or + }def + AGMCORE_host_sep{ + /setcolortransfer + { + AGMCORE_cyan_plate{ + pop pop pop + }{ + AGMCORE_magenta_plate{ + 4 3 roll pop pop pop + }{ + AGMCORE_yellow_plate{ + 4 2 roll pop pop pop + }{ + 4 1 roll pop pop pop + }ifelse + }ifelse + }ifelse + settransfer + } + def + /AGMCORE_get_ink_data + AGMCORE_cyan_plate{ + {pop pop pop} + }{ + AGMCORE_magenta_plate{ + {4 3 roll pop pop pop} + }{ + AGMCORE_yellow_plate{ + {4 2 roll pop pop pop} + }{ + {4 1 roll pop pop pop} + }ifelse + }ifelse + }ifelse + def + /AGMCORE_RemoveProcessColorNames + { + 1 dict begin + /filtername + { + dup/Cyan eq 1 index(Cyan)eq or + {pop(_cyan_)}if + dup/Magenta eq 1 index(Magenta)eq or + {pop(_magenta_)}if + dup/Yellow eq 1 index(Yellow)eq or + {pop(_yellow_)}if + dup/Black eq 1 index(Black)eq or + {pop(_black_)}if + }def + dup type/arraytype eq + {[exch{filtername}forall]} + {filtername}ifelse + end + }def + level3{ + /AGMCORE_IsCurrentColor + { + dup AGMCORE_IsSeparationAProcessColor + { + AGMCORE_plate_ndx 0 eq + {dup(Cyan)eq exch/Cyan eq or}if + AGMCORE_plate_ndx 1 eq + {dup(Magenta)eq exch/Magenta eq or}if + AGMCORE_plate_ndx 2 eq + {dup(Yellow)eq exch/Yellow eq or}if + AGMCORE_plate_ndx 3 eq + {dup(Black)eq exch/Black eq or}if + AGMCORE_plate_ndx 4 eq + {pop false}if + }{ + gsave + false setoverprint + current_spot_alias false set_spot_alias + 1 1 1 1 6 -1 roll findcmykcustomcolor 1 setcustomcolor + set_spot_alias + currentgray 1 ne + grestore + }ifelse + }def + /AGMCORE_filter_functiondatasource + { + 5 dict begin + /data_in xdf + data_in type/stringtype eq + { + /ncomp xdf + /comp xdf + /string_out data_in length ncomp idiv string def + 0 ncomp data_in length 1 sub + { + string_out exch dup ncomp idiv exch data_in exch ncomp getinterval comp get 255 exch sub put + }for + string_out + }{ + string/string_in xdf + /string_out 1 string def + /component xdf + [ + data_in string_in/readstring cvx + [component/get cvx 255/exch cvx/sub cvx string_out/exch cvx 0/exch cvx/put cvx string_out]cvx + [/pop cvx()]cvx/ifelse cvx + ]cvx/ReusableStreamDecode filter + }ifelse + end + }def + /AGMCORE_separateShadingFunction + { + 2 dict begin + /paint? xdf + /channel xdf + dup type/dicttype eq + { + begin + FunctionType 0 eq + { + /DataSource channel Range length 2 idiv DataSource AGMCORE_filter_functiondatasource def + currentdict/Decode known + {/Decode Decode channel 2 mul 2 getinterval def}if + paint? not + {/Decode[1 1]def}if + }if + FunctionType 2 eq + { + paint? + { + /C0[C0 channel get 1 exch sub]def + /C1[C1 channel get 1 exch sub]def + }{ + /C0[1]def + /C1[1]def + }ifelse + }if + FunctionType 3 eq + { + /Functions[Functions{channel paint? AGMCORE_separateShadingFunction}forall]def + }if + currentdict/Range known + {/Range[0 1]def}if + currentdict + end}{ + channel get 0 paint? AGMCORE_separateShadingFunction + }ifelse + end + }def + /AGMCORE_separateShading + { + 3 -1 roll begin + currentdict/Function known + { + currentdict/Background known + {[1 index{Background 3 index get 1 exch sub}{1}ifelse]/Background xdf}if + Function 3 1 roll AGMCORE_separateShadingFunction/Function xdf + /ColorSpace[/DeviceGray]def + }{ + ColorSpace dup type/arraytype eq{0 get}if/DeviceCMYK eq + { + /ColorSpace[/DeviceN[/_cyan_/_magenta_/_yellow_/_black_]/DeviceCMYK{}]def + }{ + ColorSpace dup 1 get AGMCORE_RemoveProcessColorNames 1 exch put + }ifelse + ColorSpace 0 get/Separation eq + { + { + [1/exch cvx/sub cvx]cvx + }{ + [/pop cvx 1]cvx + }ifelse + ColorSpace 3 3 -1 roll put + pop + }{ + { + [exch ColorSpace 1 get length 1 sub exch sub/index cvx 1/exch cvx/sub cvx ColorSpace 1 get length 1 add 1/roll cvx ColorSpace 1 get length{/pop cvx}repeat]cvx + }{ + pop[ColorSpace 1 get length{/pop cvx}repeat cvx 1]cvx + }ifelse + ColorSpace 3 3 -1 roll bind put + }ifelse + ColorSpace 2/DeviceGray put + }ifelse + end + }def + /AGMCORE_separateShadingDict + { + dup/ColorSpace get + dup type/arraytype ne + {[exch]}if + dup 0 get/DeviceCMYK eq + { + exch begin + currentdict + AGMCORE_cyan_plate + {0 true}if + AGMCORE_magenta_plate + {1 true}if + AGMCORE_yellow_plate + {2 true}if + AGMCORE_black_plate + {3 true}if + AGMCORE_plate_ndx 4 eq + {0 false}if + dup not currentoverprint and + {/AGMCORE_ignoreshade true def}if + AGMCORE_separateShading + currentdict + end exch + }if + dup 0 get/Separation eq + { + exch begin + ColorSpace 1 get dup/None ne exch/All ne and + { + ColorSpace 1 get AGMCORE_IsCurrentColor AGMCORE_plate_ndx 4 lt and ColorSpace 1 get AGMCORE_IsSeparationAProcessColor not and + { + ColorSpace 2 get dup type/arraytype eq{0 get}if/DeviceCMYK eq + { + /ColorSpace + [ + /Separation + ColorSpace 1 get + /DeviceGray + [ + ColorSpace 3 get/exec cvx + 4 AGMCORE_plate_ndx sub -1/roll cvx + 4 1/roll cvx + 3[/pop cvx]cvx/repeat cvx + 1/exch cvx/sub cvx + ]cvx + ]def + }{ + AGMCORE_report_unsupported_color_space + AGMCORE_black_plate not + { + currentdict 0 false AGMCORE_separateShading + }if + }ifelse + }{ + currentdict ColorSpace 1 get AGMCORE_IsCurrentColor + 0 exch + dup not currentoverprint and + {/AGMCORE_ignoreshade true def}if + AGMCORE_separateShading + }ifelse + }if + currentdict + end exch + }if + dup 0 get/DeviceN eq + { + exch begin + ColorSpace 1 get convert_to_process + { + ColorSpace 2 get dup type/arraytype eq{0 get}if/DeviceCMYK eq + { + /ColorSpace + [ + /DeviceN + ColorSpace 1 get + /DeviceGray + [ + ColorSpace 3 get/exec cvx + 4 AGMCORE_plate_ndx sub -1/roll cvx + 4 1/roll cvx + 3[/pop cvx]cvx/repeat cvx + 1/exch cvx/sub cvx + ]cvx + ]def + }{ + AGMCORE_report_unsupported_color_space + AGMCORE_black_plate not + { + currentdict 0 false AGMCORE_separateShading + /ColorSpace[/DeviceGray]def + }if + }ifelse + }{ + currentdict + false -1 ColorSpace 1 get + { + AGMCORE_IsCurrentColor + { + 1 add + exch pop true exch exit + }if + 1 add + }forall + exch + dup not currentoverprint and + {/AGMCORE_ignoreshade true def}if + AGMCORE_separateShading + }ifelse + currentdict + end exch + }if + dup 0 get dup/DeviceCMYK eq exch dup/Separation eq exch/DeviceN eq or or not + { + exch begin + ColorSpace dup type/arraytype eq + {0 get}if + /DeviceGray ne + { + AGMCORE_report_unsupported_color_space + AGMCORE_black_plate not + { + ColorSpace 0 get/CIEBasedA eq + { + /ColorSpace[/Separation/_ciebaseda_/DeviceGray{}]def + }if + ColorSpace 0 get dup/CIEBasedABC eq exch dup/CIEBasedDEF eq exch/DeviceRGB eq or or + { + /ColorSpace[/DeviceN[/_red_/_green_/_blue_]/DeviceRGB{}]def + }if + ColorSpace 0 get/CIEBasedDEFG eq + { + /ColorSpace[/DeviceN[/_cyan_/_magenta_/_yellow_/_black_]/DeviceCMYK{}]def + }if + currentdict 0 false AGMCORE_separateShading + }if + }if + currentdict + end exch + }if + pop + dup/AGMCORE_ignoreshade known + { + begin + /ColorSpace[/Separation(None)/DeviceGray{}]def + currentdict end + }if + }def + /shfill + { + AGMCORE_separateShadingDict + dup/AGMCORE_ignoreshade known + {pop} + {AGMCORE_&sysshfill}ifelse + }def + /makepattern + { + exch + dup/PatternType get 2 eq + { + clonedict + begin + /Shading Shading AGMCORE_separateShadingDict def + Shading/AGMCORE_ignoreshade known + currentdict end exch + {pop<>}if + exch AGMCORE_&sysmakepattern + }{ + exch AGMCORE_&usrmakepattern + }ifelse + }def + }if + }if + AGMCORE_in_rip_sep{ + /setcustomcolor + { + exch aload pop + dup 7 1 roll inRip_spot_has_ink not { + 4{4 index mul 4 1 roll} + repeat + /DeviceCMYK setcolorspace + 6 -2 roll pop pop + }{ + //Adobe_AGM_Core begin + /AGMCORE_k xdf/AGMCORE_y xdf/AGMCORE_m xdf/AGMCORE_c xdf + end + [/Separation 4 -1 roll/DeviceCMYK + {dup AGMCORE_c mul exch dup AGMCORE_m mul exch dup AGMCORE_y mul exch AGMCORE_k mul} + ] + setcolorspace + }ifelse + setcolor + }ndf + /setseparationgray + { + [/Separation(All)/DeviceGray{}]setcolorspace_opt + 1 exch sub setcolor + }ndf + }{ + /setseparationgray + { + AGMCORE_&setgray + }ndf + }ifelse + /findcmykcustomcolor + { + 5 makereadonlyarray + }ndf + /setcustomcolor + { + exch aload pop pop + 4{4 index mul 4 1 roll}repeat + setcmykcolor pop + }ndf + /has_color + /colorimage where{ + AGMCORE_producing_seps{ + pop true + }{ + systemdict eq + }ifelse + }{ + false + }ifelse + def + /map_index + { + 1 index mul exch getinterval{255 div}forall + }bdf + /map_indexed_devn + { + Lookup Names length 3 -1 roll cvi map_index + }bdf + /n_color_components + { + base_colorspace_type + dup/DeviceGray eq{ + pop 1 + }{ + /DeviceCMYK eq{ + 4 + }{ + 3 + }ifelse + }ifelse + }bdf + level2{ + /mo/moveto ldf + /li/lineto ldf + /cv/curveto ldf + /knockout_unitsq + { + 1 setgray + 0 0 1 1 rectfill + }def + level2/setcolorspace AGMCORE_key_known not and{ + /AGMCORE_&&&setcolorspace/setcolorspace ldf + /AGMCORE_ReplaceMappedColor + { + dup type dup/arraytype eq exch/packedarraytype eq or + { + /AGMCORE_SpotAliasAry2 where{ + begin + dup 0 get dup/Separation eq + { + pop + dup length array copy + dup dup 1 get + current_spot_alias + { + dup map_alias + { + false set_spot_alias + dup 1 exch setsepcolorspace + true set_spot_alias + begin + /sep_colorspace_dict currentdict AGMCORE_gput + pop pop pop + [ + /Separation Name + CSA map_csa + MappedCSA + /sep_colorspace_proc load + ] + dup Name + end + }if + }if + map_reserved_ink_name 1 xpt + }{ + /DeviceN eq + { + dup length array copy + dup dup 1 get[ + exch{ + current_spot_alias{ + dup map_alias{ + /Name get exch pop + }if + }if + map_reserved_ink_name + }forall + ]1 xpt + }if + }ifelse + end + }if + }if + }def + /setcolorspace + { + dup type dup/arraytype eq exch/packedarraytype eq or + { + dup 0 get/Indexed eq + { + AGMCORE_distilling + { + /PhotoshopDuotoneList where + { + pop false + }{ + true + }ifelse + }{ + true + }ifelse + { + aload pop 3 -1 roll + AGMCORE_ReplaceMappedColor + 3 1 roll 4 array astore + }if + }{ + AGMCORE_ReplaceMappedColor + }ifelse + }if + DeviceN_PS2_inRip_seps{AGMCORE_&&&setcolorspace}if + }def + }if + }{ + /adj + { + currentstrokeadjust{ + transform + 0.25 sub round 0.25 add exch + 0.25 sub round 0.25 add exch + itransform + }if + }def + /mo{ + adj moveto + }def + /li{ + adj lineto + }def + /cv{ + 6 2 roll adj + 6 2 roll adj + 6 2 roll adj curveto + }def + /knockout_unitsq + { + 1 setgray + 8 8 1[8 0 0 8 0 0]{}image + }def + /currentstrokeadjust{ + /currentstrokeadjust AGMCORE_gget + }def + /setstrokeadjust{ + /currentstrokeadjust exch AGMCORE_gput + }def + /setcolorspace + { + /currentcolorspace exch AGMCORE_gput + }def + /currentcolorspace + { + /currentcolorspace AGMCORE_gget + }def + /setcolor_devicecolor + { + base_colorspace_type + dup/DeviceGray eq{ + pop setgray + }{ + /DeviceCMYK eq{ + setcmykcolor + }{ + setrgbcolor + }ifelse + }ifelse + }def + /setcolor + { + currentcolorspace 0 get + dup/DeviceGray ne{ + dup/DeviceCMYK ne{ + dup/DeviceRGB ne{ + dup/Separation eq{ + pop + currentcolorspace 3 gx + currentcolorspace 2 get + }{ + dup/Indexed eq{ + pop + currentcolorspace 3 get dup type/stringtype eq{ + currentcolorspace 1 get n_color_components + 3 -1 roll map_index + }{ + exec + }ifelse + currentcolorspace 1 get + }{ + /AGMCORE_cur_err/AGMCORE_invalid_color_space def + AGMCORE_invalid_color_space + }ifelse + }ifelse + }if + }if + }if + setcolor_devicecolor + }def + }ifelse + /sop/setoverprint ldf + /lw/setlinewidth ldf + /lc/setlinecap ldf + /lj/setlinejoin ldf + /ml/setmiterlimit ldf + /dsh/setdash ldf + /sadj/setstrokeadjust ldf + /gry/setgray ldf + /rgb/setrgbcolor ldf + /cmyk[ + /currentcolorspace[/DeviceCMYK]/AGMCORE_gput cvx + /setcmykcolor load dup type/operatortype ne{/exec cvx}if + ]cvx bdf + level3 AGMCORE_host_sep not and{ + /nzopmsc{ + 6 dict begin + /kk exch def + /yy exch def + /mm exch def + /cc exch def + /sum 0 def + cc 0 ne{/sum sum 2#1000 or def cc}if + mm 0 ne{/sum sum 2#0100 or def mm}if + yy 0 ne{/sum sum 2#0010 or def yy}if + kk 0 ne{/sum sum 2#0001 or def kk}if + AGMCORE_CMYKDeviceNColorspaces sum get setcolorspace + sum 0 eq{0}if + end + setcolor + }bdf + }{ + /nzopmsc/cmyk ldf + }ifelse + /sep/setsepcolor ldf + /devn/setdevicencolor ldf + /idx/setindexedcolor ldf + /colr/setcolor ldf + /csacrd/set_csa_crd ldf + /sepcs/setsepcolorspace ldf + /devncs/setdevicencolorspace ldf + /idxcs/setindexedcolorspace ldf + /cp/closepath ldf + /clp/clp_npth ldf + /eclp/eoclp_npth ldf + /f/fill ldf + /ef/eofill ldf + /@/stroke ldf + /nclp/npth_clp ldf + /gset/graphic_setup ldf + /gcln/graphic_cleanup ldf + /ct/concat ldf + /cf/currentfile ldf + /fl/filter ldf + /rs/readstring ldf + /AGMCORE_def_ht currenthalftone def + /clonedict Adobe_AGM_Utils begin/clonedict load end def + /clonearray Adobe_AGM_Utils begin/clonearray load end def + currentdict{ + dup xcheck 1 index type dup/arraytype eq exch/packedarraytype eq or and{ + bind + }if + def + }forall + /getrampcolor + { + /indx exch def + 0 1 NumComp 1 sub + { + dup + Samples exch get + dup type/stringtype eq{indx get}if + exch + Scaling exch get aload pop + 3 1 roll + mul add + }for + ColorSpaceFamily/Separation eq + {sep} + { + ColorSpaceFamily/DeviceN eq + {devn}{setcolor}ifelse + }ifelse + }bdf + /sssetbackground{ + aload pop + ColorSpaceFamily/Separation eq + {sep} + { + ColorSpaceFamily/DeviceN eq + {devn}{setcolor}ifelse + }ifelse + }bdf + /RadialShade + { + 40 dict begin + /ColorSpaceFamily xdf + /background xdf + /ext1 xdf + /ext0 xdf + /BBox xdf + /r2 xdf + /c2y xdf + /c2x xdf + /r1 xdf + /c1y xdf + /c1x xdf + /rampdict xdf + /setinkoverprint where{pop/setinkoverprint{pop}def}if + gsave + BBox length 0 gt + { + np + BBox 0 get BBox 1 get moveto + BBox 2 get BBox 0 get sub 0 rlineto + 0 BBox 3 get BBox 1 get sub rlineto + BBox 2 get BBox 0 get sub neg 0 rlineto + closepath + clip + np + }if + c1x c2x eq + { + c1y c2y lt{/theta 90 def}{/theta 270 def}ifelse + }{ + /slope c2y c1y sub c2x c1x sub div def + /theta slope 1 atan def + c2x c1x lt c2y c1y ge and{/theta theta 180 sub def}if + c2x c1x lt c2y c1y lt and{/theta theta 180 add def}if + }ifelse + gsave + clippath + c1x c1y translate + theta rotate + -90 rotate + {pathbbox}stopped + {0 0 0 0}if + /yMax xdf + /xMax xdf + /yMin xdf + /xMin xdf + grestore + xMax xMin eq yMax yMin eq or + { + grestore + end + }{ + /max{2 copy gt{pop}{exch pop}ifelse}bdf + /min{2 copy lt{pop}{exch pop}ifelse}bdf + rampdict begin + 40 dict begin + background length 0 gt{background sssetbackground gsave clippath fill grestore}if + gsave + c1x c1y translate + theta rotate + -90 rotate + /c2y c1x c2x sub dup mul c1y c2y sub dup mul add sqrt def + /c1y 0 def + /c1x 0 def + /c2x 0 def + ext0 + { + 0 getrampcolor + c2y r2 add r1 sub 0.0001 lt + { + c1x c1y r1 360 0 arcn + pathbbox + /aymax exch def + /axmax exch def + /aymin exch def + /axmin exch def + /bxMin xMin axmin min def + /byMin yMin aymin min def + /bxMax xMax axmax max def + /byMax yMax aymax max def + bxMin byMin moveto + bxMax byMin lineto + bxMax byMax lineto + bxMin byMax lineto + bxMin byMin lineto + eofill + }{ + c2y r1 add r2 le + { + c1x c1y r1 0 360 arc + fill + } + { + c2x c2y r2 0 360 arc fill + r1 r2 eq + { + /p1x r1 neg def + /p1y c1y def + /p2x r1 def + /p2y c1y def + p1x p1y moveto p2x p2y lineto p2x yMin lineto p1x yMin lineto + fill + }{ + /AA r2 r1 sub c2y div def + AA -1 eq + {/theta 89.99 def} + {/theta AA 1 AA dup mul sub sqrt div 1 atan def} + ifelse + /SS1 90 theta add dup sin exch cos div def + /p1x r1 SS1 SS1 mul SS1 SS1 mul 1 add div sqrt mul neg def + /p1y p1x SS1 div neg def + /SS2 90 theta sub dup sin exch cos div def + /p2x r1 SS2 SS2 mul SS2 SS2 mul 1 add div sqrt mul def + /p2y p2x SS2 div neg def + r1 r2 gt + { + /L1maxX p1x yMin p1y sub SS1 div add def + /L2maxX p2x yMin p2y sub SS2 div add def + }{ + /L1maxX 0 def + /L2maxX 0 def + }ifelse + p1x p1y moveto p2x p2y lineto L2maxX L2maxX p2x sub SS2 mul p2y add lineto + L1maxX L1maxX p1x sub SS1 mul p1y add lineto + fill + }ifelse + }ifelse + }ifelse + }if + c1x c2x sub dup mul + c1y c2y sub dup mul + add 0.5 exp + 0 dtransform + dup mul exch dup mul add 0.5 exp 72 div + 0 72 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt + 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt + 1 index 1 index lt{exch}if pop + /hires xdf + hires mul + /numpix xdf + /numsteps NumSamples def + /rampIndxInc 1 def + /subsampling false def + numpix 0 ne + { + NumSamples numpix div 0.5 gt + { + /numsteps numpix 2 div round cvi dup 1 le{pop 2}if def + /rampIndxInc NumSamples 1 sub numsteps div def + /subsampling true def + }if + }if + /xInc c2x c1x sub numsteps div def + /yInc c2y c1y sub numsteps div def + /rInc r2 r1 sub numsteps div def + /cx c1x def + /cy c1y def + /radius r1 def + np + xInc 0 eq yInc 0 eq rInc 0 eq and and + { + 0 getrampcolor + cx cy radius 0 360 arc + stroke + NumSamples 1 sub getrampcolor + cx cy radius 72 hires div add 0 360 arc + 0 setlinewidth + stroke + }{ + 0 + numsteps + { + dup + subsampling{round cvi}if + getrampcolor + cx cy radius 0 360 arc + /cx cx xInc add def + /cy cy yInc add def + /radius radius rInc add def + cx cy radius 360 0 arcn + eofill + rampIndxInc add + }repeat + pop + }ifelse + ext1 + { + c2y r2 add r1 lt + { + c2x c2y r2 0 360 arc + fill + }{ + c2y r1 add r2 sub 0.0001 le + { + c2x c2y r2 360 0 arcn + pathbbox + /aymax exch def + /axmax exch def + /aymin exch def + /axmin exch def + /bxMin xMin axmin min def + /byMin yMin aymin min def + /bxMax xMax axmax max def + /byMax yMax aymax max def + bxMin byMin moveto + bxMax byMin lineto + bxMax byMax lineto + bxMin byMax lineto + bxMin byMin lineto + eofill + }{ + c2x c2y r2 0 360 arc fill + r1 r2 eq + { + /p1x r2 neg def + /p1y c2y def + /p2x r2 def + /p2y c2y def + p1x p1y moveto p2x p2y lineto p2x yMax lineto p1x yMax lineto + fill + }{ + /AA r2 r1 sub c2y div def + AA -1 eq + {/theta 89.99 def} + {/theta AA 1 AA dup mul sub sqrt div 1 atan def} + ifelse + /SS1 90 theta add dup sin exch cos div def + /p1x r2 SS1 SS1 mul SS1 SS1 mul 1 add div sqrt mul neg def + /p1y c2y p1x SS1 div sub def + /SS2 90 theta sub dup sin exch cos div def + /p2x r2 SS2 SS2 mul SS2 SS2 mul 1 add div sqrt mul def + /p2y c2y p2x SS2 div sub def + r1 r2 lt + { + /L1maxX p1x yMax p1y sub SS1 div add def + /L2maxX p2x yMax p2y sub SS2 div add def + }{ + /L1maxX 0 def + /L2maxX 0 def + }ifelse + p1x p1y moveto p2x p2y lineto L2maxX L2maxX p2x sub SS2 mul p2y add lineto + L1maxX L1maxX p1x sub SS1 mul p1y add lineto + fill + }ifelse + }ifelse + }ifelse + }if + grestore + grestore + end + end + end + }ifelse + }bdf + /GenStrips + { + 40 dict begin + /ColorSpaceFamily xdf + /background xdf + /ext1 xdf + /ext0 xdf + /BBox xdf + /y2 xdf + /x2 xdf + /y1 xdf + /x1 xdf + /rampdict xdf + /setinkoverprint where{pop/setinkoverprint{pop}def}if + gsave + BBox length 0 gt + { + np + BBox 0 get BBox 1 get moveto + BBox 2 get BBox 0 get sub 0 rlineto + 0 BBox 3 get BBox 1 get sub rlineto + BBox 2 get BBox 0 get sub neg 0 rlineto + closepath + clip + np + }if + x1 x2 eq + { + y1 y2 lt{/theta 90 def}{/theta 270 def}ifelse + }{ + /slope y2 y1 sub x2 x1 sub div def + /theta slope 1 atan def + x2 x1 lt y2 y1 ge and{/theta theta 180 sub def}if + x2 x1 lt y2 y1 lt and{/theta theta 180 add def}if + } + ifelse + gsave + clippath + x1 y1 translate + theta rotate + {pathbbox}stopped + {0 0 0 0}if + /yMax exch def + /xMax exch def + /yMin exch def + /xMin exch def + grestore + xMax xMin eq yMax yMin eq or + { + grestore + end + }{ + rampdict begin + 20 dict begin + background length 0 gt{background sssetbackground gsave clippath fill grestore}if + gsave + x1 y1 translate + theta rotate + /xStart 0 def + /xEnd x2 x1 sub dup mul y2 y1 sub dup mul add 0.5 exp def + /ySpan yMax yMin sub def + /numsteps NumSamples def + /rampIndxInc 1 def + /subsampling false def + xStart 0 transform + xEnd 0 transform + 3 -1 roll + sub dup mul + 3 1 roll + sub dup mul + add 0.5 exp 72 div + 0 72 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt + 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt + 1 index 1 index lt{exch}if pop + mul + /numpix xdf + numpix 0 ne + { + NumSamples numpix div 0.5 gt + { + /numsteps numpix 2 div round cvi dup 1 le{pop 2}if def + /rampIndxInc NumSamples 1 sub numsteps div def + /subsampling true def + }if + }if + ext0 + { + 0 getrampcolor + xMin xStart lt + { + xMin yMin xMin neg ySpan rectfill + }if + }if + /xInc xEnd xStart sub numsteps div def + /x xStart def + 0 + numsteps + { + dup + subsampling{round cvi}if + getrampcolor + x yMin xInc ySpan rectfill + /x x xInc add def + rampIndxInc add + }repeat + pop + ext1{ + xMax xEnd gt + { + xEnd yMin xMax xEnd sub ySpan rectfill + }if + }if + grestore + grestore + end + end + end + }ifelse + }bdf +}def +/pt +{ + end +}def +/dt{ +}def +/pgsv{ + //Adobe_AGM_Core/AGMCORE_save save put +}def +/pgrs{ + //Adobe_AGM_Core/AGMCORE_save get restore +}def +systemdict/findcolorrendering known{ + /findcolorrendering systemdict/findcolorrendering get def +}if +systemdict/setcolorrendering known{ + /setcolorrendering systemdict/setcolorrendering get def +}if +/test_cmyk_color_plate +{ + gsave + setcmykcolor currentgray 1 ne + grestore +}def +/inRip_spot_has_ink +{ + dup//Adobe_AGM_Core/AGMCORE_name xddf + convert_spot_to_process not +}def +/map255_to_range +{ + 1 index sub + 3 -1 roll 255 div mul add +}def +/set_csa_crd +{ + /sep_colorspace_dict null AGMCORE_gput + begin + CSA get_csa_by_name setcolorspace_opt + set_crd + end +} +def +/map_csa +{ + currentdict/MappedCSA known{MappedCSA null ne}{false}ifelse + {pop}{get_csa_by_name/MappedCSA xdf}ifelse +}def +/setsepcolor +{ + /sep_colorspace_dict AGMCORE_gget begin + dup/sep_tint exch AGMCORE_gput + TintProc + end +}def +/setdevicencolor +{ + /devicen_colorspace_dict AGMCORE_gget begin + Names length copy + Names length 1 sub -1 0 + { + /devicen_tints AGMCORE_gget 3 1 roll xpt + }for + TintProc + end +}def +/sep_colorspace_proc +{ + /AGMCORE_tmp exch store + /sep_colorspace_dict AGMCORE_gget begin + currentdict/Components known{ + Components aload pop + TintMethod/Lab eq{ + 2{AGMCORE_tmp mul NComponents 1 roll}repeat + LMax sub AGMCORE_tmp mul LMax add NComponents 1 roll + }{ + TintMethod/Subtractive eq{ + NComponents{ + AGMCORE_tmp mul NComponents 1 roll + }repeat + }{ + NComponents{ + 1 sub AGMCORE_tmp mul 1 add NComponents 1 roll + }repeat + }ifelse + }ifelse + }{ + ColorLookup AGMCORE_tmp ColorLookup length 1 sub mul round cvi get + aload pop + }ifelse + end +}def +/sep_colorspace_gray_proc +{ + /AGMCORE_tmp exch store + /sep_colorspace_dict AGMCORE_gget begin + GrayLookup AGMCORE_tmp GrayLookup length 1 sub mul round cvi get + end +}def +/sep_proc_name +{ + dup 0 get + dup/DeviceRGB eq exch/DeviceCMYK eq or level2 not and has_color not and{ + pop[/DeviceGray] + /sep_colorspace_gray_proc + }{ + /sep_colorspace_proc + }ifelse +}def +/setsepcolorspace +{ + current_spot_alias{ + dup begin + Name map_alias{ + exch pop + }if + end + }if + dup/sep_colorspace_dict exch AGMCORE_gput + begin + CSA map_csa + /AGMCORE_sep_special Name dup()eq exch(All)eq or store + AGMCORE_avoid_L2_sep_space{ + [/Indexed MappedCSA sep_proc_name 255 exch + {255 div}/exec cvx 3 -1 roll[4 1 roll load/exec cvx]cvx + ]setcolorspace_opt + /TintProc{ + 255 mul round cvi setcolor + }bdf + }{ + MappedCSA 0 get/DeviceCMYK eq + currentdict/Components known and + AGMCORE_sep_special not and{ + /TintProc[ + Components aload pop Name findcmykcustomcolor + /exch cvx/setcustomcolor cvx + ]cvx bdf + }{ + AGMCORE_host_sep Name(All)eq and{ + /TintProc{ + 1 exch sub setseparationgray + }bdf + }{ + AGMCORE_in_rip_sep MappedCSA 0 get/DeviceCMYK eq and + AGMCORE_host_sep or + Name()eq and{ + /TintProc[ + MappedCSA sep_proc_name exch 0 get/DeviceCMYK eq{ + cvx/setcmykcolor cvx + }{ + cvx/setgray cvx + }ifelse + ]cvx bdf + }{ + AGMCORE_producing_seps MappedCSA 0 get dup/DeviceCMYK eq exch/DeviceGray eq or and AGMCORE_sep_special not and{ + /TintProc[ + /dup cvx + MappedCSA sep_proc_name cvx exch + 0 get/DeviceGray eq{ + 1/exch cvx/sub cvx 0 0 0 4 -1/roll cvx + }if + /Name cvx/findcmykcustomcolor cvx/exch cvx + AGMCORE_host_sep{ + AGMCORE_is_cmyk_sep + /Name cvx + /AGMCORE_IsSeparationAProcessColor load/exec cvx + /not cvx/and cvx + }{ + Name inRip_spot_has_ink not + }ifelse + [ + /pop cvx 1 + ]cvx/if cvx + /setcustomcolor cvx + ]cvx bdf + }{ + /TintProc{setcolor}bdf + [/Separation Name MappedCSA sep_proc_name load]setcolorspace_opt + }ifelse + }ifelse + }ifelse + }ifelse + }ifelse + set_crd + setsepcolor + end +}def +/additive_blend +{ + 3 dict begin + /numarrays xdf + /numcolors xdf + 0 1 numcolors 1 sub + { + /c1 xdf + 1 + 0 1 numarrays 1 sub + { + 1 exch add/index cvx + c1/get cvx/mul cvx + }for + numarrays 1 add 1/roll cvx + }for + numarrays[/pop cvx]cvx/repeat cvx + end +}def +/subtractive_blend +{ + 3 dict begin + /numarrays xdf + /numcolors xdf + 0 1 numcolors 1 sub + { + /c1 xdf + 1 1 + 0 1 numarrays 1 sub + { + 1 3 3 -1 roll add/index cvx + c1/get cvx/sub cvx/mul cvx + }for + /sub cvx + numarrays 1 add 1/roll cvx + }for + numarrays[/pop cvx]cvx/repeat cvx + end +}def +/exec_tint_transform +{ + /TintProc[ + /TintTransform cvx/setcolor cvx + ]cvx bdf + MappedCSA setcolorspace_opt +}bdf +/devn_makecustomcolor +{ + 2 dict begin + /names_index xdf + /Names xdf + 1 1 1 1 Names names_index get findcmykcustomcolor + /devicen_tints AGMCORE_gget names_index get setcustomcolor + Names length{pop}repeat + end +}bdf +/setdevicencolorspace +{ + dup/AliasedColorants known{false}{true}ifelse + current_spot_alias and{ + 7 dict begin + /names_index 0 def + dup/names_len exch/Names get length def + /new_names names_len array def + /new_LookupTables names_len array def + /alias_cnt 0 def + dup/Names get + { + dup map_alias{ + exch pop + dup/ColorLookup known{ + dup begin + new_LookupTables names_index ColorLookup put + end + }{ + dup/Components known{ + dup begin + new_LookupTables names_index Components put + end + }{ + dup begin + new_LookupTables names_index[null null null null]put + end + }ifelse + }ifelse + new_names names_index 3 -1 roll/Name get put + /alias_cnt alias_cnt 1 add def + }{ + /name xdf + new_names names_index name put + dup/LookupTables known{ + dup begin + new_LookupTables names_index LookupTables names_index get put + end + }{ + dup begin + new_LookupTables names_index[null null null null]put + end + }ifelse + }ifelse + /names_index names_index 1 add def + }forall + alias_cnt 0 gt{ + /AliasedColorants true def + /lut_entry_len new_LookupTables 0 get dup length 256 ge{0 get length}{length}ifelse def + 0 1 names_len 1 sub{ + /names_index xdf + new_LookupTables names_index get dup length 256 ge{0 get length}{length}ifelse lut_entry_len ne{ + /AliasedColorants false def + exit + }{ + new_LookupTables names_index get 0 get null eq{ + dup/Names get names_index get/name xdf + name(Cyan)eq name(Magenta)eq name(Yellow)eq name(Black)eq + or or or not{ + /AliasedColorants false def + exit + }if + }if + }ifelse + }for + lut_entry_len 1 eq{ + /AliasedColorants false def + }if + AliasedColorants{ + dup begin + /Names new_names def + /LookupTables new_LookupTables def + /AliasedColorants true def + /NComponents lut_entry_len def + /TintMethod NComponents 4 eq{/Subtractive}{/Additive}ifelse def + /MappedCSA TintMethod/Additive eq{/DeviceRGB}{/DeviceCMYK}ifelse def + currentdict/TTTablesIdx known not{ + /TTTablesIdx -1 def + }if + end + }if + }if + end + }if + dup/devicen_colorspace_dict exch AGMCORE_gput + begin + currentdict/AliasedColorants known{ + AliasedColorants + }{ + false + }ifelse + dup not{ + CSA map_csa + }if + /TintTransform load type/nulltype eq or{ + /TintTransform[ + 0 1 Names length 1 sub + { + /TTTablesIdx TTTablesIdx 1 add def + dup LookupTables exch get dup 0 get null eq + { + 1 index + Names exch get + dup(Cyan)eq + { + pop exch + LookupTables length exch sub + /index cvx + 0 0 0 + } + { + dup(Magenta)eq + { + pop exch + LookupTables length exch sub + /index cvx + 0/exch cvx 0 0 + }{ + (Yellow)eq + { + exch + LookupTables length exch sub + /index cvx + 0 0 3 -1/roll cvx 0 + }{ + exch + LookupTables length exch sub + /index cvx + 0 0 0 4 -1/roll cvx + }ifelse + }ifelse + }ifelse + 5 -1/roll cvx/astore cvx + }{ + dup length 1 sub + LookupTables length 4 -1 roll sub 1 add + /index cvx/mul cvx/round cvx/cvi cvx/get cvx + }ifelse + Names length TTTablesIdx add 1 add 1/roll cvx + }for + Names length[/pop cvx]cvx/repeat cvx + NComponents Names length + TintMethod/Subtractive eq + { + subtractive_blend + }{ + additive_blend + }ifelse + ]cvx bdf + }if + AGMCORE_host_sep{ + Names convert_to_process{ + exec_tint_transform + } + { + currentdict/AliasedColorants known{ + AliasedColorants not + }{ + false + }ifelse + 5 dict begin + /AvoidAliasedColorants xdf + /painted? false def + /names_index 0 def + /names_len Names length def + AvoidAliasedColorants{ + /currentspotalias current_spot_alias def + false set_spot_alias + }if + Names{ + AGMCORE_is_cmyk_sep{ + dup(Cyan)eq AGMCORE_cyan_plate and exch + dup(Magenta)eq AGMCORE_magenta_plate and exch + dup(Yellow)eq AGMCORE_yellow_plate and exch + (Black)eq AGMCORE_black_plate and or or or{ + /devicen_colorspace_dict AGMCORE_gget/TintProc[ + Names names_index/devn_makecustomcolor cvx + ]cvx ddf + /painted? true def + }if + painted?{exit}if + }{ + 0 0 0 0 5 -1 roll findcmykcustomcolor 1 setcustomcolor currentgray 0 eq{ + /devicen_colorspace_dict AGMCORE_gget/TintProc[ + Names names_index/devn_makecustomcolor cvx + ]cvx ddf + /painted? true def + exit + }if + }ifelse + /names_index names_index 1 add def + }forall + AvoidAliasedColorants{ + currentspotalias set_spot_alias + }if + painted?{ + /devicen_colorspace_dict AGMCORE_gget/names_index names_index put + }{ + /devicen_colorspace_dict AGMCORE_gget/TintProc[ + names_len[/pop cvx]cvx/repeat cvx 1/setseparationgray cvx + 0 0 0 0/setcmykcolor cvx + ]cvx ddf + }ifelse + end + }ifelse + } + { + AGMCORE_in_rip_sep{ + Names convert_to_process not + }{ + level3 + }ifelse + { + [/DeviceN Names MappedCSA/TintTransform load]setcolorspace_opt + /TintProc level3 not AGMCORE_in_rip_sep and{ + [ + Names/length cvx[/pop cvx]cvx/repeat cvx + ]cvx bdf + }{ + {setcolor}bdf + }ifelse + }{ + exec_tint_transform + }ifelse + }ifelse + set_crd + /AliasedColorants false def + end +}def +/setindexedcolorspace +{ + dup/indexed_colorspace_dict exch AGMCORE_gput + begin + currentdict/CSDBase known{ + CSDBase/CSD get_res begin + currentdict/Names known{ + currentdict devncs + }{ + 1 currentdict sepcs + }ifelse + AGMCORE_host_sep{ + 4 dict begin + /compCnt/Names where{pop Names length}{1}ifelse def + /NewLookup HiVal 1 add string def + 0 1 HiVal{ + /tableIndex xdf + Lookup dup type/stringtype eq{ + compCnt tableIndex map_index + }{ + exec + }ifelse + /Names where{ + pop setdevicencolor + }{ + setsepcolor + }ifelse + currentgray + tableIndex exch + 255 mul cvi + NewLookup 3 1 roll put + }for + [/Indexed currentcolorspace HiVal NewLookup]setcolorspace_opt + end + }{ + level3 + { + currentdict/Names known{ + [/Indexed[/DeviceN Names MappedCSA/TintTransform load]HiVal Lookup]setcolorspace_opt + }{ + [/Indexed[/Separation Name MappedCSA sep_proc_name load]HiVal Lookup]setcolorspace_opt + }ifelse + }{ + [/Indexed MappedCSA HiVal + [ + currentdict/Names known{ + Lookup dup type/stringtype eq + {/exch cvx CSDBase/CSD get_res/Names get length dup/mul cvx exch/getinterval cvx{255 div}/forall cvx} + {/exec cvx}ifelse + /TintTransform load/exec cvx + }{ + Lookup dup type/stringtype eq + {/exch cvx/get cvx 255/div cvx} + {/exec cvx}ifelse + CSDBase/CSD get_res/MappedCSA get sep_proc_name exch pop/load cvx/exec cvx + }ifelse + ]cvx + ]setcolorspace_opt + }ifelse + }ifelse + end + set_crd + } + { + CSA map_csa + AGMCORE_host_sep level2 not and{ + 0 0 0 0 setcmykcolor + }{ + [/Indexed MappedCSA + level2 not has_color not and{ + dup 0 get dup/DeviceRGB eq exch/DeviceCMYK eq or{ + pop[/DeviceGray] + }if + HiVal GrayLookup + }{ + HiVal + currentdict/RangeArray known{ + { + /indexed_colorspace_dict AGMCORE_gget begin + Lookup exch + dup HiVal gt{ + pop HiVal + }if + NComponents mul NComponents getinterval{}forall + NComponents 1 sub -1 0{ + RangeArray exch 2 mul 2 getinterval aload pop map255_to_range + NComponents 1 roll + }for + end + }bind + }{ + Lookup + }ifelse + }ifelse + ]setcolorspace_opt + set_crd + }ifelse + }ifelse + end +}def +/setindexedcolor +{ + AGMCORE_host_sep{ + /indexed_colorspace_dict AGMCORE_gget + begin + currentdict/CSDBase known{ + CSDBase/CSD get_res begin + currentdict/Names known{ + map_indexed_devn + devn + } + { + Lookup 1 3 -1 roll map_index + sep + }ifelse + end + }{ + Lookup MappedCSA/DeviceCMYK eq{4}{1}ifelse 3 -1 roll + map_index + MappedCSA/DeviceCMYK eq{setcmykcolor}{setgray}ifelse + }ifelse + end + }{ + level3 not AGMCORE_in_rip_sep and/indexed_colorspace_dict AGMCORE_gget/CSDBase known and{ + /indexed_colorspace_dict AGMCORE_gget/CSDBase get/CSD get_res begin + map_indexed_devn + devn + end + } + { + setcolor + }ifelse + }ifelse +}def +/ignoreimagedata +{ + currentoverprint not{ + gsave + dup clonedict begin + 1 setgray + /Decode[0 1]def + /DataSourcedef + /MultipleDataSources false def + /BitsPerComponent 8 def + currentdict end + systemdict/image gx + grestore + }if + consumeimagedata +}def +/add_res +{ + dup/CSD eq{ + pop + //Adobe_AGM_Core begin + /AGMCORE_CSD_cache load 3 1 roll put + end + }{ + defineresource pop + }ifelse +}def +/del_res +{ + { + aload pop exch + dup/CSD eq{ + pop + {//Adobe_AGM_Core/AGMCORE_CSD_cache get exch undef}forall + }{ + exch + {1 index undefineresource}forall + pop + }ifelse + }forall +}def +/get_res +{ + dup/CSD eq{ + pop + dup type dup/nametype eq exch/stringtype eq or{ + AGMCORE_CSD_cache exch get + }if + }{ + findresource + }ifelse +}def +/get_csa_by_name +{ + dup type dup/nametype eq exch/stringtype eq or{ + /CSA get_res + }if +}def +/paintproc_buf_init +{ + /count get 0 0 put +}def +/paintproc_buf_next +{ + dup/count get dup 0 get + dup 3 1 roll + 1 add 0 xpt + get +}def +/cachepaintproc_compress +{ + 5 dict begin + currentfile exch 0 exch/SubFileDecode filter/ReadFilter exch def + /ppdict 20 dict def + /string_size 16000 def + /readbuffer string_size string def + currentglobal true setglobal + ppdict 1 array dup 0 1 put/count xpt + setglobal + /LZWFilter + { + exch + dup length 0 eq{ + pop + }{ + ppdict dup length 1 sub 3 -1 roll put + }ifelse + {string_size}{0}ifelse string + }/LZWEncode filter def + { + ReadFilter readbuffer readstring + exch LZWFilter exch writestring + not{exit}if + }loop + LZWFilter closefile + ppdict + end +}def +/cachepaintproc +{ + 2 dict begin + currentfile exch 0 exch/SubFileDecode filter/ReadFilter exch def + /ppdict 20 dict def + currentglobal true setglobal + ppdict 1 array dup 0 1 put/count xpt + setglobal + { + ReadFilter 16000 string readstring exch + ppdict dup length 1 sub 3 -1 roll put + not{exit}if + }loop + ppdict dup dup length 1 sub()put + end +}def +/make_pattern +{ + exch clonedict exch + dup matrix currentmatrix matrix concatmatrix 0 0 3 2 roll itransform + exch 3 index/XStep get 1 index exch 2 copy div cvi mul sub sub + exch 3 index/YStep get 1 index exch 2 copy div cvi mul sub sub + matrix translate exch matrix concatmatrix + 1 index begin + BBox 0 get XStep div cvi XStep mul/xshift exch neg def + BBox 1 get YStep div cvi YStep mul/yshift exch neg def + BBox 0 get xshift add + BBox 1 get yshift add + BBox 2 get xshift add + BBox 3 get yshift add + 4 array astore + /BBox exch def + [xshift yshift/translate load null/exec load]dup + 3/PaintProc load put cvx/PaintProc exch def + end + gsave 0 setgray + makepattern + grestore +}def +/set_pattern +{ + dup/PatternType get 1 eq{ + dup/PaintType get 1 eq{ + currentoverprint sop[/DeviceGray]setcolorspace 0 setgray + }if + }if + setpattern +}def +/setcolorspace_opt +{ + dup currentcolorspace eq{pop}{setcolorspace}ifelse +}def +/updatecolorrendering +{ + currentcolorrendering/RenderingIntent known{ + currentcolorrendering/RenderingIntent get + } + { + Intent/AbsoluteColorimetric eq + { + /absolute_colorimetric_crd AGMCORE_gget dup null eq + } + { + Intent/RelativeColorimetric eq + { + /relative_colorimetric_crd AGMCORE_gget dup null eq + } + { + Intent/Saturation eq + { + /saturation_crd AGMCORE_gget dup null eq + } + { + /perceptual_crd AGMCORE_gget dup null eq + }ifelse + }ifelse + }ifelse + { + pop null + } + { + /RenderingIntent known{null}{Intent}ifelse + }ifelse + }ifelse + Intent ne{ + Intent/ColorRendering{findresource}stopped + { + pop pop systemdict/findcolorrendering known + { + Intent findcolorrendering + { + /ColorRendering findresource true exch + } + { + /ColorRendering findresource + product(Xerox Phaser 5400)ne + exch + }ifelse + dup Intent/AbsoluteColorimetric eq + { + /absolute_colorimetric_crd exch AGMCORE_gput + } + { + Intent/RelativeColorimetric eq + { + /relative_colorimetric_crd exch AGMCORE_gput + } + { + Intent/Saturation eq + { + /saturation_crd exch AGMCORE_gput + } + { + Intent/Perceptual eq + { + /perceptual_crd exch AGMCORE_gput + } + { + pop + }ifelse + }ifelse + }ifelse + }ifelse + 1 index{exch}{pop}ifelse + } + {false}ifelse + } + {true}ifelse + { + dup begin + currentdict/TransformPQR known{ + currentdict/TransformPQR get aload pop + 3{{}eq 3 1 roll}repeat or or + } + {true}ifelse + currentdict/MatrixPQR known{ + currentdict/MatrixPQR get aload pop + 1.0 eq 9 1 roll 0.0 eq 9 1 roll 0.0 eq 9 1 roll + 0.0 eq 9 1 roll 1.0 eq 9 1 roll 0.0 eq 9 1 roll + 0.0 eq 9 1 roll 0.0 eq 9 1 roll 1.0 eq + and and and and and and and and + } + {true}ifelse + end + or + { + clonedict begin + /TransformPQR[ + {4 -1 roll 3 get dup 3 1 roll sub 5 -1 roll 3 get 3 -1 roll sub div + 3 -1 roll 3 get 3 -1 roll 3 get dup 4 1 roll sub mul add}bind + {4 -1 roll 4 get dup 3 1 roll sub 5 -1 roll 4 get 3 -1 roll sub div + 3 -1 roll 4 get 3 -1 roll 4 get dup 4 1 roll sub mul add}bind + {4 -1 roll 5 get dup 3 1 roll sub 5 -1 roll 5 get 3 -1 roll sub div + 3 -1 roll 5 get 3 -1 roll 5 get dup 4 1 roll sub mul add}bind + ]def + /MatrixPQR[0.8951 -0.7502 0.0389 0.2664 1.7135 -0.0685 -0.1614 0.0367 1.0296]def + /RangePQR[-0.3227950745 2.3229645538 -1.5003771057 3.5003465881 -0.1369979095 2.136967392]def + currentdict end + }if + setcolorrendering_opt + }if + }if +}def +/set_crd +{ + AGMCORE_host_sep not level2 and{ + currentdict/ColorRendering known{ + ColorRendering/ColorRendering{findresource}stopped not{setcolorrendering_opt}if + }{ + currentdict/Intent known{ + updatecolorrendering + }if + }ifelse + currentcolorspace dup type/arraytype eq + {0 get}if + /DeviceRGB eq + { + currentdict/UCR known + {/UCR}{/AGMCORE_currentucr}ifelse + load setundercolorremoval + currentdict/BG known + {/BG}{/AGMCORE_currentbg}ifelse + load setblackgeneration + }if + }if +}def +/set_ucrbg +{ + dup null eq{pop/AGMCORE_currentbg load}{/Procedure get_res}ifelse setblackgeneration + dup null eq{pop/AGMCORE_currentucr load}{/Procedure get_res}ifelse setundercolorremoval +}def +/setcolorrendering_opt +{ + dup currentcolorrendering eq{ + pop + }{ + product(HP Color LaserJet 2605)anchorsearch{ + pop pop pop + }{ + pop + clonedict + begin + /Intent Intent def + currentdict + end + setcolorrendering + }ifelse + }ifelse +}def +/cpaint_gcomp +{ + convert_to_process//Adobe_AGM_Core/AGMCORE_ConvertToProcess xddf + //Adobe_AGM_Core/AGMCORE_ConvertToProcess get not + { + (%end_cpaint_gcomp)flushinput + }if +}def +/cpaint_gsep +{ + //Adobe_AGM_Core/AGMCORE_ConvertToProcess get + { + (%end_cpaint_gsep)flushinput + }if +}def +/cpaint_gend +{np}def +/T1_path +{ + currentfile token pop currentfile token pop mo + { + currentfile token pop dup type/stringtype eq + {pop exit}if + 0 exch rlineto + currentfile token pop dup type/stringtype eq + {pop exit}if + 0 rlineto + }loop +}def +/T1_gsave + level3 + {/clipsave} + {/gsave}ifelse + load def +/T1_grestore + level3 + {/cliprestore} + {/grestore}ifelse + load def +/set_spot_alias_ary +{ + dup inherit_aliases + //Adobe_AGM_Core/AGMCORE_SpotAliasAry xddf +}def +/set_spot_normalization_ary +{ + dup inherit_aliases + dup length + /AGMCORE_SpotAliasAry where{pop AGMCORE_SpotAliasAry length add}if + array + //Adobe_AGM_Core/AGMCORE_SpotAliasAry2 xddf + /AGMCORE_SpotAliasAry where{ + pop + AGMCORE_SpotAliasAry2 0 AGMCORE_SpotAliasAry putinterval + AGMCORE_SpotAliasAry length + }{0}ifelse + AGMCORE_SpotAliasAry2 3 1 roll exch putinterval + true set_spot_alias +}def +/inherit_aliases +{ + {dup/Name get map_alias{/CSD put}{pop}ifelse}forall +}def +/set_spot_alias +{ + /AGMCORE_SpotAliasAry2 where{ + /AGMCORE_current_spot_alias 3 -1 roll put + }{ + pop + }ifelse +}def +/current_spot_alias +{ + /AGMCORE_SpotAliasAry2 where{ + /AGMCORE_current_spot_alias get + }{ + false + }ifelse +}def +/map_alias +{ + /AGMCORE_SpotAliasAry2 where{ + begin + /AGMCORE_name xdf + false + AGMCORE_SpotAliasAry2{ + dup/Name get AGMCORE_name eq{ + /CSD get/CSD get_res + exch pop true + exit + }{ + pop + }ifelse + }forall + end + }{ + pop false + }ifelse +}bdf +/spot_alias +{ + true set_spot_alias + /AGMCORE_&setcustomcolor AGMCORE_key_known not{ + //Adobe_AGM_Core/AGMCORE_&setcustomcolor/setcustomcolor load put + }if + /customcolor_tint 1 AGMCORE_gput + //Adobe_AGM_Core begin + /setcustomcolor + { + //Adobe_AGM_Core begin + dup/customcolor_tint exch AGMCORE_gput + 1 index aload pop pop 1 eq exch 1 eq and exch 1 eq and exch 1 eq and not + current_spot_alias and{1 index 4 get map_alias}{false}ifelse + { + false set_spot_alias + /sep_colorspace_dict AGMCORE_gget null ne + {/sep_colorspace_dict AGMCORE_gget/ForeignContent known not}{false}ifelse + 3 1 roll 2 index{ + exch pop/sep_tint AGMCORE_gget exch + }if + mark 3 1 roll + setsepcolorspace + counttomark 0 ne{ + setsepcolor + }if + pop + not{/sep_tint 1.0 AGMCORE_gput/sep_colorspace_dict AGMCORE_gget/ForeignContent true put}if + pop + true set_spot_alias + }{ + AGMCORE_&setcustomcolor + }ifelse + end + }bdf + end +}def +/begin_feature +{ + Adobe_AGM_Core/AGMCORE_feature_dictCount countdictstack put + count Adobe_AGM_Core/AGMCORE_feature_opCount 3 -1 roll put + {Adobe_AGM_Core/AGMCORE_feature_ctm matrix currentmatrix put}if +}def +/end_feature +{ + 2 dict begin + /spd/setpagedevice load def + /setpagedevice{get_gstate spd set_gstate}def + stopped{$error/newerror false put}if + end + count Adobe_AGM_Core/AGMCORE_feature_opCount get sub dup 0 gt{{pop}repeat}{pop}ifelse + countdictstack Adobe_AGM_Core/AGMCORE_feature_dictCount get sub dup 0 gt{{end}repeat}{pop}ifelse + {Adobe_AGM_Core/AGMCORE_feature_ctm get setmatrix}if +}def +/set_negative +{ + //Adobe_AGM_Core begin + /AGMCORE_inverting exch def + level2{ + currentpagedevice/NegativePrint known AGMCORE_distilling not and{ + currentpagedevice/NegativePrint get//Adobe_AGM_Core/AGMCORE_inverting get ne{ + true begin_feature true{ + <>setpagedevice + }end_feature + }if + /AGMCORE_inverting false def + }if + }if + AGMCORE_inverting{ + [{1 exch sub}/exec load dup currenttransfer exch]cvx bind settransfer + AGMCORE_distilling{ + erasepage + }{ + gsave np clippath 1/setseparationgray where{pop setseparationgray}{setgray}ifelse + /AGMIRS_&fill where{pop AGMIRS_&fill}{fill}ifelse grestore + }ifelse + }if + end +}def +/lw_save_restore_override{ + /md where{ + pop + md begin + initializepage + /initializepage{}def + /pmSVsetup{}def + /endp{}def + /pse{}def + /psb{}def + /orig_showpage where + {pop} + {/orig_showpage/showpage load def} + ifelse + /showpage{orig_showpage gR}def + end + }if +}def +/pscript_showpage_override{ + /NTPSOct95 where + { + begin + showpage + save + /showpage/restore load def + /restore{exch pop}def + end + }if +}def +/driver_media_override +{ + /md where{ + pop + md/initializepage known{ + md/initializepage{}put + }if + md/rC known{ + md/rC{4{pop}repeat}put + }if + }if + /mysetup where{ + /mysetup[1 0 0 1 0 0]put + }if + Adobe_AGM_Core/AGMCORE_Default_CTM matrix currentmatrix put + level2 + {Adobe_AGM_Core/AGMCORE_Default_PageSize currentpagedevice/PageSize get put}if +}def +/capture_mysetup +{ + /Pscript_Win_Data where{ + pop + Pscript_Win_Data/mysetup known{ + Adobe_AGM_Core/save_mysetup Pscript_Win_Data/mysetup get put + }if + }if +}def +/restore_mysetup +{ + /Pscript_Win_Data where{ + pop + Pscript_Win_Data/mysetup known{ + Adobe_AGM_Core/save_mysetup known{ + Pscript_Win_Data/mysetup Adobe_AGM_Core/save_mysetup get put + Adobe_AGM_Core/save_mysetup undef + }if + }if + }if +}def +/driver_check_media_override +{ + /PrepsDict where + {pop} + { + Adobe_AGM_Core/AGMCORE_Default_CTM get matrix currentmatrix ne + Adobe_AGM_Core/AGMCORE_Default_PageSize get type/arraytype eq + { + Adobe_AGM_Core/AGMCORE_Default_PageSize get 0 get currentpagedevice/PageSize get 0 get eq and + Adobe_AGM_Core/AGMCORE_Default_PageSize get 1 get currentpagedevice/PageSize get 1 get eq and + }if + { + Adobe_AGM_Core/AGMCORE_Default_CTM get setmatrix + }if + }ifelse +}def +AGMCORE_err_strings begin + /AGMCORE_bad_environ(Environment not satisfactory for this job. Ensure that the PPD is correct or that the PostScript level requested is supported by this printer. )def + /AGMCORE_color_space_onhost_seps(This job contains colors that will not separate with on-host methods. )def + /AGMCORE_invalid_color_space(This job contains an invalid color space. )def +end +/set_def_ht +{AGMCORE_def_ht sethalftone}def +/set_def_flat +{AGMCORE_Default_flatness setflat}def +end +systemdict/setpacking known +{setpacking}if +%%EndResource +%%BeginResource: procset Adobe_CoolType_Core 2.31 0 %%Copyright: Copyright 1997-2006 Adobe Systems Incorporated. All Rights Reserved. %%Version: 2.31 0 10 dict begin /Adobe_CoolType_Passthru currentdict def /Adobe_CoolType_Core_Defined userdict/Adobe_CoolType_Core known def Adobe_CoolType_Core_Defined {/Adobe_CoolType_Core userdict/Adobe_CoolType_Core get def} if userdict/Adobe_CoolType_Core 70 dict dup begin put /Adobe_CoolType_Version 2.31 def /Level2? systemdict/languagelevel known dup {pop systemdict/languagelevel get 2 ge} if def Level2? not { /currentglobal false def /setglobal/pop load def /gcheck{pop false}bind def /currentpacking false def /setpacking/pop load def /SharedFontDirectory 0 dict def } if currentpacking true setpacking currentglobal false setglobal userdict/Adobe_CoolType_Data 2 copy known not {2 copy 10 dict put} if get begin /@opStackCountByLevel 32 dict def /@opStackLevel 0 def /@dictStackCountByLevel 32 dict def /@dictStackLevel 0 def end setglobal currentglobal true setglobal userdict/Adobe_CoolType_GVMFonts known not {userdict/Adobe_CoolType_GVMFonts 10 dict put} if setglobal currentglobal false setglobal userdict/Adobe_CoolType_LVMFonts known not {userdict/Adobe_CoolType_LVMFonts 10 dict put} if setglobal /ct_VMDictPut { dup gcheck{Adobe_CoolType_GVMFonts}{Adobe_CoolType_LVMFonts}ifelse 3 1 roll put }bind def /ct_VMDictUndef { dup Adobe_CoolType_GVMFonts exch known {Adobe_CoolType_GVMFonts exch undef} { dup Adobe_CoolType_LVMFonts exch known {Adobe_CoolType_LVMFonts exch undef} {pop} ifelse }ifelse }bind def /ct_str1 1 string def /ct_xshow { /_ct_na exch def /_ct_i 0 def currentpoint /_ct_y exch def /_ct_x exch def { pop pop ct_str1 exch 0 exch put ct_str1 show {_ct_na _ct_i get}stopped {pop pop} { _ct_x _ct_y moveto 0 rmoveto } ifelse /_ct_i _ct_i 1 add def currentpoint /_ct_y exch def /_ct_x exch def } exch @cshow }bind def /ct_yshow { /_ct_na exch def /_ct_i 0 def currentpoint /_ct_y exch def /_ct_x exch def { pop pop ct_str1 exch 0 exch put ct_str1 show {_ct_na _ct_i get}stopped {pop pop} { _ct_x _ct_y moveto 0 exch rmoveto } ifelse /_ct_i _ct_i 1 add def currentpoint /_ct_y exch def /_ct_x exch def } exch @cshow }bind def /ct_xyshow { /_ct_na exch def /_ct_i 0 def currentpoint /_ct_y exch def /_ct_x exch def { pop pop ct_str1 exch 0 exch put ct_str1 show {_ct_na _ct_i get}stopped {pop pop} { {_ct_na _ct_i 1 add get}stopped {pop pop pop} { _ct_x _ct_y moveto rmoveto } ifelse } ifelse /_ct_i _ct_i 2 add def currentpoint /_ct_y exch def /_ct_x exch def } exch @cshow }bind def /xsh{{@xshow}stopped{Adobe_CoolType_Data begin ct_xshow end}if}bind def /ysh{{@yshow}stopped{Adobe_CoolType_Data begin ct_yshow end}if}bind def /xysh{{@xyshow}stopped{Adobe_CoolType_Data begin ct_xyshow end}if}bind def currentglobal true setglobal /ct_T3Defs { /BuildChar { 1 index/Encoding get exch get 1 index/BuildGlyph get exec }bind def /BuildGlyph { exch begin GlyphProcs exch get exec end }bind def }bind def setglobal /@_SaveStackLevels { Adobe_CoolType_Data begin /@vmState currentglobal def false setglobal @opStackCountByLevel @opStackLevel 2 copy known not { 2 copy 3 dict dup/args 7 index 5 add array put put get } { get dup/args get dup length 3 index lt { dup length 5 add array exch 1 index exch 0 exch putinterval 1 index exch/args exch put } {pop} ifelse } ifelse begin count 1 sub 1 index lt {pop count} if dup/argCount exch def dup 0 gt { args exch 0 exch getinterval astore pop } {pop} ifelse count /restCount exch def end /@opStackLevel @opStackLevel 1 add def countdictstack 1 sub @dictStackCountByLevel exch @dictStackLevel exch put /@dictStackLevel @dictStackLevel 1 add def @vmState setglobal end }bind def /@_RestoreStackLevels { Adobe_CoolType_Data begin /@opStackLevel @opStackLevel 1 sub def @opStackCountByLevel @opStackLevel get begin count restCount sub dup 0 gt {{pop}repeat} {pop} ifelse args 0 argCount getinterval{}forall end /@dictStackLevel @dictStackLevel 1 sub def @dictStackCountByLevel @dictStackLevel get end countdictstack exch sub dup 0 gt {{end}repeat} {pop} ifelse }bind def /@_PopStackLevels { Adobe_CoolType_Data begin /@opStackLevel @opStackLevel 1 sub def /@dictStackLevel @dictStackLevel 1 sub def end }bind def /@Raise { exch cvx exch errordict exch get exec stop }bind def /@ReRaise { cvx $error/errorname get errordict exch get exec stop }bind def /@Stopped { 0 @#Stopped }bind def /@#Stopped { @_SaveStackLevels stopped {@_RestoreStackLevels true} {@_PopStackLevels false} ifelse }bind def /@Arg { Adobe_CoolType_Data begin @opStackCountByLevel @opStackLevel 1 sub get begin args exch argCount 1 sub exch sub get end end }bind def currentglobal true setglobal /CTHasResourceForAllBug Level2? { 1 dict dup /@shouldNotDisappearDictValue true def Adobe_CoolType_Data exch/@shouldNotDisappearDict exch put begin count @_SaveStackLevels {(*){pop stop}128 string/Category resourceforall} stopped pop @_RestoreStackLevels currentdict Adobe_CoolType_Data/@shouldNotDisappearDict get dup 3 1 roll ne dup 3 1 roll { /@shouldNotDisappearDictValue known { { end currentdict 1 index eq {pop exit} if } loop } if } { pop end } ifelse } {false} ifelse def true setglobal /CTHasResourceStatusBug Level2? { mark {/steveamerige/Category resourcestatus} stopped {cleartomark true} {cleartomark currentglobal not} ifelse } {false} ifelse def setglobal /CTResourceStatus { mark 3 1 roll /Category findresource begin ({ResourceStatus}stopped)0()/SubFileDecode filter cvx exec {cleartomark false} {{3 2 roll pop true}{cleartomark false}ifelse} ifelse end }bind def /CTWorkAroundBugs { Level2? { /cid_PreLoad/ProcSet resourcestatus { pop pop currentglobal mark { (*) { dup/CMap CTHasResourceStatusBug {CTResourceStatus} {resourcestatus} ifelse { pop dup 0 eq exch 1 eq or { dup/CMap findresource gcheck setglobal /CMap undefineresource } { pop CTHasResourceForAllBug {exit} {stop} ifelse } ifelse } {pop} ifelse } 128 string/CMap resourceforall } stopped {cleartomark} stopped pop setglobal } if } if }bind def /ds { Adobe_CoolType_Core begin CTWorkAroundBugs /mo/moveto load def /nf/newencodedfont load def /msf{makefont setfont}bind def /uf{dup undefinefont ct_VMDictUndef}bind def /ur/undefineresource load def /chp/charpath load def /awsh/awidthshow load def /wsh/widthshow load def /ash/ashow load def /@xshow/xshow load def /@yshow/yshow load def /@xyshow/xyshow load def /@cshow/cshow load def /sh/show load def /rp/repeat load def /.n/.notdef def end currentglobal false setglobal userdict/Adobe_CoolType_Data 2 copy known not {2 copy 10 dict put} if get begin /AddWidths? false def /CC 0 def /charcode 2 string def /@opStackCountByLevel 32 dict def /@opStackLevel 0 def /@dictStackCountByLevel 32 dict def /@dictStackLevel 0 def /InVMFontsByCMap 10 dict def /InVMDeepCopiedFonts 10 dict def end setglobal }bind def /dt { currentdict Adobe_CoolType_Core eq {end} if }bind def /ps { Adobe_CoolType_Core begin Adobe_CoolType_GVMFonts begin Adobe_CoolType_LVMFonts begin SharedFontDirectory begin }bind def /pt { end end end end }bind def /unload { systemdict/languagelevel known { systemdict/languagelevel get 2 ge { userdict/Adobe_CoolType_Core 2 copy known {undef} {pop pop} ifelse } if } if }bind def /ndf { 1 index where {pop pop pop} {dup xcheck{bind}if def} ifelse }def /findfont systemdict begin userdict begin /globaldict where{/globaldict get begin}if dup where pop exch get /globaldict where{pop end}if end end Adobe_CoolType_Core_Defined {/systemfindfont exch def} { /findfont 1 index def /systemfindfont exch def } ifelse /undefinefont {pop}ndf /copyfont { currentglobal 3 1 roll 1 index gcheck setglobal dup null eq{0}{dup length}ifelse 2 index length add 1 add dict begin exch { 1 index/FID eq {pop pop} {def} ifelse } forall dup null eq {pop} {{def}forall} ifelse currentdict end exch setglobal }bind def /copyarray { currentglobal exch dup gcheck setglobal dup length array copy exch setglobal }bind def /newencodedfont { currentglobal { SharedFontDirectory 3 index known {SharedFontDirectory 3 index get/FontReferenced known} {false} ifelse } { FontDirectory 3 index known {FontDirectory 3 index get/FontReferenced known} { SharedFontDirectory 3 index known {SharedFontDirectory 3 index get/FontReferenced known} {false} ifelse } ifelse } ifelse dup { 3 index findfont/FontReferenced get 2 index dup type/nametype eq {findfont} if ne {pop false} if } if dup { 1 index dup type/nametype eq {findfont} if dup/CharStrings known { /CharStrings get length 4 index findfont/CharStrings get length ne { pop false } if } {pop} ifelse } if { pop 1 index findfont /Encoding get exch 0 1 255 {2 copy get 3 index 3 1 roll put} for pop pop pop } { currentglobal 4 1 roll dup type/nametype eq {findfont} if dup gcheck setglobal dup dup maxlength 2 add dict begin exch { 1 index/FID ne 2 index/Encoding ne and {def} {pop pop} ifelse } forall /FontReferenced exch def /Encoding exch dup length array copy def /FontName 1 index dup type/stringtype eq{cvn}if def dup currentdict end definefont ct_VMDictPut setglobal } ifelse }bind def /SetSubstituteStrategy { $SubstituteFont begin dup type/dicttype ne {0 dict} if currentdict/$Strategies known { exch $Strategies exch 2 copy known { get 2 copy maxlength exch maxlength add dict begin {def}forall {def}forall currentdict dup/$Init known {dup/$Init get exec} if end /$Strategy exch def } {pop pop pop} ifelse } {pop pop} ifelse end }bind def /scff { $SubstituteFont begin dup type/stringtype eq {dup length exch} {null} ifelse /$sname exch def /$slen exch def /$inVMIndex $sname null eq { 1 index $str cvs dup length $slen sub $slen getinterval cvn } {$sname} ifelse def end {findfont} @Stopped { dup length 8 add string exch 1 index 0(BadFont:)putinterval 1 index exch 8 exch dup length string cvs putinterval cvn {findfont} @Stopped {pop/Courier findfont} if } if $SubstituteFont begin /$sname null def /$slen 0 def /$inVMIndex null def end }bind def /isWidthsOnlyFont { dup/WidthsOnly known {pop pop true} { dup/FDepVector known {/FDepVector get{isWidthsOnlyFont dup{exit}if}forall} { dup/FDArray known {/FDArray get{isWidthsOnlyFont dup{exit}if}forall} {pop} ifelse } ifelse } ifelse }bind def /ct_StyleDicts 4 dict dup begin /Adobe-Japan1 4 dict dup begin Level2? { /Serif /HeiseiMin-W3-83pv-RKSJ-H/Font resourcestatus {pop pop/HeiseiMin-W3} { /CIDFont/Category resourcestatus { pop pop /HeiseiMin-W3/CIDFont resourcestatus {pop pop/HeiseiMin-W3} {/Ryumin-Light} ifelse } {/Ryumin-Light} ifelse } ifelse def /SansSerif /HeiseiKakuGo-W5-83pv-RKSJ-H/Font resourcestatus {pop pop/HeiseiKakuGo-W5} { /CIDFont/Category resourcestatus { pop pop /HeiseiKakuGo-W5/CIDFont resourcestatus {pop pop/HeiseiKakuGo-W5} {/GothicBBB-Medium} ifelse } {/GothicBBB-Medium} ifelse } ifelse def /HeiseiMaruGo-W4-83pv-RKSJ-H/Font resourcestatus {pop pop/HeiseiMaruGo-W4} { /CIDFont/Category resourcestatus { pop pop /HeiseiMaruGo-W4/CIDFont resourcestatus {pop pop/HeiseiMaruGo-W4} { /Jun101-Light-RKSJ-H/Font resourcestatus {pop pop/Jun101-Light} {SansSerif} ifelse } ifelse } { /Jun101-Light-RKSJ-H/Font resourcestatus {pop pop/Jun101-Light} {SansSerif} ifelse } ifelse } ifelse /RoundSansSerif exch def /Default Serif def } { /Serif/Ryumin-Light def /SansSerif/GothicBBB-Medium def { (fonts/Jun101-Light-83pv-RKSJ-H)status }stopped {pop}{ {pop pop pop pop/Jun101-Light} {SansSerif} ifelse /RoundSansSerif exch def }ifelse /Default Serif def } ifelse end def /Adobe-Korea1 4 dict dup begin /Serif/HYSMyeongJo-Medium def /SansSerif/HYGoThic-Medium def /RoundSansSerif SansSerif def /Default Serif def end def /Adobe-GB1 4 dict dup begin /Serif/STSong-Light def /SansSerif/STHeiti-Regular def /RoundSansSerif SansSerif def /Default Serif def end def /Adobe-CNS1 4 dict dup begin /Serif/MKai-Medium def /SansSerif/MHei-Medium def /RoundSansSerif SansSerif def /Default Serif def end def end def Level2?{currentglobal true setglobal}if /ct_BoldRomanWidthProc { stringwidth 1 index 0 ne{exch .03 add exch}if setcharwidth 0 0 }bind def /ct_Type0WidthProc { dup stringwidth 0 0 moveto 2 index true charpath pathbbox 0 -1 7 index 2 div .88 setcachedevice2 pop 0 0 }bind def /ct_Type0WMode1WidthProc { dup stringwidth pop 2 div neg -0.88 2 copy moveto 0 -1 5 -1 roll true charpath pathbbox setcachedevice }bind def /cHexEncoding [/c00/c01/c02/c03/c04/c05/c06/c07/c08/c09/c0A/c0B/c0C/c0D/c0E/c0F/c10/c11/c12 /c13/c14/c15/c16/c17/c18/c19/c1A/c1B/c1C/c1D/c1E/c1F/c20/c21/c22/c23/c24/c25 /c26/c27/c28/c29/c2A/c2B/c2C/c2D/c2E/c2F/c30/c31/c32/c33/c34/c35/c36/c37/c38 /c39/c3A/c3B/c3C/c3D/c3E/c3F/c40/c41/c42/c43/c44/c45/c46/c47/c48/c49/c4A/c4B /c4C/c4D/c4E/c4F/c50/c51/c52/c53/c54/c55/c56/c57/c58/c59/c5A/c5B/c5C/c5D/c5E /c5F/c60/c61/c62/c63/c64/c65/c66/c67/c68/c69/c6A/c6B/c6C/c6D/c6E/c6F/c70/c71 /c72/c73/c74/c75/c76/c77/c78/c79/c7A/c7B/c7C/c7D/c7E/c7F/c80/c81/c82/c83/c84 /c85/c86/c87/c88/c89/c8A/c8B/c8C/c8D/c8E/c8F/c90/c91/c92/c93/c94/c95/c96/c97 /c98/c99/c9A/c9B/c9C/c9D/c9E/c9F/cA0/cA1/cA2/cA3/cA4/cA5/cA6/cA7/cA8/cA9/cAA /cAB/cAC/cAD/cAE/cAF/cB0/cB1/cB2/cB3/cB4/cB5/cB6/cB7/cB8/cB9/cBA/cBB/cBC/cBD /cBE/cBF/cC0/cC1/cC2/cC3/cC4/cC5/cC6/cC7/cC8/cC9/cCA/cCB/cCC/cCD/cCE/cCF/cD0 /cD1/cD2/cD3/cD4/cD5/cD6/cD7/cD8/cD9/cDA/cDB/cDC/cDD/cDE/cDF/cE0/cE1/cE2/cE3 /cE4/cE5/cE6/cE7/cE8/cE9/cEA/cEB/cEC/cED/cEE/cEF/cF0/cF1/cF2/cF3/cF4/cF5/cF6 /cF7/cF8/cF9/cFA/cFB/cFC/cFD/cFE/cFF]def /ct_BoldBaseFont 11 dict begin /FontType 3 def /FontMatrix[1 0 0 1 0 0]def /FontBBox[0 0 1 1]def /Encoding cHexEncoding def /_setwidthProc/ct_BoldRomanWidthProc load def /_bcstr1 1 string def /BuildChar { exch begin _basefont setfont _bcstr1 dup 0 4 -1 roll put dup _setwidthProc 3 copy moveto show _basefonto setfont moveto show end }bind def currentdict end def systemdict/composefont known { /ct_DefineIdentity-H { /Identity-H/CMap resourcestatus { pop pop } { /CIDInit/ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo 3 dict dup begin /Registry(Adobe)def /Ordering(Identity)def /Supplement 0 def end def /CMapName/Identity-H def /CMapVersion 1.000 def /CMapType 1 def 1 begincodespacerange <0000> endcodespacerange 1 begincidrange <0000>0 endcidrange endcmap CMapName currentdict/CMap defineresource pop end end } ifelse } def /ct_BoldBaseCIDFont 11 dict begin /CIDFontType 1 def /CIDFontName/ct_BoldBaseCIDFont def /FontMatrix[1 0 0 1 0 0]def /FontBBox[0 0 1 1]def /_setwidthProc/ct_Type0WidthProc load def /_bcstr2 2 string def /BuildGlyph { exch begin _basefont setfont _bcstr2 1 2 index 256 mod put _bcstr2 0 3 -1 roll 256 idiv put _bcstr2 dup _setwidthProc 3 copy moveto show _basefonto setfont moveto show end }bind def currentdict end def }if Level2?{setglobal}if /ct_CopyFont{ { 1 index/FID ne 2 index/UniqueID ne and {def}{pop pop}ifelse }forall }bind def /ct_Type0CopyFont { exch dup length dict begin ct_CopyFont [ exch FDepVector { dup/FontType get 0 eq { 1 index ct_Type0CopyFont /_ctType0 exch definefont } { /_ctBaseFont exch 2 index exec } ifelse exch } forall pop ] /FDepVector exch def currentdict end }bind def /ct_MakeBoldFont { dup/ct_SyntheticBold known { dup length 3 add dict begin ct_CopyFont /ct_StrokeWidth .03 0 FontMatrix idtransform pop def /ct_SyntheticBold true def currentdict end definefont } { dup dup length 3 add dict begin ct_CopyFont /PaintType 2 def /StrokeWidth .03 0 FontMatrix idtransform pop def /dummybold currentdict end definefont dup/FontType get dup 9 ge exch 11 le and { ct_BoldBaseCIDFont dup length 3 add dict copy begin dup/CIDSystemInfo get/CIDSystemInfo exch def ct_DefineIdentity-H /_Type0Identity/Identity-H 3 -1 roll[exch]composefont /_basefont exch def /_Type0Identity/Identity-H 3 -1 roll[exch]composefont /_basefonto exch def currentdict end /CIDFont defineresource } { ct_BoldBaseFont dup length 3 add dict copy begin /_basefont exch def /_basefonto exch def currentdict end definefont } ifelse } ifelse }bind def /ct_MakeBold{ 1 index 1 index findfont currentglobal 5 1 roll dup gcheck setglobal dup /FontType get 0 eq { dup/WMode known{dup/WMode get 1 eq}{false}ifelse version length 4 ge and {version 0 4 getinterval cvi 2015 ge} {true} ifelse {/ct_Type0WidthProc} {/ct_Type0WMode1WidthProc} ifelse ct_BoldBaseFont/_setwidthProc 3 -1 roll load put {ct_MakeBoldFont}ct_Type0CopyFont definefont } { dup/_fauxfont known not 1 index/SubstMaster known not and { ct_BoldBaseFont/_setwidthProc /ct_BoldRomanWidthProc load put ct_MakeBoldFont } { 2 index 2 index eq {exch pop } { dup length dict begin ct_CopyFont currentdict end definefont } ifelse } ifelse } ifelse pop pop pop setglobal }bind def /?str1 256 string def /?set { $SubstituteFont begin /$substituteFound false def /$fontname 1 index def /$doSmartSub false def end dup findfont $SubstituteFont begin $substituteFound {false} { dup/FontName known { dup/FontName get $fontname eq 1 index/DistillerFauxFont known not and /currentdistillerparams where {pop false 2 index isWidthsOnlyFont not and} if } {false} ifelse } ifelse exch pop /$doSmartSub true def end { 5 1 roll pop pop pop pop findfont } { 1 index findfont dup/FontType get 3 eq { 6 1 roll pop pop pop pop pop false } {pop true} ifelse { $SubstituteFont begin pop pop /$styleArray 1 index def /$regOrdering 2 index def pop pop 0 1 $styleArray length 1 sub { $styleArray exch get ct_StyleDicts $regOrdering 2 copy known { get exch 2 copy known not {pop/Default} if get dup type/nametype eq { ?str1 cvs length dup 1 add exch ?str1 exch(-)putinterval exch dup length exch ?str1 exch 3 index exch putinterval add ?str1 exch 0 exch getinterval cvn } { pop pop/Unknown } ifelse } { pop pop pop pop/Unknown } ifelse } for end findfont }if } ifelse currentglobal false setglobal 3 1 roll null copyfont definefont pop setglobal }bind def setpacking userdict/$SubstituteFont 25 dict put 1 dict begin /SubstituteFont dup $error exch 2 copy known {get} {pop pop{pop/Courier}bind} ifelse def /currentdistillerparams where dup { pop pop currentdistillerparams/CannotEmbedFontPolicy 2 copy known {get/Error eq} {pop pop false} ifelse } if not { countdictstack array dictstack 0 get begin userdict begin $SubstituteFont begin /$str 128 string def /$fontpat 128 string def /$slen 0 def /$sname null def /$match false def /$fontname null def /$substituteFound false def /$inVMIndex null def /$doSmartSub true def /$depth 0 def /$fontname null def /$italicangle 26.5 def /$dstack null def /$Strategies 10 dict dup begin /$Type3Underprint { currentglobal exch false setglobal 11 dict begin /UseFont exch $WMode 0 ne { dup length dict copy dup/WMode $WMode put /UseFont exch definefont } if def /FontName $fontname dup type/stringtype eq{cvn}if def /FontType 3 def /FontMatrix[.001 0 0 .001 0 0]def /Encoding 256 array dup 0 1 255{/.notdef put dup}for pop def /FontBBox[0 0 0 0]def /CCInfo 7 dict dup begin /cc null def /x 0 def /y 0 def end def /BuildChar { exch begin CCInfo begin 1 string dup 0 3 index put exch pop /cc exch def UseFont 1000 scalefont setfont cc stringwidth/y exch def/x exch def x y setcharwidth $SubstituteFont/$Strategy get/$Underprint get exec 0 0 moveto cc show x y moveto end end }bind def currentdict end exch setglobal }bind def /$GetaTint 2 dict dup begin /$BuildFont { dup/WMode known {dup/WMode get} {0} ifelse /$WMode exch def $fontname exch dup/FontName known { dup/FontName get dup type/stringtype eq{cvn}if } {/unnamedfont} ifelse exch Adobe_CoolType_Data/InVMDeepCopiedFonts get 1 index/FontName get known { pop Adobe_CoolType_Data/InVMDeepCopiedFonts get 1 index get null copyfont } {$deepcopyfont} ifelse exch 1 index exch/FontBasedOn exch put dup/FontName $fontname dup type/stringtype eq{cvn}if put definefont Adobe_CoolType_Data/InVMDeepCopiedFonts get begin dup/FontBasedOn get 1 index def end }bind def /$Underprint { gsave x abs y abs gt {/y 1000 def} {/x -1000 def 500 120 translate} ifelse Level2? { [/Separation(All)/DeviceCMYK{0 0 0 1 pop}] setcolorspace } {0 setgray} ifelse 10 setlinewidth x .8 mul [7 3] { y mul 8 div 120 sub x 10 div exch moveto 0 y 4 div neg rlineto dup 0 rlineto 0 y 4 div rlineto closepath gsave Level2? {.2 setcolor} {.8 setgray} ifelse fill grestore stroke } forall pop grestore }bind def end def /$Oblique 1 dict dup begin /$BuildFont { currentglobal exch dup gcheck setglobal null copyfont begin /FontBasedOn currentdict/FontName known { FontName dup type/stringtype eq{cvn}if } {/unnamedfont} ifelse def /FontName $fontname dup type/stringtype eq{cvn}if def /currentdistillerparams where {pop} { /FontInfo currentdict/FontInfo known {FontInfo null copyfont} {2 dict} ifelse dup begin /ItalicAngle $italicangle def /FontMatrix FontMatrix [1 0 ItalicAngle dup sin exch cos div 1 0 0] matrix concatmatrix readonly end 4 2 roll def def } ifelse FontName currentdict end definefont exch setglobal }bind def end def /$None 1 dict dup begin /$BuildFont{}bind def end def end def /$Oblique SetSubstituteStrategy /$findfontByEnum { dup type/stringtype eq{cvn}if dup/$fontname exch def $sname null eq {$str cvs dup length $slen sub $slen getinterval} {pop $sname} ifelse $fontpat dup 0(fonts/*)putinterval exch 7 exch putinterval /$match false def $SubstituteFont/$dstack countdictstack array dictstack put mark { $fontpat 0 $slen 7 add getinterval {/$match exch def exit} $str filenameforall } stopped { cleardictstack currentdict true $SubstituteFont/$dstack get { exch { 1 index eq {pop false} {true} ifelse } {begin false} ifelse } forall pop } if cleartomark /$slen 0 def $match false ne {$match(fonts/)anchorsearch pop pop cvn} {/Courier} ifelse }bind def /$ROS 1 dict dup begin /Adobe 4 dict dup begin /Japan1 [/Ryumin-Light/HeiseiMin-W3 /GothicBBB-Medium/HeiseiKakuGo-W5 /HeiseiMaruGo-W4/Jun101-Light]def /Korea1 [/HYSMyeongJo-Medium/HYGoThic-Medium]def /GB1 [/STSong-Light/STHeiti-Regular]def /CNS1 [/MKai-Medium/MHei-Medium]def end def end def /$cmapname null def /$deepcopyfont { dup/FontType get 0 eq { 1 dict dup/FontName/copied put copyfont begin /FDepVector FDepVector copyarray 0 1 2 index length 1 sub { 2 copy get $deepcopyfont dup/FontName/copied put /copied exch definefont 3 copy put pop pop } for def currentdict end } {$Strategies/$Type3Underprint get exec} ifelse }bind def /$buildfontname { dup/CIDFont findresource/CIDSystemInfo get begin Registry length Ordering length Supplement 8 string cvs 3 copy length 2 add add add string dup 5 1 roll dup 0 Registry putinterval dup 4 index(-)putinterval dup 4 index 1 add Ordering putinterval 4 2 roll add 1 add 2 copy(-)putinterval end 1 add 2 copy 0 exch getinterval $cmapname $fontpat cvs exch anchorsearch {pop pop 3 2 roll putinterval cvn/$cmapname exch def} {pop pop pop pop pop} ifelse length $str 1 index(-)putinterval 1 add $str 1 index $cmapname $fontpat cvs putinterval $cmapname length add $str exch 0 exch getinterval cvn }bind def /$findfontByROS { /$fontname exch def $ROS Registry 2 copy known { get Ordering 2 copy known {get} {pop pop[]} ifelse } {pop pop[]} ifelse false exch { dup/CIDFont resourcestatus { pop pop save 1 index/CIDFont findresource dup/WidthsOnly known {dup/WidthsOnly get} {false} ifelse exch pop exch restore {pop} {exch pop true exit} ifelse } {pop} ifelse } forall {$str cvs $buildfontname} { false(*) { save exch dup/CIDFont findresource dup/WidthsOnly known {dup/WidthsOnly get not} {true} ifelse exch/CIDSystemInfo get dup/Registry get Registry eq exch/Ordering get Ordering eq and and {exch restore exch pop true exit} {pop restore} ifelse } $str/CIDFont resourceforall {$buildfontname} {$fontname $findfontByEnum} ifelse } ifelse }bind def end end currentdict/$error known currentdict/languagelevel known and dup {pop $error/SubstituteFont known} if dup {$error} {Adobe_CoolType_Core} ifelse begin { /SubstituteFont /CMap/Category resourcestatus { pop pop { $SubstituteFont begin /$substituteFound true def dup length $slen gt $sname null ne or $slen 0 gt and { $sname null eq {dup $str cvs dup length $slen sub $slen getinterval cvn} {$sname} ifelse Adobe_CoolType_Data/InVMFontsByCMap get 1 index 2 copy known { get false exch { pop currentglobal { GlobalFontDirectory 1 index known {exch pop true exit} {pop} ifelse } { FontDirectory 1 index known {exch pop true exit} { GlobalFontDirectory 1 index known {exch pop true exit} {pop} ifelse } ifelse } ifelse } forall } {pop pop false} ifelse { exch pop exch pop } { dup/CMap resourcestatus { pop pop dup/$cmapname exch def /CMap findresource/CIDSystemInfo get{def}forall $findfontByROS } { 128 string cvs dup(-)search { 3 1 roll search { 3 1 roll pop {dup cvi} stopped {pop pop pop pop pop $findfontByEnum} { 4 2 roll pop pop exch length exch 2 index length 2 index sub exch 1 sub -1 0 { $str cvs dup length 4 index 0 4 index 4 3 roll add getinterval exch 1 index exch 3 index exch putinterval dup/CMap resourcestatus { pop pop 4 1 roll pop pop pop dup/$cmapname exch def /CMap findresource/CIDSystemInfo get{def}forall $findfontByROS true exit } {pop} ifelse } for dup type/booleantype eq {pop} {pop pop pop $findfontByEnum} ifelse } ifelse } {pop pop pop $findfontByEnum} ifelse } {pop pop $findfontByEnum} ifelse } ifelse } ifelse } {//SubstituteFont exec} ifelse /$slen 0 def end } } { { $SubstituteFont begin /$substituteFound true def dup length $slen gt $sname null ne or $slen 0 gt and {$findfontByEnum} {//SubstituteFont exec} ifelse end } } ifelse bind readonly def Adobe_CoolType_Core/scfindfont/systemfindfont load put } { /scfindfont { $SubstituteFont begin dup systemfindfont dup/FontName known {dup/FontName get dup 3 index ne} {/noname true} ifelse dup { /$origfontnamefound 2 index def /$origfontname 4 index def/$substituteFound true def } if exch pop { $slen 0 gt $sname null ne 3 index length $slen gt or and { pop dup $findfontByEnum findfont dup maxlength 1 add dict begin {1 index/FID eq{pop pop}{def}ifelse} forall currentdict end definefont dup/FontName known{dup/FontName get}{null}ifelse $origfontnamefound ne { $origfontname $str cvs print ( substitution revised, using )print dup/FontName known {dup/FontName get}{(unspecified font)} ifelse $str cvs print(.\n)print } if } {exch pop} ifelse } {exch pop} ifelse end }bind def } ifelse end end Adobe_CoolType_Core_Defined not { Adobe_CoolType_Core/findfont { $SubstituteFont begin $depth 0 eq { /$fontname 1 index dup type/stringtype ne{$str cvs}if def /$substituteFound false def } if /$depth $depth 1 add def end scfindfont $SubstituteFont begin /$depth $depth 1 sub def $substituteFound $depth 0 eq and { $inVMIndex null ne {dup $inVMIndex $AddInVMFont} if $doSmartSub { currentdict/$Strategy known {$Strategy/$BuildFont get exec} if } if } if end }bind put } if } if end /$AddInVMFont { exch/FontName 2 copy known { get 1 dict dup begin exch 1 index gcheck def end exch Adobe_CoolType_Data/InVMFontsByCMap get exch $DictAdd } {pop pop pop} ifelse }bind def /$DictAdd { 2 copy known not {2 copy 4 index length dict put} if Level2? not { 2 copy get dup maxlength exch length 4 index length add lt 2 copy get dup length 4 index length add exch maxlength 1 index lt { 2 mul dict begin 2 copy get{forall}def 2 copy currentdict put end } {pop} ifelse } if get begin {def} forall end }bind def end end %%EndResource currentglobal true setglobal %%BeginResource: procset Adobe_CoolType_Utility_MAKEOCF 1.23 0 %%Copyright: Copyright 1987-2006 Adobe Systems Incorporated. %%Version: 1.23 0 systemdict/languagelevel known dup {currentglobal false setglobal} {false} ifelse exch userdict/Adobe_CoolType_Utility 2 copy known {2 copy get dup maxlength 27 add dict copy} {27 dict} ifelse put Adobe_CoolType_Utility begin /@eexecStartData def /@recognizeCIDFont null def /ct_Level2? exch def /ct_Clone? 1183615869 internaldict dup /CCRun known not exch/eCCRun known not ct_Level2? and or def ct_Level2? {globaldict begin currentglobal true setglobal} if /ct_AddStdCIDMap ct_Level2? {{ mark Adobe_CoolType_Utility/@recognizeCIDFont currentdict put { ((Hex)57 StartData 0615 1e27 2c39 1c60 d8a8 cc31 fe2b f6e0 7aa3 e541 e21c 60d8 a8c9 c3d0 6d9e 1c60 d8a8 c9c2 02d7 9a1c 60d8 a849 1c60 d8a8 cc36 74f4 1144 b13b 77)0()/SubFileDecode filter cvx exec } stopped { cleartomark Adobe_CoolType_Utility/@recognizeCIDFont get countdictstack dup array dictstack exch 1 sub -1 0 { 2 copy get 3 index eq {1 index length exch sub 1 sub{end}repeat exit} {pop} ifelse } for pop pop Adobe_CoolType_Utility/@eexecStartData get eexec } {cleartomark} ifelse }} {{ Adobe_CoolType_Utility/@eexecStartData get eexec }} ifelse bind def userdict/cid_extensions known dup{cid_extensions/cid_UpdateDB known and}if { cid_extensions begin /cid_GetCIDSystemInfo { 1 index type/stringtype eq {exch cvn exch} if cid_extensions begin dup load 2 index known { 2 copy cid_GetStatusInfo dup null ne { 1 index load 3 index get dup null eq {pop pop cid_UpdateDB} { exch 1 index/Created get eq {exch pop exch pop} {pop cid_UpdateDB} ifelse } ifelse } {pop cid_UpdateDB} ifelse } {cid_UpdateDB} ifelse end }bind def end } if ct_Level2? {end setglobal} if /ct_UseNativeCapability? systemdict/composefont known def /ct_MakeOCF 35 dict def /ct_Vars 25 dict def /ct_GlyphDirProcs 6 dict def /ct_BuildCharDict 15 dict dup begin /charcode 2 string def /dst_string 1500 string def /nullstring()def /usewidths? true def end def ct_Level2?{setglobal}{pop}ifelse ct_GlyphDirProcs begin /GetGlyphDirectory { systemdict/languagelevel known {pop/CIDFont findresource/GlyphDirectory get} { 1 index/CIDFont findresource/GlyphDirectory get dup type/dicttype eq { dup dup maxlength exch length sub 2 index lt { dup length 2 index add dict copy 2 index /CIDFont findresource/GlyphDirectory 2 index put } if } if exch pop exch pop } ifelse + }def /+ { systemdict/languagelevel known { currentglobal false setglobal 3 dict begin /vm exch def } {1 dict begin} ifelse /$ exch def systemdict/languagelevel known { vm setglobal /gvm currentglobal def $ gcheck setglobal } if ?{$ begin}if }def /?{$ type/dicttype eq}def /|{ userdict/Adobe_CoolType_Data known { Adobe_CoolType_Data/AddWidths? known { currentdict Adobe_CoolType_Data begin begin AddWidths? { Adobe_CoolType_Data/CC 3 index put ?{def}{$ 3 1 roll put}ifelse CC charcode exch 1 index 0 2 index 256 idiv put 1 index exch 1 exch 256 mod put stringwidth 2 array astore currentfont/Widths get exch CC exch put } {?{def}{$ 3 1 roll put}ifelse} ifelse end end } {?{def}{$ 3 1 roll put}ifelse} ifelse } {?{def}{$ 3 1 roll put}ifelse} ifelse }def /! { ?{end}if systemdict/languagelevel known {gvm setglobal} if end }def /:{string currentfile exch readstring pop}executeonly def end ct_MakeOCF begin /ct_cHexEncoding [/c00/c01/c02/c03/c04/c05/c06/c07/c08/c09/c0A/c0B/c0C/c0D/c0E/c0F/c10/c11/c12 /c13/c14/c15/c16/c17/c18/c19/c1A/c1B/c1C/c1D/c1E/c1F/c20/c21/c22/c23/c24/c25 /c26/c27/c28/c29/c2A/c2B/c2C/c2D/c2E/c2F/c30/c31/c32/c33/c34/c35/c36/c37/c38 /c39/c3A/c3B/c3C/c3D/c3E/c3F/c40/c41/c42/c43/c44/c45/c46/c47/c48/c49/c4A/c4B /c4C/c4D/c4E/c4F/c50/c51/c52/c53/c54/c55/c56/c57/c58/c59/c5A/c5B/c5C/c5D/c5E /c5F/c60/c61/c62/c63/c64/c65/c66/c67/c68/c69/c6A/c6B/c6C/c6D/c6E/c6F/c70/c71 /c72/c73/c74/c75/c76/c77/c78/c79/c7A/c7B/c7C/c7D/c7E/c7F/c80/c81/c82/c83/c84 /c85/c86/c87/c88/c89/c8A/c8B/c8C/c8D/c8E/c8F/c90/c91/c92/c93/c94/c95/c96/c97 /c98/c99/c9A/c9B/c9C/c9D/c9E/c9F/cA0/cA1/cA2/cA3/cA4/cA5/cA6/cA7/cA8/cA9/cAA /cAB/cAC/cAD/cAE/cAF/cB0/cB1/cB2/cB3/cB4/cB5/cB6/cB7/cB8/cB9/cBA/cBB/cBC/cBD /cBE/cBF/cC0/cC1/cC2/cC3/cC4/cC5/cC6/cC7/cC8/cC9/cCA/cCB/cCC/cCD/cCE/cCF/cD0 /cD1/cD2/cD3/cD4/cD5/cD6/cD7/cD8/cD9/cDA/cDB/cDC/cDD/cDE/cDF/cE0/cE1/cE2/cE3 /cE4/cE5/cE6/cE7/cE8/cE9/cEA/cEB/cEC/cED/cEE/cEF/cF0/cF1/cF2/cF3/cF4/cF5/cF6 /cF7/cF8/cF9/cFA/cFB/cFC/cFD/cFE/cFF]def /ct_CID_STR_SIZE 8000 def /ct_mkocfStr100 100 string def /ct_defaultFontMtx[.001 0 0 .001 0 0]def /ct_1000Mtx[1000 0 0 1000 0 0]def /ct_raise{exch cvx exch errordict exch get exec stop}bind def /ct_reraise {cvx $error/errorname get(Error: )print dup( )cvs print errordict exch get exec stop }bind def /ct_cvnsi { 1 index add 1 sub 1 exch 0 4 1 roll { 2 index exch get exch 8 bitshift add } for exch pop }bind def /ct_GetInterval { Adobe_CoolType_Utility/ct_BuildCharDict get begin /dst_index 0 def dup dst_string length gt {dup string/dst_string exch def} if 1 index ct_CID_STR_SIZE idiv /arrayIndex exch def 2 index arrayIndex get 2 index arrayIndex ct_CID_STR_SIZE mul sub { dup 3 index add 2 index length le { 2 index getinterval dst_string dst_index 2 index putinterval length dst_index add/dst_index exch def exit } { 1 index length 1 index sub dup 4 1 roll getinterval dst_string dst_index 2 index putinterval pop dup dst_index add/dst_index exch def sub /arrayIndex arrayIndex 1 add def 2 index dup length arrayIndex gt {arrayIndex get} { pop exit } ifelse 0 } ifelse } loop pop pop pop dst_string 0 dst_index getinterval end }bind def ct_Level2? { /ct_resourcestatus currentglobal mark true setglobal {/unknowninstancename/Category resourcestatus} stopped {cleartomark setglobal true} {cleartomark currentglobal not exch setglobal} ifelse { { mark 3 1 roll/Category findresource begin ct_Vars/vm currentglobal put ({ResourceStatus}stopped)0()/SubFileDecode filter cvx exec {cleartomark false} {{3 2 roll pop true}{cleartomark false}ifelse} ifelse ct_Vars/vm get setglobal end } } {{resourcestatus}} ifelse bind def /CIDFont/Category ct_resourcestatus {pop pop} { currentglobal true setglobal /Generic/Category findresource dup length dict copy dup/InstanceType/dicttype put /CIDFont exch/Category defineresource pop setglobal } ifelse ct_UseNativeCapability? { /CIDInit/ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo 3 dict dup begin /Registry(Adobe)def /Ordering(Identity)def /Supplement 0 def end def /CMapName/Identity-H def /CMapVersion 1.000 def /CMapType 1 def 1 begincodespacerange <0000> endcodespacerange 1 begincidrange <0000>0 endcidrange endcmap CMapName currentdict/CMap defineresource pop end end } if } { /ct_Category 2 dict begin /CIDFont 10 dict def /ProcSet 2 dict def currentdict end def /defineresource { ct_Category 1 index 2 copy known { get dup dup maxlength exch length eq { dup length 10 add dict copy ct_Category 2 index 2 index put } if 3 index 3 index put pop exch pop } {pop pop/defineresource/undefined ct_raise} ifelse }bind def /findresource { ct_Category 1 index 2 copy known { get 2 index 2 copy known {get 3 1 roll pop pop} {pop pop/findresource/undefinedresource ct_raise} ifelse } {pop pop/findresource/undefined ct_raise} ifelse }bind def /resourcestatus { ct_Category 1 index 2 copy known { get 2 index known exch pop exch pop { 0 -1 true } { false } ifelse } {pop pop/findresource/undefined ct_raise} ifelse }bind def /ct_resourcestatus/resourcestatus load def } ifelse /ct_CIDInit 2 dict begin /ct_cidfont_stream_init { { dup(Binary)eq { pop null currentfile ct_Level2? { {cid_BYTE_COUNT()/SubFileDecode filter} stopped {pop pop pop} if } if /readstring load exit } if dup(Hex)eq { pop currentfile ct_Level2? { {null exch/ASCIIHexDecode filter/readstring} stopped {pop exch pop(>)exch/readhexstring} if } {(>)exch/readhexstring} ifelse load exit } if /StartData/typecheck ct_raise } loop cid_BYTE_COUNT ct_CID_STR_SIZE le { 2 copy cid_BYTE_COUNT string exch exec pop 1 array dup 3 -1 roll 0 exch put } { cid_BYTE_COUNT ct_CID_STR_SIZE div ceiling cvi dup array exch 2 sub 0 exch 1 exch { 2 copy 5 index ct_CID_STR_SIZE string 6 index exec pop put pop } for 2 index cid_BYTE_COUNT ct_CID_STR_SIZE mod string 3 index exec pop 1 index exch 1 index length 1 sub exch put } ifelse cid_CIDFONT exch/GlyphData exch put 2 index null eq { pop pop pop } { pop/readstring load 1 string exch { 3 copy exec pop dup length 0 eq { pop pop pop pop pop true exit } if 4 index eq { pop pop pop pop false exit } if } loop pop } ifelse }bind def /StartData { mark { currentdict dup/FDArray get 0 get/FontMatrix get 0 get 0.001 eq { dup/CDevProc known not { /CDevProc 1183615869 internaldict/stdCDevProc 2 copy known {get} { pop pop {pop pop pop pop pop 0 -1000 7 index 2 div 880} } ifelse def } if } { /CDevProc { pop pop pop pop pop 0 1 cid_temp/cid_CIDFONT get /FDArray get 0 get /FontMatrix get 0 get div 7 index 2 div 1 index 0.88 mul }def } ifelse /cid_temp 15 dict def cid_temp begin /cid_CIDFONT exch def 3 copy pop dup/cid_BYTE_COUNT exch def 0 gt { ct_cidfont_stream_init FDArray { /Private get dup/SubrMapOffset known { begin /Subrs SubrCount array def Subrs SubrMapOffset SubrCount SDBytes ct_Level2? { currentdict dup/SubrMapOffset undef dup/SubrCount undef /SDBytes undef } if end /cid_SD_BYTES exch def /cid_SUBR_COUNT exch def /cid_SUBR_MAP_OFFSET exch def /cid_SUBRS exch def cid_SUBR_COUNT 0 gt { GlyphData cid_SUBR_MAP_OFFSET cid_SD_BYTES ct_GetInterval 0 cid_SD_BYTES ct_cvnsi 0 1 cid_SUBR_COUNT 1 sub { exch 1 index 1 add cid_SD_BYTES mul cid_SUBR_MAP_OFFSET add GlyphData exch cid_SD_BYTES ct_GetInterval 0 cid_SD_BYTES ct_cvnsi cid_SUBRS 4 2 roll GlyphData exch 4 index 1 index sub ct_GetInterval dup length string copy put } for pop } if } {pop} ifelse } forall } if cleartomark pop pop end CIDFontName currentdict/CIDFont defineresource pop end end } stopped {cleartomark/StartData ct_reraise} if }bind def currentdict end def /ct_saveCIDInit { /CIDInit/ProcSet ct_resourcestatus {true} {/CIDInitC/ProcSet ct_resourcestatus} ifelse { pop pop /CIDInit/ProcSet findresource ct_UseNativeCapability? {pop null} {/CIDInit ct_CIDInit/ProcSet defineresource pop} ifelse } {/CIDInit ct_CIDInit/ProcSet defineresource pop null} ifelse ct_Vars exch/ct_oldCIDInit exch put }bind def /ct_restoreCIDInit { ct_Vars/ct_oldCIDInit get dup null ne {/CIDInit exch/ProcSet defineresource pop} {pop} ifelse }bind def /ct_BuildCharSetUp { 1 index begin CIDFont begin Adobe_CoolType_Utility/ct_BuildCharDict get begin /ct_dfCharCode exch def /ct_dfDict exch def CIDFirstByte ct_dfCharCode add dup CIDCount ge {pop 0} if /cid exch def { GlyphDirectory cid 2 copy known {get} {pop pop nullstring} ifelse dup length FDBytes sub 0 gt { dup FDBytes 0 ne {0 FDBytes ct_cvnsi} {pop 0} ifelse /fdIndex exch def dup length FDBytes sub FDBytes exch getinterval /charstring exch def exit } { pop cid 0 eq {/charstring nullstring def exit} if /cid 0 def } ifelse } loop }def /ct_SetCacheDevice { 0 0 moveto dup stringwidth 3 -1 roll true charpath pathbbox 0 -1000 7 index 2 div 880 setcachedevice2 0 0 moveto }def /ct_CloneSetCacheProc { 1 eq { stringwidth pop -2 div -880 0 -1000 setcharwidth moveto } { usewidths? { currentfont/Widths get cid 2 copy known {get exch pop aload pop} {pop pop stringwidth} ifelse } {stringwidth} ifelse setcharwidth 0 0 moveto } ifelse }def /ct_Type3ShowCharString { ct_FDDict fdIndex 2 copy known {get} { currentglobal 3 1 roll 1 index gcheck setglobal ct_Type1FontTemplate dup maxlength dict copy begin FDArray fdIndex get dup/FontMatrix 2 copy known {get} {pop pop ct_defaultFontMtx} ifelse /FontMatrix exch dup length array copy def /Private get /Private exch def /Widths rootfont/Widths get def /CharStrings 1 dict dup/.notdef dup length string copy put def currentdict end /ct_Type1Font exch definefont dup 5 1 roll put setglobal } ifelse dup/CharStrings get 1 index/Encoding get ct_dfCharCode get charstring put rootfont/WMode 2 copy known {get} {pop pop 0} ifelse exch 1000 scalefont setfont ct_str1 0 ct_dfCharCode put ct_str1 exch ct_dfSetCacheProc ct_SyntheticBold { currentpoint ct_str1 show newpath moveto ct_str1 true charpath ct_StrokeWidth setlinewidth stroke } {ct_str1 show} ifelse }def /ct_Type4ShowCharString { ct_dfDict ct_dfCharCode charstring FDArray fdIndex get dup/FontMatrix get dup ct_defaultFontMtx ct_matrixeq not {ct_1000Mtx matrix concatmatrix concat} {pop} ifelse /Private get Adobe_CoolType_Utility/ct_Level2? get not { ct_dfDict/Private 3 -1 roll {put} 1183615869 internaldict/superexec get exec } if 1183615869 internaldict Adobe_CoolType_Utility/ct_Level2? get {1 index} {3 index/Private get mark 6 1 roll} ifelse dup/RunInt known {/RunInt get} {pop/CCRun} ifelse get exec Adobe_CoolType_Utility/ct_Level2? get not {cleartomark} if }bind def /ct_BuildCharIncremental { { Adobe_CoolType_Utility/ct_MakeOCF get begin ct_BuildCharSetUp ct_ShowCharString } stopped {stop} if end end end end }bind def /BaseFontNameStr(BF00)def /ct_Type1FontTemplate 14 dict begin /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0]def /FontBBox [-250 -250 1250 1250]def /Encoding ct_cHexEncoding def /PaintType 0 def currentdict end def /BaseFontTemplate 11 dict begin /FontMatrix [0.001 0 0 0.001 0 0]def /FontBBox [-250 -250 1250 1250]def /Encoding ct_cHexEncoding def /BuildChar/ct_BuildCharIncremental load def ct_Clone? { /FontType 3 def /ct_ShowCharString/ct_Type3ShowCharString load def /ct_dfSetCacheProc/ct_CloneSetCacheProc load def /ct_SyntheticBold false def /ct_StrokeWidth 1 def } { /FontType 4 def /Private 1 dict dup/lenIV 4 put def /CharStrings 1 dict dup/.notdefput def /PaintType 0 def /ct_ShowCharString/ct_Type4ShowCharString load def } ifelse /ct_str1 1 string def currentdict end def /BaseFontDictSize BaseFontTemplate length 5 add def /ct_matrixeq { true 0 1 5 { dup 4 index exch get exch 3 index exch get eq and dup not {exit} if } for exch pop exch pop }bind def /ct_makeocf { 15 dict begin exch/WMode exch def exch/FontName exch def /FontType 0 def /FMapType 2 def dup/FontMatrix known {dup/FontMatrix get/FontMatrix exch def} {/FontMatrix matrix def} ifelse /bfCount 1 index/CIDCount get 256 idiv 1 add dup 256 gt{pop 256}if def /Encoding 256 array 0 1 bfCount 1 sub{2 copy dup put pop}for bfCount 1 255{2 copy bfCount put pop}for def /FDepVector bfCount dup 256 lt{1 add}if array def BaseFontTemplate BaseFontDictSize dict copy begin /CIDFont exch def CIDFont/FontBBox known {CIDFont/FontBBox get/FontBBox exch def} if CIDFont/CDevProc known {CIDFont/CDevProc get/CDevProc exch def} if currentdict end BaseFontNameStr 3(0)putinterval 0 1 bfCount dup 256 eq{1 sub}if { FDepVector exch 2 index BaseFontDictSize dict copy begin dup/CIDFirstByte exch 256 mul def FontType 3 eq {/ct_FDDict 2 dict def} if currentdict end 1 index 16 BaseFontNameStr 2 2 getinterval cvrs pop BaseFontNameStr exch definefont put } for ct_Clone? {/Widths 1 index/CIDFont get/GlyphDirectory get length dict def} if FontName currentdict end definefont ct_Clone? { gsave dup 1000 scalefont setfont ct_BuildCharDict begin /usewidths? false def currentfont/Widths get begin exch/CIDFont get/GlyphDirectory get { pop dup charcode exch 1 index 0 2 index 256 idiv put 1 index exch 1 exch 256 mod put stringwidth 2 array astore def } forall end /usewidths? true def end grestore } {exch pop} ifelse }bind def currentglobal true setglobal /ct_ComposeFont { ct_UseNativeCapability? { 2 index/CMap ct_resourcestatus {pop pop exch pop} { /CIDInit/ProcSet findresource begin 12 dict begin begincmap /CMapName 3 index def /CMapVersion 1.000 def /CMapType 1 def exch/WMode exch def /CIDSystemInfo 3 dict dup begin /Registry(Adobe)def /Ordering CMapName ct_mkocfStr100 cvs (Adobe-)search { pop pop (-)search { dup length string copy exch pop exch pop } {pop(Identity)} ifelse } {pop (Identity)} ifelse def /Supplement 0 def end def 1 begincodespacerange <0000> endcodespacerange 1 begincidrange <0000>0 endcidrange endcmap CMapName currentdict/CMap defineresource pop end end } ifelse composefont } { 3 2 roll pop 0 get/CIDFont findresource ct_makeocf } ifelse }bind def setglobal /ct_MakeIdentity { ct_UseNativeCapability? { 1 index/CMap ct_resourcestatus {pop pop} { /CIDInit/ProcSet findresource begin 12 dict begin begincmap /CMapName 2 index def /CMapVersion 1.000 def /CMapType 1 def /CIDSystemInfo 3 dict dup begin /Registry(Adobe)def /Ordering CMapName ct_mkocfStr100 cvs (Adobe-)search { pop pop (-)search {dup length string copy exch pop exch pop} {pop(Identity)} ifelse } {pop(Identity)} ifelse def /Supplement 0 def end def 1 begincodespacerange <0000> endcodespacerange 1 begincidrange <0000>0 endcidrange endcmap CMapName currentdict/CMap defineresource pop end end } ifelse composefont } { exch pop 0 get/CIDFont findresource ct_makeocf } ifelse }bind def currentdict readonly pop end end %%EndResource setglobal %%BeginResource: procset Adobe_CoolType_Utility_T42 1.0 0 %%Copyright: Copyright 1987-2004 Adobe Systems Incorporated. %%Version: 1.0 0 userdict/ct_T42Dict 15 dict put ct_T42Dict begin /Is2015? { version cvi 2015 ge }bind def /AllocGlyphStorage { Is2015? { pop } { {string}forall }ifelse }bind def /Type42DictBegin { 25 dict begin /FontName exch def /CharStrings 256 dict begin /.notdef 0 def currentdict end def /Encoding exch def /PaintType 0 def /FontType 42 def /FontMatrix[1 0 0 1 0 0]def 4 array astore cvx/FontBBox exch def /sfnts }bind def /Type42DictEnd { currentdict dup/FontName get exch definefont end ct_T42Dict exch dup/FontName get exch put }bind def /RD{string currentfile exch readstring pop}executeonly def /PrepFor2015 { Is2015? { /GlyphDirectory 16 dict def sfnts 0 get dup 2 index (glyx) putinterval 2 index (locx) putinterval pop pop } { pop pop }ifelse }bind def /AddT42Char { Is2015? { /GlyphDirectory get begin def end pop pop } { /sfnts get 4 index get 3 index 2 index putinterval pop pop pop pop }ifelse }bind def /T0AddT42Mtx2 { /CIDFont findresource/Metrics2 get begin def end }bind def end %%EndResource currentglobal true setglobal %%BeginFile: MMFauxFont.prc %%Copyright: Copyright 1987-2001 Adobe Systems Incorporated. %%All Rights Reserved. userdict /ct_EuroDict 10 dict put ct_EuroDict begin /ct_CopyFont { { 1 index /FID ne {def} {pop pop} ifelse} forall } def /ct_GetGlyphOutline { gsave initmatrix newpath exch findfont dup length 1 add dict begin ct_CopyFont /Encoding Encoding dup length array copy dup 4 -1 roll 0 exch put def currentdict end /ct_EuroFont exch definefont 1000 scalefont setfont 0 0 moveto [ <00> stringwidth <00> false charpath pathbbox [ {/m cvx} {/l cvx} {/c cvx} {/cp cvx} pathforall grestore counttomark 8 add } def /ct_MakeGlyphProc { ] cvx /ct_PSBuildGlyph cvx ] cvx } def /ct_PSBuildGlyph { gsave 8 -1 roll pop 7 1 roll 6 -2 roll ct_FontMatrix transform 6 2 roll 4 -2 roll ct_FontMatrix transform 4 2 roll ct_FontMatrix transform currentdict /PaintType 2 copy known {get 2 eq}{pop pop false} ifelse dup 9 1 roll { currentdict /StrokeWidth 2 copy known { get 2 div 0 ct_FontMatrix dtransform pop 5 1 roll 4 -1 roll 4 index sub 4 1 roll 3 -1 roll 4 index sub 3 1 roll exch 4 index add exch 4 index add 5 -1 roll pop } { pop pop } ifelse } if setcachedevice ct_FontMatrix concat ct_PSPathOps begin exec end { currentdict /StrokeWidth 2 copy known { get } { pop pop 0 } ifelse setlinewidth stroke } { fill } ifelse grestore } def /ct_PSPathOps 4 dict dup begin /m {moveto} def /l {lineto} def /c {curveto} def /cp {closepath} def end def /ct_matrix1000 [1000 0 0 1000 0 0] def /ct_AddGlyphProc { 2 index findfont dup length 4 add dict begin ct_CopyFont /CharStrings CharStrings dup length 1 add dict copy begin 3 1 roll def currentdict end def /ct_FontMatrix ct_matrix1000 FontMatrix matrix concatmatrix def /ct_PSBuildGlyph /ct_PSBuildGlyph load def /ct_PSPathOps /ct_PSPathOps load def currentdict end definefont pop } def systemdict /languagelevel known { /ct_AddGlyphToPrinterFont { 2 copy ct_GetGlyphOutline 3 add -1 roll restore ct_MakeGlyphProc ct_AddGlyphProc } def } { /ct_AddGlyphToPrinterFont { pop pop restore Adobe_CTFauxDict /$$$FONTNAME get /Euro Adobe_CTFauxDict /$$$SUBSTITUTEBASE get ct_EuroDict exch get ct_AddGlyphProc } def } ifelse /AdobeSansMM { 556 0 24 -19 541 703 { 541 628 m 510 669 442 703 354 703 c 201 703 117 607 101 444 c 50 444 l 25 372 l 97 372 l 97 301 l 49 301 l 24 229 l 103 229 l 124 67 209 -19 350 -19 c 435 -19 501 25 509 32 c 509 131 l 492 105 417 60 343 60 c 267 60 204 127 197 229 c 406 229 l 430 301 l 191 301 l 191 372 l 455 372 l 479 444 l 194 444 l 201 531 245 624 348 624 c 433 624 484 583 509 534 c cp 556 0 m } ct_PSBuildGlyph } def /AdobeSerifMM { 500 0 10 -12 484 692 { 347 298 m 171 298 l 170 310 170 322 170 335 c 170 362 l 362 362 l 374 403 l 172 403 l 184 580 244 642 308 642 c 380 642 434 574 457 457 c 481 462 l 474 691 l 449 691 l 433 670 429 657 410 657 c 394 657 360 692 299 692 c 204 692 94 604 73 403 c 22 403 l 10 362 l 70 362 l 69 352 69 341 69 330 c 69 319 69 308 70 298 c 22 298 l 10 257 l 73 257 l 97 57 216 -12 295 -12 c 364 -12 427 25 484 123 c 458 142 l 425 101 384 37 316 37 c 256 37 189 84 173 257 c 335 257 l cp 500 0 m } ct_PSBuildGlyph } def end %%EndFile setglobal Adobe_CoolType_Core begin /$Oblique SetSubstituteStrategy end %%BeginResource: procset Adobe_AGM_Image 1.0 0 +%%Version: 1.0 0 +%%Copyright: Copyright(C)2000-2006 Adobe Systems, Inc. All Rights Reserved. +systemdict/setpacking known +{ + currentpacking + true setpacking +}if +userdict/Adobe_AGM_Image 71 dict dup begin put +/Adobe_AGM_Image_Id/Adobe_AGM_Image_1.0_0 def +/nd{ + null def +}bind def +/AGMIMG_&image nd +/AGMIMG_&colorimage nd +/AGMIMG_&imagemask nd +/AGMIMG_mbuf()def +/AGMIMG_ybuf()def +/AGMIMG_kbuf()def +/AGMIMG_c 0 def +/AGMIMG_m 0 def +/AGMIMG_y 0 def +/AGMIMG_k 0 def +/AGMIMG_tmp nd +/AGMIMG_imagestring0 nd +/AGMIMG_imagestring1 nd +/AGMIMG_imagestring2 nd +/AGMIMG_imagestring3 nd +/AGMIMG_imagestring4 nd +/AGMIMG_imagestring5 nd +/AGMIMG_cnt nd +/AGMIMG_fsave nd +/AGMIMG_colorAry nd +/AGMIMG_override nd +/AGMIMG_name nd +/AGMIMG_maskSource nd +/AGMIMG_flushfilters nd +/invert_image_samples nd +/knockout_image_samples nd +/img nd +/sepimg nd +/devnimg nd +/idximg nd +/ds +{ + Adobe_AGM_Core begin + Adobe_AGM_Image begin + /AGMIMG_&image systemdict/image get def + /AGMIMG_&imagemask systemdict/imagemask get def + /colorimage where{ + pop + /AGMIMG_&colorimage/colorimage ldf + }if + end + end +}def +/ps +{ + Adobe_AGM_Image begin + /AGMIMG_ccimage_exists{/customcolorimage where + { + pop + /Adobe_AGM_OnHost_Seps where + { + pop false + }{ + /Adobe_AGM_InRip_Seps where + { + pop false + }{ + true + }ifelse + }ifelse + }{ + false + }ifelse + }bdf + level2{ + /invert_image_samples + { + Adobe_AGM_Image/AGMIMG_tmp Decode length ddf + /Decode[Decode 1 get Decode 0 get]def + }def + /knockout_image_samples + { + Operator/imagemask ne{ + /Decode[1 1]def + }if + }def + }{ + /invert_image_samples + { + {1 exch sub}currenttransfer addprocs settransfer + }def + /knockout_image_samples + { + {pop 1}currenttransfer addprocs settransfer + }def + }ifelse + /img/imageormask ldf + /sepimg/sep_imageormask ldf + /devnimg/devn_imageormask ldf + /idximg/indexed_imageormask ldf + /_ctype 7 def + currentdict{ + dup xcheck 1 index type dup/arraytype eq exch/packedarraytype eq or and{ + bind + }if + def + }forall +}def +/pt +{ + end +}def +/dt +{ +}def +/AGMIMG_flushfilters +{ + dup type/arraytype ne + {1 array astore}if + dup 0 get currentfile ne + {dup 0 get flushfile}if + { + dup type/filetype eq + { + dup status 1 index currentfile ne and + {closefile} + {pop} + ifelse + }{pop}ifelse + }forall +}def +/AGMIMG_init_common +{ + currentdict/T known{/ImageType/T ldf currentdict/T undef}if + currentdict/W known{/Width/W ldf currentdict/W undef}if + currentdict/H known{/Height/H ldf currentdict/H undef}if + currentdict/M known{/ImageMatrix/M ldf currentdict/M undef}if + currentdict/BC known{/BitsPerComponent/BC ldf currentdict/BC undef}if + currentdict/D known{/Decode/D ldf currentdict/D undef}if + currentdict/DS known{/DataSource/DS ldf currentdict/DS undef}if + currentdict/O known{ + /Operator/O load 1 eq{ + /imagemask + }{ + /O load 2 eq{ + /image + }{ + /colorimage + }ifelse + }ifelse + def + currentdict/O undef + }if + currentdict/HSCI known{/HostSepColorImage/HSCI ldf currentdict/HSCI undef}if + currentdict/MD known{/MultipleDataSources/MD ldf currentdict/MD undef}if + currentdict/I known{/Interpolate/I ldf currentdict/I undef}if + currentdict/SI known{/SkipImageProc/SI ldf currentdict/SI undef}if + /DataSource load xcheck not{ + DataSource type/arraytype eq{ + DataSource 0 get type/filetype eq{ + /_Filters DataSource def + currentdict/MultipleDataSources known not{ + /DataSource DataSource dup length 1 sub get def + }if + }if + }if + currentdict/MultipleDataSources known not{ + /MultipleDataSources DataSource type/arraytype eq{ + DataSource length 1 gt + } + {false}ifelse def + }if + }if + /NComponents Decode length 2 div def + currentdict/SkipImageProc known not{/SkipImageProc{false}def}if +}bdf +/imageormask_sys +{ + begin + AGMIMG_init_common + save mark + level2{ + currentdict + Operator/imagemask eq{ + AGMIMG_&imagemask + }{ + use_mask{ + process_mask AGMIMG_&image + }{ + AGMIMG_&image + }ifelse + }ifelse + }{ + Width Height + Operator/imagemask eq{ + Decode 0 get 1 eq Decode 1 get 0 eq and + ImageMatrix/DataSource load + AGMIMG_&imagemask + }{ + BitsPerComponent ImageMatrix/DataSource load + AGMIMG_&image + }ifelse + }ifelse + currentdict/_Filters known{_Filters AGMIMG_flushfilters}if + cleartomark restore + end +}def +/overprint_plate +{ + currentoverprint{ + 0 get dup type/nametype eq{ + dup/DeviceGray eq{ + pop AGMCORE_black_plate not + }{ + /DeviceCMYK eq{ + AGMCORE_is_cmyk_sep not + }if + }ifelse + }{ + false exch + { + AGMOHS_sepink eq or + }forall + not + }ifelse + }{ + pop false + }ifelse +}def +/process_mask +{ + level3{ + dup begin + /ImageType 1 def + end + 4 dict begin + /DataDict exch def + /ImageType 3 def + /InterleaveType 3 def + /MaskDict 9 dict begin + /ImageType 1 def + /Width DataDict dup/MaskWidth known{/MaskWidth}{/Width}ifelse get def + /Height DataDict dup/MaskHeight known{/MaskHeight}{/Height}ifelse get def + /ImageMatrix[Width 0 0 Height neg 0 Height]def + /NComponents 1 def + /BitsPerComponent 1 def + /Decode DataDict dup/MaskD known{/MaskD}{[1 0]}ifelse get def + /DataSource Adobe_AGM_Core/AGMIMG_maskSource get def + currentdict end def + currentdict end + }if +}def +/use_mask +{ + dup/Mask known {dup/Mask get}{false}ifelse +}def +/imageormask +{ + begin + AGMIMG_init_common + SkipImageProc{ + currentdict consumeimagedata + } + { + save mark + level2 AGMCORE_host_sep not and{ + currentdict + Operator/imagemask eq DeviceN_PS2 not and{ + imagemask + }{ + AGMCORE_in_rip_sep currentoverprint and currentcolorspace 0 get/DeviceGray eq and{ + [/Separation/Black/DeviceGray{}]setcolorspace + /Decode[Decode 1 get Decode 0 get]def + }if + use_mask{ + process_mask image + }{ + DeviceN_NoneName DeviceN_PS2 Indexed_DeviceN level3 not and or or AGMCORE_in_rip_sep and + { + Names convert_to_process not{ + 2 dict begin + /imageDict xdf + /names_index 0 def + gsave + imageDict write_image_file{ + Names{ + dup(None)ne{ + [/Separation 3 -1 roll/DeviceGray{1 exch sub}]setcolorspace + Operator imageDict read_image_file + names_index 0 eq{true setoverprint}if + /names_index names_index 1 add def + }{ + pop + }ifelse + }forall + close_image_file + }if + grestore + end + }{ + Operator/imagemask eq{ + imagemask + }{ + image + }ifelse + }ifelse + }{ + Operator/imagemask eq{ + imagemask + }{ + image + }ifelse + }ifelse + }ifelse + }ifelse + }{ + Width Height + Operator/imagemask eq{ + Decode 0 get 1 eq Decode 1 get 0 eq and + ImageMatrix/DataSource load + /Adobe_AGM_OnHost_Seps where{ + pop imagemask + }{ + currentgray 1 ne{ + currentdict imageormask_sys + }{ + currentoverprint not{ + 1 AGMCORE_&setgray + currentdict imageormask_sys + }{ + currentdict ignoreimagedata + }ifelse + }ifelse + }ifelse + }{ + BitsPerComponent ImageMatrix + MultipleDataSources{ + 0 1 NComponents 1 sub{ + DataSource exch get + }for + }{ + /DataSource load + }ifelse + Operator/colorimage eq{ + AGMCORE_host_sep{ + MultipleDataSources level2 or NComponents 4 eq and{ + AGMCORE_is_cmyk_sep{ + MultipleDataSources{ + /DataSource DataSource 0 get xcheck + { + [ + DataSource 0 get/exec cvx + DataSource 1 get/exec cvx + DataSource 2 get/exec cvx + DataSource 3 get/exec cvx + /AGMCORE_get_ink_data cvx + ]cvx + }{ + DataSource aload pop AGMCORE_get_ink_data + }ifelse def + }{ + /DataSource + Width BitsPerComponent mul 7 add 8 idiv Height mul 4 mul + /DataSource load + filter_cmyk 0()/SubFileDecode filter def + }ifelse + /Decode[Decode 0 get Decode 1 get]def + /MultipleDataSources false def + /NComponents 1 def + /Operator/image def + invert_image_samples + 1 AGMCORE_&setgray + currentdict imageormask_sys + }{ + currentoverprint not Operator/imagemask eq and{ + 1 AGMCORE_&setgray + currentdict imageormask_sys + }{ + currentdict ignoreimagedata + }ifelse + }ifelse + }{ + MultipleDataSources NComponents AGMIMG_&colorimage + }ifelse + }{ + true NComponents colorimage + }ifelse + }{ + Operator/image eq{ + AGMCORE_host_sep{ + /DoImage true def + currentdict/HostSepColorImage known{HostSepColorImage not}{false}ifelse + { + AGMCORE_black_plate not Operator/imagemask ne and{ + /DoImage false def + currentdict ignoreimagedata + }if + }if + 1 AGMCORE_&setgray + DoImage + {currentdict imageormask_sys}if + }{ + use_mask{ + process_mask image + }{ + image + }ifelse + }ifelse + }{ + Operator/knockout eq{ + pop pop pop pop pop + currentcolorspace overprint_plate not{ + knockout_unitsq + }if + }if + }ifelse + }ifelse + }ifelse + }ifelse + cleartomark restore + }ifelse + currentdict/_Filters known{_Filters AGMIMG_flushfilters}if + end +}def +/sep_imageormask +{ + /sep_colorspace_dict AGMCORE_gget begin + CSA map_csa + begin + AGMIMG_init_common + SkipImageProc{ + currentdict consumeimagedata + }{ + save mark + AGMCORE_avoid_L2_sep_space{ + /Decode[Decode 0 get 255 mul Decode 1 get 255 mul]def + }if + AGMIMG_ccimage_exists + MappedCSA 0 get/DeviceCMYK eq and + currentdict/Components known and + Name()ne and + Name(All)ne and + Operator/image eq and + AGMCORE_producing_seps not and + level2 not and + { + Width Height BitsPerComponent ImageMatrix + [ + /DataSource load/exec cvx + { + 0 1 2 index length 1 sub{ + 1 index exch + 2 copy get 255 xor put + }for + }/exec cvx + ]cvx bind + MappedCSA 0 get/DeviceCMYK eq{ + Components aload pop + }{ + 0 0 0 Components aload pop 1 exch sub + }ifelse + Name findcmykcustomcolor + customcolorimage + }{ + AGMCORE_producing_seps not{ + level2{ + //Adobe_AGM_Core/AGMCORE_pattern_paint_type get 2 ne AGMCORE_avoid_L2_sep_space not and currentcolorspace 0 get/Separation ne and{ + [/Separation Name MappedCSA sep_proc_name exch dup 0 get 15 string cvs(/Device)anchorsearch{pop pop 0 get}{pop}ifelse exch load]setcolorspace_opt + /sep_tint AGMCORE_gget setcolor + }if + currentdict imageormask + }{ + currentdict + Operator/imagemask eq{ + imageormask + }{ + sep_imageormask_lev1 + }ifelse + }ifelse + }{ + AGMCORE_host_sep{ + Operator/knockout eq{ + currentdict/ImageMatrix get concat + knockout_unitsq + }{ + currentgray 1 ne{ + AGMCORE_is_cmyk_sep Name(All)ne and{ + level2{ + Name AGMCORE_IsSeparationAProcessColor + { + Operator/imagemask eq{ + //Adobe_AGM_Core/AGMCORE_pattern_paint_type get 2 ne{ + /sep_tint AGMCORE_gget 1 exch sub AGMCORE_&setcolor + }if + }{ + invert_image_samples + }ifelse + }{ + //Adobe_AGM_Core/AGMCORE_pattern_paint_type get 2 ne{ + [/Separation Name[/DeviceGray] + { + sep_colorspace_proc AGMCORE_get_ink_data + 1 exch sub + }bind + ]AGMCORE_&setcolorspace + /sep_tint AGMCORE_gget AGMCORE_&setcolor + }if + }ifelse + currentdict imageormask_sys + }{ + currentdict + Operator/imagemask eq{ + imageormask_sys + }{ + sep_image_lev1_sep + }ifelse + }ifelse + }{ + Operator/imagemask ne{ + invert_image_samples + }if + currentdict imageormask_sys + }ifelse + }{ + currentoverprint not Name(All)eq or Operator/imagemask eq and{ + currentdict imageormask_sys + }{ + currentoverprint not + { + gsave + knockout_unitsq + grestore + }if + currentdict consumeimagedata + }ifelse + }ifelse + }ifelse + }{ + //Adobe_AGM_Core/AGMCORE_pattern_paint_type get 2 ne{ + currentcolorspace 0 get/Separation ne{ + [/Separation Name MappedCSA sep_proc_name exch 0 get exch load]setcolorspace_opt + /sep_tint AGMCORE_gget setcolor + }if + }if + currentoverprint + MappedCSA 0 get/DeviceCMYK eq and + Name AGMCORE_IsSeparationAProcessColor not and + //Adobe_AGM_Core/AGMCORE_pattern_paint_type get 2 ne{Name inRip_spot_has_ink not and}{false}ifelse + Name(All)ne and{ + imageormask_l2_overprint + }{ + currentdict imageormask + }ifelse + }ifelse + }ifelse + }ifelse + cleartomark restore + }ifelse + currentdict/_Filters known{_Filters AGMIMG_flushfilters}if + end + end +}def +/colorSpaceElemCnt +{ + mark currentcolor counttomark dup 2 add 1 roll cleartomark +}bdf +/devn_sep_datasource +{ + 1 dict begin + /dataSource xdf + [ + 0 1 dataSource length 1 sub{ + dup currentdict/dataSource get/exch cvx/get cvx/exec cvx + /exch cvx names_index/ne cvx[/pop cvx]cvx/if cvx + }for + ]cvx bind + end +}bdf +/devn_alt_datasource +{ + 11 dict begin + /convProc xdf + /origcolorSpaceElemCnt xdf + /origMultipleDataSources xdf + /origBitsPerComponent xdf + /origDecode xdf + /origDataSource xdf + /dsCnt origMultipleDataSources{origDataSource length}{1}ifelse def + /DataSource origMultipleDataSources + { + [ + BitsPerComponent 8 idiv origDecode length 2 idiv mul string + 0 1 origDecode length 2 idiv 1 sub + { + dup 7 mul 1 add index exch dup BitsPerComponent 8 idiv mul exch + origDataSource exch get 0()/SubFileDecode filter + BitsPerComponent 8 idiv string/readstring cvx/pop cvx/putinterval cvx + }for + ]bind cvx + }{origDataSource}ifelse 0()/SubFileDecode filter def + [ + origcolorSpaceElemCnt string + 0 2 origDecode length 2 sub + { + dup origDecode exch get dup 3 -1 roll 1 add origDecode exch get exch sub 2 BitsPerComponent exp 1 sub div + 1 BitsPerComponent 8 idiv{DataSource/read cvx/not cvx{0}/if cvx/mul cvx}repeat/mul cvx/add cvx + }for + /convProc load/exec cvx + origcolorSpaceElemCnt 1 sub -1 0 + { + /dup cvx 2/add cvx/index cvx + 3 1/roll cvx/exch cvx 255/mul cvx/cvi cvx/put cvx + }for + ]bind cvx 0()/SubFileDecode filter + end +}bdf +/devn_imageormask +{ + /devicen_colorspace_dict AGMCORE_gget begin + CSA map_csa + 2 dict begin + dup + /srcDataStrs[3 -1 roll begin + AGMIMG_init_common + currentdict/MultipleDataSources known{MultipleDataSources{DataSource length}{1}ifelse}{1}ifelse + { + Width Decode length 2 div mul cvi + { + dup 65535 gt{1 add 2 div cvi}{exit}ifelse + }loop + string + }repeat + end]def + /dstDataStr srcDataStrs 0 get length string def + begin + AGMIMG_init_common + SkipImageProc{ + currentdict consumeimagedata + }{ + save mark + AGMCORE_producing_seps not{ + level3 not{ + Operator/imagemask ne{ + /DataSource[[ + DataSource Decode BitsPerComponent currentdict/MultipleDataSources known{MultipleDataSources}{false}ifelse + colorSpaceElemCnt/devicen_colorspace_dict AGMCORE_gget/TintTransform get + devn_alt_datasource 1/string cvx/readstring cvx/pop cvx]cvx colorSpaceElemCnt 1 sub{dup}repeat]def + /MultipleDataSources true def + /Decode colorSpaceElemCnt[exch{0 1}repeat]def + }if + }if + currentdict imageormask + }{ + AGMCORE_host_sep{ + Names convert_to_process{ + CSA get_csa_by_name 0 get/DeviceCMYK eq{ + /DataSource + Width BitsPerComponent mul 7 add 8 idiv Height mul 4 mul + DataSource Decode BitsPerComponent currentdict/MultipleDataSources known{MultipleDataSources}{false}ifelse + 4/devicen_colorspace_dict AGMCORE_gget/TintTransform get + devn_alt_datasource + filter_cmyk 0()/SubFileDecode filter def + /MultipleDataSources false def + /Decode[1 0]def + /DeviceGray setcolorspace + currentdict imageormask_sys + }{ + AGMCORE_report_unsupported_color_space + AGMCORE_black_plate{ + /DataSource + DataSource Decode BitsPerComponent currentdict/MultipleDataSources known{MultipleDataSources}{false}ifelse + CSA get_csa_by_name 0 get/DeviceRGB eq{3}{1}ifelse/devicen_colorspace_dict AGMCORE_gget/TintTransform get + devn_alt_datasource + /MultipleDataSources false def + /Decode colorSpaceElemCnt[exch{0 1}repeat]def + currentdict imageormask_sys + }{ + gsave + knockout_unitsq + grestore + currentdict consumeimagedata + }ifelse + }ifelse + } + { + /devicen_colorspace_dict AGMCORE_gget/names_index known{ + Operator/imagemask ne{ + MultipleDataSources{ + /DataSource[DataSource devn_sep_datasource/exec cvx]cvx def + /MultipleDataSources false def + }{ + /DataSource/DataSource load dstDataStr srcDataStrs 0 get filter_devn def + }ifelse + invert_image_samples + }if + currentdict imageormask_sys + }{ + currentoverprint not Operator/imagemask eq and{ + currentdict imageormask_sys + }{ + currentoverprint not + { + gsave + knockout_unitsq + grestore + }if + currentdict consumeimagedata + }ifelse + }ifelse + }ifelse + }{ + currentdict imageormask + }ifelse + }ifelse + cleartomark restore + }ifelse + currentdict/_Filters known{_Filters AGMIMG_flushfilters}if + end + end + end +}def +/imageormask_l2_overprint +{ + currentdict + currentcmykcolor add add add 0 eq{ + currentdict consumeimagedata + }{ + level3{ + currentcmykcolor + /AGMIMG_k xdf + /AGMIMG_y xdf + /AGMIMG_m xdf + /AGMIMG_c xdf + Operator/imagemask eq{ + [/DeviceN[ + AGMIMG_c 0 ne{/Cyan}if + AGMIMG_m 0 ne{/Magenta}if + AGMIMG_y 0 ne{/Yellow}if + AGMIMG_k 0 ne{/Black}if + ]/DeviceCMYK{}]setcolorspace + AGMIMG_c 0 ne{AGMIMG_c}if + AGMIMG_m 0 ne{AGMIMG_m}if + AGMIMG_y 0 ne{AGMIMG_y}if + AGMIMG_k 0 ne{AGMIMG_k}if + setcolor + }{ + /Decode[Decode 0 get 255 mul Decode 1 get 255 mul]def + [/Indexed + [ + /DeviceN[ + AGMIMG_c 0 ne{/Cyan}if + AGMIMG_m 0 ne{/Magenta}if + AGMIMG_y 0 ne{/Yellow}if + AGMIMG_k 0 ne{/Black}if + ] + /DeviceCMYK{ + AGMIMG_k 0 eq{0}if + AGMIMG_y 0 eq{0 exch}if + AGMIMG_m 0 eq{0 3 1 roll}if + AGMIMG_c 0 eq{0 4 1 roll}if + } + ] + 255 + { + 255 div + mark exch + dup dup dup + AGMIMG_k 0 ne{ + /sep_tint AGMCORE_gget mul MappedCSA sep_proc_name exch pop load exec 4 1 roll pop pop pop + counttomark 1 roll + }{ + pop + }ifelse + AGMIMG_y 0 ne{ + /sep_tint AGMCORE_gget mul MappedCSA sep_proc_name exch pop load exec 4 2 roll pop pop pop + counttomark 1 roll + }{ + pop + }ifelse + AGMIMG_m 0 ne{ + /sep_tint AGMCORE_gget mul MappedCSA sep_proc_name exch pop load exec 4 3 roll pop pop pop + counttomark 1 roll + }{ + pop + }ifelse + AGMIMG_c 0 ne{ + /sep_tint AGMCORE_gget mul MappedCSA sep_proc_name exch pop load exec pop pop pop + counttomark 1 roll + }{ + pop + }ifelse + counttomark 1 add -1 roll pop + } + ]setcolorspace + }ifelse + imageormask_sys + }{ + write_image_file{ + currentcmykcolor + 0 ne{ + [/Separation/Black/DeviceGray{}]setcolorspace + gsave + /Black + [{1 exch sub/sep_tint AGMCORE_gget mul}/exec cvx MappedCSA sep_proc_name cvx exch pop{4 1 roll pop pop pop 1 exch sub}/exec cvx] + cvx modify_halftone_xfer + Operator currentdict read_image_file + grestore + }if + 0 ne{ + [/Separation/Yellow/DeviceGray{}]setcolorspace + gsave + /Yellow + [{1 exch sub/sep_tint AGMCORE_gget mul}/exec cvx MappedCSA sep_proc_name cvx exch pop{4 2 roll pop pop pop 1 exch sub}/exec cvx] + cvx modify_halftone_xfer + Operator currentdict read_image_file + grestore + }if + 0 ne{ + [/Separation/Magenta/DeviceGray{}]setcolorspace + gsave + /Magenta + [{1 exch sub/sep_tint AGMCORE_gget mul}/exec cvx MappedCSA sep_proc_name cvx exch pop{4 3 roll pop pop pop 1 exch sub}/exec cvx] + cvx modify_halftone_xfer + Operator currentdict read_image_file + grestore + }if + 0 ne{ + [/Separation/Cyan/DeviceGray{}]setcolorspace + gsave + /Cyan + [{1 exch sub/sep_tint AGMCORE_gget mul}/exec cvx MappedCSA sep_proc_name cvx exch pop{pop pop pop 1 exch sub}/exec cvx] + cvx modify_halftone_xfer + Operator currentdict read_image_file + grestore + }if + close_image_file + }{ + imageormask + }ifelse + }ifelse + }ifelse +}def +/indexed_imageormask +{ + begin + AGMIMG_init_common + save mark + currentdict + AGMCORE_host_sep{ + Operator/knockout eq{ + /indexed_colorspace_dict AGMCORE_gget dup/CSA known{ + /CSA get get_csa_by_name + }{ + /Names get + }ifelse + overprint_plate not{ + knockout_unitsq + }if + }{ + Indexed_DeviceN{ + /devicen_colorspace_dict AGMCORE_gget dup/names_index known exch/Names get convert_to_process or{ + indexed_image_lev2_sep + }{ + currentoverprint not{ + knockout_unitsq + }if + currentdict consumeimagedata + }ifelse + }{ + AGMCORE_is_cmyk_sep{ + Operator/imagemask eq{ + imageormask_sys + }{ + level2{ + indexed_image_lev2_sep + }{ + indexed_image_lev1_sep + }ifelse + }ifelse + }{ + currentoverprint not{ + knockout_unitsq + }if + currentdict consumeimagedata + }ifelse + }ifelse + }ifelse + }{ + level2{ + Indexed_DeviceN{ + /indexed_colorspace_dict AGMCORE_gget begin + }{ + /indexed_colorspace_dict AGMCORE_gget dup null ne + { + begin + currentdict/CSDBase known{CSDBase/CSD get_res/MappedCSA get}{CSA}ifelse + get_csa_by_name 0 get/DeviceCMYK eq ps_level 3 ge and ps_version 3015.007 lt and + AGMCORE_in_rip_sep and{ + [/Indexed[/DeviceN[/Cyan/Magenta/Yellow/Black]/DeviceCMYK{}]HiVal Lookup] + setcolorspace + }if + end + } + {pop}ifelse + }ifelse + imageormask + Indexed_DeviceN{ + end + }if + }{ + Operator/imagemask eq{ + imageormask + }{ + indexed_imageormask_lev1 + }ifelse + }ifelse + }ifelse + cleartomark restore + currentdict/_Filters known{_Filters AGMIMG_flushfilters}if + end +}def +/indexed_image_lev2_sep +{ + /indexed_colorspace_dict AGMCORE_gget begin + begin + Indexed_DeviceN not{ + currentcolorspace + dup 1/DeviceGray put + dup 3 + currentcolorspace 2 get 1 add string + 0 1 2 3 AGMCORE_get_ink_data 4 currentcolorspace 3 get length 1 sub + { + dup 4 idiv exch currentcolorspace 3 get exch get 255 exch sub 2 index 3 1 roll put + }for + put setcolorspace + }if + currentdict + Operator/imagemask eq{ + AGMIMG_&imagemask + }{ + use_mask{ + process_mask AGMIMG_&image + }{ + AGMIMG_&image + }ifelse + }ifelse + end end +}def + /OPIimage + { + dup type/dicttype ne{ + 10 dict begin + /DataSource xdf + /ImageMatrix xdf + /BitsPerComponent xdf + /Height xdf + /Width xdf + /ImageType 1 def + /Decode[0 1 def] + currentdict + end + }if + dup begin + /NComponents 1 cdndf + /MultipleDataSources false cdndf + /SkipImageProc{false}cdndf + /Decode[ + 0 + currentcolorspace 0 get/Indexed eq{ + 2 BitsPerComponent exp 1 sub + }{ + 1 + }ifelse + ]cdndf + /Operator/image cdndf + end + /sep_colorspace_dict AGMCORE_gget null eq{ + imageormask + }{ + gsave + dup begin invert_image_samples end + sep_imageormask + grestore + }ifelse + }def +/cachemask_level2 +{ + 3 dict begin + /LZWEncode filter/WriteFilter xdf + /readBuffer 256 string def + /ReadFilter + currentfile + 0(%EndMask)/SubFileDecode filter + /ASCII85Decode filter + /RunLengthDecode filter + def + { + ReadFilter readBuffer readstring exch + WriteFilter exch writestring + not{exit}if + }loop + WriteFilter closefile + end +}def +/spot_alias +{ + /mapto_sep_imageormask + { + dup type/dicttype ne{ + 12 dict begin + /ImageType 1 def + /DataSource xdf + /ImageMatrix xdf + /BitsPerComponent xdf + /Height xdf + /Width xdf + /MultipleDataSources false def + }{ + begin + }ifelse + /Decode[/customcolor_tint AGMCORE_gget 0]def + /Operator/image def + /SkipImageProc{false}def + currentdict + end + sep_imageormask + }bdf + /customcolorimage + { + Adobe_AGM_Image/AGMIMG_colorAry xddf + /customcolor_tint AGMCORE_gget + << + /Name AGMIMG_colorAry 4 get + /CSA[/DeviceCMYK] + /TintMethod/Subtractive + /TintProc null + /MappedCSA null + /NComponents 4 + /Components[AGMIMG_colorAry aload pop pop] + >> + setsepcolorspace + mapto_sep_imageormask + }ndf + Adobe_AGM_Image/AGMIMG_&customcolorimage/customcolorimage load put + /customcolorimage + { + Adobe_AGM_Image/AGMIMG_override false put + current_spot_alias{dup 4 get map_alias}{false}ifelse + { + false set_spot_alias + /customcolor_tint AGMCORE_gget exch setsepcolorspace + pop + mapto_sep_imageormask + true set_spot_alias + }{ + //Adobe_AGM_Image/AGMIMG_&customcolorimage get exec + }ifelse + }bdf +}def +/snap_to_device +{ + 6 dict begin + matrix currentmatrix + dup 0 get 0 eq 1 index 3 get 0 eq and + 1 index 1 get 0 eq 2 index 2 get 0 eq and or exch pop + { + 1 1 dtransform 0 gt exch 0 gt/AGMIMG_xSign? exch def/AGMIMG_ySign? exch def + 0 0 transform + AGMIMG_ySign?{floor 0.1 sub}{ceiling 0.1 add}ifelse exch + AGMIMG_xSign?{floor 0.1 sub}{ceiling 0.1 add}ifelse exch + itransform/AGMIMG_llY exch def/AGMIMG_llX exch def + 1 1 transform + AGMIMG_ySign?{ceiling 0.1 add}{floor 0.1 sub}ifelse exch + AGMIMG_xSign?{ceiling 0.1 add}{floor 0.1 sub}ifelse exch + itransform/AGMIMG_urY exch def/AGMIMG_urX exch def + [AGMIMG_urX AGMIMG_llX sub 0 0 AGMIMG_urY AGMIMG_llY sub AGMIMG_llX AGMIMG_llY]concat + }{ + }ifelse + end +}def +level2 not{ + /colorbuf + { + 0 1 2 index length 1 sub{ + dup 2 index exch get + 255 exch sub + 2 index + 3 1 roll + put + }for + }def + /tint_image_to_color + { + begin + Width Height BitsPerComponent ImageMatrix + /DataSource load + end + Adobe_AGM_Image begin + /AGMIMG_mbuf 0 string def + /AGMIMG_ybuf 0 string def + /AGMIMG_kbuf 0 string def + { + colorbuf dup length AGMIMG_mbuf length ne + { + dup length dup dup + /AGMIMG_mbuf exch string def + /AGMIMG_ybuf exch string def + /AGMIMG_kbuf exch string def + }if + dup AGMIMG_mbuf copy AGMIMG_ybuf copy AGMIMG_kbuf copy pop + } + addprocs + {AGMIMG_mbuf}{AGMIMG_ybuf}{AGMIMG_kbuf}true 4 colorimage + end + }def + /sep_imageormask_lev1 + { + begin + MappedCSA 0 get dup/DeviceRGB eq exch/DeviceCMYK eq or has_color not and{ + { + 255 mul round cvi GrayLookup exch get + }currenttransfer addprocs settransfer + currentdict imageormask + }{ + /sep_colorspace_dict AGMCORE_gget/Components known{ + MappedCSA 0 get/DeviceCMYK eq{ + Components aload pop + }{ + 0 0 0 Components aload pop 1 exch sub + }ifelse + Adobe_AGM_Image/AGMIMG_k xddf + Adobe_AGM_Image/AGMIMG_y xddf + Adobe_AGM_Image/AGMIMG_m xddf + Adobe_AGM_Image/AGMIMG_c xddf + AGMIMG_y 0.0 eq AGMIMG_m 0.0 eq and AGMIMG_c 0.0 eq and{ + {AGMIMG_k mul 1 exch sub}currenttransfer addprocs settransfer + currentdict imageormask + }{ + currentcolortransfer + {AGMIMG_k mul 1 exch sub}exch addprocs 4 1 roll + {AGMIMG_y mul 1 exch sub}exch addprocs 4 1 roll + {AGMIMG_m mul 1 exch sub}exch addprocs 4 1 roll + {AGMIMG_c mul 1 exch sub}exch addprocs 4 1 roll + setcolortransfer + currentdict tint_image_to_color + }ifelse + }{ + MappedCSA 0 get/DeviceGray eq{ + {255 mul round cvi ColorLookup exch get 0 get}currenttransfer addprocs settransfer + currentdict imageormask + }{ + MappedCSA 0 get/DeviceCMYK eq{ + currentcolortransfer + {255 mul round cvi ColorLookup exch get 3 get 1 exch sub}exch addprocs 4 1 roll + {255 mul round cvi ColorLookup exch get 2 get 1 exch sub}exch addprocs 4 1 roll + {255 mul round cvi ColorLookup exch get 1 get 1 exch sub}exch addprocs 4 1 roll + {255 mul round cvi ColorLookup exch get 0 get 1 exch sub}exch addprocs 4 1 roll + setcolortransfer + currentdict tint_image_to_color + }{ + currentcolortransfer + {pop 1}exch addprocs 4 1 roll + {255 mul round cvi ColorLookup exch get 2 get}exch addprocs 4 1 roll + {255 mul round cvi ColorLookup exch get 1 get}exch addprocs 4 1 roll + {255 mul round cvi ColorLookup exch get 0 get}exch addprocs 4 1 roll + setcolortransfer + currentdict tint_image_to_color + }ifelse + }ifelse + }ifelse + }ifelse + end + }def + /sep_image_lev1_sep + { + begin + /sep_colorspace_dict AGMCORE_gget/Components known{ + Components aload pop + Adobe_AGM_Image/AGMIMG_k xddf + Adobe_AGM_Image/AGMIMG_y xddf + Adobe_AGM_Image/AGMIMG_m xddf + Adobe_AGM_Image/AGMIMG_c xddf + {AGMIMG_c mul 1 exch sub} + {AGMIMG_m mul 1 exch sub} + {AGMIMG_y mul 1 exch sub} + {AGMIMG_k mul 1 exch sub} + }{ + {255 mul round cvi ColorLookup exch get 0 get 1 exch sub} + {255 mul round cvi ColorLookup exch get 1 get 1 exch sub} + {255 mul round cvi ColorLookup exch get 2 get 1 exch sub} + {255 mul round cvi ColorLookup exch get 3 get 1 exch sub} + }ifelse + AGMCORE_get_ink_data currenttransfer addprocs settransfer + currentdict imageormask_sys + end + }def + /indexed_imageormask_lev1 + { + /indexed_colorspace_dict AGMCORE_gget begin + begin + currentdict + MappedCSA 0 get dup/DeviceRGB eq exch/DeviceCMYK eq or has_color not and{ + {HiVal mul round cvi GrayLookup exch get HiVal div}currenttransfer addprocs settransfer + imageormask + }{ + MappedCSA 0 get/DeviceGray eq{ + {HiVal mul round cvi Lookup exch get HiVal div}currenttransfer addprocs settransfer + imageormask + }{ + MappedCSA 0 get/DeviceCMYK eq{ + currentcolortransfer + {4 mul HiVal mul round cvi 3 add Lookup exch get HiVal div 1 exch sub}exch addprocs 4 1 roll + {4 mul HiVal mul round cvi 2 add Lookup exch get HiVal div 1 exch sub}exch addprocs 4 1 roll + {4 mul HiVal mul round cvi 1 add Lookup exch get HiVal div 1 exch sub}exch addprocs 4 1 roll + {4 mul HiVal mul round cvi Lookup exch get HiVal div 1 exch sub}exch addprocs 4 1 roll + setcolortransfer + tint_image_to_color + }{ + currentcolortransfer + {pop 1}exch addprocs 4 1 roll + {3 mul HiVal mul round cvi 2 add Lookup exch get HiVal div}exch addprocs 4 1 roll + {3 mul HiVal mul round cvi 1 add Lookup exch get HiVal div}exch addprocs 4 1 roll + {3 mul HiVal mul round cvi Lookup exch get HiVal div}exch addprocs 4 1 roll + setcolortransfer + tint_image_to_color + }ifelse + }ifelse + }ifelse + end end + }def + /indexed_image_lev1_sep + { + /indexed_colorspace_dict AGMCORE_gget begin + begin + {4 mul HiVal mul round cvi Lookup exch get HiVal div 1 exch sub} + {4 mul HiVal mul round cvi 1 add Lookup exch get HiVal div 1 exch sub} + {4 mul HiVal mul round cvi 2 add Lookup exch get HiVal div 1 exch sub} + {4 mul HiVal mul round cvi 3 add Lookup exch get HiVal div 1 exch sub} + AGMCORE_get_ink_data currenttransfer addprocs settransfer + currentdict imageormask_sys + end end + }def +}if +end +systemdict/setpacking known +{setpacking}if +%%EndResource +currentdict Adobe_AGM_Utils eq {end} if +%%EndProlog +%%BeginSetup +Adobe_AGM_Utils begin +2 2010 Adobe_AGM_Core/ds gx +Adobe_CoolType_Core/ds get exec Adobe_AGM_Image/ds gx +currentdict Adobe_AGM_Utils eq {end} if +%%EndSetup +%%Page: 32 1 +%%EndPageComments +%%BeginPageSetup +%ADOBeginClientInjection: PageSetup Start "AI11EPS" +%AI12_RMC_Transparency: Balance=75 RasterRes=300 GradRes=150 Text=0 Stroke=1 Clip=1 OP=0 +%ADOEndClientInjection: PageSetup Start "AI11EPS" +Adobe_AGM_Utils begin +Adobe_AGM_Core/ps gx +Adobe_AGM_Utils/capture_cpd gx +Adobe_CoolType_Core/ps get exec Adobe_AGM_Image/ps gx +%ADOBeginClientInjection: PageSetup End "AI11EPS" +/currentdistillerparams where {pop currentdistillerparams /CoreDistVersion get 5000 lt} {true} ifelse { userdict /AI11_PDFMark5 /cleartomark load put userdict /AI11_ReadMetadata_PDFMark5 {flushfile cleartomark } bind put} { userdict /AI11_PDFMark5 /pdfmark load put userdict /AI11_ReadMetadata_PDFMark5 {/PUT pdfmark} bind put } ifelse [/NamespacePush AI11_PDFMark5 [/_objdef {ai_metadata_stream_123} /type /stream /OBJ AI11_PDFMark5 [{ai_metadata_stream_123} currentfile 0 (% &&end XMP packet marker&&) /SubFileDecode filter AI11_ReadMetadata_PDFMark5 + + + + application/postscript + + + diagramas_01 + + + + + Adobe Illustrator CS4 + 2011-08-11T16:24:12-03:00 + 2011-08-11T16:24:13-03:00 + 2011-08-11T16:24:13-03:00 + + + + 256 + 152 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAmAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A715g80eW9GsobkR2NzG5 KE8v21APD91FN8RHjTAyAFeaE1Pz1+XxtBGjwsLs+irtbui8GkMMkis8LI4ShPgae4qWKDt/N/5f aZPGI5I5IbmNXk9S0MBiiWJpVZEW3UuHr0r1O3fFUxbz35IXV/0dwjJoFb/R5fWEzSKixeh6PMlu ddvA7eKqfJeeW3thcLLaCyZlBcmNUD8WIVq0o1D0O+KpBJ538pW2ty6XexWsTxtwUxJJM5kZ1RF4 LAPtc6/CxwBlIDogrrzT+Xmq3pg5R8YkKxOlkZZCzq7PWNrd2X01hr4b74WKvpPnj8vxbSxVhENm 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 + + + + + + proof:pdf + uuid:65E6390686CF11DBA6E2D887CEACB407 + xmp.did:F77F11740720681195FE9289A38AD1BC + xmp.iid:F77F11740720681195FE9289A38AD1BC + + + + converted + from application/pdf to <unknown> + + + saved + xmp.iid:D47F11740720681191099C3B601C4548 + 2008-04-17T14:19:21+05:30 + Adobe Illustrator CS4 + + + / + + + + + converted + from application/pdf to <unknown> + + + converted + from application/pdf to <unknown> + + + saved + xmp.iid:FD7F11740720681197C1BF14D1759E83 + 2008-05-16T17:01:20-07:00 + Adobe Illustrator CS4 + + + / + + + + + saved + xmp.iid:F77F117407206811BC18AC99CBA78E83 + 2008-05-19T18:10:15-07:00 + Adobe Illustrator CS4 + + + / + + + + + converted + from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator + + + saved + xmp.iid:FB7F117407206811B628E3BF27C8C41B + 2008-05-22T14:26:44-07:00 + Adobe Illustrator CS4 + + + / + + + + + converted + from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator + + + saved + xmp.iid:08C3BD25102DDD1181B594070CEB88D9 + 2008-05-28T16:51:46-07:00 + Adobe Illustrator CS4 + + + / + + + + + converted + from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator + + + saved + xmp.iid:F77F11740720681192B0DFFC927805D7 + 2008-05-30T21:26:38-07:00 + Adobe Illustrator CS4 + + + / + + + + + converted + from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator + + + saved + xmp.iid:F87F11740720681192B0DFFC927805D7 + 2008-05-30T21:27-07:00 + Adobe Illustrator CS4 + + + / + + + + + converted + from application/vnd.adobe.illustrator to application/vnd.adobe.illustrator + + + saved + xmp.iid:F97F1174072068119098B097FDA39BEF + 2008-06-02T13:26:10-07:00 + Adobe Illustrator CS4 + + + / + + + + + saved + xmp.iid:F77F1174072068118DBB9A084B3843B2 + 2011-06-09T11:06:05-03:00 + Adobe Illustrator CS4 + / + + + saved + xmp.iid:F87F1174072068118DBB9A084B3843B2 + 2011-06-09T15:15:58-03:00 + Adobe Illustrator CS4 + / + + + saved + xmp.iid:7FF2245A3B2068118DBB9A084B3843B2 + 2011-06-09T17:21:50-03:00 + Adobe Illustrator CS4 + / + + + saved + xmp.iid:F77F11740720681195FE9289A38AD1BC + 2011-08-11T16:24:13-03:00 + Adobe Illustrator CS4 + / + + + + + uuid:4e77a4dc-c4f9-5f4e-8a6a-79787d0e84c9 + xmp.did:7FF2245A3B2068118DBB9A084B3843B2 + uuid:65E6390686CF11DBA6E2D887CEACB407 + proof:pdf + + + + Web + + + 1 + False + False + + 719.658203 + 779.438477 + Pixels + + + + + BitstreamVeraSerif-Roman + Bitstream Vera Serif + Roman + TrueType + Release 1.10 + False + VeraSe.ttf + + + Arial-BoldMT + Arial + Bold + Open Type + Version 5.01.2x + False + Arial Bold.ttf + + + ArialMT + Arial + Regular + Open Type + Version 5.01.2x + False + Arial.ttf + + + Arial-BoldItalicMT + Arial + Bold Italic + Open Type + Version 5.00.2x + False + Arial Bold Italic.ttf + + + MyriadPro-Regular + Myriad Pro + Regular + Open Type + Version 2.037;PS 2.000;hotconv 1.0.51;makeotf.lib2.0.18671 + False + MyriadPro-Regular.otf + + + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + White + RGB + PROCESS + 255 + 255 + 255 + + + Black + RGB + PROCESS + 0 + 0 + 0 + + + RGB Red + RGB + PROCESS + 255 + 0 + 0 + + + RGB Yellow + RGB + PROCESS + 255 + 255 + 0 + + + RGB Green + RGB + PROCESS + 0 + 255 + 0 + + + RGB Cyan + RGB + PROCESS + 0 + 255 + 255 + + + RGB Blue + RGB + PROCESS + 0 + 0 + 255 + + + RGB Magenta + RGB + PROCESS + 255 + 0 + 255 + + + R=193 G=39 B=45 + RGB + PROCESS + 193 + 39 + 45 + + + R=237 G=28 B=36 + RGB + PROCESS + 237 + 28 + 36 + + + R=241 G=90 B=36 + RGB + PROCESS + 241 + 90 + 36 + + + R=247 G=147 B=30 + RGB + PROCESS + 247 + 147 + 30 + + + R=251 G=176 B=59 + RGB + PROCESS + 251 + 176 + 59 + + + R=252 G=238 B=33 + RGB + PROCESS + 252 + 238 + 33 + + + R=217 G=224 B=33 + RGB + PROCESS + 217 + 224 + 33 + + + R=140 G=198 B=63 + RGB + PROCESS + 140 + 198 + 63 + + + R=57 G=181 B=74 + RGB + PROCESS + 57 + 181 + 74 + + + R=0 G=146 B=69 + RGB + PROCESS + 0 + 146 + 69 + + + R=0 G=104 B=55 + RGB + PROCESS + 0 + 104 + 55 + + + R=34 G=181 B=115 + RGB + PROCESS + 34 + 181 + 115 + + + R=0 G=169 B=157 + RGB + PROCESS + 0 + 169 + 157 + + + R=41 G=171 B=226 + RGB + PROCESS + 41 + 171 + 226 + + + R=0 G=113 B=188 + RGB + PROCESS + 0 + 113 + 188 + + + R=46 G=49 B=146 + RGB + PROCESS + 46 + 49 + 146 + + + R=27 G=20 B=100 + RGB + PROCESS + 27 + 20 + 100 + + + R=102 G=45 B=145 + RGB + PROCESS + 102 + 45 + 145 + + + R=147 G=39 B=143 + RGB + PROCESS + 147 + 39 + 143 + + + R=158 G=0 B=93 + RGB + PROCESS + 158 + 0 + 93 + + + R=212 G=20 B=90 + RGB + PROCESS + 212 + 20 + 90 + + + R=237 G=30 B=121 + RGB + PROCESS + 237 + 30 + 121 + + + R=199 G=178 B=153 + RGB + PROCESS + 199 + 178 + 153 + + + R=153 G=134 B=117 + RGB + PROCESS + 153 + 134 + 117 + + + R=115 G=99 B=87 + RGB + PROCESS + 115 + 99 + 87 + + + R=83 G=71 B=65 + RGB + PROCESS + 83 + 71 + 65 + + + R=198 G=156 B=109 + RGB + PROCESS + 198 + 156 + 109 + + + R=166 G=124 B=82 + RGB + PROCESS + 166 + 124 + 82 + + + R=140 G=98 B=57 + RGB + PROCESS + 140 + 98 + 57 + + + R=117 G=76 B=36 + RGB + PROCESS + 117 + 76 + 36 + + + R=96 G=56 B=19 + RGB + PROCESS + 96 + 56 + 19 + + + R=66 G=33 B=11 + RGB + PROCESS + 66 + 33 + 11 + + + + + + Grays + 1 + + + + R=0 G=0 B=0 + RGB + PROCESS + 0 + 0 + 0 + + + R=26 G=26 B=26 + RGB + PROCESS + 26 + 26 + 26 + + + R=51 G=51 B=51 + RGB + PROCESS + 51 + 51 + 51 + + + R=77 G=77 B=77 + RGB + PROCESS + 77 + 77 + 77 + + + R=102 G=102 B=102 + RGB + PROCESS + 102 + 102 + 102 + + + R=128 G=128 B=128 + RGB + PROCESS + 128 + 128 + 128 + + + R=153 G=153 B=153 + RGB + PROCESS + 153 + 153 + 153 + + + R=179 G=179 B=179 + RGB + PROCESS + 179 + 179 + 179 + + + R=204 G=204 B=204 + RGB + PROCESS + 204 + 204 + 204 + + + R=230 G=230 B=230 + RGB + PROCESS + 230 + 230 + 230 + + + R=242 G=242 B=242 + RGB + PROCESS + 242 + 242 + 242 + + + + + + Web Color Group + 1 + + + + R=63 G=169 B=245 + RGB + PROCESS + 63 + 169 + 245 + + + R=122 G=201 B=67 + RGB + PROCESS + 122 + 201 + 67 + + + R=255 G=147 B=30 + RGB + PROCESS + 255 + 147 + 30 + + + R=255 G=29 B=37 + RGB + PROCESS + 255 + 29 + 37 + + + R=255 G=123 B=172 + RGB + PROCESS + 255 + 123 + 172 + + + R=189 G=204 B=212 + RGB + PROCESS + 189 + 204 + 212 + + + + + + + + + Adobe PDF library 9.00 + + + + + + + + + + + + + + + + + + + + + + + + + % &&end XMP packet marker&& [{ai_metadata_stream_123} <> /PUT AI11_PDFMark5 [/Document 1 dict begin /Metadata {ai_metadata_stream_123} def currentdict end /BDC AI11_PDFMark5 +%ADOEndClientInjection: PageSetup End "AI11EPS" +%%EndPageSetup +1 -1 scale 0 -779.438 translate +pgsv +[1 0 0 1 0 0 ]ct +gsave +np +gsave +0 0 mo +0 779.438 li +719.658 779.438 li +719.658 0 li +cp +clp +[1 0 0 1 0 0 ]ct +706.658 767.438 mo +13.1016 767.438 li +13.1016 43.1133 li +706.658 43.1133 li +706.658 767.438 li +cp +false sop +/0 +[/DeviceCMYK] /CSA add_res +3.0518e-05 3.0518e-05 3.0518e-05 3.0518e-05 cmyk +f +1.49613 lw +0 lc +0 lj +4 ml +[] 0 dsh +true sadj +706.658 767.438 mo +13.1016 767.438 li +13.1016 43.1133 li +706.658 43.1133 li +706.658 767.438 li +cp +.193668 .150057 .155337 3.0518e-05 cmyk +@ +706.658 43.4492 mo +13.1016 43.4492 li +13.1016 14.3047 li +706.658 14.3047 li +706.658 43.4492 li +cp +f +1.17553 lw +706.658 43.4492 mo +13.1016 43.4492 li +13.1016 14.3047 li +706.658 14.3047 li +706.658 43.4492 li +cp +@ +.69482 .6318 .621515 .583612 cmyk +%ADOBeginSubsetFont: ArialMT Initial +%ADOt1write: (1.0.24) %%Copyright: Copyright 2011 Adobe System Incorporated. All rights reserved. 12 dict dup begin /FontType 1 def /FontName /ArialMT def /FontInfo 5 dict dup begin /ItalicAngle 0 def /FSType 8 def end def /PaintType 0 def /FontMatrix [0.001 0 0 0.001 0 0] def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 32 /space put dup 65 /A put dup 67 /C put dup 69 /E put dup 73 /I put dup 76 /L put dup 77 /M put dup 78 /N put dup 79 /O put dup 80 /P put dup 82 /R put def /FontBBox {-665 -325 2000 1006} def end systemdict begin dup /Private 7 dict dup begin /|- {def} def /| {put} def /BlueValues [0 0] def /password 5839 def /MinFeature {16 16} def /OtherSubrs[{}{}{}{systemdict/internaldict known not{pop 3}{1183615869 systemdict/internaldict get exec dup/startlock known{/startlock get exec}{dup /strtlck known{/strtlck get exec}{pop 3}ifelse}ifelse}ifelse}executeonly]def /Subrs 5 array dup 0 <1C60D8A8CC31FE2BF6E07AA3E541E2> | dup 1 <1C60D8A8C9C3D06D9E> | dup 2 <1C60D8A8C9C202D79A> | dup 3 <1C60D8A849> | dup 4 <1C60D8A8CC3674F41144B13B77> | def put dup /CharStrings 12 dict dup begin /.notdef <1C60D8A8C9B6E3FA5101D97F0BCF44F7161DEB1E2A84766DD477E7 C8A936AA182F5809A9> |- /space <1C60D8A8C9B854D00D> |- /A <1C60D8A8C9B64EDFED26B9E21A4F64848088903AC9891CF791BDBC4AB29A CC8B3E8D13924A7DDE35F09AC5F4A8229C87124C732743268600EF8D4582208B D16D82> |- /C <1C60D8A8C9B6079F6D1C46AC2732DFBDC9143C94793529C1940296210AAD 6EE09C39CFC4DAB7C5F3BA33C9E10838E0BC6FC9318A4E57F309EE20438B434C 69AE73A499211EBA75E22A57C1581D93869428818DC700A28C027571D7047CDF A8B017AACDE96DE4B2579EFD2C826A30F6EBDDC52701A22CDD669ADC60B66F32 261A1F55EDEF9802FD4511E0EF130772EDFD708A4113A1EDB1E717E0FA7D3148 51DE59> |- /E <1C60D8A8C9B64EDFFB83C6241DB110BEE5AB2FAD9D94B39ED5E81E7411B6 6E9361DDE78FC667AB91EF9824> |- /I <1C60D8A8C9B854D0F463D3892D665712D6B7D6A81E> |- /L <1C60D8A8C9B7EF3224EC6E192BD0FEC2445DA87B99CF0E03A72A> |- /M <1C60D8A8C9B6B41CBB4B6664BFFC865F56E6FEAFA79E7B90883C1C68AFB3 79AC174B0F8DCC9294E2C26BD06BBA9FD3867F8768651EF4BA798B4F538FCE8F 80AF5A83421F8F> |- /N <1C60D8A8C9B6079F629170873C67115641D0B6890161EC48F71E8D2106F3 AC927984C1E464F121F968> |- /O <1C60D8A8C9B6FF86E621E1FAD9CC02A23AF5AAF7451327A9277DAE8170AA C8E603A02E3EEFF561DDADE9FD6F6F16B77EE709DD797791A73F1C532C58482F 9C51E1EAE7EA6E4D820E6AA1026E7BE345B1C97C5D9EBBEF4840C4188F96B538 0E7625249BBAD172254404F6F1CB17CABA1F131B17AAAB56C5D3B94E3AC2C2E9 F0A0D079C435D0249DF6C47E18FCF00E7FFE3C519BB35DF797EF47286BDCA762 289BE1> |- /P <1C60D8A8C9B64EDFF4950CC53012D47AE97D5586315BA2F5162B63CEC117 C5379A1B3DB174CB2C739C68916A1E99A346AFF71DBF25658867D9AEF1BF3C47 CE1BA73978E8D0D40E52B85A56E08A1369D85E15B0A0C517291916FF6E61D0EF BF59B4862165C7DEA15B42BE3811C2CAA25C54> |- /R <1C60D8A8C9B6079F62E89B521DCDBE3DC5497B8DD99916239C0DFA5ED4F6 32B33575F4260343AF5DB7D477D12055F49C5E99C0AC176EAD42723223937F2B A15ECAD7751CB6A136B700EE485E38E7CDB87D9465C90BB8E29B04FDDA42609F BC3833B9FB5105619F4CC434003085F449D9FD5022725306B331FB97B31D2952 57B180DE1FD5465D256CCA19301DA97326882845130A5257BF61307ABA64C3F0 B222> |- end put end dup /FontName get exch definefont pop end %ADOEndSubsetFont +/CYNJSJ+ArialMT /ArialMT findfont ct_VMDictPut /CYNJSJ+ArialMT*1 [32{/.notdef}rp /space 32{/.notdef}rp /A /.notdef /C /.notdef /E 3{/.notdef}rp /I 2{/.notdef}rp /L /M /N /O /P /.notdef /R 173{/.notdef}rp] CYNJSJ+ArialMT nf CYNJSJ+ArialMT*1 [16 0 0 -16 0 0 ]msf 284.899 36.4146 mo (ECORE MAIN LOOP)sh 234.184 104.554 mo +59.1172 104.554 li +59.1172 65.1787 li +234.184 65.1787 li +234.184 104.554 li +cp +3.0518e-05 3.0518e-05 3.0518e-05 3.0518e-05 cmyk +f +.278741 lw +234.184 104.554 mo +59.1172 104.554 li +59.1172 65.1787 li +234.184 65.1787 li +234.184 104.554 li +cp +.75021 .679683 .670222 .90164 cmyk +@ +234.184 191.073 mo +59.1172 191.073 li +59.1172 151.698 li +234.184 151.698 li +234.184 191.073 li +cp +3.0518e-05 3.0518e-05 3.0518e-05 3.0518e-05 cmyk +f +234.184 191.073 mo +59.1172 191.073 li +59.1172 151.698 li +234.184 151.698 li +234.184 191.073 li +cp +.75021 .679683 .670222 .90164 cmyk +@ +234.184 277.533 mo +59.1172 277.533 li +59.1172 238.158 li +234.184 238.158 li +234.184 277.533 li +cp +3.0518e-05 3.0518e-05 3.0518e-05 3.0518e-05 cmyk +f +234.184 277.533 mo +59.1172 277.533 li +59.1172 238.158 li +234.184 238.158 li +234.184 277.533 li +cp +.75021 .679683 .670222 .90164 cmyk +@ +234.184 362.545 mo +59.1172 362.545 li +59.1172 323.17 li +234.184 323.17 li +234.184 362.545 li +cp +3.0518e-05 3.0518e-05 3.0518e-05 3.0518e-05 cmyk +f +234.184 362.545 mo +59.1172 362.545 li +59.1172 323.17 li +234.184 323.17 li +234.184 362.545 li +cp +.75021 .679683 .670222 .90164 cmyk +@ +234.184 564.759 mo +59.1172 564.759 li +59.1172 525.384 li +234.184 525.384 li +234.184 564.759 li +cp +3.0518e-05 3.0518e-05 3.0518e-05 3.0518e-05 cmyk +f +234.184 564.759 mo +59.1172 564.759 li +59.1172 525.384 li +234.184 525.384 li +234.184 564.759 li +cp +.75021 .679683 .670222 .90164 cmyk +@ +.69482 .6318 .621515 .583612 cmyk +%ADOBeginSubsetFont: ArialMT AddGlyphs +%ADOt1write: (1.0.24) %%Copyright: Copyright 2011 Adobe System Incorporated. All rights reserved. systemdict begin CYNJSJ+ArialMT dup /Private get dup rcheck {begin true}{pop false}ifelse exch /CharStrings get begin systemdict /gcheck known {currentglobal currentdict gcheck setglobal} if /S <1C60D8A8C9B64EDFE3D078722A65C31955939D63AA5C8A4945719B5E558E 3B73A676CC12D1E18D93A8DC67C074D6E352D426981DE76F8EC4CFE5DAE051BE 47753A7C234C4B8D7D9F50292A61882B5500CC701F878FE626CDC6D4C322BB39 1537921D673F5AEE3EC19E36E7EFEC0F06A0EA4EAAB6BBA94DDCD11A6A564B13 B510F8C915848233B82F046D854DCD4F1639F149305DC73D3C68DF8AEB47A96A 30E55CF8BAD07FA2825BCE0D675F1CC2EBE61B07B772130E23119250F1EBF8FE 12A2098D9F09F3F21BDC41666CA4A0BB70D5F0A750B44BB93A5FBFDD2BF8DE45 0B277265536F77D5BD6F44FB72FF2E708C60107653AE44BFFB26AFF8> |- /a <1C60D8A8C9B7EF32244AC11AA6BAAA29EE8C78E0E7206F4A2776A2D1EA7D C8D9A28C62ADE3B609CF5E2EE23C64D0B75055BD249ADFEC7B4224D040D883CA 6747571955349CF8AD17E94E6FE5D0259F4D55623D4DC5C3CB4AC64A7A87DBBA 48B7420D7990F3C261DB9838C5B90BF72B82C8238A1A58FE8E6137AAFE2405FD 710F7ADB95B4F576668A6DB104942C88ED8D01E4E58188F5E32A24B5B964D5CE C10C08F76C0F472E84A0FB6EB5E37AAEE233DE54C212B0A012D3E20F864B2D53 463E221F81B784B6F7BE81FBFCAE6785C2430454DD81C436E0A516BF8C8307B2 879FF86378629C5EA7E586D83C83550D2E732930F7FE3BAD07B86C81E024D177 B5D88A> |- /e <1C60D8A8C9B7EF322472FA01213C7AD90A23B536C2309DD40D370E2449B0 D0FEF85A6BE8067F30686F143E75903EB6FA56935472EF47CE3F33433C2F0C8B 6FA51573AE54B2C516F6F024F8775AD6639544E339FC2A328548BCBFD58B0EEA 03B7DC3AB069F44477958BFBFAAC7196D411DF9BE0B78A86C4BC33EC5D7C3729 5284C077711C162623860AACA404F650F8D516970257> |- /g <1C60D8A8C9B7EF322851D9960AE993FFFAEAEBBA8EF734FCE7E65DE817A0 65D42CB79E2F25620DE08D5E215259551032CAAB8B674940F5B4BAAF40766D55 9B26E9A0C2464D0F504C4718579670D62707FEBC08A2CD71BF2528BA3A24A0C2 47BA70F9E817A1709BB6F7008D6C121249525DEE3A93F6DA16170F68BD3667DC 9FF533284D078DAE144C0DB42F376056761CFA5A80B4ED7D37E57EA658F3FBD8 8F779C828BF992A89F02F1397EF90BADA44FB7F676FF0295FF6F9748D66EBF57 5C72F67F4BEBB98F8AFA57505EC9> |- /m <1C60D8A8C9B6B41CBB5F87BE20C872DF59FABCB36542419CBFA3D5519AD5 BA8076F32ECFD724B055F72CAC37BC47239ACC8B0FB48B8ACFF099B97085BD99 C333951D0338D27FF6AB9B3F3C69320476BA0CD4F9573B79AD358A91B0176AFB 9AEF169308783E9C6287F18E6E658AF5AA6C9688B500806DA169A1B21069D55C 54A2FF607A6A38976171B08665C3ACCAA84DFB970D01180645CE5CBC48DFE37B> |- /o <1C60D8A8C9B7EF32334FFE7884F6C3B903D000D9FD76C2EAE8EDCCA90A98 7875625CA0393015EF6761BE1C3B6D9E9DA4BABE1DD313B783BCBF8F620C846C 7F6361946173FB7A4A6BF94EAA0CB4947DD1974AF371F3C211E584576DE9AD79 F9DA988E9E531810E3876F3029BB1D2ED366525F30E48DD7CE3C9B66C5CC099F 518C54BB58C51D6FB6D0C8> |- /p <1C60D8A8C9B7EF322B3B0CFC8FED720BC90E20B208D27DC4B8F11F10B964 70F8B4F5FABEC7F7010781F5077B417FE44279776F2304ACD6E0EA12F436330D C4B79C907B9D28468D10FF9256A7D2CA504E4498D719ACD86FCA89B33C61F556 CF1168C3F262A781155D5EBF0C47D71C584AB93037B47B18D39FE408A49672C1 E63F9E8368D19E113FC95C59A9FA4650E46F6399F2FF256844E27568BA34B9> |- /r <1C60D8A8C9B81F2C3A9694980E415F1DEF5C498473095A24D1BE11285789 4FEA85DB28AD762FB8D2F4CAC5BF8B9C18D8A2DFCF155E0751AF58898A6619AD D420F549AB7C795751D32E8EE6> |- /t <1C60D8A8C9B854D0F45CF665C7276F8075B54A4ECD6470F395A458CA2D06 5152075036EEECA213894C1EA0DACFBD370590F4B831924E5BDA5281442349CF AD2545E0750C3004A129C25B1EAA8DEF5DA8BF1998E80AE266F591E64CB5127F 5C42C88FB43C> |- /u <1C60D8A8C9B7EF32240889FE90FF09F794E92023A18223CCBE3629AB7F51 7D090BF7D55C0A5A8EADD9BE381137FE8504E8B2DB3D16839889E327241ACA8F 992A2BB9AD2BCE57ADB306CE2789439E67A64C32BE8669C197F5851EE3879399 0906DA8D7F8ACFF6D70790F06B02> |- systemdict /gcheck known {setglobal} if end {end} if end CYNJSJ+ArialMT /Encoding get dup 83 /S put dup 97 /a put dup 101 /e put dup 103 /g put dup 109 /m put dup 111 /o put dup 112 /p put dup 114 /r put dup 116 /t put dup 117 /u put pop %ADOEndSubsetFont +/CYNJSJ+ArialMT*1 [32{/.notdef}rp /space 32{/.notdef}rp /A /.notdef /C /.notdef /E 3{/.notdef}rp /I 2{/.notdef}rp /L /M /N /O /P /.notdef /R /S 13{/.notdef}rp /a 3{/.notdef}rp /e /.notdef /g 5{/.notdef}rp /m /.notdef /o /p /.notdef /r /.notdef /t /u 138{/.notdef}rp] CYNJSJ+ArialMT nf CYNJSJ+ArialMT*1 [20.625 0 0 -20.625 0 0 ]msf 75.5703 92.5557 mo (Set)sh 106.528 92.5557 mo ( up )sh 140.93 92.5557 mo (program)sh %ADOBeginSubsetFont: ArialMT AddGlyphs +%ADOt1write: (1.0.24) %%Copyright: Copyright 2011 Adobe System Incorporated. All rights reserved. systemdict begin CYNJSJ+ArialMT dup /Private get dup rcheck {begin true}{pop false}ifelse exch /CharStrings get begin systemdict /gcheck known {currentglobal currentdict gcheck setglobal} if /d <1C60D8A8C9B7EF322407C6655A1B3652DB8522EB511BE6B0855A72D96214 58876CAD1FA22A00635F436A34E23EAFC09C394044ECC1389CD99E4AF1C1F6DD 52305C78619784840FC37A805B0805EF290BC9E049CF068290816CB7E74DB612 941355BCE71CBDD11DD0F9CA29531036ED13EFB9CAB613E9F630FBBC9408EF13 CE4683D92968530F64760C3DF85C7C7EA06EBA8BF859> |- /i <1C60D8A8C9B88C087228DFC7C7ABCC71B868F57EDB285655227000619B17 1C8A80AB> |- /l <1C60D8A8C9B88C08722AD20D19A90F9064193C8D82> |- /n <1C60D8A8C9B7EF322B3BE19FB964E04D2DB06D4930CA5D8F41D2EF3A285C 0BD536CD2C57668EB9E30311BF9A2872DFB44F2BF2A4683B5D66FA01BB1CCDAD E9C8A9EE2CB010715D3D6DFF0E843CF77C87A07D1DBD0482675E3CA1DAA2A520 3A8015DD09B7CE> |- /s <1C60D8A8C9B7A73DA057E90C9BFBE0FE301E99CB771FA2F05368A6342B5F 80456D91458EA2F3CAD55CDF89BFF34EEB39D7DD325B057E2BF0E9B878C214E2 BD1BD70DCABE10E0DC8EBCF7B100B55EBE94FB0F17084E21EBD279B324AEABD9 6538911D053BE9D7ECBF43F934B1033C9E405BBE31E7EDB643609C8D779046E1 B250C3CF05E6FA4787649137D90F47F85972A6603BA900DD7CB710E02662DB32 87CB26D7B7AE794611498865FC85A28083D2F6C2DEC302D47619A4A577C5B843 5558FCFE71A1BB6783AFD5F58B6D2C03593B3F2297A66A7E6D13C1E321C57F41 72D53C8FCAF4D28F2B78D3A4BF03> |- /x <1C60D8A8C9B7A73DB920A1A3B81DE7234ACAA5546B4C65820CF3C50E1629 C5A6423BAA34A2ECA8C7FE4B71726AC6704CC23AF1725AFB30D2892FC1BDDAFE AD7BE7BD65F1051699CCF4B0> |- /quotedblleft <1C60D8A8C9B81F2C29FEF6324F1D6735A7858A1650FF442B8 8CE2923602889F1B3B1A969EB1BD5F20410F3DB624E1F268B8C262BA05A2218D B63CD4FCDB84E55D828665FCCF9A1929C551F51708569F37B29C42371CBCFE1A DDF91> |- /quotedblright <1C60D8A8C9B81F2C2EF77CAB1B3909C6126BCD66FE80E8DB 29C6D13E62A206E4D2C01E4CBD15B6CCAE445397315B1B2A4223B2D9E8CFF123 FD968D68396195C7E56F7437E66455F3A5CFF0D3E7C9903481BE93623D7A22F2 1FF9D67D> |- systemdict /gcheck known {setglobal} if end {end} if end CYNJSJ+ArialMT /Encoding get dup 100 /d put dup 105 /i put dup 108 /l put dup 110 /n put dup 115 /s put dup 120 /x put dup 210 /quotedblleft put dup 211 /quotedblright put pop %ADOEndSubsetFont +/CYNJSJ+ArialMT*1 [32{/.notdef}rp /space 32{/.notdef}rp /A /.notdef /C /.notdef /E 3{/.notdef}rp /I 2{/.notdef}rp /L /M /N /O /P /.notdef /R /S 13{/.notdef}rp /a 2{/.notdef}rp /d /e /.notdef /g /.notdef /i 2{/.notdef}rp /l /m /n /o /p /.notdef /r /s /t /u 2{/.notdef}rp /x 89{/.notdef}rp /quotedblleft /quotedblright 44{/.notdef}rp] CYNJSJ+ArialMT nf CYNJSJ+ArialMT*1 [20.625 0 0 -20.625 0 0 ]msf 89.3267 176.887 mo (Idle )sh 128.311 176.887 mo (enterers)sh 75.0112 264.347 mo (Idlers or )sh 155.245 264.347 mo (\322sleep\323) [6.86865 10.3125 4.58203 11.4707 11.4707 11.4707 0 ]xsh 96.7842 349.331 mo (Idle exiters) [5.73047 11.4702 4.58252 11.4707 5.72998 11.4707 10.3125 4.58252 5.72998 11.4707 6.86816 0 ]xsh 234.184 479.113 mo +59.1172 479.113 li +59.1172 407.598 li +234.184 407.598 li +234.184 479.113 li +cp +3.0518e-05 3.0518e-05 3.0518e-05 3.0518e-05 cmyk +f +234.184 479.113 mo +59.1172 479.113 li +59.1172 407.598 li +234.184 407.598 li +234.184 479.113 li +cp +.75021 .679683 .670222 .90164 cmyk +@ +234.184 683.385 mo +59.1172 683.385 li +59.1172 611.869 li +234.184 611.869 li +234.184 683.385 li +cp +3.0518e-05 3.0518e-05 3.0518e-05 3.0518e-05 cmyk +f +234.184 683.385 mo +59.1172 683.385 li +59.1172 611.869 li +234.184 611.869 li +234.184 683.385 li +cp +.75021 .679683 .670222 .90164 cmyk +@ +.69482 .6318 .621515 .583612 cmyk +%ADOBeginSubsetFont: ArialMT AddGlyphs +%ADOt1write: (1.0.24) %%Copyright: Copyright 2011 Adobe System Incorporated. All rights reserved. systemdict begin CYNJSJ+ArialMT dup /Private get dup rcheck {begin true}{pop false}ifelse exch /CharStrings get begin systemdict /gcheck known {currentglobal currentdict gcheck setglobal} if /F <1C60D8A8C9B7D8BE1661AF70E1029B586475C590C02056C6BE2BB9C2329F 7F6ED1937D1E8A10> |- /c <1C60D8A8C9B7A73DB9D8FD6AA4FBAF8D65C36EA1D4AADBD389F972C0EDCE 9E7F36285FA93A80D3647871D2CE5AAAA6A6A370DC54E1595FB6AAB3E389C9F7 BBBB85F787D6C418B35B940450E5E243895ECFD2205F51B2D154CFFECF34148C 344C1EF806F9AAF539FB961E3EFAF6353381E833DF7C0542FFF27122A28D3654 8FE63FC8465B1B685766E782F0> |- systemdict /gcheck known {setglobal} if end {end} if end CYNJSJ+ArialMT /Encoding get dup 70 /F put dup 99 /c put pop %ADOEndSubsetFont +/CYNJSJ+ArialMT*1 [32{/.notdef}rp /space 32{/.notdef}rp /A /.notdef /C /.notdef /E /F 2{/.notdef}rp /I 2{/.notdef}rp /L /M /N /O /P /.notdef /R /S 13{/.notdef}rp /a /.notdef /c /d /e /.notdef /g /.notdef /i 2{/.notdef}rp /l /m /n /o /p /.notdef /r /s /t /u 2{/.notdef}rp /x 89{/.notdef}rp /quotedblleft /quotedblright 44{/.notdef}rp] CYNJSJ+ArialMT nf CYNJSJ+ArialMT*1 [20.625 0 0 -20.625 0 0 ]msf 81.8896 436.481 mo (Fil)sh 103.653 436.481 mo (e descriptor) [11.4707 5.72998 11.4707 11.4707 10.3125 10.3125 6.86816 4.58252 11.4702 5.73047 11.4707 0 ]xsh %ADOBeginSubsetFont: ArialMT AddGlyphs +%ADOt1write: (1.0.24) %%Copyright: Copyright 2011 Adobe System Incorporated. All rights reserved. systemdict begin CYNJSJ+ArialMT dup /Private get dup rcheck {begin true}{pop false}ifelse exch /CharStrings get begin systemdict /gcheck known {currentglobal currentdict gcheck setglobal} if /h <1C60D8A8C9B7EF322B3BE19FB964E037672C8A279BC86F7B9BF0C8203E13 1450D56E388301CEAE43162551FBE05CABF94DC3B5DDFBB4DA55D11470EBD41A C970CEE2D2EFA88D51157B4EF5536CB673423CDDB06FA774D27105AD2B1AC2DF A8> |- systemdict /gcheck known {setglobal} if end {end} if end CYNJSJ+ArialMT /Encoding get dup 104 /h put pop %ADOEndSubsetFont +/CYNJSJ+ArialMT*1 [32{/.notdef}rp /space 32{/.notdef}rp /A /.notdef /C /.notdef /E /F 2{/.notdef}rp /I 2{/.notdef}rp /L /M /N /O /P /.notdef /R /S 13{/.notdef}rp /a /.notdef /c /d /e /.notdef /g /h /i 2{/.notdef}rp /l /m /n /o /p /.notdef /r /s /t /u 2{/.notdef}rp /x 89{/.notdef}rp /quotedblleft /quotedblright 44{/.notdef}rp] CYNJSJ+ArialMT nf CYNJSJ+ArialMT*1 [20.625 0 0 -20.625 0 0 ]msf 83.5967 461.231 mo (hand)sh 129.479 461.231 mo (lers calls) [4.58252 11.4707 6.86816 10.3125 5.73047 10.3125 11.4702 4.58252 4.58203 0 ]xsh %ADOBeginSubsetFont: ArialMT AddGlyphs +%ADOt1write: (1.0.24) %%Copyright: Copyright 2011 Adobe System Incorporated. All rights reserved. systemdict begin CYNJSJ+ArialMT dup /Private get dup rcheck {begin true}{pop false}ifelse exch /CharStrings get begin systemdict /gcheck known {currentglobal currentdict gcheck setglobal} if /v <1C60D8A8C9B7A73DB99D94C9412F55B03E92C174A4755E69F97C27D9162B 37724F74F272B140D258652D102C2EAC46833C73F9> |- systemdict /gcheck known {setglobal} if end {end} if end CYNJSJ+ArialMT /Encoding get dup 118 /v put pop %ADOEndSubsetFont +/CYNJSJ+ArialMT*1 [32{/.notdef}rp /space 32{/.notdef}rp /A /.notdef /C /.notdef /E /F 2{/.notdef}rp /I 2{/.notdef}rp /L /M /N /O /P /.notdef /R /S 13{/.notdef}rp /a /.notdef /c /d /e /.notdef /g /h /i 2{/.notdef}rp /l /m /n /o /p /.notdef /r /s /t /u /v /.notdef /x 89{/.notdef}rp /quotedblleft /quotedblright 44{/.notdef}rp] CYNJSJ+ArialMT nf CYNJSJ+ArialMT*1 [20.625 0 0 -20.625 0 0 ]msf 77.8564 552.572 mo (Even)sh 124.867 552.572 mo (t han)sh 170.739 552.572 mo (dlers) [11.4707 4.58252 11.4707 6.86816 0 ]xsh 364.847 564.759 mo +285.306 564.759 li +285.306 525.384 li +364.847 525.384 li +364.847 564.759 li +cp +3.0518e-05 3.0518e-05 3.0518e-05 3.0518e-05 cmyk +f +364.847 564.759 mo +285.306 564.759 li +285.306 525.384 li +364.847 525.384 li +364.847 564.759 li +cp +.75021 .679683 .670222 .90164 cmyk +@ +.69482 .6318 .621515 .583612 cmyk +%ADOBeginSubsetFont: ArialMT AddGlyphs +%ADOt1write: (1.0.24) %%Copyright: Copyright 2011 Adobe System Incorporated. All rights reserved. systemdict begin CYNJSJ+ArialMT dup /Private get dup rcheck {begin true}{pop false}ifelse exch /CharStrings get begin systemdict /gcheck known {currentglobal currentdict gcheck setglobal} if /T <1C60D8A8C9B7D8BE16D2C1CA7ED2E06F707C0E9530AE37D06FF7501A595D 3927> |- /V <1C60D8A8C9B64EDFFB759009DDECF50F0319B844741E3CEB2C0ABDDB89E7 563FC0955B866D61D9CC736D3C346A5623E20C1E4D> |- systemdict /gcheck known {setglobal} if end {end} if end CYNJSJ+ArialMT /Encoding get dup 84 /T put dup 86 /V put pop %ADOEndSubsetFont +/CYNJSJ+ArialMT*1 [32{/.notdef}rp /space 32{/.notdef}rp /A /.notdef /C /.notdef /E /F 2{/.notdef}rp /I 2{/.notdef}rp /L /M /N /O /P /.notdef /R /S /T /.notdef /V 10{/.notdef}rp /a /.notdef /c /d /e /.notdef /g /h /i 2{/.notdef}rp /l /m /n /o /p /.notdef /r /s /t /u /v /.notdef /x 89{/.notdef}rp /quotedblleft /quotedblright 44{/.notdef}rp] CYNJSJ+ArialMT nf CYNJSJ+ArialMT*1 [20.625 0 0 -20.625 0 0 ]msf 305.207 552.572 mo (EVT) [13.7568 13.7563 0 ]xsh 493.763 564.759 mo +414.222 564.759 li +414.222 525.384 li +493.763 525.384 li +493.763 564.759 li +cp +3.0518e-05 3.0518e-05 3.0518e-05 3.0518e-05 cmyk +f +493.763 564.759 mo +414.222 564.759 li +414.222 525.384 li +493.763 525.384 li +493.763 564.759 li +cp +.75021 .679683 .670222 .90164 cmyk +@ +.69482 .6318 .621515 .583612 cmyk +%ADOBeginSubsetFont: ArialMT AddGlyphs +%ADOt1write: (1.0.24) %%Copyright: Copyright 2011 Adobe System Incorporated. All rights reserved. systemdict begin CYNJSJ+ArialMT dup /Private get dup rcheck {begin true}{pop false}ifelse exch /CharStrings get begin systemdict /gcheck known {currentglobal currentdict gcheck setglobal} if /B <1C60D8A8C9B64EDFF43B9E1D43B76E7425A98F23F483468D5596DA760F15 54BAD296AA38A849FEE692D78BAC3B162E2013F61317550246D6F77AF27886D4 E04AB44C473130F6FA990DAC6640A48EC2A80691207E5DDBCA7196686E7CD5C9 80FB78081AA13952C8D8F3373FF54323A4853D0F014ED4C5A1024912E545AAB4 BA7F36D08386B7A08B38C3035C03383BB204897FB23E6B597B4E784900841F18 58E5E1740AFA815171FE44AAE751E7961222B185E93D26B02E1EB5C1FF9174E0 C619907BEEF9FED49CD2B96F29B7B01884> |- /J <1C60D8A8C9B7A73D9658D627ED627C91284E113B36EE4477BE063DB79C01 4B4C1304B38BFA4196C7B3993D5118026189127416D2C23E3BA1516C5E2D259E E2D27698DAD25B31EA788FD5CFA3D890F5093AD3EE1D75864143B6DAD8719C69> |- systemdict /gcheck known {setglobal} if end {end} if end CYNJSJ+ArialMT /Encoding get dup 66 /B put dup 74 /J put pop %ADOEndSubsetFont +/CYNJSJ+ArialMT*1 [32{/.notdef}rp /space 32{/.notdef}rp /A /B /C /.notdef /E /F 2{/.notdef}rp /I /J /.notdef /L /M /N /O /P /.notdef /R /S /T /.notdef /V 10{/.notdef}rp /a /.notdef /c /d /e /.notdef /g /h /i 2{/.notdef}rp /l /m /n /o /p /.notdef /r /s /t /u /v /.notdef /x 89{/.notdef}rp /quotedblleft /quotedblright 44{/.notdef}rp] CYNJSJ+ArialMT nf CYNJSJ+ArialMT*1 [20.625 0 0 -20.625 0 0 ]msf 433.936 552.572 mo (JOB)sh 627.095 564.759 mo +547.554 564.759 li +547.554 525.384 li +627.095 525.384 li +627.095 564.759 li +cp +3.0518e-05 3.0518e-05 3.0518e-05 3.0518e-05 cmyk +f +627.095 564.759 mo +547.554 564.759 li +547.554 525.384 li +627.095 525.384 li +627.095 564.759 li +cp +.75021 .679683 .670222 .90164 cmyk +@ +.69482 .6318 .621515 .583612 cmyk +CYNJSJ+ArialMT*1 [20.625 0 0 -20.625 0 0 ]msf 567.455 552.572 mo (EVT) [13.7568 13.7563 0 ]xsh %ADOBeginSubsetFont: ArialMT AddGlyphs +%ADOt1write: (1.0.24) %%Copyright: Copyright 2011 Adobe System Incorporated. All rights reserved. systemdict begin CYNJSJ+ArialMT dup /Private get dup rcheck {begin true}{pop false}ifelse exch /CharStrings get begin systemdict /gcheck known {currentglobal currentdict gcheck setglobal} if /comma <1C60D8A8C9B854D0F42C7AF5C4668C35A6B5F5176B9FC6F495643D40 00A6D27DE0DDA4D01F0D89D11ABC5445CF8C34A3A1CF> |- systemdict /gcheck known {setglobal} if end {end} if end CYNJSJ+ArialMT /Encoding get dup 44 /comma put pop %ADOEndSubsetFont +/CYNJSJ+ArialMT*1 [32{/.notdef}rp /space 11{/.notdef}rp /comma 20{/.notdef}rp /A /B /C /.notdef /E /F 2{/.notdef}rp /I /J /.notdef /L /M /N /O /P /.notdef /R /S /T /.notdef /V 10{/.notdef}rp /a /.notdef /c /d /e /.notdef /g /h /i 2{/.notdef}rp /l /m /n /o /p /.notdef /r /s /t /u /v /.notdef /x 89{/.notdef}rp /quotedblleft /quotedblright 44{/.notdef}rp] CYNJSJ+ArialMT nf CYNJSJ+ArialMT*1 [20.625 0 0 -20.625 0 0 ]msf 76.5522 640.753 mo (Timers, pollers,) [11.833 4.58252 17.1807 11.4707 6.86816 10.3125 5.73047 5.72998 11.4707 11.4707 4.58203 4.58252 11.4707 6.86816 10.3125 0 ]xsh CYNJSJ+ArialMT*1 [20.625 0 0 -20.625 0 0 ]msf 101.372 665.503 mo (animators)sh 43.0615 168.983 mo +49.8262 171.868 li +43.0615 174.751 li +43.0615 168.983 li +cp +.75021 .679683 .670222 .90164 cmyk +f +.5 lw +43.5879 171.87 mo +33.0605 171.87 li +33.0605 649.18 li +50.1582 649.18 li +@ +152.418 136.505 mo +149.533 143.269 li +146.65 136.505 li +152.418 136.505 li +cp +f +149.534 139.887 mo +149.534 113.584 li +3.0518e-05 3.0518e-05 3.0518e-05 3.0518e-05 cmyk +f +.278741 lw +149.534 139.887 mo +149.534 113.584 li +.75021 .679683 .670222 .90164 cmyk +@ +152.418 221.519 mo +149.533 228.282 li +146.65 221.519 li +152.418 221.519 li +cp +f +149.534 224.9 mo +149.534 198.598 li +3.0518e-05 3.0518e-05 3.0518e-05 3.0518e-05 cmyk +f +149.534 224.9 mo +149.534 198.598 li +.75021 .679683 .670222 .90164 cmyk +@ +152.418 306.991 mo +149.533 313.755 li +146.65 306.991 li +152.418 306.991 li +cp +f +149.534 310.373 mo +149.534 284.07 li +3.0518e-05 3.0518e-05 3.0518e-05 3.0518e-05 cmyk +f +149.534 310.373 mo +149.534 284.07 li +.75021 .679683 .670222 .90164 cmyk +@ +250.658 549.955 mo +243.895 547.07 li +250.658 544.188 li +250.658 549.955 li +cp +f +247.277 547.072 mo +273.58 547.072 li +3.0518e-05 3.0518e-05 3.0518e-05 3.0518e-05 cmyk +f +247.277 547.072 mo +273.58 547.072 li +.75021 .679683 .670222 .90164 cmyk +@ +380.706 549.955 mo +373.942 547.07 li +380.706 544.188 li +380.706 549.955 li +cp +f +377.325 547.072 mo +403.628 547.072 li +3.0518e-05 3.0518e-05 3.0518e-05 3.0518e-05 cmyk +f +377.325 547.072 mo +403.628 547.072 li +.75021 .679683 .670222 .90164 cmyk +@ +510.706 549.955 mo +503.942 547.07 li +510.706 544.188 li +510.706 549.955 li +cp +f +507.325 547.072 mo +533.628 547.072 li +3.0518e-05 3.0518e-05 3.0518e-05 3.0518e-05 cmyk +f +507.325 547.072 mo +533.628 547.072 li +.75021 .679683 .670222 .90164 cmyk +@ +642.706 549.955 mo +635.942 547.07 li +642.706 544.188 li +642.706 549.955 li +cp +f +639.325 547.072 mo +665.628 547.072 li +3.0518e-05 3.0518e-05 3.0518e-05 3.0518e-05 cmyk +f +639.325 547.072 mo +665.628 547.072 li +.75021 .679683 .670222 .90164 cmyk +@ +152.418 392.375 mo +149.533 399.139 li +146.65 392.375 li +152.418 392.375 li +cp +f +149.534 395.757 mo +149.534 369.454 li +3.0518e-05 3.0518e-05 3.0518e-05 3.0518e-05 cmyk +f +149.534 395.757 mo +149.534 369.454 li +.75021 .679683 .670222 .90164 cmyk +@ +152.418 510.026 mo +149.533 516.79 li +146.65 510.026 li +152.418 510.026 li +cp +f +149.534 513.408 mo +149.534 487.105 li +3.0518e-05 3.0518e-05 3.0518e-05 3.0518e-05 cmyk +f +149.534 513.408 mo +149.534 487.105 li +.75021 .679683 .670222 .90164 cmyk +@ +152.418 595.912 mo +149.533 602.676 li +146.65 595.912 li +152.418 595.912 li +cp +f +149.534 599.294 mo +149.534 572.991 li +3.0518e-05 3.0518e-05 3.0518e-05 3.0518e-05 cmyk +f +149.534 599.294 mo +149.534 572.991 li +.75021 .679683 .670222 .90164 cmyk +@ +675.316 547.074 mo +675.316 546.584 675.654 546.215 676.133 546.215 cv +676.609 546.215 676.936 546.569 676.936 547.074 cv +676.936 547.563 676.609 547.93 676.104 547.93 cv +675.643 547.93 675.316 547.563 675.316 547.074 cv +cp +.69482 .6318 .621515 .583612 cmyk +f +683.486 547.074 mo +683.486 546.584 683.828 546.215 684.305 546.215 cv +684.779 546.215 685.105 546.569 685.105 547.074 cv +685.105 547.563 684.779 547.93 684.275 547.93 cv +683.814 547.93 683.486 547.563 683.486 547.074 cv +cp +f +691.658 547.074 mo +691.658 546.584 691.996 546.215 692.473 546.215 cv +692.949 546.215 693.275 546.569 693.275 547.074 cv +693.275 547.563 692.949 547.93 692.445 547.93 cv +691.982 547.93 691.658 547.563 691.658 547.074 cv +cp +f +.75021 .679683 .670222 .90164 cmyk +%ADOBeginSubsetFont: MyriadPro-Regular Initial +%ADOt1write: (1.0.24) 12 dict dup begin /FontType 1 def /FontName /MyriadPro-Regular def /FontInfo 7 dict dup begin /Notice (Copyright 1992, 1994, 1997, 2000, 2004 Adobe Systems Incorporated. All rights reserved. Protected by U.S. Patents D454,582. Myriad is either a registered trademark or a trademark of Adobe Systems Incorporated in the United States and/or other countries.) def /Weight (Regular) def /ItalicAngle 0 def /FSType 8 def end def /PaintType 0 def /FontMatrix [0.001 0 0 0.001 0 0] def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 42 /asterisk put def /FontBBox {-157 -250 1126 952} def end systemdict begin dup /Private 12 dict dup begin /|- {def} def /| {put} def /BlueValues [-11 -0 674 686 484 495 650 661 710 721 241 248] def /OtherBlues [438 444 260 266 -209 -198 -153 -147 -118 -112] def /BlueScale 0.0604582 def /StdHW [67] def /StdVW [88] def /StemSnapV [88 92] def /password 5839 def /MinFeature {16 16} def /OtherSubrs[{}{}{}{systemdict/internaldict known not{pop 3}{1183615869 systemdict/internaldict get exec dup/startlock known{/startlock get exec}{dup /strtlck known{/strtlck get exec}{pop 3}ifelse}ifelse}ifelse}executeonly]def /Subrs 5 array dup 0 <1C60D8A8CC31FE2BF6E07AA3E541E2> | dup 1 <1C60D8A8C9C3D06D9E> | dup 2 <1C60D8A8C9C202D79A> | dup 3 <1C60D8A849> | dup 4 <1C60D8A8CC3674F41144B13B77> | def put dup /CharStrings 2 dict dup begin /asterisk <1C60D8A8C9B71C16FD6190DE2747ECD6E73FF07230A807E96C7AE 2B98B3B10B9552D7A2F8DB1494B6D182C31A4D9AB4A4349CBF43A3D56BEC1068 448E5F4282D9D59206E816275B1EF4B6EA21F17B5CFA3518C7E5A044A5E16A3E 5363912798C4BC12A384F0DCFFC564312FABC87A136226D4061A4502240CA590 7EA37376CC3> |- /.notdef <1C60D8A8C9B7A73DC56ED86B010528A4AE924D9B6A4AEB6B57364C BBC1FC7743E3F5B16223C8BD8911534CBC6ED69BD6AA5A2C449B7A6EF268B5A0 D64C6C74FC81FE7341B7ED82094E8390BB44FFD88AB4DB74763338FA8306E917 B17192> |- end put end dup /FontName get exch definefont pop end %ADOEndSubsetFont +/CYNJSK+MyriadPro-Regular /MyriadPro-Regular findfont ct_VMDictPut /CYNJSK+MyriadPro-Regular*1 [42{/.notdef}rp /asterisk 213{/.notdef}rp] CYNJSK+MyriadPro-Regular nf CYNJSK+MyriadPro-Regular*1 [12 0 0 -12 0 0 ]msf 243.895 161.453 mo (*)sh .597284 .512352 .507713 .201328 cmyk +%ADOBeginSubsetFont: ArialMT AddGlyphs +%ADOt1write: (1.0.24) %%Copyright: Copyright 2011 Adobe System Incorporated. All rights reserved. systemdict begin CYNJSJ+ArialMT dup /Private get dup rcheck {begin true}{pop false}ifelse exch /CharStrings get begin systemdict /gcheck known {currentglobal currentdict gcheck setglobal} if /asterisk <1C60D8A8C9B7361F029BA98E8009911CF482C1C857CBE589E37D9 A1982A7DBDD3195F89E2C6022B037A854A7BF1931D8EFEA5631A8AF345DD2E73 7C1E354B06DEC6E11AB4D71707767CA1076E0E28ADF8EB1761EA2E2D596E2663 AED0252CA9E55ED4E> |- /period <1C60D8A8C9B854D0F4604C2A88D29523E6F8C6> |- /underscore <1C60D8A8C9B7EF3224BB0E94C1F3EA8D5F87D58A9CCE> |- /k <1C60D8A8C9B7A73DB90BDE2D32BC36BC1297E20AB90FA9E27E830D444A32 0C85D226D41FA634DF03A4FEE2FD90BF314563D4BF5C68> |- /w <1C60D8A8C9B6079F623B1BE11B16961396A063624588AB070AF82F2F6FEA 646F6999B73C9332DE350CB17016778F548397735D109B5E72AA9A92DCB1D726 4371419D7043A117419C0FAF4C> |- /y <1C60D8A8C9B7A73DB92EFAEC912AA9CB61EA2C87B96577B4D13A11140AAA 18C6E226D96ACA3DE3B427B0A298EF106E8BC0FCA1DC8D81AF2F08A42A0F5836 B6230FDF576E37CE129EFF9730F23EC10CF5ACA4D4CA70309E71B89A944CA734 8AEBF55FF5ADA9F61B4BA14C9A2301A8C53EBFBE665E1DC22E> |- systemdict /gcheck known {setglobal} if end {end} if end CYNJSJ+ArialMT /Encoding get dup 42 /asterisk put dup 46 /period put dup 95 /underscore put dup 107 /k put dup 119 /w put dup 121 /y put pop %ADOEndSubsetFont +/CYNJSJ+ArialMT*1 [32{/.notdef}rp /space 9{/.notdef}rp /asterisk /.notdef /comma /.notdef /period 18{/.notdef}rp /A /B /C /.notdef /E /F 2{/.notdef}rp /I /J /.notdef /L /M /N /O /P /.notdef /R /S /T /.notdef /V 8{/.notdef}rp /underscore /.notdef /a /.notdef /c /d /e /.notdef /g /h /i /.notdef /k /l /m /n /o /p /.notdef /r /s /t /u /v /w /x /y 88{/.notdef}rp /quotedblleft /quotedblright 44{/.notdef}rp] CYNJSJ+ArialMT nf CYNJSJ+ArialMT*1 [12 0 0 -12 0 0 ]msf 33.0605 739.02 mo ( * ecore_evas registers its )sh %ADOBeginSubsetFont: Arial-BoldItalicMT Initial +%ADOt1write: (1.0.24) %%Copyright: Copyright 2011 Adobe System Incorporated. All rights reserved. 12 dict dup begin /FontType 1 def /FontName /Arial-BoldItalicMT def /FontInfo 5 dict dup begin /ItalicAngle 0 def /FSType 8 def end def /PaintType 0 def /FontMatrix [0.001 0 0 0.001 0 0] def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 32 /space put dup 100 /d put dup 101 /e put dup 103 /g put dup 105 /i put dup 110 /n put dup 114 /r put def /FontBBox {-560 -376 1489 1000} def end systemdict begin dup /Private 7 dict dup begin /|- {def} def /| {put} def /BlueValues [0 0] def /password 5839 def /MinFeature {16 16} def /OtherSubrs[{}{}{}{systemdict/internaldict known not{pop 3}{1183615869 systemdict/internaldict get exec dup/startlock known{/startlock get exec}{dup /strtlck known{/strtlck get exec}{pop 3}ifelse}ifelse}ifelse}executeonly]def /Subrs 5 array dup 0 <1C60D8A8CC31FE2BF6E07AA3E541E2> | dup 1 <1C60D8A8C9C3D06D9E> | dup 2 <1C60D8A8C9C202D79A> | dup 3 <1C60D8A849> | dup 4 <1C60D8A8CC3674F41144B13B77> | def put dup /CharStrings 8 dict dup begin /.notdef <1C60D8A8C9B6E3FA5101D97F0BCF44F7161DEB1E2A84766DD477E7 C8A936AA182F5809A9> |- /space <1C60D8A8C9B854D00D> |- /d <1C60D8A8C9B7D8BE18F849B536EFCA0F02FA3E76A4A36E3F76777EA56B16 1C32BD3650224D2C9259AB137A3C28285F8A9610171A5241A00CEFF78A51C9FA 2E4D589D8C9CF88EF8E317ADB723E8E9FAE4F993B2D89B336943A7DBBBEE7EEC E669D1C221EAFAC164EB8F3C6FF7D3C43B06E75F14E8644FEF2361494818DE01 2A036AA7CCF2F7FB1D562B56C84E6A50CCEFC44A> |- /e <1C60D8A8C9B7EF3224CFE21A04FB83F1C45A37777D179847B4EC86B1681D F0F99CBBD414684BAFE73557D0E065AAAC81256CF83BE63EFBD3AF9BD69F9F87 14A4A2B32E3E594C3DF30F01568D0B36A70B75B5AADFF38717D024E3A1D9BC4A EDF484C697CF9A2B7A61694B407AF3DBB6C86F1B9051369419BE53DEFC654B2F 835A366FFF7D34803565C3D20B2CABED35FFDE7B9891216B2A2B0E> |- /g <1C60D8A8C9B7D8BE4BBB56159F6EEF7A9D7E8A196BBB978AFAC5D36E71A0 F24B30BB4A1B5B10E9AA7CBBB62826E8B120FDAE7186231DCB6E95547DE3703A 40384D4C861478CF109A506DD3CDBAAC6E5C0729DC036C5D8EAAD080AD330AC8 65F9BF665B0A0CC79471469F3AAE05D350164D0F5932464C7A0FA860E50B8E40 5242350E1CB55888115E061E4FF3255F51C4138A8027E43EDDE5569A8D41815E 78C1D4C64B1BC3BF7F89635AFF2FCB151B40DB9E8CBF741674034A783056DFD8 3909C1CD2E5E140A6297822093439BCD0613178B3F1EBD9FC45308DD08A2368C B8C3C7F0DA915F094687E32FEAC82B72F737768D3C8769888FD0CD1B87E57057 35B1AD49E447> |- /i <1C60D8A8C9B854D0F404D3C2A96F9D07DC14A3CA0E60D784855FD9CE583E A7EBA0E2E0029C64C1FD6689> |- /n <1C60D8A8C9B7D8BE543421B6181044C47731ABD2BAEF68FF0D0DB7753F6B 1FA10389D204682A5B33541322032BF9431D697179DE1F4251B2FB86F61AEF47 52502C86CF232A02EDF9E1B77E34F9009EF05DCA5484473BD82BE28C6E3EE509 9F9ED9BBCFB467B04ACA70EBBE95BE554659F1> |- /r <1C60D8A8C9B7361F5EF709B7989AC3BC298794B6140D777839B5A64C013F 0C5B98F7B8C3A392C57C88712E6D3D72BFB0244A1B98F5AC6EF74A203B4AEC71 CBFBEF6382C15BA91B> |- end put end dup /FontName get exch definefont pop end %ADOEndSubsetFont +/CYNJSL+Arial-BoldItalicMT /Arial-BoldItalicMT findfont ct_VMDictPut /CYNJSL+Arial-BoldItalicMT*1 [32{/.notdef}rp /space 67{/.notdef}rp /d /e /.notdef /g /.notdef /i 4{/.notdef}rp /n 3{/.notdef}rp /r 141{/.notdef}rp] CYNJSL+Arial-BoldItalicMT nf CYNJSL+Arial-BoldItalicMT*1 [12 0 0 -12 0 0 ]msf 174.453 739.02 mo (rendering )sh CYNJSJ+ArialMT*1 [12 0 0 -12 0 0 ]msf 233.129 739.02 mo (idle enterer automatically)sh 365.639 739.02 mo (, ) [3.33398 0 ]xsh 33.0605 753.42 mo (where rendering takes place.)sh %ADOBeginClientInjection: EndPageContent "AI11EPS" +userdict /annotatepage 2 copy known {get exec}{pop pop} ifelse +%ADOEndClientInjection: EndPageContent "AI11EPS" +grestore +grestore +pgrs +%%PageTrailer +%ADOBeginClientInjection: PageTrailer Start "AI11EPS" +[/EMC AI11_PDFMark5 [/NamespacePop AI11_PDFMark5 +%ADOEndClientInjection: PageTrailer Start "AI11EPS" +[ +[/CSA [/0 ]] +] del_res +/CYNJSK+MyriadPro-Regular*1 uf /CYNJSK+MyriadPro-Regular uf /MyriadPro-Regular uf /CYNJSL+Arial-BoldItalicMT*1 uf /CYNJSL+Arial-BoldItalicMT uf /Arial-BoldItalicMT uf /CYNJSJ+ArialMT*1 uf /CYNJSJ+ArialMT uf /ArialMT uf Adobe_AGM_Image/pt gx +Adobe_CoolType_Core/pt get exec Adobe_AGM_Core/pt gx +currentdict Adobe_AGM_Utils eq {end} if +%%Trailer +Adobe_AGM_Image/dt get exec +Adobe_CoolType_Core/dt get exec Adobe_AGM_Core/dt get exec +%%EOF +%AI9_PrintingDataEnd userdict /AI9_read_buffer 256 string put userdict begin /ai9_skip_data { mark { currentfile AI9_read_buffer { readline } stopped { } { not { exit } if (%AI9_PrivateDataEnd) eq { exit } if } ifelse } loop cleartomark } def end userdict /ai9_skip_data get exec %AI9_PrivateDataBegin %!PS-Adobe-3.0 EPSF-3.0 %%Creator: Adobe Illustrator(R) 11.0 %%AI8_CreatorVersion: 14.0.0 %%For: (Marina Proni) () %%Title: (diagramas_01-32.eps) %%CreationDate: 8/11/11 4:24 PM %%Canvassize: 16383 %AI9_DataStream %Gb"-6CNCcCE?P#aniu%?bt,H^+QJRr)8*@5Wr`VhmP[KPLX\pD>8m[V0f+74!*]>_2#HUbhr0u+k\!a*=.$AZ7QVeW4Zkhhgc[b^ %Idr?p_h\,UYO6nq5Q'iNcUs&SfsCRgGCuf3R!DiiB4#`JetR2?@98p]mp(Z[gt-0hn?XLGl@.*h65-W %J%iHXqsDXhn=,oRJ%0q*qVbf,p9/C@r(m(0ou$`TBY&QflK7bXrs6C75PXDSqhNcV2h9eu^NoeCKn/p$hS4F;p@dY:mr%%>I!>J] %eIU"*n8NSm:VZhpcg]@U+R%K#DL_TRqW=pWk'%p(]QsJ@p>s'J[s,TT^;#-iqY'dEmG6%aZ[+eZ/:CQi@>U]n.<\]RTTns$(rY`4UMC %F*I6LJ%kg0J7IV(hVPqkIImH(jeL)\q2ESW$`Ql?J@kt(i:bWicU/]lTHEcNS3qmHeAAFHf(0gBR:#6rFo0LgDZAhM+Ajduh7nGa %pChW:pTImWIs5hgJ+r5X!@)AnkO=1MW\Q`q_0E.@pR$&:4S*/+t^oTC(A#\E-e1h5e$Yl75@(MVGdaD-gA7HU9r%4E0$[DYrAG5$6PE-KP=grP2,loVTOF#Aa5-k/SQ^ %hd3qu!cN!1?3%_nhS$[Pq\jhOme-gAh8Q!N]RG;+ro22I>NEShT.]%2cp08ar#3*;QDQTKH[5/@i=5"G++JTd!Rq#//PbdCVSPH? %IfJp:jmMVVhS$XKpX!;?9s?84Q+C!Dr<\f02XuJXSY-Wo?FmO,EVm*:#H!C %nDPCDaDeD*,'n2mmoV=T7biPto,EGa`f'/$XO1srdI4Tmmi4OYp[>W2T=Dk44ISM)Y?p3Z]mKM=_S+1rEHh$6/]p0=Iqj/uJgLUr %BqE_i`D7TDJ%U((iU6B`L\EJ5+7=(IkJ`>uG]3B;J^ioU?bcX$4'5%&IJ1/>93tdm9c`Y/4J8D>la-'!&ho7%+"n=MTtfSUiK+!l %,64:4YFkd`m>'F\rqtpPbJ#=3`mXA'n&iBu(+oP1'W?"mbhcK!UX4oDn",WHa6]kI%54CFZ/8hLMX?'2DiDCTAg#I1!FBSLA/jGD %4kVnI(f;$0pJDf8HVi'2rM#?9]eLqJN%I/3&_+"j4]G@VIq]QsDDo"ti; %@U9)TpUF<,qRKo0mdBehS$O9FklOm"<6/IYe;KeTnA;pI'lC[p\pY$2IgfJe+DC6DFaO/Km9.XX2LZ*]nb_d(^AIN>lgHM%n&9fN %biA/CkJ)eoNi'ne[r:apoCp"Lr;hB?2fBd%]_ThN%hHQ2M)-i#BH-qqp:EQhJ$;QElKji=kWaLiiRRh[o:&g"Ie?Q+?k'f_4l]nd %bOeU/qpTIjh>RCtIXdo^L\lS8IJrZTTf!,>jKnl8oCgG,;1hM\%jF>Z_u0EIQrCc7!?QC=*VL@ADr1KsSf')%mgLTDF,>rdT>pW] %$a_5;T'bEaGk]\?+!2P1)qsDW%(h#rMXCFRI,jtn_YrrkR6fR\8V?]&^k_[qpD%B?p_VkTs,jQnhLN:/7dd;na$+J'p\#p4h3SB_ %Bqe\tm^bM@aR;u)^3G)'h9TJ8hgGnPEWah\9+XKh3h=u[]/LR33W&6BRl@g0oDMJ:eFG[g32,4'WpeWIO6FNLcM%##pO@gA)2t@u %TD`g1qSV^R+5icaPnj4tiA_ZT*C060I('&1N;-b1-][,Z__],-`]DCTK4d.2a34!f4H.nP2)G[aL(nZq?sNik4g_F$H[%0\p\m"9$2t`W)(6qWAok.q&'Z]RnFfk=BLurJ1D. %>[Lh[Y-4u]YP6Y\lNY[_?*DHE"O'EgnN'p9L[2k:E-8ZQljp]q43WJ+.#7&K&*XW9!AMFW=,3iWX37RBeS_m3=7]G*.Tb)!#1ghq %!!HP6*\OWK0/*'d]?>@X?e3D@3F1djF;ZaLjg`(^+8/e5bPcn)gUI-oYPYVtp3E;(E<&iQGLsIEmV6sVg[BG&p=j4>!o.W7kY+2;`V98=d&3kY;sB_/C%/nl:4%:P,-_*_8f3m]@UDHQ).+"> %).(>_C7._iB/^M9PQJ])bWFaE_X%R#`0r1"E;EV7[Ee7uG]n4:62Z8l+9XZZjtMESRF@[gU&k6AfQNkL2M7[IqtUjo#`&;gd4B(, %`KhF@%Nlk8J;126?/%<"D&cIeODC59TZC5j>fd)",nGpe[AXN5Dj3IPh9f#\*`-_CB;WF"4jsDB'")9oNEP5d)?'cUi9q]b]na?U %7>kK8-G9`kI8C`2?4@JK]D.@F^^m(X6%r(0@o:EMpi@cfgIU4r`nciu7@ec*Q$/-4J^.iORm?R?TQpq/hY@b#K6*-P&+Ku%"nNaZ %[f[*a+*!5HM?Rr81cTk#]//HZKb:hHZ+,H!fjRerTfTts'c=4bT1!,jBZ=hXPq]q=0[cUA!94LJ?U,)t*YNQGJ0)DDGmdMk$1bET %;4KqR8somFYmdoRJ[H`Di;r$0&nH%g,g@UD"]g?d4cM,u,Nt-ibh#Ki6ZsR`1OPnW$'pq]g^Kk6=YJa(VC1%AN4bmI;=Tai-Mlkf %Pf4sK\#3k/:E,C8Qc+hUP%L3bQSa7YWFf&0W*1FF=+!J8ZIbmc;:T!8\j_=2s6U$=]8^ncC1#K*Klf"`iCo\"iUH;-VJo\3\U>U. %Hpt%QPr#FQ<7$U^fF_t>jCt7`%#]V\?hDiXcYsS'54b2N:Y0ahBOZJbOWX@TB@D*3>H6Vr_TUgG^\Ifo?J`GLY9m(n%AWOT"A3Vo %MP3EL?u.X:"Ko8Xe)h6S)e,l2WJ,G[VXl]?SY"<),t^h)9qE1?=E[1H`a$Oj&Ji_a);@!PJEDdr_`=[#Hj5=,-h:dbJ\M)J):N?^ %*]K:dDdM:l]mi$=mm!MF5-4_m_\1WV7OhjSN?oh3HpgC)3A#ub/q6+nQ\'p9c4nUPNq2MZ*tSqhb`Zb>5t=<=NMu,aFum2?fp<-. %hn6Y9^%\,D$39:IqDb2^]2J8.d47Sm=4(JgS!C*VZs1@eQ1Y\h_L\#h7S@-_,r!O5a,AgiBiJ1IB3JalE-)^d10B3<0tm]X^B]E$ %f"_V#3%j9rZ@b#]+=ghi2F8`X@Ka">>lo*`5e7<5+jp*AMuPtQM15,I`t4u]atae-R:F4J/&t^V:>8?6+p2%?] %]SEQ%0!%sZ8.TL@+M:1ULe/#dT=\j7#S?3Hh,<1aTsYcJZJon1kSKh5e\j:g9+j=%NpB1,]Wqf.P0Ke %fCM-VmoQaG?c1kF^^s%E(/-u!"f$Y#BC\R7Xs=[@NAu$R1V(mHS)&p78#)*7l:-g,Nh#Du3S9\XA7#f0r?QE\`33a)PtXihl!4>T %$?p*J%dg&jQXir5E'dFb!_kHL*rAE;kFufdnUX,JTLiNV_ZGaX!5+8&W;5]*r:7K+<,edFB;#Y>E,92Sl'+N9eL&e+*'AE7%d`0ajQ!M37m8!i%.)uuj@Gr-a)7J.HK+4`lbWL2B2@chL;4AXrZ)AiFDT6/NbX*3Mh(DfTi)=4%I4+P %1l??$0h)c3KC9-g/4j\&Bk8aLPB:-[;Lr"[U0B/XjCA:n6p[qGJZVaOc#SX"+@3.\$?Ye_Oe&eaV[XV@AR"&Dh_+W9?c9Z9o%dg5 %)Yrg+mnmTP!sQG"r2m6m*rTslrU04Ea[O>f&MfB,%5'V`,W'Zi0"-au/Ri2l0/"q?jo]-H84HBrEAEN=Bs`hqDAk'>VEQ2^@<;N, %$)6sr#_sE9%rl?G^MnS7E"g4!;'+I\):f`U@YLuPd%rsQOC0Vp@TB]_%QfbK#8?8N'BH"l9Tkl%'J%#P.gs@334?,@4ZEOjCL6HT %1cnWL[ZI>BiRpVbB-8kt>/IXJ,Q[dnU9tuES]Q+.'XboiD.Y#]*#:@IfYKtBL'=+/P(cF3GK5I6@\[EPWYQ(=2Xf>AnBpO7c#dPr %B2TRW:2fsX4crEs$50oCZ"mp5A'[Eq$!Zg7C[-L#bReC+6!1?MLBO-06%"g:]FaX!E*&%3M^sW^m)^5b'W[U8PG(gk,5WqocpJXW %:"OqQ&Sdt.)J?VLLh_XqPM&tLh/;;!U9c*S4@s4TkTnQ(7[bAR3I#;sR]uG-E&QWZ^j/2O?k=p96d10U_^\$2"3NufdOr,!`fE%u %=MA@bE4cAm0Q@mpSlLr!Pce%+%;:4Ma93NM,m2C(,&>WoFX>l03jR/@h!3ml"G\;#JKbcX4iQ %Zqp5TnfZi>n*7B_D#MYb&2Ft^=WmH?nho8_Q::G]/#q=Vpt2104KPHd4Hhm:$-9DXBaMh87W/h_SKCu8[?h-qoV):tS'8O'8UN=\ %BTlK%9WB5eW(@EU9)O/KX0I#iiAB9B$T5%2.q?_sag!j`bIJH:%baZeY#cf]gZ %6*a*F_.c>RK:>aoTa"X0F=@JVT54u#PDQ3d;YMj;rXK#EXJ-6&OAQU2QpS4K9%08)YW[-omINN\%o %I68Og-\QSc4%hsWB#qbO2['fDmoId3;S@!pRWH9F38m<'FuEE,>Sm(S_^nYWb7%3U\?b;GT)IYWYC/@V+66K"*/%o"5gM^E/2YU> %P?]qaaOM^e_&6Kag81q)\qW/1UXm-OC1b9B1=jBf+3].o/qGUQS`*Jd%aLia1;CR#p>Xs?@a?lXApZQDM`m8Nnr\SCORVJ*i1@2< %X0f:Piji5V_r^U,rT;cro!IdO[Nc7UOW6s9OF/<>ntRXsK6T#@G4=*9rc4@II/Lh?=ut2U].#D=Y'M@/-a%p+PcJV4PhCc!=fEL=FbhXaZSP;K*9)49+qspi6u1AUaH..@?HD0 %l^[2EYTk@Rd6u8JM.\Q7UHPqWc8Zh:9$jL]n-Cgk^t>S!-4g2%0F?usGKSCe0S*hfZ&&2*^_eNBUS[Pfj5*?h!A;Y"!oXt.cNllu %c\uL1Fi'B(*'u4jSO8`M7dM'A5+Rs`Sj39\#10j>,+<2sH95"e!).0fmV+2\h+,"n:&B&-E %"9Iok\9ij>3UAqqk@"2[bM>eR-\u7R#NqG[=5LD:fd!\YD0Wf!J(,J\S3Oa\a;7$#KpfSPY&:d2jqM;D1s!$21MNLR4`q2l2%)D2 %(YL&=bpXGXlE4"Zk`\Xb'K(^t;T,/r`P^;?B@!/DA[N<'!)e_KZJq34P@9SqU?=Uu-Cd'3fUS!?S8=-+3?ckta".lcHs-c3ae6[a %N_2nTmsZ.k=U&kH@@Y/]piV>*Q_!CS2ghtf/>AEjIh,$_2Qg>qE[aT1UoENl/9:@fPH!L$8s;&1[YgIDo1HlC:SUr3 %/'5A?PXeb>]K,^I"IMrSeBBAd9b);@4U_-Y'V7_O8JIaa@3Z+3bk.kQI9[+jHdLp`hie^:T77@8XgoO;i00(bMr)-i^?Y&Vhs>O:0s!0*1Ia[(H0*N8-go]e3P5uK0FWE`0rYNA@$G&VnCV+:BEq.knmE7+n< %omr.Fo)\YZqL1rtNqA/*-*7C',X.tCP36md76/rbKrc;oj*u95#!;6ba5.$tATY[\`piD[,rYfEQL0g,LEhfNcpqF?0%g9hP9KOgj_XQ7Of"8))P[WS75:NgAB_JO_'dYE3<,UFmU[u6@jMAg[0!5UL48%.:W$pKhsKcKp@^B2rp&\O^MNENDNDR$no+9uqbI0# %YM\I,bBOQ@h0uijJ,%NBs3`ZVs9c;eIa0KBfA?!+Tg/pbD=F1HXN<>L=O'-Z3_+ %S-IfYR5/bGC1ZNGNDrei4:(qdJhbi*+[=jJ&D=f1VP7eA+/VocH56oIlm/a(i&rYXdX@Er!9UXG;O<\`kj%kAbc(3`lW %`c'2KImFsND=sgc98Ynr